command.test.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import fs from "fs/promises"
  2. import path from "path"
  3. import { describe, expect } from "bun:test"
  4. import { Effect, Layer, Schema } from "effect"
  5. import { CommandV2 } from "@opencode-ai/core/command"
  6. import { Config } from "@opencode-ai/core/config"
  7. import { ConfigCommandPlugin } from "@opencode-ai/core/config/plugin/command"
  8. import { FSUtil } from "@opencode-ai/core/fs-util"
  9. import { ModelV2 } from "@opencode-ai/core/model"
  10. import { ProviderV2 } from "@opencode-ai/core/provider"
  11. import { AbsolutePath } from "@opencode-ai/core/schema"
  12. import { tmpdir } from "../fixture/tmpdir"
  13. import { testEffect } from "../lib/effect"
  14. import { host } from "../plugin/host"
  15. const it = testEffect(Layer.mergeAll(CommandV2.locationLayer, FSUtil.defaultLayer))
  16. const decode = Schema.decodeUnknownSync(Config.Info)
  17. describe("ConfigCommandPlugin.Plugin", () => {
  18. it.live("loads inline and file-based commands in config order", () =>
  19. Effect.acquireRelease(
  20. Effect.promise(() => tmpdir()),
  21. (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
  22. ).pipe(
  23. Effect.flatMap((tmp) =>
  24. Effect.gen(function* () {
  25. yield* Effect.promise(async () => {
  26. await fs.mkdir(path.join(tmp.path, "commands", "nested"), { recursive: true })
  27. await fs.writeFile(
  28. path.join(tmp.path, "commands", "review.md"),
  29. `---
  30. description: File review
  31. agent: reviewer
  32. model: anthropic/claude
  33. variant: high
  34. subtask: true
  35. ---
  36. Review files`,
  37. )
  38. await fs.writeFile(path.join(tmp.path, "commands", "nested", "docs.md"), "Write docs")
  39. await fs.writeFile(path.join(tmp.path, "commands", "empty.md"), "")
  40. })
  41. const command = yield* CommandV2.Service
  42. yield* ConfigCommandPlugin.Plugin.effect(host({ command: { ...command, reload: command.reload } })).pipe(
  43. Effect.provideService(
  44. Config.Service,
  45. Config.Service.of({
  46. entries: () =>
  47. Effect.succeed([
  48. new Config.Document({
  49. type: "document",
  50. info: decode({ commands: { review: { template: "Inline review" } } }),
  51. }),
  52. new Config.Directory({ type: "directory", path: AbsolutePath.make(tmp.path) }),
  53. ]),
  54. }),
  55. ),
  56. )
  57. expect(yield* command.list()).toEqual([
  58. CommandV2.Info.make({
  59. name: "review",
  60. template: "Review files",
  61. description: "File review",
  62. agent: "reviewer",
  63. model: {
  64. providerID: ProviderV2.ID.make("anthropic"),
  65. id: ModelV2.ID.make("claude"),
  66. variant: ModelV2.VariantID.make("high"),
  67. },
  68. subtask: true,
  69. }),
  70. CommandV2.Info.make({ name: "empty", template: "" }),
  71. CommandV2.Info.make({ name: "nested/docs", template: "Write docs" }),
  72. ])
  73. }),
  74. ),
  75. ),
  76. )
  77. })