opencode-courier 0.5.0 → 0.6.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 +20 -13
- package/dist/index.js +6 -3
- package/dist/person/form.d.ts +4 -1
- package/dist/person/form.js +5 -0
- package/dist/person/index.d.ts +2 -1
- package/dist/person/index.js +1 -0
- package/dist/person/permission.d.ts +14 -0
- package/dist/person/permission.js +15 -0
- package/dist/person/ports.d.ts +8 -2
- package/dist/person/rpc-handlers.d.ts +37 -30
- package/dist/person/rpc-handlers.js +26 -16
- package/dist/person/rpc.d.ts +43 -24
- package/dist/person/rpc.js +4 -3
- package/dist/person/tui.d.ts +23 -12
- package/dist/tree/domain.d.ts +23 -0
- package/dist/tree/domain.js +26 -0
- package/dist/tree/events.d.ts +2 -2
- package/dist/tree/events.js +5 -3
- package/dist/tree/index.d.ts +1 -1
- package/dist/tree/panel.d.ts +7 -2
- package/dist/tree/panel.js +19 -16
- package/dist/tree/ports.d.ts +7 -0
- package/dist/tree/roster.d.ts +5 -0
- package/dist/tree/roster.js +5 -3
- package/dist/tree/rpc-handlers.d.ts +45 -5
- package/dist/tree/rpc-handlers.js +30 -1
- package/dist/tree/rpc.d.ts +79 -19
- package/dist/tree/rpc.js +20 -8
- package/dist/tree/subtree.d.ts +40 -9
- package/dist/tree/subtree.js +40 -19
- package/dist/tree/summary.d.ts +2 -2
- package/dist/tree/summary.js +8 -16
- package/dist/tree/text.js +4 -1
- package/dist/tree/tools.js +2 -1
- package/dist/tree/tui.d.ts +11 -4
- package/dist/tui.js +567 -174
- package/package.json +1 -1
package/dist/tree/rpc.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
2
|
/** The sessions started under a session, as the prompt footer's status entry shows them. */
|
|
3
3
|
declare const Summary: Schema.Struct<{
|
|
4
|
-
/** Running, and waiting on no request. */
|
|
4
|
+
/** Running, and waiting on no request or form. */
|
|
5
5
|
readonly running: Schema.Int;
|
|
6
|
-
/** Waiting on a permission request or a
|
|
6
|
+
/** Waiting on a permission request, a question or a form it shows, which go to the person. */
|
|
7
7
|
readonly waiting: Schema.Int;
|
|
8
8
|
/** Not running: done, or waiting for a message. */
|
|
9
9
|
readonly idle: Schema.Int;
|
|
@@ -12,11 +12,9 @@ declare const Summary: Schema.Struct<{
|
|
|
12
12
|
readonly reported: Schema.Int;
|
|
13
13
|
readonly members: Schema.Int;
|
|
14
14
|
}>>;
|
|
15
|
-
/** Set when the subtree had more sessions than `maxTotal`, which were not counted. */
|
|
16
|
-
readonly truncated: Schema.optionalKey<Schema.Int>;
|
|
17
15
|
}>;
|
|
18
16
|
export type Summary = typeof Summary.Type;
|
|
19
|
-
/** A request a session waits on until the person answers it: a permission request,
|
|
17
|
+
/** A request a session waits on until the person answers it: a permission request, its first question, or a form it shows. */
|
|
20
18
|
declare const Wait: Schema.Union<readonly [Schema.Struct<{
|
|
21
19
|
readonly type: Schema.Literal<"permission">;
|
|
22
20
|
readonly action: Schema.String;
|
|
@@ -24,6 +22,9 @@ declare const Wait: Schema.Union<readonly [Schema.Struct<{
|
|
|
24
22
|
}>, Schema.Struct<{
|
|
25
23
|
readonly type: Schema.Literal<"question">;
|
|
26
24
|
readonly question: Schema.String;
|
|
25
|
+
}>, Schema.Struct<{
|
|
26
|
+
readonly type: Schema.Literal<"form">;
|
|
27
|
+
readonly title: Schema.String;
|
|
27
28
|
}>]>;
|
|
28
29
|
/** One session of the tree panel: what courier_tree shows of it, and what it is doing, in epoch milliseconds. */
|
|
29
30
|
declare const Row: Schema.Struct<{
|
|
@@ -32,10 +33,12 @@ declare const Row: Schema.Struct<{
|
|
|
32
33
|
readonly title: Schema.String;
|
|
33
34
|
/** A child of the panel's session is at depth 1. */
|
|
34
35
|
readonly depth: Schema.Int;
|
|
35
|
-
/** `waiting` on a request to the person; `gone` when OpenCode no longer knows it. */
|
|
36
|
+
/** `waiting` on a request to the person or a form it shows them; `gone` when OpenCode no longer knows it. */
|
|
36
37
|
readonly state: Schema.Literals<readonly ["running", "waiting", "idle", "gone"]>;
|
|
37
38
|
/** How its last turn ended. */
|
|
38
39
|
readonly outcome: Schema.optionalKey<Schema.Literals<readonly ["succeeded", "failed", "interrupted"]>>;
|
|
40
|
+
/** Set when courier_stop stopped it since its last prompt. */
|
|
41
|
+
readonly stopped: Schema.optionalKey<Schema.Boolean>;
|
|
39
42
|
/** Its report since its last prompt: still owed, arrived (held with its group or delivered), or its turn ended without one. */
|
|
40
43
|
readonly report: Schema.optionalKey<Schema.Struct<{
|
|
41
44
|
readonly state: Schema.Literals<readonly ["owed", "reported", "ended"]>;
|
|
@@ -65,9 +68,12 @@ declare const Row: Schema.Struct<{
|
|
|
65
68
|
}>, Schema.Struct<{
|
|
66
69
|
readonly type: Schema.Literal<"question">;
|
|
67
70
|
readonly question: Schema.String;
|
|
71
|
+
}>, Schema.Struct<{
|
|
72
|
+
readonly type: Schema.Literal<"form">;
|
|
73
|
+
readonly title: Schema.String;
|
|
68
74
|
}>]>>;
|
|
69
75
|
}>;
|
|
70
|
-
/** The sessions under a session, as courier_tree
|
|
76
|
+
/** The sessions under a session, as courier_tree lists them, in the order a tree is drawn. */
|
|
71
77
|
declare const Tree: Schema.Struct<{
|
|
72
78
|
readonly rows: Schema.$Array<Schema.Struct<{
|
|
73
79
|
readonly sessionID: Schema.String;
|
|
@@ -75,10 +81,12 @@ declare const Tree: Schema.Struct<{
|
|
|
75
81
|
readonly title: Schema.String;
|
|
76
82
|
/** A child of the panel's session is at depth 1. */
|
|
77
83
|
readonly depth: Schema.Int;
|
|
78
|
-
/** `waiting` on a request to the person; `gone` when OpenCode no longer knows it. */
|
|
84
|
+
/** `waiting` on a request to the person or a form it shows them; `gone` when OpenCode no longer knows it. */
|
|
79
85
|
readonly state: Schema.Literals<readonly ["running", "waiting", "idle", "gone"]>;
|
|
80
86
|
/** How its last turn ended. */
|
|
81
87
|
readonly outcome: Schema.optionalKey<Schema.Literals<readonly ["succeeded", "failed", "interrupted"]>>;
|
|
88
|
+
/** Set when courier_stop stopped it since its last prompt. */
|
|
89
|
+
readonly stopped: Schema.optionalKey<Schema.Boolean>;
|
|
82
90
|
/** Its report since its last prompt: still owed, arrived (held with its group or delivered), or its turn ended without one. */
|
|
83
91
|
readonly report: Schema.optionalKey<Schema.Struct<{
|
|
84
92
|
readonly state: Schema.Literals<readonly ["owed", "reported", "ended"]>;
|
|
@@ -108,9 +116,12 @@ declare const Tree: Schema.Struct<{
|
|
|
108
116
|
}>, Schema.Struct<{
|
|
109
117
|
readonly type: Schema.Literal<"question">;
|
|
110
118
|
readonly question: Schema.String;
|
|
119
|
+
}>, Schema.Struct<{
|
|
120
|
+
readonly type: Schema.Literal<"form">;
|
|
121
|
+
readonly title: Schema.String;
|
|
111
122
|
}>]>>;
|
|
112
123
|
}>>;
|
|
113
|
-
/**
|
|
124
|
+
/** How many older sessions the listing left out, when it had more than `maxTotal`: the live ones come first, then the newest. */
|
|
114
125
|
readonly truncated: Schema.optionalKey<Schema.Int>;
|
|
115
126
|
}>;
|
|
116
127
|
export type Row = typeof Row.Type;
|
|
@@ -127,6 +138,14 @@ declare const Stopped: Schema.Struct<{
|
|
|
127
138
|
readonly cancelled: Schema.Int;
|
|
128
139
|
}>;
|
|
129
140
|
export type Stopped = typeof Stopped.Type;
|
|
141
|
+
/** What courier_cleanup did: forgot it, removed its worktree, found that already gone, or kept the worktree, saying why. */
|
|
142
|
+
declare const Forgotten: Schema.Union<readonly [Schema.Struct<{
|
|
143
|
+
readonly outcome: Schema.Literals<readonly ["forgotten", "removed", "gone"]>;
|
|
144
|
+
}>, Schema.Struct<{
|
|
145
|
+
readonly outcome: Schema.Literal<"kept">;
|
|
146
|
+
readonly reason: Schema.String;
|
|
147
|
+
}>]>;
|
|
148
|
+
export type Forgotten = typeof Forgotten.Type;
|
|
130
149
|
export declare const treeRpc: {
|
|
131
150
|
readonly id: "courier";
|
|
132
151
|
readonly methods: {
|
|
@@ -140,28 +159,26 @@ export declare const treeRpc: {
|
|
|
140
159
|
}>;
|
|
141
160
|
readonly output: import("effect/StandardSchema").StandardSchemaV1<{
|
|
142
161
|
readonly running: number;
|
|
162
|
+
readonly waiting: number;
|
|
143
163
|
readonly idle: number;
|
|
144
164
|
readonly groups: readonly {
|
|
145
165
|
readonly name: string;
|
|
146
166
|
readonly reported: number;
|
|
147
167
|
readonly members: number;
|
|
148
168
|
}[];
|
|
149
|
-
readonly waiting: number;
|
|
150
|
-
readonly truncated?: number | undefined;
|
|
151
169
|
}, {
|
|
152
170
|
readonly running: number;
|
|
171
|
+
readonly waiting: number;
|
|
153
172
|
readonly idle: number;
|
|
154
173
|
readonly groups: readonly {
|
|
155
174
|
readonly name: string;
|
|
156
175
|
readonly reported: number;
|
|
157
176
|
readonly members: number;
|
|
158
177
|
}[];
|
|
159
|
-
readonly waiting: number;
|
|
160
|
-
readonly truncated?: number | undefined;
|
|
161
178
|
}> & Schema.Struct<{
|
|
162
|
-
/** Running, and waiting on no request. */
|
|
179
|
+
/** Running, and waiting on no request or form. */
|
|
163
180
|
readonly running: Schema.Int;
|
|
164
|
-
/** Waiting on a permission request or a
|
|
181
|
+
/** Waiting on a permission request, a question or a form it shows, which go to the person. */
|
|
165
182
|
readonly waiting: Schema.Int;
|
|
166
183
|
/** Not running: done, or waiting for a message. */
|
|
167
184
|
readonly idle: Schema.Int;
|
|
@@ -170,8 +187,6 @@ export declare const treeRpc: {
|
|
|
170
187
|
readonly reported: Schema.Int;
|
|
171
188
|
readonly members: Schema.Int;
|
|
172
189
|
}>>;
|
|
173
|
-
/** Set when the subtree had more sessions than `maxTotal`, which were not counted. */
|
|
174
|
-
readonly truncated: Schema.optionalKey<Schema.Int>;
|
|
175
190
|
}>;
|
|
176
191
|
};
|
|
177
192
|
readonly tree: {
|
|
@@ -198,11 +213,15 @@ export declare const treeRpc: {
|
|
|
198
213
|
} | {
|
|
199
214
|
readonly type: "question";
|
|
200
215
|
readonly question: string;
|
|
216
|
+
} | {
|
|
217
|
+
readonly type: "form";
|
|
218
|
+
readonly title: string;
|
|
201
219
|
})[];
|
|
202
220
|
readonly group?: {
|
|
203
221
|
readonly name: string;
|
|
204
222
|
readonly standing: string;
|
|
205
223
|
} | undefined;
|
|
224
|
+
readonly stopped?: boolean | undefined;
|
|
206
225
|
readonly idle?: number | undefined;
|
|
207
226
|
readonly report?: {
|
|
208
227
|
readonly progressed: boolean;
|
|
@@ -233,11 +252,15 @@ export declare const treeRpc: {
|
|
|
233
252
|
} | {
|
|
234
253
|
readonly type: "question";
|
|
235
254
|
readonly question: string;
|
|
255
|
+
} | {
|
|
256
|
+
readonly type: "form";
|
|
257
|
+
readonly title: string;
|
|
236
258
|
})[];
|
|
237
259
|
readonly group?: {
|
|
238
260
|
readonly name: string;
|
|
239
261
|
readonly standing: string;
|
|
240
262
|
} | undefined;
|
|
263
|
+
readonly stopped?: boolean | undefined;
|
|
241
264
|
readonly idle?: number | undefined;
|
|
242
265
|
readonly report?: {
|
|
243
266
|
readonly progressed: boolean;
|
|
@@ -259,10 +282,12 @@ export declare const treeRpc: {
|
|
|
259
282
|
readonly title: Schema.String;
|
|
260
283
|
/** A child of the panel's session is at depth 1. */
|
|
261
284
|
readonly depth: Schema.Int;
|
|
262
|
-
/** `waiting` on a request to the person; `gone` when OpenCode no longer knows it. */
|
|
285
|
+
/** `waiting` on a request to the person or a form it shows them; `gone` when OpenCode no longer knows it. */
|
|
263
286
|
readonly state: Schema.Literals<readonly ["running", "waiting", "idle", "gone"]>;
|
|
264
287
|
/** How its last turn ended. */
|
|
265
288
|
readonly outcome: Schema.optionalKey<Schema.Literals<readonly ["succeeded", "failed", "interrupted"]>>;
|
|
289
|
+
/** Set when courier_stop stopped it since its last prompt. */
|
|
290
|
+
readonly stopped: Schema.optionalKey<Schema.Boolean>;
|
|
266
291
|
/** Its report since its last prompt: still owed, arrived (held with its group or delivered), or its turn ended without one. */
|
|
267
292
|
readonly report: Schema.optionalKey<Schema.Struct<{
|
|
268
293
|
readonly state: Schema.Literals<readonly ["owed", "reported", "ended"]>;
|
|
@@ -292,9 +317,12 @@ export declare const treeRpc: {
|
|
|
292
317
|
}>, Schema.Struct<{
|
|
293
318
|
readonly type: Schema.Literal<"question">;
|
|
294
319
|
readonly question: Schema.String;
|
|
320
|
+
}>, Schema.Struct<{
|
|
321
|
+
readonly type: Schema.Literal<"form">;
|
|
322
|
+
readonly title: Schema.String;
|
|
295
323
|
}>]>>;
|
|
296
324
|
}>>;
|
|
297
|
-
/**
|
|
325
|
+
/** How many older sessions the listing left out, when it had more than `maxTotal`: the live ones come first, then the newest. */
|
|
298
326
|
readonly truncated: Schema.optionalKey<Schema.Int>;
|
|
299
327
|
}>;
|
|
300
328
|
};
|
|
@@ -337,6 +365,38 @@ export declare const treeRpc: {
|
|
|
337
365
|
readonly refused: import("effect/StandardSchema").StandardSchemaV1<{}, {}> & Schema.Struct<{}>;
|
|
338
366
|
};
|
|
339
367
|
};
|
|
368
|
+
/** Forgets `sessionID` as courier_cleanup called from its parent, without `force`; `by` must be above it. */
|
|
369
|
+
readonly cleanup: {
|
|
370
|
+
readonly input: import("effect/StandardSchema").StandardSchemaV1<{
|
|
371
|
+
readonly sessionID: string;
|
|
372
|
+
readonly by: string;
|
|
373
|
+
}, {
|
|
374
|
+
readonly sessionID: string;
|
|
375
|
+
readonly by: string;
|
|
376
|
+
}> & Schema.Struct<{
|
|
377
|
+
readonly sessionID: Schema.String;
|
|
378
|
+
readonly by: Schema.String;
|
|
379
|
+
}>;
|
|
380
|
+
readonly output: import("effect/StandardSchema").StandardSchemaV1<{
|
|
381
|
+
readonly outcome: "removed" | "gone" | "forgotten";
|
|
382
|
+
} | {
|
|
383
|
+
readonly outcome: "kept";
|
|
384
|
+
readonly reason: string;
|
|
385
|
+
}, {
|
|
386
|
+
readonly outcome: "removed" | "gone" | "forgotten";
|
|
387
|
+
} | {
|
|
388
|
+
readonly outcome: "kept";
|
|
389
|
+
readonly reason: string;
|
|
390
|
+
}> & Schema.Union<readonly [Schema.Struct<{
|
|
391
|
+
readonly outcome: Schema.Literals<readonly ["forgotten", "removed", "gone"]>;
|
|
392
|
+
}>, Schema.Struct<{
|
|
393
|
+
readonly outcome: Schema.Literal<"kept">;
|
|
394
|
+
readonly reason: Schema.String;
|
|
395
|
+
}>]>;
|
|
396
|
+
readonly errors: {
|
|
397
|
+
readonly refused: import("effect/StandardSchema").StandardSchemaV1<{}, {}> & Schema.Struct<{}>;
|
|
398
|
+
};
|
|
399
|
+
};
|
|
340
400
|
};
|
|
341
401
|
readonly events: {};
|
|
342
402
|
};
|
package/dist/tree/rpc.js
CHANGED
|
@@ -9,20 +9,19 @@ const Count = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
|
|
|
9
9
|
const Group = Schema.Struct({ name: Schema.String, reported: Count, members: Count });
|
|
10
10
|
/** The sessions started under a session, as the prompt footer's status entry shows them. */
|
|
11
11
|
const Summary = Schema.Struct({
|
|
12
|
-
/** Running, and waiting on no request. */
|
|
12
|
+
/** Running, and waiting on no request or form. */
|
|
13
13
|
running: Count,
|
|
14
|
-
/** Waiting on a permission request or a
|
|
14
|
+
/** Waiting on a permission request, a question or a form it shows, which go to the person. */
|
|
15
15
|
waiting: Count,
|
|
16
16
|
/** Not running: done, or waiting for a message. */
|
|
17
17
|
idle: Count,
|
|
18
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
19
|
});
|
|
22
|
-
/** A request a session waits on until the person answers it: a permission request,
|
|
20
|
+
/** A request a session waits on until the person answers it: a permission request, its first question, or a form it shows. */
|
|
23
21
|
const Wait = Schema.Union([
|
|
24
22
|
Schema.Struct({ type: Schema.Literal("permission"), action: Schema.String, resources: Schema.Array(Schema.String) }),
|
|
25
23
|
Schema.Struct({ type: Schema.Literal("question"), question: Schema.String }),
|
|
24
|
+
Schema.Struct({ type: Schema.Literal("form"), title: Schema.String }),
|
|
26
25
|
]);
|
|
27
26
|
/** One session of the tree panel: what courier_tree shows of it, and what it is doing, in epoch milliseconds. */
|
|
28
27
|
const Row = Schema.Struct({
|
|
@@ -31,10 +30,12 @@ const Row = Schema.Struct({
|
|
|
31
30
|
title: Schema.String,
|
|
32
31
|
/** A child of the panel's session is at depth 1. */
|
|
33
32
|
depth: Count,
|
|
34
|
-
/** `waiting` on a request to the person; `gone` when OpenCode no longer knows it. */
|
|
33
|
+
/** `waiting` on a request to the person or a form it shows them; `gone` when OpenCode no longer knows it. */
|
|
35
34
|
state: Schema.Literals(["running", "waiting", "idle", "gone"]),
|
|
36
35
|
/** How its last turn ended. */
|
|
37
36
|
outcome: Schema.optionalKey(Schema.Literals(["succeeded", "failed", "interrupted"])),
|
|
37
|
+
/** Set when courier_stop stopped it since its last prompt. */
|
|
38
|
+
stopped: Schema.optionalKey(Schema.Boolean),
|
|
38
39
|
/** Its report since its last prompt: still owed, arrived (held with its group or delivered), or its turn ended without one. */
|
|
39
40
|
report: Schema.optionalKey(Schema.Struct({ state: Schema.Literals(["owed", "reported", "ended"]), status: Schema.optionalKey(Schema.String), progressed: Schema.Boolean })),
|
|
40
41
|
/** Its join group, and its standing there: `held`, `out`, how it left, or `released`. */
|
|
@@ -49,10 +50,10 @@ const Row = Schema.Struct({
|
|
|
49
50
|
tool: Schema.optionalKey(Schema.Struct({ name: Schema.String, at: Schema.Number })),
|
|
50
51
|
waits: Schema.Array(Wait),
|
|
51
52
|
});
|
|
52
|
-
/** The sessions under a session, as courier_tree
|
|
53
|
+
/** The sessions under a session, as courier_tree lists them, in the order a tree is drawn. */
|
|
53
54
|
const Tree = Schema.Struct({
|
|
54
55
|
rows: Schema.Array(Row),
|
|
55
|
-
/**
|
|
56
|
+
/** How many older sessions the listing left out, when it had more than `maxTotal`: the live ones come first, then the newest. */
|
|
56
57
|
truncated: Schema.optionalKey(Count),
|
|
57
58
|
});
|
|
58
59
|
/** What a stop did to each session, deepest first, as courier_stop reports it. */
|
|
@@ -61,6 +62,11 @@ const Stopped = Schema.Struct({
|
|
|
61
62
|
/** How many scheduled messages were cancelled. */
|
|
62
63
|
cancelled: Count,
|
|
63
64
|
});
|
|
65
|
+
/** What courier_cleanup did: forgot it, removed its worktree, found that already gone, or kept the worktree, saying why. */
|
|
66
|
+
const Forgotten = Schema.Union([
|
|
67
|
+
Schema.Struct({ outcome: Schema.Literals(["forgotten", "removed", "gone"]) }),
|
|
68
|
+
Schema.Struct({ outcome: Schema.Literal("kept"), reason: Schema.String }),
|
|
69
|
+
]);
|
|
64
70
|
export const treeRpc = Rpc.define({
|
|
65
71
|
id: "courier",
|
|
66
72
|
methods: {
|
|
@@ -78,6 +84,12 @@ export const treeRpc = Rpc.define({
|
|
|
78
84
|
output: Schema.toStandardSchemaV1(Stopped),
|
|
79
85
|
errors: { refused: Schema.toStandardSchemaV1(Schema.Struct({})) },
|
|
80
86
|
},
|
|
87
|
+
/** Forgets `sessionID` as courier_cleanup called from its parent, without `force`; `by` must be above it. */
|
|
88
|
+
cleanup: {
|
|
89
|
+
input: Schema.toStandardSchemaV1(Schema.Struct({ sessionID: Schema.String, by: Schema.String })),
|
|
90
|
+
output: Schema.toStandardSchemaV1(Forgotten),
|
|
91
|
+
errors: { refused: Schema.toStandardSchemaV1(Schema.Struct({})) },
|
|
92
|
+
},
|
|
81
93
|
},
|
|
82
94
|
events: {},
|
|
83
95
|
});
|
package/dist/tree/subtree.d.ts
CHANGED
|
@@ -1,20 +1,50 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Plugin } from "@opencode/plugin";
|
|
2
|
+
import type { CourierPorts, Pending, RosterEntry, RosterStorage, ShownForm } from "./ports.js";
|
|
3
|
+
import { reportOf } from "./report.js";
|
|
4
|
+
import { type Exists } from "./roster.js";
|
|
2
5
|
/** A session below the one a subtree is read from, with how many levels below it is: a child is at depth 1. */
|
|
3
6
|
export interface Below {
|
|
4
7
|
readonly entry: RosterEntry;
|
|
5
8
|
readonly depth: number;
|
|
6
9
|
}
|
|
10
|
+
/** What a read drops: the entries past retention at `now`, as `courier_children` drops them; `exists` tells a worktree still there. */
|
|
11
|
+
export interface Retention {
|
|
12
|
+
readonly now: number;
|
|
13
|
+
readonly exists?: Exists;
|
|
14
|
+
}
|
|
7
15
|
/**
|
|
8
|
-
* The sessions started from a session, directly or through others, read one prefix scan per
|
|
9
|
-
*
|
|
16
|
+
* The sessions started from a session, directly or through others, every one of them, read one prefix scan per
|
|
17
|
+
* parent, in the order a tree is drawn; with `retention`, without the expired entries and what is under them.
|
|
10
18
|
*/
|
|
11
|
-
export declare function subtree(storage: RosterStorage, rootID: string,
|
|
19
|
+
export declare function subtree(storage: RosterStorage, rootID: string, retention?: Retention): Promise<{
|
|
12
20
|
nodes: Below[];
|
|
13
|
-
|
|
21
|
+
}>;
|
|
22
|
+
type Info = Awaited<ReturnType<Plugin.Context["session"]["get"]>>;
|
|
23
|
+
/** A session of a tree as a read looks it up: OpenCode's info of it, if it still knows it, and what it waits on. */
|
|
24
|
+
export interface Looked extends Below {
|
|
25
|
+
readonly info: Info | undefined;
|
|
26
|
+
readonly pending: ReadonlyArray<Pending>;
|
|
27
|
+
readonly forms: ReadonlyArray<ShownForm>;
|
|
28
|
+
}
|
|
29
|
+
/** A session as a listing looks it up: `Looked` plus its report state, and whether it is live (`isLive`). */
|
|
30
|
+
export interface Listed extends Looked {
|
|
31
|
+
readonly report: Awaited<ReturnType<typeof reportOf>>;
|
|
32
|
+
readonly live: boolean;
|
|
33
|
+
}
|
|
34
|
+
export type ReadPorts = Pick<CourierPorts, "storage" | "session" | "pending" | "forms" | "now" | "limits">;
|
|
35
|
+
/** Every session under a session, without those past retention, each looked up, in the order a tree is drawn. */
|
|
36
|
+
export declare function lookUp(ports: ReadPorts, rootID: string): Promise<Looked[]>;
|
|
37
|
+
/**
|
|
38
|
+
* The listing of at most `max` of the sessions under a session: the live ones first, then the newest, with what is
|
|
39
|
+
* above them, in the order a tree is drawn (`cut`); `leftOut` counts the rest.
|
|
40
|
+
*/
|
|
41
|
+
export declare function readTree(ports: ReadPorts, rootID: string, max?: number): Promise<{
|
|
42
|
+
kept: Listed[];
|
|
43
|
+
leftOut: number;
|
|
14
44
|
}>;
|
|
15
45
|
/**
|
|
16
|
-
* The subtree under a session
|
|
17
|
-
* its parent and its report state.
|
|
46
|
+
* The subtree under a session as courier_tree lists it (`readTree`): each session as courier_children shows it, plus
|
|
47
|
+
* its depth, its parent and its report state; `truncated` counts the older sessions left out.
|
|
18
48
|
*/
|
|
19
49
|
export declare function tree(ports: CourierPorts, rootID: string): Promise<{
|
|
20
50
|
truncated?: number | undefined;
|
|
@@ -41,7 +71,7 @@ export declare function tree(ports: CourierPorts, rootID: string): Promise<{
|
|
|
41
71
|
updated?: number | undefined;
|
|
42
72
|
idle?: number | undefined;
|
|
43
73
|
lastText?: string | undefined;
|
|
44
|
-
pending?: readonly
|
|
74
|
+
pending?: readonly Pending[] | undefined;
|
|
45
75
|
} | {
|
|
46
76
|
report?: {
|
|
47
77
|
status?: "done" | "partial" | "blocked" | "failed" | undefined;
|
|
@@ -61,7 +91,7 @@ export declare function tree(ports: CourierPorts, rootID: string): Promise<{
|
|
|
61
91
|
updated?: number | undefined;
|
|
62
92
|
idle?: number | undefined;
|
|
63
93
|
lastText?: string | undefined;
|
|
64
|
-
pending?: readonly
|
|
94
|
+
pending?: readonly Pending[] | undefined;
|
|
65
95
|
} | {
|
|
66
96
|
report?: {
|
|
67
97
|
status?: "done" | "partial" | "blocked" | "failed" | undefined;
|
|
@@ -99,3 +129,4 @@ export declare function tree(ports: CourierPorts, rootID: string): Promise<{
|
|
|
99
129
|
title: string;
|
|
100
130
|
})[];
|
|
101
131
|
}>;
|
|
132
|
+
export {};
|
package/dist/tree/subtree.js
CHANGED
|
@@ -1,24 +1,23 @@
|
|
|
1
|
+
import { busy, cut, isLive } from "./domain.js";
|
|
1
2
|
import { lastStatus, reportOf } from "./report.js";
|
|
3
|
+
import { isExpired } from "./roster.js";
|
|
2
4
|
import { described } from "./status.js";
|
|
3
5
|
import { childStore } from "./store.js";
|
|
4
6
|
/**
|
|
5
|
-
* The sessions started from a session, directly or through others, read one prefix scan per
|
|
6
|
-
*
|
|
7
|
+
* The sessions started from a session, directly or through others, every one of them, read one prefix scan per
|
|
8
|
+
* parent, in the order a tree is drawn; with `retention`, without the expired entries and what is under them.
|
|
7
9
|
*/
|
|
8
|
-
export async function subtree(storage, rootID,
|
|
10
|
+
export async function subtree(storage, rootID, retention) {
|
|
9
11
|
const children = childStore(storage);
|
|
10
12
|
const byParent = new Map();
|
|
11
13
|
const seen = new Set([rootID]);
|
|
12
|
-
let truncated = false;
|
|
13
14
|
const expand = async (level, depth) => {
|
|
14
|
-
if (!level.length
|
|
15
|
+
if (!level.length)
|
|
15
16
|
return;
|
|
16
17
|
const found = await Promise.all(level.map((parentID) => children.children(parentID)));
|
|
17
18
|
const next = [];
|
|
18
19
|
for (const [index, entries] of found.entries()) {
|
|
19
|
-
const
|
|
20
|
-
const kept = fresh.slice(0, Math.max(0, max - (seen.size - 1)));
|
|
21
|
-
truncated ||= kept.length < fresh.length;
|
|
20
|
+
const kept = entries.filter((entry) => !seen.has(entry.sessionID) && !(retention && isExpired(entry, retention.now, retention.exists)));
|
|
22
21
|
for (const entry of kept)
|
|
23
22
|
seen.add(entry.sessionID);
|
|
24
23
|
if (kept.length)
|
|
@@ -28,25 +27,47 @@ export async function subtree(storage, rootID, max = Number.POSITIVE_INFINITY) {
|
|
|
28
27
|
return expand(next, depth + 1);
|
|
29
28
|
};
|
|
30
29
|
await expand([rootID], 1);
|
|
31
|
-
return { nodes: drawn(byParent, rootID)
|
|
30
|
+
return { nodes: drawn(byParent, rootID) };
|
|
32
31
|
}
|
|
33
32
|
/** The nodes in the order a tree is drawn: each followed by what it started. */
|
|
34
33
|
function drawn(byParent, parentID) {
|
|
35
34
|
return (byParent.get(parentID) ?? []).flatMap((node) => [node, ...drawn(byParent, node.entry.sessionID)]);
|
|
36
35
|
}
|
|
36
|
+
/** Every session under a session, without those past retention, each looked up, in the order a tree is drawn. */
|
|
37
|
+
export async function lookUp(ports, rootID) {
|
|
38
|
+
const { nodes } = await subtree(ports.storage, rootID, { now: ports.now() });
|
|
39
|
+
return Promise.all(nodes.map(async (node) => {
|
|
40
|
+
const [info, pending, forms] = await Promise.all([
|
|
41
|
+
ports.session.get({ sessionID: node.entry.sessionID }).catch(() => undefined),
|
|
42
|
+
ports.pending(node.entry.sessionID).catch(() => []),
|
|
43
|
+
ports.forms(node.entry.sessionID).catch(() => []),
|
|
44
|
+
]);
|
|
45
|
+
// A form outlives its session's turn only when its withdrawal was missed, as while no instance followed the events.
|
|
46
|
+
return { ...node, info, pending, forms: info && busy(info.time) ? forms : [] };
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
37
49
|
/**
|
|
38
|
-
* The
|
|
39
|
-
*
|
|
50
|
+
* The listing of at most `max` of the sessions under a session: the live ones first, then the newest, with what is
|
|
51
|
+
* above them, in the order a tree is drawn (`cut`); `leftOut` counts the rest.
|
|
52
|
+
*/
|
|
53
|
+
export async function readTree(ports, rootID, max = ports.limits.maxTotal) {
|
|
54
|
+
const children = childStore(ports.storage);
|
|
55
|
+
const all = await Promise.all((await lookUp(ports, rootID)).map(async (node) => {
|
|
56
|
+
const report = await reportOf(children, node.entry.sessionID).catch(() => undefined);
|
|
57
|
+
return { ...node, report, live: isLive(node.info?.time, node.pending.length + node.forms.length, report) };
|
|
58
|
+
}));
|
|
59
|
+
const listing = cut(all.map((node) => ({ sessionID: node.entry.sessionID, parentID: node.entry.parentID, createdAt: node.entry.createdAt, live: node.live, node })), max);
|
|
60
|
+
return { kept: listing.kept.map(({ node }) => node), leftOut: listing.leftOut };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The subtree under a session as courier_tree lists it (`readTree`): each session as courier_children shows it, plus
|
|
64
|
+
* its depth, its parent and its report state; `truncated` counts the older sessions left out.
|
|
40
65
|
*/
|
|
41
66
|
export async function tree(ports, rootID) {
|
|
42
|
-
const {
|
|
67
|
+
const { kept, leftOut } = await readTree(ports, rootID);
|
|
43
68
|
const children = childStore(ports.storage);
|
|
44
|
-
const listed = await Promise.all(
|
|
45
|
-
const [info,
|
|
46
|
-
described(ports, entry),
|
|
47
|
-
reportOf(children, entry.sessionID).catch(() => undefined),
|
|
48
|
-
lastStatus(children, entry.sessionID).catch(() => undefined),
|
|
49
|
-
]);
|
|
69
|
+
const listed = await Promise.all(kept.map(async ({ entry, depth, report }) => {
|
|
70
|
+
const [info, last] = await Promise.all([described(ports, entry), lastStatus(children, entry.sessionID).catch(() => undefined)]);
|
|
50
71
|
return {
|
|
51
72
|
...info,
|
|
52
73
|
parentID: entry.parentID,
|
|
@@ -56,5 +77,5 @@ export async function tree(ports, rootID) {
|
|
|
56
77
|
: {}),
|
|
57
78
|
};
|
|
58
79
|
}));
|
|
59
|
-
return { sessionID: rootID, sessions: listed, ...(
|
|
80
|
+
return { sessionID: rootID, sessions: listed, ...(leftOut ? { truncated: leftOut } : {}) };
|
|
60
81
|
}
|
package/dist/tree/summary.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CourierPorts } from "./ports.js";
|
|
2
2
|
import type { Summary } from "./rpc.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Every session started under a session, counted by what it is doing, and its open join groups, those of its own
|
|
5
|
+
* children, with how far each has reported.
|
|
6
6
|
*/
|
|
7
7
|
export declare function summary(ports: CourierPorts, sessionID: string): Promise<Summary>;
|
package/dist/tree/summary.js
CHANGED
|
@@ -1,35 +1,27 @@
|
|
|
1
1
|
import { busy } from "./domain.js";
|
|
2
2
|
import { groupStandings } from "./group.js";
|
|
3
3
|
import { groupStore } from "./store.js";
|
|
4
|
-
import {
|
|
5
|
-
/** What a session is doing: waiting on a request it made, running, or idle; undefined when OpenCode no longer knows it. */
|
|
6
|
-
|
|
7
|
-
const [info, pending] = await Promise.all([
|
|
8
|
-
ports.session.get({ sessionID }).catch(() => undefined),
|
|
9
|
-
ports.pending(sessionID).catch(() => []),
|
|
10
|
-
]);
|
|
4
|
+
import { lookUp } from "./subtree.js";
|
|
5
|
+
/** What a session is doing: waiting on a request it made or a form it shows, running, or idle; undefined when OpenCode no longer knows it. */
|
|
6
|
+
function activity({ info, pending, forms }) {
|
|
11
7
|
if (!info)
|
|
12
8
|
return undefined;
|
|
13
|
-
if (pending.length)
|
|
9
|
+
if (pending.length || forms.length)
|
|
14
10
|
return "waiting";
|
|
15
11
|
return busy(info.time) ? "running" : "idle";
|
|
16
12
|
}
|
|
17
13
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
14
|
+
* Every session started under a session, counted by what it is doing, and its open join groups, those of its own
|
|
15
|
+
* children, with how far each has reported.
|
|
20
16
|
*/
|
|
21
17
|
export async function summary(ports, sessionID) {
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
return { activities: await Promise.all(nodes.map(({ entry }) => activity(ports, entry.sessionID))), truncated };
|
|
25
|
-
};
|
|
26
|
-
const [{ activities, truncated }, standings] = await Promise.all([counted(), groupStandings(groupStore(ports.storage), sessionID)]);
|
|
18
|
+
const [looked, standings] = await Promise.all([lookUp(ports, sessionID), groupStandings(groupStore(ports.storage), sessionID)]);
|
|
19
|
+
const activities = looked.map(activity);
|
|
27
20
|
const count = (kind) => activities.filter((item) => item === kind).length;
|
|
28
21
|
return {
|
|
29
22
|
running: count("running"),
|
|
30
23
|
waiting: count("waiting"),
|
|
31
24
|
idle: count("idle"),
|
|
32
25
|
groups: standings.map(({ name, reported, members }) => ({ name, reported, members })),
|
|
33
|
-
...(truncated ? { truncated: ports.limits.maxTotal } : {}),
|
|
34
26
|
};
|
|
35
27
|
}
|
package/dist/tree/text.js
CHANGED
|
@@ -160,7 +160,10 @@ export function cleanupText(result) {
|
|
|
160
160
|
export function treeText(tree) {
|
|
161
161
|
if (!tree.sessions.length)
|
|
162
162
|
return "No sessions started with courier_spawn.";
|
|
163
|
-
|
|
163
|
+
if (tree.truncated === undefined)
|
|
164
|
+
return JSON.stringify(tree, null, 2);
|
|
165
|
+
const older = tree.truncated === 1 ? "1 older session is" : `${tree.truncated} older sessions are`;
|
|
166
|
+
const note = `\n${older} not listed: at most maxTotal are, the live ones first, then the newest; courier_tree on a listed session lists what is under it.`;
|
|
164
167
|
return JSON.stringify(tree, null, 2) + note;
|
|
165
168
|
}
|
|
166
169
|
/** What courier_stop did to each session, and to the messages and worktrees. */
|
package/dist/tree/tools.js
CHANGED
|
@@ -128,7 +128,8 @@ export function addTreeTools(tools, ports) {
|
|
|
128
128
|
options: { codemode: false },
|
|
129
129
|
description: "List the whole tree of sessions under this one (or under sessionID): every session started with courier_spawn " +
|
|
130
130
|
"from it, directly or through others, each with its depth, what courier_children shows, and whether it still " +
|
|
131
|
-
"owes a report, sent progress, or ended without one. For a one-off look, not for waiting
|
|
131
|
+
"owes a report, sent progress, or ended without one. For a one-off look, not for waiting. A long tree lists at most " +
|
|
132
|
+
"maxTotal sessions, the live ones first, then the newest, and says how many older ones are left out.",
|
|
132
133
|
input: TreeInput,
|
|
133
134
|
execute: async (input, context) => {
|
|
134
135
|
const result = await tree(ports.courier, input.sessionID || context.sessionID).catch(rethrow("courier_tree"));
|
package/dist/tree/tui.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Plugin } from "@opencode/plugin/tui";
|
|
2
|
-
import { type Row, type Stopped, type Summary, type Wait } from "./rpc.js";
|
|
2
|
+
import { type Forgotten, type Row, type Stopped, type Summary, type Wait } from "./rpc.js";
|
|
3
3
|
type Context = Plugin.Context;
|
|
4
|
+
/** The events after which a summary may read differently: a turn started or ended, a request or form, a session made or removed. */
|
|
5
|
+
export declare const CHANGES: Set<string>;
|
|
4
6
|
/** How long after the first of a burst of changes the entry asks the server again. */
|
|
5
7
|
export declare const SETTLE_MS = 250;
|
|
6
8
|
/** The panel's settle: each of its asks reads every row's messages, so a busy tree is asked at most once a second. */
|
|
@@ -9,8 +11,11 @@ export declare const PANEL_SETTLE_MS = 1000;
|
|
|
9
11
|
export declare const PANEL = "courier-tree";
|
|
10
12
|
/** How often the panel redraws its running times and how long ago each last tool call was. */
|
|
11
13
|
export declare const TICK_MS = 1000;
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
+
/**
|
|
15
|
+
* The status entry's text, such as "courier 1 waiting on you · 2 running · group pair 1/2"; empty when there is nothing to show.
|
|
16
|
+
* Within `maxWidth` it keeps whole parts, most important first, and counts the groups it drops: "· +2 groups".
|
|
17
|
+
*/
|
|
18
|
+
export declare function summaryLine(summary: Summary, maxWidth?: number): string;
|
|
14
19
|
/** A span of time, coarsest first: "45s", "3m 05s", "2h 07m". */
|
|
15
20
|
export declare function duration(ms: number): string;
|
|
16
21
|
/** How many of a session's children have reported, out of those it started, among the rows read. */
|
|
@@ -23,7 +28,7 @@ export declare function bar({ reported, started }: {
|
|
|
23
28
|
reported: number;
|
|
24
29
|
started: number;
|
|
25
30
|
}, width?: number): string;
|
|
26
|
-
/** What a paused session waits on, such as "asks permission: shell echo hi". */
|
|
31
|
+
/** What a paused session waits on, such as "asks permission: shell echo hi" or "shows a form: Web Search". */
|
|
27
32
|
export declare function waitLine(wait: Wait): string;
|
|
28
33
|
/** What a row's session is doing, its report and its group standing: "idle · reported done · group pair held". */
|
|
29
34
|
export declare function statusLine(row: Row): string;
|
|
@@ -38,6 +43,8 @@ export declare function detailLines(row: Row, rows: ReadonlyArray<Row>, now: num
|
|
|
38
43
|
export declare function addTreeStatus(ctx: Context, onWaiting?: (sessionID: string) => void): () => void;
|
|
39
44
|
/** The toast after a stop: how many sessions were interrupted, and how many scheduled messages were cancelled. */
|
|
40
45
|
export declare function stoppedLine({ stopped, cancelled }: Stopped): string;
|
|
46
|
+
/** The toast after a forget, as courier_cleanup reports it: forgotten, its worktree removed or already gone, or kept and why. */
|
|
47
|
+
export declare function forgottenLine(title: string, result: Forgotten): string;
|
|
41
48
|
/** The usage the `/courier` command shows for an input it does not know. */
|
|
42
49
|
export declare const USAGE = "/courier tree opens the session tree; /courier stop [session] stops a session and those under it";
|
|
43
50
|
/**
|