refactor(protocol): remove current project endpoint

This commit is contained in:
Dax Raad
2026-09-13 16:19:25 -04:00
parent 195158c34c
commit 42ff564913
39 changed files with 1195 additions and 526 deletions
+261
View File
@@ -0,0 +1,261 @@
# V2 HTTP API audit checklist
**Source:** `packages/protocol/openapi.json`
**Current endpoint count:** 143
**Last regenerated:** 2026-09-13
## How to use this checklist
Review endpoints in document order. For each endpoint, select one disposition and capture rationale or follow-up work in Notes. Mark **Reviewed** only after the disposition is agreed.
### Review criteria
- Resource and operation naming
- HTTP method and idempotency
- Request parameters and location scope
- Response shape and error taxonomy
- Authentication and authorization
- Current production consumers
- Stability level: public, experimental, or internal
- Whether the generated client API is intuitive
### Disposition legend
- **Keep:** ship unchanged as a supported V2 API
- **Change:** retain after a defined contract change
- **Remove:** exclude from the official V2 API
- **Experimental-only:** retain outside the stable API commitment
## Progress
- [ ] Group 1: Foundation and placement (7)
- [ ] Group 2: Configuration and capability catalogs (17)
- [ ] Group 3: Credentials, integrations, MCP, and web search (22)
- [ ] Group 4: Session lifecycle (12)
- [ ] Group 5: Session execution and inputs (11)
- [ ] Group 6: Session history and recovery (13)
- [ ] Group 7: Inbox, permissions, and forms (19)
- [ ] Group 8: Filesystem, worktrees, and VCS (12)
- [ ] Group 9: PTYs, persistent terminals, and shells (24)
- [ ] Group 10: Events, RPC, and experimental operations (6)
## Resolved during audit
### [x] `GET /api/project/current`
- **Decision:** Remove
- **Replacement:** `GET /api/location`, using `project` from the response.
- **Notes:** The endpoint duplicated `Location.Info.project`; production callers were migrated.
## Group 1: Foundation and placement
**Endpoints:** 7
| Done | Method | Path | Operation ID | Decision | Notes |
|---|---|---|---|---|---|
| [ ] 001 | `GET` | `/api/health` | `v2.health.get` | | |
| [ ] 002 | `GET` | `/api/server` | `v2.server.get` | | |
| [ ] 003 | `GET` | `/api/location` | `v2.location.get` | | |
| [ ] 004 | `GET` | `/api/project` | `v2.project.list` | | |
| [ ] 005 | `PATCH` | `/api/project/{projectID}` | `v2.project.update` | | |
| [ ] 006 | `POST` | `/api/workspace` | `v2.workspace.create` | Proposed remove | Awaiting feedback in `#core`. |
| [ ] 007 | `DELETE` | `/api/workspace/{workspaceID}` | `v2.workspace.destroy` | Proposed remove | Awaiting feedback in `#core`. |
## Group 2: Configuration and capability catalogs
**Endpoints:** 17
| Done | Method | Path | Operation ID | Decision | Notes |
|---|---|---|---|---|---|
| [ ] 008 | `GET` | `/api/agent` | `v2.agent.list` | | |
| [ ] 009 | `GET` | `/api/agent/{agentID}` | `v2.agent.get` | | |
| [ ] 010 | `GET` | `/api/plugin` | `v2.plugin.list` | | |
| [ ] 011 | `POST` | `/api/plugin/await-activation` | `v2.plugin.awaitActivation` | | |
| [ ] 012 | `POST` | `/api/plugin/check` | `v2.plugin.check` | | |
| [ ] 013 | `POST` | `/api/plugin/update` | `v2.plugin.update` | | |
| [ ] 014 | `GET` | `/api/model` | `v2.model.list` | | |
| [ ] 015 | `GET` | `/api/model/default` | `v2.model.default` | | |
| [ ] 016 | `GET` | `/api/provider` | `v2.provider.list` | | |
| [ ] 017 | `GET` | `/api/provider/{providerID}` | `v2.provider.get` | | |
| [ ] 018 | `GET` | `/api/command` | `v2.command.list` | | |
| [ ] 019 | `GET` | `/api/skill` | `v2.skill.list` | | |
| [ ] 020 | `GET` | `/api/reference` | `v2.reference.list` | | |
| [ ] 021 | `GET` | `/api/config` | `v2.config.get` | | |
| [ ] 022 | `GET` | `/api/config/preferences` | `v2.config.preferences` | | |
| [ ] 023 | `PATCH` | `/api/config/preferences` | `v2.config.updatePreferences` | | |
| [ ] 024 | `GET` | `/api/config/shell` | `v2.config.shells` | | |
## Group 3: Credentials, integrations, MCP, and web search
**Endpoints:** 22
| Done | Method | Path | Operation ID | Decision | Notes |
|---|---|---|---|---|---|
| [ ] 025 | `GET` | `/api/integration` | `v2.integration.list` | | |
| [ ] 026 | `GET` | `/api/integration/{integrationID}` | `v2.integration.get` | | |
| [ ] 027 | `POST` | `/api/experimental/integration/wellknown` | `v2.experimental.integration.wellknown.add` | | |
| [ ] 028 | `POST` | `/api/integration/{integrationID}/connect/key` | `v2.integration.connect.key` | | |
| [ ] 029 | `POST` | `/api/integration/{integrationID}/connect/oauth` | `v2.integration.oauth.connect` | | |
| [ ] 030 | `GET` | `/api/integration/{integrationID}/connect/oauth/{attemptID}` | `v2.integration.oauth.status` | | |
| [ ] 031 | `DELETE` | `/api/integration/{integrationID}/connect/oauth/{attemptID}` | `v2.integration.oauth.cancel` | | |
| [ ] 032 | `POST` | `/api/integration/{integrationID}/connect/oauth/{attemptID}/complete` | `v2.integration.oauth.complete` | | |
| [ ] 033 | `POST` | `/api/integration/{integrationID}/connect/command` | `v2.integration.command.connect` | | |
| [ ] 034 | `GET` | `/api/integration/{integrationID}/connect/command/{attemptID}` | `v2.integration.command.status` | | |
| [ ] 035 | `DELETE` | `/api/integration/{integrationID}/connect/command/{attemptID}` | `v2.integration.command.cancel` | | |
| [ ] 036 | `GET` | `/api/mcp` | `v2.mcp.list` | | |
| [ ] 037 | `PUT` | `/api/mcp/{server}` | `v2.mcp.add` | | |
| [ ] 038 | `DELETE` | `/api/mcp/{server}` | `v2.mcp.remove` | | |
| [ ] 039 | `POST` | `/api/mcp/{server}/connect` | `v2.mcp.connect` | | |
| [ ] 040 | `POST` | `/api/mcp/{server}/disconnect` | `v2.mcp.disconnect` | | |
| [ ] 041 | `GET` | `/api/mcp/resource` | `v2.mcp.resource.catalog` | | |
| [ ] 042 | `PATCH` | `/api/credential/{credentialID}` | `v2.credential.update` | | |
| [ ] 043 | `DELETE` | `/api/credential/{credentialID}` | `v2.credential.remove` | | |
| [ ] 044 | `POST` | `/api/credential/{credentialID}/activate` | `v2.credential.activate` | | |
| [ ] 045 | `GET` | `/api/websearch/provider` | `v2.websearch.providers` | | |
| [ ] 046 | `POST` | `/api/websearch` | `v2.websearch.query` | | |
## Group 4: Session lifecycle
**Endpoints:** 12
| Done | Method | Path | Operation ID | Decision | Notes |
|---|---|---|---|---|---|
| [ ] 047 | `GET` | `/api/session` | `v2.session.list` | | |
| [ ] 048 | `POST` | `/api/session` | `v2.session.create` | | |
| [ ] 049 | `GET` | `/api/session/stats` | `v2.session.stats` | | |
| [ ] 050 | `GET` | `/api/session/active` | `v2.session.active` | | |
| [ ] 051 | `GET` | `/api/session/{sessionID}` | `v2.session.get` | | |
| [ ] 052 | `DELETE` | `/api/session/{sessionID}` | `v2.session.remove` | | |
| [ ] 053 | `POST` | `/api/session/{sessionID}/fork` | `v2.session.fork` | | |
| [ ] 054 | `POST` | `/api/session/{sessionID}/agent` | `v2.session.switchAgent` | | |
| [ ] 055 | `POST` | `/api/session/{sessionID}/model` | `v2.session.switchModel` | | |
| [ ] 056 | `POST` | `/api/session/{sessionID}/rename` | `v2.session.rename` | | |
| [ ] 057 | `POST` | `/api/session/{sessionID}/move` | `v2.session.move` | | |
| [ ] 058 | `POST` | `/api/session/{sessionID}/background` | `v2.session.background` | | |
## Group 5: Session execution and inputs
**Endpoints:** 11
| Done | Method | Path | Operation ID | Decision | Notes |
|---|---|---|---|---|---|
| [ ] 059 | `POST` | `/api/session/{sessionID}/prompt` | `v2.session.prompt` | | |
| [ ] 060 | `POST` | `/api/session/{sessionID}/command` | `v2.session.command` | | |
| [ ] 061 | `POST` | `/api/session/{sessionID}/skill` | `v2.session.skill` | | |
| [ ] 062 | `POST` | `/api/session/{sessionID}/synthetic` | `v2.session.synthetic` | | |
| [ ] 063 | `POST` | `/api/session/{sessionID}/shell` | `v2.session.shell` | | |
| [ ] 064 | `POST` | `/api/session/{sessionID}/compact` | `v2.session.compact` | | |
| [ ] 065 | `POST` | `/api/session/{sessionID}/wait` | `v2.session.wait` | | |
| [ ] 066 | `POST` | `/api/session/{sessionID}/generate` | `v2.session.generate` | | |
| [ ] 067 | `POST` | `/api/session/{sessionID}/interrupt` | `v2.session.interrupt` | | |
| [ ] 068 | `PUT` | `/api/session/{sessionID}/environment` | `v2.session.environment` | | |
| [ ] 069 | `POST` | `/api/session/{sessionID}/view` | `v2.session.view` | | |
## Group 6: Session history and recovery
**Endpoints:** 13
| Done | Method | Path | Operation ID | Decision | Notes |
|---|---|---|---|---|---|
| [ ] 070 | `POST` | `/api/session/import` | `v2.session.import` | | |
| [ ] 071 | `GET` | `/api/session/{sessionID}/export` | `v2.session.export` | | |
| [ ] 072 | `POST` | `/api/session/{sessionID}/revert/stage` | `v2.session.revert.stage` | | |
| [ ] 073 | `POST` | `/api/session/{sessionID}/revert/clear` | `v2.session.revert.clear` | | |
| [ ] 074 | `POST` | `/api/session/{sessionID}/revert/commit` | `v2.session.revert.commit` | | |
| [ ] 075 | `GET` | `/api/session/{sessionID}/context` | `v2.session.context` | | |
| [ ] 076 | `GET` | `/api/session/{sessionID}/diff` | `v2.session.diff` | | |
| [ ] 077 | `GET` | `/api/session/{sessionID}/instructions/entries` | `v2.session.instructions.entry.list` | | |
| [ ] 078 | `PUT` | `/api/session/{sessionID}/instructions/entries/{key}` | `v2.session.instructions.entry.put` | | |
| [ ] 079 | `DELETE` | `/api/session/{sessionID}/instructions/entries/{key}` | `v2.session.instructions.entry.remove` | | |
| [ ] 080 | `GET` | `/api/experimental/session/{sessionID}/log` | `v2.session.log` | | |
| [ ] 081 | `GET` | `/api/session/{sessionID}/message/{messageID}` | `v2.session.message` | | |
| [ ] 082 | `GET` | `/api/session/{sessionID}/message` | `v2.message.list` | | |
## Group 7: Inbox, permissions, and forms
**Endpoints:** 19
| Done | Method | Path | Operation ID | Decision | Notes |
|---|---|---|---|---|---|
| [ ] 083 | `GET` | `/api/session/{sessionID}/inbox` | `v2.session.inbox.list` | | |
| [ ] 084 | `DELETE` | `/api/session/{sessionID}/inbox/{inboxID}` | `v2.session.inbox.cancel` | | |
| [ ] 085 | `POST` | `/api/session/{sessionID}/inbox/{inboxID}/steer` | `v2.session.inbox.steer` | | |
| [ ] 086 | `POST` | `/api/session/{sessionID}/inbox/{inboxID}/queue` | `v2.session.inbox.queue` | | |
| [ ] 087 | `GET` | `/api/form/request` | `v2.form.request.list` | | |
| [ ] 088 | `GET` | `/api/session/{sessionID}/form` | `v2.session.form.list` | | |
| [ ] 089 | `POST` | `/api/session/{sessionID}/form` | `v2.session.form.create` | | |
| [ ] 090 | `GET` | `/api/session/{sessionID}/form/{formID}` | `v2.session.form.get` | | |
| [ ] 091 | `GET` | `/api/session/{sessionID}/form/{formID}/state` | `v2.session.form.state` | | |
| [ ] 092 | `POST` | `/api/session/{sessionID}/form/{formID}/reply` | `v2.session.form.reply` | | |
| [ ] 093 | `POST` | `/api/session/{sessionID}/form/{formID}/cancel` | `v2.session.form.cancel` | | |
| [ ] 094 | `GET` | `/api/permission/request` | `v2.permission.request.list` | | |
| [ ] 095 | `GET` | `/api/permission/saved` | `v2.permission.saved.list` | | |
| [ ] 096 | `DELETE` | `/api/permission/saved/{id}` | `v2.permission.saved.remove` | | |
| [ ] 097 | `POST` | `/api/session/{sessionID}/permission` | `v2.session.permission.create` | | |
| [ ] 098 | `GET` | `/api/session/{sessionID}/permission` | `v2.session.permission.list` | | |
| [ ] 099 | `GET` | `/api/session/{sessionID}/permission/{requestID}` | `v2.session.permission.get` | | |
| [ ] 100 | `POST` | `/api/session/{sessionID}/permission/{requestID}/reply` | `v2.session.permission.reply` | | |
| [ ] 101 | `PUT` | `/api/session/{sessionID}/permission/rules` | `v2.session.permission.rules` | | |
## Group 8: Filesystem, worktrees, and VCS
**Endpoints:** 12
| Done | Method | Path | Operation ID | Decision | Notes |
|---|---|---|---|---|---|
| [ ] 102 | `GET` | `/api/fs/read/*` | `v2.fs.read` | | |
| [ ] 103 | `GET` | `/api/fs/list` | `v2.fs.list` | | |
| [ ] 104 | `GET` | `/api/fs/find` | `v2.fs.find` | | |
| [ ] 105 | `GET` | `/api/worktree` | `v2.worktree.list` | | |
| [ ] 106 | `POST` | `/api/worktree` | `v2.worktree.create` | | |
| [ ] 107 | `DELETE` | `/api/worktree` | `v2.worktree.remove` | | |
| [ ] 108 | `POST` | `/api/worktree/refresh` | `v2.worktree.refresh` | | |
| [ ] 109 | `GET` | `/api/vcs` | `v2.vcs.get` | | |
| [ ] 110 | `GET` | `/api/vcs/base` | `v2.vcs.base` | | |
| [ ] 111 | `GET` | `/api/vcs/status` | `v2.vcs.status` | | |
| [ ] 112 | `GET` | `/api/vcs/branches` | `v2.vcs.branches` | | |
| [ ] 113 | `GET` | `/api/vcs/diff` | `v2.vcs.diff` | | |
## Group 9: PTYs, persistent terminals, and shells
**Endpoints:** 24
| Done | Method | Path | Operation ID | Decision | Notes |
|---|---|---|---|---|---|
| [ ] 114 | `GET` | `/api/pty` | `v2.pty.list` | | |
| [ ] 115 | `POST` | `/api/pty` | `v2.pty.create` | | |
| [ ] 116 | `GET` | `/api/pty/{ptyID}` | `v2.pty.get` | | |
| [ ] 117 | `PUT` | `/api/pty/{ptyID}` | `v2.pty.update` | | |
| [ ] 118 | `DELETE` | `/api/pty/{ptyID}` | `v2.pty.remove` | | |
| [ ] 119 | `POST` | `/api/pty/{ptyID}/connect-token` | `v2.pty.connect.token` | | |
| [ ] 120 | `GET` | `/api/pty/{ptyID}/connect` | `v2.pty.connect` | | |
| [ ] 121 | `GET` | `/api/experimental/session/{sessionID}/terminal/read` | `server.experimental.persistentPty.read` | | |
| [ ] 122 | `GET` | `/api/experimental/session/{sessionID}/terminal` | `server.experimental.persistentPty.list` | | |
| [ ] 123 | `POST` | `/api/experimental/session/{sessionID}/terminal` | `server.experimental.persistentPty.create` | | |
| [ ] 124 | `POST` | `/api/experimental/persistent-pty/shutdown` | `server.experimental.persistentPty.shutdown` | | |
| [ ] 125 | `POST` | `/api/experimental/persistent-pty/handoff` | `server.experimental.persistentPty.handoff` | | |
| [ ] 126 | `GET` | `/api/experimental/persistent-pty/{ptyID}` | `server.experimental.persistentPty.get` | | |
| [ ] 127 | `PUT` | `/api/experimental/persistent-pty/{ptyID}` | `server.experimental.persistentPty.update` | | |
| [ ] 128 | `DELETE` | `/api/experimental/persistent-pty/{ptyID}` | `server.experimental.persistentPty.remove` | | |
| [ ] 129 | `GET` | `/api/experimental/persistent-pty/{ptyID}/snapshot` | `server.experimental.persistentPty.snapshot` | | |
| [ ] 130 | `POST` | `/api/experimental/persistent-pty/{ptyID}/connect-token` | `server.experimental.persistentPty.connectToken` | | |
| [ ] 131 | `GET` | `/api/experimental/persistent-pty/{ptyID}/connect` | `v2.persistentPty.connect` | | |
| [ ] 132 | `GET` | `/api/shell` | `v2.shell.list` | | |
| [ ] 133 | `POST` | `/api/shell` | `v2.shell.create` | | |
| [ ] 134 | `GET` | `/api/shell/{id}` | `v2.shell.get` | | |
| [ ] 135 | `DELETE` | `/api/shell/{id}` | `v2.shell.remove` | | |
| [ ] 136 | `PATCH` | `/api/shell/{id}/timeout` | `v2.shell.timeout` | | |
| [ ] 137 | `GET` | `/api/shell/{id}/output` | `v2.shell.output` | | |
## Group 10: Events, RPC, and experimental operations
**Endpoints:** 6
| Done | Method | Path | Operation ID | Decision | Notes |
|---|---|---|---|---|---|
| [ ] 138 | `POST` | `/api/generate` | `v2.generate.text` | | |
| [ ] 139 | `POST` | `/api/rpc/{rpcID}/{method}` | `v2.rpc.call` | | |
| [ ] 140 | `GET` | `/api/event` | `v2.event.subscribe` | | |
| [ ] 141 | `GET` | `/api/debug/location` | `v2.debug.location.list` | | |
| [ ] 142 | `DELETE` | `/api/debug/location` | `v2.debug.location.evict` | | |
| [ ] 143 | `GET` | `/api/experimental/migration/v1` | `v2.experimental.migration.v1.status` | | |
@@ -76,7 +76,7 @@ async function mockServers(page: Page, requests: string[]) {
if (url.pathname === "/api/mcp") return json(route, { location: { directory: current.directory }, data: [] })
if (url.pathname === "/api/mcp/resource")
return json(route, { location: { directory: current.directory }, data: { resources: [], templates: [] } })
if (url.pathname === "/api/project" || url.pathname === "/api/project/current") {
if (url.pathname === "/api/project") {
const project = {
id: current.projectID,
canonical: current.directory,
@@ -84,7 +84,7 @@ async function mockServers(page: Page, requests: string[]) {
time: { created: 1, updated: 1 },
sandboxes: [],
}
return json(route, url.pathname === "/api/project" ? [project] : { id: project.id, directory: current.directory })
return json(route, [project])
}
if (url.pathname === "/api/location")
return json(route, {
@@ -398,8 +398,6 @@ async function mockServers(
},
])
}
if (url.pathname === "/api/project/current")
return json(route, { id: remote ? sessionB.projectID : "project-server-a", directory, canonical: directory })
if (url.pathname === "/api/session")
return json(route, { data: sessions.map((session) => currentSession(session)), cursor: {} })
if (url.pathname === "/api/session/active")
@@ -592,7 +592,7 @@ async function mockServer(page: Page) {
if (url.pathname === "/api/mcp") return json(route, { location: { directory: sessionA.directory }, data: [] })
if (url.pathname === "/api/mcp/resource")
return json(route, { location: { directory: sessionA.directory }, data: { resources: [], templates: [] } })
if (url.pathname === "/api/project" || url.pathname === "/api/project/current") {
if (url.pathname === "/api/project") {
const project = {
id: sessionA.projectID,
canonical: sessionA.directory,
@@ -600,10 +600,7 @@ async function mockServer(page: Page) {
time: { created: 1, updated: 1 },
sandboxes: [],
}
return json(
route,
url.pathname === "/api/project" ? [project] : { id: project.id, directory: sessionA.directory },
)
return json(route, [project])
}
if (url.pathname === "/api/location")
return json(route, {
-1
View File
@@ -77,7 +77,6 @@ const Group = HttpApiGroup.make("mock")
success: Json,
}),
)
.add(HttpApiEndpoint.get("projectCurrent", "/api/project/current", { success: Json }))
.add(HttpApiEndpoint.get("configPreferences", "/api/config/preferences", { success: Json }))
.add(
HttpApiEndpoint.patch("configUpdatePreferences", "/api/config/preferences", {
+1 -1
View File
@@ -110,7 +110,7 @@ export function createHomeController() {
.list({ path: ".", location })
.then(async (files) => {
// TODO: Initialize empty directories when V2 exposes a native Git init API.
return ctx.sdk.api.project.current({ location })
return ctx.sdk.api.location.get({ location }).then((result) => result.project)
})
.then((project) => ctx.sync.child(item, { bootstrap: false })[1]("project", project.id))
.catch(() => undefined)
@@ -2,8 +2,6 @@ import type { Config, Path, Project, ProviderAuthResponse } from "@/runtime/serv
import type {
LocationGetInput,
LocationGetOutput,
ProjectCurrentInput,
ProjectCurrentOutput,
ProjectListOutput,
} from "@opencode/client/promise"
import { showToast } from "@/shell/notifications/toast"
@@ -61,7 +59,6 @@ export const loadGlobalConfigQuery = (scope: ServerScope) =>
type ProjectApi = {
readonly list: () => Promise<ProjectListOutput>
readonly current: (input?: ProjectCurrentInput) => Promise<ProjectCurrentOutput>
}
type LocationApi = { readonly get: (input?: LocationGetInput) => Promise<LocationGetOutput> }
@@ -132,6 +129,7 @@ export async function bootstrapDirectory(input: {
mcp: boolean
api: {
readonly project: ProjectApi
readonly location: LocationApi
}
store: Store<State>
setStore: SetStoreFunction<State>
@@ -155,8 +153,8 @@ export async function bootstrapDirectory(input: {
seededProject
? undefined
: () =>
retry(() => input.api.project.current({ location: { directory: input.directory } })).then((project) =>
input.setStore("project", project.id),
retry(() => input.api.location.get({ location: { directory: input.directory } })).then((location) =>
input.setStore("project", location.project.id),
),
].filter((task): task is () => Promise<void> => !!task)
-7
View File
@@ -1489,16 +1489,9 @@ export type ProjectUpdateInput = {
export type ProjectUpdateOutput = Project.Info
export type ProjectUpdateOperation<E = never> = (input: ProjectUpdateInput) => Effect.Effect<ProjectUpdateOutput, E>
export type ProjectCurrentInput = {
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
}
export type ProjectCurrentOutput = Project.Current
export type ProjectCurrentOperation<E = never> = (input?: ProjectCurrentInput) => Effect.Effect<ProjectCurrentOutput, E>
export interface ProjectApi<E = never> {
readonly list: ProjectListOperation<E>
readonly update: ProjectUpdateOperation<E>
readonly current: ProjectCurrentOperation<E>
}
export type FormRequestListInput = {
@@ -153,8 +153,6 @@ import type {
ProjectListOutput,
ProjectUpdateInput,
ProjectUpdateOutput,
ProjectCurrentInput,
ProjectCurrentOutput,
FormRequestListInput,
FormRequestListOutput,
FormListInput,
@@ -1029,15 +1027,9 @@ const EndpointProjectUpdate = (raw: RawClient["server.project"]) => (input: Proj
}).pipe(Effect.mapError(mapClientError)),
)
const EndpointProjectCurrent = (raw: RawClient["server.project"]) => (input?: ProjectCurrentInput) =>
preserveEffect<ProjectCurrentOutput>()(
raw["project.current"]({ query: { location: input?.["location"] } }).pipe(Effect.mapError(mapClientError)),
)
const adaptGroupProject = (raw: RawClient["server.project"]) => ({
list: EndpointProjectList(raw),
update: EndpointProjectUpdate(raw),
current: EndpointProjectCurrent(raw),
})
const EndpointFormRequestList = (raw: RawClient["server.form"]) => (input?: FormRequestListInput) =>
@@ -147,8 +147,6 @@ import type {
ProjectListOutput,
ProjectUpdateInput,
ProjectUpdateOutput,
ProjectCurrentInput,
ProjectCurrentOutput,
FormRequestListInput,
FormRequestListOutput,
FormListInput,
@@ -1396,18 +1394,6 @@ export function make(options: ClientOptions) {
},
requestOptions,
),
current: (input?: ProjectCurrentInput, requestOptions?: RequestOptions) =>
request<ProjectCurrentOutput>(
{
method: "GET",
path: `/api/project/current`,
query: { location: input?.["location"] },
successStatus: 200,
declaredStatuses: [400, 401],
empty: false,
},
requestOptions,
),
},
form: {
request: {
@@ -310,8 +310,6 @@ export type ProjectCommands = { start?: string }
export type ProjectTime = { created: number; updated: number; initialized?: number }
export type ProjectCurrent = { id: string; directory: string; canonical: string }
export type FormMetadata = { [x: string]: JsonValue }
export type FormValue = string | number | boolean | Array<string>
@@ -4912,14 +4910,6 @@ export type ProjectUpdateInput = {
export type ProjectUpdateOutput = Project
export type ProjectCurrentInput = {
readonly location?: {
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
}["location"]
}
export type ProjectCurrentOutput = ProjectCurrent
export type FormRequestListInput = {
readonly location?: {
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
@@ -5170,89 +5170,6 @@
"summary": "List projects"
}
},
"/api/project/current": {
"get": {
"tags": ["project"],
"operationId": "v2.project.current",
"parameters": [
{
"name": "location",
"in": "query",
"schema": {
"anyOf": [
{
"type": "object",
"properties": {
"directory": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"workspace": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
{
"type": "null"
}
]
},
"required": false,
"style": "deepObject",
"explode": true
}
],
"security": [],
"responses": {
"200": {
"description": "Project.Current",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Project.Current"
}
}
}
},
"400": {
"description": "InvalidRequestError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvalidRequestError"
}
}
}
},
"401": {
"description": "UnauthorizedError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnauthorizedError"
}
}
}
}
},
"description": "Resolve the project for the requested location.",
"summary": "Get current project"
}
},
"/api/project/{projectID}/directories": {
"get": {
"tags": ["project"],
+299 -99
View File
@@ -1115,6 +1115,16 @@
"type": "null"
}
]
},
"permissions": {
"anyOf": [
{
"$ref": "#/components/schemas/Permission.Ruleset"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
@@ -7466,89 +7476,6 @@
}
}
},
"/api/project/current": {
"get": {
"tags": ["project"],
"operationId": "v2.project.current",
"parameters": [
{
"name": "location",
"in": "query",
"schema": {
"anyOf": [
{
"type": "object",
"properties": {
"directory": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"workspace": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
{
"type": "null"
}
]
},
"required": false,
"style": "deepObject",
"explode": true
}
],
"security": [],
"responses": {
"200": {
"description": "Project.Current",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Project.Current"
}
}
}
},
"400": {
"description": "InvalidRequestError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
}
}
}
},
"401": {
"description": "UnauthorizedError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
}
}
}
}
},
"description": "Resolve the project for the requested location.",
"summary": "Get current project"
}
},
"/api/form/request": {
"get": {
"tags": ["form"],
@@ -8783,6 +8710,85 @@
}
}
},
"/api/session/{sessionID}/permission/rules": {
"put": {
"tags": ["permission"],
"operationId": "v2.session.permission.rules",
"parameters": [
{
"name": "sessionID",
"in": "path",
"schema": {
"type": "string",
"pattern": "^ses"
},
"required": true
}
],
"security": [],
"responses": {
"204": {
"description": "<No Content>"
},
"400": {
"description": "InvalidRequestError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
}
}
}
},
"401": {
"description": "UnauthorizedError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
}
}
}
},
"404": {
"description": "SessionNotFoundError",
"content": {
"application/json": {
"schema": {
"anyOf": [
{
"$ref": "#/components/schemas/SessionNotFoundErrorEncoded"
},
{
"$ref": "#/components/schemas/SessionNotFoundErrorEncoded"
}
]
}
}
}
}
},
"description": "Replace the session-scoped permission rules. Rules are evaluated after the agent's rules, and the last matching rule wins.",
"summary": "Replace session permission rules",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"permissions": {
"$ref": "#/components/schemas/Permission.Ruleset"
}
},
"required": ["permissions"],
"additionalProperties": false
}
}
},
"required": true
}
}
},
"/api/fs/read/*": {
"get": {
"tags": ["filesystem"],
@@ -13672,6 +13678,143 @@
"description": "Return configuration documents and discovery sources for the requested location, from lowest to highest priority.",
"summary": "Get configuration"
}
},
"/api/config/preferences": {
"get": {
"tags": ["config"],
"operationId": "v2.config.preferences",
"parameters": [],
"security": [],
"responses": {
"200": {
"description": "Config.Preferences",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Config.Preferences"
}
}
}
},
"400": {
"description": "InvalidRequestError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
}
}
}
},
"401": {
"description": "UnauthorizedError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
}
}
}
}
},
"description": "Return preferences from the highest-precedence global configuration document.",
"summary": "Get global preferences"
},
"patch": {
"tags": ["config"],
"operationId": "v2.config.updatePreferences",
"parameters": [],
"security": [],
"responses": {
"200": {
"description": "Config.Preferences",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Config.Preferences"
}
}
}
},
"400": {
"description": "InvalidRequestError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
}
}
}
},
"401": {
"description": "UnauthorizedError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
}
}
}
}
},
"description": "Patch preferences in the highest-precedence global configuration document.",
"summary": "Update global preferences",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Config.PreferencesPatch"
}
}
},
"required": true
}
}
},
"/api/config/shell": {
"get": {
"tags": ["config"],
"operationId": "v2.config.shells",
"parameters": [],
"security": [],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ConfigShell.Option"
}
}
}
}
},
"400": {
"description": "InvalidRequestError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
}
}
}
},
"401": {
"description": "UnauthorizedError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
}
}
}
}
},
"description": "Return shells available to terminal and agent execution.",
"summary": "List available shells"
}
}
},
"components": {
@@ -14532,6 +14675,60 @@
"required": ["package"],
"additionalProperties": false
},
"Config.Preferences": {
"type": "object",
"properties": {
"shell": {
"type": "string"
},
"websearch": {
"anyOf": [
{
"type": "boolean",
"enum": [false]
},
{
"$ref": "#/components/schemas/ConfigWebSearch.InfoEncoded"
}
]
}
},
"additionalProperties": false
},
"Config.PreferencesPatch": {
"type": "object",
"properties": {
"shell": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"websearch": {
"anyOf": [
{
"anyOf": [
{
"type": "boolean",
"enum": [false]
},
{
"$ref": "#/components/schemas/ConfigWebSearch.InfoEncoded"
}
]
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
"Config.ProviderEncoded": {
"type": "object",
"properties": {
@@ -14637,6 +14834,22 @@
"required": ["directory"],
"additionalProperties": false
},
"ConfigShell.Option": {
"type": "object",
"properties": {
"path": {
"type": "string"
},
"name": {
"type": "string"
},
"acceptable": {
"type": "boolean"
}
},
"required": ["path", "name", "acceptable"],
"additionalProperties": false
},
"ConfigWebSearch.InfoEncoded": {
"type": "object",
"properties": {
@@ -17231,22 +17444,6 @@
},
"additionalProperties": false
},
"Project.Current": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"directory": {
"type": "string"
},
"canonical": {
"type": "string"
}
},
"required": ["id", "directory", "canonical"],
"additionalProperties": false
},
"Project.Icon": {
"type": "object",
"properties": {
@@ -18151,6 +18348,9 @@
"metadata": {
"$ref": "#/components/schemas/Session.Metadata"
},
"permissions": {
"$ref": "#/components/schemas/Permission.Ruleset"
},
"revert": {
"$ref": "#/components/schemas/Session.Revert"
}
-15
View File
@@ -1,7 +1,6 @@
import { Project } from "@opencode/schema/project"
import { Schema, Struct } from "effect"
import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
import { LocationQuery, locationQueryOpenApi } from "./location.js"
import { ProjectNotFoundError } from "../errors.js"
const root = "/api/project"
@@ -33,20 +32,6 @@ export const ProjectGroup = HttpApiGroup.make("server.project")
}),
),
)
.add(
HttpApiEndpoint.get("project.current", `${root}/current`, {
query: LocationQuery,
success: Project.Current,
})
.annotateMerge(locationQueryOpenApi)
.annotateMerge(
OpenApi.annotations({
identifier: "v2.project.current",
summary: "Get current project",
description: "Resolve the project for the requested location.",
}),
),
)
.annotateMerge(
OpenApi.annotations({
title: "project",
-10
View File
@@ -1,4 +1,3 @@
import { Location } from "@opencode/core/location"
import { Project } from "@opencode/core/project"
import { Effect } from "effect"
import { HttpApiBuilder } from "effect/unstable/httpapi"
@@ -20,14 +19,5 @@ export const ProjectHandler = HttpApiBuilder.group(Api, "server.project", (handl
),
),
),
)
.handle("project.current", () =>
Location.Service.use((location) =>
Effect.succeed({
id: location.project.id,
directory: location.project.directory,
canonical: location.project.canonical,
}),
),
),
)
@@ -70,9 +70,9 @@ export function DialogWorkspaces(props: DialogWorkspacesProps) {
const [loadedProject] = createResource(
() => (location()?.project.id === props.projectID ? undefined : props.projectID),
(projectID) =>
client.api.project
.current({ location: { directory: location()?.directory || paths.cwd } })
.then((project) => (project.id === projectID ? project.directory : undefined))
client.api.location
.get({ location: { directory: location()?.directory || paths.cwd } })
.then((result) => (result.project.id === projectID ? result.project.directory : undefined))
.catch(() => undefined),
)
const currentCheckout = createMemo(() => {
+3 -3
View File
@@ -118,9 +118,9 @@ export function usePromptMove(input: { projectID: () => string | undefined; sess
const location = homeLocation()
const current = data.location.info(location)
if (current) return current.project.id
return client.api.project
.current({ location: { directory: location.directory, workspace: location.workspaceID } })
.then((project) => project.id)
return client.api.location
.get({ location: { directory: location.directory, workspace: location.workspaceID } })
.then((result) => result.project.id)
.catch(() => undefined)
}
+23 -5
View File
@@ -47,7 +47,7 @@ test.each([
expect(fixture.requests).toEqual([{ payload: { name: "fresh" }, directory: input.directory, workspace: null }])
expect(fixture.data.location.info({ directory: created })?.project.canonical).toBe(clone)
expect(fixture.reads.locations.filter((directory) => directory === input.directory)).toHaveLength(1)
expect(fixture.reads.locations.filter((directory) => directory === input.directory)).toHaveLength(input.home ? 3 : 1)
expect(fixture.reads.session).toBe(input.home ? 0 : 1)
expect(fixture.moves).toEqual([])
if (!input.home) expect(fixture.route.data).toEqual({ type: "home", location: { directory: created } })
@@ -149,11 +149,9 @@ test.each([false, true])("Ctrl+M moves only an existing session (home=%s)", asyn
test.each([
{ name: "session", unavailable: "session" as const },
{ name: "location", unavailable: "location" as const },
{ name: "selected Home location", unavailable: "location" as const, home: true, launch: main },
])("does not create from another clone when $name lookup fails", async (input) => {
const fixture = await renderMove({ ...input, directory: `${linked}/packages/tui`, worktree: linked })
try {
if (input.home) fixture.location.set({ directory: `${linked}/packages/tui` })
await fixture.create()
expect(fixture.requests).toEqual([])
@@ -165,6 +163,27 @@ test.each([
}
})
test("does not open creation when the selected Home location lookup fails", async () => {
const fixture = await renderMove({
unavailable: "location",
home: true,
launch: main,
directory: `${linked}/packages/tui`,
worktree: linked,
})
try {
fixture.location.set({ directory: `${linked}/packages/tui` })
await fixture.move.open()
await fixture.app.waitFor(() => fixture.toast.currentToast !== null)
expect(fixture.requests).toEqual([])
expect(fixture.moves).toEqual([])
expect(fixture.toast.currentToast).toMatchObject({ message: "Unable to determine current project", variant: "error" })
} finally {
fixture.app.renderer.destroy()
}
})
async function renderMove(input: {
directory: string
worktree?: string
@@ -179,7 +198,7 @@ async function renderMove(input: {
const moves: unknown[] = []
const reads = { session: 0, locations: [] as string[], worktrees: [] as string[] }
const calls = createFetch(async (url, request) => {
if (url.pathname === "/api/location" || url.pathname === "/api/project/current") {
if (url.pathname === "/api/location") {
const directory = url.searchParams.get("location[directory]") ?? launch
const project = {
id: directory === launch ? (input.launchProjectID ?? "proj_test") : "proj_test",
@@ -191,7 +210,6 @@ async function renderMove(input: {
? launch
: main,
}
if (url.pathname === "/api/project/current") return json(project)
reads.locations.push(directory)
if (input.unavailable === "location" && directory === input.directory)
return json({ message: "Location unavailable" }, { status: 503 })
-1
View File
@@ -110,7 +110,6 @@ export function createFetch(override?: FetchHandler, events?: ReturnType<typeof
location: { directory, project: { id: "proj_test", directory: worktree, canonical: worktree } },
data: [],
})
if (url.pathname === "/api/project/current") return json({ id: "proj_test", directory: worktree })
if (url.pathname === "/api/project") return json([])
if (url.pathname === "/api/worktree") {
if (request.method === "GET") return json([{ directory: worktree }])
-3
View File
@@ -244,7 +244,6 @@ const agents = await client.app.agents()
| الطريقة | الوصف | الاستجابة |
| ------------------- | ------------------ | --------------------------------------------- |
| `project.list()` | سرد جميع المشاريع | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | جلب المشروع الحالي | <a href={typesUrl}><code>Project</code></a> |
---
@@ -254,8 +253,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
-3
View File
@@ -244,7 +244,6 @@ const agents = await client.app.agents()
| Metoda | Opis | Odgovor |
| ------------------- | -------------------- | --------------------------------------------- |
| `project.list()` | Lista svih projekata | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | Trenutni projekat | <a href={typesUrl}><code>Project</code></a> |
---
@@ -254,8 +253,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
-3
View File
@@ -244,7 +244,6 @@ const agents = await client.app.agents()
| Metode | Beskrivelse | Svar |
| ------------------- | -------------------------- | ---------------------------------------------- |
| `project.list()` | Liste over alle prosjekter | <a href={typesUrl}><code>Prosjekt[]</code></a> |
| `project.current()` | Få nåværende prosjekt | <a href={typesUrl}><code>Prosjekt</code></a> |
---
@@ -254,8 +253,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
-3
View File
@@ -246,7 +246,6 @@ const agents = await client.app.agents()
| Method | Description | Response |
| ------------------- | ---------------------------- | --------------------------------------------- |
| `project.list()` | Listet alle Projekte | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | Ruft das aktuelle Projekt ab | <a href={typesUrl}><code>Project</code></a> |
---
@@ -256,8 +255,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
-3
View File
@@ -244,7 +244,6 @@ const agents = await client.app.agents()
| Método | Descripción | Respuesta |
| ------------------- | -------------------------- | --------------------------------------------- |
| `project.list()` | Listar todos los proyectos | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | Obtener proyecto actual | <a href={typesUrl}><code>Project</code></a> |
---
@@ -254,8 +253,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
-3
View File
@@ -244,7 +244,6 @@ const agents = await client.app.agents()
| Méthode | Descriptif | Réponse |
| ------------------- | -------------------------- | --------------------------------------------- |
| `project.list()` | Lister tous les projets | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | Obtenir le projet en cours | <a href={typesUrl}><code>Project</code></a> |
---
@@ -254,8 +253,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
-3
View File
@@ -244,7 +244,6 @@ const agents = await client.app.agents()
| Metodo | Descrizione | Risposta |
| ------------------- | ----------------- | --------------------------------------------- |
| `project.list()` | Elenca i progetti | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | Progetto corrente | <a href={typesUrl}><code>Project</code></a> |
---
@@ -254,8 +253,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
-3
View File
@@ -244,7 +244,6 @@ const agents = await client.app.agents()
| メソッド | 説明 | 戻り値 |
| ------------------- | -------------------------------- | --------------------------------------------- |
| `project.list()` | すべてのプロジェクトをリストする | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | 現在のプロジェクトを取得 | <a href={typesUrl}><code>Project</code></a> |
---
@@ -254,8 +253,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
-3
View File
@@ -244,7 +244,6 @@ const agents = await client.app.agents()
| 방법 | 설명 | 응답 |
| ------------------- | ----------------------- | --------------------------------------------- |
| `project.list()` | 모든 프로젝트 보기 | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | 현재 프로젝트 가져 오기 | <a href={typesUrl}><code>Project</code></a> |
---
@@ -254,8 +253,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
-3
View File
@@ -244,7 +244,6 @@ const agents = await client.app.agents()
| Metode | Beskrivelse | Svar |
| ------------------- | ----------------------- | --------------------------------------------- |
| `project.list()` | List alle prosjekter | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | Hent gjeldende prosjekt | <a href={typesUrl}><code>Project</code></a> |
---
@@ -254,8 +253,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
-3
View File
@@ -244,7 +244,6 @@ const agents = await client.app.agents()
| Metoda | Opis | Odpowiedź |
| ------------------- | -------------------------- | --------------------------------------------- |
| `project.list()` | Lista wszystkich projektów | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | Pobierz bieżący projekt | <a href={typesUrl}><code>Project</code></a> |
---
@@ -254,8 +253,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
@@ -244,7 +244,6 @@ const agents = await client.app.agents()
| Método | Descrição | Resposta |
| ------------------- | ------------------------ | --------------------------------------------- |
| `project.list()` | Listar todos os projetos | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | Obter projeto atual | <a href={typesUrl}><code>Project</code></a> |
---
@@ -254,8 +253,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
-3
View File
@@ -244,7 +244,6 @@ const agents = await client.app.agents()
| Метод | Описание | Ответ |
| ------------------- | ------------------- | --------------------------------------------- |
| `project.list()` | List all projects | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | Get current project | <a href={typesUrl}><code>Project</code></a> |
---
@@ -254,8 +253,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
-3
View File
@@ -244,7 +244,6 @@ const agents = await client.app.agents()
| Method | Description | Response |
| ------------------- | ------------------- | --------------------------------------------- |
| `project.list()` | List all projects | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | Get current project | <a href={typesUrl}><code>Project</code></a> |
---
@@ -254,8 +253,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
-3
View File
@@ -244,7 +244,6 @@ const agents = await client.app.agents()
| Method | คำอธิบาย | การตอบสนอง |
| ------------------- | ------------------------ | --------------------------------------------- |
| `project.list()` | แสดงรายการโครงการทั้งหมด | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | รับโครงการปัจจุบัน | <a href={typesUrl}><code>Project</code></a> |
---
@@ -254,8 +253,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
-3
View File
@@ -244,7 +244,6 @@ const agents = await client.app.agents()
| Yöntem | Açıklama | Yanıt |
| ------------------- | --------------------- | --------------------------------------------- |
| `project.list()` | Tüm projeleri listele | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | Mevcut projeyi al | <a href={typesUrl}><code>Project</code></a> |
---
@@ -254,8 +253,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
@@ -244,7 +244,6 @@ const agents = await client.app.agents()
| 方法 | 描述 | 响应 |
| ------------------- | ------------ | --------------------------------------------- |
| `project.list()` | 列出所有项目 | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | 获取当前项目 | <a href={typesUrl}><code>Project</code></a> |
---
@@ -254,8 +253,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
@@ -244,7 +244,6 @@ const agents = await client.app.agents()
| 方法 | 描述 | 回應 |
| ------------------- | ------------ | --------------------------------------------- |
| `project.list()` | 列出所有專案 | <a href={typesUrl}><code>Project[]</code></a> |
| `project.current()` | 取得當前專案 | <a href={typesUrl}><code>Project</code></a> |
---
@@ -254,8 +253,6 @@ const agents = await client.app.agents()
// List all projects
const projects = await client.project.list()
// Get current project
const currentProject = await client.project.current()
```
---
+299 -99
View File
@@ -1115,6 +1115,16 @@
"type": "null"
}
]
},
"permissions": {
"anyOf": [
{
"$ref": "#/components/schemas/Permission.Ruleset"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
@@ -7466,89 +7476,6 @@
}
}
},
"/api/project/current": {
"get": {
"tags": ["project"],
"operationId": "v2.project.current",
"parameters": [
{
"name": "location",
"in": "query",
"schema": {
"anyOf": [
{
"type": "object",
"properties": {
"directory": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"workspace": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
{
"type": "null"
}
]
},
"required": false,
"style": "deepObject",
"explode": true
}
],
"security": [],
"responses": {
"200": {
"description": "Project.Current",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Project.Current"
}
}
}
},
"400": {
"description": "InvalidRequestError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
}
}
}
},
"401": {
"description": "UnauthorizedError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
}
}
}
}
},
"description": "Resolve the project for the requested location.",
"summary": "Get current project"
}
},
"/api/form/request": {
"get": {
"tags": ["form"],
@@ -8783,6 +8710,85 @@
}
}
},
"/api/session/{sessionID}/permission/rules": {
"put": {
"tags": ["permission"],
"operationId": "v2.session.permission.rules",
"parameters": [
{
"name": "sessionID",
"in": "path",
"schema": {
"type": "string",
"pattern": "^ses"
},
"required": true
}
],
"security": [],
"responses": {
"204": {
"description": "<No Content>"
},
"400": {
"description": "InvalidRequestError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
}
}
}
},
"401": {
"description": "UnauthorizedError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
}
}
}
},
"404": {
"description": "SessionNotFoundError",
"content": {
"application/json": {
"schema": {
"anyOf": [
{
"$ref": "#/components/schemas/SessionNotFoundErrorEncoded"
},
{
"$ref": "#/components/schemas/SessionNotFoundErrorEncoded"
}
]
}
}
}
}
},
"description": "Replace the session-scoped permission rules. Rules are evaluated after the agent's rules, and the last matching rule wins.",
"summary": "Replace session permission rules",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"permissions": {
"$ref": "#/components/schemas/Permission.Ruleset"
}
},
"required": ["permissions"],
"additionalProperties": false
}
}
},
"required": true
}
}
},
"/api/fs/read/*": {
"get": {
"tags": ["filesystem"],
@@ -13672,6 +13678,143 @@
"description": "Return configuration documents and discovery sources for the requested location, from lowest to highest priority.",
"summary": "Get configuration"
}
},
"/api/config/preferences": {
"get": {
"tags": ["config"],
"operationId": "v2.config.preferences",
"parameters": [],
"security": [],
"responses": {
"200": {
"description": "Config.Preferences",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Config.Preferences"
}
}
}
},
"400": {
"description": "InvalidRequestError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
}
}
}
},
"401": {
"description": "UnauthorizedError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
}
}
}
}
},
"description": "Return preferences from the highest-precedence global configuration document.",
"summary": "Get global preferences"
},
"patch": {
"tags": ["config"],
"operationId": "v2.config.updatePreferences",
"parameters": [],
"security": [],
"responses": {
"200": {
"description": "Config.Preferences",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Config.Preferences"
}
}
}
},
"400": {
"description": "InvalidRequestError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
}
}
}
},
"401": {
"description": "UnauthorizedError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
}
}
}
}
},
"description": "Patch preferences in the highest-precedence global configuration document.",
"summary": "Update global preferences",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Config.PreferencesPatch"
}
}
},
"required": true
}
}
},
"/api/config/shell": {
"get": {
"tags": ["config"],
"operationId": "v2.config.shells",
"parameters": [],
"security": [],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ConfigShell.Option"
}
}
}
}
},
"400": {
"description": "InvalidRequestError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
}
}
}
},
"401": {
"description": "UnauthorizedError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
}
}
}
}
},
"description": "Return shells available to terminal and agent execution.",
"summary": "List available shells"
}
}
},
"components": {
@@ -14532,6 +14675,60 @@
"required": ["package"],
"additionalProperties": false
},
"Config.Preferences": {
"type": "object",
"properties": {
"shell": {
"type": "string"
},
"websearch": {
"anyOf": [
{
"type": "boolean",
"enum": [false]
},
{
"$ref": "#/components/schemas/ConfigWebSearch.InfoEncoded"
}
]
}
},
"additionalProperties": false
},
"Config.PreferencesPatch": {
"type": "object",
"properties": {
"shell": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"websearch": {
"anyOf": [
{
"anyOf": [
{
"type": "boolean",
"enum": [false]
},
{
"$ref": "#/components/schemas/ConfigWebSearch.InfoEncoded"
}
]
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
"Config.ProviderEncoded": {
"type": "object",
"properties": {
@@ -14637,6 +14834,22 @@
"required": ["directory"],
"additionalProperties": false
},
"ConfigShell.Option": {
"type": "object",
"properties": {
"path": {
"type": "string"
},
"name": {
"type": "string"
},
"acceptable": {
"type": "boolean"
}
},
"required": ["path", "name", "acceptable"],
"additionalProperties": false
},
"ConfigWebSearch.InfoEncoded": {
"type": "object",
"properties": {
@@ -17231,22 +17444,6 @@
},
"additionalProperties": false
},
"Project.Current": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"directory": {
"type": "string"
},
"canonical": {
"type": "string"
}
},
"required": ["id", "directory", "canonical"],
"additionalProperties": false
},
"Project.Icon": {
"type": "object",
"properties": {
@@ -18151,6 +18348,9 @@
"metadata": {
"$ref": "#/components/schemas/Session.Metadata"
},
"permissions": {
"$ref": "#/components/schemas/Permission.Ruleset"
},
"revert": {
"$ref": "#/components/schemas/Session.Revert"
}
+299 -99
View File
@@ -1115,6 +1115,16 @@
"type": "null"
}
]
},
"permissions": {
"anyOf": [
{
"$ref": "#/components/schemas/Permission.Ruleset"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
@@ -7466,89 +7476,6 @@
}
}
},
"/api/project/current": {
"get": {
"tags": ["project"],
"operationId": "v2.project.current",
"parameters": [
{
"name": "location",
"in": "query",
"schema": {
"anyOf": [
{
"type": "object",
"properties": {
"directory": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"workspace": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
{
"type": "null"
}
]
},
"required": false,
"style": "deepObject",
"explode": true
}
],
"security": [],
"responses": {
"200": {
"description": "Project.Current",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Project.Current"
}
}
}
},
"400": {
"description": "InvalidRequestError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
}
}
}
},
"401": {
"description": "UnauthorizedError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
}
}
}
}
},
"description": "Resolve the project for the requested location.",
"summary": "Get current project"
}
},
"/api/form/request": {
"get": {
"tags": ["form"],
@@ -8783,6 +8710,85 @@
}
}
},
"/api/session/{sessionID}/permission/rules": {
"put": {
"tags": ["permission"],
"operationId": "v2.session.permission.rules",
"parameters": [
{
"name": "sessionID",
"in": "path",
"schema": {
"type": "string",
"pattern": "^ses"
},
"required": true
}
],
"security": [],
"responses": {
"204": {
"description": "<No Content>"
},
"400": {
"description": "InvalidRequestError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
}
}
}
},
"401": {
"description": "UnauthorizedError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
}
}
}
},
"404": {
"description": "SessionNotFoundError",
"content": {
"application/json": {
"schema": {
"anyOf": [
{
"$ref": "#/components/schemas/SessionNotFoundErrorEncoded"
},
{
"$ref": "#/components/schemas/SessionNotFoundErrorEncoded"
}
]
}
}
}
}
},
"description": "Replace the session-scoped permission rules. Rules are evaluated after the agent's rules, and the last matching rule wins.",
"summary": "Replace session permission rules",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"permissions": {
"$ref": "#/components/schemas/Permission.Ruleset"
}
},
"required": ["permissions"],
"additionalProperties": false
}
}
},
"required": true
}
}
},
"/api/fs/read/*": {
"get": {
"tags": ["filesystem"],
@@ -13672,6 +13678,143 @@
"description": "Return configuration documents and discovery sources for the requested location, from lowest to highest priority.",
"summary": "Get configuration"
}
},
"/api/config/preferences": {
"get": {
"tags": ["config"],
"operationId": "v2.config.preferences",
"parameters": [],
"security": [],
"responses": {
"200": {
"description": "Config.Preferences",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Config.Preferences"
}
}
}
},
"400": {
"description": "InvalidRequestError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
}
}
}
},
"401": {
"description": "UnauthorizedError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
}
}
}
}
},
"description": "Return preferences from the highest-precedence global configuration document.",
"summary": "Get global preferences"
},
"patch": {
"tags": ["config"],
"operationId": "v2.config.updatePreferences",
"parameters": [],
"security": [],
"responses": {
"200": {
"description": "Config.Preferences",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Config.Preferences"
}
}
}
},
"400": {
"description": "InvalidRequestError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
}
}
}
},
"401": {
"description": "UnauthorizedError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
}
}
}
}
},
"description": "Patch preferences in the highest-precedence global configuration document.",
"summary": "Update global preferences",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Config.PreferencesPatch"
}
}
},
"required": true
}
}
},
"/api/config/shell": {
"get": {
"tags": ["config"],
"operationId": "v2.config.shells",
"parameters": [],
"security": [],
"responses": {
"200": {
"description": "Success",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ConfigShell.Option"
}
}
}
}
},
"400": {
"description": "InvalidRequestError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/InvalidRequestErrorEncoded"
}
}
}
},
"401": {
"description": "UnauthorizedError",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnauthorizedErrorEncoded"
}
}
}
}
},
"description": "Return shells available to terminal and agent execution.",
"summary": "List available shells"
}
}
},
"components": {
@@ -14532,6 +14675,60 @@
"required": ["package"],
"additionalProperties": false
},
"Config.Preferences": {
"type": "object",
"properties": {
"shell": {
"type": "string"
},
"websearch": {
"anyOf": [
{
"type": "boolean",
"enum": [false]
},
{
"$ref": "#/components/schemas/ConfigWebSearch.InfoEncoded"
}
]
}
},
"additionalProperties": false
},
"Config.PreferencesPatch": {
"type": "object",
"properties": {
"shell": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"websearch": {
"anyOf": [
{
"anyOf": [
{
"type": "boolean",
"enum": [false]
},
{
"$ref": "#/components/schemas/ConfigWebSearch.InfoEncoded"
}
]
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
"Config.ProviderEncoded": {
"type": "object",
"properties": {
@@ -14637,6 +14834,22 @@
"required": ["directory"],
"additionalProperties": false
},
"ConfigShell.Option": {
"type": "object",
"properties": {
"path": {
"type": "string"
},
"name": {
"type": "string"
},
"acceptable": {
"type": "boolean"
}
},
"required": ["path", "name", "acceptable"],
"additionalProperties": false
},
"ConfigWebSearch.InfoEncoded": {
"type": "object",
"properties": {
@@ -17231,22 +17444,6 @@
},
"additionalProperties": false
},
"Project.Current": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"directory": {
"type": "string"
},
"canonical": {
"type": "string"
}
},
"required": ["id", "directory", "canonical"],
"additionalProperties": false
},
"Project.Icon": {
"type": "object",
"properties": {
@@ -18151,6 +18348,9 @@
"metadata": {
"$ref": "#/components/schemas/Session.Metadata"
},
"permissions": {
"$ref": "#/components/schemas/Permission.Ruleset"
},
"revert": {
"$ref": "#/components/schemas/Session.Revert"
}