mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-06 08:21:50 +00:00
chore: generate
This commit is contained in:
parent
6015084fa2
commit
df147b65fd
25 changed files with 978 additions and 715 deletions
|
|
@ -29,14 +29,18 @@ export const PtyApi = HttpApi.make("pty")
|
|||
.add(
|
||||
HttpApiGroup.make("pty")
|
||||
.add(
|
||||
HttpApiEndpoint.get("shells", PtyPaths.shells, { success: described(Schema.Array(ShellItem), "List of shells") }).annotateMerge(
|
||||
HttpApiEndpoint.get("shells", PtyPaths.shells, {
|
||||
success: described(Schema.Array(ShellItem), "List of shells"),
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "pty.shells",
|
||||
summary: "List available shells",
|
||||
description: "Get a list of available shells on the system.",
|
||||
}),
|
||||
),
|
||||
HttpApiEndpoint.get("list", PtyPaths.list, { success: described(Schema.Array(Pty.Info), "List of sessions") }).annotateMerge(
|
||||
HttpApiEndpoint.get("list", PtyPaths.list, {
|
||||
success: described(Schema.Array(Pty.Info), "List of sessions"),
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "pty.list",
|
||||
summary: "List PTY sessions",
|
||||
|
|
|
|||
|
|
@ -11,11 +11,28 @@ export const TuiRequestPayload = Schema.Struct({
|
|||
path: Schema.String,
|
||||
body: Schema.Unknown,
|
||||
})
|
||||
const EventTuiPromptAppend = Schema.Struct({ type: Schema.Literal(TuiEvent.PromptAppend.type), properties: TuiEvent.PromptAppend.properties }).annotate({ identifier: "EventTuiPromptAppend" })
|
||||
const EventTuiCommandExecute = Schema.Struct({ type: Schema.Literal(TuiEvent.CommandExecute.type), properties: TuiEvent.CommandExecute.properties }).annotate({ identifier: "EventTuiCommandExecute" })
|
||||
const EventTuiToastShow = Schema.Struct({ type: Schema.Literal(TuiEvent.ToastShow.type), properties: TuiEvent.ToastShow.properties }).annotate({ identifier: "EventTuiToastShow" })
|
||||
const EventTuiSessionSelect = Schema.Struct({ type: Schema.Literal(TuiEvent.SessionSelect.type), properties: TuiEvent.SessionSelect.properties }).annotate({ identifier: "EventTuiSessionSelect" })
|
||||
export const TuiPublishPayload = Schema.Union([EventTuiPromptAppend, EventTuiCommandExecute, EventTuiToastShow, EventTuiSessionSelect])
|
||||
const EventTuiPromptAppend = Schema.Struct({
|
||||
type: Schema.Literal(TuiEvent.PromptAppend.type),
|
||||
properties: TuiEvent.PromptAppend.properties,
|
||||
}).annotate({ identifier: "EventTuiPromptAppend" })
|
||||
const EventTuiCommandExecute = Schema.Struct({
|
||||
type: Schema.Literal(TuiEvent.CommandExecute.type),
|
||||
properties: TuiEvent.CommandExecute.properties,
|
||||
}).annotate({ identifier: "EventTuiCommandExecute" })
|
||||
const EventTuiToastShow = Schema.Struct({
|
||||
type: Schema.Literal(TuiEvent.ToastShow.type),
|
||||
properties: TuiEvent.ToastShow.properties,
|
||||
}).annotate({ identifier: "EventTuiToastShow" })
|
||||
const EventTuiSessionSelect = Schema.Struct({
|
||||
type: Schema.Literal(TuiEvent.SessionSelect.type),
|
||||
properties: TuiEvent.SessionSelect.properties,
|
||||
}).annotate({ identifier: "EventTuiSessionSelect" })
|
||||
export const TuiPublishPayload = Schema.Union([
|
||||
EventTuiPromptAppend,
|
||||
EventTuiCommandExecute,
|
||||
EventTuiToastShow,
|
||||
EventTuiSessionSelect,
|
||||
])
|
||||
|
||||
export const TuiPaths = {
|
||||
appendPrompt: `${root}/append-prompt`,
|
||||
|
|
@ -48,42 +65,54 @@ export const TuiApi = HttpApi.make("tui")
|
|||
description: "Append prompt to the TUI.",
|
||||
}),
|
||||
),
|
||||
HttpApiEndpoint.post("openHelp", TuiPaths.openHelp, { success: described(Schema.Boolean, "Help dialog opened successfully") }).annotateMerge(
|
||||
HttpApiEndpoint.post("openHelp", TuiPaths.openHelp, {
|
||||
success: described(Schema.Boolean, "Help dialog opened successfully"),
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "tui.openHelp",
|
||||
summary: "Open help dialog",
|
||||
description: "Open the help dialog in the TUI to display user assistance information.",
|
||||
}),
|
||||
),
|
||||
HttpApiEndpoint.post("openSessions", TuiPaths.openSessions, { success: described(Schema.Boolean, "Session dialog opened successfully") }).annotateMerge(
|
||||
HttpApiEndpoint.post("openSessions", TuiPaths.openSessions, {
|
||||
success: described(Schema.Boolean, "Session dialog opened successfully"),
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "tui.openSessions",
|
||||
summary: "Open sessions dialog",
|
||||
description: "Open the session dialog.",
|
||||
}),
|
||||
),
|
||||
HttpApiEndpoint.post("openThemes", TuiPaths.openThemes, { success: described(Schema.Boolean, "Theme dialog opened successfully") }).annotateMerge(
|
||||
HttpApiEndpoint.post("openThemes", TuiPaths.openThemes, {
|
||||
success: described(Schema.Boolean, "Theme dialog opened successfully"),
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "tui.openThemes",
|
||||
summary: "Open themes dialog",
|
||||
description: "Open the theme dialog.",
|
||||
}),
|
||||
),
|
||||
HttpApiEndpoint.post("openModels", TuiPaths.openModels, { success: described(Schema.Boolean, "Model dialog opened successfully") }).annotateMerge(
|
||||
HttpApiEndpoint.post("openModels", TuiPaths.openModels, {
|
||||
success: described(Schema.Boolean, "Model dialog opened successfully"),
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "tui.openModels",
|
||||
summary: "Open models dialog",
|
||||
description: "Open the model dialog.",
|
||||
}),
|
||||
),
|
||||
HttpApiEndpoint.post("submitPrompt", TuiPaths.submitPrompt, { success: described(Schema.Boolean, "Prompt submitted successfully") }).annotateMerge(
|
||||
HttpApiEndpoint.post("submitPrompt", TuiPaths.submitPrompt, {
|
||||
success: described(Schema.Boolean, "Prompt submitted successfully"),
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "tui.submitPrompt",
|
||||
summary: "Submit TUI prompt",
|
||||
description: "Submit the prompt.",
|
||||
}),
|
||||
),
|
||||
HttpApiEndpoint.post("clearPrompt", TuiPaths.clearPrompt, { success: described(Schema.Boolean, "Prompt cleared successfully") }).annotateMerge(
|
||||
HttpApiEndpoint.post("clearPrompt", TuiPaths.clearPrompt, {
|
||||
success: described(Schema.Boolean, "Prompt cleared successfully"),
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "tui.clearPrompt",
|
||||
summary: "Clear TUI prompt",
|
||||
|
|
@ -133,7 +162,9 @@ export const TuiApi = HttpApi.make("tui")
|
|||
description: "Navigate the TUI to display the specified session.",
|
||||
}),
|
||||
),
|
||||
HttpApiEndpoint.get("controlNext", TuiPaths.controlNext, { success: described(TuiRequestPayload, "Next TUI request") }).annotateMerge(
|
||||
HttpApiEndpoint.get("controlNext", TuiPaths.controlNext, {
|
||||
success: described(TuiRequestPayload, "Next TUI request"),
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "tui.control.next",
|
||||
summary: "Get next TUI request",
|
||||
|
|
|
|||
|
|
@ -9,9 +9,7 @@ import { described } from "./metadata"
|
|||
|
||||
const root = "/experimental/workspace"
|
||||
export const CreatePayload = Schema.Struct(Struct.omit(Workspace.CreateInput.fields, ["projectID"]))
|
||||
export const SessionRestorePayload = Schema.Struct(
|
||||
Struct.omit(Workspace.SessionRestoreInput.fields, ["workspaceID"]),
|
||||
)
|
||||
export const SessionRestorePayload = Schema.Struct(Struct.omit(Workspace.SessionRestoreInput.fields, ["workspaceID"]))
|
||||
export const SessionRestoreResponse = Schema.Struct({
|
||||
total: NonNegativeInt,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -7,28 +7,28 @@ import { InstanceHttpApi } from "../api"
|
|||
import { markInstanceForDisposal } from "../lifecycle"
|
||||
|
||||
export const configHandlers = HttpApiBuilder.group(InstanceHttpApi, "config", (handlers) =>
|
||||
Effect.gen(function* () {
|
||||
const providerSvc = yield* Provider.Service
|
||||
const configSvc = yield* Config.Service
|
||||
Effect.gen(function* () {
|
||||
const providerSvc = yield* Provider.Service
|
||||
const configSvc = yield* Config.Service
|
||||
|
||||
const get = Effect.fn("ConfigHttpApi.get")(function* () {
|
||||
return yield* configSvc.get()
|
||||
})
|
||||
const get = Effect.fn("ConfigHttpApi.get")(function* () {
|
||||
return yield* configSvc.get()
|
||||
})
|
||||
|
||||
const update = Effect.fn("ConfigHttpApi.update")(function* (ctx) {
|
||||
yield* configSvc.update(ctx.payload, { dispose: false })
|
||||
yield* markInstanceForDisposal(yield* InstanceState.context)
|
||||
return ctx.payload
|
||||
})
|
||||
const update = Effect.fn("ConfigHttpApi.update")(function* (ctx) {
|
||||
yield* configSvc.update(ctx.payload, { dispose: false })
|
||||
yield* markInstanceForDisposal(yield* InstanceState.context)
|
||||
return ctx.payload
|
||||
})
|
||||
|
||||
const providers = Effect.fn("ConfigHttpApi.providers")(function* () {
|
||||
const providers = yield* providerSvc.list()
|
||||
return {
|
||||
providers: Object.values(providers),
|
||||
default: Provider.defaultModelIDs(providers),
|
||||
}
|
||||
})
|
||||
const providers = Effect.fn("ConfigHttpApi.providers")(function* () {
|
||||
const providers = yield* providerSvc.list()
|
||||
return {
|
||||
providers: Object.values(providers),
|
||||
default: Provider.defaultModelIDs(providers),
|
||||
}
|
||||
})
|
||||
|
||||
return handlers.handle("get", get).handle("update", update).handle("providers", providers)
|
||||
}),
|
||||
return handlers.handle("get", get).handle("update", update).handle("providers", providers)
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,28 +7,28 @@ import { RootHttpApi } from "../api"
|
|||
import { LogInput } from "../groups/control"
|
||||
|
||||
export const controlHandlers = HttpApiBuilder.group(RootHttpApi, "control", (handlers) =>
|
||||
Effect.gen(function* () {
|
||||
const auth = yield* Auth.Service
|
||||
Effect.gen(function* () {
|
||||
const auth = yield* Auth.Service
|
||||
|
||||
const authSet = Effect.fn("ControlHttpApi.authSet")(function* (ctx: {
|
||||
params: { providerID: ProviderID }
|
||||
payload: Auth.Info
|
||||
}) {
|
||||
yield* auth.set(ctx.params.providerID, ctx.payload).pipe(Effect.orDie)
|
||||
return true
|
||||
})
|
||||
const authSet = Effect.fn("ControlHttpApi.authSet")(function* (ctx: {
|
||||
params: { providerID: ProviderID }
|
||||
payload: Auth.Info
|
||||
}) {
|
||||
yield* auth.set(ctx.params.providerID, ctx.payload).pipe(Effect.orDie)
|
||||
return true
|
||||
})
|
||||
|
||||
const authRemove = Effect.fn("ControlHttpApi.authRemove")(function* (ctx: { params: { providerID: ProviderID } }) {
|
||||
yield* auth.remove(ctx.params.providerID).pipe(Effect.orDie)
|
||||
return true
|
||||
})
|
||||
const authRemove = Effect.fn("ControlHttpApi.authRemove")(function* (ctx: { params: { providerID: ProviderID } }) {
|
||||
yield* auth.remove(ctx.params.providerID).pipe(Effect.orDie)
|
||||
return true
|
||||
})
|
||||
|
||||
const log = Effect.fn("ControlHttpApi.log")(function* (ctx: { payload: typeof LogInput.Type }) {
|
||||
const logger = Log.create({ service: ctx.payload.service })
|
||||
logger[ctx.payload.level](ctx.payload.message, ctx.payload.extra)
|
||||
return true
|
||||
})
|
||||
const log = Effect.fn("ControlHttpApi.log")(function* (ctx: { payload: typeof LogInput.Type }) {
|
||||
const logger = Log.create({ service: ctx.payload.service })
|
||||
logger[ctx.payload.level](ctx.payload.message, ctx.payload.extra)
|
||||
return true
|
||||
})
|
||||
|
||||
return handlers.handle("authSet", authSet).handle("authRemove", authRemove).handle("log", log)
|
||||
}),
|
||||
return handlers.handle("authSet", authSet).handle("authRemove", authRemove).handle("log", log)
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,141 +15,141 @@ import { InstanceHttpApi } from "../api"
|
|||
import { ConsoleSwitchPayload, SessionListQuery, ToolListQuery } from "../groups/experimental"
|
||||
|
||||
export const experimentalHandlers = HttpApiBuilder.group(InstanceHttpApi, "experimental", (handlers) =>
|
||||
Effect.gen(function* () {
|
||||
const account = yield* Account.Service
|
||||
const agents = yield* Agent.Service
|
||||
const config = yield* Config.Service
|
||||
const mcp = yield* MCP.Service
|
||||
const project = yield* Project.Service
|
||||
const registry = yield* ToolRegistry.Service
|
||||
const worktreeSvc = yield* Worktree.Service
|
||||
Effect.gen(function* () {
|
||||
const account = yield* Account.Service
|
||||
const agents = yield* Agent.Service
|
||||
const config = yield* Config.Service
|
||||
const mcp = yield* MCP.Service
|
||||
const project = yield* Project.Service
|
||||
const registry = yield* ToolRegistry.Service
|
||||
const worktreeSvc = yield* Worktree.Service
|
||||
|
||||
const getConsole = Effect.fn("ExperimentalHttpApi.console")(function* () {
|
||||
const [state, groups] = yield* Effect.all(
|
||||
[config.getConsoleState(), account.orgsByAccount().pipe(Effect.orDie)],
|
||||
{
|
||||
concurrency: "unbounded",
|
||||
},
|
||||
)
|
||||
return {
|
||||
consoleManagedProviders: state.consoleManagedProviders,
|
||||
...(state.activeOrgName ? { activeOrgName: state.activeOrgName } : {}),
|
||||
switchableOrgCount: groups.reduce((count, group) => count + group.orgs.length, 0),
|
||||
}
|
||||
const getConsole = Effect.fn("ExperimentalHttpApi.console")(function* () {
|
||||
const [state, groups] = yield* Effect.all(
|
||||
[config.getConsoleState(), account.orgsByAccount().pipe(Effect.orDie)],
|
||||
{
|
||||
concurrency: "unbounded",
|
||||
},
|
||||
)
|
||||
return {
|
||||
consoleManagedProviders: state.consoleManagedProviders,
|
||||
...(state.activeOrgName ? { activeOrgName: state.activeOrgName } : {}),
|
||||
switchableOrgCount: groups.reduce((count, group) => count + group.orgs.length, 0),
|
||||
}
|
||||
})
|
||||
|
||||
const listConsoleOrgs = Effect.fn("ExperimentalHttpApi.consoleOrgs")(function* () {
|
||||
const [groups, active] = yield* Effect.all(
|
||||
[account.orgsByAccount().pipe(Effect.orDie), account.active().pipe(Effect.orDie)],
|
||||
{
|
||||
concurrency: "unbounded",
|
||||
},
|
||||
)
|
||||
const info = Option.getOrUndefined(active)
|
||||
return {
|
||||
orgs: groups.flatMap((group) =>
|
||||
group.orgs.map((org) => ({
|
||||
accountID: group.account.id,
|
||||
accountEmail: group.account.email,
|
||||
accountUrl: group.account.url,
|
||||
orgID: org.id,
|
||||
orgName: org.name,
|
||||
active: !!info && info.id === group.account.id && info.active_org_id === org.id,
|
||||
})),
|
||||
),
|
||||
}
|
||||
})
|
||||
|
||||
const switchConsole = Effect.fn("ExperimentalHttpApi.consoleSwitch")(function* (ctx: {
|
||||
payload: typeof ConsoleSwitchPayload.Type
|
||||
}) {
|
||||
yield* account
|
||||
.use(ctx.payload.accountID, Option.some(ctx.payload.orgID))
|
||||
.pipe(Effect.catch(() => Effect.fail(new HttpApiError.BadRequest({}))))
|
||||
return true
|
||||
})
|
||||
|
||||
const tool = Effect.fn("ExperimentalHttpApi.tool")(function* (ctx: { query: typeof ToolListQuery.Type }) {
|
||||
const list = yield* registry.tools({
|
||||
providerID: ctx.query.provider,
|
||||
modelID: ctx.query.model,
|
||||
agent: yield* agents.get(yield* agents.defaultAgent()),
|
||||
})
|
||||
return list.map((item) => ({
|
||||
id: item.id,
|
||||
description: item.description,
|
||||
parameters: EffectZod.toJsonSchema(item.parameters),
|
||||
}))
|
||||
})
|
||||
|
||||
const listConsoleOrgs = Effect.fn("ExperimentalHttpApi.consoleOrgs")(function* () {
|
||||
const [groups, active] = yield* Effect.all(
|
||||
[account.orgsByAccount().pipe(Effect.orDie), account.active().pipe(Effect.orDie)],
|
||||
{
|
||||
concurrency: "unbounded",
|
||||
},
|
||||
)
|
||||
const info = Option.getOrUndefined(active)
|
||||
return {
|
||||
orgs: groups.flatMap((group) =>
|
||||
group.orgs.map((org) => ({
|
||||
accountID: group.account.id,
|
||||
accountEmail: group.account.email,
|
||||
accountUrl: group.account.url,
|
||||
orgID: org.id,
|
||||
orgName: org.name,
|
||||
active: !!info && info.id === group.account.id && info.active_org_id === org.id,
|
||||
})),
|
||||
),
|
||||
}
|
||||
const toolIDs = Effect.fn("ExperimentalHttpApi.toolIDs")(function* () {
|
||||
return yield* registry.ids()
|
||||
})
|
||||
|
||||
const worktree = Effect.fn("ExperimentalHttpApi.worktree")(function* () {
|
||||
const ctx = yield* InstanceState.context
|
||||
return yield* project.sandboxes(ctx.project.id)
|
||||
})
|
||||
|
||||
const worktreeCreate = Effect.fn("ExperimentalHttpApi.worktreeCreate")(function* (ctx: {
|
||||
payload: Worktree.CreateInput | undefined
|
||||
}) {
|
||||
return yield* worktreeSvc.create(ctx.payload)
|
||||
})
|
||||
|
||||
const worktreeRemove = Effect.fn("ExperimentalHttpApi.worktreeRemove")(function* (input: {
|
||||
payload: Worktree.RemoveInput
|
||||
}) {
|
||||
const ctx = yield* InstanceState.context
|
||||
yield* worktreeSvc.remove(input.payload)
|
||||
yield* project.removeSandbox(ctx.project.id, input.payload.directory)
|
||||
return true
|
||||
})
|
||||
|
||||
const worktreeReset = Effect.fn("ExperimentalHttpApi.worktreeReset")(function* (ctx: {
|
||||
payload: Worktree.ResetInput
|
||||
}) {
|
||||
yield* worktreeSvc.reset(ctx.payload)
|
||||
return true
|
||||
})
|
||||
|
||||
const session = Effect.fn("ExperimentalHttpApi.session")(function* (ctx: { query: typeof SessionListQuery.Type }) {
|
||||
const limit = ctx.query.limit ?? 100
|
||||
const sessions = Array.from(
|
||||
Session.listGlobal({
|
||||
directory: ctx.query.directory,
|
||||
roots: ctx.query.roots,
|
||||
start: ctx.query.start,
|
||||
cursor: ctx.query.cursor,
|
||||
search: ctx.query.search,
|
||||
limit: limit + 1,
|
||||
archived: ctx.query.archived,
|
||||
}),
|
||||
)
|
||||
const list = sessions.length > limit ? sessions.slice(0, limit) : sessions
|
||||
return HttpServerResponse.jsonUnsafe(list, {
|
||||
headers:
|
||||
sessions.length > limit && list.length > 0
|
||||
? { "x-next-cursor": String(list[list.length - 1].time.updated) }
|
||||
: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
const switchConsole = Effect.fn("ExperimentalHttpApi.consoleSwitch")(function* (ctx: {
|
||||
payload: typeof ConsoleSwitchPayload.Type
|
||||
}) {
|
||||
yield* account
|
||||
.use(ctx.payload.accountID, Option.some(ctx.payload.orgID))
|
||||
.pipe(Effect.catch(() => Effect.fail(new HttpApiError.BadRequest({}))))
|
||||
return true
|
||||
})
|
||||
const resource = Effect.fn("ExperimentalHttpApi.resource")(function* () {
|
||||
return yield* mcp.resources()
|
||||
})
|
||||
|
||||
const tool = Effect.fn("ExperimentalHttpApi.tool")(function* (ctx: { query: typeof ToolListQuery.Type }) {
|
||||
const list = yield* registry.tools({
|
||||
providerID: ctx.query.provider,
|
||||
modelID: ctx.query.model,
|
||||
agent: yield* agents.get(yield* agents.defaultAgent()),
|
||||
})
|
||||
return list.map((item) => ({
|
||||
id: item.id,
|
||||
description: item.description,
|
||||
parameters: EffectZod.toJsonSchema(item.parameters),
|
||||
}))
|
||||
})
|
||||
|
||||
const toolIDs = Effect.fn("ExperimentalHttpApi.toolIDs")(function* () {
|
||||
return yield* registry.ids()
|
||||
})
|
||||
|
||||
const worktree = Effect.fn("ExperimentalHttpApi.worktree")(function* () {
|
||||
const ctx = yield* InstanceState.context
|
||||
return yield* project.sandboxes(ctx.project.id)
|
||||
})
|
||||
|
||||
const worktreeCreate = Effect.fn("ExperimentalHttpApi.worktreeCreate")(function* (ctx: {
|
||||
payload: Worktree.CreateInput | undefined
|
||||
}) {
|
||||
return yield* worktreeSvc.create(ctx.payload)
|
||||
})
|
||||
|
||||
const worktreeRemove = Effect.fn("ExperimentalHttpApi.worktreeRemove")(function* (input: {
|
||||
payload: Worktree.RemoveInput
|
||||
}) {
|
||||
const ctx = yield* InstanceState.context
|
||||
yield* worktreeSvc.remove(input.payload)
|
||||
yield* project.removeSandbox(ctx.project.id, input.payload.directory)
|
||||
return true
|
||||
})
|
||||
|
||||
const worktreeReset = Effect.fn("ExperimentalHttpApi.worktreeReset")(function* (ctx: {
|
||||
payload: Worktree.ResetInput
|
||||
}) {
|
||||
yield* worktreeSvc.reset(ctx.payload)
|
||||
return true
|
||||
})
|
||||
|
||||
const session = Effect.fn("ExperimentalHttpApi.session")(function* (ctx: { query: typeof SessionListQuery.Type }) {
|
||||
const limit = ctx.query.limit ?? 100
|
||||
const sessions = Array.from(
|
||||
Session.listGlobal({
|
||||
directory: ctx.query.directory,
|
||||
roots: ctx.query.roots,
|
||||
start: ctx.query.start,
|
||||
cursor: ctx.query.cursor,
|
||||
search: ctx.query.search,
|
||||
limit: limit + 1,
|
||||
archived: ctx.query.archived,
|
||||
}),
|
||||
)
|
||||
const list = sessions.length > limit ? sessions.slice(0, limit) : sessions
|
||||
return HttpServerResponse.jsonUnsafe(list, {
|
||||
headers:
|
||||
sessions.length > limit && list.length > 0
|
||||
? { "x-next-cursor": String(list[list.length - 1].time.updated) }
|
||||
: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
const resource = Effect.fn("ExperimentalHttpApi.resource")(function* () {
|
||||
return yield* mcp.resources()
|
||||
})
|
||||
|
||||
return handlers
|
||||
.handle("console", getConsole)
|
||||
.handle("consoleOrgs", listConsoleOrgs)
|
||||
.handle("consoleSwitch", switchConsole)
|
||||
.handle("tool", tool)
|
||||
.handle("toolIDs", toolIDs)
|
||||
.handle("worktree", worktree)
|
||||
.handle("worktreeCreate", worktreeCreate)
|
||||
.handle("worktreeRemove", worktreeRemove)
|
||||
.handle("worktreeReset", worktreeReset)
|
||||
.handle("session", session)
|
||||
.handle("resource", resource)
|
||||
}),
|
||||
return handlers
|
||||
.handle("console", getConsole)
|
||||
.handle("consoleOrgs", listConsoleOrgs)
|
||||
.handle("consoleSwitch", switchConsole)
|
||||
.handle("tool", tool)
|
||||
.handle("toolIDs", toolIDs)
|
||||
.handle("worktree", worktree)
|
||||
.handle("worktreeCreate", worktreeCreate)
|
||||
.handle("worktreeRemove", worktreeRemove)
|
||||
.handle("worktreeReset", worktreeReset)
|
||||
.handle("session", session)
|
||||
.handle("resource", resource)
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,49 +6,49 @@ import { HttpApiBuilder } from "effect/unstable/httpapi"
|
|||
import { InstanceHttpApi } from "../api"
|
||||
|
||||
export const fileHandlers = HttpApiBuilder.group(InstanceHttpApi, "file", (handlers) =>
|
||||
Effect.gen(function* () {
|
||||
const svc = yield* File.Service
|
||||
const ripgrep = yield* Ripgrep.Service
|
||||
Effect.gen(function* () {
|
||||
const svc = yield* File.Service
|
||||
const ripgrep = yield* Ripgrep.Service
|
||||
|
||||
const findText = Effect.fn("FileHttpApi.findText")(function* (ctx: { query: { pattern: string } }) {
|
||||
return (yield* ripgrep
|
||||
.search({ cwd: (yield* InstanceState.context).directory, pattern: ctx.query.pattern, limit: 10 })
|
||||
.pipe(Effect.orDie)).items
|
||||
const findText = Effect.fn("FileHttpApi.findText")(function* (ctx: { query: { pattern: string } }) {
|
||||
return (yield* ripgrep
|
||||
.search({ cwd: (yield* InstanceState.context).directory, pattern: ctx.query.pattern, limit: 10 })
|
||||
.pipe(Effect.orDie)).items
|
||||
})
|
||||
|
||||
const findFile = Effect.fn("FileHttpApi.findFile")(function* (ctx: {
|
||||
query: { query: string; dirs?: "true" | "false"; type?: "file" | "directory"; limit?: number }
|
||||
}) {
|
||||
return yield* svc.search({
|
||||
query: ctx.query.query,
|
||||
limit: ctx.query.limit ?? 10,
|
||||
dirs: ctx.query.dirs !== "false",
|
||||
type: ctx.query.type,
|
||||
})
|
||||
})
|
||||
|
||||
const findFile = Effect.fn("FileHttpApi.findFile")(function* (ctx: {
|
||||
query: { query: string; dirs?: "true" | "false"; type?: "file" | "directory"; limit?: number }
|
||||
}) {
|
||||
return yield* svc.search({
|
||||
query: ctx.query.query,
|
||||
limit: ctx.query.limit ?? 10,
|
||||
dirs: ctx.query.dirs !== "false",
|
||||
type: ctx.query.type,
|
||||
})
|
||||
})
|
||||
const findSymbol = Effect.fn("FileHttpApi.findSymbol")(function* () {
|
||||
return []
|
||||
})
|
||||
|
||||
const findSymbol = Effect.fn("FileHttpApi.findSymbol")(function* () {
|
||||
return []
|
||||
})
|
||||
const list = Effect.fn("FileHttpApi.list")(function* (ctx: { query: { path: string } }) {
|
||||
return yield* svc.list(ctx.query.path)
|
||||
})
|
||||
|
||||
const list = Effect.fn("FileHttpApi.list")(function* (ctx: { query: { path: string } }) {
|
||||
return yield* svc.list(ctx.query.path)
|
||||
})
|
||||
const content = Effect.fn("FileHttpApi.content")(function* (ctx: { query: { path: string } }) {
|
||||
return yield* svc.read(ctx.query.path)
|
||||
})
|
||||
|
||||
const content = Effect.fn("FileHttpApi.content")(function* (ctx: { query: { path: string } }) {
|
||||
return yield* svc.read(ctx.query.path)
|
||||
})
|
||||
const status = Effect.fn("FileHttpApi.status")(function* () {
|
||||
return yield* svc.status()
|
||||
})
|
||||
|
||||
const status = Effect.fn("FileHttpApi.status")(function* () {
|
||||
return yield* svc.status()
|
||||
})
|
||||
|
||||
return handlers
|
||||
.handle("findText", findText)
|
||||
.handle("findFile", findFile)
|
||||
.handle("findSymbol", findSymbol)
|
||||
.handle("list", list)
|
||||
.handle("content", content)
|
||||
.handle("status", status)
|
||||
}),
|
||||
return handlers
|
||||
.handle("findText", findText)
|
||||
.handle("findFile", findFile)
|
||||
.handle("findSymbol", findSymbol)
|
||||
.handle("list", list)
|
||||
.handle("content", content)
|
||||
.handle("status", status)
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -65,92 +65,92 @@ function eventResponse() {
|
|||
}
|
||||
|
||||
export const globalHandlers = HttpApiBuilder.group(RootHttpApi, "global", (handlers) =>
|
||||
Effect.gen(function* () {
|
||||
const config = yield* Config.Service
|
||||
const installation = yield* Installation.Service
|
||||
Effect.gen(function* () {
|
||||
const config = yield* Config.Service
|
||||
const installation = yield* Installation.Service
|
||||
|
||||
const health = Effect.fn("GlobalHttpApi.health")(function* () {
|
||||
return { healthy: true as const, version: InstallationVersion }
|
||||
const health = Effect.fn("GlobalHttpApi.health")(function* () {
|
||||
return { healthy: true as const, version: InstallationVersion }
|
||||
})
|
||||
|
||||
const event = Effect.fn("GlobalHttpApi.event")(function* () {
|
||||
return eventResponse()
|
||||
})
|
||||
|
||||
const configGet = Effect.fn("GlobalHttpApi.configGet")(function* () {
|
||||
return yield* config.getGlobal()
|
||||
})
|
||||
|
||||
const configUpdate = Effect.fn("GlobalHttpApi.configUpdate")(function* (ctx) {
|
||||
return yield* config.updateGlobal(ctx.payload)
|
||||
})
|
||||
|
||||
const dispose = Effect.fn("GlobalHttpApi.dispose")(function* () {
|
||||
yield* Effect.promise(() => Instance.disposeAll())
|
||||
GlobalBus.emit("event", {
|
||||
directory: "global",
|
||||
payload: { type: "global.disposed", properties: {} },
|
||||
})
|
||||
return true
|
||||
})
|
||||
|
||||
const event = Effect.fn("GlobalHttpApi.event")(function* () {
|
||||
return eventResponse()
|
||||
})
|
||||
|
||||
const configGet = Effect.fn("GlobalHttpApi.configGet")(function* () {
|
||||
return yield* config.getGlobal()
|
||||
})
|
||||
|
||||
const configUpdate = Effect.fn("GlobalHttpApi.configUpdate")(function* (ctx) {
|
||||
return yield* config.updateGlobal(ctx.payload)
|
||||
})
|
||||
|
||||
const dispose = Effect.fn("GlobalHttpApi.dispose")(function* () {
|
||||
yield* Effect.promise(() => Instance.disposeAll())
|
||||
GlobalBus.emit("event", {
|
||||
directory: "global",
|
||||
payload: { type: "global.disposed", properties: {} },
|
||||
})
|
||||
return true
|
||||
})
|
||||
|
||||
const upgrade = Effect.fn("GlobalHttpApi.upgrade")(function* (ctx: { payload: typeof GlobalUpgradeInput.Type }) {
|
||||
const method = yield* installation.method()
|
||||
if (method === "unknown") {
|
||||
return {
|
||||
status: 400,
|
||||
body: { success: false as const, error: "Unknown installation method" },
|
||||
}
|
||||
const upgrade = Effect.fn("GlobalHttpApi.upgrade")(function* (ctx: { payload: typeof GlobalUpgradeInput.Type }) {
|
||||
const method = yield* installation.method()
|
||||
if (method === "unknown") {
|
||||
return {
|
||||
status: 400,
|
||||
body: { success: false as const, error: "Unknown installation method" },
|
||||
}
|
||||
const target = ctx.payload.target || (yield* installation.latest(method))
|
||||
const result = yield* installation.upgrade(method, target).pipe(
|
||||
Effect.as({ status: 200, body: { success: true as const, version: target } }),
|
||||
Effect.catch((err) =>
|
||||
Effect.succeed({
|
||||
status: 500,
|
||||
body: {
|
||||
success: false as const,
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
},
|
||||
}),
|
||||
),
|
||||
)
|
||||
if (!result.body.success) return result
|
||||
GlobalBus.emit("event", {
|
||||
directory: "global",
|
||||
payload: {
|
||||
type: Installation.Event.Updated.type,
|
||||
properties: { version: target },
|
||||
},
|
||||
})
|
||||
return result
|
||||
}
|
||||
const target = ctx.payload.target || (yield* installation.latest(method))
|
||||
const result = yield* installation.upgrade(method, target).pipe(
|
||||
Effect.as({ status: 200, body: { success: true as const, version: target } }),
|
||||
Effect.catch((err) =>
|
||||
Effect.succeed({
|
||||
status: 500,
|
||||
body: {
|
||||
success: false as const,
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
},
|
||||
}),
|
||||
),
|
||||
)
|
||||
if (!result.body.success) return result
|
||||
GlobalBus.emit("event", {
|
||||
directory: "global",
|
||||
payload: {
|
||||
type: Installation.Event.Updated.type,
|
||||
properties: { version: target },
|
||||
},
|
||||
})
|
||||
return result
|
||||
})
|
||||
|
||||
const upgradeRaw = Effect.fn("GlobalHttpApi.upgradeRaw")(function* (ctx: {
|
||||
request: HttpServerRequest.HttpServerRequest
|
||||
}) {
|
||||
const body = yield* Effect.orDie(ctx.request.text)
|
||||
const json = parseBody(body)
|
||||
if (json === undefined) {
|
||||
return HttpServerResponse.jsonUnsafe({ success: false, error: "Invalid request body" }, { status: 400 })
|
||||
}
|
||||
const payload = yield* Schema.decodeUnknownEffect(GlobalUpgradeInput)(json).pipe(
|
||||
Effect.map((payload) => ({ valid: true as const, payload })),
|
||||
Effect.catch(() => Effect.succeed({ valid: false as const })),
|
||||
)
|
||||
if (!payload.valid) {
|
||||
return HttpServerResponse.jsonUnsafe({ success: false, error: "Invalid request body" }, { status: 400 })
|
||||
}
|
||||
const result = yield* upgrade({ payload: payload.payload })
|
||||
return HttpServerResponse.jsonUnsafe(result.body, { status: result.status })
|
||||
})
|
||||
const upgradeRaw = Effect.fn("GlobalHttpApi.upgradeRaw")(function* (ctx: {
|
||||
request: HttpServerRequest.HttpServerRequest
|
||||
}) {
|
||||
const body = yield* Effect.orDie(ctx.request.text)
|
||||
const json = parseBody(body)
|
||||
if (json === undefined) {
|
||||
return HttpServerResponse.jsonUnsafe({ success: false, error: "Invalid request body" }, { status: 400 })
|
||||
}
|
||||
const payload = yield* Schema.decodeUnknownEffect(GlobalUpgradeInput)(json).pipe(
|
||||
Effect.map((payload) => ({ valid: true as const, payload })),
|
||||
Effect.catch(() => Effect.succeed({ valid: false as const })),
|
||||
)
|
||||
if (!payload.valid) {
|
||||
return HttpServerResponse.jsonUnsafe({ success: false, error: "Invalid request body" }, { status: 400 })
|
||||
}
|
||||
const result = yield* upgrade({ payload: payload.payload })
|
||||
return HttpServerResponse.jsonUnsafe(result.body, { status: result.status })
|
||||
})
|
||||
|
||||
return handlers
|
||||
.handle("health", health)
|
||||
.handleRaw("event", event)
|
||||
.handle("configGet", configGet)
|
||||
.handle("configUpdate", configUpdate)
|
||||
.handle("dispose", dispose)
|
||||
.handleRaw("upgrade", upgradeRaw)
|
||||
}),
|
||||
return handlers
|
||||
.handle("health", health)
|
||||
.handleRaw("event", event)
|
||||
.handle("configGet", configGet)
|
||||
.handle("configUpdate", configUpdate)
|
||||
.handle("dispose", dispose)
|
||||
.handleRaw("upgrade", upgradeRaw)
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,68 +12,68 @@ import { InstanceHttpApi } from "../api"
|
|||
import { markInstanceForDisposal } from "../lifecycle"
|
||||
|
||||
export const instanceHandlers = HttpApiBuilder.group(InstanceHttpApi, "instance", (handlers) =>
|
||||
Effect.gen(function* () {
|
||||
const agent = yield* Agent.Service
|
||||
const command = yield* Command.Service
|
||||
const format = yield* Format.Service
|
||||
const lsp = yield* LSP.Service
|
||||
const skill = yield* Skill.Service
|
||||
const vcs = yield* Vcs.Service
|
||||
Effect.gen(function* () {
|
||||
const agent = yield* Agent.Service
|
||||
const command = yield* Command.Service
|
||||
const format = yield* Format.Service
|
||||
const lsp = yield* LSP.Service
|
||||
const skill = yield* Skill.Service
|
||||
const vcs = yield* Vcs.Service
|
||||
|
||||
const dispose = Effect.fn("InstanceHttpApi.dispose")(function* () {
|
||||
yield* markInstanceForDisposal(yield* InstanceState.context)
|
||||
return true
|
||||
})
|
||||
const dispose = Effect.fn("InstanceHttpApi.dispose")(function* () {
|
||||
yield* markInstanceForDisposal(yield* InstanceState.context)
|
||||
return true
|
||||
})
|
||||
|
||||
const getPath = Effect.fn("InstanceHttpApi.path")(function* () {
|
||||
const ctx = yield* InstanceState.context
|
||||
return {
|
||||
home: Global.Path.home,
|
||||
state: Global.Path.state,
|
||||
config: Global.Path.config,
|
||||
worktree: ctx.worktree,
|
||||
directory: ctx.directory,
|
||||
}
|
||||
})
|
||||
const getPath = Effect.fn("InstanceHttpApi.path")(function* () {
|
||||
const ctx = yield* InstanceState.context
|
||||
return {
|
||||
home: Global.Path.home,
|
||||
state: Global.Path.state,
|
||||
config: Global.Path.config,
|
||||
worktree: ctx.worktree,
|
||||
directory: ctx.directory,
|
||||
}
|
||||
})
|
||||
|
||||
const getVcs = Effect.fn("InstanceHttpApi.vcs")(function* () {
|
||||
const [branch, default_branch] = yield* Effect.all([vcs.branch(), vcs.defaultBranch()], { concurrency: 2 })
|
||||
return { branch, default_branch }
|
||||
})
|
||||
const getVcs = Effect.fn("InstanceHttpApi.vcs")(function* () {
|
||||
const [branch, default_branch] = yield* Effect.all([vcs.branch(), vcs.defaultBranch()], { concurrency: 2 })
|
||||
return { branch, default_branch }
|
||||
})
|
||||
|
||||
const getVcsDiff = Effect.fn("InstanceHttpApi.vcsDiff")(function* (ctx: { query: { mode: Vcs.Mode } }) {
|
||||
return yield* vcs.diff(ctx.query.mode)
|
||||
})
|
||||
const getVcsDiff = Effect.fn("InstanceHttpApi.vcsDiff")(function* (ctx: { query: { mode: Vcs.Mode } }) {
|
||||
return yield* vcs.diff(ctx.query.mode)
|
||||
})
|
||||
|
||||
const getCommand = Effect.fn("InstanceHttpApi.command")(function* () {
|
||||
return yield* command.list()
|
||||
})
|
||||
const getCommand = Effect.fn("InstanceHttpApi.command")(function* () {
|
||||
return yield* command.list()
|
||||
})
|
||||
|
||||
const getAgent = Effect.fn("InstanceHttpApi.agent")(function* () {
|
||||
return yield* agent.list()
|
||||
})
|
||||
const getAgent = Effect.fn("InstanceHttpApi.agent")(function* () {
|
||||
return yield* agent.list()
|
||||
})
|
||||
|
||||
const getSkill = Effect.fn("InstanceHttpApi.skill")(function* () {
|
||||
return yield* skill.all()
|
||||
})
|
||||
const getSkill = Effect.fn("InstanceHttpApi.skill")(function* () {
|
||||
return yield* skill.all()
|
||||
})
|
||||
|
||||
const getLsp = Effect.fn("InstanceHttpApi.lsp")(function* () {
|
||||
return yield* lsp.status()
|
||||
})
|
||||
const getLsp = Effect.fn("InstanceHttpApi.lsp")(function* () {
|
||||
return yield* lsp.status()
|
||||
})
|
||||
|
||||
const getFormatter = Effect.fn("InstanceHttpApi.formatter")(function* () {
|
||||
return yield* format.status()
|
||||
})
|
||||
const getFormatter = Effect.fn("InstanceHttpApi.formatter")(function* () {
|
||||
return yield* format.status()
|
||||
})
|
||||
|
||||
return handlers
|
||||
.handle("dispose", dispose)
|
||||
.handle("path", getPath)
|
||||
.handle("vcs", getVcs)
|
||||
.handle("vcsDiff", getVcsDiff)
|
||||
.handle("command", getCommand)
|
||||
.handle("agent", getAgent)
|
||||
.handle("skill", getSkill)
|
||||
.handle("lsp", getLsp)
|
||||
.handle("formatter", getFormatter)
|
||||
}),
|
||||
return handlers
|
||||
.handle("dispose", dispose)
|
||||
.handle("path", getPath)
|
||||
.handle("vcs", getVcs)
|
||||
.handle("vcsDiff", getVcsDiff)
|
||||
.handle("command", getCommand)
|
||||
.handle("agent", getAgent)
|
||||
.handle("skill", getSkill)
|
||||
.handle("lsp", getLsp)
|
||||
.handle("formatter", getFormatter)
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,64 +5,64 @@ import { InstanceHttpApi } from "../api"
|
|||
import { AddPayload, AuthCallbackPayload, StatusMap, UnsupportedOAuthError } from "../groups/mcp"
|
||||
|
||||
export const mcpHandlers = HttpApiBuilder.group(InstanceHttpApi, "mcp", (handlers) =>
|
||||
Effect.gen(function* () {
|
||||
const mcp = yield* MCP.Service
|
||||
Effect.gen(function* () {
|
||||
const mcp = yield* MCP.Service
|
||||
|
||||
const status = Effect.fn("McpHttpApi.status")(function* () {
|
||||
return yield* mcp.status()
|
||||
})
|
||||
const status = Effect.fn("McpHttpApi.status")(function* () {
|
||||
return yield* mcp.status()
|
||||
})
|
||||
|
||||
const add = Effect.fn("McpHttpApi.add")(function* (ctx: { payload: typeof AddPayload.Type }) {
|
||||
const result = (yield* mcp.add(ctx.payload.name, ctx.payload.config)).status
|
||||
return yield* Schema.decodeUnknownEffect(StatusMap)(
|
||||
"status" in result ? { [ctx.payload.name]: result } : result,
|
||||
).pipe(Effect.mapError(() => new HttpApiError.BadRequest({})))
|
||||
})
|
||||
const add = Effect.fn("McpHttpApi.add")(function* (ctx: { payload: typeof AddPayload.Type }) {
|
||||
const result = (yield* mcp.add(ctx.payload.name, ctx.payload.config)).status
|
||||
return yield* Schema.decodeUnknownEffect(StatusMap)(
|
||||
"status" in result ? { [ctx.payload.name]: result } : result,
|
||||
).pipe(Effect.mapError(() => new HttpApiError.BadRequest({})))
|
||||
})
|
||||
|
||||
const authStart = Effect.fn("McpHttpApi.authStart")(function* (ctx: { params: { name: string } }) {
|
||||
if (!(yield* mcp.supportsOAuth(ctx.params.name))) {
|
||||
return yield* new UnsupportedOAuthError({ error: `MCP server ${ctx.params.name} does not support OAuth` })
|
||||
}
|
||||
return yield* mcp.startAuth(ctx.params.name)
|
||||
})
|
||||
const authStart = Effect.fn("McpHttpApi.authStart")(function* (ctx: { params: { name: string } }) {
|
||||
if (!(yield* mcp.supportsOAuth(ctx.params.name))) {
|
||||
return yield* new UnsupportedOAuthError({ error: `MCP server ${ctx.params.name} does not support OAuth` })
|
||||
}
|
||||
return yield* mcp.startAuth(ctx.params.name)
|
||||
})
|
||||
|
||||
const authCallback = Effect.fn("McpHttpApi.authCallback")(function* (ctx: {
|
||||
params: { name: string }
|
||||
payload: typeof AuthCallbackPayload.Type
|
||||
}) {
|
||||
return yield* mcp.finishAuth(ctx.params.name, ctx.payload.code)
|
||||
})
|
||||
const authCallback = Effect.fn("McpHttpApi.authCallback")(function* (ctx: {
|
||||
params: { name: string }
|
||||
payload: typeof AuthCallbackPayload.Type
|
||||
}) {
|
||||
return yield* mcp.finishAuth(ctx.params.name, ctx.payload.code)
|
||||
})
|
||||
|
||||
const authAuthenticate = Effect.fn("McpHttpApi.authAuthenticate")(function* (ctx: { params: { name: string } }) {
|
||||
if (!(yield* mcp.supportsOAuth(ctx.params.name))) {
|
||||
return yield* new UnsupportedOAuthError({ error: `MCP server ${ctx.params.name} does not support OAuth` })
|
||||
}
|
||||
return yield* mcp.authenticate(ctx.params.name)
|
||||
})
|
||||
const authAuthenticate = Effect.fn("McpHttpApi.authAuthenticate")(function* (ctx: { params: { name: string } }) {
|
||||
if (!(yield* mcp.supportsOAuth(ctx.params.name))) {
|
||||
return yield* new UnsupportedOAuthError({ error: `MCP server ${ctx.params.name} does not support OAuth` })
|
||||
}
|
||||
return yield* mcp.authenticate(ctx.params.name)
|
||||
})
|
||||
|
||||
const authRemove = Effect.fn("McpHttpApi.authRemove")(function* (ctx: { params: { name: string } }) {
|
||||
yield* mcp.removeAuth(ctx.params.name)
|
||||
return { success: true as const }
|
||||
})
|
||||
const authRemove = Effect.fn("McpHttpApi.authRemove")(function* (ctx: { params: { name: string } }) {
|
||||
yield* mcp.removeAuth(ctx.params.name)
|
||||
return { success: true as const }
|
||||
})
|
||||
|
||||
const connect = Effect.fn("McpHttpApi.connect")(function* (ctx: { params: { name: string } }) {
|
||||
yield* mcp.connect(ctx.params.name)
|
||||
return true
|
||||
})
|
||||
const connect = Effect.fn("McpHttpApi.connect")(function* (ctx: { params: { name: string } }) {
|
||||
yield* mcp.connect(ctx.params.name)
|
||||
return true
|
||||
})
|
||||
|
||||
const disconnect = Effect.fn("McpHttpApi.disconnect")(function* (ctx: { params: { name: string } }) {
|
||||
yield* mcp.disconnect(ctx.params.name)
|
||||
return true
|
||||
})
|
||||
const disconnect = Effect.fn("McpHttpApi.disconnect")(function* (ctx: { params: { name: string } }) {
|
||||
yield* mcp.disconnect(ctx.params.name)
|
||||
return true
|
||||
})
|
||||
|
||||
return handlers
|
||||
.handle("status", status)
|
||||
.handle("add", add)
|
||||
.handle("authStart", authStart)
|
||||
.handle("authCallback", authCallback)
|
||||
.handle("authAuthenticate", authAuthenticate)
|
||||
.handle("authRemove", authRemove)
|
||||
.handle("connect", connect)
|
||||
.handle("disconnect", disconnect)
|
||||
}),
|
||||
return handlers
|
||||
.handle("status", status)
|
||||
.handle("add", add)
|
||||
.handle("authStart", authStart)
|
||||
.handle("authCallback", authCallback)
|
||||
.handle("authAuthenticate", authAuthenticate)
|
||||
.handle("authRemove", authRemove)
|
||||
.handle("connect", connect)
|
||||
.handle("disconnect", disconnect)
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,25 +5,25 @@ import { HttpApiBuilder } from "effect/unstable/httpapi"
|
|||
import { InstanceHttpApi } from "../api"
|
||||
|
||||
export const permissionHandlers = HttpApiBuilder.group(InstanceHttpApi, "permission", (handlers) =>
|
||||
Effect.gen(function* () {
|
||||
const svc = yield* Permission.Service
|
||||
Effect.gen(function* () {
|
||||
const svc = yield* Permission.Service
|
||||
|
||||
const list = Effect.fn("PermissionHttpApi.list")(function* () {
|
||||
return yield* svc.list()
|
||||
const list = Effect.fn("PermissionHttpApi.list")(function* () {
|
||||
return yield* svc.list()
|
||||
})
|
||||
|
||||
const reply = Effect.fn("PermissionHttpApi.reply")(function* (ctx: {
|
||||
params: { requestID: PermissionID }
|
||||
payload: Permission.ReplyBody
|
||||
}) {
|
||||
yield* svc.reply({
|
||||
requestID: ctx.params.requestID,
|
||||
reply: ctx.payload.reply,
|
||||
message: ctx.payload.message,
|
||||
})
|
||||
return true
|
||||
})
|
||||
|
||||
const reply = Effect.fn("PermissionHttpApi.reply")(function* (ctx: {
|
||||
params: { requestID: PermissionID }
|
||||
payload: Permission.ReplyBody
|
||||
}) {
|
||||
yield* svc.reply({
|
||||
requestID: ctx.params.requestID,
|
||||
reply: ctx.payload.reply,
|
||||
message: ctx.payload.message,
|
||||
})
|
||||
return true
|
||||
})
|
||||
|
||||
return handlers.handle("list", list).handle("reply", reply)
|
||||
}),
|
||||
return handlers.handle("list", list).handle("reply", reply)
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,38 +9,38 @@ import { InstanceHttpApi } from "../api"
|
|||
import { markInstanceForReload } from "../lifecycle"
|
||||
|
||||
export const projectHandlers = HttpApiBuilder.group(InstanceHttpApi, "project", (handlers) =>
|
||||
Effect.gen(function* () {
|
||||
const svc = yield* Project.Service
|
||||
Effect.gen(function* () {
|
||||
const svc = yield* Project.Service
|
||||
|
||||
const list = Effect.fn("ProjectHttpApi.list")(function* () {
|
||||
return yield* svc.list()
|
||||
})
|
||||
const list = Effect.fn("ProjectHttpApi.list")(function* () {
|
||||
return yield* svc.list()
|
||||
})
|
||||
|
||||
const current = Effect.fn("ProjectHttpApi.current")(function* () {
|
||||
return (yield* InstanceState.context).project
|
||||
})
|
||||
const current = Effect.fn("ProjectHttpApi.current")(function* () {
|
||||
return (yield* InstanceState.context).project
|
||||
})
|
||||
|
||||
const initGit = Effect.fn("ProjectHttpApi.initGit")(function* () {
|
||||
const ctx = yield* InstanceState.context
|
||||
const next = yield* svc.initGit({ directory: ctx.directory, project: ctx.project })
|
||||
if (next.id === ctx.project.id && next.vcs === ctx.project.vcs && next.worktree === ctx.project.worktree)
|
||||
return next
|
||||
yield* markInstanceForReload(ctx, {
|
||||
directory: ctx.directory,
|
||||
worktree: ctx.directory,
|
||||
project: next,
|
||||
init: () => AppRuntime.runPromise(InstanceBootstrap),
|
||||
})
|
||||
const initGit = Effect.fn("ProjectHttpApi.initGit")(function* () {
|
||||
const ctx = yield* InstanceState.context
|
||||
const next = yield* svc.initGit({ directory: ctx.directory, project: ctx.project })
|
||||
if (next.id === ctx.project.id && next.vcs === ctx.project.vcs && next.worktree === ctx.project.worktree)
|
||||
return next
|
||||
yield* markInstanceForReload(ctx, {
|
||||
directory: ctx.directory,
|
||||
worktree: ctx.directory,
|
||||
project: next,
|
||||
init: () => AppRuntime.runPromise(InstanceBootstrap),
|
||||
})
|
||||
return next
|
||||
})
|
||||
|
||||
const update = Effect.fn("ProjectHttpApi.update")(function* (ctx: {
|
||||
params: { projectID: ProjectID }
|
||||
payload: Project.UpdatePayload
|
||||
}) {
|
||||
return yield* svc.update({ ...ctx.payload, projectID: ctx.params.projectID })
|
||||
})
|
||||
const update = Effect.fn("ProjectHttpApi.update")(function* (ctx: {
|
||||
params: { projectID: ProjectID }
|
||||
payload: Project.UpdatePayload
|
||||
}) {
|
||||
return yield* svc.update({ ...ctx.payload, projectID: ctx.params.projectID })
|
||||
})
|
||||
|
||||
return handlers.handle("list", list).handle("current", current).handle("initGit", initGit).handle("update", update)
|
||||
}),
|
||||
return handlers.handle("list", list).handle("current", current).handle("initGit", initGit).handle("update", update)
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,80 +10,80 @@ import { HttpApiBuilder, HttpApiError } from "effect/unstable/httpapi"
|
|||
import { InstanceHttpApi } from "../api"
|
||||
|
||||
export const providerHandlers = HttpApiBuilder.group(InstanceHttpApi, "provider", (handlers) =>
|
||||
Effect.gen(function* () {
|
||||
const cfg = yield* Config.Service
|
||||
const provider = yield* Provider.Service
|
||||
const svc = yield* ProviderAuth.Service
|
||||
Effect.gen(function* () {
|
||||
const cfg = yield* Config.Service
|
||||
const provider = yield* Provider.Service
|
||||
const svc = yield* ProviderAuth.Service
|
||||
|
||||
const list = Effect.fn("ProviderHttpApi.list")(function* () {
|
||||
const config = yield* cfg.get()
|
||||
const all = yield* Effect.promise(() => ModelsDev.get())
|
||||
const disabled = new Set(config.disabled_providers ?? [])
|
||||
const enabled = config.enabled_providers ? new Set(config.enabled_providers) : undefined
|
||||
const filtered: Record<string, (typeof all)[string]> = {}
|
||||
for (const [key, value] of Object.entries(all)) {
|
||||
if ((enabled ? enabled.has(key) : true) && !disabled.has(key)) filtered[key] = value
|
||||
}
|
||||
const connected = yield* provider.list()
|
||||
const providers = Object.assign(
|
||||
mapValues(filtered, (item) => Provider.fromModelsDevProvider(item)),
|
||||
connected,
|
||||
)
|
||||
return {
|
||||
all: Object.values(providers),
|
||||
default: Provider.defaultModelIDs(providers),
|
||||
connected: Object.keys(connected),
|
||||
}
|
||||
})
|
||||
const list = Effect.fn("ProviderHttpApi.list")(function* () {
|
||||
const config = yield* cfg.get()
|
||||
const all = yield* Effect.promise(() => ModelsDev.get())
|
||||
const disabled = new Set(config.disabled_providers ?? [])
|
||||
const enabled = config.enabled_providers ? new Set(config.enabled_providers) : undefined
|
||||
const filtered: Record<string, (typeof all)[string]> = {}
|
||||
for (const [key, value] of Object.entries(all)) {
|
||||
if ((enabled ? enabled.has(key) : true) && !disabled.has(key)) filtered[key] = value
|
||||
}
|
||||
const connected = yield* provider.list()
|
||||
const providers = Object.assign(
|
||||
mapValues(filtered, (item) => Provider.fromModelsDevProvider(item)),
|
||||
connected,
|
||||
)
|
||||
return {
|
||||
all: Object.values(providers),
|
||||
default: Provider.defaultModelIDs(providers),
|
||||
connected: Object.keys(connected),
|
||||
}
|
||||
})
|
||||
|
||||
const auth = Effect.fn("ProviderHttpApi.auth")(function* () {
|
||||
return yield* svc.methods()
|
||||
})
|
||||
const auth = Effect.fn("ProviderHttpApi.auth")(function* () {
|
||||
return yield* svc.methods()
|
||||
})
|
||||
|
||||
const authorize = Effect.fn("ProviderHttpApi.authorize")(function* (ctx: {
|
||||
params: { providerID: ProviderID }
|
||||
payload: ProviderAuth.AuthorizeInput
|
||||
}) {
|
||||
return yield* svc
|
||||
.authorize({
|
||||
providerID: ctx.params.providerID,
|
||||
method: ctx.payload.method,
|
||||
inputs: ctx.payload.inputs,
|
||||
})
|
||||
.pipe(Effect.catch(() => Effect.fail(new HttpApiError.BadRequest({}))))
|
||||
})
|
||||
const authorize = Effect.fn("ProviderHttpApi.authorize")(function* (ctx: {
|
||||
params: { providerID: ProviderID }
|
||||
payload: ProviderAuth.AuthorizeInput
|
||||
}) {
|
||||
return yield* svc
|
||||
.authorize({
|
||||
providerID: ctx.params.providerID,
|
||||
method: ctx.payload.method,
|
||||
inputs: ctx.payload.inputs,
|
||||
})
|
||||
.pipe(Effect.catch(() => Effect.fail(new HttpApiError.BadRequest({}))))
|
||||
})
|
||||
|
||||
const authorizeRaw = Effect.fn("ProviderHttpApi.authorizeRaw")(function* (ctx: {
|
||||
params: { providerID: ProviderID }
|
||||
request: HttpServerRequest.HttpServerRequest
|
||||
}) {
|
||||
const body = yield* Effect.orDie(ctx.request.text)
|
||||
const payload = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(ProviderAuth.AuthorizeInput))(body).pipe(
|
||||
Effect.mapError(() => new HttpApiError.BadRequest({})),
|
||||
)
|
||||
const result = yield* authorize({ params: ctx.params, payload })
|
||||
if (result === undefined) return HttpServerResponse.empty({ status: 200 })
|
||||
return HttpServerResponse.jsonUnsafe(result)
|
||||
})
|
||||
const authorizeRaw = Effect.fn("ProviderHttpApi.authorizeRaw")(function* (ctx: {
|
||||
params: { providerID: ProviderID }
|
||||
request: HttpServerRequest.HttpServerRequest
|
||||
}) {
|
||||
const body = yield* Effect.orDie(ctx.request.text)
|
||||
const payload = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(ProviderAuth.AuthorizeInput))(body).pipe(
|
||||
Effect.mapError(() => new HttpApiError.BadRequest({})),
|
||||
)
|
||||
const result = yield* authorize({ params: ctx.params, payload })
|
||||
if (result === undefined) return HttpServerResponse.empty({ status: 200 })
|
||||
return HttpServerResponse.jsonUnsafe(result)
|
||||
})
|
||||
|
||||
const callback = Effect.fn("ProviderHttpApi.callback")(function* (ctx: {
|
||||
params: { providerID: ProviderID }
|
||||
payload: ProviderAuth.CallbackInput
|
||||
}) {
|
||||
yield* svc
|
||||
.callback({
|
||||
providerID: ctx.params.providerID,
|
||||
method: ctx.payload.method,
|
||||
code: ctx.payload.code,
|
||||
})
|
||||
.pipe(Effect.catch(() => Effect.fail(new HttpApiError.BadRequest({}))))
|
||||
return true
|
||||
})
|
||||
const callback = Effect.fn("ProviderHttpApi.callback")(function* (ctx: {
|
||||
params: { providerID: ProviderID }
|
||||
payload: ProviderAuth.CallbackInput
|
||||
}) {
|
||||
yield* svc
|
||||
.callback({
|
||||
providerID: ctx.params.providerID,
|
||||
method: ctx.payload.method,
|
||||
code: ctx.payload.code,
|
||||
})
|
||||
.pipe(Effect.catch(() => Effect.fail(new HttpApiError.BadRequest({}))))
|
||||
return true
|
||||
})
|
||||
|
||||
return handlers
|
||||
.handle("list", list)
|
||||
.handle("auth", auth)
|
||||
.handleRaw("authorize", authorizeRaw)
|
||||
.handle("callback", callback)
|
||||
}),
|
||||
return handlers
|
||||
.handle("list", list)
|
||||
.handle("auth", auth)
|
||||
.handleRaw("authorize", authorizeRaw)
|
||||
.handle("callback", callback)
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -88,7 +88,9 @@ export const ptyConnectRoute = HttpRouter.add(
|
|||
},
|
||||
send: (data: string | Uint8Array | ArrayBuffer) => {
|
||||
if (closed) return
|
||||
Effect.runFork(write(data instanceof ArrayBuffer ? new Uint8Array(data) : data).pipe(Effect.catch(() => Effect.void)))
|
||||
Effect.runFork(
|
||||
write(data instanceof ArrayBuffer ? new Uint8Array(data) : data).pipe(Effect.catch(() => Effect.void)),
|
||||
)
|
||||
},
|
||||
close: (code?: number, reason?: string) => {
|
||||
if (closed) return
|
||||
|
|
|
|||
|
|
@ -5,29 +5,29 @@ import { HttpApiBuilder } from "effect/unstable/httpapi"
|
|||
import { InstanceHttpApi } from "../api"
|
||||
|
||||
export const questionHandlers = HttpApiBuilder.group(InstanceHttpApi, "question", (handlers) =>
|
||||
Effect.gen(function* () {
|
||||
const svc = yield* Question.Service
|
||||
Effect.gen(function* () {
|
||||
const svc = yield* Question.Service
|
||||
|
||||
const list = Effect.fn("QuestionHttpApi.list")(function* () {
|
||||
return yield* svc.list()
|
||||
const list = Effect.fn("QuestionHttpApi.list")(function* () {
|
||||
return yield* svc.list()
|
||||
})
|
||||
|
||||
const reply = Effect.fn("QuestionHttpApi.reply")(function* (ctx: {
|
||||
params: { requestID: QuestionID }
|
||||
payload: Question.Reply
|
||||
}) {
|
||||
yield* svc.reply({
|
||||
requestID: ctx.params.requestID,
|
||||
answers: ctx.payload.answers,
|
||||
})
|
||||
return true
|
||||
})
|
||||
|
||||
const reply = Effect.fn("QuestionHttpApi.reply")(function* (ctx: {
|
||||
params: { requestID: QuestionID }
|
||||
payload: Question.Reply
|
||||
}) {
|
||||
yield* svc.reply({
|
||||
requestID: ctx.params.requestID,
|
||||
answers: ctx.payload.answers,
|
||||
})
|
||||
return true
|
||||
})
|
||||
const reject = Effect.fn("QuestionHttpApi.reject")(function* (ctx: { params: { requestID: QuestionID } }) {
|
||||
yield* svc.reject(ctx.params.requestID)
|
||||
return true
|
||||
})
|
||||
|
||||
const reject = Effect.fn("QuestionHttpApi.reject")(function* (ctx: { params: { requestID: QuestionID } }) {
|
||||
yield* svc.reject(ctx.params.requestID)
|
||||
return true
|
||||
})
|
||||
|
||||
return handlers.handle("list", list).handle("reply", reply).handle("reject", reject)
|
||||
}),
|
||||
return handlers.handle("list", list).handle("reply", reply).handle("reject", reject)
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,20 @@ import * as Stream from "effect/Stream"
|
|||
import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http"
|
||||
import { HttpApiBuilder, HttpApiError, HttpApiSchema } from "effect/unstable/httpapi"
|
||||
import { InstanceHttpApi } from "../api"
|
||||
import { CommandPayload, DiffQuery, ForkPayload, InitPayload, ListQuery, MessagesQuery, PermissionResponsePayload, PromptPayload, RevertPayload, ShellPayload, SummarizePayload, UpdatePayload } from "../groups/session"
|
||||
import {
|
||||
CommandPayload,
|
||||
DiffQuery,
|
||||
ForkPayload,
|
||||
InitPayload,
|
||||
ListQuery,
|
||||
MessagesQuery,
|
||||
PermissionResponsePayload,
|
||||
PromptPayload,
|
||||
RevertPayload,
|
||||
ShellPayload,
|
||||
SummarizePayload,
|
||||
UpdatePayload,
|
||||
} from "../groups/session"
|
||||
|
||||
const log = Log.create({ service: "server" })
|
||||
|
||||
|
|
@ -88,40 +101,42 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session",
|
|||
params: { sessionID: SessionID }
|
||||
query: typeof MessagesQuery.Type
|
||||
}) {
|
||||
return yield* mapNotFound(Effect.gen(function* () {
|
||||
if (ctx.query.before && ctx.query.limit === undefined) return yield* new HttpApiError.BadRequest({})
|
||||
if (ctx.query.before) {
|
||||
const before = ctx.query.before
|
||||
yield* Effect.try({
|
||||
try: () => MessageV2.cursor.decode(before),
|
||||
catch: () => new HttpApiError.BadRequest({}),
|
||||
})
|
||||
}
|
||||
if (ctx.query.limit === undefined || ctx.query.limit === 0) {
|
||||
return yield* mapNotFound(
|
||||
Effect.gen(function* () {
|
||||
if (ctx.query.before && ctx.query.limit === undefined) return yield* new HttpApiError.BadRequest({})
|
||||
if (ctx.query.before) {
|
||||
const before = ctx.query.before
|
||||
yield* Effect.try({
|
||||
try: () => MessageV2.cursor.decode(before),
|
||||
catch: () => new HttpApiError.BadRequest({}),
|
||||
})
|
||||
}
|
||||
if (ctx.query.limit === undefined || ctx.query.limit === 0) {
|
||||
yield* session.get(ctx.params.sessionID)
|
||||
return yield* session.messages({ sessionID: ctx.params.sessionID })
|
||||
}
|
||||
|
||||
yield* session.get(ctx.params.sessionID)
|
||||
return yield* session.messages({ sessionID: ctx.params.sessionID })
|
||||
}
|
||||
const page = MessageV2.page({
|
||||
sessionID: ctx.params.sessionID,
|
||||
limit: ctx.query.limit,
|
||||
before: ctx.query.before,
|
||||
})
|
||||
if (!page.cursor) return page.items
|
||||
|
||||
yield* session.get(ctx.params.sessionID)
|
||||
const page = MessageV2.page({
|
||||
sessionID: ctx.params.sessionID,
|
||||
limit: ctx.query.limit,
|
||||
before: ctx.query.before,
|
||||
})
|
||||
if (!page.cursor) return page.items
|
||||
|
||||
const request = yield* HttpServerRequest.HttpServerRequest
|
||||
const url = new URL(request.url, "http://localhost")
|
||||
url.searchParams.set("limit", ctx.query.limit.toString())
|
||||
url.searchParams.set("before", page.cursor)
|
||||
return HttpServerResponse.jsonUnsafe(page.items, {
|
||||
headers: {
|
||||
"Access-Control-Expose-Headers": "Link, X-Next-Cursor",
|
||||
Link: `<${url.toString()}>; rel="next"`,
|
||||
"X-Next-Cursor": page.cursor,
|
||||
},
|
||||
})
|
||||
}))
|
||||
const request = yield* HttpServerRequest.HttpServerRequest
|
||||
const url = new URL(request.url, "http://localhost")
|
||||
url.searchParams.set("limit", ctx.query.limit.toString())
|
||||
url.searchParams.set("before", page.cursor)
|
||||
return HttpServerResponse.jsonUnsafe(page.items, {
|
||||
headers: {
|
||||
"Access-Control-Expose-Headers": "Link, X-Next-Cursor",
|
||||
Link: `<${url.toString()}>; rel="next"`,
|
||||
"X-Next-Cursor": page.cursor,
|
||||
},
|
||||
})
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
const message = Effect.fn("SessionHttpApi.message")(function* (ctx: {
|
||||
|
|
|
|||
|
|
@ -19,11 +19,12 @@ import * as Socket from "effect/unstable/socket/Socket"
|
|||
|
||||
type HandlerEffect = Effect.Effect<HttpServerResponse.HttpServerResponse, unhandled, never>
|
||||
|
||||
export class InstanceContextMiddleware extends HttpApiMiddleware.Service<InstanceContextMiddleware, {
|
||||
requires: Session.Service
|
||||
}>()(
|
||||
"@opencode/ExperimentalHttpApiInstanceContext",
|
||||
) {}
|
||||
export class InstanceContextMiddleware extends HttpApiMiddleware.Service<
|
||||
InstanceContextMiddleware,
|
||||
{
|
||||
requires: Session.Service
|
||||
}
|
||||
>()("@opencode/ExperimentalHttpApiInstanceContext") {}
|
||||
|
||||
function decode(input: string) {
|
||||
try {
|
||||
|
|
@ -53,9 +54,14 @@ function requestHeaders(request: HttpServerRequest.HttpServerRequest) {
|
|||
return sourceRequest(request).headers
|
||||
}
|
||||
|
||||
function writeSocket(write: (data: string | Uint8Array | Socket.CloseEvent) => Effect.Effect<void, unknown>, data: unknown) {
|
||||
function writeSocket(
|
||||
write: (data: string | Uint8Array | Socket.CloseEvent) => Effect.Effect<void, unknown>,
|
||||
data: unknown,
|
||||
) {
|
||||
if (data instanceof Blob) {
|
||||
void data.arrayBuffer().then((buffer) => Effect.runFork(write(new Uint8Array(buffer)).pipe(Effect.catch(() => Effect.void))))
|
||||
void data
|
||||
.arrayBuffer()
|
||||
.then((buffer) => Effect.runFork(write(new Uint8Array(buffer)).pipe(Effect.catch(() => Effect.void))))
|
||||
return
|
||||
}
|
||||
if (typeof data === "string" || data instanceof Uint8Array) {
|
||||
|
|
@ -78,7 +84,8 @@ function proxyWebSocket(request: HttpServerRequest.HttpServerRequest, target: st
|
|||
queue.length = 0
|
||||
}
|
||||
remote.onmessage = (event) => writeSocket(write, event.data)
|
||||
remote.onerror = () => Effect.runFork(write(new Socket.CloseEvent(1011, "proxy error")).pipe(Effect.catch(() => Effect.void)))
|
||||
remote.onerror = () =>
|
||||
Effect.runFork(write(new Socket.CloseEvent(1011, "proxy error")).pipe(Effect.catch(() => Effect.void)))
|
||||
remote.onclose = (event) =>
|
||||
Effect.runFork(write(new Socket.CloseEvent(event.code, event.reason)).pipe(Effect.catch(() => Effect.void)))
|
||||
|
||||
|
|
@ -109,7 +116,9 @@ function proxyRemote(
|
|||
const url = workspaceProxyURL(target.url, requestURL)
|
||||
const source = sourceRequest(request)
|
||||
if (source.headers.get("upgrade")?.toLowerCase() === "websocket") return proxyWebSocket(request, url)
|
||||
return Effect.promise(() => ServerProxy.http(url, target.headers, source, workspace.id)).pipe(Effect.map(HttpServerResponse.raw))
|
||||
return Effect.promise(() => ServerProxy.http(url, target.headers, source, workspace.id)).pipe(
|
||||
Effect.map(HttpServerResponse.raw),
|
||||
)
|
||||
}
|
||||
|
||||
function requestContext() {
|
||||
|
|
@ -118,14 +127,19 @@ function requestContext() {
|
|||
)
|
||||
}
|
||||
|
||||
function provideRequestContext(effect: HandlerEffect, request: HttpServerRequest.HttpServerRequest, sessionWorkspaceID?: WorkspaceID) {
|
||||
function provideRequestContext(
|
||||
effect: HandlerEffect,
|
||||
request: HttpServerRequest.HttpServerRequest,
|
||||
sessionWorkspaceID?: WorkspaceID,
|
||||
) {
|
||||
return Effect.gen(function* () {
|
||||
const url = new URL(request.url, "http://localhost")
|
||||
const headers = requestHeaders(request)
|
||||
const envWorkspaceID = Flag.OPENCODE_WORKSPACE_ID ? WorkspaceID.make(Flag.OPENCODE_WORKSPACE_ID) : undefined
|
||||
const workspaceParam = url.searchParams.get("workspace")
|
||||
const workspaceID = sessionWorkspaceID ?? (workspaceParam ? WorkspaceID.make(workspaceParam) : undefined)
|
||||
const workspace = workspaceID && !envWorkspaceID ? yield* Effect.promise(() => Workspace.get(workspaceID)) : undefined
|
||||
const workspace =
|
||||
workspaceID && !envWorkspaceID ? yield* Effect.promise(() => Workspace.get(workspaceID)) : undefined
|
||||
|
||||
if (workspaceID && !workspace && !envWorkspaceID) {
|
||||
return HttpServerResponse.text(`Workspace not found: ${workspaceID}`, {
|
||||
|
|
@ -134,7 +148,12 @@ function provideRequestContext(effect: HandlerEffect, request: HttpServerRequest
|
|||
})
|
||||
}
|
||||
|
||||
if (workspace && !isLocalWorkspaceRoute(request.method, url.pathname) && !url.pathname.startsWith("/console") && !envWorkspaceID) {
|
||||
if (
|
||||
workspace &&
|
||||
!isLocalWorkspaceRoute(request.method, url.pathname) &&
|
||||
!url.pathname.startsWith("/console") &&
|
||||
!envWorkspaceID
|
||||
) {
|
||||
const adaptor = yield* Effect.promise(() => getAdaptor(workspace.projectID, workspace.type))
|
||||
const target = yield* Effect.promise(() => Promise.resolve(adaptor.target(workspace)))
|
||||
if (target.type === "remote") return yield* proxyRemote(request, workspace, target, url)
|
||||
|
|
@ -186,6 +205,8 @@ export const instanceContextLayer = Layer.succeed(
|
|||
InstanceContextMiddleware.of((effect) => provideInstanceContext(effect)),
|
||||
)
|
||||
|
||||
export const instanceRouterLayer = HttpRouter.middleware()(Effect.succeed((effect) =>
|
||||
requestContext().pipe(Effect.flatMap((request) => provideRequestContext(effect, request))),
|
||||
)).layer
|
||||
export const instanceRouterLayer = HttpRouter.middleware()(
|
||||
Effect.succeed((effect) =>
|
||||
requestContext().pipe(Effect.flatMap((request) => provideRequestContext(effect, request))),
|
||||
),
|
||||
).layer
|
||||
|
|
|
|||
|
|
@ -14,7 +14,10 @@ export const markInstanceForDisposal = (ctx: InstanceContext) =>
|
|||
|
||||
export const markInstanceForReload = (ctx: InstanceContext, next: Parameters<typeof Instance.reload>[0]) =>
|
||||
HttpEffect.appendPreResponseHandler((_request, response) =>
|
||||
Effect.as(Effect.uninterruptible(Effect.promise(() => Instance.restore(ctx, () => Instance.reload(next)))), response),
|
||||
Effect.as(
|
||||
Effect.uninterruptible(Effect.promise(() => Instance.restore(ctx, () => Instance.reload(next)))),
|
||||
response,
|
||||
),
|
||||
)
|
||||
|
||||
export const disposeMiddleware: HttpMiddleware.HttpMiddleware = (effect) =>
|
||||
|
|
|
|||
|
|
@ -126,8 +126,13 @@ function matchLegacyOpenApi(input: Record<string, unknown>) {
|
|||
// Workspace creation fields `branch` and `extra` are Schema.NullOr —
|
||||
// genuinely nullable, not just optional. Re-add the null that the
|
||||
// component-level strip above removed.
|
||||
const ref = operation.requestBody.content?.["application/json"]?.schema?.$ref?.replace("#/components/schemas/", "")
|
||||
const properties = ref ? spec.components?.schemas?.[ref]?.properties : operation.requestBody.content?.["application/json"]?.schema?.properties
|
||||
const ref = operation.requestBody.content?.["application/json"]?.schema?.$ref?.replace(
|
||||
"#/components/schemas/",
|
||||
"",
|
||||
)
|
||||
const properties = ref
|
||||
? spec.components?.schemas?.[ref]?.properties
|
||||
: operation.requestBody.content?.["application/json"]?.schema?.properties
|
||||
if (properties?.branch) properties.branch = { anyOf: [properties.branch, { type: "null" }] }
|
||||
if (properties?.extra) properties.extra = { anyOf: [properties.extra, { type: "null" }] }
|
||||
}
|
||||
|
|
@ -150,7 +155,10 @@ function matchLegacyOpenApi(input: Record<string, unknown>) {
|
|||
description: "Event stream",
|
||||
content: {
|
||||
"text/event-stream": {
|
||||
schema: path === "/event" ? { $ref: "#/components/schemas/Event" } : { $ref: "#/components/schemas/GlobalEvent" },
|
||||
schema:
|
||||
path === "/event"
|
||||
? { $ref: "#/components/schemas/Event" }
|
||||
: { $ref: "#/components/schemas/GlobalEvent" },
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -251,7 +259,8 @@ function applyLegacySchemaOverrides(spec: OpenApiSpec) {
|
|||
schemas.Workspace.properties.directory = nullable(schemas.Workspace.properties.directory)
|
||||
schemas.Workspace.properties.extra = nullable(schemas.Workspace.properties.extra)
|
||||
}
|
||||
if (schemas.GlobalSession?.properties?.project) schemas.GlobalSession.properties.project = nullable(schemas.GlobalSession.properties.project)
|
||||
if (schemas.GlobalSession?.properties?.project)
|
||||
schemas.GlobalSession.properties.project = nullable(schemas.GlobalSession.properties.project)
|
||||
const providerOptions = schemas.ProviderConfig?.properties?.options
|
||||
if (providerOptions) providerOptions.additionalProperties = {}
|
||||
const model = schemas.ProviderConfig?.properties?.models?.additionalProperties
|
||||
|
|
@ -486,12 +495,11 @@ function normalizeParameter(param: OpenApiParameter, route: string) {
|
|||
param.schema = stripOptionalNull(param.schema)
|
||||
}
|
||||
|
||||
export const PublicApi = OpenCodeHttpApi
|
||||
.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
title: "opencode",
|
||||
version: "1.0.0",
|
||||
description: "opencode api",
|
||||
transform: matchLegacyOpenApi,
|
||||
}),
|
||||
)
|
||||
export const PublicApi = OpenCodeHttpApi.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
title: "opencode",
|
||||
version: "1.0.0",
|
||||
description: "opencode api",
|
||||
transform: matchLegacyOpenApi,
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,9 @@ type ServerApp = {
|
|||
request(input: string | URL | Request, init?: RequestInit): Response | Promise<Response>
|
||||
}
|
||||
|
||||
const DefaultHono = lazy(() => withBackend({ backend: "hono", reason: "stable" }, createHono({}, { backend: "hono", reason: "stable" })))
|
||||
const DefaultHono = lazy(() =>
|
||||
withBackend({ backend: "hono", reason: "stable" }, createHono({}, { backend: "hono", reason: "stable" })),
|
||||
)
|
||||
const DefaultHttpApi = lazy(() => createDefaultHttpApi())
|
||||
|
||||
function select() {
|
||||
|
|
@ -86,7 +88,10 @@ function createHttpApi() {
|
|||
}
|
||||
}
|
||||
|
||||
function createHono(opts: { cors?: string[] }, selection: ServerBackend.Selection = ServerBackend.force(select(), "hono")) {
|
||||
function createHono(
|
||||
opts: { cors?: string[] },
|
||||
selection: ServerBackend.Selection = ServerBackend.force(select(), "hono"),
|
||||
) {
|
||||
const backendAttributes = ServerBackend.attributes(selection)
|
||||
const app = new Hono()
|
||||
.onError(ErrorMiddleware)
|
||||
|
|
|
|||
|
|
@ -461,7 +461,9 @@ type AssistantError = z.infer<typeof AssistantErrorZod>
|
|||
// Effect Schema for the same union — used by HttpApi OpenAPI generation.
|
||||
const AssistantErrorSchema = Schema.Union([
|
||||
AuthError.EffectSchema,
|
||||
Schema.Struct({ name: Schema.Literal("UnknownError"), data: Schema.Struct({ message: Schema.String }) }).annotate({ identifier: "UnknownError" }),
|
||||
Schema.Struct({ name: Schema.Literal("UnknownError"), data: Schema.Struct({ message: Schema.String }) }).annotate({
|
||||
identifier: "UnknownError",
|
||||
}),
|
||||
OutputLengthError.EffectSchema,
|
||||
AbortedError.EffectSchema,
|
||||
StructuredOutputError.EffectSchema,
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ export const PositiveInt = Schema.Int.check(Schema.isGreaterThan(0))
|
|||
*/
|
||||
export const NonNegativeInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Optional public JSON field that can hold explicit `undefined` on the type
|
||||
* side but encodes it as an omitted key, matching legacy `JSON.stringify`.
|
||||
|
|
|
|||
|
|
@ -126,9 +126,9 @@ function requestBodyKey(spec: OpenApiSpec, body: unknown) {
|
|||
|
||||
function requestBodySchemaKind(spec: OpenApiSpec, schema: OpenApiSchema | undefined) {
|
||||
if (!schema) return ""
|
||||
const resolved = (schema.$ref ? spec.components?.schemas?.[schema.$ref.replace("#/components/schemas/", "")] : schema) as
|
||||
| OpenApiSchema
|
||||
| undefined
|
||||
const resolved = (
|
||||
schema.$ref ? spec.components?.schemas?.[schema.$ref.replace("#/components/schemas/", "")] : schema
|
||||
) as OpenApiSchema | undefined
|
||||
if (resolved?.properties) return "object"
|
||||
if (resolved?.anyOf ?? resolved?.oneOf ?? resolved?.allOf) return "object"
|
||||
return resolved?.type ?? schema.type ?? "inline"
|
||||
|
|
|
|||
|
|
@ -214,7 +214,11 @@ describe("workspace HttpApi", () => {
|
|||
const workspace = await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
registerAdaptor(Instance.project.id, "remote-target", remoteAdaptor(path.join(tmp.path, ".remote"), "https://remote.test/base"))
|
||||
registerAdaptor(
|
||||
Instance.project.id,
|
||||
"remote-target",
|
||||
remoteAdaptor(path.join(tmp.path, ".remote"), "https://remote.test/base"),
|
||||
)
|
||||
return Workspace.create({
|
||||
type: "remote-target",
|
||||
branch: null,
|
||||
|
|
|
|||
|
|
@ -1339,10 +1339,14 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"rows": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"exclusiveMinimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"cols": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"exclusiveMinimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["rows", "cols"]
|
||||
|
|
@ -5595,10 +5599,14 @@
|
|||
"required": ["text"]
|
||||
},
|
||||
"line_number": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"absolute_offset": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"submatches": {
|
||||
"type": "array",
|
||||
|
|
@ -5615,10 +5623,14 @@
|
|||
"required": ["text"]
|
||||
},
|
||||
"start": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"end": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["match", "start", "end"]
|
||||
|
|
@ -6901,7 +6913,9 @@
|
|||
},
|
||||
"duration": {
|
||||
"description": "Duration in milliseconds",
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"exclusiveMinimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["message", "variant"]
|
||||
|
|
@ -7621,13 +7635,19 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"updated": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"initialized": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["created", "updated"]
|
||||
|
|
@ -7913,10 +7933,14 @@
|
|||
"type": "string"
|
||||
},
|
||||
"additions": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"deletions": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
|
|
@ -8039,7 +8063,9 @@
|
|||
"type": "string"
|
||||
},
|
||||
"retries": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["message", "retries"]
|
||||
|
|
@ -8083,7 +8109,9 @@
|
|||
"type": "string"
|
||||
},
|
||||
"statusCode": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"isRetryable": {
|
||||
"type": "boolean"
|
||||
|
|
@ -8420,13 +8448,17 @@
|
|||
"const": "retry"
|
||||
},
|
||||
"attempt": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"next": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["type", "attempt", "message", "next"]
|
||||
|
|
@ -8591,7 +8623,9 @@
|
|||
},
|
||||
"duration": {
|
||||
"description": "Duration in milliseconds",
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"exclusiveMinimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["message", "variant"]
|
||||
|
|
@ -8777,7 +8811,9 @@
|
|||
"enum": ["running", "exited"]
|
||||
},
|
||||
"pid": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"exclusiveMinimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["id", "title", "command", "args", "cwd", "status", "pid"]
|
||||
|
|
@ -8835,7 +8871,9 @@
|
|||
"pattern": "^pty.*"
|
||||
},
|
||||
"exitCode": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["id", "exitCode"]
|
||||
|
|
@ -9024,7 +9062,9 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["created"]
|
||||
|
|
@ -9102,10 +9142,14 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"completed": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["created"]
|
||||
|
|
@ -9173,25 +9217,37 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"total": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"input": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"output": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"reasoning": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"cache": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"read": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"write": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["read", "write"]
|
||||
|
|
@ -9311,10 +9367,14 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"start": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"end": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["start"]
|
||||
|
|
@ -9408,10 +9468,14 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"start": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"end": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["start"]
|
||||
|
|
@ -9427,12 +9491,12 @@
|
|||
},
|
||||
"start": {
|
||||
"type": "integer",
|
||||
"minimum": -9007199254740991,
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"end": {
|
||||
"type": "integer",
|
||||
"minimum": -9007199254740991,
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
|
|
@ -9461,10 +9525,14 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"line": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"character": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["line", "character"]
|
||||
|
|
@ -9473,10 +9541,14 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"line": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"character": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["line", "character"]
|
||||
|
|
@ -9505,7 +9577,7 @@
|
|||
},
|
||||
"kind": {
|
||||
"type": "integer",
|
||||
"minimum": -9007199254740991,
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
|
|
@ -9625,7 +9697,9 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"start": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["start"]
|
||||
|
|
@ -9664,13 +9738,19 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"start": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"end": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"compacted": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["start", "end"]
|
||||
|
|
@ -9712,10 +9792,14 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"start": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"end": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["start", "end"]
|
||||
|
|
@ -9834,25 +9918,37 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"total": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"input": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"output": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"reasoning": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"cache": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"read": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"write": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["read", "write"]
|
||||
|
|
@ -9949,12 +10045,12 @@
|
|||
},
|
||||
"start": {
|
||||
"type": "integer",
|
||||
"minimum": -9007199254740991,
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"end": {
|
||||
"type": "integer",
|
||||
"minimum": -9007199254740991,
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
|
|
@ -9983,7 +10079,9 @@
|
|||
"const": "retry"
|
||||
},
|
||||
"attempt": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"error": {
|
||||
"$ref": "#/components/schemas/APIError"
|
||||
|
|
@ -9992,7 +10090,9 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["created"]
|
||||
|
|
@ -10090,7 +10190,9 @@
|
|||
"$ref": "#/components/schemas/Part"
|
||||
},
|
||||
"time": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["sessionID", "part", "time"]
|
||||
|
|
@ -10182,13 +10284,19 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"additions": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"deletions": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"files": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"diffs": {
|
||||
"type": "array",
|
||||
|
|
@ -10218,16 +10326,24 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"updated": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"compacting": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"archived": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["created", "updated"]
|
||||
|
|
@ -10434,7 +10550,9 @@
|
|||
"$ref": "#/components/schemas/Part"
|
||||
},
|
||||
"time": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["sessionID", "part", "time"]
|
||||
|
|
@ -10631,13 +10749,19 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"additions": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"deletions": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"files": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"diffs": {
|
||||
"type": "array",
|
||||
|
|
@ -10694,7 +10818,9 @@
|
|||
"created": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
|
|
@ -10704,7 +10830,9 @@
|
|||
"updated": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
|
|
@ -10714,7 +10842,9 @@
|
|||
"compacting": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
|
|
@ -10724,7 +10854,9 @@
|
|||
"archived": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
|
|
@ -11481,7 +11613,9 @@
|
|||
},
|
||||
"timeout": {
|
||||
"description": "Timeout in ms for MCP server requests. Defaults to 5000 (5 seconds) if not specified.",
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"exclusiveMinimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["type", "command"]
|
||||
|
|
@ -11547,7 +11681,9 @@
|
|||
},
|
||||
"timeout": {
|
||||
"description": "Timeout in ms for MCP server requests. Defaults to 5000 (5 seconds) if not specified.",
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"exclusiveMinimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["type", "url"]
|
||||
|
|
@ -12055,7 +12191,9 @@
|
|||
"type": "string"
|
||||
},
|
||||
"expires": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"accountId": {
|
||||
"type": "string"
|
||||
|
|
@ -12458,7 +12596,9 @@
|
|||
"type": "string"
|
||||
},
|
||||
"switchableOrgCount": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["consoleManagedProviders", "switchableOrgCount"]
|
||||
|
|
@ -12579,13 +12719,19 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"additions": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"deletions": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"files": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"diffs": {
|
||||
"type": "array",
|
||||
|
|
@ -12615,16 +12761,24 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"created": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"updated": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"compacting": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"archived": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["created", "updated"]
|
||||
|
|
@ -12710,10 +12864,14 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"start": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"end": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
"required": ["start"]
|
||||
|
|
@ -12776,12 +12934,12 @@
|
|||
},
|
||||
"start": {
|
||||
"type": "integer",
|
||||
"minimum": -9007199254740991,
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"end": {
|
||||
"type": "integer",
|
||||
"minimum": -9007199254740991,
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
}
|
||||
},
|
||||
|
|
@ -12956,7 +13114,9 @@
|
|||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"location": {
|
||||
"type": "object",
|
||||
|
|
@ -13029,16 +13189,24 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"oldStart": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"oldLines": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"newStart": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"newLines": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"lines": {
|
||||
"type": "array",
|
||||
|
|
@ -13074,12 +13242,12 @@
|
|||
},
|
||||
"added": {
|
||||
"type": "integer",
|
||||
"minimum": -9007199254740991,
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"removed": {
|
||||
"type": "integer",
|
||||
"minimum": -9007199254740991,
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"status": {
|
||||
|
|
@ -13360,10 +13528,14 @@
|
|||
"type": "string"
|
||||
},
|
||||
"additions": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"deletions": {
|
||||
"type": "number"
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 9007199254740991
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue