Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/remove-file-tool-char-limits.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@perstack/base": patch
---

Remove character limits from file operation tools

The following tools no longer have character limits:
- writeTextFile: removed 10,000 character limit
- appendTextFile: removed 2,000 character limit
- editTextFile: removed 2,000 character limit for both newText and oldText

4 changes: 2 additions & 2 deletions knip.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"$schema": "https://unpkg.com/knip@5/schema.json",
"ignoreDependencies": ["@tsconfig/node22", "vitest", "ts-dedent"],
"ignoreExportsUsedInFile": true,
"ignoreBinaries": [],
"ignore": ["dist/**/*", "**/*.test.ts", "**/*.test.tsx", "docs/content/**/*", "scripts/**/*"],
"ignoreBinaries": ["perstack"],
"ignore": ["dist/**/*", "**/*.test.ts", "**/*.test.tsx", "docs/content/**/*", "scripts/**/*", "examples/**/*"],
"workspaces": {
"packages/perstack": {
"entry": ["bin/cli.ts", "src/**/*.ts"]
Expand Down
8 changes: 1 addition & 7 deletions packages/base/src/tools/append-text-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,10 @@ export function registerAppendTextFile(server: McpServer) {
Rules:
- FILE MUST EXIST BEFORE APPENDING
- YOU MUST PROVIDE A VALID UTF-8 STRING FOR THE TEXT
- THERE IS A LIMIT ON THE NUMBER OF TOKENS THAT CAN BE GENERATED, SO DO NOT APPEND ALL THE CONTENT AT ONCE
- IF YOU WANT TO APPEND MORE THAN 2000 CHARACTERS, USE THIS TOOL MULTIPLE TIMES
`,
inputSchema: {
path: z.string().describe("Target file path to append to."),
text: z
.string()
.min(1)
.max(2_000)
.describe("Text to append to the file. Max 2000 characters."),
text: z.string().describe("Text to append to the file."),
},
},
async ({ path, text }: { path: string; text: string }) => {
Expand Down
14 changes: 2 additions & 12 deletions packages/base/src/tools/edit-text-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,22 +61,12 @@ export function registerEditTextFile(server: McpServer) {

Rules:
- YOU MUST PROVIDE A VALID UTF-8 STRING FOR THE TEXT
- THERE IS A LIMIT ON THE NUMBER OF TOKENS THAT CAN BE GENERATED, SO DO NOT WRITE ALL THE CONTENT AT ONCE (IT WILL CAUSE AN ERROR)
- IF YOU WANT TO EDIT MORE THAN 2000 CHARACTERS, USE THIS TOOL MULTIPLE TIMES
- DO NOT USE THIS TOOL FOR APPENDING TEXT TO FILES - USE appendTextFile TOOL INSTEAD
`,
inputSchema: {
path: z.string().describe("Target file path to edit."),
newText: z
.string()
.min(1)
.max(2_000)
.describe("Text to append to the file. Max 2000 characters."),
oldText: z
.string()
.min(1)
.max(2_000)
.describe("Exact text to find and replace. Max 2000 characters."),
newText: z.string().describe("Text to replace with."),
oldText: z.string().describe("Exact text to find and replace."),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Empty oldText causes unintended prepend behavior

Removing .min(1) validation from oldText allows empty strings to be passed. In JavaScript, "any string".includes("") always returns true, and "any string".replace("", newText) prepends newText to the beginning of the content rather than performing a find-and-replace. This means passing an empty oldText will silently prepend content to the file instead of throwing an error, which is almost certainly not the intended behavior for a text replacement operation.

Fix in Cursor Fix in Web

},
},
async (input: { path: string; newText: string; oldText: string }) => {
Expand Down
4 changes: 1 addition & 3 deletions packages/base/src/tools/write-text-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,10 @@ export function registerWriteTextFile(server: McpServer) {
Rules:
- IF THE FILE ALREADY EXISTS, IT WILL BE OVERWRITTEN
- YOU MUST PROVIDE A VALID UTF-8 STRING FOR THE TEXT
- THERE IS A LIMIT ON THE NUMBER OF TOKENS THAT CAN BE GENERATED, SO DO NOT WRITE ALL THE CONTENT AT ONCE (IT WILL CAUSE AN ERROR)
- IF YOU WANT TO WRITE MORE THAN 10,000 CHARACTERS, USE "appendTextFile" TOOL AFTER THIS ONE
`,
inputSchema: {
path: z.string().describe("Target file path (relative or absolute)."),
text: z.string().max(10_000).describe("Text to write to the file. Max 10000 characters."),
text: z.string().describe("Text to write to the file."),
},
},
async (input: { path: string; text: string }) => {
Expand Down