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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ src/
test/
unit/ Unit tests (node:test, dependency-injected, no VS Code API)
batchApply.test.ts Batch template and operation count parsing (16 tests)
binary.test.ts Binary discovery, managed install, compatibility, workspace env (59 tests)
binary.test.ts Binary discovery, managed install, compatibility, workspace env (64 tests)
binaryDiscovery.test.ts Real executable discovery on PATH (13 tests)
initializeProject.test.ts Status display, agents file classification, formatError (39 tests)
managedLifecycle.test.ts Managed install with real file I/O (22 tests)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ On CLI 0.25+, section ops that match the same heading more than once report `err
Run `Patchloom: Configure MCP` and select the target editor config.

**Managed install failure persists after restart**
Run `Patchloom: Show Status` to see persisted diagnostic details.
Run `Patchloom: Show Status` to see persisted diagnostic details. If the managed binary is present but not usable, choose **Reinstall Patchloom** (or the status-bar action) to re-download from GitHub Releases.

**Debugging CLI errors**
Run `Patchloom: Show Output` to see full CLI invocations, arguments, stdout, and stderr in the output channel.
Expand Down
40 changes: 20 additions & 20 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -253,15 +253,15 @@
"check": "npm run test && npm run test:coverage && npm run package"
},
"overrides": {
"brace-expansion": "5.0.8",
"brace-expansion": "5.0.9",
"mocha": {
"diff": "^8.0.3",
"serialize-javascript": "^7.0.5"
}
},
"devDependencies": {
"@types/mocha": "^10.0.10",
"@types/node": "^26.1.2",
"@types/node": "^26.2.0",
"@types/vscode": "^1.90.0",
"@vscode/test-electron": "^3.1.0",
"@vscode/vsce": "^3.0.0",
Expand Down
108 changes: 72 additions & 36 deletions src/binary/patchloom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,65 @@ export function patchloomNeedsUpgrade(status: PatchloomStatus): boolean {
return status.compatibility === "unsupported";
}

/** Primary palette action when the CLI is missing or too old. */
export interface PatchloomRemediationAction {
readonly title: string;
readonly command: string;
}

/**
* Choose the best one-click remediation for a missing or outdated CLI.
* Prefers managed install/update (GitHub Releases) so users do not stick on
* lagging community packages (winget, Chocolatey). Pure: unit-testable without VS Code.
*/
export function preferredBinaryRemediationAction(
status: PatchloomStatus
): PatchloomRemediationAction | undefined {
if (!status.ready || !status.binaryPath) {
if (status.managedInstall?.exists) {
return {
title: "Reinstall Patchloom",
command: "patchloom.reinstallBinary"
};
}
if (status.managedInstall) {
return {
title: "Install Patchloom",
command: "patchloom.installBinary"
};
}
return {
title: "Open Settings",
command: "patchloom.openPatchloomSettings"
};
}

if (patchloomNeedsUpgrade(status)) {
if (status.source === "managed" || status.managedInstall?.exists) {
return {
title: "Update Patchloom",
command: "patchloom.updateBinary"
};
}
if (status.managedInstall) {
return {
title: "Install Patchloom",
command: "patchloom.installBinary"
};
}
return {
title: "Open Releases",
command: "patchloom.openPatchloomReleases"
};
}

return undefined;
}

/**
* Ensures Patchloom is ready (found + compatible). If not, shows a warning
* and offers to open Settings or Releases. Returns the binaryPath if ready,
* otherwise null (after showing UI).
* with the preferred remediation (managed install/update when available).
* Returns the binaryPath if ready, otherwise null (after showing UI).
*
* This removes duplicated ready-check + notify logic across commands.
*/
Expand All @@ -168,43 +223,24 @@ export async function ensurePatchloomReadyOrNotify(
? await resolvePatchloomStatusWithInputs(testInputs)
: await resolvePatchloomStatus();

if (!status.ready || !status.binaryPath) {
const vscode = await import("vscode");
const choice = await vscode.window.showWarningMessage(
`${status.message}${contextSuffix ? `\n\n${contextSuffix}` : ""}`,
"Open Settings"
);
if (choice === "Open Settings") {
await vscode.commands.executeCommand("patchloom.openPatchloomSettings");
}
return null;
const remediation = preferredBinaryRemediationAction(status);
if (!remediation) {
return status.binaryPath ?? null;
}

if (patchloomNeedsUpgrade(status)) {
const vscode = await import("vscode");
// Prefer managed install/update (GitHub Releases) over lagging community packages.
const canUpdateManaged = status.source === "managed" || status.managedInstall?.exists === true;
const canInstallManaged = status.managedInstall !== undefined;
const primaryAction = canUpdateManaged
? "Update Patchloom"
: canInstallManaged
? "Install Patchloom"
: "Open Releases";
const choice = await vscode.window.showWarningMessage(
`${status.compatibilityMessage}${contextSuffix ? `\n\n${contextSuffix}` : ""}`,
primaryAction
);
if (choice === "Update Patchloom") {
await vscode.commands.executeCommand("patchloom.updateBinary");
} else if (choice === "Install Patchloom") {
await vscode.commands.executeCommand("patchloom.installBinary");
} else if (choice === "Open Releases") {
await vscode.commands.executeCommand("patchloom.openPatchloomReleases");
}
return null;
const vscode = await import("vscode");
const baseMessage =
status.ready && patchloomNeedsUpgrade(status)
? (status.compatibilityMessage ?? status.message)
: status.message;
const choice = await vscode.window.showWarningMessage(
`${baseMessage}${contextSuffix ? `\n\n${contextSuffix}` : ""}`,
remediation.title
);
if (choice === remediation.title) {
await vscode.commands.executeCommand(remediation.command);
}

return status.binaryPath;
return null;
}

export function parsePatchloomVersion(versionText?: string): string | undefined {
Expand Down
36 changes: 4 additions & 32 deletions src/status/details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
describePatchloomCompatibility,
describePatchloomSource,
patchloomNeedsUpgrade,
preferredBinaryRemediationAction,
PatchloomStatus
} from "../binary/patchloom.js";
import type { McpTargetStatus } from "../mcp/config.js";
Expand Down Expand Up @@ -43,38 +44,9 @@ export function buildStatusDetails(status: PatchloomStatus, workspaceReadiness?:
}

export function preferredStatusAction(status: PatchloomStatus, workspaceReadiness?: WorkspaceReadiness): SetupAction | undefined {
if (!status.ready) {
if (status.source === "missing" && status.managedInstall && !status.managedInstall.exists) {
return {
title: "Install Patchloom",
command: "patchloom.installBinary"
};
}
return {
title: "Open Settings",
command: "patchloom.openPatchloomSettings"
};
}

if (patchloomNeedsUpgrade(status)) {
// Prefer managed install/update so users stay on GitHub Releases (not lagging
// community packages such as winget/Chocolatey).
if (status.source === "managed" || status.managedInstall?.exists) {
return {
title: "Update Patchloom",
command: "patchloom.updateBinary"
};
}
if (status.managedInstall) {
return {
title: "Install Patchloom",
command: "patchloom.installBinary"
};
}
return {
title: "Open Releases",
command: "patchloom.openPatchloomReleases"
};
// Missing or outdated CLI: shared remediation (managed install preferred).
if (!status.ready || patchloomNeedsUpgrade(status)) {
return preferredBinaryRemediationAction(status);
}

if (workspaceReadiness?.hasWorkspace && workspaceReadiness.hasAgentsFile === false) {
Expand Down
Loading
Loading