Compare commits

...

1 Commits

Author SHA1 Message Date
Kit Langton d9c79b5acc refactor(config): simplify loading and fallbacks 2026-08-21 13:26:18 -04:00
4 changed files with 24 additions and 33 deletions
+9 -14
View File
@@ -449,21 +449,16 @@ type Edit = { readonly path: (string | number)[]; readonly value: unknown }
function changes(before: unknown, after: unknown, path: (string | number)[] = []): Edit[] {
if (Object.is(before, after)) return []
if (
before !== null &&
after !== null &&
typeof before === "object" &&
typeof after === "object" &&
!Array.isArray(before) &&
!Array.isArray(after)
) {
const previous = before as Record<string, unknown>
const next = after as Record<string, unknown>
return [...new Set([...Object.keys(previous), ...Object.keys(next)])].flatMap((key) => {
if (!(key in next)) return [{ path: [...path, key], value: undefined }]
if (!(key in previous)) return [{ path: [...path, key], value: next[key] }]
return changes(previous[key], next[key], [...path, key])
if (isRecord(before) && isRecord(after)) {
return [...new Set([...Object.keys(before), ...Object.keys(after)])].flatMap((key) => {
if (!(key in after)) return [{ path: [...path, key], value: undefined }]
if (!(key in before)) return [{ path: [...path, key], value: after[key] }]
return changes(before[key], after[key], [...path, key])
})
}
return [{ path, value: after }]
}
function isRecord(value: unknown): value is Record<string, unknown> {
return value !== null && typeof value === "object" && !Array.isArray(value)
}
+5 -5
View File
@@ -54,7 +54,7 @@ export const Plugin = define({
"ConfigSkillPlugin.watchDirectory",
)(function* (directory: string) {
const target = path.resolve(directory)
const resolved = yield* fs.realPath(directory).pipe(Effect.catch(() => Effect.succeed(undefined)))
const resolved = yield* fs.realPath(directory).pipe(Effect.orElseSucceed(() => undefined))
if (resolved) {
yield* watch(resolved, "directory")
if (resolved !== target) yield* watch(target, "file")
@@ -65,7 +65,7 @@ export const Plugin = define({
if (
yield* fs.realPath(directory).pipe(
Effect.as(true),
Effect.catch(() => Effect.succeed(false)),
Effect.orElseSucceed(() => false),
)
) {
if (missing) yield* FiberMap.remove(watches, `file:${path.resolve(missing)}`)
@@ -124,11 +124,11 @@ export const Plugin = define({
for (const directory of directories) {
const files = yield* fs
.scan("{*.md,**/SKILL.md}", { cwd: directory, absolute: true, include: "file", symlink: true, dot: true })
.pipe(Effect.catch(() => Effect.succeed([] as string[])))
.pipe(Effect.orElseSucceed(() => [] as string[]))
for (const filepath of files.toSorted()) {
const resolved = yield* fs.realPath(filepath).pipe(Effect.catch(() => Effect.succeed(filepath)))
const resolved = yield* fs.realPath(filepath).pipe(Effect.orElseSucceed(() => filepath))
if (!roots.some((root) => FSUtil.contains(root, resolved))) yield* watch(path.dirname(resolved), "directory")
const content = yield* fs.readFileStringSafe(filepath).pipe(Effect.catch(() => Effect.succeed(undefined)))
const content = yield* fs.readFileStringSafe(filepath).pipe(Effect.orElseSucceed(() => undefined))
if (!content) continue
const parsed = SkillFile.parse(directory, filepath, content)
if (parsed._tag === "Skipped") {
+1 -1
View File
@@ -157,7 +157,7 @@ const layer = Layer.effect(
const current =
version === undefined
? undefined
: yield* fs.readFileStringSafe(versionFile).pipe(Effect.catch(() => Effect.succeed(undefined)))
: yield* fs.readFileStringSafe(versionFile).pipe(Effect.orElseSucceed(() => undefined))
if (version === undefined || current === version) {
yield* Effect.forEach(files, (file) => download(file.url, file.destination), {
concurrency: fileConcurrency,
+9 -13
View File
@@ -106,6 +106,10 @@ const layer = Layer.effect(
const bus = yield* Bus.Service
const cache = yield* Ref.make(new Map<string, Entry>())
const lock = Semaphore.makeUnsafe(1)
const loadEntry = Effect.fn("WellKnown.loadEntry")(function* (origin: string) {
const manifest = yield* inspect(origin).pipe(Effect.provideService(HttpClient.HttpClient, http))
return { origin, integrationID: Integration.ID.make(origin), manifest }
})
const load = Effect.fn("WellKnown.load")(function* () {
const value = yield* kv.get(sourcesKey)
@@ -114,10 +118,7 @@ const layer = Layer.effect(
const entries = yield* Effect.forEach(origins, (origin) => {
const cached = current.get(origin)
if (cached) return Effect.succeed(cached)
return inspect(origin).pipe(
Effect.provideService(HttpClient.HttpClient, http),
Effect.map((manifest) => ({ origin, integrationID: Integration.ID.make(origin), manifest })),
)
return loadEntry(origin)
})
yield* Ref.set(cache, new Map(entries.map((entry) => [entry.origin, entry])))
return entries
@@ -129,12 +130,7 @@ const layer = Layer.effect(
const value = yield* kv.get(sourcesKey)
const origins = Schema.is(Sources)(value) ? value : []
if (!origins.length) return false
const entries = yield* Effect.forEach(origins, (origin) =>
inspect(origin).pipe(
Effect.provideService(HttpClient.HttpClient, http),
Effect.map((manifest) => ({ origin, integrationID: Integration.ID.make(origin), manifest })),
),
)
const entries = yield* Effect.forEach(origins, loadEntry)
const next = new Map(entries.map((entry) => [entry.origin, entry]))
const changed = !isDeepStrictEqual(Ref.getUnsafe(cache), next)
if (!changed) return false
@@ -153,9 +149,9 @@ const layer = Layer.effect(
return yield* lock.withPermit(
Effect.gen(function* () {
const origin = value.replace(/\/+$/, "")
const manifest = yield* inspect(origin).pipe(Effect.provideService(HttpClient.HttpClient, http))
if (!manifest.auth) return yield* Effect.fail(new Error(`No authentication method found at ${origin}`))
const entry = { origin, integrationID: Integration.ID.make(origin), manifest }
const entry = yield* loadEntry(origin)
if (!entry.manifest.auth)
return yield* Effect.fail(new Error(`No authentication method found at ${origin}`))
const sources = yield* kv.get(sourcesKey)
const origins = Schema.is(Sources)(sources) ? sources : []
yield* kv.set(sourcesKey, Array.from(new Set([...origins, origin])))