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
4 changes: 3 additions & 1 deletion packages/kilo-vscode/src/services/marketplace/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import * as os from "os"
* This matches where the CLI reads global config from.
*/
function globalConfigDir(): string {
const xdg = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config")
const xdg = process.env.XDG_CONFIG_HOME
? path.normalize(process.env.XDG_CONFIG_HOME)
: path.normalize(path.join(os.homedir(), ".config"))
return path.join(xdg, "kilo")
}

Expand Down
18 changes: 4 additions & 14 deletions packages/opencode/src/global/index.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,18 @@
import fs from "fs/promises"
import { xdgData, xdgCache, xdgConfig, xdgState } from "xdg-basedir"
import path from "path"
import os from "os"
import { Filesystem } from "../util/filesystem"
import { resolveGlobalPaths, resolveHome } from "./paths"

const app = "kilo" // kilocode_change

const data = path.join(xdgData!, app)
const cache = path.join(xdgCache!, app)
const config = path.join(xdgConfig!, app)
const state = path.join(xdgState!, app)
const paths = resolveGlobalPaths(app)

export namespace Global {
export const Path = {
// Allow override via KILO_TEST_HOME for test isolation
get home() {
return process.env.KILO_TEST_HOME || os.homedir() // kilocode_change
return resolveHome() // kilocode_change
},
data,
bin: path.join(data, "bin"),
log: path.join(data, "log"),
cache,
config,
state,
...paths,
}
}

Expand Down
65 changes: 65 additions & 0 deletions packages/opencode/src/global/paths.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import os from "os"
import path from "path"

type PathModule = Pick<typeof path, "join" | "normalize">

interface XdgEnv {
data?: string
cache?: string
config?: string
state?: string
}

function baseDir(value: string | undefined, home: string, fallback: string[], pathmod: PathModule) {
if (value) return pathmod.normalize(value)
return pathmod.normalize(pathmod.join(home, ...fallback))
}

export function resolveHome(home = process.env.KILO_TEST_HOME || os.homedir()) {
return home
}

export function resolveGlobalPaths(
app: string,
opts: {
home?: string
env?: XdgEnv
pathmod?: PathModule
} = {},
) {
const home = resolveHome(opts.home)
const pathmod = opts.pathmod ?? path
const env = opts.env ?? {
data: process.env["XDG_DATA_HOME"],
cache: process.env["XDG_CACHE_HOME"],
config: process.env["XDG_CONFIG_HOME"],
state: process.env["XDG_STATE_HOME"],
}

const dataRoot = baseDir(env.data, home, [".local", "share"], pathmod)
const cacheRoot = baseDir(env.cache, home, [".cache"], pathmod)
const configRoot = baseDir(env.config, home, [".config"], pathmod)
const stateRoot = baseDir(env.state, home, [".local", "state"], pathmod)

const data = pathmod.join(dataRoot, app)
const cache = pathmod.join(cacheRoot, app)
const config = pathmod.join(configRoot, app)
const state = pathmod.join(stateRoot, app)

return {
home,
data,
bin: pathmod.join(data, "bin"),
log: pathmod.join(data, "log"),
cache,
config,
state,
}
}

export function expandHomePattern(pattern: string, home = resolveHome(), pathmod: PathModule = path) {
if (pattern === "~" || pattern === "$HOME") return home
if (pattern.startsWith("~/")) return pathmod.join(home, pattern.slice(2))
if (pattern.startsWith("$HOME/")) return pathmod.join(home, pattern.slice(6))
return pattern
}
8 changes: 2 additions & 6 deletions packages/opencode/src/permission/next.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,14 @@ import { Log } from "@/util/log"
import { Wildcard } from "@/util/wildcard"
import { drainCovered } from "@/kilocode/permission/drain" // kilocode_change
import { ConfigProtection } from "@/kilocode/permission/config-paths" // kilocode_change
import os from "os"
import { expandHomePattern } from "@/global/paths"
import z from "zod"

export namespace PermissionNext {
const log = Log.create({ service: "permission" })

function expand(pattern: string): string {
if (pattern.startsWith("~/")) return os.homedir() + pattern.slice(1)
if (pattern === "~") return os.homedir()
if (pattern.startsWith("$HOME/")) return os.homedir() + pattern.slice(5)
if (pattern.startsWith("$HOME")) return os.homedir() + pattern.slice(5)
return pattern
return expandHomePattern(pattern)
}

export const Action = z.enum(["allow", "deny", "ask"]).meta({
Expand Down
41 changes: 41 additions & 0 deletions packages/opencode/test/global/paths.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { describe, expect, test } from "bun:test"
import path from "path"
import { expandHomePattern, resolveGlobalPaths } from "../../src/global/paths"

describe("resolveGlobalPaths", () => {
test("builds Windows config path with separator before .config", () => {
const result = resolveGlobalPaths("kilo", {
home: "C:\\Users\\user1",
env: {},
pathmod: path.win32,
})

expect(result.config).toBe("C:\\Users\\user1\\.config\\kilo")
expect(result.data).toBe("C:\\Users\\user1\\.local\\share\\kilo")
expect(result.state).toBe("C:\\Users\\user1\\.local\\state\\kilo")
})

test("prefers XDG_CONFIG_HOME when provided", () => {
const result = resolveGlobalPaths("kilo", {
home: "C:\\Users\\user1",
env: {
config: "D:\\config-root",
},
pathmod: path.win32,
})

expect(result.config).toBe("D:\\config-root\\kilo")
})
})

describe("expandHomePattern", () => {
test("expands tilde paths with Windows separators", () => {
const result = expandHomePattern("~/agent/rules.md", "C:\\Users\\user1", path.win32)
expect(result).toBe("C:\\Users\\user1\\agent\\rules.md")
})

test("expands $HOME paths with Windows separators", () => {
const result = expandHomePattern("$HOME/agent/rules.md", "C:\\Users\\user1", path.win32)
expect(result).toBe("C:\\Users\\user1\\agent\\rules.md")
})
})