diff --git a/src/api/providers/vscode-lm.ts b/src/api/providers/vscode-lm.ts index 4d2c6791bfb..8a303a767f4 100644 --- a/src/api/providers/vscode-lm.ts +++ b/src/api/providers/vscode-lm.ts @@ -111,6 +111,13 @@ export class VsCodeLmHandler extends BaseProvider implements SingleCompletionHan */ async createClient(selector: vscode.LanguageModelChatSelector): Promise { try { + // Check if vscode.lm API is available + if (!vscode.lm) { + throw new Error( + "VS Code Language Model API is not available. The vscode-lm provider can only be used within VS Code extension, not in CLI.", + ) + } + const models = await vscode.lm.selectChatModels(selector) // Use first available model or create a minimal model object @@ -565,6 +572,12 @@ const VSCODE_LM_STATIC_BLACKLIST: string[] = ["claude-3.7-sonnet", "claude-3.7-s export async function getVsCodeLmModels() { try { + // Check if vscode.lm API is available + if (!vscode.lm) { + console.warn("VS Code Language Model API is not available.") + return [] + } + const models = (await vscode.lm.selectChatModels({})) || [] return models.filter((model) => !VSCODE_LM_STATIC_BLACKLIST.includes(model.id)) } catch (error) { diff --git a/src/core/diff/strategies/multi-search-replace.ts b/src/core/diff/strategies/multi-search-replace.ts index a6a9913203c..e97724ad7fb 100644 --- a/src/core/diff/strategies/multi-search-replace.ts +++ b/src/core/diff/strategies/multi-search-replace.ts @@ -298,7 +298,9 @@ Only use a single line of '=======' between search and replacement content, beca ? reportInvalidDiffError(SEP, SEARCH) : reportMergeConflictError(SEP, SEARCH) if (marker === REPLACE) return reportInvalidDiffError(REPLACE, SEARCH) - if (marker.startsWith(REPLACE_PREFIX)) return reportMergeConflictError(marker, SEARCH) + // Only report merge conflict error if not the exact REPLACE closing marker + if (marker.startsWith(REPLACE_PREFIX) && marker !== REPLACE) + return reportMergeConflictError(marker, SEARCH) if (SEARCH_PATTERN.test(marker)) state.current = State.AFTER_SEARCH else if (marker.startsWith(SEARCH_PREFIX)) return reportMergeConflictError(marker, SEARCH) break @@ -307,7 +309,9 @@ Only use a single line of '=======' between search and replacement content, beca if (SEARCH_PATTERN.test(marker)) return reportInvalidDiffError(SEARCH_PATTERN.source, SEP) if (marker.startsWith(SEARCH_PREFIX)) return reportMergeConflictError(marker, SEARCH) if (marker === REPLACE) return reportInvalidDiffError(REPLACE, SEP) - if (marker.startsWith(REPLACE_PREFIX)) return reportMergeConflictError(marker, SEARCH) + // Only report merge conflict error if not the exact REPLACE closing marker + if (marker.startsWith(REPLACE_PREFIX) && marker !== REPLACE) + return reportMergeConflictError(marker, SEARCH) if (marker === SEP) state.current = State.AFTER_SEPARATOR break diff --git a/src/core/prompts/sections/skills.ts b/src/core/prompts/sections/skills.ts index a05c0aea738..0451a9498ca 100644 --- a/src/core/prompts/sections/skills.ts +++ b/src/core/prompts/sections/skills.ts @@ -1,15 +1,29 @@ +import * as os from "os" +import * as path from "path" import { SkillsManager, SkillMetadata } from "../../../services/skills/SkillsManager" /** - * Get a display-friendly relative path for a skill. + * Get a display-friendly path for a skill. * Converts absolute paths to relative paths to avoid leaking sensitive filesystem info. * + * For global skills, uses the actual home directory path (not ~) to ensure + * the path works correctly when the AI model tries to read the file on all platforms. + * * @param skill - The skill metadata - * @returns A relative path like ".kilocode/skills/name/SKILL.md" or "~/.kilocode/skills/name/SKILL.md" + * @returns A path like ".kilocode/skills/name/SKILL.md" or "C:/Users/john/.kilocode/skills/name/SKILL.md" */ function getDisplayPath(skill: SkillMetadata): string { - const basePath = skill.source === "project" ? ".kilocode" : "~/.kilocode" const skillsDir = skill.mode ? `skills-${skill.mode}` : "skills" + + if (skill.source === "project") { + return `.kilocode/${skillsDir}/${skill.name}/SKILL.md` + } + + // For global skills, use the actual home directory path instead of ~ + // This ensures the path works correctly when the AI model tries to read the file + // on all platforms, especially Windows where ~ is not automatically expanded + const homeDir = os.homedir() + const basePath = path.join(homeDir, ".kilocode") return `${basePath}/${skillsDir}/${skill.name}/SKILL.md` }