wormclaude 1.0.100 → 1.0.102

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
@@ -3,12 +3,13 @@ import React, { useState, useRef, useEffect, useMemo } from 'react';
3
3
  import { render, Box, Text, useApp, useInput } from 'ink';
4
4
  import LineEditor from './lineeditor.js';
5
5
  import * as path from 'node:path';
6
+ import * as fs from 'node:fs';
6
7
  import { theme, VERSION } from './theme.js';
7
8
  import { loadConfig, streamChat, fetchAccount } from './api.js';
8
9
  import { stripInlineToolCalls } from './inlinetools.js';
9
10
  import { newTrace, flushTelemetry } from './telemetry.js';
10
11
  import { tier } from './program.js';
11
- import { allToolSchemas, executeToolCalls, executeTool, toolLabel, setToolConfig } from './tools.js';
12
+ import { allToolSchemas, executeToolCalls, executeTool, toolLabel, setToolConfig, setBashCwd } from './tools.js';
12
13
  import { sanitizeError, sanitizeOutput } from './errorsan.js';
13
14
  import { cleanModelText } from './textclean.js';
14
15
  import { MarkdownDisplay } from './markdown.js';
@@ -679,6 +680,7 @@ function App() {
679
680
  let lastAnswer = ''; // modelin son (sentez) cevabı
680
681
  let lastToolSig = '';
681
682
  let sameToolCount = 0;
683
+ let taskIn = 0, taskOut = 0, taskCache = 0; // bu görevin GERÇEK token toplamı (tüm turlar; API usage'dan)
682
684
  while (iter < MAX_TURNS) {
683
685
  if (ac.signal.aborted) {
684
686
  push({ kind: 'note', text: t('note.interrupted') });
@@ -732,6 +734,9 @@ function App() {
732
734
  else if (ev.type === 'done') {
733
735
  toolCalls = ev.toolCalls;
734
736
  usage.record(config.model, ev.usage); // billing: token/maliyet kaydı
737
+ taskIn += ev.usage?.input || 0; // bu görevin gerçek token toplamı
738
+ taskOut += ev.usage?.output || 0;
739
+ taskCache += ev.usage?.cacheRead || 0; // havuz hafıza (prefix-cache) isabeti
735
740
  }
736
741
  }
737
742
  setStreaming('');
@@ -832,6 +837,12 @@ function App() {
832
837
  }
833
838
  if (!done)
834
839
  push({ kind: 'note', text: t('note.maxTurns', MAX_TURNS) });
840
+ // Bu görevin GERÇEK token maliyeti (tüm turların toplamı, API usage'dan)
841
+ if (taskIn + taskOut > 0) {
842
+ const tot = (taskIn + taskOut).toLocaleString();
843
+ const cacheStr = taskCache > 0 ? ` (${taskCache.toLocaleString()} havuz-önbellek)` : '';
844
+ push({ kind: 'note', text: `⎿ Bu istek: ↑${taskIn.toLocaleString()} giriş${cacheStr} · ↓${taskOut.toLocaleString()} çıkış · toplam ${tot} token` });
845
+ }
835
846
  abortRef.current = null;
836
847
  setCtxTokens(Math.round(JSON.stringify(historyRef.current).length / 4));
837
848
  setBusy(false);
@@ -917,6 +928,26 @@ function App() {
917
928
  }
918
929
  return;
919
930
  }
931
+ // /cd <yol> — çalışma klasörünü (workspace) değiştir. Dosyalar artık buraya yazılır.
932
+ if (tok === '/cd' || tok === '/klasor' || tok === '/workspace') {
933
+ const en = getLang() === 'en';
934
+ const arg = v.slice(tok.length).trim().replace(/^["']|["']$/g, '');
935
+ if (!arg) {
936
+ push({ kind: 'note', text: (en ? 'Workspace: ' : 'Çalışma klasörü: ') + process.cwd() });
937
+ return;
938
+ }
939
+ try {
940
+ const target = path.isAbsolute(arg) ? arg : path.resolve(process.cwd(), arg);
941
+ fs.mkdirSync(target, { recursive: true });
942
+ process.chdir(target);
943
+ setBashCwd(target);
944
+ push({ kind: 'note', text: (en ? '✓ Workspace → ' : '✓ Çalışma klasörü → ') + target });
945
+ }
946
+ catch (e) {
947
+ push({ kind: 'note', text: (en ? 'cd failed: ' : 'Klasör değiştirilemedi: ') + (e?.message || String(e)) });
948
+ }
949
+ return;
950
+ }
920
951
  // /agent ve /multi-agent — tek / çoklu alt-agent
921
952
  if (tok === '/agent' || tok === '/multi-agent') {
922
953
  const task = v.slice(tok.length).trim();
package/dist/commands.js CHANGED
@@ -20,6 +20,7 @@ export const COMMANDS = [
20
20
  { name: '/help', desc: 'komutları ve ipuçlarını göster' },
21
21
  { name: '/clear', desc: 'sohbeti ve geçmişi temizle' },
22
22
  { name: '/kopyala', desc: 'son yanıtı panoya kopyala (/kopyala hepsi · tüm sohbet)' },
23
+ { name: '/cd', desc: 'çalışma klasörünü değiştir — dosyalar buraya yazılır: /cd <yol>' },
23
24
  { name: '/compact', desc: 'geçmişi modelle özetleyip bağlamı küçült' },
24
25
  { name: '/context', desc: 'bağlam / token kullanımını göster' },
25
26
  { name: '/cost', desc: 'oturum token tahminini göster' },
@@ -110,6 +110,21 @@ export function recoverInlineToolCalls(text) {
110
110
  push(o);
111
111
  }
112
112
  }
113
+ // 4) AskUserQuestion'ı JSON yerine DÜZ-METİN (prose) yazan model (abliterated):
114
+ // AskUserQuestion question "X" with options [A · B · C] → gerçek çağrıya çevir.
115
+ if (!out.length && /AskUserQuestion/i.test(t)) {
116
+ const m = t.match(/AskUserQuestion[\s\S]*?["“]([^"”]{3,}?)["”][\s\S]*?\[([^\]]+)\]/i);
117
+ if (m) {
118
+ const question = m[1].trim();
119
+ const options = m[2]
120
+ .split(/\s*[·•|,/]\s*|\s{2,}/)
121
+ .map((s) => s.trim().replace(/^["'“]|["'”]$/g, ''))
122
+ .filter(Boolean)
123
+ .map((label) => ({ label }));
124
+ if (options.length >= 2)
125
+ push({ name: 'AskUserQuestion', arguments: { question, options } });
126
+ }
127
+ }
113
128
  return out;
114
129
  }
115
130
  /** Kurtarılan çağrı bloklarını GÖRÜNTÜ/geçmiş metninden temizler (çirkin JSON kalmasın). */
@@ -124,5 +139,7 @@ export function stripInlineToolCalls(text) {
124
139
  if (/"(name|tool|function)"/.test(frag))
125
140
  s = s.replace(frag, '');
126
141
  }
142
+ // AskUserQuestion prose biçimi (interaktif seçiciye çevrildi → metni gizle).
143
+ s = s.replace(/AskUserQuestion[\s\S]*?\[[^\]]*\]\s*/gi, '');
127
144
  return s.trim();
128
145
  }
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.100';
19
+ export const VERSION = '1.0.102';
package/dist/tools.js CHANGED
@@ -33,6 +33,16 @@ const MAX_BASH_TIMEOUT_MS = 600000;
33
33
  let bashCwd;
34
34
  export function getBashCwd() { return bashCwd || process.cwd(); }
35
35
  export function setBashCwd(dir) { bashCwd = dir; }
36
+ // Göreli dosya yollarını AKTİF workspace'e (bashCwd) çözer; mutlak yol aynen kalır.
37
+ // Böylece model "index.html" gibi göreli yol verse bile dosya bilinen klasöre yazılır.
38
+ export function resolveWs(fp) {
39
+ try {
40
+ return path.isAbsolute(fp) ? fp : path.resolve(getBashCwd(), fp);
41
+ }
42
+ catch {
43
+ return fp;
44
+ }
45
+ }
36
46
  // Komutu çalıştırır ve sonrasında cwd değişikliğini (cd) yakalayıp bashCwd'yi günceller.
37
47
  // POSIX: pwd'yi temp dosyaya yazan, çıkış kodunu KORUYAN sarmalayıcı (hata propagasyonu bozulmaz).
38
48
  // Windows: komutu olduğu gibi çalıştır, sonra baştaki `cd <hedef>`'i regex ile yakala (best-effort).
@@ -1007,7 +1017,7 @@ export async function executeTool(name, args) {
1007
1017
  }
1008
1018
  }
1009
1019
  if (name === 'Read') {
1010
- const fp = args.file_path;
1020
+ const fp = resolveWs(args.file_path);
1011
1021
  if (!fs.existsSync(fp))
1012
1022
  return { ok: false, output: `Error: file does not exist: ${fp}` };
1013
1023
  if (fs.statSync(fp).isDirectory())
@@ -1027,7 +1037,7 @@ export async function executeTool(name, args) {
1027
1037
  return { ok: true, output: numbered.slice(0, 40000) };
1028
1038
  }
1029
1039
  if (name === 'Write') {
1030
- const fp = args.file_path;
1040
+ const fp = resolveWs(args.file_path);
1031
1041
  if (fs.existsSync(fp) && !readFiles.has(norm(fp)))
1032
1042
  return { ok: false, output: 'Error: existing file must be read first. Use the Read tool before overwriting.' };
1033
1043
  fs.mkdirSync(path.dirname(path.resolve(fp)), { recursive: true });
@@ -1043,7 +1053,7 @@ export async function executeTool(name, args) {
1043
1053
  return { ok: true, output: `Wrote ${fp} (${_wnew.length} chars)${diffStat(_wold, _wnew)}` };
1044
1054
  }
1045
1055
  if (name === 'Edit') {
1046
- const fp = args.file_path;
1056
+ const fp = resolveWs(args.file_path);
1047
1057
  if (!fs.existsSync(fp))
1048
1058
  return { ok: false, output: `Error: file does not exist: ${fp}` };
1049
1059
  if (!readFiles.has(norm(fp)))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wormclaude",
3
- "version": "1.0.100",
3
+ "version": "1.0.102",
4
4
  "description": "WormClaude CLI - uncensored security+code assistant (ink TUI, Claude-style)",
5
5
  "type": "module",
6
6
  "bin": {