feat: update session notices and skill reloads
This commit is contained in:
parent
98c09884bf
commit
fb884bb91e
29 changed files with 304 additions and 75 deletions
|
|
@ -1,14 +1,16 @@
|
|||
import fs from "fs/promises"
|
||||
import path from "path"
|
||||
import { describe, expect } from "bun:test"
|
||||
import { Effect, Layer } from "effect"
|
||||
import { Deferred, Effect, Fiber, Layer, Stream } from "effect"
|
||||
import { AgentV2 } from "@opencode-ai/core/agent"
|
||||
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||
import { EventV2 } from "@opencode-ai/core/event"
|
||||
import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||
import { SkillV2 } from "@opencode-ai/core/skill"
|
||||
import { SkillDiscovery } from "@opencode-ai/core/skill/discovery"
|
||||
import { FileSystemWatcher } from "@opencode-ai/schema/filesystem-watcher"
|
||||
import { tmpdir } from "./fixture/tmpdir"
|
||||
import { testEffect } from "./lib/effect"
|
||||
|
||||
|
|
@ -24,7 +26,7 @@ const discovery = Layer.succeed(
|
|||
}),
|
||||
)
|
||||
const it = testEffect(
|
||||
AppNodeBuilder.build(LayerNode.group([SkillV2.node, AgentV2.node]), [
|
||||
AppNodeBuilder.build(LayerNode.group([SkillV2.node, AgentV2.node, EventV2.node]), [
|
||||
LayerNode.replace(SkillDiscovery.layer, discovery),
|
||||
]),
|
||||
)
|
||||
|
|
@ -40,6 +42,19 @@ description: ${description}
|
|||
)
|
||||
}
|
||||
|
||||
function waitForSkillUpdate() {
|
||||
return Effect.gen(function* () {
|
||||
const events = yield* EventV2.Service
|
||||
const deferred = yield* Deferred.make<void>()
|
||||
const fiber = yield* events.subscribe(SkillV2.Event.Updated).pipe(
|
||||
Stream.runForEach(() => Deferred.succeed(deferred, undefined).pipe(Effect.asVoid)),
|
||||
Effect.forkScoped,
|
||||
)
|
||||
yield* Effect.yieldNow
|
||||
return { deferred, fiber }
|
||||
})
|
||||
}
|
||||
|
||||
describe("SkillV2", () => {
|
||||
it.live("registers sources and resolves later source precedence", () =>
|
||||
Effect.acquireRelease(
|
||||
|
|
@ -124,4 +139,41 @@ describe("SkillV2", () => {
|
|||
),
|
||||
),
|
||||
)
|
||||
|
||||
it.live("invalidates cached skills and publishes updates for watcher changes", () =>
|
||||
Effect.acquireRelease(
|
||||
Effect.promise(() => tmpdir()),
|
||||
(tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
|
||||
).pipe(
|
||||
Effect.flatMap((tmp) =>
|
||||
Effect.gen(function* () {
|
||||
yield* Effect.promise(async () => {
|
||||
await fs.mkdir(path.join(tmp.path, "deploy"), { recursive: true })
|
||||
await write(tmp.path, "deploy", "Initial deploy")
|
||||
})
|
||||
|
||||
const events = yield* EventV2.Service
|
||||
const skill = yield* SkillV2.Service
|
||||
yield* skill.transform((editor) => editor.source({ type: "directory", path: AbsolutePath.make(tmp.path) }))
|
||||
|
||||
expect((yield* skill.list()).find((item) => item.name === "deploy")?.description).toBe("Initial deploy")
|
||||
|
||||
const file = path.join(tmp.path, "deploy", "SKILL.md")
|
||||
yield* Effect.promise(() => write(tmp.path, "deploy", "Updated deploy"))
|
||||
expect((yield* skill.list()).find((item) => item.name === "deploy")?.description).toBe("Initial deploy")
|
||||
|
||||
yield* Effect.acquireUseRelease(
|
||||
waitForSkillUpdate(),
|
||||
({ deferred }) =>
|
||||
events
|
||||
.publish(FileSystemWatcher.Event.Updated, { file, event: "change" })
|
||||
.pipe(Effect.andThen(Deferred.await(deferred)), Effect.timeout("1 second")),
|
||||
({ fiber }) => Fiber.interrupt(fiber),
|
||||
)
|
||||
|
||||
expect((yield* skill.list()).find((item) => item.name === "deploy")?.description).toBe("Updated deploy")
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue