@taj-special/dravix-code 1.1.24 → 1.1.26

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.
Files changed (2) hide show
  1. package/dist/cli/repl.js +60 -15
  2. package/package.json +1 -1
package/dist/cli/repl.js CHANGED
@@ -2117,9 +2117,34 @@ export async function startRepl(cwd) {
2117
2117
  }
2118
2118
  // activeCwd can change when /resume loads a conversation from a different directory
2119
2119
  let activeCwd = cwd;
2120
+ // Rules appended to every system prompt to enforce safe file-operation behavior
2121
+ const SAFE_FILE_RULES = `
2122
+
2123
+ ## CRITICAL RULES — Follow these on every response
2124
+
2125
+ ### Creating files
2126
+ - NEVER show code in code blocks when the user asks to create files or a project.
2127
+ - ALWAYS use <write_file path="filename"> tags to create actual files.
2128
+ - Code blocks are for short explanations only — they do NOT create files.
2129
+ - Output ALL required files in ONE response using <write_file> tags.
2130
+
2131
+ ### File operations
2132
+ - **write_file** = CREATE only. Use it ONLY when a file does NOT exist yet.
2133
+ - **edit_file** = MODIFY existing files. For ANY change to an existing file, always use edit_file with <find>/<replace>.
2134
+ - Before editing any file: use <read_file> to see its current content first.
2135
+ - NEVER overwrite an existing file with write_file — it destroys user code.
2136
+
2137
+ ### Scope
2138
+ - Only touch files the user explicitly mentioned or that are clearly required by the task.
2139
+ - If the user says "create X" and X already exists: STOP and ask — "I see X already exists at [path]. Do you want me to (a) modify it, or (b) create a new file?"
2140
+ - Do NOT restructure, rename, or "improve" anything that wasn't asked.
2141
+
2142
+ ### When unsure
2143
+ - Ask ONE short clarifying question before writing any code.
2144
+ - Better to ask than to guess wrong and destroy existing work.`;
2120
2145
  const buildSystemMsg = (dir) => ({
2121
2146
  role: 'system',
2122
- content: SYSTEM_PROMPT + '\n\nProject context:\n' + buildContext(dir),
2147
+ content: SYSTEM_PROMPT + SAFE_FILE_RULES + '\n\nProject context:\n' + buildContext(dir),
2123
2148
  });
2124
2149
  const history = [buildSystemMsg(activeCwd)];
2125
2150
  let sessionId = generateId();
@@ -2196,8 +2221,8 @@ export async function startRepl(cwd) {
2196
2221
  userReminder = `The user's request: "${display}". `;
2197
2222
  }
2198
2223
  const taskInstruction = userReminder
2199
- ? `The user's exact request was: "${rawUserMsg.slice(0, 300)}"\nNow execute THIS request and ONLY this request — nothing else. Do not invent, add, or change anything the user did not ask for. Use the file content above to find the exact text and apply the change.`
2200
- : `Execute the user's request using the file content above.`;
2224
+ ? `The user's exact request was: "${rawUserMsg.slice(0, 300)}"\nNow execute THIS request and ONLY this request — nothing else. Do not invent, add, or change anything the user did not ask for. Use <edit_file> with targeted <find>/<replace> — never use <write_file> on existing files. Use the file content above to find the exact text and apply the change.`
2225
+ : `Execute the user's request using the file content above. Use <edit_file> for existing files, <write_file> only for new files.`;
2201
2226
  // Keep using FLASH_MODEL after file reads
2202
2227
  if (readFileTurnCount > 5 && !forcedEditMode) {
2203
2228
  forcedEditMode = true;
@@ -2435,6 +2460,16 @@ export async function startRepl(cwd) {
2435
2460
  executedInlineOps.add(inlineOpFingerprint(op));
2436
2461
  }
2437
2462
  else {
2463
+ // Track existing file size to detect write_file overwrites of existing code
2464
+ let existingLineCount = 0;
2465
+ if (op.type === 'write' && op.path) {
2466
+ try {
2467
+ const fp = path.resolve(activeCwd, op.path);
2468
+ if (fs.existsSync(fp))
2469
+ existingLineCount = fs.readFileSync(fp, 'utf-8').split('\n').length;
2470
+ }
2471
+ catch { /* ignore */ }
2472
+ }
2438
2473
  const previewLines = (op.type === 'write' || op.type === 'edit') ? printDiffPreview(op, activeCwd) : 0;
2439
2474
  const allowed = await askPermission(label, key, alwaysAllowed, op.type === 'run', previewLines > 0, previewLines);
2440
2475
  executedInlineOps.add(inlineOpFingerprint(op));
@@ -2510,11 +2545,17 @@ export async function startRepl(cwd) {
2510
2545
  else if ((opResult.type === 'modified' || opResult.type === 'created') && op.path &&
2511
2546
  (op.type === 'edit' || op.type === 'write')) {
2512
2547
  // After a successful edit, inject a note so AI knows the file changed
2513
- // This prevents subsequent <edit_file> ops from using stale <find> text
2514
2548
  history.push({
2515
2549
  role: 'system',
2516
- content: `[File updated] ${op.path} was just modified by a previous operation in this response. If you have more edits for this file, use <read_file path="${op.path}"/> first to get the current content before using <edit_file>, or use <write_file> with the complete new content.`,
2550
+ content: `[File updated] ${op.path} was just modified. For further edits to this file, use <read_file path="${op.path}"/> first to get the current content, then <edit_file> with targeted changes.`,
2517
2551
  });
2552
+ // Educate AI when it used write_file to overwrite a non-trivial existing file
2553
+ if (op.type === 'write' && opResult.type === 'modified' && existingLineCount > 20) {
2554
+ history.push({
2555
+ role: 'system',
2556
+ content: `[Rule] You used <write_file> to completely replace ${op.path} (${existingLineCount} lines of existing code). This is wrong. RULE: write_file is ONLY for creating new files. For existing files, always use <edit_file> with <find>/<replace> to make targeted changes. Never overwrite existing code with write_file.`,
2557
+ });
2558
+ }
2518
2559
  }
2519
2560
  }
2520
2561
  }
@@ -2738,24 +2779,28 @@ export async function startRepl(cwd) {
2738
2779
  }
2739
2780
  const allOps = parseOps(normalized);
2740
2781
  // ── Detect incomplete plan: AI described steps but didn't output tags ──
2741
- // Pattern: response has numbered items like "2. something" or "3. something"
2742
- // but very few actual file operation tags were output → force continuation
2743
2782
  if (!readFileContinue && !streamCancelled) {
2744
2783
  const hasAnyReadOp = allOps.some(op => op.type === 'read_file' || op.type === 'read_folder' || op.type === 'search_code');
2745
2784
  const writeOps = allOps.filter(op => op.type !== 'read_file' && op.type !== 'read_folder' && op.type !== 'search_code').length;
2746
2785
  const plannedSteps = (normalized.match(/^\s*[2-9]\.\s+\S/mg) ?? []).length;
2747
- // AI described a plan (numbered steps 2+) but did nothing at all — force execution
2786
+ const hasCodeFence = normalized.includes('```');
2787
+ const hasStepList = (normalized.match(/^\s*\d+[.)]\s+\S/mg) ?? []).length >= 2;
2788
+ // Case 1: AI listed numbered steps (2+) but produced zero file ops
2748
2789
  if (plannedSteps >= 1 && writeOps === 0 && !hasAnyReadOp) {
2749
- history.push({ role: 'system', content: 'You described the steps but did not output any tags. Output the actual <edit_file> or <write_file> tags NOW to apply the changes. No explanationjust the tags.' });
2790
+ history.push({ role: 'system', content: 'CRITICAL ERROR: You described steps but produced NO file operation tags. You MUST output <write_file> or <edit_file> tags to create/modify actual files. Do NOT show code in ``` blocks use <write_file path="filename"> tags instead. Output all the tags NOW. No explanation.' });
2791
+ readFileContinue = true;
2792
+ // Case 2: AI showed code blocks + numbered list but no tags — regardless of language
2793
+ }
2794
+ else if (hasCodeFence && hasStepList && writeOps === 0 && allOps.length === 0) {
2795
+ history.push({ role: 'system', content: 'CRITICAL ERROR: You are showing code in ``` blocks instead of using <write_file> tags. This is wrong. ``` blocks do NOT create files — only <write_file> tags create files. Replace every ``` code block with a <write_file path="filename"> tag and output ALL files now.' });
2750
2796
  readFileContinue = true;
2751
- // AI gave a non-trivial response with zero operations of any kind
2797
+ // Case 3: Long response with code blocks but zero file ops — catch any language
2752
2798
  }
2753
- else if (writeOps === 0 && allOps.length === 0 && normalized.trim().length > 200) {
2754
- const hasCodeFence = normalized.includes('```');
2755
- const hasStepList = (normalized.match(/^\s*\d+[.)]\s+\S/mg) ?? []).length >= 2;
2799
+ else if (hasCodeFence && writeOps === 0 && allOps.length === 0 && normalized.trim().length > 400) {
2756
2800
  const hasWouldNeed = /(?:should|would need to|need to|you(?:'d)? need to|we(?:'d)? need to)\s+(?:edit|modify|update|change|create|add|remove)/i.test(normalized);
2757
- if ((hasCodeFence || hasStepList) && hasWouldNeed) {
2758
- history.push({ role: 'system', content: 'You explained what to do but did not output any tags. Apply the changes NOW using <edit_file> or <write_file> tags. Do not re-explain — just output the tags.' });
2801
+ const looksLikeFileDump = normalized.split('```').length > 3; // 2+ code blocks
2802
+ if (hasWouldNeed || looksLikeFileDump) {
2803
+ history.push({ role: 'system', content: 'CRITICAL ERROR: You showed code in ``` blocks instead of using <write_file> tags. ``` blocks are for explanations only — they do NOT create actual files. Output all files using <write_file path="..."> tags RIGHT NOW. No text, no explanation — only tags.' });
2759
2804
  readFileContinue = true;
2760
2805
  }
2761
2806
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taj-special/dravix-code",
3
- "version": "1.1.24",
3
+ "version": "1.1.26",
4
4
  "description": "AI-powered coding assistant CLI — Dravix Code",
5
5
  "type": "module",
6
6
  "bin": {