Skip to content
This repository was archived by the owner on Feb 25, 2026. It is now read-only.

Commit 5c2b10d

Browse files
committed
fix: use path normalization to fix win32 issues
1 parent c7c401a commit 5c2b10d

47 files changed

Lines changed: 336 additions & 162 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/app/e2e/fixtures.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,14 @@ async function seedStorage(page: Page, input: { directory: string; extra?: strin
8585
}
8686

8787
export { expect }
88+
89+
/**
90+
* Check if KILO credentials are available for tests requiring connected providers.
91+
* Model picker tests require connected providers which need these credentials.
92+
* @returns true if credentials are missing
93+
*/
94+
export function missingKiloCredentials() {
95+
const hasKey = !!process.env.KILO_API_KEY
96+
const hasOrg = !!process.env.KILO_ORG_ID
97+
return !hasKey || !hasOrg
98+
}

packages/app/e2e/models/models-visibility.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { test, expect } from "../fixtures"
1+
import { test, expect, missingKiloCredentials } from "../fixtures"
22
import { promptSelector } from "../selectors"
33
import { closeDialog, openSettings, clickListItem } from "../actions"
44

55
test("hiding a model removes it from the model picker", async ({ page, gotoSession }) => {
6+
test.skip(missingKiloCredentials(), "KILO_API_KEY or KILO_ORG_ID not set")
67
await gotoSession()
78

89
await page.locator(promptSelector).click()

packages/app/e2e/settings/settings-models.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { test, expect } from "../fixtures"
1+
import { test, expect, missingKiloCredentials } from "../fixtures"
22
import { promptSelector } from "../selectors"
33
import { closeDialog, openSettings } from "../actions"
44

55
test("hiding a model removes it from the model picker", async ({ page, gotoSession }) => {
6+
test.skip(missingKiloCredentials(), "KILO_API_KEY or KILO_ORG_ID not set")
67
await gotoSession()
78

89
await page.locator(promptSelector).click()
@@ -61,6 +62,7 @@ test("hiding a model removes it from the model picker", async ({ page, gotoSessi
6162
})
6263

6364
test("showing a hidden model restores it to the model picker", async ({ page, gotoSession }) => {
65+
test.skip(missingKiloCredentials(), "KILO_API_KEY or KILO_ORG_ID not set")
6466
await gotoSession()
6567

6668
await page.locator(promptSelector).click()

packages/app/src/custom-elements.d.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// kilocode_change - copy content instead of symlink for Windows compatibility
2+
import { DIFFS_TAG_NAME } from "@pierre/diffs"
3+
4+
/**
5+
* TypeScript declaration for the <diffs-container> custom element.
6+
* This tells TypeScript that <diffs-container> is a valid JSX element in SolidJS.
7+
* Required for using the @pierre/diffs web component in .tsx files.
8+
*/
9+
10+
declare module "solid-js" {
11+
namespace JSX {
12+
interface IntrinsicElements {
13+
[DIFFS_TAG_NAME]: HTMLAttributes<HTMLElement>
14+
}
15+
}
16+
}
17+
18+
export {}

packages/opencode/src/agent/agent.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { Plugin } from "@/plugin"
2424
import { Skill } from "../skill"
2525

2626
import { Telemetry } from "@kilocode/kilo-telemetry" // kilocode_change
27+
import { Filesystem } from "@/util/filesystem"
2728

2829
export namespace Agent {
2930
export const Info = z
@@ -106,12 +107,12 @@ export namespace Agent {
106107
question: "allow",
107108
plan_exit: "allow",
108109
external_directory: {
109-
[path.join(Global.Path.data, "plans", "*")]: "allow",
110+
[Filesystem.join(Global.Path.data, "plans", "*")]: "allow",
110111
},
111112
edit: {
112113
"*": "deny",
113-
[path.join(".opencode", "plans", "*.md")]: "allow",
114-
[path.relative(Instance.worktree, path.join(Global.Path.data, path.join("plans", "*.md")))]: "allow",
114+
[Filesystem.join(".opencode", "plans", "*.md")]: "allow",
115+
[Filesystem.relative(Instance.worktree, Filesystem.join(Global.Path.data, "plans", "*.md"))]: "allow",
115116
},
116117
}),
117118
user,

packages/opencode/src/cli/cmd/tui/routes/session/index.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,7 @@ export function Session() {
857857
} else {
858858
const exportDir = process.cwd()
859859
const filename = options.filename.trim()
860-
const filepath = path.join(exportDir, filename)
860+
const filepath = Filesystem.join(exportDir, filename)
861861

862862
await Bun.write(filepath, transcript)
863863

@@ -1675,7 +1675,7 @@ function Bash(props: ToolProps<typeof BashTool>) {
16751675
const base = sync.data.path.directory
16761676
if (!base) return undefined
16771677

1678-
const absolute = path.resolve(base, workdir)
1678+
const absolute = Filesystem.resolve(base, workdir)
16791679
if (absolute === base) return undefined
16801680

16811681
const home = Global.Path.home
@@ -1730,7 +1730,7 @@ function Write(props: ToolProps<typeof WriteTool>) {
17301730
})
17311731

17321732
const diagnostics = createMemo(() => {
1733-
const filePath = Filesystem.normalizePath(props.input.filePath ?? "")
1733+
const filePath = Filesystem.realpath(props.input.filePath ?? "")
17341734
return props.metadata.diagnostics?.[filePath] ?? []
17351735
})
17361736

@@ -1940,7 +1940,7 @@ function Edit(props: ToolProps<typeof EditTool>) {
19401940
const diffContent = createMemo(() => props.metadata.diff)
19411941

19421942
const diagnostics = createMemo(() => {
1943-
const filePath = Filesystem.normalizePath(props.input.filePath ?? "")
1943+
const filePath = Filesystem.realpath(props.input.filePath ?? "")
19441944
const arr = props.metadata.diagnostics?.[filePath] ?? []
19451945
return arr.filter((x) => x.severity === 1).slice(0, 3)
19461946
})
@@ -2133,7 +2133,7 @@ function Skill(props: ToolProps<typeof SkillTool>) {
21332133
function normalizePath(input?: string) {
21342134
if (!input) return ""
21352135
if (path.isAbsolute(input)) {
2136-
return path.relative(process.cwd(), input) || "."
2136+
return Filesystem.relative(process.cwd(), input) || "."
21372137
}
21382138
return input
21392139
}

packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { Keybind } from "@/util/keybind"
1515
import { Locale } from "@/util/locale"
1616
import { Global } from "@/global"
1717
import { useDialog } from "../../ui/dialog"
18+
import { Filesystem } from "@/util/filesystem"
1819

1920
type PermissionStage = "permission" | "always" | "reject"
2021

@@ -23,8 +24,8 @@ function normalizePath(input?: string) {
2324

2425
const cwd = process.cwd()
2526
const home = Global.Path.home
26-
const absolute = path.isAbsolute(input) ? input : path.resolve(cwd, input)
27-
const relative = path.relative(cwd, absolute)
27+
const absolute = path.isAbsolute(input) ? input : Filesystem.resolve(cwd, input)
28+
const relative = Filesystem.relative(cwd, absolute)
2829

2930
if (!relative) return "."
3031
if (!relative.startsWith("..")) return relative
@@ -248,7 +249,7 @@ export function PermissionPrompt(props: { request: PermissionRequest }) {
248249
const derived =
249250
typeof pattern === "string"
250251
? pattern.includes("*")
251-
? path.dirname(pattern)
252+
? Filesystem.dirname(pattern)
252253
: pattern
253254
: undefined
254255

packages/opencode/src/config/config.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,10 +411,13 @@ export namespace Config {
411411
}
412412

413413
function rel(item: string, patterns: string[]) {
414+
// Normalize the item path first
415+
const normalizedItem = Filesystem.normalize(item)
414416
for (const pattern of patterns) {
415-
const index = item.indexOf(pattern)
417+
const normalizedPattern = Filesystem.normalize(pattern)
418+
const index = normalizedItem.indexOf(normalizedPattern)
416419
if (index === -1) continue
417-
return item.slice(index + pattern.length)
420+
return normalizedItem.slice(index + normalizedPattern.length)
418421
}
419422
}
420423

packages/opencode/src/file/ignore.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { sep } from "node:path"
1+
import { Filesystem } from "../util/filesystem"
22

33
export namespace FileIgnore {
44
const FOLDERS = new Set([
@@ -64,18 +64,20 @@ export namespace FileIgnore {
6464
whitelist?: Bun.Glob[]
6565
},
6666
) {
67+
const normalizedPath = Filesystem.normalize(filepath)
68+
6769
for (const glob of opts?.whitelist || []) {
68-
if (glob.match(filepath)) return false
70+
if (glob.match(normalizedPath)) return false
6971
}
7072

71-
const parts = filepath.split(sep)
73+
const parts = normalizedPath.split("/")
7274
for (let i = 0; i < parts.length; i++) {
7375
if (FOLDERS.has(parts[i])) return true
7476
}
7577

7678
const extra = opts?.extra || []
7779
for (const glob of [...FILE_GLOBS, ...extra]) {
78-
if (glob.match(filepath)) return true
80+
if (glob.match(normalizedPath)) return true
7981
}
8082

8183
return false

0 commit comments

Comments
 (0)