wormclaude 1.0.129 → 1.0.131

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.
@@ -206,16 +206,29 @@ export function recoverInlineToolCalls(text) {
206
206
  }
207
207
  }
208
208
  // 4) AskUserQuestion'ı JSON yerine DÜZ-METİN (prose) yazan model (abliterated):
209
- // AskUserQuestion question "X" with options [A · B · C] → gerçek çağrıya çevir.
209
+ // AskUserQuestion question "X" with options ["A","B"] | [A · B · C] → gerçek çağrıya çevir.
210
210
  if (!out.length && /AskUserQuestion/i.test(t)) {
211
- const m = t.match(/AskUserQuestion[\s\S]*?["“]([^"”]{3,}?)["”][\s\S]*?\[([^\]]+)\]/i);
211
+ const m = t.match(/AskUserQuestion[\s\S]*?["“]([^"”]{3,}?)["”][\s\S]*?(\[[\s\S]*?\])/i);
212
212
  if (m) {
213
213
  const question = m[1].trim();
214
- const options = m[2]
215
- .split(/\s*[·•|,/]\s*|\s{2,}/)
216
- .map((s) => s.trim().replace(/^["'“]|["'”]$/g, ''))
217
- .filter(Boolean)
218
- .map((label) => ({ label }));
214
+ let options = [];
215
+ // Önce gerçek JSON array dene (model çoğunlukla ["A","B/C","D"] yazıyor → "/" ile BÖLME).
216
+ const arr = safeJsonParse(m[2], null);
217
+ if (Array.isArray(arr)) {
218
+ options = arr
219
+ .map((x) => (typeof x === 'string' ? x.trim() : (x && (x.label || x.value || x.text) ? String(x.label || x.value || x.text).trim() : '')))
220
+ .filter(Boolean)
221
+ .map((label) => ({ label }));
222
+ }
223
+ // JSON değilse ayraçla böl ("·•|," ve 2+ boşluk — "/" YOK, "İşletme/Teknoloji" bölünmesin).
224
+ if (options.length < 2) {
225
+ options = m[2]
226
+ .replace(/^\[|\]$/g, '')
227
+ .split(/\s*[·•|,]\s*|\s{2,}/)
228
+ .map((s) => s.trim().replace(/^["'“]|["'”]$/g, ''))
229
+ .filter(Boolean)
230
+ .map((label) => ({ label }));
231
+ }
219
232
  if (options.length >= 2)
220
233
  push({ name: 'AskUserQuestion', arguments: { question, options } });
221
234
  }
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.129';
19
+ export const VERSION = '1.0.131';
package/dist/tools.js CHANGED
@@ -27,6 +27,9 @@ let todosStore = []; // TodoWrite durumu
27
27
  export function getTodos() { return todosStore; }
28
28
  const MAX_LINES_TO_READ = 2000;
29
29
  const DEFAULT_BASH_TIMEOUT_MS = 120000;
30
+ // Sunucu/never-exits komutları: ön planda çalışırsa CLI'ı bloklar (timeout'a kadar "donma").
31
+ // Bunları run_in_background istenmese bile OTOMATİK arka plana alıyoruz → CLI asla donmaz.
32
+ const _DEV_SERVER_RE = /\b(?:npm|pnpm|yarn)\s+(?:run\s+)?(?:dev|start|serve|preview)\b|\b(?:next|nuxt|vite|gatsby)\s+(?:dev|develop|start)\b|\bng\s+serve\b|\breact-scripts\s+start\b|\bnodemon\b|\bhttp-server\b|(?:^|\s)serve(?:\s|$)|\bpython3?\s+-m\s+http\.server\b|\bflask\s+run\b|\buvicorn\b|\bgunicorn\b|\bphp\s+-S\b|\brails\s+s(?:erver)?\b|\bwebpack(?:-dev-server)?\s+serve\b/i;
30
33
  const MAX_BASH_TIMEOUT_MS = 600000;
31
34
  // Bash çalışma dizini — oturum boyunca kalıcı. execSync her çağrıda taze shell açtığı için
32
35
  // `cd` normalde kaybolur; burada cwd'yi takip edip her komuta geçiriyoruz.
@@ -532,15 +535,15 @@ export const toolSchemas = [
532
535
  type: 'function',
533
536
  function: {
534
537
  name: 'AskUserQuestion',
535
- description: 'Ask the user a multiple-choice question and get their answer (renders as an interactive picker). Use when a request is AMBIGUOUS and you need a decision only the user can make BEFORE acting — e.g. they ask you to build a website/app/project but did not specify the type, tech stack, or style. Prefer asking ONE concise question with 2-4 clear options (each with a short description) over guessing. Do NOT use it for things you can reasonably decide yourself.',
538
+ description: 'Ask the user a multiple-choice question and get their answer (renders as an interactive numbered picker). Use when a request is AMBIGUOUS and you need a decision only the user can make BEFORE acting — e.g. they ask you to build a website/app/project but did not specify the type, tech stack, or style. Ask ONE concise question with 2-4 SHORT option strings. Do NOT use it for things you can reasonably decide yourself. IMPORTANT: emit it as a single tool call ONLY — never also write the question as prose.',
536
539
  parameters: {
537
540
  type: 'object',
538
541
  properties: {
539
542
  question: { type: 'string', description: 'The question to ask' },
540
543
  options: {
541
544
  type: 'array',
542
- description: '2-4 options',
543
- items: { type: 'object', properties: { label: { type: 'string' }, description: { type: 'string' } }, required: ['label'] },
545
+ description: '2-4 short option strings, e.g. ["React.js", "Vue.js", "Angular"]',
546
+ items: { type: 'string' },
544
547
  },
545
548
  },
546
549
  required: ['question', 'options'],
@@ -610,8 +613,9 @@ const CORE_TOOLS = new Set([
610
613
  'Bash', 'PowerShell', 'Read', 'Write', 'Edit', 'Glob', 'Grep',
611
614
  'WebFetch', 'WebSearch', 'Sleep',
612
615
  'TaskOutput', // uzun komutları arka planda çalıştırıp bitişini yoklamak için (run_in_background)
613
- // AskUserQuestion KALDIRILDI: 32B nested options array'ini sağlıklı üretemiyor degenere
614
- // oluyor ({"name":"","arguments":""} tekrarı). Model artık makul varsayımla direkt kurar.
616
+ 'AskUserQuestion', // GERİ EKLENDİ: FLAT şema (options: string[]) ile 32B temiz çağrı üretiyor
617
+ // (test edildi). Eski degenere NESTED şemadandı ([{label,description}]). Handler string→{label}
618
+ // normalize ediyor; bare-JSON inline recovery temiz çağrıyı yakalıyor → numaralı menü.
615
619
  ]);
616
620
  export function allToolSchemas() {
617
621
  const sk = skillToolSchema();
@@ -674,8 +678,15 @@ async function execOne(call, hooks) {
674
678
  return { ok: false, output: `Geçersiz girdi: ${verr}`, args };
675
679
  // 2) İnteraktif/plan araçları
676
680
  if (call.name === 'AskUserQuestion') {
677
- const opts = Array.isArray(args.options) ? args.options : [];
678
- if (hooks?.ask) {
681
+ // Seçenekleri normalize et: model FLAT string[] verir ("React.js"), ama eski/karışık çağrı
682
+ // {label,description} objesi de olabilir. Hepsini {label, description?} biçimine indir.
683
+ const raw = Array.isArray(args.options) ? args.options : [];
684
+ const opts = raw
685
+ .map((o) => typeof o === 'string' ? { label: o.trim() }
686
+ : (o && (o.label || o.value || o.text)) ? { label: String(o.label || o.value || o.text).trim(), description: o.description ? String(o.description) : undefined }
687
+ : null)
688
+ .filter((o) => o && o.label);
689
+ if (hooks?.ask && opts.length) {
679
690
  const ch = await hooks.ask({ question: String(args.question), options: opts });
680
691
  return { ok: true, output: ch, args };
681
692
  }
@@ -965,9 +976,12 @@ export async function executeTool(name, args) {
965
976
  return { ok: true, output: `Kaydirildi: ${args.direction}` };
966
977
  }
967
978
  if (name === 'Bash') {
968
- if (args.run_in_background) {
969
- const task = tasks.create('shell', String(args.command).slice(0, 60));
970
- const child = spawn(String(args.command), { shell: true, windowsHide: true, cwd: getBashCwd() });
979
+ const _cmd = String(args.command);
980
+ // Sunucu/never-exits komutu → run_in_background istenmese bile otomatik arka plana al (donma yok).
981
+ const _autoBg = !args.run_in_background && _DEV_SERVER_RE.test(_cmd);
982
+ if (args.run_in_background || _autoBg) {
983
+ const task = tasks.create('shell', _cmd.slice(0, 60));
984
+ const child = spawn(_cmd, { shell: true, windowsHide: true, cwd: getBashCwd() });
971
985
  task.child = child;
972
986
  child.stdout?.on('data', (d) => tasks.append(task.id, d.toString()));
973
987
  child.stderr?.on('data', (d) => tasks.append(task.id, d.toString()));
@@ -976,7 +990,10 @@ export async function executeTool(name, args) {
976
990
  tasks.finish(task.id, code === 0 ? 'done' : 'error');
977
991
  });
978
992
  child.on('error', (e) => { tasks.append(task.id, `\n[spawn error: ${e.message}]`); tasks.finish(task.id, 'error'); });
979
- return { ok: true, output: `Background task started: ${task.id}. Read output later with TaskOutput("${task.id}").` };
993
+ const _note = _autoBg
994
+ ? ` (This is a long-running/server command — it was auto-started in the BACKGROUND so it cannot freeze the CLI. The server is now running. Do NOT run it again in the foreground; just tell the user it is running and on which command/port.)`
995
+ : '';
996
+ return { ok: true, output: `Background task started: ${task.id}.${_note} Read output later with TaskOutput("${task.id}").` };
980
997
  }
981
998
  let timeout = Number(args.timeout) || DEFAULT_BASH_TIMEOUT_MS;
982
999
  if (timeout > MAX_BASH_TIMEOUT_MS)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wormclaude",
3
- "version": "1.0.129",
3
+ "version": "1.0.131",
4
4
  "description": "WormClaude CLI - uncensored security+code assistant (ink TUI, Claude-style)",
5
5
  "type": "module",
6
6
  "bin": {