wormclaude 1.0.143 → 1.0.145

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.
@@ -128,6 +128,72 @@ function toToolCall(obj, i) {
128
128
  function looksLikeCall(o) {
129
129
  return !!o && typeof o === 'object' && (typeof o.name === 'string' || typeof o.tool === 'string' || (o.function && typeof o.function === 'object'));
130
130
  }
131
+ // Sarmasız (wrapper'sız) üst-düzey JSON için SIKI kontrol: yalnız adı BİLİNEN bir araç olan
132
+ // veya `function`/`arguments` yapısı taşıyan nesne çağrıdır. Aksi halde `package.json` gibi
133
+ // `"name"` içeren GERÇEK dosya içerikleri yanlışlıkla araç çağrısı sanılırdı (latent bug).
134
+ const _KNOWN_TOOL_RE = /^(?:Bash|PowerShell|Read|Write|Edit|Glob|Grep|WebFetch|WebSearch|Sleep|TaskOutput|AskUserQuestion)$/;
135
+ function looksLikeKnownCall(o) {
136
+ if (!o || typeof o !== 'object')
137
+ return false;
138
+ if (o.function && typeof o.function === 'object')
139
+ return true;
140
+ const nm = o.name || o.tool || o.tool_name;
141
+ if (typeof nm !== 'string' || !_KNOWN_TOOL_RE.test(nm))
142
+ return false;
143
+ // Bilinen ad + bir argüman anahtarı (çıplak `{"name":"Read"}` da geçerli olabilir → ad yeter).
144
+ return true;
145
+ }
146
+ // ---- DOSYA-BLOĞU KURTARMA (build paste-vs-write) -----------------------------
147
+ // Model bir build görevinde Write çağırmak yerine ```kod bloğu YAPIŞTIRABİLİR ve
148
+ // dosya hiç oluşmaz. Bunu kurtarıyoruz — AMA yalnız blok AÇIKÇA bir dosya adıyla
149
+ // etiketliyse (`index.html`, **app.py**, `# server.py`, `Dosya: x.css`…). Etiket
150
+ // yoksa (saf "kod göster" / örnek) DOKUNMAYIZ. Recovered Write yine onay ister →
151
+ // kullanıcı sadece görmek istediyse reddeder (güvenli).
152
+ const _CODE_EXT = 'py|js|jsx|ts|tsx|html?|htm|css|scss|sass|less|json|jsonc|sh|bash|zsh|go|rs|java|kt|c|cc|cpp|cxx|h|hpp|rb|php|sql|ya?ml|toml|ini|env|xml|svg|vue|svelte|astro|md|markdown|txt|dockerfile|makefile|cs|swift|dart|lua|pl|r|m|mjs|cjs|tf|gradle|bat|ps1';
153
+ const _ECHO_FILE_LANGS = /^(plaintext|plain|text|txt|http|https|console|output|log|raw|diff|patch)$/i;
154
+ // Dosya-adı token'ı: `path/to/file.ext` veya `file.ext` (gerçek kod uzantısı şart).
155
+ const _FNAME = '(?:[\\w./\\\\-]+\\.(?:' + _CODE_EXT + ')|Dockerfile|Makefile|\\.(?:env|gitignore|babelrc)[\\w.-]*)';
156
+ // Etiket biçimleri — fence'ten HEMEN önce (≤2 satır), aynı paragraf:
157
+ // `file.ext` | **file.ext** | ## file.ext | File:/Dosya:/Filename: file.ext | file.ext:
158
+ const _LABEL_RE = new RegExp('(?:^|\\n)[ \\t>*#`\\-]*' +
159
+ '(?:(?:file|dosya|filename|dosya adı|path|yol)\\s*[:=]\\s*)?' +
160
+ '["`*\\[(]*\\s*(' + _FNAME + ')\\s*["`*\\])]*\\s*:?[ \\t]*' + // **bold**/`tick`/[bracket] çoklu sarmal
161
+ '(?:\\([^)\\n]*\\))?[ \\t]*' + // "index.html (ana sayfa)" gibi parantez-not
162
+ '\\r?\\n(?:[ \\t]*\\r?\\n)?' + // araya en çok bir boş satır
163
+ '```([a-zA-Z0-9_+-]*)[ \\t]*\\r?\\n([\\s\\S]*?)```', 'gi');
164
+ /** Metindeki dosya-adı etiketli kod bloklarını bulur (span'larıyla). Konservatif:
165
+ * gerçek kod uzantısı + echo-olmayan dil + ≥2 satır/≥40 karakter gövde şart. */
166
+ export function findFileBlocks(text) {
167
+ const t = text || '';
168
+ const out = [];
169
+ const seen = new Set();
170
+ let m;
171
+ _LABEL_RE.lastIndex = 0;
172
+ while ((m = _LABEL_RE.exec(t)) !== null) {
173
+ const file = m[1].trim();
174
+ const lang = (m[2] || '').trim();
175
+ const body = m[3] || '';
176
+ if (_ECHO_FILE_LANGS.test(lang))
177
+ continue; // komut/çıktı bloğu — dosya değil
178
+ const nonEmpty = body.split('\n').filter((l) => l.trim()).length;
179
+ if (body.trim().length < 15 && nonEmpty < 2)
180
+ continue; // önemsiz snippet (`a=1` gibi) — etiket asıl sinyal
181
+ const key = file + '|' + body.length;
182
+ if (seen.has(key))
183
+ continue;
184
+ seen.add(key);
185
+ out.push({ file, content: body.replace(/\s+$/, '') + '\n', start: m.index, end: m.index + m[0].length });
186
+ }
187
+ return out;
188
+ }
189
+ /** Dosya-bloklarını Write çağrılarına çevirir (yapısal/inline tool-call YOKKEN son çare). */
190
+ export function recoverFileBlocks(text) {
191
+ return findFileBlocks(text).map((b, i) => ({
192
+ id: `fileblock_${i}`,
193
+ name: 'Write',
194
+ args: JSON.stringify({ file_path: b.file, content: b.content }),
195
+ }));
196
+ }
131
197
  /** Metindeki üst-düzey {…} JSON nesnelerini (string/escape duyarlı) çıkarır.
132
198
  * Model çağrıları sarmasız ve BİRDEN FAZLA nesne olarak dökebilir: {…}{…} veya {…}\n{…}
133
199
  * (abliterated coder davranışı). Her üst-düzey nesneyi ayrı parça olarak döndürür. */
@@ -169,7 +235,8 @@ function extractTopLevelJsonObjects(text) {
169
235
  export function recoverInlineToolCalls(text) {
170
236
  const t = (text || '').trim();
171
237
  // JSON/prose/ToolName{…}/ToolName(…) çağrısı yoksa erken çık.
172
- if (!t || (!t.includes('"name"') && !t.includes('"tool"') && !t.includes('"function"') && !/AskUserQuestion/i.test(t) && !TOOL_PREFIX_RE.test(t) && !TOOL_PAREN_RE.test(t)))
238
+ // (Kod fence'i varsa çıkma dosya-adı etiketli blok olabilir, adım 7 karar verir.)
239
+ if (!t || (!t.includes('"name"') && !t.includes('"tool"') && !t.includes('"function"') && !/AskUserQuestion/i.test(t) && !TOOL_PREFIX_RE.test(t) && !TOOL_PAREN_RE.test(t) && !t.includes('```')))
173
240
  return [];
174
241
  const out = [];
175
242
  const seen = new Set();
@@ -193,7 +260,9 @@ export function recoverInlineToolCalls(text) {
193
260
  if (!out.length) {
194
261
  for (const m of t.matchAll(/```(?:json|tool_call|tool|function)?\s*([\s\S]*?)```/gi)) {
195
262
  const o = safeJsonParse(m[1].trim(), null);
196
- if (looksLikeCall(o))
263
+ // SIKI: ```json içine konmuş GERÇEK dosya (`{"name":"app",...}`) tool-call sanılmasın;
264
+ // sarmalı tool-call'lar zaten bilinen araç adı (Write/Bash…) kullanır → step 7 dosyayı alır.
265
+ if (looksLikeKnownCall(o))
197
266
  push(o);
198
267
  }
199
268
  }
@@ -202,8 +271,8 @@ export function recoverInlineToolCalls(text) {
202
271
  if (!out.length) {
203
272
  for (const frag of extractTopLevelJsonObjects(t)) {
204
273
  const o = safeJsonParse(frag, null);
205
- if (looksLikeCall(o))
206
- push(o);
274
+ if (looksLikeKnownCall(o))
275
+ push(o); // SIKI: package.json gibi dosyaları çağrı sanma
207
276
  }
208
277
  }
209
278
  // 4) AskUserQuestion'ı JSON yerine DÜZ-METİN (prose) yazan model (abliterated):
@@ -265,6 +334,18 @@ export function recoverInlineToolCalls(text) {
265
334
  }
266
335
  }
267
336
  }
337
+ // 7) SON ÇARE: hiç çağrı kurtarılamadıysa, dosya-adı etiketli ```kod bloklarını
338
+ // Write'a çevir (model build'de Write yerine kod yapıştırınca dosya kaybolmasın).
339
+ // Adım 7, gerçek tool-call YOKKEN çalışır → "kod göster"i bozmaz (etiket gerekir).
340
+ if (!out.length) {
341
+ for (const tc of recoverFileBlocks(t)) {
342
+ const k = tc.name + '|' + tc.args;
343
+ if (!seen.has(k)) {
344
+ seen.add(k);
345
+ out.push(tc);
346
+ }
347
+ }
348
+ }
268
349
  return out;
269
350
  }
270
351
  /** Modelin komut/çıktıyı TEKRAR yazdığı kod-bloklarını siler (```plaintext/bash/http/console…).
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.143';
19
+ export const VERSION = '1.0.145';
package/dist/tools.js CHANGED
@@ -149,45 +149,12 @@ function norm(p) {
149
149
  }
150
150
  }
151
151
  // ── Araç açıklamaları (WormClaude prompt.ts'lerinden birebir) ────────────────
152
- const BASH_DESCRIPTION = `Executes a given bash command and returns its output.
153
-
154
- The working directory persists between commands, but shell state does not. The shell environment is initialized from the user's profile (bash or zsh).
155
-
156
- IMPORTANT: Avoid using this tool to run \`find\`, \`grep\`, \`cat\`, \`head\`, \`tail\`, \`sed\`, \`awk\`, or \`echo\` commands, unless explicitly instructed or after you have verified that a dedicated tool cannot accomplish your task. Instead, use the appropriate dedicated tool as this will provide a much better experience for the user:
157
-
158
- - File search: Use Glob (NOT find or ls)
159
- - Content search: Use Grep (NOT grep or rg)
160
- - Read files: Use Read (NOT cat/head/tail)
161
- - Edit files: Use Edit (NOT sed/awk)
162
- - Write files: Use Write (NOT echo >/cat <<EOF)
163
- - Communication: Output text directly (NOT echo/printf)
164
-
165
- While the Bash tool can do similar things, it's better to use the built-in tools as they provide a better user experience and make it easier to review tool calls and give permission.
166
-
167
- # Instructions
168
- - If your command will create new directories or files, first use this tool to run \`ls\` to verify the parent directory exists and is the correct location.
169
- - Always quote file paths that contain spaces with double quotes in your command (e.g., cd "path with spaces/file.txt")
170
- - Try to maintain your current working directory throughout the session by using absolute paths and avoiding usage of \`cd\`. You may use \`cd\` if the User explicitly requests it.
171
- - You may specify an optional timeout in milliseconds (up to ${MAX_BASH_TIMEOUT_MS}ms / ${MAX_BASH_TIMEOUT_MS / 60000} minutes). By default, your command will timeout after ${DEFAULT_BASH_TIMEOUT_MS}ms (${DEFAULT_BASH_TIMEOUT_MS / 60000} minutes).
172
- - When issuing multiple commands:
173
- - If the commands depend on each other and must run sequentially, use a single Bash call with '&&' to chain them together.
174
- - Use ';' only when you need to run commands sequentially but don't care if earlier commands fail.
175
- - DO NOT use newlines to separate commands (newlines are ok in quoted strings).
176
- - For git commands:
177
- - Prefer to create a new commit rather than amending an existing commit.
178
- - Before running destructive operations (e.g., git reset --hard, git push --force, git checkout --), consider whether there is a safer alternative that achieves the same goal. Only use destructive operations when they are truly the best approach.
179
- - Never skip hooks (--no-verify) or bypass signing unless the user has explicitly asked for it. If a hook fails, investigate and fix the underlying issue.
180
- - Avoid unnecessary \`sleep\` commands: do not sleep between commands that can run immediately — just run them.`;
181
- const READ_DESCRIPTION = `Reads a file from the local filesystem. You can access any file directly by using this tool.
182
- Assume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned.
183
-
184
- Usage:
185
- - The file_path parameter must be an absolute path, not a relative path
186
- - By default, it reads up to ${MAX_LINES_TO_READ} lines starting from the beginning of the file
187
- - You can optionally specify a line offset and limit (especially handy for long files), but it's recommended to read the whole file by not providing these parameters
188
- - Results are returned using cat -n format, with line numbers starting at 1
189
- - This tool can only read files, not directories. To read a directory, use an ls command via the Bash tool.
190
- - If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents.`;
152
+ const BASH_DESCRIPTION = `Run a shell command and return its output. Working directory persists between calls; shell state does not.
153
+ - Prefer the dedicated tools over shell: Glob (not find/ls), Grep (not grep/rg), Read (not cat/head/tail), Edit (not sed/awk), Write (not echo>). Use Bash for everything else (npm, git, build, run, curl, pip).
154
+ - Quote paths with spaces. Chain dependent commands with && in ONE call; use ; if you do not care about failures; no newlines between commands.
155
+ - timeout: optional ms (max ${MAX_BASH_TIMEOUT_MS}, default ${DEFAULT_BASH_TIMEOUT_MS}). run_in_background: true for long or never-exiting commands (returns a task id; read later with TaskOutput).
156
+ - git: commit only when asked; avoid destructive ops (reset --hard, push --force) unless clearly best.`;
157
+ const READ_DESCRIPTION = `Read a file from the local filesystem. file_path must be ABSOLUTE. Returns content with line numbers (cat -n format), up to ${MAX_LINES_TO_READ} lines; optional offset/limit for long files. Cannot read directories (use ls via Bash). A missing file returns an error.`;
191
158
  const WRITE_DESCRIPTION = `Writes a file to the local filesystem.
192
159
 
193
160
  Usage:
@@ -196,28 +163,12 @@ Usage:
196
163
  - Prefer the Edit tool for modifying existing files — it only sends the diff. Only use this tool to create new files or for complete rewrites.
197
164
  - NEVER create documentation files (*.md) or README files unless explicitly requested by the User.
198
165
  - Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked.`;
199
- const EDIT_DESCRIPTION = `Performs exact string replacements in files.
200
-
201
- Usage:
202
- - You must use your \`Read\` tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file.
203
- - When editing text from Read tool output, ensure you preserve the exact indentation (tabs/spaces) as it appears AFTER the line number prefix. The line number prefix format is: spaces + line number + tab. Everything after that is the actual file content to match. Never include any part of the line number prefix in the old_string or new_string.
204
- - ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.
205
- - Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.
206
- - The edit will FAIL if \`old_string\` is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use \`replace_all\` to change every instance of \`old_string\`.
207
- - Use \`replace_all\` for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.`;
166
+ const EDIT_DESCRIPTION = `Exact string replacement in a file. You MUST Read the file at least once first (errors otherwise). old_string must be UNIQUE in the file - include enough surrounding context, or use replace_all to change every occurrence (e.g. renaming a variable). Preserve exact indentation from the file; do NOT include the line-number prefix from Read output.`;
208
167
  const GLOB_DESCRIPTION = `- Fast file pattern matching tool that works with any codebase size
209
168
  - Supports glob patterns like "**/*.js" or "src/**/*.ts"
210
169
  - Returns matching file paths sorted by modification time
211
170
  - Use this tool when you need to find files by name patterns`;
212
- const GREP_DESCRIPTION = `A powerful search tool built on ripgrep
213
-
214
- Usage:
215
- - ALWAYS use Grep for search tasks. NEVER invoke \`grep\` or \`rg\` as a Bash command. The Grep tool has been optimized for correct permissions and access.
216
- - Supports full regex syntax (e.g., "log.*Error", "function\\s+\\w+")
217
- - Filter files with glob parameter (e.g., "*.js", "**/*.tsx") or type parameter (e.g., "js", "py", "rust")
218
- - Output modes: "content" shows matching lines, "files_with_matches" shows only file paths (default), "count" shows match counts
219
- - Pattern syntax: literal braces need escaping (use \`interface\\{\\}\` to find \`interface{}\` in Go code)
220
- - Multiline matching: By default patterns match within single lines only. For cross-line patterns like \`struct \\{[\\s\\S]*?field\`, use \`multiline: true\``;
171
+ const GREP_DESCRIPTION = `Search file contents (built on ripgrep) - ALWAYS use this instead of grep/rg in Bash. Full regex syntax. Filter with glob ("*.ts") or type ("py","js"). output_mode: "files_with_matches" (default), "content" (matching lines; supports -A/-B/-C/-n), or "count". Use multiline:true for cross-line patterns.`;
221
172
  const AGENT_DESCRIPTION = `Launch a new sub-agent to handle a complex, multi-step task autonomously.
222
173
 
223
174
  The sub-agent runs its own tool-calling loop (Bash, Read, Write, Edit, Glob, Grep, WebFetch) against the same model, then returns a final summary. Use this to:
@@ -230,18 +181,7 @@ Usage:
230
181
  - run_in_background: if true, returns a task id immediately and the agent works in the background; read its result later with TaskOutput. If false (default), blocks until the sub-agent finishes and returns its result directly.
231
182
  - The sub-agent CANNOT launch further sub-agents (no nesting).`;
232
183
  const TASKOUTPUT_DESCRIPTION = `Read the current output and status of a background task (shell command or sub-agent) previously started with run_in_background. Returns the task status and its accumulated output.`;
233
- const WEBFETCH_DESCRIPTION = `- Fetches content from a specified URL
234
- - Takes a URL and a prompt as input
235
- - Fetches the URL content, converts HTML to text
236
- - Returns the page content for analysis against the prompt
237
- - Use this tool when you need to retrieve and analyze web content
238
-
239
- Usage notes:
240
- - The URL must be a fully-formed valid URL
241
- - HTTP URLs will be automatically upgraded to HTTPS
242
- - The prompt should describe what information you want to extract from the page
243
- - This tool is read-only and does not modify any files
244
- - For GitHub URLs, prefer using the gh CLI via Bash instead (e.g., gh pr view, gh issue view, gh api).`;
184
+ const WEBFETCH_DESCRIPTION = `Fetch a URL and return its text content for analysis against your prompt. url must be a full valid URL (http auto-upgraded to https); prompt describes what to extract. Read-only. For GitHub URLs prefer gh CLI via Bash.`;
245
185
  // ── Şemalar (OpenAI function-calling formatı) ─────────────────────────────────
246
186
  export const toolSchemas = [
247
187
  {
package/dist/tui.js CHANGED
@@ -445,7 +445,10 @@ export async function runTui() {
445
445
  if (allowAll.has(c.name))
446
446
  return resolve('allow');
447
447
  // Claude tarzı: Write/Edit'te YAZMADAN ÖNCE dosya içeriğini göster, sonra onay iste.
448
- if ((c.name === 'Write' && args?.content != null) || (c.name === 'Edit' && args?.new_string != null)) {
448
+ // İSTİSNA: kurtarılan dosya-bloğu (id `fileblock_`) içeriği zaten akışta prose olarak
449
+ // gösterildi → fileprev'i ATLA, yoksa aynı kod iki kez basılır.
450
+ const _recoveredBlock = typeof c.id === 'string' && c.id.startsWith('fileblock_');
451
+ if (!_recoveredBlock && ((c.name === 'Write' && args?.content != null) || (c.name === 'Edit' && args?.new_string != null))) {
449
452
  const _content = String(c.name === 'Write' ? args.content : args.new_string);
450
453
  printItem({ kind: 'fileprev', file: relWs(args.file_path), lines: _content.split('\n') });
451
454
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wormclaude",
3
- "version": "1.0.143",
3
+ "version": "1.0.145",
4
4
  "description": "WormClaude CLI - uncensored security+code assistant (ink TUI, Claude-style)",
5
5
  "type": "module",
6
6
  "bin": {