feat(core): refactor project copies for v2 (#31943)

This commit is contained in:
James Long
2026-06-12 14:45:16 -04:00
committed by GitHub
parent 8d97c8d412
commit c2e6b18076
33 changed files with 1468 additions and 836 deletions
@@ -1,87 +1,31 @@
import { ProjectCopy } from "@opencode-ai/core/project/copy"
import { ProjectV2 } from "@opencode-ai/core/project"
import { Schema } from "effect"
import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi"
import { HttpApi, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
import { Authorization } from "../middleware/authorization"
import { InstanceContextMiddleware } from "../middleware/instance-context"
import {
WorkspaceRoutingMiddleware,
WorkspaceRoutingQuery,
WorkspaceRoutingQueryFields,
} from "../middleware/workspace-routing"
import { described } from "./metadata"
import { WorkspaceRoutingMiddleware, WorkspaceRoutingQuery } from "../middleware/workspace-routing"
const root = "/experimental/project/:projectID/copy"
const CopyQuery = Schema.Struct({
workspace: WorkspaceRoutingQueryFields.workspace,
export const GenerateNamePayload = Schema.Struct({
context: Schema.optional(Schema.String),
})
export const CreatePayload = Schema.Struct({
strategy: ProjectCopy.StrategyID,
directory: ProjectCopy.CreateInput.fields.directory,
name: ProjectCopy.CreateInput.fields.name,
context: ProjectCopy.CreateInput.fields.context,
})
export const RemovePayload = Schema.Struct({
directory: ProjectCopy.RemoveInput.fields.directory,
force: ProjectCopy.RemoveInput.fields.force,
})
export class ApiProjectCopyError extends Schema.ErrorClass<ApiProjectCopyError>("ProjectCopyError")(
{
name: Schema.Literal("ProjectCopyError"),
data: Schema.Struct({
message: Schema.String,
forceRequired: Schema.optional(Schema.Boolean),
}),
},
{ httpApiStatus: 400 },
) {}
export const ProjectCopyApi = HttpApi.make("projectCopy").add(
HttpApiGroup.make("projectCopy")
export const ProjectCopyApi = HttpApi.make("projectCopyName").add(
HttpApiGroup.make("projectCopyName")
.add(
HttpApiEndpoint.post("create", root, {
params: { projectID: ProjectV2.ID },
query: CopyQuery,
payload: CreatePayload,
success: described(ProjectCopy.Copy, "Project copy created"),
error: ApiProjectCopyError,
}).annotateMerge(
OpenApi.annotations({
identifier: "experimental.projectCopy.create",
summary: "Create project copy",
description: "Create a local physical copy of a project using the selected strategy.",
}),
),
HttpApiEndpoint.delete("remove", root, {
params: { projectID: ProjectV2.ID },
query: CopyQuery,
payload: RemovePayload,
success: described(HttpApiSchema.NoContent, "Project copy removed"),
error: ApiProjectCopyError,
}).annotateMerge(
OpenApi.annotations({
identifier: "experimental.projectCopy.remove",
summary: "Remove project copy",
description: "Remove a local physical copy of a project using the selected strategy.",
}),
),
HttpApiEndpoint.post("refresh", `${root}/refresh`, {
HttpApiEndpoint.post("generateName", "/experimental/project/:projectID/copy/generate-name", {
params: { projectID: ProjectV2.ID },
query: WorkspaceRoutingQuery,
payload: HttpApiSchema.NoContent,
success: described(HttpApiSchema.NoContent, "Project copies refreshed"),
error: ApiProjectCopyError,
payload: GenerateNamePayload,
success: Schema.Struct({ name: Schema.String }),
}).annotateMerge(
OpenApi.annotations({
identifier: "experimental.projectCopy.refresh",
summary: "Refresh project copies",
description: "Discover local project copies using one or all configured strategies.",
identifier: "experimental.projectCopy.generateName",
summary: "Generate project copy name",
description: "Generate a short name for a project copy from task context.",
}),
),
)
.annotateMerge(OpenApi.annotations({ title: "projectCopy", description: "Project copy management routes." }))
.annotateMerge(OpenApi.annotations({ title: "projectCopy", description: "Project copy naming routes." }))
.middleware(InstanceContextMiddleware)
.middleware(WorkspaceRoutingMiddleware)
.middleware(Authorization),