workspace-adapter.test.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import { afterEach, describe, expect } from "bun:test"
  2. import { Effect, Layer } from "effect"
  3. import { Npm } from "@kirincode-ai/core/npm"
  4. import { Ripgrep } from "@kirincode-ai/core/ripgrep"
  5. import path from "path"
  6. import { pathToFileURL } from "url"
  7. import { Auth } from "../../src/auth"
  8. import { Account } from "../../src/account/account"
  9. import { RuntimeFlags } from "../../src/effect/runtime-flags"
  10. import { Workspace } from "../../src/control-plane/workspace"
  11. import { Plugin } from "../../src/plugin/index"
  12. import { InstanceBootstrap } from "../../src/project/bootstrap"
  13. import { InstanceStore } from "../../src/project/instance-store"
  14. import { InstanceState } from "../../src/effect/instance-state"
  15. import { disposeAllInstances, TestInstance } from "../fixture/fixture"
  16. import { testEffect } from "../lib/effect"
  17. import { AccountTest } from "../fake/account"
  18. import { AuthTest } from "../fake/auth"
  19. import { NpmTest } from "../fake/npm"
  20. import { AppNodeBuilder } from "@kirincode-ai/core/effect/app-node-builder"
  21. import { LayerNode } from "@kirincode-ai/core/effect/layer-node"
  22. const noopBootstrapLayer = Layer.succeed(InstanceBootstrap.Service, InstanceBootstrap.Service.of({ run: Effect.void }))
  23. const it = testEffect(
  24. AppNodeBuilder.build(LayerNode.group([Plugin.node, Workspace.node, InstanceStore.node, Ripgrep.node]), [
  25. [Auth.node, AuthTest.empty],
  26. [Account.node, AccountTest.empty],
  27. [Npm.node, NpmTest.noop],
  28. [InstanceStore.bootstrapNode, noopBootstrapLayer],
  29. [RuntimeFlags.node, RuntimeFlags.layer({ disableDefaultPlugins: true, experimentalWorkspaces: true })],
  30. ]),
  31. )
  32. afterEach(async () => {
  33. await disposeAllInstances()
  34. })
  35. describe("plugin.workspace", () => {
  36. it.instance("plugin can install a workspace adapter", () =>
  37. Effect.gen(function* () {
  38. const dir = (yield* TestInstance).directory
  39. const type = `plug-${Math.random().toString(36).slice(2)}`
  40. const file = path.join(dir, "plugin.ts")
  41. const mark = path.join(dir, "created.json")
  42. const space = path.join(dir, "space")
  43. yield* Effect.promise(() =>
  44. Bun.write(
  45. file,
  46. [
  47. "export default async ({ experimental_workspace }) => {",
  48. ` experimental_workspace.register(${JSON.stringify(type)}, {`,
  49. ' name: "plug",',
  50. ' description: "plugin workspace adapter",',
  51. " configure(input) {",
  52. ` return { ...input, name: "plug", branch: "plug/main", directory: ${JSON.stringify(space)} }`,
  53. " },",
  54. " async create(input) {",
  55. ` await Bun.write(${JSON.stringify(mark)}, JSON.stringify(input))`,
  56. " },",
  57. " async remove() {},",
  58. " target(input) {",
  59. ' return { type: "local", directory: input.directory }',
  60. " },",
  61. " })",
  62. " return {}",
  63. "}",
  64. "",
  65. ].join("\n"),
  66. ),
  67. )
  68. yield* Effect.promise(() =>
  69. Bun.write(
  70. path.join(dir, "kirincode.json"),
  71. JSON.stringify(
  72. {
  73. $schema: "https://kirincode.ai/config.json",
  74. plugin: [pathToFileURL(file).href],
  75. },
  76. null,
  77. 2,
  78. ),
  79. ),
  80. )
  81. const plugin = yield* Plugin.Service
  82. yield* plugin.init()
  83. const workspace = yield* Workspace.Service
  84. const ctx = yield* InstanceState.context
  85. const info = yield* workspace.create({
  86. type,
  87. branch: null,
  88. extra: { key: "value" },
  89. projectID: ctx.project.id,
  90. })
  91. expect(info.type).toBe(type)
  92. expect(info.name).toBe("plug")
  93. expect(info.branch).toBe("plug/main")
  94. expect(info.directory).toBe(space)
  95. expect(info.extra).toEqual({ key: "value" })
  96. expect(JSON.parse(yield* Effect.promise(() => Bun.file(mark).text()))).toMatchObject({
  97. type,
  98. name: "plug",
  99. branch: "plug/main",
  100. directory: space,
  101. extra: { key: "value" },
  102. })
  103. }),
  104. )
  105. })