Skip to content
Open
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
13 changes: 13 additions & 0 deletions src/api/providers/vscode-lm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ export class VsCodeLmHandler extends BaseProvider implements SingleCompletionHan
*/
async createClient(selector: vscode.LanguageModelChatSelector): Promise<vscode.LanguageModelChat> {
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
Expand Down Expand Up @@ -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) {
Expand Down
8 changes: 6 additions & 2 deletions src/core/diff/strategies/multi-search-replace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down
20 changes: 17 additions & 3 deletions src/core/prompts/sections/skills.ts
Original file line number Diff line number Diff line change
@@ -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`
}

Expand Down