skill.test.ts 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import path from "path"
  2. import { describe, expect } from "bun:test"
  3. import { Effect, Layer, Schema } from "effect"
  4. import { Config } from "@opencode-ai/core/config"
  5. import { ConfigSkillPlugin } from "@opencode-ai/core/config/plugin/skill"
  6. import { Global } from "@opencode-ai/core/global"
  7. import { Location } from "@opencode-ai/core/location"
  8. import { AbsolutePath } from "@opencode-ai/core/schema"
  9. import { SkillV2 } from "@opencode-ai/core/skill"
  10. import { location } from "../fixture/location"
  11. import { testEffect } from "../lib/effect"
  12. import { host } from "../plugin/host"
  13. const it = testEffect(Layer.empty)
  14. const decode = Schema.decodeUnknownSync(Config.Info)
  15. describe("ConfigSkillPlugin.Plugin", () => {
  16. it.effect("registers configured skill directories and URLs", () =>
  17. Effect.gen(function* () {
  18. const directory = AbsolutePath.make("/repo/packages/app")
  19. const sources: SkillV2.Source[] = []
  20. const transform = Effect.fnUntraced(function* (update: (draft: SkillV2.Draft) => void | Effect.Effect<void>) {
  21. const result = update({
  22. source: (source) => {
  23. sources.push(source)
  24. },
  25. list: () => sources,
  26. })
  27. if (Effect.isEffect(result)) yield* result
  28. const dispose = Effect.sync(() => {
  29. sources.length = 0
  30. })
  31. yield* Effect.addFinalizer(() => dispose)
  32. return { dispose }
  33. })
  34. yield* ConfigSkillPlugin.Plugin.effect(
  35. host({
  36. location: location({ directory }),
  37. path: { ...host().path, home: "/home/test" },
  38. skill: SkillV2.Service.of({
  39. transform,
  40. rebuild: () => Effect.void,
  41. sources: () => Effect.succeed(sources),
  42. list: () => Effect.succeed([]),
  43. }),
  44. }),
  45. ).pipe(
  46. Effect.provideService(
  47. Config.Service,
  48. Config.Service.of({
  49. entries: () =>
  50. Effect.succeed([
  51. new Config.Directory({ type: "directory", path: AbsolutePath.make("/repo/.opencode") }),
  52. new Config.Document({
  53. type: "document",
  54. info: decode({
  55. skills: ["./skills", "~/shared-skills", "/opt/skills", "https://example.test/skills/"],
  56. }),
  57. }),
  58. ]),
  59. }),
  60. ),
  61. )
  62. expect(sources).toEqual([
  63. new SkillV2.DirectorySource({
  64. type: "directory",
  65. path: AbsolutePath.make(path.join("/repo/.opencode", "skill")),
  66. }),
  67. new SkillV2.DirectorySource({
  68. type: "directory",
  69. path: AbsolutePath.make(path.join("/repo/.opencode", "skills")),
  70. }),
  71. new SkillV2.DirectorySource({ type: "directory", path: AbsolutePath.make(path.join(directory, "skills")) }),
  72. new SkillV2.DirectorySource({
  73. type: "directory",
  74. path: AbsolutePath.make(path.join("/home/test", "shared-skills")),
  75. }),
  76. new SkillV2.DirectorySource({ type: "directory", path: AbsolutePath.make("/opt/skills") }),
  77. new SkillV2.UrlSource({ type: "url", url: "https://example.test/skills/" }),
  78. ])
  79. }),
  80. )
  81. })