location.ts 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. import { Location } from "@opencode-ai/core/location"
  2. import { LocationServiceMap } from "@opencode-ai/core/location-layer"
  3. import { AbsolutePath } from "@opencode-ai/core/schema"
  4. import { WorkspaceV2 } from "@opencode-ai/core/workspace"
  5. import { Effect, Layer } from "effect"
  6. import { HttpServerRequest } from "effect/unstable/http"
  7. import { HttpApiMiddleware } from "effect/unstable/httpapi"
  8. export type LocationServices = Layer.Success<ReturnType<(typeof LocationServiceMap)["get"]>>
  9. export class LocationMiddleware extends HttpApiMiddleware.Service<LocationMiddleware, { provides: LocationServices }>()(
  10. "@opencode/HttpApiLocation",
  11. ) {}
  12. export function response<A, E, R>(data: Effect.Effect<A, E, R>) {
  13. return Effect.gen(function* () {
  14. const location = yield* Location.Service
  15. return {
  16. location: new Location.Info({
  17. directory: location.directory,
  18. workspaceID: location.workspaceID,
  19. project: location.project,
  20. }),
  21. data: yield* data,
  22. }
  23. })
  24. }
  25. function ref(request: HttpServerRequest.HttpServerRequest): Location.Ref {
  26. const query = new URL(request.url, "http://localhost").searchParams
  27. const workspaceID = query.get("location[workspace]") || request.headers["x-opencode-workspace"]
  28. const directory =
  29. query.get("location[directory]") ||
  30. (request.headers["x-opencode-directory"] ? decode(request.headers["x-opencode-directory"]) : process.cwd())
  31. return Location.Ref.make({
  32. directory: AbsolutePath.make(directory),
  33. workspaceID: workspaceID ? WorkspaceV2.ID.make(workspaceID) : undefined,
  34. })
  35. }
  36. function decode(input: string) {
  37. try {
  38. return decodeURIComponent(input)
  39. } catch {
  40. return input
  41. }
  42. }
  43. export const layer = Layer.effect(
  44. LocationMiddleware,
  45. Effect.gen(function* () {
  46. const locations = yield* LocationServiceMap
  47. return LocationMiddleware.of((effect) =>
  48. Effect.gen(function* () {
  49. const request = yield* HttpServerRequest.HttpServerRequest
  50. return yield* effect.pipe(Effect.provide(locations.get(ref(request))))
  51. }),
  52. )
  53. }),
  54. )