extract expandHome utility, fix scan error handling scope

kit/skill-lazy-init
Kit Langton 2026-03-19 16:54:06 -04:00
parent 47cb07a8cf
commit be7a9c4987
5 changed files with 20 additions and 17 deletions

View File

@ -1,5 +1,4 @@
import path from "path"
import os from "os"
import z from "zod"
import { type ParseError as JsoncParseError, parse as parseJsonc, printParseErrorCode } from "jsonc-parser"
import { NamedError } from "@opencode-ai/util/error"
@ -109,9 +108,7 @@ export namespace ConfigPaths {
}
let filePath = token.replace(/^\{file:/, "").replace(/\}$/, "")
if (filePath.startsWith("~/")) {
filePath = path.join(os.homedir(), filePath.slice(2))
}
filePath = Filesystem.expandHome(filePath)
const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(configDir, filePath)
const fileContent = (

View File

@ -95,9 +95,7 @@ export namespace InstructionPrompt {
if (config.instructions) {
for (let instruction of config.instructions) {
if (instruction.startsWith("https://") || instruction.startsWith("http://")) continue
if (instruction.startsWith("~/")) {
instruction = path.join(os.homedir(), instruction.slice(2))
}
instruction = Filesystem.expandHome(instruction)
const matches = path.isAbsolute(instruction)
? await Glob.scan(path.basename(instruction), {
cwd: path.dirname(instruction),

View File

@ -202,7 +202,7 @@ export namespace SessionPrompt {
if (seen.has(name)) return
seen.add(name)
const filepath = name.startsWith("~/")
? path.join(os.homedir(), name.slice(2))
? Filesystem.expandHome(name)
: path.resolve(Instance.worktree, name)
const stats = await fs.stat(filepath).catch(() => undefined)

View File

@ -1,4 +1,3 @@
import os from "os"
import path from "path"
import { pathToFileURL } from "url"
import z from "zod"
@ -12,6 +11,7 @@ import { runPromiseInstance } from "@/effect/runtime"
import { Flag } from "@/flag/flag"
import { Global } from "@/global"
import { PermissionNext } from "@/permission"
import { Filesystem } from "@/util/filesystem"
import { Config } from "../config/config"
import { ConfigMarkdown } from "../config/markdown"
import { Log } from "../util/log"
@ -127,14 +127,17 @@ export namespace Skill {
symlink: true,
dot: opts?.dot,
})
.pipe(Effect.orDie)
.pipe(
Effect.catch((error) => {
if (!opts?.scope) return Effect.fail(error)
return Effect.sync(() => {
log.error(`failed to scan ${opts.scope} skills`, { dir: root, error })
return [] as string[]
})
}),
)
yield* Effect.forEach(matches, (match) => add(match), { concurrency: "unbounded" }).pipe(
Effect.catch((error) => {
if (!opts?.scope) return Effect.die(error)
return Effect.sync(() => log.error(`failed to scan ${opts.scope} skills`, { dir: root, error }))
}),
)
yield* Effect.forEach(matches, (match) => add(match), { concurrency: "unbounded" })
})
const load = Effect.fn("Skill.load")(function* () {
@ -169,7 +172,7 @@ export namespace Skill {
// Phase 4: Custom paths
const cfg = yield* Effect.promise(() => Config.get())
for (const item of cfg.skills?.paths ?? []) {
const expanded = item.startsWith("~/") ? path.join(os.homedir(), item.slice(2)) : item
const expanded = Filesystem.expandHome(item)
const dir = path.isAbsolute(expanded) ? expanded : path.join(instance.directory, expanded)
if (!(yield* fs.isDir(dir).pipe(Effect.orDie))) {
log.warn("skill path not found", { path: dir })

View File

@ -2,6 +2,7 @@ import { chmod, mkdir, readFile, writeFile } from "fs/promises"
import { createWriteStream, existsSync, statSync } from "fs"
import { lookup } from "mime-types"
import { realpathSync } from "fs"
import os from "os"
import { dirname, join, relative, resolve as pathResolve } from "path"
import { Readable } from "stream"
import { pipeline } from "stream/promises"
@ -95,6 +96,10 @@ export namespace Filesystem {
}
}
export function expandHome(p: string): string {
return p.startsWith("~/") ? join(os.homedir(), p.slice(2)) : p
}
export function mimeType(p: string): string {
return lookup(p) || "application/octet-stream"
}