draftify-cli 1.0.92 → 1.0.95

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/repl.js +73 -16
  2. package/package.json +1 -1
package/dist/repl.js CHANGED
@@ -578,6 +578,7 @@ async function startRepl(initialUsername) {
578
578
  // 3. AI Chat Prompt (default)
579
579
  async function applyFileOperations(result) {
580
580
  let displayResult = result;
581
+ const operationErrors = [];
581
582
  // Pre-process native tool calls (<tool_call> and <longcat_tool_call>) to translate them to standard XML tags
582
583
  const toolCallRegex = /<(?:tool_call|longcat_tool_call)>([\s\S]*?)<\/(?:tool_call|tool|longcat_tool_call)>/gi;
583
584
  let tcMatch;
@@ -644,7 +645,9 @@ async function startRepl(initialUsername) {
644
645
  const filePath = match[1];
645
646
  const fullPath = path_1.default.resolve(process.cwd(), filePath);
646
647
  if (!isSafePath(fullPath)) {
647
- ui_1.ui.error(`Security error: Cannot delete file outside workspace (${filePath})`);
648
+ const err = `Security error: Cannot delete file outside workspace (${filePath})`;
649
+ ui_1.ui.error(err);
650
+ operationErrors.push(err);
648
651
  displayResult = displayResult.replace(match[0], `[Blocked: ${filePath} is outside workspace]`);
649
652
  continue;
650
653
  }
@@ -655,7 +658,9 @@ async function startRepl(initialUsername) {
655
658
  displayResult = displayResult.replace(match[0], '');
656
659
  }
657
660
  catch (e) {
658
- ui_1.ui.error(`Failed to delete ${filePath}: ${e.message}`);
661
+ const err = `Failed to delete ${filePath}: ${e.message}`;
662
+ ui_1.ui.error(err);
663
+ operationErrors.push(err);
659
664
  }
660
665
  }
661
666
  }
@@ -664,7 +669,9 @@ async function startRepl(initialUsername) {
664
669
  const filePath = match[1];
665
670
  const fullPath = path_1.default.resolve(process.cwd(), filePath);
666
671
  if (!isSafePath(fullPath)) {
667
- ui_1.ui.error(`Security error: Cannot create file outside workspace (${filePath})`);
672
+ const err = `Security error: Cannot create file outside workspace (${filePath})`;
673
+ ui_1.ui.error(err);
674
+ operationErrors.push(err);
668
675
  displayResult = displayResult.replace(match[0], `\n[Blocked: ${filePath} is outside workspace]\n`);
669
676
  continue;
670
677
  }
@@ -681,7 +688,10 @@ async function startRepl(initialUsername) {
681
688
  displayResult = displayResult.replace(match[0], '');
682
689
  }
683
690
  catch (e) {
684
- ui_1.ui.error(`Failed to create ${filePath}: ${e.message}`);
691
+ const err = `Failed to create ${filePath}: ${e.message}`;
692
+ ui_1.ui.error(err);
693
+ operationErrors.push(err);
694
+ displayResult = displayResult.replace(match[0], `[Failed to create: ${filePath}]`);
685
695
  }
686
696
  }
687
697
  const modifyRegex = /<FILE_MODIFY\s+path=['"]([^'"]+)['"]>([\s\S]*?)<\/(?:FILE|SCRIPT|STYLE|HTML)_MODIFY>/gi;
@@ -690,7 +700,9 @@ async function startRepl(initialUsername) {
690
700
  const block = match[2];
691
701
  const fullPath = path_1.default.resolve(process.cwd(), filePath);
692
702
  if (!isSafePath(fullPath)) {
693
- ui_1.ui.error(`Security error: Cannot modify file outside workspace (${filePath})`);
703
+ const err = `Security error: Cannot modify file outside workspace (${filePath})`;
704
+ ui_1.ui.error(err);
705
+ operationErrors.push(err);
694
706
  displayResult = displayResult.replace(match[0], `[Blocked: ${filePath} is outside workspace]`);
695
707
  continue;
696
708
  }
@@ -826,17 +838,23 @@ async function startRepl(initialUsername) {
826
838
  ui_1.ui.info(`Partial-matched diff for ${filePath} (unique line anchors)`);
827
839
  }
828
840
  else {
829
- ui_1.ui.error(`Could not apply diff to ${filePath}: SEARCH block not matched (all 6 strategies failed).`);
841
+ const err = `Could not apply diff to ${filePath}: SEARCH block not matched (all 6 strategies failed).`;
842
+ ui_1.ui.error(err);
843
+ operationErrors.push(err);
830
844
  }
831
845
  }
832
846
  else {
833
- ui_1.ui.error(`Could not apply diff to ${filePath}: SEARCH block not matched (all strategies failed).`);
847
+ const err = `Could not apply diff to ${filePath}: SEARCH block not matched (all strategies failed).`;
848
+ ui_1.ui.error(err);
849
+ operationErrors.push(err);
834
850
  }
835
851
  }
836
852
  }
837
853
  }
838
854
  else {
839
- ui_1.ui.error(`Could not apply diff to ${filePath}: SEARCH block is empty.`);
855
+ const err = `Could not apply diff to ${filePath}: SEARCH block is empty.`;
856
+ ui_1.ui.error(err);
857
+ operationErrors.push(err);
840
858
  }
841
859
  }
842
860
  }
@@ -848,14 +866,20 @@ async function startRepl(initialUsername) {
848
866
  displayResult = displayResult.replace(match[0], '');
849
867
  }
850
868
  else if (!hasDiffBlocks) {
851
- ui_1.ui.error(`Invalid FILE_MODIFY block for ${filePath}`);
869
+ const err = `Invalid FILE_MODIFY block for ${filePath}`;
870
+ ui_1.ui.error(err);
871
+ operationErrors.push(err);
872
+ displayResult = displayResult.replace(match[0], `[Failed to modify: ${filePath} - Invalid block]`);
852
873
  }
853
874
  else {
854
875
  displayResult = displayResult.replace(match[0], `[Failed to modify: ${filePath} - SEARCH block mismatch]`);
855
876
  }
856
877
  }
857
878
  else {
858
- ui_1.ui.error(`Cannot modify ${filePath}: File not found.`);
879
+ const err = `Cannot modify ${filePath}: File not found.`;
880
+ ui_1.ui.error(err);
881
+ operationErrors.push(err);
882
+ displayResult = displayResult.replace(match[0], `[Failed to modify: ${filePath} - File not found]`);
859
883
  }
860
884
  }
861
885
  const commandsToRun = [];
@@ -881,7 +905,8 @@ async function startRepl(initialUsername) {
881
905
  cleanResult: displayResult.replace(/\n\s*\n\s*\n/g, '\n\n').trim(),
882
906
  commandsToRun,
883
907
  filesToReadAuto,
884
- dirsToListAuto
908
+ dirsToListAuto,
909
+ errors: operationErrors
885
910
  };
886
911
  }
887
912
  exports.globalAbortController = new AbortController();
@@ -905,18 +930,32 @@ async function startRepl(initialUsername) {
905
930
  let retryCount = 0;
906
931
  let success = false;
907
932
  let partialText = "";
908
- while (retryCount < 3 && !success) {
933
+ // Detect if a successful response was actually truncated mid-content
934
+ function detectTruncation(text) {
935
+ // Check for unclosed FILE_CREATE
936
+ const createOpenMatch = text.match(/<FILE_CREATE\s+path="([^"]+)"[^>]*>/);
937
+ if (createOpenMatch && !/<\/FILE_CREATE>/i.test(text)) {
938
+ return { truncated: true, filePath: createOpenMatch[1], tagType: 'FILE_CREATE' };
939
+ }
940
+ // Check for unclosed FILE_MODIFY
941
+ const modifyOpenMatch = text.match(/<FILE_MODIFY\s+path="([^"]+)"[^>]*>/);
942
+ if (modifyOpenMatch && !/<\/FILE_MODIFY>/i.test(text)) {
943
+ return { truncated: true, filePath: modifyOpenMatch[1], tagType: 'FILE_MODIFY' };
944
+ }
945
+ return { truncated: false };
946
+ }
947
+ while (retryCount < 4 && !success) {
909
948
  try {
910
949
  let retryHistory = [...conversationHistory];
911
950
  let retryPrompt = finalPrompt;
912
951
  if (partialText) {
913
952
  retryHistory.push({ role: "user", content: finalPrompt });
914
953
  retryHistory.push({ role: "assistant", content: partialText });
915
- retryPrompt = "Continue exactly from where you left off. Do not repeat what you already said, just continue the exact code or sentence you were writing.";
954
+ retryPrompt = "Continue exactly from where you left off. Do not repeat anything you already wrote. Continue the file content from the exact character where it was cut off.";
916
955
  }
917
956
  spinner = (0, ui_1.createSpinner)("Working...").start();
918
957
  if (retryCount > 0) {
919
- spinner.setPrefix(`Retrying... (${retryCount}/3)`);
958
+ spinner.setPrefix(`Continuing... (${retryCount}/3)`);
920
959
  }
921
960
  let thisAttemptText = "";
922
961
  const attemptResult = await (0, api_1.refactorCodeApi)(requestPayloadFileName, requestPayloadCode, retryPrompt, retryHistory, currentModel, activeSkillsData, (0, config_1.getThinkingLevel)(), (chunk) => {
@@ -948,7 +987,22 @@ async function startRepl(initialUsername) {
948
987
  spinner.setPrefix("Analyzing...");
949
988
  }
950
989
  }, exports.globalAbortController.signal);
951
- rawResult = partialText + attemptResult;
990
+ const combined = partialText + attemptResult;
991
+ // --- TRUNCATION DETECTION ---
992
+ // If the stream ended cleanly but the content is still incomplete (token-limited),
993
+ // treat it like a retry scenario and continue generation.
994
+ const truncationInfo = detectTruncation(combined);
995
+ if (truncationInfo.truncated && retryCount < 3) {
996
+ if (spinner)
997
+ spinner.stop();
998
+ ui_1.ui.info(`Response truncated mid-file (${truncationInfo.filePath}). Continuing...`);
999
+ partialText = combined;
1000
+ retryCount++;
1001
+ currentStreamedText = combined;
1002
+ await new Promise(r => setTimeout(r, 500));
1003
+ continue; // restart the while loop with updated partialText
1004
+ }
1005
+ rawResult = combined;
952
1006
  success = true;
953
1007
  }
954
1008
  catch (e) {
@@ -981,7 +1035,7 @@ async function startRepl(initialUsername) {
981
1035
  }
982
1036
  }
983
1037
  spinner.stop();
984
- const { cleanResult, commandsToRun, filesToReadAuto, dirsToListAuto } = await applyFileOperations(rawResult);
1038
+ const { cleanResult, commandsToRun, filesToReadAuto, dirsToListAuto, errors: fileOpErrors } = await applyFileOperations(rawResult);
985
1039
  // --- PARSE CLARIFICATION QUESTIONS ---
986
1040
  let finalDisplayResult = cleanResult;
987
1041
  let questions = [];
@@ -1076,6 +1130,9 @@ async function startRepl(initialUsername) {
1076
1130
  autoExplorationOutputs.push(`Failed to read ${filePath}: ${e.message}`);
1077
1131
  }
1078
1132
  }
1133
+ if (fileOpErrors && fileOpErrors.length > 0) {
1134
+ autoExplorationOutputs.push(`Some file operations failed:\n${fileOpErrors.map(e => `- ${e}`).join('\n')}`);
1135
+ }
1079
1136
  if (autoExplorationOutputs.length > 0) {
1080
1137
  let promptAdditions = autoPrompt ? [autoPrompt] : [];
1081
1138
  promptAdditions.push(`I executed your file system requests. Here are the results:\n${autoExplorationOutputs.join('\n\n')}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "draftify-cli",
3
- "version": "1.0.92",
3
+ "version": "1.0.95",
4
4
  "description": "Draftify AI CLI tool",
5
5
  "main": "dist/index.js",
6
6
  "bin": {