opencode-gbk-tools 0.1.10 → 0.1.11

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.
@@ -16309,6 +16309,11 @@ import { createReadStream } from "fs";
16309
16309
  import fs2 from "fs/promises";
16310
16310
  import path2 from "path";
16311
16311
  var STREAMING_FILE_SIZE_THRESHOLD_BYTES = 1024 * 1024;
16312
+ function assertStringArgument(value, name) {
16313
+ if (typeof value !== "string") {
16314
+ throw createGbkError("GBK_INVALID_ARGUMENT", `${name} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32`);
16315
+ }
16316
+ }
16312
16317
  function assertPositiveInteger(value, name) {
16313
16318
  if (!Number.isInteger(value) || Number(value) <= 0) {
16314
16319
  throw createGbkError("GBK_INVALID_ARGUMENT", `${name} \u5FC5\u987B\u662F\u6B63\u6574\u6570`);
@@ -16336,6 +16341,8 @@ function detectNewlineStyle(text) {
16336
16341
  return "none";
16337
16342
  }
16338
16343
  function countOccurrences(text, target) {
16344
+ assertStringArgument(text, "text");
16345
+ assertStringArgument(target, "oldString");
16339
16346
  if (target.length === 0) {
16340
16347
  throw createGbkError("GBK_EMPTY_OLD_STRING", "oldString \u4E0D\u80FD\u4E3A\u7A7A");
16341
16348
  }
@@ -16354,6 +16361,25 @@ function countOccurrences(text, target) {
16354
16361
  // src/lib/text-file.ts
16355
16362
  var TEXT_STREAMING_FILE_SIZE_THRESHOLD_BYTES = 1024 * 1024;
16356
16363
  var UTF8_DECODER = new TextDecoder("utf-8", { fatal: true });
16364
+ function assertStringArgument2(value, name) {
16365
+ if (typeof value !== "string") {
16366
+ throw createTextError("GBK_INVALID_ARGUMENT", `${name} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32`);
16367
+ }
16368
+ }
16369
+ function assertReplaceArguments(input) {
16370
+ assertStringArgument2(input.oldString, "oldString");
16371
+ assertStringArgument2(input.newString, "newString");
16372
+ }
16373
+ function resolveEditMode(mode) {
16374
+ return mode ?? "replace";
16375
+ }
16376
+ function resolveInsertIfExists(value) {
16377
+ return value ?? "skip";
16378
+ }
16379
+ function resolveExplicitTextEncoding(value, fallback) {
16380
+ const requested = value ?? "auto";
16381
+ return requested === "auto" ? fallback : requested;
16382
+ }
16357
16383
  function isSupportedEncoding(value) {
16358
16384
  return value === "utf8" || value === "utf8-bom" || value === "utf16le" || value === "utf16be" || value === "gbk" || value === "gb18030";
16359
16385
  }
@@ -16472,6 +16498,8 @@ function assertLikelyTextBuffer(buffer) {
16472
16498
  throw createTextError("GBK_BINARY_FILE", "\u7591\u4F3C\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\u6309\u6587\u672C\u5904\u7406");
16473
16499
  }
16474
16500
  function getNearestContext(content, oldString) {
16501
+ assertStringArgument2(content, "content");
16502
+ assertStringArgument2(oldString, "oldString");
16475
16503
  const lines = content.split(/\r?\n/);
16476
16504
  const oldLines = oldString.replace(/\r\n/g, "\n").split("\n").filter(Boolean);
16477
16505
  const firstToken = oldLines[0] || oldString.trim();
@@ -16483,6 +16511,8 @@ function getNearestContext(content, oldString) {
16483
16511
  return lines.slice(0, 4).join("\n");
16484
16512
  }
16485
16513
  function buildNoMatchMessage(content, oldString) {
16514
+ assertStringArgument2(content, "content");
16515
+ assertStringArgument2(oldString, "oldString");
16486
16516
  return [
16487
16517
  "\u672A\u627E\u5230\u9700\u8981\u66FF\u6362\u7684\u6587\u672C\u3002",
16488
16518
  "oldString \u5FC5\u987B\u4E0E\u6587\u4EF6\u5B9E\u9645\u5185\u5BB9\u5B8C\u5168\u5BF9\u5E94\u3002",
@@ -16490,6 +16520,105 @@ function buildNoMatchMessage(content, oldString) {
16490
16520
  getNearestContext(content, oldString)
16491
16521
  ].join("\n");
16492
16522
  }
16523
+ function findOccurrenceIndex(text, token, occurrence) {
16524
+ assertStringArgument2(text, "text");
16525
+ assertStringArgument2(token, "anchor");
16526
+ assertPositiveInteger(occurrence, "occurrence");
16527
+ if (token.length === 0) {
16528
+ throw createTextError("GBK_INVALID_ARGUMENT", "anchor \u4E0D\u80FD\u4E3A\u7A7A");
16529
+ }
16530
+ let count = 0;
16531
+ let searchFrom = 0;
16532
+ while (true) {
16533
+ const index = text.indexOf(token, searchFrom);
16534
+ if (index === -1) {
16535
+ break;
16536
+ }
16537
+ count += 1;
16538
+ if (count === occurrence) {
16539
+ return { index, total: countOccurrences(text, token) };
16540
+ }
16541
+ searchFrom = index + token.length;
16542
+ }
16543
+ if (count === 0) {
16544
+ throw createTextError("GBK_NO_MATCH", `\u672A\u627E\u5230\u951A\u70B9: ${token}`);
16545
+ }
16546
+ throw createTextError("GBK_NO_MATCH", `\u951A\u70B9 ${token} \u53EA\u627E\u5230 ${count} \u5904\uFF0C\u65E0\u6CD5\u4F7F\u7528\u7B2C ${occurrence} \u5904`);
16547
+ }
16548
+ function assertInsertArguments(input) {
16549
+ assertStringArgument2(input.anchor, "anchor");
16550
+ assertStringArgument2(input.content, "content");
16551
+ if (input.content.length === 0) {
16552
+ throw createTextError("GBK_INVALID_ARGUMENT", "content \u4E0D\u80FD\u4E3A\u7A7A");
16553
+ }
16554
+ if (input.replaceAll !== void 0) {
16555
+ throw createTextError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\u6301 replaceAll");
16556
+ }
16557
+ if (input.startLine !== void 0 || input.endLine !== void 0 || input.startAnchor !== void 0 || input.endAnchor !== void 0) {
16558
+ throw createTextError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u6A21\u5F0F\u4E0D\u652F\u6301 startLine/endLine/startAnchor/endAnchor");
16559
+ }
16560
+ }
16561
+ function buildLineDiffPreview(filePath, encoding, beforeText, afterText) {
16562
+ const beforeLines = normalizeNewlines(beforeText).split("\n");
16563
+ const afterLines = normalizeNewlines(afterText).split("\n");
16564
+ const maxLines = Math.max(beforeLines.length, afterLines.length);
16565
+ const lines = [
16566
+ `--- ${path3.basename(filePath)} (${encoding})`,
16567
+ `+++ ${path3.basename(filePath)} (${encoding})`
16568
+ ];
16569
+ for (let index = 0; index < maxLines; index += 1) {
16570
+ const before = beforeLines[index];
16571
+ const after = afterLines[index];
16572
+ if (before !== void 0 && after !== void 0 && before === after) {
16573
+ lines.push(` ${before}`);
16574
+ continue;
16575
+ }
16576
+ if (before !== void 0) {
16577
+ lines.push(`-${before}`);
16578
+ }
16579
+ if (after !== void 0) {
16580
+ lines.push(`+${after}`);
16581
+ }
16582
+ }
16583
+ return lines.join("\n");
16584
+ }
16585
+ function buildInsertOutput(text, mode, anchor, content, occurrence, ifExists, newlineStyle) {
16586
+ const alignedContent = alignTextToNewlineStyle(content, newlineStyle);
16587
+ const located = findOccurrenceIndex(text, anchor, occurrence);
16588
+ const insertionPoint = mode === "insertAfter" ? located.index + anchor.length : located.index;
16589
+ const alreadyExists = mode === "insertAfter" ? text.slice(insertionPoint, insertionPoint + alignedContent.length) === alignedContent : text.slice(Math.max(0, insertionPoint - alignedContent.length), insertionPoint) === alignedContent;
16590
+ if (alreadyExists) {
16591
+ if (ifExists === "error") {
16592
+ throw createTextError("GBK_INVALID_ARGUMENT", "\u63D2\u5165\u4F4D\u7F6E\u5DF2\u5B58\u5728\u76F8\u540C\u5185\u5BB9");
16593
+ }
16594
+ if (ifExists === "skip") {
16595
+ return {
16596
+ outputText: text,
16597
+ inserted: false,
16598
+ skipped: true,
16599
+ anchorMatches: located.total,
16600
+ occurrence,
16601
+ anchor,
16602
+ previewBefore: text.slice(Math.max(0, located.index - 80), Math.min(text.length, located.index + anchor.length + 80)),
16603
+ previewAfter: text.slice(Math.max(0, located.index - 80), Math.min(text.length, located.index + anchor.length + 80))
16604
+ };
16605
+ }
16606
+ }
16607
+ const outputText = `${text.slice(0, insertionPoint)}${alignedContent}${text.slice(insertionPoint)}`;
16608
+ const previewStart = Math.max(0, insertionPoint - 80);
16609
+ const previewBeforeEnd = Math.min(text.length, insertionPoint + 80);
16610
+ const previewAfterEnd = Math.min(outputText.length, insertionPoint + alignedContent.length + 80);
16611
+ return {
16612
+ outputText,
16613
+ inserted: true,
16614
+ skipped: false,
16615
+ anchorMatches: located.total,
16616
+ occurrence,
16617
+ anchor,
16618
+ previewBefore: text.slice(previewStart, previewBeforeEnd),
16619
+ previewAfter: outputText.slice(previewStart, previewAfterEnd)
16620
+ };
16621
+ }
16493
16622
  function detectTextEncodingFromBuffer(buffer, requestedEncoding = "auto") {
16494
16623
  if (requestedEncoding !== "auto") {
16495
16624
  assertTextEncodingSupported(requestedEncoding);
@@ -16665,6 +16794,7 @@ function resolveEditScope(text, input) {
16665
16794
  };
16666
16795
  }
16667
16796
  function alignTextToNewlineStyle(text, newlineStyle) {
16797
+ assertStringArgument2(text, "text");
16668
16798
  const normalized = text.replace(/\r\n/g, "\n");
16669
16799
  if (newlineStyle === "crlf") {
16670
16800
  return normalized.replace(/\n/g, "\r\n");
@@ -16675,6 +16805,7 @@ function alignTextToNewlineStyle(text, newlineStyle) {
16675
16805
  return text;
16676
16806
  }
16677
16807
  function ensureLossless(input, encoding, hasBom = encoding === "utf8-bom") {
16808
+ assertStringArgument2(input, "content");
16678
16809
  const buffer = encodeText(input, encoding, hasBom);
16679
16810
  const roundTrip = decodeText(buffer, encoding);
16680
16811
  if (roundTrip !== input) {
@@ -16682,43 +16813,100 @@ function ensureLossless(input, encoding, hasBom = encoding === "utf8-bom") {
16682
16813
  }
16683
16814
  }
16684
16815
  async function replaceTextFileText(input) {
16816
+ const mode = resolveEditMode(input.mode);
16685
16817
  const normalizedInput = {
16686
16818
  ...input,
16687
16819
  startLine: normalizeOptionalPositiveInteger(input.startLine, "startLine"),
16688
16820
  endLine: normalizeOptionalPositiveInteger(input.endLine, "endLine")
16689
16821
  };
16690
- if (input.oldString.length === 0) {
16691
- throw createTextError("GBK_EMPTY_OLD_STRING", "oldString \u4E0D\u80FD\u4E3A\u7A7A");
16692
- }
16693
16822
  const loaded = await readWholeTextFile({
16694
16823
  filePath: input.filePath,
16695
16824
  encoding: input.encoding ?? "auto",
16696
16825
  allowExternal: input.allowExternal,
16697
16826
  context: input.context
16698
16827
  });
16828
+ if (mode === "insertAfter" || mode === "insertBefore") {
16829
+ assertInsertArguments(normalizedInput);
16830
+ const occurrence = normalizeOptionalPositiveInteger(normalizedInput.occurrence, "occurrence") ?? 1;
16831
+ const insertResult = buildInsertOutput(
16832
+ loaded.content,
16833
+ mode,
16834
+ normalizedInput.anchor,
16835
+ normalizedInput.content,
16836
+ occurrence,
16837
+ resolveInsertIfExists(normalizedInput.ifExists),
16838
+ loaded.newlineStyle
16839
+ );
16840
+ if (insertResult.skipped) {
16841
+ return {
16842
+ mode,
16843
+ filePath: loaded.filePath,
16844
+ encoding: loaded.encoding,
16845
+ requestedEncoding: loaded.requestedEncoding,
16846
+ detectedEncoding: loaded.detectedEncoding,
16847
+ confidence: loaded.confidence,
16848
+ hasBom: loaded.hasBom,
16849
+ anchor: insertResult.anchor,
16850
+ occurrence: insertResult.occurrence,
16851
+ anchorMatches: insertResult.anchorMatches,
16852
+ inserted: false,
16853
+ skipped: true,
16854
+ bytesRead: loaded.bytesRead,
16855
+ bytesWritten: 0,
16856
+ newlineStyle: loaded.newlineStyle
16857
+ };
16858
+ }
16859
+ const targetEncoding2 = (normalizedInput.preserveEncoding ?? true) || (normalizedInput.encoding ?? "auto") === "auto" ? loaded.encoding : resolveExplicitTextEncoding(normalizedInput.encoding, loaded.encoding);
16860
+ const targetHasBom2 = normalizedInput.preserveEncoding === false ? targetEncoding2 === "utf8-bom" || targetEncoding2 === "utf16le" || targetEncoding2 === "utf16be" : loaded.hasBom;
16861
+ ensureLossless(insertResult.outputText, targetEncoding2, targetHasBom2);
16862
+ const buffer2 = encodeText(insertResult.outputText, targetEncoding2, targetHasBom2);
16863
+ await fs3.writeFile(loaded.filePath, buffer2);
16864
+ return {
16865
+ mode,
16866
+ filePath: loaded.filePath,
16867
+ encoding: targetEncoding2,
16868
+ requestedEncoding: loaded.requestedEncoding,
16869
+ detectedEncoding: loaded.detectedEncoding,
16870
+ confidence: loaded.confidence,
16871
+ hasBom: targetHasBom2,
16872
+ anchor: insertResult.anchor,
16873
+ occurrence: insertResult.occurrence,
16874
+ anchorMatches: insertResult.anchorMatches,
16875
+ inserted: true,
16876
+ skipped: false,
16877
+ bytesRead: loaded.bytesRead,
16878
+ bytesWritten: buffer2.byteLength,
16879
+ newlineStyle: detectNewlineStyle(insertResult.outputText)
16880
+ };
16881
+ }
16882
+ assertReplaceArguments(input);
16883
+ if (input.oldString.length === 0) {
16884
+ throw createTextError("GBK_EMPTY_OLD_STRING", "oldString \u4E0D\u80FD\u4E3A\u7A7A");
16885
+ }
16699
16886
  const scope = resolveEditScope(loaded.content, normalizedInput);
16700
16887
  const replaceAll = normalizedInput.replaceAll ?? false;
16701
16888
  const preserveEncoding = normalizedInput.preserveEncoding ?? true;
16702
16889
  const requestedEncoding = normalizedInput.encoding ?? "auto";
16703
- const occurrencesBefore = countOccurrences(scope.selectedText, normalizedInput.oldString);
16890
+ const occurrencesBefore = countOccurrences(scope.selectedText, input.oldString);
16704
16891
  if (replaceAll) {
16705
16892
  if (occurrencesBefore === 0) {
16706
- throw createTextError("GBK_NO_MATCH", buildNoMatchMessage(scope.selectedText, normalizedInput.oldString));
16893
+ throw createTextError("GBK_NO_MATCH", buildNoMatchMessage(scope.selectedText, input.oldString));
16707
16894
  }
16708
16895
  } else if (occurrencesBefore === 0) {
16709
- throw createTextError("GBK_NO_MATCH", buildNoMatchMessage(scope.selectedText, normalizedInput.oldString));
16896
+ throw createTextError("GBK_NO_MATCH", buildNoMatchMessage(scope.selectedText, input.oldString));
16710
16897
  } else if (occurrencesBefore > 1) {
16711
- throw createTextError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\u9879: ${normalizedInput.oldString}`);
16898
+ throw createTextError("GBK_MULTIPLE_MATCHES", `\u627E\u5230\u591A\u4E2A\u5339\u914D\u9879: ${input.oldString}`);
16712
16899
  }
16713
- const alignedNewString = normalizedInput.preserveNewlineStyle === false ? normalizedInput.newString : alignTextToNewlineStyle(normalizedInput.newString, loaded.newlineStyle);
16714
- const replaced = replaceAll ? scope.selectedText.split(normalizedInput.oldString).join(alignedNewString) : scope.selectedText.replace(normalizedInput.oldString, alignedNewString);
16900
+ const alignedNewString = normalizedInput.preserveNewlineStyle === false ? input.newString : alignTextToNewlineStyle(input.newString, loaded.newlineStyle);
16901
+ const replaced = replaceAll ? scope.selectedText.split(input.oldString).join(alignedNewString) : scope.selectedText.replace(input.oldString, alignedNewString);
16715
16902
  const outputText = `${loaded.content.slice(0, scope.rangeStart)}${replaced}${loaded.content.slice(scope.rangeEnd)}`;
16716
- const targetEncoding = preserveEncoding || requestedEncoding === "auto" ? loaded.encoding : requestedEncoding;
16903
+ const targetEncoding = preserveEncoding || requestedEncoding === "auto" ? loaded.encoding : resolveExplicitTextEncoding(requestedEncoding, loaded.encoding);
16717
16904
  const targetHasBom = preserveEncoding ? loaded.hasBom : targetEncoding === "utf8-bom" || targetEncoding === "utf16le" || targetEncoding === "utf16be";
16718
16905
  ensureLossless(outputText, targetEncoding, targetHasBom);
16719
16906
  const buffer = encodeText(outputText, targetEncoding, targetHasBom);
16720
16907
  await fs3.writeFile(loaded.filePath, buffer);
16721
16908
  return {
16909
+ mode: "replace",
16722
16910
  filePath: loaded.filePath,
16723
16911
  encoding: targetEncoding,
16724
16912
  requestedEncoding: loaded.requestedEncoding,
@@ -16733,40 +16921,39 @@ async function replaceTextFileText(input) {
16733
16921
  };
16734
16922
  }
16735
16923
  async function createTextDiffPreview(input) {
16924
+ const mode = resolveEditMode(input.mode);
16736
16925
  const loaded = await readWholeTextFile({
16737
16926
  filePath: input.filePath,
16738
16927
  encoding: input.encoding ?? "auto",
16739
16928
  allowExternal: input.allowExternal,
16740
16929
  context: input.context
16741
16930
  });
16931
+ if (mode === "insertAfter" || mode === "insertBefore") {
16932
+ assertInsertArguments(input);
16933
+ const occurrence = normalizeOptionalPositiveInteger(input.occurrence, "occurrence") ?? 1;
16934
+ const insertResult = buildInsertOutput(
16935
+ loaded.content,
16936
+ mode,
16937
+ input.anchor,
16938
+ input.content,
16939
+ occurrence,
16940
+ resolveInsertIfExists(input.ifExists),
16941
+ loaded.newlineStyle
16942
+ );
16943
+ return {
16944
+ filePath: loaded.filePath,
16945
+ encoding: loaded.encoding,
16946
+ preview: buildLineDiffPreview(loaded.filePath, loaded.encoding, insertResult.previewBefore, insertResult.previewAfter)
16947
+ };
16948
+ }
16949
+ assertReplaceArguments(input);
16742
16950
  const scope = resolveEditScope(loaded.content, input);
16743
16951
  const alignedNewString = alignTextToNewlineStyle(input.newString, loaded.newlineStyle);
16744
16952
  const replaced = input.replaceAll ?? false ? scope.selectedText.split(input.oldString).join(alignedNewString) : scope.selectedText.replace(input.oldString, alignedNewString);
16745
- const beforeLines = normalizeNewlines(scope.selectedText).split("\n");
16746
- const afterLines = normalizeNewlines(replaced).split("\n");
16747
- const maxLines = Math.max(beforeLines.length, afterLines.length);
16748
- const lines = [
16749
- `--- ${path3.basename(loaded.filePath)} (${loaded.encoding})`,
16750
- `+++ ${path3.basename(loaded.filePath)} (${loaded.encoding})`
16751
- ];
16752
- for (let index = 0; index < maxLines; index += 1) {
16753
- const before = beforeLines[index];
16754
- const after = afterLines[index];
16755
- if (before !== void 0 && after !== void 0 && before === after) {
16756
- lines.push(` ${before}`);
16757
- continue;
16758
- }
16759
- if (before !== void 0) {
16760
- lines.push(`-${before}`);
16761
- }
16762
- if (after !== void 0) {
16763
- lines.push(`+${after}`);
16764
- }
16765
- }
16766
16953
  return {
16767
16954
  filePath: loaded.filePath,
16768
16955
  encoding: loaded.encoding,
16769
- preview: lines.join("\n")
16956
+ preview: buildLineDiffPreview(loaded.filePath, loaded.encoding, scope.selectedText, replaced)
16770
16957
  };
16771
16958
  }
16772
16959
 
@@ -16776,11 +16963,17 @@ var text_edit_default = tool({
16776
16963
 
16777
16964
  - Existing files keep their original encoding and BOM by default.
16778
16965
  - Existing newline style is preserved by default.
16779
- - Use startLine/endLine or anchors to narrow the edit scope.`,
16966
+ - Replace mode uses oldString/newString.
16967
+ - Insert mode uses mode=insertAfter or insertBefore with anchor/content.`,
16780
16968
  args: {
16781
16969
  filePath: tool.schema.string().describe("Target file path"),
16782
- oldString: tool.schema.string().describe("Exact text to replace"),
16783
- newString: tool.schema.string().describe("Replacement text"),
16970
+ mode: tool.schema.enum(["replace", "insertAfter", "insertBefore"]).optional().describe("Edit mode, default replace"),
16971
+ oldString: tool.schema.string().optional().describe("Exact text to replace when mode=replace"),
16972
+ newString: tool.schema.string().optional().describe("Replacement text when mode=replace"),
16973
+ anchor: tool.schema.string().optional().describe("Anchor text used by insertAfter/insertBefore"),
16974
+ content: tool.schema.string().optional().describe("Inserted content used by insertAfter/insertBefore"),
16975
+ occurrence: tool.schema.number().int().positive().optional().describe("1-based anchor occurrence for insert mode"),
16976
+ ifExists: tool.schema.enum(["allow", "skip", "error"]).optional().describe("What to do when inserted content already exists at target position"),
16784
16977
  replaceAll: tool.schema.boolean().optional().describe("Replace all occurrences"),
16785
16978
  startLine: tool.schema.number().int().positive().optional().describe("Start line for scoped edit"),
16786
16979
  endLine: tool.schema.number().int().positive().optional().describe("End line for scoped edit"),
@@ -16794,16 +16987,23 @@ var text_edit_default = tool({
16794
16987
  async execute(args, context) {
16795
16988
  const result = await replaceTextFileText({ ...args, context });
16796
16989
  const preview = await createTextDiffPreview({ ...args, context });
16990
+ const title = result.mode === "replace" ? `\u6587\u672C\u7F16\u8F91 ${result.encoding.toUpperCase()} x${result.replacements}` : result.inserted ? `\u6587\u672C\u63D2\u5165 ${result.encoding.toUpperCase()} #${result.occurrence}` : `\u6587\u672C\u8DF3\u8FC7 ${result.encoding.toUpperCase()} #${result.occurrence}`;
16797
16991
  context.metadata({
16798
- title: `\u6587\u672C\u7F16\u8F91 ${result.encoding.toUpperCase()} x${result.replacements}`,
16992
+ title,
16799
16993
  metadata: {
16800
16994
  filePath: result.filePath,
16801
16995
  encoding: result.encoding,
16802
16996
  requestedEncoding: result.requestedEncoding,
16803
16997
  confidence: result.confidence,
16804
16998
  hasBom: result.hasBom,
16805
- replacements: result.replacements,
16806
- occurrencesBefore: result.occurrencesBefore,
16999
+ mode: result.mode,
17000
+ replacements: result.mode === "replace" ? result.replacements : void 0,
17001
+ occurrencesBefore: result.mode === "replace" ? result.occurrencesBefore : void 0,
17002
+ anchor: result.mode === "replace" ? void 0 : result.anchor,
17003
+ occurrence: result.mode === "replace" ? void 0 : result.occurrence,
17004
+ anchorMatches: result.mode === "replace" ? void 0 : result.anchorMatches,
17005
+ inserted: result.mode === "replace" ? void 0 : result.inserted,
17006
+ skipped: result.mode === "replace" ? void 0 : result.skipped,
16807
17007
  newlineStyle: result.newlineStyle,
16808
17008
  diffPreview: preview.preview
16809
17009
  }
@@ -16327,6 +16327,11 @@ function detectNewlineStyle(text) {
16327
16327
  // src/lib/text-file.ts
16328
16328
  var TEXT_STREAMING_FILE_SIZE_THRESHOLD_BYTES = 1024 * 1024;
16329
16329
  var UTF8_DECODER = new TextDecoder("utf-8", { fatal: true });
16330
+ function assertStringArgument(value, name) {
16331
+ if (typeof value !== "string") {
16332
+ throw createTextError("GBK_INVALID_ARGUMENT", `${name} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32`);
16333
+ }
16334
+ }
16330
16335
  function isSupportedEncoding(value) {
16331
16336
  return value === "utf8" || value === "utf8-bom" || value === "utf16le" || value === "utf16be" || value === "gbk" || value === "gb18030";
16332
16337
  }
@@ -16535,6 +16540,7 @@ async function readWholeTextFile(input) {
16535
16540
  }
16536
16541
  }
16537
16542
  function alignTextToNewlineStyle(text, newlineStyle) {
16543
+ assertStringArgument(text, "text");
16538
16544
  const normalized = text.replace(/\r\n/g, "\n");
16539
16545
  if (newlineStyle === "crlf") {
16540
16546
  return normalized.replace(/\n/g, "\r\n");
@@ -16545,6 +16551,7 @@ function alignTextToNewlineStyle(text, newlineStyle) {
16545
16551
  return text;
16546
16552
  }
16547
16553
  function ensureLossless(input, encoding, hasBom = encoding === "utf8-bom") {
16554
+ assertStringArgument(input, "content");
16548
16555
  const buffer = encodeText(input, encoding, hasBom);
16549
16556
  const roundTrip = decodeText(buffer, encoding);
16550
16557
  if (roundTrip !== input) {
@@ -16569,6 +16576,7 @@ async function ensureParentDirectory(parent, createDirectories) {
16569
16576
  }
16570
16577
  }
16571
16578
  async function writeTextFile(input) {
16579
+ assertStringArgument(input.content, "content");
16572
16580
  const requestedEncoding = input.encoding ?? "auto";
16573
16581
  assertTextEncodingSupported(requestedEncoding);
16574
16582
  const preserveEncoding = input.preserveEncoding ?? true;