diff --git a/AGENTS.md b/AGENTS.md index c80a677..9e19c62 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -37,6 +37,7 @@ src/ batchApply.ts Batch Apply command: atomic multi-operation plan via JSON setupWorkspace.ts Setup Workspace command: guided readiness walkthrough showStatus.ts Show Status command: diagnostics display + verifyMcp.ts Verify MCP Server command: JSON-RPC initialize probe autoUpdate.ts Auto-update check on activation: compare installed vs latest release install/managed.ts Managed install safety: checksum, staging, promotion, rollback, persistence logging/outputChannel.ts Output channel wrapper: log, logCommand, logResult, show, dispose @@ -50,11 +51,11 @@ test/ batchApply.test.ts Batch template and operation count parsing (15 tests) binary.test.ts Binary discovery, managed install, compatibility, workspace env (59 tests) binaryDiscovery.test.ts Real executable discovery on PATH (13 tests) - initializeProject.test.ts Status display, agents file classification, formatError (29 tests) + initializeProject.test.ts Status display, agents file classification, formatError (30 tests) managedLifecycle.test.ts Managed install with real file I/O (22 tests) mcpConfig.test.ts MCP config with real temp directories (9 tests) outputChannel.test.ts Output channel logging wrapper (10 tests) - patchloomCli.test.ts Patchloom CLI integration with real binary + managed install e2e MCP (37 tests incl. e2e) + patchloomCli.test.ts Patchloom CLI integration with real binary + managed install e2e MCP (39 tests incl. e2e) propertyBased.test.ts Property-based tests with fast-check (13 tests) quickActions.test.ts Quick action command building, path containment, patch merge (57 tests) verifyMcp.test.ts MCP server verify and JSON-RPC response parsing (15 tests) @@ -66,6 +67,7 @@ test/ extension.test.ts ExTester UI tests (status bar, command palette) scripts/ hide-test-vscode.sh macOS: patch test VS Code to suppress window activation + guard-no-release-merge.sh Hard abort if agent tries to merge a release PR without approval .github/ CODEOWNERS Owner for all files copilot-instructions.md Pointer to AGENTS.md for GitHub Copilot diff --git a/README.md b/README.md index fc2e067..30c89be 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,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.18.0 is recommended. +Run `Patchloom: Open Releases` to download the latest release. The extension requires 0.3.0 or newer; 0.19.0 is recommended. **Path rejected by workspace guard** Quick Actions and Batch Apply pass `--contain` so paths stay inside the open workspace folder. On CLI 0.18+, sandbox escapes report `error_kind: guard_rejected` (not a generic `invalid_input`). Keep targets under the workspace root, or open the folder that owns the files. @@ -178,6 +178,9 @@ Quick Actions and Batch Apply pass `--contain` so paths stay inside the open wor **Batch replace shape** Batch lines use `replace PATH OLD NEW` (and optional flags such as `--fuzzy`). Do not paste CLI form `replace OLD --new NEW path` into a batch plan; CLI 0.18+ returns a clear parse error with the PATH OLD NEW hint. +**Create or rename destination already exists** +On CLI 0.19+, create/rename conflicts report `error_kind: already_exists` (not a generic `invalid_input`). Use the force flag when overwriting is intentional, or pick a free destination path. + **MCP config not injected** Run `Patchloom: Configure MCP` and select the target editor config. @@ -211,7 +214,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.18.0+ recommended for structured `guard_rejected` on `--contain` failures, clearer batch `replace PATH OLD NEW` parse hints, multi-doc `doc merge --selector`, line-oriented `insert_before`/`insert_after`, 56 MCP tools, JSON `applied` honesty, and agent-facing `error_kind` envelopes) +- [Patchloom CLI](https://github.com/patchloom/patchloom) 0.3.0 or newer (0.19.0+ recommended for stable `error_kind` peels including `already_exists` / `not_found` / `guard_rejected`, clearer create/rename force hints, multi-doc `doc merge --selector`, line-oriented `insert_before`/`insert_after`, batch `replace PATH OLD NEW` parse hints, 56 MCP tools, JSON `applied` honesty, and agent-facing envelopes) ## Contributing diff --git a/package-lock.json b/package-lock.json index 7874b07..f5e50fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1049,9 +1049,9 @@ } }, "node_modules/@types/vscode": { - "version": "1.120.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.120.0.tgz", - "integrity": "sha512-feaT4Rst+FkTch5zz/ZbNCxoIvo55YU80Be2kiL7OJcod4+CUYf2lUBPdIJzozNnSEMq1VRTGrWEcCGFB3fBmA==", + "version": "1.125.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.125.0.tgz", + "integrity": "sha512-0icm/ZQAaism87P0ekHqi4/Ju9du+Tm0RUW+y7vqRsxY2cY0FNRX1nAnaW7nT6npPt2tfHiheZ55Zm9UhqonFA==", "dev": true, "license": "MIT" }, @@ -1752,14 +1752,6 @@ "typed-rest-client": "^1.8.4" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -1833,16 +1825,16 @@ "license": "BSD-2-Clause" }, "node_modules/brace-expansion": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", - "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", + "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "18 || 20 || >=22" + "node": "20 || >=22" } }, "node_modules/brace-expansion/node_modules/balanced-match": { @@ -4760,17 +4752,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.2.tgz", - "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/mocha/node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", diff --git a/package.json b/package.json index 5a4e89d..e686394 100644 --- a/package.json +++ b/package.json @@ -253,6 +253,7 @@ "check": "npm run test && npm run test:coverage && npm run package" }, "overrides": { + "brace-expansion": "5.0.8", "mocha": { "diff": "^8.0.3", "serialize-javascript": "^7.0.5" diff --git a/test/unit/initializeProject.test.ts b/test/unit/initializeProject.test.ts index 74a5814..0abf514 100644 --- a/test/unit/initializeProject.test.ts +++ b/test/unit/initializeProject.test.ts @@ -85,6 +85,19 @@ test("formatCliOutput prefers JSON error over noisy stderr", () => { ); }); +test("formatCliOutput surfaces already_exists kind (CLI 0.19+)", () => { + const stdout = JSON.stringify({ + ok: false, + error: "destination already exists: src/out.ts", + error_kind: "already_exists", + applied: false + }); + assert.equal( + formatCliOutput({ exitCode: 1, stdout, stderr: "" }), + "already_exists: destination already exists: src/out.ts" + ); +}); + test("classifyAgentsFile returns missing when AGENTS.md does not exist", () => { assert.equal(classifyAgentsFile(undefined, "# Rules\n"), "missing"); });