@opencode-ai/protocol 0.0.0-next-14661
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.d.ts +44 -0
- package/dist/api.js +61 -0
- package/dist/client.d.ts +69 -0
- package/dist/client.js +52 -0
- package/dist/errors.d.ts +97 -0
- package/dist/errors.js +74 -0
- package/dist/groups/agent.d.ts +91 -0
- package/dist/groups/agent.js +15 -0
- package/dist/groups/command.d.ts +51 -0
- package/dist/groups/command.js +20 -0
- package/dist/groups/credential.d.ts +23 -0
- package/dist/groups/credential.js +28 -0
- package/dist/groups/event.d.ts +16086 -0
- package/dist/groups/event.js +42 -0
- package/dist/groups/fs.d.ts +35 -0
- package/dist/groups/fs.js +51 -0
- package/dist/groups/generate.d.ts +32 -0
- package/dist/groups/generate.js +27 -0
- package/dist/groups/health.d.ts +5 -0
- package/dist/groups/health.js +9 -0
- package/dist/groups/integration.d.ts +105 -0
- package/dist/groups/integration.js +98 -0
- package/dist/groups/location.d.ts +16 -0
- package/dist/groups/location.js +32 -0
- package/dist/groups/mcp.d.ts +30 -0
- package/dist/groups/mcp.js +17 -0
- package/dist/groups/message.d.ts +409 -0
- package/dist/groups/message.js +37 -0
- package/dist/groups/model.d.ts +151 -0
- package/dist/groups/model.js +22 -0
- package/dist/groups/permission.d.ts +153 -0
- package/dist/groups/permission.js +99 -0
- package/dist/groups/plugin.d.ts +14 -0
- package/dist/groups/plugin.js +20 -0
- package/dist/groups/project-copy.d.ts +49 -0
- package/dist/groups/project-copy.js +44 -0
- package/dist/groups/project.d.ts +24 -0
- package/dist/groups/project.js +30 -0
- package/dist/groups/provider.d.ts +156 -0
- package/dist/groups/provider.js +34 -0
- package/dist/groups/pty.d.ts +145 -0
- package/dist/groups/pty.js +111 -0
- package/dist/groups/question.d.ts +92 -0
- package/dist/groups/question.js +56 -0
- package/dist/groups/reference.d.ts +13 -0
- package/dist/groups/reference.js +20 -0
- package/dist/groups/session.d.ts +8020 -0
- package/dist/groups/session.js +331 -0
- package/dist/groups/shell.d.ts +120 -0
- package/dist/groups/shell.js +65 -0
- package/dist/groups/skill.d.ts +19 -0
- package/dist/groups/skill.js +20 -0
- package/dist/middleware/authorization.d.ts +13 -0
- package/dist/middleware/authorization.js +6 -0
- package/dist/middleware/schema-error.d.ts +13 -0
- package/dist/middleware/schema-error.js +4 -0
- package/package.json +38 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { Location } from "@opencode-ai/schema/location";
|
|
2
|
+
import { Schema } from "effect";
|
|
3
|
+
import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/unstable/httpapi";
|
|
4
|
+
import { ForbiddenError, PtyNotFoundError } from "../errors.js";
|
|
5
|
+
export declare const PTY_CONNECT_TICKET_QUERY = "ticket";
|
|
6
|
+
export declare const PTY_CONNECT_TOKEN_HEADER = "x-opencode-ticket";
|
|
7
|
+
export declare const PTY_CONNECT_TOKEN_HEADER_VALUE = "1";
|
|
8
|
+
export declare function hasPtyConnectTicketURL(url: URL): boolean;
|
|
9
|
+
export declare const PtyGroup: HttpApiGroup.HttpApiGroup<"server.pty", HttpApiEndpoint.HttpApiEndpoint<"pty.list", "GET", "/api/pty", HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
10
|
+
readonly location: Schema.optional<Schema.Struct<{
|
|
11
|
+
readonly directory: Schema.optional<Schema.String>;
|
|
12
|
+
readonly workspace: Schema.optional<Schema.String>;
|
|
13
|
+
}>>;
|
|
14
|
+
}>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
15
|
+
readonly location: typeof Location.Info;
|
|
16
|
+
readonly data: Schema.$Array<Schema.Struct<{
|
|
17
|
+
readonly id: Schema.brand<Schema.String, "PtyID"> & {
|
|
18
|
+
create: () => string & import("effect/Brand").Brand<"PtyID">;
|
|
19
|
+
ascending: (id?: string) => string & import("effect/Brand").Brand<"PtyID">;
|
|
20
|
+
};
|
|
21
|
+
readonly title: Schema.String;
|
|
22
|
+
readonly command: Schema.String;
|
|
23
|
+
readonly args: Schema.$Array<Schema.String>;
|
|
24
|
+
readonly cwd: Schema.String;
|
|
25
|
+
readonly status: Schema.Literals<readonly ["running", "exited"]>;
|
|
26
|
+
readonly pid: Schema.Int;
|
|
27
|
+
readonly exitCode: Schema.decodeTo<Schema.optional<Schema.toType<Schema.Int>>, Schema.optionalKey<Schema.Int>, never, never>;
|
|
28
|
+
}>>;
|
|
29
|
+
}>>, HttpApiEndpoint.Json<never>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"pty.create", "POST", "/api/pty", HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
30
|
+
readonly location: Schema.optional<Schema.Struct<{
|
|
31
|
+
readonly directory: Schema.optional<Schema.String>;
|
|
32
|
+
readonly workspace: Schema.optional<Schema.String>;
|
|
33
|
+
}>>;
|
|
34
|
+
}>>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
35
|
+
readonly command: Schema.decodeTo<Schema.optional<Schema.toType<Schema.String>>, Schema.optionalKey<Schema.String>, never, never>;
|
|
36
|
+
readonly args: Schema.decodeTo<Schema.optional<Schema.toType<Schema.$Array<Schema.String>>>, Schema.optionalKey<Schema.$Array<Schema.String>>, never, never>;
|
|
37
|
+
readonly cwd: Schema.decodeTo<Schema.optional<Schema.toType<Schema.String>>, Schema.optionalKey<Schema.String>, never, never>;
|
|
38
|
+
readonly title: Schema.decodeTo<Schema.optional<Schema.toType<Schema.String>>, Schema.optionalKey<Schema.String>, never, never>;
|
|
39
|
+
readonly env: Schema.decodeTo<Schema.optional<Schema.toType<Schema.$Record<Schema.String, Schema.String>>>, Schema.optionalKey<Schema.$Record<Schema.String, Schema.String>>, never, never>;
|
|
40
|
+
}>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
41
|
+
readonly location: typeof Location.Info;
|
|
42
|
+
readonly data: Schema.Struct<{
|
|
43
|
+
readonly id: Schema.brand<Schema.String, "PtyID"> & {
|
|
44
|
+
create: () => string & import("effect/Brand").Brand<"PtyID">;
|
|
45
|
+
ascending: (id?: string) => string & import("effect/Brand").Brand<"PtyID">;
|
|
46
|
+
};
|
|
47
|
+
readonly title: Schema.String;
|
|
48
|
+
readonly command: Schema.String;
|
|
49
|
+
readonly args: Schema.$Array<Schema.String>;
|
|
50
|
+
readonly cwd: Schema.String;
|
|
51
|
+
readonly status: Schema.Literals<readonly ["running", "exited"]>;
|
|
52
|
+
readonly pid: Schema.Int;
|
|
53
|
+
readonly exitCode: Schema.decodeTo<Schema.optional<Schema.toType<Schema.Int>>, Schema.optionalKey<Schema.Int>, never, never>;
|
|
54
|
+
}>;
|
|
55
|
+
}>>, HttpApiEndpoint.Json<never>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"pty.get", "GET", "/api/pty/:ptyID", HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
56
|
+
ptyID: Schema.brand<Schema.String, "PtyID"> & {
|
|
57
|
+
create: () => string & import("effect/Brand").Brand<"PtyID">;
|
|
58
|
+
ascending: (id?: string) => string & import("effect/Brand").Brand<"PtyID">;
|
|
59
|
+
};
|
|
60
|
+
}>>, HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
61
|
+
readonly location: Schema.optional<Schema.Struct<{
|
|
62
|
+
readonly directory: Schema.optional<Schema.String>;
|
|
63
|
+
readonly workspace: Schema.optional<Schema.String>;
|
|
64
|
+
}>>;
|
|
65
|
+
}>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
66
|
+
readonly location: typeof Location.Info;
|
|
67
|
+
readonly data: Schema.Struct<{
|
|
68
|
+
readonly id: Schema.brand<Schema.String, "PtyID"> & {
|
|
69
|
+
create: () => string & import("effect/Brand").Brand<"PtyID">;
|
|
70
|
+
ascending: (id?: string) => string & import("effect/Brand").Brand<"PtyID">;
|
|
71
|
+
};
|
|
72
|
+
readonly title: Schema.String;
|
|
73
|
+
readonly command: Schema.String;
|
|
74
|
+
readonly args: Schema.$Array<Schema.String>;
|
|
75
|
+
readonly cwd: Schema.String;
|
|
76
|
+
readonly status: Schema.Literals<readonly ["running", "exited"]>;
|
|
77
|
+
readonly pid: Schema.Int;
|
|
78
|
+
readonly exitCode: Schema.decodeTo<Schema.optional<Schema.toType<Schema.Int>>, Schema.optionalKey<Schema.Int>, never, never>;
|
|
79
|
+
}>;
|
|
80
|
+
}>>, HttpApiEndpoint.Json<typeof PtyNotFoundError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"pty.update", "PUT", "/api/pty/:ptyID", HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
81
|
+
ptyID: Schema.brand<Schema.String, "PtyID"> & {
|
|
82
|
+
create: () => string & import("effect/Brand").Brand<"PtyID">;
|
|
83
|
+
ascending: (id?: string) => string & import("effect/Brand").Brand<"PtyID">;
|
|
84
|
+
};
|
|
85
|
+
}>>, HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
86
|
+
readonly location: Schema.optional<Schema.Struct<{
|
|
87
|
+
readonly directory: Schema.optional<Schema.String>;
|
|
88
|
+
readonly workspace: Schema.optional<Schema.String>;
|
|
89
|
+
}>>;
|
|
90
|
+
}>>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
91
|
+
readonly title: Schema.decodeTo<Schema.optional<Schema.toType<Schema.String>>, Schema.optionalKey<Schema.String>, never, never>;
|
|
92
|
+
readonly size: Schema.decodeTo<Schema.optional<Schema.toType<Schema.Struct<{
|
|
93
|
+
readonly rows: Schema.Int;
|
|
94
|
+
readonly cols: Schema.Int;
|
|
95
|
+
}>>>, Schema.optionalKey<Schema.Struct<{
|
|
96
|
+
readonly rows: Schema.Int;
|
|
97
|
+
readonly cols: Schema.Int;
|
|
98
|
+
}>>, never, never>;
|
|
99
|
+
}>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
100
|
+
readonly location: typeof Location.Info;
|
|
101
|
+
readonly data: Schema.Struct<{
|
|
102
|
+
readonly id: Schema.brand<Schema.String, "PtyID"> & {
|
|
103
|
+
create: () => string & import("effect/Brand").Brand<"PtyID">;
|
|
104
|
+
ascending: (id?: string) => string & import("effect/Brand").Brand<"PtyID">;
|
|
105
|
+
};
|
|
106
|
+
readonly title: Schema.String;
|
|
107
|
+
readonly command: Schema.String;
|
|
108
|
+
readonly args: Schema.$Array<Schema.String>;
|
|
109
|
+
readonly cwd: Schema.String;
|
|
110
|
+
readonly status: Schema.Literals<readonly ["running", "exited"]>;
|
|
111
|
+
readonly pid: Schema.Int;
|
|
112
|
+
readonly exitCode: Schema.decodeTo<Schema.optional<Schema.toType<Schema.Int>>, Schema.optionalKey<Schema.Int>, never, never>;
|
|
113
|
+
}>;
|
|
114
|
+
}>>, HttpApiEndpoint.Json<typeof PtyNotFoundError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"pty.remove", "DELETE", "/api/pty/:ptyID", HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
115
|
+
ptyID: Schema.brand<Schema.String, "PtyID"> & {
|
|
116
|
+
create: () => string & import("effect/Brand").Brand<"PtyID">;
|
|
117
|
+
ascending: (id?: string) => string & import("effect/Brand").Brand<"PtyID">;
|
|
118
|
+
};
|
|
119
|
+
}>>, HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
120
|
+
readonly location: Schema.optional<Schema.Struct<{
|
|
121
|
+
readonly directory: Schema.optional<Schema.String>;
|
|
122
|
+
readonly workspace: Schema.optional<Schema.String>;
|
|
123
|
+
}>>;
|
|
124
|
+
}>>, HttpApiEndpoint.Json<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<HttpApiSchema.NoContent>, HttpApiEndpoint.Json<typeof PtyNotFoundError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"pty.connectToken", "POST", "/api/pty/:ptyID/connect-token", HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
125
|
+
ptyID: Schema.brand<Schema.String, "PtyID"> & {
|
|
126
|
+
create: () => string & import("effect/Brand").Brand<"PtyID">;
|
|
127
|
+
ascending: (id?: string) => string & import("effect/Brand").Brand<"PtyID">;
|
|
128
|
+
};
|
|
129
|
+
}>>, HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
130
|
+
readonly location: Schema.optional<Schema.Struct<{
|
|
131
|
+
readonly directory: Schema.optional<Schema.String>;
|
|
132
|
+
readonly workspace: Schema.optional<Schema.String>;
|
|
133
|
+
}>>;
|
|
134
|
+
}>>, HttpApiEndpoint.Json<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
135
|
+
readonly location: typeof Location.Info;
|
|
136
|
+
readonly data: Schema.Struct<{
|
|
137
|
+
readonly ticket: Schema.String;
|
|
138
|
+
readonly expires_in: Schema.Int;
|
|
139
|
+
}>;
|
|
140
|
+
}>>, HttpApiEndpoint.Json<typeof ForbiddenError | typeof PtyNotFoundError>, never, never> | HttpApiEndpoint.HttpApiEndpoint<"pty.connect", "GET", "/api/pty/:ptyID/connect", HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
141
|
+
ptyID: Schema.brand<Schema.String, "PtyID"> & {
|
|
142
|
+
create: () => string & import("effect/Brand").Brand<"PtyID">;
|
|
143
|
+
ascending: (id?: string) => string & import("effect/Brand").Brand<"PtyID">;
|
|
144
|
+
};
|
|
145
|
+
}>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Boolean>, HttpApiEndpoint.Json<typeof ForbiddenError | typeof PtyNotFoundError>, never, never>, false>;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Pty } from "@opencode-ai/schema/pty";
|
|
2
|
+
import { PtyTicket } from "@opencode-ai/schema/pty-ticket";
|
|
3
|
+
import { Location } from "@opencode-ai/schema/location";
|
|
4
|
+
import { Schema } from "effect";
|
|
5
|
+
import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi";
|
|
6
|
+
import { ForbiddenError, PtyNotFoundError } from "../errors.js";
|
|
7
|
+
import { LocationQuery, locationQueryOpenApi } from "./location.js";
|
|
8
|
+
export const PTY_CONNECT_TICKET_QUERY = "ticket";
|
|
9
|
+
export const PTY_CONNECT_TOKEN_HEADER = "x-opencode-ticket";
|
|
10
|
+
export const PTY_CONNECT_TOKEN_HEADER_VALUE = "1";
|
|
11
|
+
const PTY_CONNECT_PATH = /^\/api\/pty\/[^/]+\/connect$/;
|
|
12
|
+
// Authorization middleware skips credential checks when this matches; the PTY connect handler
|
|
13
|
+
// is then responsible for consuming and validating the ticket.
|
|
14
|
+
export function hasPtyConnectTicketURL(url) {
|
|
15
|
+
return PTY_CONNECT_PATH.test(url.pathname) && !!url.searchParams.get(PTY_CONNECT_TICKET_QUERY);
|
|
16
|
+
}
|
|
17
|
+
export const PtyGroup = HttpApiGroup.make("server.pty")
|
|
18
|
+
.add(HttpApiEndpoint.get("pty.list", "/api/pty", {
|
|
19
|
+
query: LocationQuery,
|
|
20
|
+
success: Location.response(Schema.Array(Pty.Info)),
|
|
21
|
+
})
|
|
22
|
+
.annotateMerge(locationQueryOpenApi)
|
|
23
|
+
.annotateMerge(OpenApi.annotations({
|
|
24
|
+
identifier: "v2.pty.list",
|
|
25
|
+
summary: "List PTY sessions",
|
|
26
|
+
description: "List PTY sessions for a location, including exited sessions retained until removal.",
|
|
27
|
+
})))
|
|
28
|
+
.add(HttpApiEndpoint.post("pty.create", "/api/pty", {
|
|
29
|
+
query: LocationQuery,
|
|
30
|
+
payload: Pty.CreateInput,
|
|
31
|
+
success: Location.response(Pty.Info),
|
|
32
|
+
})
|
|
33
|
+
.annotateMerge(locationQueryOpenApi)
|
|
34
|
+
.annotateMerge(OpenApi.annotations({
|
|
35
|
+
identifier: "v2.pty.create",
|
|
36
|
+
summary: "Create PTY session",
|
|
37
|
+
description: "Create a pseudo-terminal session for a location.",
|
|
38
|
+
})))
|
|
39
|
+
.add(HttpApiEndpoint.get("pty.get", "/api/pty/:ptyID", {
|
|
40
|
+
params: { ptyID: Pty.ID },
|
|
41
|
+
query: LocationQuery,
|
|
42
|
+
success: Location.response(Pty.Info),
|
|
43
|
+
error: PtyNotFoundError,
|
|
44
|
+
})
|
|
45
|
+
.annotateMerge(locationQueryOpenApi)
|
|
46
|
+
.annotateMerge(OpenApi.annotations({
|
|
47
|
+
identifier: "v2.pty.get",
|
|
48
|
+
summary: "Get PTY session",
|
|
49
|
+
description: "Get one PTY session, including its exit code once exited.",
|
|
50
|
+
})))
|
|
51
|
+
.add(HttpApiEndpoint.put("pty.update", "/api/pty/:ptyID", {
|
|
52
|
+
params: { ptyID: Pty.ID },
|
|
53
|
+
query: LocationQuery,
|
|
54
|
+
payload: Pty.UpdateInput,
|
|
55
|
+
success: Location.response(Pty.Info),
|
|
56
|
+
error: PtyNotFoundError,
|
|
57
|
+
})
|
|
58
|
+
.annotateMerge(locationQueryOpenApi)
|
|
59
|
+
.annotateMerge(OpenApi.annotations({
|
|
60
|
+
identifier: "v2.pty.update",
|
|
61
|
+
summary: "Update PTY session",
|
|
62
|
+
description: "Update the title or viewport size of one PTY session.",
|
|
63
|
+
})))
|
|
64
|
+
.add(HttpApiEndpoint.delete("pty.remove", "/api/pty/:ptyID", {
|
|
65
|
+
params: { ptyID: Pty.ID },
|
|
66
|
+
query: LocationQuery,
|
|
67
|
+
success: HttpApiSchema.NoContent,
|
|
68
|
+
error: PtyNotFoundError,
|
|
69
|
+
})
|
|
70
|
+
.annotateMerge(locationQueryOpenApi)
|
|
71
|
+
.annotateMerge(OpenApi.annotations({
|
|
72
|
+
identifier: "v2.pty.remove",
|
|
73
|
+
summary: "Remove PTY session",
|
|
74
|
+
description: "Terminate and remove one PTY session.",
|
|
75
|
+
})))
|
|
76
|
+
.add(HttpApiEndpoint.post("pty.connectToken", "/api/pty/:ptyID/connect-token", {
|
|
77
|
+
params: { ptyID: Pty.ID },
|
|
78
|
+
query: LocationQuery,
|
|
79
|
+
success: Location.response(PtyTicket.ConnectToken),
|
|
80
|
+
error: [ForbiddenError, PtyNotFoundError],
|
|
81
|
+
})
|
|
82
|
+
.annotateMerge(locationQueryOpenApi)
|
|
83
|
+
.annotateMerge(OpenApi.annotations({
|
|
84
|
+
identifier: "v2.pty.connectToken",
|
|
85
|
+
summary: "Create PTY WebSocket token",
|
|
86
|
+
description: "Create a short-lived single-use ticket for opening a PTY WebSocket connection.",
|
|
87
|
+
})))
|
|
88
|
+
.add(
|
|
89
|
+
// Query fields are decoded in the raw handler after the existence check so a missing
|
|
90
|
+
// session responds with an empty 404 before any upgrade work.
|
|
91
|
+
HttpApiEndpoint.get("pty.connect", "/api/pty/:ptyID/connect", {
|
|
92
|
+
params: { ptyID: Pty.ID },
|
|
93
|
+
success: Schema.Boolean,
|
|
94
|
+
error: [ForbiddenError, PtyNotFoundError],
|
|
95
|
+
}).annotateMerge(OpenApi.annotations({
|
|
96
|
+
identifier: "v2.pty.connect",
|
|
97
|
+
summary: "Connect to PTY session",
|
|
98
|
+
description: "Establish a WebSocket connection streaming PTY output and accepting terminal input.",
|
|
99
|
+
transform: (operation) => ({
|
|
100
|
+
...operation,
|
|
101
|
+
parameters: [
|
|
102
|
+
...(operation.parameters ?? []),
|
|
103
|
+
...["location[directory]", "location[workspace]", "cursor", PTY_CONNECT_TICKET_QUERY].map((name) => ({
|
|
104
|
+
in: "query",
|
|
105
|
+
name,
|
|
106
|
+
schema: { type: "string" },
|
|
107
|
+
})),
|
|
108
|
+
],
|
|
109
|
+
}),
|
|
110
|
+
})))
|
|
111
|
+
.annotateMerge(OpenApi.annotations({ title: "pty", description: "Experimental location-scoped PTY routes." }));
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Location } from "@opencode-ai/schema/location";
|
|
2
|
+
import { Context, Schema } from "effect";
|
|
3
|
+
import { HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema } from "effect/unstable/httpapi";
|
|
4
|
+
import { QuestionNotFoundError, SessionNotFoundError } from "../errors.js";
|
|
5
|
+
export declare const makeQuestionGroup: <LocationId extends HttpApiMiddleware.AnyId, LocationService, SessionLocationId extends HttpApiMiddleware.AnyId, SessionLocationService>(locationMiddleware: Context.Key<LocationId, LocationService>, sessionLocationMiddleware: Context.Key<SessionLocationId, SessionLocationService>) => HttpApiGroup.HttpApiGroup<"server.question", HttpApiEndpoint.HttpApiEndpoint<"question.request.list", "GET", "/api/question/request", HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
6
|
+
readonly location: Schema.optional<Schema.Struct<{
|
|
7
|
+
readonly directory: Schema.optional<Schema.String>;
|
|
8
|
+
readonly workspace: Schema.optional<Schema.String>;
|
|
9
|
+
}>>;
|
|
10
|
+
}>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
11
|
+
readonly location: typeof Location.Info;
|
|
12
|
+
readonly data: Schema.$Array<Schema.Struct<{
|
|
13
|
+
readonly id: Schema.brand<Schema.String, "QuestionV2.ID"> & {
|
|
14
|
+
create: () => string & import("effect/Brand").Brand<"QuestionV2.ID">;
|
|
15
|
+
ascending: (id?: string) => string & import("effect/Brand").Brand<"QuestionV2.ID">;
|
|
16
|
+
};
|
|
17
|
+
readonly sessionID: Schema.brand<Schema.String, "SessionID"> & {
|
|
18
|
+
create: () => string & import("effect/Brand").Brand<"SessionID">;
|
|
19
|
+
descending: (id?: string) => string & import("effect/Brand").Brand<"SessionID">;
|
|
20
|
+
};
|
|
21
|
+
readonly questions: Schema.$Array<Schema.Struct<{
|
|
22
|
+
readonly custom: Schema.decodeTo<Schema.optional<Schema.toType<Schema.Boolean>>, Schema.optionalKey<Schema.Boolean>, never, never>;
|
|
23
|
+
readonly question: Schema.String;
|
|
24
|
+
readonly header: Schema.String;
|
|
25
|
+
readonly options: Schema.$Array<Schema.Struct<{
|
|
26
|
+
readonly label: Schema.String;
|
|
27
|
+
readonly description: Schema.String;
|
|
28
|
+
}>>;
|
|
29
|
+
readonly multiple: Schema.decodeTo<Schema.optional<Schema.toType<Schema.Boolean>>, Schema.optionalKey<Schema.Boolean>, never, never>;
|
|
30
|
+
}>>;
|
|
31
|
+
readonly tool: Schema.decodeTo<Schema.optional<Schema.toType<Schema.Struct<{
|
|
32
|
+
readonly messageID: Schema.String;
|
|
33
|
+
readonly callID: Schema.String;
|
|
34
|
+
}>>>, Schema.optionalKey<Schema.Struct<{
|
|
35
|
+
readonly messageID: Schema.String;
|
|
36
|
+
readonly callID: Schema.String;
|
|
37
|
+
}>>, never, never>;
|
|
38
|
+
}>>;
|
|
39
|
+
}>>, HttpApiEndpoint.Json<never>, LocationId, HttpApiMiddleware.Requires<LocationId>> | HttpApiEndpoint.HttpApiEndpoint<"session.question.list", "GET", "/api/session/:sessionID/question", HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
40
|
+
sessionID: Schema.brand<Schema.String, "SessionID"> & {
|
|
41
|
+
create: () => string & import("effect/Brand").Brand<"SessionID">;
|
|
42
|
+
descending: (id?: string) => string & import("effect/Brand").Brand<"SessionID">;
|
|
43
|
+
};
|
|
44
|
+
}>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
45
|
+
readonly data: Schema.$Array<Schema.Struct<{
|
|
46
|
+
readonly id: Schema.brand<Schema.String, "QuestionV2.ID"> & {
|
|
47
|
+
create: () => string & import("effect/Brand").Brand<"QuestionV2.ID">;
|
|
48
|
+
ascending: (id?: string) => string & import("effect/Brand").Brand<"QuestionV2.ID">;
|
|
49
|
+
};
|
|
50
|
+
readonly sessionID: Schema.brand<Schema.String, "SessionID"> & {
|
|
51
|
+
create: () => string & import("effect/Brand").Brand<"SessionID">;
|
|
52
|
+
descending: (id?: string) => string & import("effect/Brand").Brand<"SessionID">;
|
|
53
|
+
};
|
|
54
|
+
readonly questions: Schema.$Array<Schema.Struct<{
|
|
55
|
+
readonly custom: Schema.decodeTo<Schema.optional<Schema.toType<Schema.Boolean>>, Schema.optionalKey<Schema.Boolean>, never, never>;
|
|
56
|
+
readonly question: Schema.String;
|
|
57
|
+
readonly header: Schema.String;
|
|
58
|
+
readonly options: Schema.$Array<Schema.Struct<{
|
|
59
|
+
readonly label: Schema.String;
|
|
60
|
+
readonly description: Schema.String;
|
|
61
|
+
}>>;
|
|
62
|
+
readonly multiple: Schema.decodeTo<Schema.optional<Schema.toType<Schema.Boolean>>, Schema.optionalKey<Schema.Boolean>, never, never>;
|
|
63
|
+
}>>;
|
|
64
|
+
readonly tool: Schema.decodeTo<Schema.optional<Schema.toType<Schema.Struct<{
|
|
65
|
+
readonly messageID: Schema.String;
|
|
66
|
+
readonly callID: Schema.String;
|
|
67
|
+
}>>>, Schema.optionalKey<Schema.Struct<{
|
|
68
|
+
readonly messageID: Schema.String;
|
|
69
|
+
readonly callID: Schema.String;
|
|
70
|
+
}>>, never, never>;
|
|
71
|
+
}>>;
|
|
72
|
+
}>>, HttpApiEndpoint.Json<typeof SessionNotFoundError>, SessionLocationId, HttpApiMiddleware.Requires<SessionLocationId>> | HttpApiEndpoint.HttpApiEndpoint<"session.question.reply", "POST", "/api/session/:sessionID/question/:requestID/reply", HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
73
|
+
sessionID: Schema.brand<Schema.String, "SessionID"> & {
|
|
74
|
+
create: () => string & import("effect/Brand").Brand<"SessionID">;
|
|
75
|
+
descending: (id?: string) => string & import("effect/Brand").Brand<"SessionID">;
|
|
76
|
+
};
|
|
77
|
+
requestID: Schema.brand<Schema.String, "QuestionV2.ID"> & {
|
|
78
|
+
create: () => string & import("effect/Brand").Brand<"QuestionV2.ID">;
|
|
79
|
+
ascending: (id?: string) => string & import("effect/Brand").Brand<"QuestionV2.ID">;
|
|
80
|
+
};
|
|
81
|
+
}>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
82
|
+
readonly answers: Schema.$Array<Schema.$Array<Schema.String>>;
|
|
83
|
+
}>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<HttpApiSchema.NoContent>, HttpApiEndpoint.Json<typeof SessionNotFoundError | typeof QuestionNotFoundError>, SessionLocationId, HttpApiMiddleware.Requires<SessionLocationId>> | HttpApiEndpoint.HttpApiEndpoint<"session.question.reject", "POST", "/api/session/:sessionID/question/:requestID/reject", HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
84
|
+
sessionID: Schema.brand<Schema.String, "SessionID"> & {
|
|
85
|
+
create: () => string & import("effect/Brand").Brand<"SessionID">;
|
|
86
|
+
descending: (id?: string) => string & import("effect/Brand").Brand<"SessionID">;
|
|
87
|
+
};
|
|
88
|
+
requestID: Schema.brand<Schema.String, "QuestionV2.ID"> & {
|
|
89
|
+
create: () => string & import("effect/Brand").Brand<"QuestionV2.ID">;
|
|
90
|
+
ascending: (id?: string) => string & import("effect/Brand").Brand<"QuestionV2.ID">;
|
|
91
|
+
};
|
|
92
|
+
}>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<HttpApiSchema.NoContent>, HttpApiEndpoint.Json<typeof SessionNotFoundError | typeof QuestionNotFoundError>, SessionLocationId, HttpApiMiddleware.Requires<SessionLocationId>>, false>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Question } from "@opencode-ai/schema/question";
|
|
2
|
+
import { Location } from "@opencode-ai/schema/location";
|
|
3
|
+
import { Session } from "@opencode-ai/schema/session";
|
|
4
|
+
import { Context, Schema } from "effect";
|
|
5
|
+
import { HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, OpenApi } from "effect/unstable/httpapi";
|
|
6
|
+
import { QuestionNotFoundError, SessionNotFoundError } from "../errors.js";
|
|
7
|
+
import { LocationQuery, locationQueryOpenApi } from "./location.js";
|
|
8
|
+
export const makeQuestionGroup = (locationMiddleware, sessionLocationMiddleware) => HttpApiGroup.make("server.question")
|
|
9
|
+
.add(HttpApiEndpoint.get("question.request.list", "/api/question/request", {
|
|
10
|
+
query: LocationQuery,
|
|
11
|
+
success: Location.response(Schema.Array(Question.Request)),
|
|
12
|
+
})
|
|
13
|
+
.annotateMerge(locationQueryOpenApi)
|
|
14
|
+
.annotateMerge(OpenApi.annotations({
|
|
15
|
+
identifier: "v2.question.request.list",
|
|
16
|
+
summary: "List pending question requests",
|
|
17
|
+
description: "Retrieve pending question requests for a location.",
|
|
18
|
+
})))
|
|
19
|
+
.annotateMerge(OpenApi.annotations({ title: "questions", description: "Experimental question routes." }))
|
|
20
|
+
// Effect applies group middleware only to endpoints already added; session endpoints use session placement below.
|
|
21
|
+
.middleware(locationMiddleware)
|
|
22
|
+
.add(HttpApiEndpoint.get("session.question.list", "/api/session/:sessionID/question", {
|
|
23
|
+
params: { sessionID: Session.ID },
|
|
24
|
+
success: Schema.Struct({ data: Schema.Array(Question.Request) }),
|
|
25
|
+
error: SessionNotFoundError,
|
|
26
|
+
})
|
|
27
|
+
.middleware(sessionLocationMiddleware)
|
|
28
|
+
.annotateMerge(OpenApi.annotations({
|
|
29
|
+
identifier: "v2.session.question.list",
|
|
30
|
+
summary: "List session question requests",
|
|
31
|
+
description: "Retrieve pending question requests owned by a session.",
|
|
32
|
+
})))
|
|
33
|
+
.add(HttpApiEndpoint.post("session.question.reply", "/api/session/:sessionID/question/:requestID/reply", {
|
|
34
|
+
params: { sessionID: Session.ID, requestID: Question.ID },
|
|
35
|
+
payload: Question.Reply,
|
|
36
|
+
success: HttpApiSchema.NoContent,
|
|
37
|
+
error: [SessionNotFoundError, QuestionNotFoundError],
|
|
38
|
+
})
|
|
39
|
+
.middleware(sessionLocationMiddleware)
|
|
40
|
+
.annotateMerge(OpenApi.annotations({
|
|
41
|
+
identifier: "v2.session.question.reply",
|
|
42
|
+
summary: "Reply to pending question request",
|
|
43
|
+
description: "Answer a pending question request owned by a session.",
|
|
44
|
+
})))
|
|
45
|
+
.add(HttpApiEndpoint.post("session.question.reject", "/api/session/:sessionID/question/:requestID/reject", {
|
|
46
|
+
params: { sessionID: Session.ID, requestID: Question.ID },
|
|
47
|
+
success: HttpApiSchema.NoContent,
|
|
48
|
+
error: [SessionNotFoundError, QuestionNotFoundError],
|
|
49
|
+
})
|
|
50
|
+
.middleware(sessionLocationMiddleware)
|
|
51
|
+
.annotateMerge(OpenApi.annotations({
|
|
52
|
+
identifier: "v2.session.question.reject",
|
|
53
|
+
summary: "Reject pending question request",
|
|
54
|
+
description: "Reject a pending question request owned by a session.",
|
|
55
|
+
})))
|
|
56
|
+
.annotateMerge(OpenApi.annotations({ title: "session questions", description: "Experimental session question routes." }));
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Location } from "@opencode-ai/schema/location";
|
|
2
|
+
import { Reference } from "@opencode-ai/schema/reference";
|
|
3
|
+
import { Schema } from "effect";
|
|
4
|
+
import { HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi";
|
|
5
|
+
export declare const ReferenceGroup: HttpApiGroup.HttpApiGroup<"server.reference", HttpApiEndpoint.HttpApiEndpoint<"reference.list", "GET", "/api/reference", HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<Schema.Struct<{
|
|
6
|
+
readonly location: Schema.optional<Schema.Struct<{
|
|
7
|
+
readonly directory: Schema.optional<Schema.String>;
|
|
8
|
+
readonly workspace: Schema.optional<Schema.String>;
|
|
9
|
+
}>>;
|
|
10
|
+
}>>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.StringTree<never>, HttpApiEndpoint.Json<Schema.Struct<{
|
|
11
|
+
readonly location: typeof Location.Info;
|
|
12
|
+
readonly data: Schema.$Array<typeof Reference.Info>;
|
|
13
|
+
}>>, HttpApiEndpoint.Json<never>, never, never>, false>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Location } from "@opencode-ai/schema/location";
|
|
2
|
+
import { Reference } from "@opencode-ai/schema/reference";
|
|
3
|
+
import { Schema } from "effect";
|
|
4
|
+
import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi";
|
|
5
|
+
import { LocationQuery, locationQueryOpenApi } from "./location.js";
|
|
6
|
+
export const ReferenceGroup = HttpApiGroup.make("server.reference")
|
|
7
|
+
.add(HttpApiEndpoint.get("reference.list", "/api/reference", {
|
|
8
|
+
query: LocationQuery,
|
|
9
|
+
success: Location.response(Schema.Array(Reference.Info)),
|
|
10
|
+
})
|
|
11
|
+
.annotateMerge(locationQueryOpenApi)
|
|
12
|
+
.annotateMerge(OpenApi.annotations({
|
|
13
|
+
identifier: "v2.reference.list",
|
|
14
|
+
summary: "List references",
|
|
15
|
+
description: "List references available in the requested location.",
|
|
16
|
+
})))
|
|
17
|
+
.annotateMerge(OpenApi.annotations({
|
|
18
|
+
title: "reference",
|
|
19
|
+
description: "Location-scoped project references.",
|
|
20
|
+
}));
|