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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ The extension detects outdated CLI builds and warns with upgrade guidance. It re
Set `patchloom.path` in settings, or add the CLI to your `PATH`.

**CLI compatibility warning**
Run `Patchloom: Open Releases` to download the latest release. The extension requires 0.3.0 or newer; 0.7.0 is recommended.
Run `Patchloom: Open Releases` to download the latest release. The extension requires 0.3.0 or newer; 0.10.0 is recommended.

**MCP config not injected**
Run `Patchloom: Configure MCP` and select the target editor config.
Expand Down Expand Up @@ -183,7 +183,7 @@ File bugs and feature requests at [patchloom/patchloom-vscode/issues](https://gi
## Requirements

- VS Code 1.90 or newer (or compatible editors: Cursor, Windsurf, VSCodium)
- [Patchloom CLI](https://github.com/patchloom/patchloom) 0.3.0 or newer (0.7.0+ recommended for 43 MCP tools, LLM-aligned CLI arguments, post-write formatter hook, and transaction engine unification)
- [Patchloom CLI](https://github.com/patchloom/patchloom) 0.3.0 or newer (0.10.0+ recommended for 54 MCP tools, correct preview exit codes, optional `--contain` path guarding, schema-driven MCP descriptions, and agent reliability fixes)

## Contributing

Expand Down
18 changes: 14 additions & 4 deletions src/commands/quickActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ export async function runQuickAction(): Promise<void> {
{
label: "Create a new file",
description: "Scaffold a new file in the workspace",
detail: "Builds `patchloom create <path>`",
detail: "Builds `patchloom create <path> --content <text> --apply`",
run: async () => {
const folder = await activeWorkspaceFolder({
promptIfMany: true,
Expand All @@ -230,7 +230,16 @@ export async function runQuickAction(): Promise<void> {
return;
}

const action = buildCreateQuickAction(absolutePath);
// Empty content is allowed; CLI requires --content or --stdin and --apply to write.
const content = await vscode.window.showInputBox({
prompt: "Initial file content (leave empty for an empty file)",
placeHolder: "// new file"
});
if (content === undefined) {
return;
}

const action = buildCreateQuickAction(absolutePath, content);
const result = await executePatchloom(binaryPath, action.args, folder.uri.fsPath);

if (result.exitCode !== 0) {
Expand Down Expand Up @@ -858,12 +867,13 @@ export function buildSearchQuickAction(workspacePath: string, pattern: string, g
};
}

export function buildCreateQuickAction(filePath: string): PlannedQuickAction {
export function buildCreateQuickAction(filePath: string, content = ""): PlannedQuickAction {
return {
title: `Create ${path.basename(filePath)}`,
targetPath: filePath,
targetArgIndices: [1],
args: ["create", filePath]
// CLI requires --content/--stdin and --apply; preview-only create returns exit 2 and does not write.
args: ["create", filePath, "--content", content, "--apply"]
};
}

Expand Down
43 changes: 36 additions & 7 deletions test/unit/quickActions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,31 @@ test("buildSearchQuickAction includes glob when provided", () => {
assert.deepEqual(action.targetArgIndices, [4]);
});

test("buildCreateQuickAction builds a create command", () => {
const action = buildCreateQuickAction("/workspace/demo/src/newfile.ts");
test("buildCreateQuickAction builds a create command with content and apply", () => {
const action = buildCreateQuickAction("/workspace/demo/src/newfile.ts", "hello");

assert.equal(action.title, "Create newfile.ts");
assert.deepEqual(action.args, ["create", "/workspace/demo/src/newfile.ts"]);
assert.deepEqual(action.args, [
"create",
"/workspace/demo/src/newfile.ts",
"--content",
"hello",
"--apply"
]);
assert.deepEqual(action.targetArgIndices, [1]);
});

test("buildCreateQuickAction allows empty content", () => {
const action = buildCreateQuickAction("/workspace/demo/empty.txt");
assert.deepEqual(action.args, [
"create",
"/workspace/demo/empty.txt",
"--content",
"",
"--apply"
]);
});

test("buildSearchQuickAction preserves spaces in pattern as a single arg", () => {
const action = buildSearchQuickAction("/workspace/demo", "hello world");

Expand Down Expand Up @@ -220,9 +237,15 @@ test("buildSearchQuickAction with regex special characters", () => {
});

test("buildCreateQuickAction with spaces in path", () => {
const action = buildCreateQuickAction("/workspace/my project/src/new file.ts");
const action = buildCreateQuickAction("/workspace/my project/src/new file.ts", "x");
assert.equal(action.title, "Create new file.ts");
assert.deepEqual(action.args, ["create", "/workspace/my project/src/new file.ts"]);
assert.deepEqual(action.args, [
"create",
"/workspace/my project/src/new file.ts",
"--content",
"x",
"--apply"
]);
});

test("buildDocGetQuickAction with deeply nested selector", () => {
Expand All @@ -232,9 +255,15 @@ test("buildDocGetQuickAction with deeply nested selector", () => {
});

test("buildCreateQuickAction with unicode filename", () => {
const action = buildCreateQuickAction("/workspace/demo/docs/日本語.md");
const action = buildCreateQuickAction("/workspace/demo/docs/日本語.md", "# title");
assert.equal(action.title, "Create 日本語.md");
assert.deepEqual(action.args, ["create", "/workspace/demo/docs/日本語.md"]);
assert.deepEqual(action.args, [
"create",
"/workspace/demo/docs/日本語.md",
"--content",
"# title",
"--apply"
]);
});

test("buildSearchQuickAction with unicode pattern", () => {
Expand Down
Loading