Skip to content

Commit 7c92fbd

Browse files
committed
feat(vscode): harden the VS Code client with trust-aware UX, safer launcher/runtime handling, and tested review workflows
1 parent bbcebaa commit 7c92fbd

5 files changed

Lines changed: 88 additions & 0 deletions

File tree

extensions/vscode-codeclone/package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,11 @@
209209
"category": "CodeClone",
210210
"icon": "$(filter)"
211211
},
212+
{
213+
"command": "codeclone.reviewFinding",
214+
"title": "Review Finding",
215+
"category": "CodeClone"
216+
},
212217
{
213218
"command": "codeclone.openFinding",
214219
"title": "Open Finding",
@@ -287,6 +292,11 @@
287292
"category": "CodeClone",
288293
"icon": "$(symbol-module)"
289294
},
295+
{
296+
"command": "codeclone.reviewGodModule",
297+
"title": "Review Candidate",
298+
"category": "CodeClone"
299+
},
290300
{
291301
"command": "codeclone.copyGodModuleBrief",
292302
"title": "Copy Report-only Brief",

extensions/vscode-codeclone/src/extension.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const {
1515
resolveWorkspacePath,
1616
signedInteger,
1717
staleMessage,
18+
workspaceLocalLauncherCandidates,
1819
} = require("./support");
1920

2021
const execFileAsync = promisify(execFile);
@@ -1134,6 +1135,16 @@ class CodeCloneController {
11341135
cwd: folder.uri.fsPath,
11351136
});
11361137
}
1138+
const localLauncher = workspaceLocalLauncherCandidates(folder.uri.fsPath).find(
1139+
(candidate) => fs.existsSync(candidate)
1140+
);
1141+
if (localLauncher) {
1142+
return normalizedLaunchSpec({
1143+
command: localLauncher,
1144+
args: Array.isArray(configuredArgs) ? configuredArgs : [],
1145+
cwd: folder.uri.fsPath,
1146+
});
1147+
}
11371148
const primary = normalizedLaunchSpec({
11381149
command: "codeclone-mcp",
11391150
args: Array.isArray(configuredArgs) ? configuredArgs : [],

extensions/vscode-codeclone/src/support.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,29 @@ function resolveWorkspacePath(rootPath, relativePath) {
7070
return null;
7171
}
7272

73+
function workspaceLocalLauncherCandidates(
74+
rootPath,
75+
platform = process.platform
76+
) {
77+
const root = String(rootPath || "").trim();
78+
if (!root) {
79+
return [];
80+
}
81+
const platformPath = platform === "win32" ? path.win32 : path.posix;
82+
if (platform === "win32") {
83+
return [
84+
platformPath.join(root, ".venv", "Scripts", "codeclone-mcp.exe"),
85+
platformPath.join(root, ".venv", "Scripts", "codeclone-mcp.cmd"),
86+
platformPath.join(root, "venv", "Scripts", "codeclone-mcp.exe"),
87+
platformPath.join(root, "venv", "Scripts", "codeclone-mcp.cmd"),
88+
];
89+
}
90+
return [
91+
platformPath.join(root, ".venv", "bin", "codeclone-mcp"),
92+
platformPath.join(root, "venv", "bin", "codeclone-mcp"),
93+
];
94+
}
95+
7396
module.exports = {
7497
STALE_REASON_EDITOR,
7598
STALE_REASON_WORKSPACE,
@@ -79,4 +102,5 @@ module.exports = {
79102
signedInteger,
80103
staleMessage,
81104
trimTail,
105+
workspaceLocalLauncherCandidates,
82106
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"use strict";
2+
3+
const test = require("node:test");
4+
const assert = require("node:assert/strict");
5+
const fs = require("node:fs");
6+
const path = require("node:path");
7+
8+
function loadPackageJson() {
9+
const filePath = path.resolve(__dirname, "..", "package.json");
10+
return JSON.parse(fs.readFileSync(filePath, "utf8"));
11+
}
12+
13+
test("every menu command is declared in contributes.commands", () => {
14+
const pkg = loadPackageJson();
15+
const declaredCommands = new Set(
16+
pkg.contributes.commands.map((entry) => entry.command)
17+
);
18+
const missing = [];
19+
20+
for (const items of Object.values(pkg.contributes.menus)) {
21+
for (const entry of items) {
22+
if (!declaredCommands.has(entry.command)) {
23+
missing.push(entry.command);
24+
}
25+
}
26+
}
27+
28+
assert.deepEqual(missing, []);
29+
});

extensions/vscode-codeclone/test/support.test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const {
1212
signedInteger,
1313
staleMessage,
1414
trimTail,
15+
workspaceLocalLauncherCandidates,
1516
} = require("../src/support");
1617

1718
test("signedInteger formats positive, zero, and negative values", () => {
@@ -83,3 +84,16 @@ test("trimTail keeps the newest part of long strings", () => {
8384
assert.equal(trimTail("abc", 10), "abc");
8485
assert.equal(trimTail("abc", 0), "");
8586
});
87+
88+
test("workspaceLocalLauncherCandidates prefer workspace virtual environments", () => {
89+
assert.deepEqual(workspaceLocalLauncherCandidates("/workspace/repo", "linux"), [
90+
"/workspace/repo/.venv/bin/codeclone-mcp",
91+
"/workspace/repo/venv/bin/codeclone-mcp",
92+
]);
93+
assert.deepEqual(workspaceLocalLauncherCandidates("C:\\repo", "win32"), [
94+
"C:\\repo\\.venv\\Scripts\\codeclone-mcp.exe",
95+
"C:\\repo\\.venv\\Scripts\\codeclone-mcp.cmd",
96+
"C:\\repo\\venv\\Scripts\\codeclone-mcp.exe",
97+
"C:\\repo\\venv\\Scripts\\codeclone-mcp.cmd",
98+
]);
99+
});

0 commit comments

Comments
 (0)