codexslimedit 0.7.4-dev.29700855995.1 → 0.7.4-dev.29702371652.1

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/mcp.js +71 -19
  2. package/package.json +1 -1
package/dist/mcp.js CHANGED
@@ -4523,6 +4523,7 @@ async function readWorkspaceFile(input) {
4523
4523
  async function editWorkspaceFile(input) {
4524
4524
  const target = await resolveWorkspaceFile(input);
4525
4525
  const nextContent = replaceContent(await readUtf8Text(target.absolutePath), input.oldString, input.newString);
4526
+ validateText(nextContent);
4526
4527
  await atomicWrite(target.absolutePath, nextContent);
4527
4528
  return {
4528
4529
  path: target.relativePath,
@@ -4562,6 +4563,15 @@ async function createWorkspaceFile(input) {
4562
4563
  content: input.content
4563
4564
  };
4564
4565
  }
4566
+ /** Validates a new workspace file without modifying the workspace. */
4567
+ async function prepareWorkspaceFileCreation(input) {
4568
+ const target = await resolveNewWorkspaceFile(input, false);
4569
+ validateText(input.content);
4570
+ return {
4571
+ path: target.relativePath,
4572
+ content: input.content
4573
+ };
4574
+ }
4565
4575
  /** Deletes one existing regular workspace file. */
4566
4576
  async function deleteWorkspaceFile(input) {
4567
4577
  const target = await resolveWorkspaceFile(input);
@@ -4587,7 +4597,7 @@ async function resolveWorkspaceFile(input) {
4587
4597
  relativePath: relative(rootPath, resolvedCandidate).split(sep).join("/")
4588
4598
  };
4589
4599
  }
4590
- async function resolveNewWorkspaceFile(input) {
4600
+ async function resolveNewWorkspaceFile(input, createParent = true) {
4591
4601
  const rootPath = await existingDirectory(input.root);
4592
4602
  const candidate = resolve(rootPath, normalizeSeparators(input.filePath));
4593
4603
  if (!isInside(rootPath, candidate)) throw new WorkspaceFileError("PATH_OUTSIDE_ROOT", "filePath must remain inside the workspace root.");
@@ -4597,13 +4607,13 @@ async function resolveNewWorkspaceFile(input) {
4597
4607
  } catch (error) {
4598
4608
  if (error instanceof WorkspaceFileError) throw error;
4599
4609
  }
4600
- const absolutePath = resolve(await createSafeParent(rootPath, dirname(candidate)), basename(candidate));
4610
+ const absolutePath = resolve(await safeParent(rootPath, dirname(candidate), createParent), basename(candidate));
4601
4611
  return {
4602
4612
  absolutePath,
4603
4613
  relativePath: relative(rootPath, absolutePath).split(sep).join("/")
4604
4614
  };
4605
4615
  }
4606
- async function createSafeParent(rootPath, requestedParent) {
4616
+ async function safeParent(rootPath, requestedParent, createParent) {
4607
4617
  const missingDirectories = [];
4608
4618
  let existingParent = requestedParent;
4609
4619
  while (true) try {
@@ -4616,7 +4626,7 @@ async function createSafeParent(rootPath, requestedParent) {
4616
4626
  }
4617
4627
  if (existingParent !== rootPath && !isInside(rootPath, existingParent)) throw new WorkspaceFileError("PATH_OUTSIDE_ROOT", "filePath parent resolves outside the workspace root through a symlink.");
4618
4628
  const parentPath = resolve(existingParent, ...missingDirectories.reverse());
4619
- await mkdir(parentPath, { recursive: true });
4629
+ if (createParent) await mkdir(parentPath, { recursive: true });
4620
4630
  return parentPath;
4621
4631
  }
4622
4632
  async function existingDirectory(root) {
@@ -4765,38 +4775,69 @@ function message(error) {
4765
4775
  /** Applies Codex add, update, and delete patch operations inside a workspace. */
4766
4776
  async function applyWorkspacePatch(input) {
4767
4777
  const operations = parsePatch(input.patch);
4778
+ const planned = await planOperations(input.root, operations);
4768
4779
  const paths = [];
4769
- for (const operation of operations) {
4780
+ for (const { operation, path, content } of planned) {
4770
4781
  if (operation.kind === "add") {
4771
- const result = await createWorkspaceFile({
4782
+ await createWorkspaceFile({
4772
4783
  root: input.root,
4773
4784
  filePath: operation.filePath,
4774
4785
  content: operation.content
4775
4786
  });
4776
- paths.push(result.path);
4787
+ paths.push(path);
4777
4788
  continue;
4778
4789
  }
4779
4790
  if (operation.kind === "delete") {
4780
- const result = await deleteWorkspaceFile({
4791
+ await deleteWorkspaceFile({
4781
4792
  root: input.root,
4782
4793
  filePath: operation.filePath
4783
4794
  });
4784
- paths.push(result.path);
4795
+ paths.push(path);
4785
4796
  continue;
4786
4797
  }
4787
- const current = await readWorkspaceFile({
4788
- root: input.root,
4789
- filePath: operation.filePath
4790
- });
4791
- const result = await writeWorkspaceFile({
4798
+ await writeWorkspaceFile({
4792
4799
  root: input.root,
4793
4800
  filePath: operation.filePath,
4794
- content: applyUpdateHunks(current.content, operation.hunks)
4801
+ content: content ?? ""
4795
4802
  });
4796
- paths.push(result.path);
4803
+ paths.push(path);
4797
4804
  }
4798
4805
  return { paths };
4799
4806
  }
4807
+ async function planOperations(root, operations) {
4808
+ const planned = [];
4809
+ const paths = /* @__PURE__ */ new Set();
4810
+ for (const operation of operations) {
4811
+ if (operation.kind === "add") {
4812
+ const result = await prepareWorkspaceFileCreation({
4813
+ root,
4814
+ filePath: operation.filePath,
4815
+ content: operation.content
4816
+ });
4817
+ assertUniquePath(paths, result.path);
4818
+ planned.push({
4819
+ operation,
4820
+ path: result.path
4821
+ });
4822
+ continue;
4823
+ }
4824
+ const current = await readWorkspaceFile({
4825
+ root,
4826
+ filePath: operation.filePath
4827
+ });
4828
+ assertUniquePath(paths, current.path);
4829
+ planned.push({
4830
+ operation,
4831
+ path: current.path,
4832
+ content: operation.kind === "update" ? applyUpdateHunks(current.content, operation.hunks) : void 0
4833
+ });
4834
+ }
4835
+ return planned;
4836
+ }
4837
+ function assertUniquePath(paths, path) {
4838
+ if (paths.has(path)) invalidPatch(`Patch contains multiple operations for ${path}.`);
4839
+ paths.add(path);
4840
+ }
4800
4841
  function parsePatch(patch) {
4801
4842
  const lines = patch.replace(/\r\n|\r/g, "\n").split("\n");
4802
4843
  while (lines.at(-1) === "") lines.pop();
@@ -4811,8 +4852,12 @@ function parsePatch(patch) {
4811
4852
  index += 1;
4812
4853
  if (addPath !== void 0) {
4813
4854
  const contentLines = [];
4814
- while (index < lines.length - 1 && !lines[index]?.startsWith("*** ")) {
4855
+ while (index < lines.length - 1 && !isOperationHeader(lines[index])) {
4815
4856
  const line = lines[index];
4857
+ if (line === "*** End of File") {
4858
+ index += 1;
4859
+ break;
4860
+ }
4816
4861
  if (!line?.startsWith("+")) invalidPatch("Add File lines must start with `+`.");
4817
4862
  contentLines.push(line.slice(1));
4818
4863
  index += 1;
@@ -4835,8 +4880,12 @@ function parsePatch(patch) {
4835
4880
  const hunks = [];
4836
4881
  let oldLines;
4837
4882
  let newLines;
4838
- while (index < lines.length - 1 && !lines[index]?.startsWith("*** ")) {
4883
+ while (index < lines.length - 1 && !isOperationHeader(lines[index])) {
4839
4884
  const line = lines[index];
4885
+ if (line === "*** End of File") {
4886
+ index += 1;
4887
+ break;
4888
+ }
4840
4889
  if (line?.startsWith("@@")) {
4841
4890
  if (oldLines !== void 0 && newLines !== void 0) hunks.push(validHunk(oldLines, newLines));
4842
4891
  oldLines = [];
@@ -4866,6 +4915,9 @@ function parsePatch(patch) {
4866
4915
  if (operations.length === 0) invalidPatch("Patch must contain at least one file operation.");
4867
4916
  return operations;
4868
4917
  }
4918
+ function isOperationHeader(line) {
4919
+ return /^\*\*\* (?:Add|Update|Delete) File: /.test(line ?? "");
4920
+ }
4869
4921
  function validHunk(oldLines, newLines) {
4870
4922
  if (oldLines.length === 0) invalidPatch("Update hunks require old or context lines for deterministic placement.");
4871
4923
  return {
@@ -4906,7 +4958,7 @@ function invalidPatch(message) {
4906
4958
  //#endregion
4907
4959
  //#region src/version.ts
4908
4960
  /** Current independent codexslimedit package version. */
4909
- var CODEX_SLIM_EDIT_VERSION = "0.7.4-dev.29700855995.1";
4961
+ var CODEX_SLIM_EDIT_VERSION = "0.7.4-dev.29702371652.1";
4910
4962
  /** Returns whether command-line arguments request the package version. */
4911
4963
  function isVersionRequest(args) {
4912
4964
  return args.includes("--version");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codexslimedit",
3
- "version": "0.7.4-dev.29700855995.1",
3
+ "version": "0.7.4-dev.29702371652.1",
4
4
  "description": "Concise, workspace-safe MCP file reading and editing.",
5
5
  "license": "SUL-1.0",
6
6
  "repository": {