opencode-courier 0.3.0 → 0.4.0
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/README.md +175 -274
- package/dist/index.js +47 -73
- package/dist/kernel/protocol.d.ts +20 -0
- package/dist/kernel/protocol.js +36 -0
- package/dist/kernel/tool.d.ts +5 -0
- package/dist/kernel/tool.js +5 -0
- package/dist/person/events.d.ts +23 -0
- package/dist/person/events.js +113 -0
- package/dist/person/form.d.ts +26 -0
- package/dist/person/form.js +64 -0
- package/dist/person/index.d.ts +17 -0
- package/dist/person/index.js +5 -0
- package/dist/{relay.d.ts → person/permission.d.ts} +27 -21
- package/dist/{relay.js → person/permission.js} +9 -5
- package/dist/person/ports.d.ts +58 -0
- package/dist/person/ports.js +2 -0
- package/dist/{question → person/question}/answer.d.ts +33 -4
- package/dist/{question → person/question}/answer.js +43 -8
- package/dist/person/question/index.d.ts +7 -0
- package/dist/{question → person/question}/index.js +3 -3
- package/dist/{question → person/question}/lifecycle.d.ts +1 -1
- package/dist/{question → person/question}/pure.d.ts +1 -2
- package/dist/{question → person/question}/pure.js +1 -1
- package/dist/{question → person/question}/relay.d.ts +1 -1
- package/dist/{question → person/question}/relay.js +14 -8
- package/dist/{question → person/question}/shared.d.ts +13 -3
- package/dist/person/question/shared.js +52 -0
- package/dist/person/question/types.d.ts +121 -0
- package/dist/person/question/types.js +1 -0
- package/dist/person/rpc-handlers.d.ts +160 -0
- package/dist/person/rpc-handlers.js +62 -0
- package/dist/person/rpc.d.ts +227 -0
- package/dist/person/rpc.js +70 -0
- package/dist/person/text.d.ts +68 -0
- package/dist/person/text.js +262 -0
- package/dist/person/tools.d.ts +20 -0
- package/dist/person/tools.js +55 -0
- package/dist/person/tui.d.ts +46 -0
- package/dist/{bounded.d.ts → platform/bounded.d.ts} +4 -0
- package/dist/{bounded.js → platform/bounded.js} +4 -0
- package/dist/platform/events.d.ts +34 -0
- package/dist/platform/events.js +121 -0
- package/dist/platform/hub.d.ts +195 -0
- package/dist/{hub.js → platform/hub.js} +27 -71
- package/dist/{version.js → platform/version.js} +1 -1
- package/dist/rpc.d.ts +2 -0
- package/dist/rpc.js +3 -0
- package/dist/scheduling/index.d.ts +6 -0
- package/dist/scheduling/index.js +5 -0
- package/dist/{later.d.ts → scheduling/later.d.ts} +7 -3
- package/dist/{later.js → scheduling/later.js} +12 -4
- package/dist/scheduling/text.d.ts +6 -0
- package/dist/scheduling/text.js +10 -0
- package/dist/scheduling/tools.d.ts +14 -0
- package/dist/scheduling/tools.js +48 -0
- package/dist/skill.d.ts +4 -0
- package/dist/skill.js +54 -1
- package/dist/{cleanup.d.ts → tree/cleanup.d.ts} +1 -27
- package/dist/{cleanup.js → tree/cleanup.js} +9 -16
- package/dist/tree/context.d.ts +15 -0
- package/dist/tree/context.js +34 -0
- package/dist/tree/domain.d.ts +101 -0
- package/dist/tree/domain.js +68 -0
- package/dist/{watch.d.ts → tree/events.d.ts} +10 -37
- package/dist/tree/events.js +204 -0
- package/dist/tree/forget.d.ts +24 -0
- package/dist/tree/forget.js +59 -0
- package/dist/tree/group.d.ts +82 -0
- package/dist/tree/group.js +203 -0
- package/dist/tree/index.d.ts +10 -0
- package/dist/tree/index.js +11 -0
- package/dist/tree/limits.d.ts +10 -0
- package/dist/{limits.js → tree/limits.js} +6 -55
- package/dist/tree/panel.d.ts +13 -0
- package/dist/tree/panel.js +75 -0
- package/dist/tree/ports.d.ts +276 -0
- package/dist/tree/ports.js +1 -0
- package/dist/tree/report.d.ts +23 -0
- package/dist/tree/report.js +33 -0
- package/dist/tree/roster.d.ts +27 -0
- package/dist/tree/roster.js +62 -0
- package/dist/tree/rpc-handlers.d.ts +201 -0
- package/dist/tree/rpc-handlers.js +20 -0
- package/dist/tree/rpc.d.ts +344 -0
- package/dist/tree/rpc.js +83 -0
- package/dist/tree/send.d.ts +14 -0
- package/dist/tree/send.js +99 -0
- package/dist/tree/spawn.d.ts +21 -0
- package/dist/tree/spawn.js +173 -0
- package/dist/tree/status.d.ts +128 -0
- package/dist/tree/status.js +62 -0
- package/dist/{stop.d.ts → tree/stop.d.ts} +1 -9
- package/dist/{stop.js → tree/stop.js} +9 -13
- package/dist/tree/store.d.ts +24 -0
- package/dist/tree/store.js +264 -0
- package/dist/{tree.d.ts → tree/subtree.d.ts} +5 -6
- package/dist/{tree.js → tree/subtree.js} +7 -5
- package/dist/tree/summary.d.ts +7 -0
- package/dist/tree/summary.js +35 -0
- package/dist/tree/text.d.ts +77 -0
- package/dist/tree/text.js +287 -0
- package/dist/tree/tools.d.ts +54 -0
- package/dist/{tools.js → tree/tools.js} +12 -142
- package/dist/tree/tui.d.ts +53 -0
- package/dist/tui.d.ts +3 -0
- package/dist/tui.js +1219 -0
- package/dist/webhook/index.d.ts +5 -0
- package/dist/webhook/index.js +3 -0
- package/dist/{webhook.d.ts → webhook/receiver.d.ts} +17 -23
- package/dist/{webhook.js → webhook/receiver.js} +58 -50
- package/dist/webhook/subscriptions.d.ts +29 -0
- package/dist/webhook/subscriptions.js +52 -0
- package/dist/webhook/text.d.ts +23 -0
- package/dist/webhook/text.js +82 -0
- package/dist/webhook/tools.d.ts +19 -0
- package/dist/webhook/tools.js +46 -0
- package/package.json +18 -7
- package/dist/courier.d.ts +0 -200
- package/dist/courier.js +0 -315
- package/dist/group.d.ts +0 -86
- package/dist/group.js +0 -247
- package/dist/hub.d.ts +0 -300
- package/dist/limits.d.ts +0 -65
- package/dist/notices.d.ts +0 -356
- package/dist/notices.js +0 -678
- package/dist/question/index.d.ts +0 -6
- package/dist/question/shared.js +0 -24
- package/dist/report.d.ts +0 -48
- package/dist/report.js +0 -88
- package/dist/roster.d.ts +0 -93
- package/dist/roster.js +0 -206
- package/dist/tools.d.ts +0 -94
- package/dist/watch.js +0 -474
- /package/dist/{question → person/question}/lifecycle.js +0 -0
- /package/dist/{question → person/question}/runtime.d.ts +0 -0
- /package/dist/{question → person/question}/runtime.js +0 -0
- /package/dist/{json.d.ts → platform/json.d.ts} +0 -0
- /package/dist/{json.js → platform/json.js} +0 -0
- /package/dist/{storage.d.ts → platform/storage.d.ts} +0 -0
- /package/dist/{storage.js → platform/storage.js} +0 -0
- /package/dist/{version.d.ts → platform/version.d.ts} +0 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
/** The sessions started under a session, as the prompt footer's status entry shows them. */
|
|
3
|
+
declare const Summary: Schema.Struct<{
|
|
4
|
+
/** Running, and waiting on no request. */
|
|
5
|
+
readonly running: Schema.Int;
|
|
6
|
+
/** Waiting on a permission request or a question, which go to the person. */
|
|
7
|
+
readonly waiting: Schema.Int;
|
|
8
|
+
/** Not running: done, or waiting for a message. */
|
|
9
|
+
readonly idle: Schema.Int;
|
|
10
|
+
readonly groups: Schema.$Array<Schema.Struct<{
|
|
11
|
+
readonly name: Schema.String;
|
|
12
|
+
readonly reported: Schema.Int;
|
|
13
|
+
readonly members: Schema.Int;
|
|
14
|
+
}>>;
|
|
15
|
+
/** Set when the subtree had more sessions than `maxTotal`, which were not counted. */
|
|
16
|
+
readonly truncated: Schema.optionalKey<Schema.Int>;
|
|
17
|
+
}>;
|
|
18
|
+
export type Summary = typeof Summary.Type;
|
|
19
|
+
/** A request a session waits on until the person answers it: a permission request, or its first question. */
|
|
20
|
+
declare const Wait: Schema.Union<readonly [Schema.Struct<{
|
|
21
|
+
readonly type: Schema.Literal<"permission">;
|
|
22
|
+
readonly action: Schema.String;
|
|
23
|
+
readonly resources: Schema.$Array<Schema.String>;
|
|
24
|
+
}>, Schema.Struct<{
|
|
25
|
+
readonly type: Schema.Literal<"question">;
|
|
26
|
+
readonly question: Schema.String;
|
|
27
|
+
}>]>;
|
|
28
|
+
/** One session of the tree panel: what courier_tree shows of it, and what it is doing, in epoch milliseconds. */
|
|
29
|
+
declare const Row: Schema.Struct<{
|
|
30
|
+
readonly sessionID: Schema.String;
|
|
31
|
+
readonly parentID: Schema.String;
|
|
32
|
+
readonly title: Schema.String;
|
|
33
|
+
/** A child of the panel's session is at depth 1. */
|
|
34
|
+
readonly depth: Schema.Int;
|
|
35
|
+
/** `waiting` on a request to the person; `gone` when OpenCode no longer knows it. */
|
|
36
|
+
readonly state: Schema.Literals<readonly ["running", "waiting", "idle", "gone"]>;
|
|
37
|
+
/** How its last turn ended. */
|
|
38
|
+
readonly outcome: Schema.optionalKey<Schema.Literals<readonly ["succeeded", "failed", "interrupted"]>>;
|
|
39
|
+
/** Its report since its last prompt: still owed, arrived (held with its group or delivered), or its turn ended without one. */
|
|
40
|
+
readonly report: Schema.optionalKey<Schema.Struct<{
|
|
41
|
+
readonly state: Schema.Literals<readonly ["owed", "reported", "ended"]>;
|
|
42
|
+
readonly status: Schema.optionalKey<Schema.String>;
|
|
43
|
+
readonly progressed: Schema.Boolean;
|
|
44
|
+
}>>;
|
|
45
|
+
/** Its join group, and its standing there: `held`, `out`, how it left, or `released`. */
|
|
46
|
+
readonly group: Schema.optionalKey<Schema.Struct<{
|
|
47
|
+
readonly name: Schema.String;
|
|
48
|
+
readonly standing: Schema.String;
|
|
49
|
+
}>>;
|
|
50
|
+
readonly isolated: Schema.Boolean;
|
|
51
|
+
readonly created: Schema.Number;
|
|
52
|
+
/** When its last turn ended, if it is not running. */
|
|
53
|
+
readonly idle: Schema.optionalKey<Schema.Number>;
|
|
54
|
+
/** What it has cost so far, in US dollars. */
|
|
55
|
+
readonly cost: Schema.optionalKey<Schema.Number>;
|
|
56
|
+
/** Its last tool call, and when it was made. */
|
|
57
|
+
readonly tool: Schema.optionalKey<Schema.Struct<{
|
|
58
|
+
readonly name: Schema.String;
|
|
59
|
+
readonly at: Schema.Number;
|
|
60
|
+
}>>;
|
|
61
|
+
readonly waits: Schema.$Array<Schema.Union<readonly [Schema.Struct<{
|
|
62
|
+
readonly type: Schema.Literal<"permission">;
|
|
63
|
+
readonly action: Schema.String;
|
|
64
|
+
readonly resources: Schema.$Array<Schema.String>;
|
|
65
|
+
}>, Schema.Struct<{
|
|
66
|
+
readonly type: Schema.Literal<"question">;
|
|
67
|
+
readonly question: Schema.String;
|
|
68
|
+
}>]>>;
|
|
69
|
+
}>;
|
|
70
|
+
/** The sessions under a session, as courier_tree reads them, in the order a tree is drawn. */
|
|
71
|
+
declare const Tree: Schema.Struct<{
|
|
72
|
+
readonly rows: Schema.$Array<Schema.Struct<{
|
|
73
|
+
readonly sessionID: Schema.String;
|
|
74
|
+
readonly parentID: Schema.String;
|
|
75
|
+
readonly title: Schema.String;
|
|
76
|
+
/** A child of the panel's session is at depth 1. */
|
|
77
|
+
readonly depth: Schema.Int;
|
|
78
|
+
/** `waiting` on a request to the person; `gone` when OpenCode no longer knows it. */
|
|
79
|
+
readonly state: Schema.Literals<readonly ["running", "waiting", "idle", "gone"]>;
|
|
80
|
+
/** How its last turn ended. */
|
|
81
|
+
readonly outcome: Schema.optionalKey<Schema.Literals<readonly ["succeeded", "failed", "interrupted"]>>;
|
|
82
|
+
/** Its report since its last prompt: still owed, arrived (held with its group or delivered), or its turn ended without one. */
|
|
83
|
+
readonly report: Schema.optionalKey<Schema.Struct<{
|
|
84
|
+
readonly state: Schema.Literals<readonly ["owed", "reported", "ended"]>;
|
|
85
|
+
readonly status: Schema.optionalKey<Schema.String>;
|
|
86
|
+
readonly progressed: Schema.Boolean;
|
|
87
|
+
}>>;
|
|
88
|
+
/** Its join group, and its standing there: `held`, `out`, how it left, or `released`. */
|
|
89
|
+
readonly group: Schema.optionalKey<Schema.Struct<{
|
|
90
|
+
readonly name: Schema.String;
|
|
91
|
+
readonly standing: Schema.String;
|
|
92
|
+
}>>;
|
|
93
|
+
readonly isolated: Schema.Boolean;
|
|
94
|
+
readonly created: Schema.Number;
|
|
95
|
+
/** When its last turn ended, if it is not running. */
|
|
96
|
+
readonly idle: Schema.optionalKey<Schema.Number>;
|
|
97
|
+
/** What it has cost so far, in US dollars. */
|
|
98
|
+
readonly cost: Schema.optionalKey<Schema.Number>;
|
|
99
|
+
/** Its last tool call, and when it was made. */
|
|
100
|
+
readonly tool: Schema.optionalKey<Schema.Struct<{
|
|
101
|
+
readonly name: Schema.String;
|
|
102
|
+
readonly at: Schema.Number;
|
|
103
|
+
}>>;
|
|
104
|
+
readonly waits: Schema.$Array<Schema.Union<readonly [Schema.Struct<{
|
|
105
|
+
readonly type: Schema.Literal<"permission">;
|
|
106
|
+
readonly action: Schema.String;
|
|
107
|
+
readonly resources: Schema.$Array<Schema.String>;
|
|
108
|
+
}>, Schema.Struct<{
|
|
109
|
+
readonly type: Schema.Literal<"question">;
|
|
110
|
+
readonly question: Schema.String;
|
|
111
|
+
}>]>>;
|
|
112
|
+
}>>;
|
|
113
|
+
/** Set when the subtree had more sessions than `maxTotal`, which were left out. */
|
|
114
|
+
readonly truncated: Schema.optionalKey<Schema.Int>;
|
|
115
|
+
}>;
|
|
116
|
+
export type Row = typeof Row.Type;
|
|
117
|
+
export type Tree = typeof Tree.Type;
|
|
118
|
+
export type Wait = typeof Wait.Type;
|
|
119
|
+
/** What a stop did to each session, deepest first, as courier_stop reports it. */
|
|
120
|
+
declare const Stopped: Schema.Struct<{
|
|
121
|
+
readonly stopped: Schema.$Array<Schema.Struct<{
|
|
122
|
+
readonly sessionID: Schema.String;
|
|
123
|
+
readonly title: Schema.String;
|
|
124
|
+
readonly outcome: Schema.String;
|
|
125
|
+
}>>;
|
|
126
|
+
/** How many scheduled messages were cancelled. */
|
|
127
|
+
readonly cancelled: Schema.Int;
|
|
128
|
+
}>;
|
|
129
|
+
export type Stopped = typeof Stopped.Type;
|
|
130
|
+
export declare const treeRpc: {
|
|
131
|
+
readonly id: "courier";
|
|
132
|
+
readonly methods: {
|
|
133
|
+
readonly summary: {
|
|
134
|
+
readonly input: import("effect/StandardSchema").StandardSchemaV1<{
|
|
135
|
+
readonly sessionID: string;
|
|
136
|
+
}, {
|
|
137
|
+
readonly sessionID: string;
|
|
138
|
+
}> & Schema.Struct<{
|
|
139
|
+
readonly sessionID: Schema.String;
|
|
140
|
+
}>;
|
|
141
|
+
readonly output: import("effect/StandardSchema").StandardSchemaV1<{
|
|
142
|
+
readonly running: number;
|
|
143
|
+
readonly idle: number;
|
|
144
|
+
readonly groups: readonly {
|
|
145
|
+
readonly name: string;
|
|
146
|
+
readonly reported: number;
|
|
147
|
+
readonly members: number;
|
|
148
|
+
}[];
|
|
149
|
+
readonly waiting: number;
|
|
150
|
+
readonly truncated?: number | undefined;
|
|
151
|
+
}, {
|
|
152
|
+
readonly running: number;
|
|
153
|
+
readonly idle: number;
|
|
154
|
+
readonly groups: readonly {
|
|
155
|
+
readonly name: string;
|
|
156
|
+
readonly reported: number;
|
|
157
|
+
readonly members: number;
|
|
158
|
+
}[];
|
|
159
|
+
readonly waiting: number;
|
|
160
|
+
readonly truncated?: number | undefined;
|
|
161
|
+
}> & Schema.Struct<{
|
|
162
|
+
/** Running, and waiting on no request. */
|
|
163
|
+
readonly running: Schema.Int;
|
|
164
|
+
/** Waiting on a permission request or a question, which go to the person. */
|
|
165
|
+
readonly waiting: Schema.Int;
|
|
166
|
+
/** Not running: done, or waiting for a message. */
|
|
167
|
+
readonly idle: Schema.Int;
|
|
168
|
+
readonly groups: Schema.$Array<Schema.Struct<{
|
|
169
|
+
readonly name: Schema.String;
|
|
170
|
+
readonly reported: Schema.Int;
|
|
171
|
+
readonly members: Schema.Int;
|
|
172
|
+
}>>;
|
|
173
|
+
/** Set when the subtree had more sessions than `maxTotal`, which were not counted. */
|
|
174
|
+
readonly truncated: Schema.optionalKey<Schema.Int>;
|
|
175
|
+
}>;
|
|
176
|
+
};
|
|
177
|
+
readonly tree: {
|
|
178
|
+
readonly input: import("effect/StandardSchema").StandardSchemaV1<{
|
|
179
|
+
readonly sessionID: string;
|
|
180
|
+
}, {
|
|
181
|
+
readonly sessionID: string;
|
|
182
|
+
}> & Schema.Struct<{
|
|
183
|
+
readonly sessionID: Schema.String;
|
|
184
|
+
}>;
|
|
185
|
+
readonly output: import("effect/StandardSchema").StandardSchemaV1<{
|
|
186
|
+
readonly rows: readonly {
|
|
187
|
+
readonly sessionID: string;
|
|
188
|
+
readonly title: string;
|
|
189
|
+
readonly parentID: string;
|
|
190
|
+
readonly depth: number;
|
|
191
|
+
readonly created: number;
|
|
192
|
+
readonly isolated: boolean;
|
|
193
|
+
readonly state: "running" | "idle" | "gone" | "waiting";
|
|
194
|
+
readonly waits: readonly ({
|
|
195
|
+
readonly type: "permission";
|
|
196
|
+
readonly action: string;
|
|
197
|
+
readonly resources: readonly string[];
|
|
198
|
+
} | {
|
|
199
|
+
readonly type: "question";
|
|
200
|
+
readonly question: string;
|
|
201
|
+
})[];
|
|
202
|
+
readonly group?: {
|
|
203
|
+
readonly name: string;
|
|
204
|
+
readonly standing: string;
|
|
205
|
+
} | undefined;
|
|
206
|
+
readonly idle?: number | undefined;
|
|
207
|
+
readonly report?: {
|
|
208
|
+
readonly progressed: boolean;
|
|
209
|
+
readonly state: "reported" | "ended" | "owed";
|
|
210
|
+
readonly status?: string | undefined;
|
|
211
|
+
} | undefined;
|
|
212
|
+
readonly outcome?: "failed" | "interrupted" | "succeeded" | undefined;
|
|
213
|
+
readonly tool?: {
|
|
214
|
+
readonly name: string;
|
|
215
|
+
readonly at: number;
|
|
216
|
+
} | undefined;
|
|
217
|
+
readonly cost?: number | undefined;
|
|
218
|
+
}[];
|
|
219
|
+
readonly truncated?: number | undefined;
|
|
220
|
+
}, {
|
|
221
|
+
readonly rows: readonly {
|
|
222
|
+
readonly sessionID: string;
|
|
223
|
+
readonly title: string;
|
|
224
|
+
readonly parentID: string;
|
|
225
|
+
readonly depth: number;
|
|
226
|
+
readonly created: number;
|
|
227
|
+
readonly isolated: boolean;
|
|
228
|
+
readonly state: "running" | "idle" | "gone" | "waiting";
|
|
229
|
+
readonly waits: readonly ({
|
|
230
|
+
readonly type: "permission";
|
|
231
|
+
readonly action: string;
|
|
232
|
+
readonly resources: readonly string[];
|
|
233
|
+
} | {
|
|
234
|
+
readonly type: "question";
|
|
235
|
+
readonly question: string;
|
|
236
|
+
})[];
|
|
237
|
+
readonly group?: {
|
|
238
|
+
readonly name: string;
|
|
239
|
+
readonly standing: string;
|
|
240
|
+
} | undefined;
|
|
241
|
+
readonly idle?: number | undefined;
|
|
242
|
+
readonly report?: {
|
|
243
|
+
readonly progressed: boolean;
|
|
244
|
+
readonly state: "reported" | "ended" | "owed";
|
|
245
|
+
readonly status?: string | undefined;
|
|
246
|
+
} | undefined;
|
|
247
|
+
readonly outcome?: "failed" | "interrupted" | "succeeded" | undefined;
|
|
248
|
+
readonly tool?: {
|
|
249
|
+
readonly name: string;
|
|
250
|
+
readonly at: number;
|
|
251
|
+
} | undefined;
|
|
252
|
+
readonly cost?: number | undefined;
|
|
253
|
+
}[];
|
|
254
|
+
readonly truncated?: number | undefined;
|
|
255
|
+
}> & Schema.Struct<{
|
|
256
|
+
readonly rows: Schema.$Array<Schema.Struct<{
|
|
257
|
+
readonly sessionID: Schema.String;
|
|
258
|
+
readonly parentID: Schema.String;
|
|
259
|
+
readonly title: Schema.String;
|
|
260
|
+
/** A child of the panel's session is at depth 1. */
|
|
261
|
+
readonly depth: Schema.Int;
|
|
262
|
+
/** `waiting` on a request to the person; `gone` when OpenCode no longer knows it. */
|
|
263
|
+
readonly state: Schema.Literals<readonly ["running", "waiting", "idle", "gone"]>;
|
|
264
|
+
/** How its last turn ended. */
|
|
265
|
+
readonly outcome: Schema.optionalKey<Schema.Literals<readonly ["succeeded", "failed", "interrupted"]>>;
|
|
266
|
+
/** Its report since its last prompt: still owed, arrived (held with its group or delivered), or its turn ended without one. */
|
|
267
|
+
readonly report: Schema.optionalKey<Schema.Struct<{
|
|
268
|
+
readonly state: Schema.Literals<readonly ["owed", "reported", "ended"]>;
|
|
269
|
+
readonly status: Schema.optionalKey<Schema.String>;
|
|
270
|
+
readonly progressed: Schema.Boolean;
|
|
271
|
+
}>>;
|
|
272
|
+
/** Its join group, and its standing there: `held`, `out`, how it left, or `released`. */
|
|
273
|
+
readonly group: Schema.optionalKey<Schema.Struct<{
|
|
274
|
+
readonly name: Schema.String;
|
|
275
|
+
readonly standing: Schema.String;
|
|
276
|
+
}>>;
|
|
277
|
+
readonly isolated: Schema.Boolean;
|
|
278
|
+
readonly created: Schema.Number;
|
|
279
|
+
/** When its last turn ended, if it is not running. */
|
|
280
|
+
readonly idle: Schema.optionalKey<Schema.Number>;
|
|
281
|
+
/** What it has cost so far, in US dollars. */
|
|
282
|
+
readonly cost: Schema.optionalKey<Schema.Number>;
|
|
283
|
+
/** Its last tool call, and when it was made. */
|
|
284
|
+
readonly tool: Schema.optionalKey<Schema.Struct<{
|
|
285
|
+
readonly name: Schema.String;
|
|
286
|
+
readonly at: Schema.Number;
|
|
287
|
+
}>>;
|
|
288
|
+
readonly waits: Schema.$Array<Schema.Union<readonly [Schema.Struct<{
|
|
289
|
+
readonly type: Schema.Literal<"permission">;
|
|
290
|
+
readonly action: Schema.String;
|
|
291
|
+
readonly resources: Schema.$Array<Schema.String>;
|
|
292
|
+
}>, Schema.Struct<{
|
|
293
|
+
readonly type: Schema.Literal<"question">;
|
|
294
|
+
readonly question: Schema.String;
|
|
295
|
+
}>]>>;
|
|
296
|
+
}>>;
|
|
297
|
+
/** Set when the subtree had more sessions than `maxTotal`, which were left out. */
|
|
298
|
+
readonly truncated: Schema.optionalKey<Schema.Int>;
|
|
299
|
+
}>;
|
|
300
|
+
};
|
|
301
|
+
/** Stops `sessionID` and everything under it, as courier_stop called from `by`, which must be above it. */
|
|
302
|
+
readonly stop: {
|
|
303
|
+
readonly input: import("effect/StandardSchema").StandardSchemaV1<{
|
|
304
|
+
readonly sessionID: string;
|
|
305
|
+
readonly by: string;
|
|
306
|
+
}, {
|
|
307
|
+
readonly sessionID: string;
|
|
308
|
+
readonly by: string;
|
|
309
|
+
}> & Schema.Struct<{
|
|
310
|
+
readonly sessionID: Schema.String;
|
|
311
|
+
readonly by: Schema.String;
|
|
312
|
+
}>;
|
|
313
|
+
readonly output: import("effect/StandardSchema").StandardSchemaV1<{
|
|
314
|
+
readonly stopped: readonly {
|
|
315
|
+
readonly sessionID: string;
|
|
316
|
+
readonly title: string;
|
|
317
|
+
readonly outcome: string;
|
|
318
|
+
}[];
|
|
319
|
+
readonly cancelled: number;
|
|
320
|
+
}, {
|
|
321
|
+
readonly stopped: readonly {
|
|
322
|
+
readonly sessionID: string;
|
|
323
|
+
readonly title: string;
|
|
324
|
+
readonly outcome: string;
|
|
325
|
+
}[];
|
|
326
|
+
readonly cancelled: number;
|
|
327
|
+
}> & Schema.Struct<{
|
|
328
|
+
readonly stopped: Schema.$Array<Schema.Struct<{
|
|
329
|
+
readonly sessionID: Schema.String;
|
|
330
|
+
readonly title: Schema.String;
|
|
331
|
+
readonly outcome: Schema.String;
|
|
332
|
+
}>>;
|
|
333
|
+
/** How many scheduled messages were cancelled. */
|
|
334
|
+
readonly cancelled: Schema.Int;
|
|
335
|
+
}>;
|
|
336
|
+
readonly errors: {
|
|
337
|
+
readonly refused: import("effect/StandardSchema").StandardSchemaV1<{}, {}> & Schema.Struct<{}>;
|
|
338
|
+
};
|
|
339
|
+
};
|
|
340
|
+
};
|
|
341
|
+
readonly events: {};
|
|
342
|
+
};
|
|
343
|
+
export type TreeRpc = typeof treeRpc;
|
|
344
|
+
export {};
|
package/dist/tree/rpc.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tree's RPC, the contract its TUI part and its server half share. Standard Schema values, so the promise
|
|
3
|
+
* API's `rpc.register` and the TUI's `client.rpc` both type it; imports only `@opencode/plugin/rpc` and `effect`.
|
|
4
|
+
*/
|
|
5
|
+
import { Rpc } from "@opencode/plugin/rpc";
|
|
6
|
+
import { Schema } from "effect";
|
|
7
|
+
const Count = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
|
|
8
|
+
/** A join group the session opened, with how many of its members have reported and how many have not left. */
|
|
9
|
+
const Group = Schema.Struct({ name: Schema.String, reported: Count, members: Count });
|
|
10
|
+
/** The sessions started under a session, as the prompt footer's status entry shows them. */
|
|
11
|
+
const Summary = Schema.Struct({
|
|
12
|
+
/** Running, and waiting on no request. */
|
|
13
|
+
running: Count,
|
|
14
|
+
/** Waiting on a permission request or a question, which go to the person. */
|
|
15
|
+
waiting: Count,
|
|
16
|
+
/** Not running: done, or waiting for a message. */
|
|
17
|
+
idle: Count,
|
|
18
|
+
groups: Schema.Array(Group),
|
|
19
|
+
/** Set when the subtree had more sessions than `maxTotal`, which were not counted. */
|
|
20
|
+
truncated: Schema.optionalKey(Count),
|
|
21
|
+
});
|
|
22
|
+
/** A request a session waits on until the person answers it: a permission request, or its first question. */
|
|
23
|
+
const Wait = Schema.Union([
|
|
24
|
+
Schema.Struct({ type: Schema.Literal("permission"), action: Schema.String, resources: Schema.Array(Schema.String) }),
|
|
25
|
+
Schema.Struct({ type: Schema.Literal("question"), question: Schema.String }),
|
|
26
|
+
]);
|
|
27
|
+
/** One session of the tree panel: what courier_tree shows of it, and what it is doing, in epoch milliseconds. */
|
|
28
|
+
const Row = Schema.Struct({
|
|
29
|
+
sessionID: Schema.String,
|
|
30
|
+
parentID: Schema.String,
|
|
31
|
+
title: Schema.String,
|
|
32
|
+
/** A child of the panel's session is at depth 1. */
|
|
33
|
+
depth: Count,
|
|
34
|
+
/** `waiting` on a request to the person; `gone` when OpenCode no longer knows it. */
|
|
35
|
+
state: Schema.Literals(["running", "waiting", "idle", "gone"]),
|
|
36
|
+
/** How its last turn ended. */
|
|
37
|
+
outcome: Schema.optionalKey(Schema.Literals(["succeeded", "failed", "interrupted"])),
|
|
38
|
+
/** Its report since its last prompt: still owed, arrived (held with its group or delivered), or its turn ended without one. */
|
|
39
|
+
report: Schema.optionalKey(Schema.Struct({ state: Schema.Literals(["owed", "reported", "ended"]), status: Schema.optionalKey(Schema.String), progressed: Schema.Boolean })),
|
|
40
|
+
/** Its join group, and its standing there: `held`, `out`, how it left, or `released`. */
|
|
41
|
+
group: Schema.optionalKey(Schema.Struct({ name: Schema.String, standing: Schema.String })),
|
|
42
|
+
isolated: Schema.Boolean,
|
|
43
|
+
created: Schema.Number,
|
|
44
|
+
/** When its last turn ended, if it is not running. */
|
|
45
|
+
idle: Schema.optionalKey(Schema.Number),
|
|
46
|
+
/** What it has cost so far, in US dollars. */
|
|
47
|
+
cost: Schema.optionalKey(Schema.Number),
|
|
48
|
+
/** Its last tool call, and when it was made. */
|
|
49
|
+
tool: Schema.optionalKey(Schema.Struct({ name: Schema.String, at: Schema.Number })),
|
|
50
|
+
waits: Schema.Array(Wait),
|
|
51
|
+
});
|
|
52
|
+
/** The sessions under a session, as courier_tree reads them, in the order a tree is drawn. */
|
|
53
|
+
const Tree = Schema.Struct({
|
|
54
|
+
rows: Schema.Array(Row),
|
|
55
|
+
/** Set when the subtree had more sessions than `maxTotal`, which were left out. */
|
|
56
|
+
truncated: Schema.optionalKey(Count),
|
|
57
|
+
});
|
|
58
|
+
/** What a stop did to each session, deepest first, as courier_stop reports it. */
|
|
59
|
+
const Stopped = Schema.Struct({
|
|
60
|
+
stopped: Schema.Array(Schema.Struct({ sessionID: Schema.String, title: Schema.String, outcome: Schema.String })),
|
|
61
|
+
/** How many scheduled messages were cancelled. */
|
|
62
|
+
cancelled: Count,
|
|
63
|
+
});
|
|
64
|
+
export const treeRpc = Rpc.define({
|
|
65
|
+
id: "courier",
|
|
66
|
+
methods: {
|
|
67
|
+
summary: {
|
|
68
|
+
input: Schema.toStandardSchemaV1(Schema.Struct({ sessionID: Schema.String })),
|
|
69
|
+
output: Schema.toStandardSchemaV1(Summary),
|
|
70
|
+
},
|
|
71
|
+
tree: {
|
|
72
|
+
input: Schema.toStandardSchemaV1(Schema.Struct({ sessionID: Schema.String })),
|
|
73
|
+
output: Schema.toStandardSchemaV1(Tree),
|
|
74
|
+
},
|
|
75
|
+
/** Stops `sessionID` and everything under it, as courier_stop called from `by`, which must be above it. */
|
|
76
|
+
stop: {
|
|
77
|
+
input: Schema.toStandardSchemaV1(Schema.Struct({ sessionID: Schema.String, by: Schema.String })),
|
|
78
|
+
output: Schema.toStandardSchemaV1(Stopped),
|
|
79
|
+
errors: { refused: Schema.toStandardSchemaV1(Schema.Struct({})) },
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
events: {},
|
|
83
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Status } from "../kernel/protocol.js";
|
|
2
|
+
import type { Artifacts, CourierPorts, Sent } from "./ports.js";
|
|
3
|
+
export interface SendInput {
|
|
4
|
+
readonly sessionID: string;
|
|
5
|
+
readonly message: string;
|
|
6
|
+
readonly status?: Status;
|
|
7
|
+
readonly artifacts?: Artifacts;
|
|
8
|
+
readonly queue?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Drops a message into another session's inbox; OpenCode wakes that session if it is idle. From a spawned session
|
|
12
|
+
* to the one that started it, it is its report or its progress (`noteReport`); a group member's final report is held (`hold`).
|
|
13
|
+
*/
|
|
14
|
+
export declare function send(ports: CourierPorts, from: string, input: SendInput): Promise<Sent>;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { envelope, isStatus, STATUSES } from "../kernel/protocol.js";
|
|
2
|
+
import { groupStanding, holdReport, membershipFor, unholdForBlocked } from "./group.js";
|
|
3
|
+
import { childStore, groupStore } from "./store.js";
|
|
4
|
+
import { reportBody } from "./text.js";
|
|
5
|
+
/**
|
|
6
|
+
* Drops a message into another session's inbox; OpenCode wakes that session if it is idle. From a spawned session
|
|
7
|
+
* to the one that started it, it is its report or its progress (`noteReport`); a group member's final report is held (`hold`).
|
|
8
|
+
*/
|
|
9
|
+
export async function send(ports, from, input) {
|
|
10
|
+
// Some models send null for an optional field they leave out.
|
|
11
|
+
const status = input.status ?? undefined;
|
|
12
|
+
if (status !== undefined && !isStatus(status))
|
|
13
|
+
throw new Error(`status must be one of ${STATUSES.join(", ")}, not ${JSON.stringify(status)}.`);
|
|
14
|
+
// Noted first: the delivery may wake the parent, whose turn may end before a later note.
|
|
15
|
+
const noted = await noteReport(ports, from, input.sessionID, status).catch(() => undefined);
|
|
16
|
+
try {
|
|
17
|
+
const held = noted?.member && status && status !== "blocked" ? await hold(ports, noted.member, { at: noted.at, status, message: input.message, ...(input.artifacts ? { artifacts: input.artifacts } : {}) }) : undefined;
|
|
18
|
+
if (held)
|
|
19
|
+
return { status, report: true, held };
|
|
20
|
+
const delivered = await ports.session.synthetic({
|
|
21
|
+
sessionID: input.sessionID,
|
|
22
|
+
text: envelope(from, reportBody(input.message, input.artifacts), status ? { status } : {}),
|
|
23
|
+
description: `Message from ${from}`,
|
|
24
|
+
metadata: { source: "courier", from, ...(status ? { status } : {}) },
|
|
25
|
+
delivery: input.queue ? "queue" : "steer",
|
|
26
|
+
});
|
|
27
|
+
// A blocked report, once delivered, is the member's latest word: an earlier report held for it would be stale.
|
|
28
|
+
if (noted?.member && status === "blocked")
|
|
29
|
+
await unholdForBlocked(groupStore(ports.storage), noted.member).catch(() => undefined);
|
|
30
|
+
return { messageID: delivered.id, ...(status ? { status } : {}), ...(noted ? { report: noted.report } : {}) };
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
await noted?.undo().catch(() => undefined);
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Notes `from`'s message to `to` when `to` started it: as its report when it carries a status, or when an earlier
|
|
39
|
+
* release briefed `from`, else as progress. Returns which, when, how to take the note back, and `from`'s group membership.
|
|
40
|
+
*/
|
|
41
|
+
async function noteReport(ports, from, to, status) {
|
|
42
|
+
const children = childStore(ports.storage);
|
|
43
|
+
const entry = await children.indexedEntry(from);
|
|
44
|
+
if (entry?.parentID !== to)
|
|
45
|
+
return undefined;
|
|
46
|
+
const report = status !== undefined || entry.reports !== "status";
|
|
47
|
+
const field = report ? "settled" : "progress";
|
|
48
|
+
const before = await children.peek(from, field);
|
|
49
|
+
const at = ports.now();
|
|
50
|
+
await (report ? children.settled(from, "report", at, status) : children.progressed(from, at));
|
|
51
|
+
// Only its own note: another courier_send of the session's may have noted its report since.
|
|
52
|
+
const undo = async () => {
|
|
53
|
+
const now = (await children.peek(from, field));
|
|
54
|
+
if (now?.at !== at || (report && now.by !== "report"))
|
|
55
|
+
return;
|
|
56
|
+
await children.restore(from, field, before);
|
|
57
|
+
};
|
|
58
|
+
return { report, at, undo, member: status !== undefined ? await memberIn(ports, entry) : undefined };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* A child's membership of an open group of its parent's, by its roster entry; none once courier_cleanup dropped it. One that
|
|
62
|
+
* cannot be read is dropped from the group, best effort, as the report then goes on its own and the group must not wait for it.
|
|
63
|
+
*/
|
|
64
|
+
async function memberIn(ports, entry) {
|
|
65
|
+
const groups = groupStore(ports.storage);
|
|
66
|
+
try {
|
|
67
|
+
const member = await membershipFor(groups, entry);
|
|
68
|
+
return member?.left?.by === "dropped" ? undefined : member;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
ports.log(`courier_send: ${entry.sessionID}'s place in group ${entry.group} could not be read, so its report goes on its own: ${String(error)}`);
|
|
72
|
+
if (entry.group)
|
|
73
|
+
await groups.remove(entry.parentID, entry.group, entry.sessionID).then(() => ports.nudge(), () => undefined);
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Holds a member's report with its group, and nudges the scheduler if that completes the group. Undefined
|
|
79
|
+
* when it could not be held: the member is dropped from the group, which releases without it, and reports on its own.
|
|
80
|
+
*/
|
|
81
|
+
async function hold(ports, member, report) {
|
|
82
|
+
const groups = groupStore(ports.storage);
|
|
83
|
+
try {
|
|
84
|
+
await holdReport(groups, member, report);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
// Neither held nor dropped, the group would wait for ever: the call fails, and the sender sends it again.
|
|
88
|
+
await groups.remove(member.parentID, member.group, member.sessionID).catch((dropError) => {
|
|
89
|
+
throw new Error(`the report could not be held with group ${member.group} (${String(error)}), nor the member dropped from it (${String(dropError)}); send it again.`);
|
|
90
|
+
});
|
|
91
|
+
ports.nudge();
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
// Held whatever the count gives; a count that cannot be read gets the nudge, as a tick that finds nothing due is cheap.
|
|
95
|
+
const standing = await groupStanding(groups, member.parentID, member.group).catch(() => undefined);
|
|
96
|
+
if (standing?.complete !== false)
|
|
97
|
+
ports.nudge();
|
|
98
|
+
return { group: member.group, ...(standing ? { reported: standing.reported, members: standing.members } : {}) };
|
|
99
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CourierPorts } from "./ports.js";
|
|
2
|
+
export interface SpawnInput {
|
|
3
|
+
readonly task: string;
|
|
4
|
+
readonly title?: string;
|
|
5
|
+
readonly agent?: string;
|
|
6
|
+
readonly isolate?: boolean;
|
|
7
|
+
readonly group?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Creates a child session, hands it the task and returns at once; the child reports back with
|
|
11
|
+
* courier_send. Refused past a limit, whether or not the `context` hook hid the tool.
|
|
12
|
+
*/
|
|
13
|
+
export declare function spawn(ports: CourierPorts, parentID: string, input: SpawnInput): Promise<{
|
|
14
|
+
uncommitted?: boolean | undefined;
|
|
15
|
+
fromParent?: boolean | undefined;
|
|
16
|
+
groupError?: string | undefined;
|
|
17
|
+
rosterError?: string | undefined;
|
|
18
|
+
group?: string | undefined;
|
|
19
|
+
sessionID: string;
|
|
20
|
+
directory: string;
|
|
21
|
+
}>;
|