feat(core): project copying and tracking directories (#30139)

This commit is contained in:
James Long 2026-06-02 23:26:10 -04:00 committed by GitHub
commit 147c6c4d51
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 3638 additions and 10 deletions

View file

@ -34,6 +34,12 @@ import type {
ExperimentalConsoleListOrgsErrors,
ExperimentalConsoleListOrgsResponses,
ExperimentalConsoleSwitchOrgResponses,
ExperimentalProjectCopyCreateErrors,
ExperimentalProjectCopyCreateResponses,
ExperimentalProjectCopyRefreshErrors,
ExperimentalProjectCopyRefreshResponses,
ExperimentalProjectCopyRemoveErrors,
ExperimentalProjectCopyRemoveResponses,
ExperimentalResourceListErrors,
ExperimentalResourceListResponses,
ExperimentalSessionListErrors,
@ -120,6 +126,8 @@ import type {
PermissionV2Reply,
ProjectCurrentErrors,
ProjectCurrentResponses,
ProjectDirectoriesErrors,
ProjectDirectoriesResponses,
ProjectInitGitErrors,
ProjectInitGitResponses,
ProjectListErrors,
@ -937,6 +945,148 @@ export class Resource extends HeyApiClient {
}
}
export class ProjectCopy extends HeyApiClient {
/**
* Remove project copy
*
* Remove a local physical copy of a project using the selected strategy.
*/
public remove<ThrowOnError extends boolean = false>(
parameters: {
projectID: string
query_directory?: string
workspace?: string
body_directory?: string
},
options?: Options<never, ThrowOnError>,
) {
const params = buildClientParams(
[parameters],
[
{
args: [
{ in: "path", key: "projectID" },
{
in: "query",
key: "query_directory",
map: "directory",
},
{ in: "query", key: "workspace" },
{
in: "body",
key: "body_directory",
map: "directory",
},
],
},
],
)
return (options?.client ?? this.client).delete<
ExperimentalProjectCopyRemoveResponses,
ExperimentalProjectCopyRemoveErrors,
ThrowOnError
>({
url: "/experimental/project/{projectID}/copy",
...options,
...params,
headers: {
"Content-Type": "application/json",
...options?.headers,
...params.headers,
},
})
}
/**
* Create project copy
*
* Create a local physical copy of a project using the selected strategy.
*/
public create<ThrowOnError extends boolean = false>(
parameters: {
projectID: string
query_directory?: string
workspace?: string
strategy?: "git_worktree"
body_directory?: string
},
options?: Options<never, ThrowOnError>,
) {
const params = buildClientParams(
[parameters],
[
{
args: [
{ in: "path", key: "projectID" },
{
in: "query",
key: "query_directory",
map: "directory",
},
{ in: "query", key: "workspace" },
{ in: "body", key: "strategy" },
{
in: "body",
key: "body_directory",
map: "directory",
},
],
},
],
)
return (options?.client ?? this.client).post<
ExperimentalProjectCopyCreateResponses,
ExperimentalProjectCopyCreateErrors,
ThrowOnError
>({
url: "/experimental/project/{projectID}/copy",
...options,
...params,
headers: {
"Content-Type": "application/json",
...options?.headers,
...params.headers,
},
})
}
/**
* Refresh project copies
*
* Discover local project copies using one or all configured strategies.
*/
public refresh<ThrowOnError extends boolean = false>(
parameters: {
projectID: string
directory?: string
workspace?: string
},
options?: Options<never, ThrowOnError>,
) {
const params = buildClientParams(
[parameters],
[
{
args: [
{ in: "path", key: "projectID" },
{ in: "query", key: "directory" },
{ in: "query", key: "workspace" },
],
},
],
)
return (options?.client ?? this.client).post<
ExperimentalProjectCopyRefreshResponses,
ExperimentalProjectCopyRefreshErrors,
ThrowOnError
>({
url: "/experimental/project/{projectID}/copy/refresh",
...options,
...params,
})
}
}
export class Adapter extends HeyApiClient {
/**
* List workspace adapters
@ -1226,6 +1376,11 @@ export class Experimental extends HeyApiClient {
return (this._resource ??= new Resource({ client: this.client }))
}
private _projectCopy?: ProjectCopy
get projectCopy(): ProjectCopy {
return (this._projectCopy ??= new ProjectCopy({ client: this.client }))
}
private _workspace?: Workspace
get workspace(): Workspace {
return (this._workspace ??= new Workspace({ client: this.client }))
@ -2388,6 +2543,38 @@ export class Project extends HeyApiClient {
},
})
}
/**
* List project directories
*
* List known local absolute directories for a project.
*/
public directories<ThrowOnError extends boolean = false>(
parameters: {
projectID: string
directory?: string
workspace?: string
},
options?: Options<never, ThrowOnError>,
) {
const params = buildClientParams(
[parameters],
[
{
args: [
{ in: "path", key: "projectID" },
{ in: "query", key: "directory" },
{ in: "query", key: "workspace" },
],
},
],
)
return (options?.client ?? this.client).get<ProjectDirectoriesResponses, ProjectDirectoriesErrors, ThrowOnError>({
url: "/project/{projectID}/directories",
...options,
...params,
})
}
}
export class Pty extends HeyApiClient {

View file

@ -63,6 +63,7 @@ export type Event =
| EventMcpToolsChanged
| EventMcpBrowserOpenFailed
| EventCommandExecuted
| EventProjectDirectoriesUpdated
| EventProjectUpdated
| EventPtyCreated
| EventPtyUpdated
@ -1300,6 +1301,13 @@ export type GlobalEvent = {
messageID: string
}
}
| {
id: string
type: "project.directories.updated"
properties: {
projectID: string
}
}
| {
id: string
type: "project.updated"
@ -3366,6 +3374,12 @@ export type ConfigV2ExperimentalPolicy = {
resource: string
}
export type ProjectDirectories = Array<string>
export type ProjectCopyCopy = {
directory: string
}
export type LocationRef = {
directory: string
workspaceID?: string
@ -4406,6 +4420,14 @@ export type EventCommandExecuted = {
}
}
export type EventProjectDirectoriesUpdated = {
id: string
type: "project.directories.updated"
properties: {
projectID: string
}
}
export type EventProjectUpdated = {
id: string
type: "project.updated"
@ -6254,6 +6276,137 @@ export type ProjectUpdateResponses = {
export type ProjectUpdateResponse = ProjectUpdateResponses[keyof ProjectUpdateResponses]
export type ProjectDirectoriesData = {
body?: never
path: {
projectID: string
}
query?: {
directory?: string
workspace?: string
}
url: "/project/{projectID}/directories"
}
export type ProjectDirectoriesErrors = {
/**
* Bad request
*/
400: BadRequestError
}
export type ProjectDirectoriesError = ProjectDirectoriesErrors[keyof ProjectDirectoriesErrors]
export type ProjectDirectoriesResponses = {
/**
* Project directories
*/
200: ProjectDirectories
}
export type ProjectDirectoriesResponse = ProjectDirectoriesResponses[keyof ProjectDirectoriesResponses]
export type ExperimentalProjectCopyRemoveData = {
body?: {
directory: string
}
path: {
projectID: string
}
query?: {
directory?: string
workspace?: string
}
url: "/experimental/project/{projectID}/copy"
}
export type ExperimentalProjectCopyRemoveErrors = {
/**
* BadRequest | InvalidRequestError
*/
400: EffectHttpApiErrorBadRequest | InvalidRequestError
}
export type ExperimentalProjectCopyRemoveError =
ExperimentalProjectCopyRemoveErrors[keyof ExperimentalProjectCopyRemoveErrors]
export type ExperimentalProjectCopyRemoveResponses = {
/**
* Project copy removed
*/
204: void
}
export type ExperimentalProjectCopyRemoveResponse =
ExperimentalProjectCopyRemoveResponses[keyof ExperimentalProjectCopyRemoveResponses]
export type ExperimentalProjectCopyCreateData = {
body?: {
strategy: "git_worktree"
directory: string
}
path: {
projectID: string
}
query?: {
directory?: string
workspace?: string
}
url: "/experimental/project/{projectID}/copy"
}
export type ExperimentalProjectCopyCreateErrors = {
/**
* BadRequest | InvalidRequestError
*/
400: EffectHttpApiErrorBadRequest | InvalidRequestError
}
export type ExperimentalProjectCopyCreateError =
ExperimentalProjectCopyCreateErrors[keyof ExperimentalProjectCopyCreateErrors]
export type ExperimentalProjectCopyCreateResponses = {
/**
* Project copy created
*/
200: ProjectCopyCopy
}
export type ExperimentalProjectCopyCreateResponse =
ExperimentalProjectCopyCreateResponses[keyof ExperimentalProjectCopyCreateResponses]
export type ExperimentalProjectCopyRefreshData = {
body?: never
path: {
projectID: string
}
query?: {
directory?: string
workspace?: string
}
url: "/experimental/project/{projectID}/copy/refresh"
}
export type ExperimentalProjectCopyRefreshErrors = {
/**
* BadRequest | InvalidRequestError
*/
400: EffectHttpApiErrorBadRequest | InvalidRequestError
}
export type ExperimentalProjectCopyRefreshError =
ExperimentalProjectCopyRefreshErrors[keyof ExperimentalProjectCopyRefreshErrors]
export type ExperimentalProjectCopyRefreshResponses = {
/**
* Project copies refreshed
*/
204: void
}
export type ExperimentalProjectCopyRefreshResponse =
ExperimentalProjectCopyRefreshResponses[keyof ExperimentalProjectCopyRefreshResponses]
export type PtyShellsData = {
body?: never
path?: never

View file

@ -3699,6 +3699,295 @@
]
}
},
"/project/{projectID}/directories": {
"get": {
"tags": ["project"],
"operationId": "project.directories",
"parameters": [
{
"name": "projectID",
"in": "path",
"schema": {
"type": "string"
},
"required": true
},
{
"name": "directory",
"in": "query",
"schema": {
"type": "string"
},
"required": false
},
{
"name": "workspace",
"in": "query",
"schema": {
"type": "string"
},
"required": false
}
],
"responses": {
"200": {
"description": "Project directories",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProjectDirectories"
}
}
}
},
"400": {
"description": "Bad request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BadRequestError"
}
}
}
}
},
"description": "List known local absolute directories for a project.",
"summary": "List project directories",
"x-codeSamples": [
{
"lang": "js",
"source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.project.directories({\n ...\n})"
}
]
}
},
"/experimental/project/{projectID}/copy": {
"post": {
"tags": ["projectCopy"],
"operationId": "experimental.projectCopy.create",
"parameters": [
{
"name": "projectID",
"in": "path",
"schema": {
"type": "string"
},
"required": true
},
{
"name": "directory",
"in": "query",
"schema": {
"type": "string"
},
"required": false
},
{
"name": "workspace",
"in": "query",
"schema": {
"type": "string"
},
"required": false
}
],
"responses": {
"200": {
"description": "Project copy created",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProjectCopyCopy"
}
}
}
},
"400": {
"description": "BadRequest | InvalidRequestError",
"content": {
"application/json": {
"schema": {
"anyOf": [
{
"$ref": "#/components/schemas/effect_HttpApiError_BadRequest"
},
{
"$ref": "#/components/schemas/InvalidRequestError"
}
]
}
}
}
}
},
"description": "Create a local physical copy of a project using the selected strategy.",
"summary": "Create project copy",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"strategy": {
"type": "string",
"enum": ["git_worktree"]
},
"directory": {
"type": "string"
}
},
"required": ["strategy", "directory"],
"additionalProperties": false
}
}
}
},
"x-codeSamples": [
{
"lang": "js",
"source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.projectCopy.create({\n ...\n})"
}
]
},
"delete": {
"tags": ["projectCopy"],
"operationId": "experimental.projectCopy.remove",
"parameters": [
{
"name": "projectID",
"in": "path",
"schema": {
"type": "string"
},
"required": true
},
{
"name": "directory",
"in": "query",
"schema": {
"type": "string"
},
"required": false
},
{
"name": "workspace",
"in": "query",
"schema": {
"type": "string"
},
"required": false
}
],
"responses": {
"204": {
"description": "Project copy removed"
},
"400": {
"description": "BadRequest | InvalidRequestError",
"content": {
"application/json": {
"schema": {
"anyOf": [
{
"$ref": "#/components/schemas/effect_HttpApiError_BadRequest"
},
{
"$ref": "#/components/schemas/InvalidRequestError"
}
]
}
}
}
}
},
"description": "Remove a local physical copy of a project using the selected strategy.",
"summary": "Remove project copy",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"directory": {
"type": "string"
}
},
"required": ["directory"],
"additionalProperties": false
}
}
}
},
"x-codeSamples": [
{
"lang": "js",
"source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.projectCopy.remove({\n ...\n})"
}
]
}
},
"/experimental/project/{projectID}/copy/refresh": {
"post": {
"tags": ["projectCopy"],
"operationId": "experimental.projectCopy.refresh",
"parameters": [
{
"name": "projectID",
"in": "path",
"schema": {
"type": "string"
},
"required": true
},
{
"name": "directory",
"in": "query",
"schema": {
"type": "string"
},
"required": false
},
{
"name": "workspace",
"in": "query",
"schema": {
"type": "string"
},
"required": false
}
],
"responses": {
"204": {
"description": "Project copies refreshed"
},
"400": {
"description": "BadRequest | InvalidRequestError",
"content": {
"application/json": {
"schema": {
"anyOf": [
{
"$ref": "#/components/schemas/effect_HttpApiError_BadRequest"
},
{
"$ref": "#/components/schemas/InvalidRequestError"
}
]
}
}
}
}
},
"description": "Discover local project copies using one or all configured strategies.",
"summary": "Refresh project copies",
"x-codeSamples": [
{
"lang": "js",
"source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.experimental.projectCopy.refresh({\n ...\n})"
}
]
}
},
"/pty/shells": {
"get": {
"tags": ["pty"],
@ -11173,6 +11462,9 @@
{
"$ref": "#/components/schemas/EventCommandExecuted"
},
{
"$ref": "#/components/schemas/EventProjectDirectoriesUpdated"
},
{
"$ref": "#/components/schemas/EventProjectUpdated"
},
@ -15039,6 +15331,30 @@
"required": ["id", "type", "properties"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["project.directories.updated"]
},
"properties": {
"type": "object",
"properties": {
"projectID": {
"type": "string"
}
},
"required": ["projectID"],
"additionalProperties": false
}
},
"required": ["id", "type", "properties"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
@ -21149,6 +21465,22 @@
"required": ["action", "effect", "resource"],
"additionalProperties": false
},
"ProjectDirectories": {
"type": "array",
"items": {
"type": "string"
}
},
"ProjectCopyCopy": {
"type": "object",
"properties": {
"directory": {
"type": "string"
}
},
"required": ["directory"],
"additionalProperties": false
},
"LocationRef": {
"type": "object",
"properties": {
@ -24299,6 +24631,30 @@
"required": ["id", "type", "properties"],
"additionalProperties": false
},
"EventProjectDirectoriesUpdated": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["project.directories.updated"]
},
"properties": {
"type": "object",
"properties": {
"projectID": {
"type": "string"
}
},
"required": ["projectID"],
"additionalProperties": false
}
},
"required": ["id", "type", "properties"],
"additionalProperties": false
},
"EventProjectUpdated": {
"type": "object",
"properties": {
@ -24947,6 +25303,10 @@
"name": "project",
"description": "Experimental HttpApi project routes."
},
{
"name": "projectCopy",
"description": "Project copy management routes."
},
{
"name": "pty",
"description": "Experimental HttpApi PTY routes."