opencode-courier 0.5.0 → 0.7.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 +39 -30
- package/dist/index.js +9 -5
- 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 +31 -4
- package/dist/tree/index.d.ts +2 -1
- package/dist/tree/index.js +2 -1
- package/dist/tree/panel.d.ts +7 -2
- package/dist/tree/panel.js +29 -17
- package/dist/tree/ports.d.ts +36 -0
- package/dist/tree/roster.d.ts +5 -0
- package/dist/tree/roster.js +5 -3
- package/dist/tree/rpc-handlers.d.ts +55 -6
- package/dist/tree/rpc-handlers.js +30 -1
- package/dist/tree/rpc.d.ts +111 -22
- package/dist/tree/rpc.js +30 -9
- package/dist/tree/stop.js +2 -0
- package/dist/tree/store.d.ts +4 -1
- package/dist/tree/store.js +51 -0
- 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 +17 -16
- package/dist/tree/text.js +4 -1
- package/dist/tree/tools.js +2 -1
- package/dist/tree/tui.d.ts +17 -6
- package/dist/tree/wake.d.ts +68 -0
- package/dist/tree/wake.js +119 -0
- package/dist/tui.js +617 -197
- package/package.json +1 -1
|
@@ -21,7 +21,7 @@ export declare function registerTreeRpc(rpc: Pick<Plugin.Context["rpc"], "regist
|
|
|
21
21
|
readonly members: number;
|
|
22
22
|
}[];
|
|
23
23
|
readonly waiting: number;
|
|
24
|
-
readonly
|
|
24
|
+
readonly stalled?: number | undefined;
|
|
25
25
|
}, {
|
|
26
26
|
readonly running: number;
|
|
27
27
|
readonly idle: number;
|
|
@@ -31,17 +31,17 @@ export declare function registerTreeRpc(rpc: Pick<Plugin.Context["rpc"], "regist
|
|
|
31
31
|
readonly members: number;
|
|
32
32
|
}[];
|
|
33
33
|
readonly waiting: number;
|
|
34
|
-
readonly
|
|
34
|
+
readonly stalled?: number | undefined;
|
|
35
35
|
}> & import("effect/Schema").Struct<{
|
|
36
36
|
readonly running: import("effect/Schema").Int;
|
|
37
37
|
readonly waiting: import("effect/Schema").Int;
|
|
38
38
|
readonly idle: import("effect/Schema").Int;
|
|
39
|
+
readonly stalled: import("effect/Schema").optionalKey<import("effect/Schema").Int>;
|
|
39
40
|
readonly groups: import("effect/Schema").$Array<import("effect/Schema").Struct<{
|
|
40
41
|
readonly name: import("effect/Schema").String;
|
|
41
42
|
readonly reported: import("effect/Schema").Int;
|
|
42
43
|
readonly members: import("effect/Schema").Int;
|
|
43
44
|
}>>;
|
|
44
|
-
readonly truncated: import("effect/Schema").optionalKey<import("effect/Schema").Int>;
|
|
45
45
|
}>;
|
|
46
46
|
};
|
|
47
47
|
readonly tree: {
|
|
@@ -60,7 +60,7 @@ export declare function registerTreeRpc(rpc: Pick<Plugin.Context["rpc"], "regist
|
|
|
60
60
|
readonly depth: number;
|
|
61
61
|
readonly created: number;
|
|
62
62
|
readonly isolated: boolean;
|
|
63
|
-
readonly state: "running" | "idle" | "gone" | "waiting";
|
|
63
|
+
readonly state: "running" | "idle" | "gone" | "stalled" | "waiting";
|
|
64
64
|
readonly waits: readonly ({
|
|
65
65
|
readonly type: "permission";
|
|
66
66
|
readonly action: string;
|
|
@@ -68,17 +68,22 @@ export declare function registerTreeRpc(rpc: Pick<Plugin.Context["rpc"], "regist
|
|
|
68
68
|
} | {
|
|
69
69
|
readonly type: "question";
|
|
70
70
|
readonly question: string;
|
|
71
|
+
} | {
|
|
72
|
+
readonly type: "form";
|
|
73
|
+
readonly title: string;
|
|
71
74
|
})[];
|
|
72
75
|
readonly group?: {
|
|
73
76
|
readonly name: string;
|
|
74
77
|
readonly standing: string;
|
|
75
78
|
} | undefined;
|
|
79
|
+
readonly stopped?: boolean | undefined;
|
|
76
80
|
readonly idle?: number | undefined;
|
|
77
81
|
readonly report?: {
|
|
78
82
|
readonly progressed: boolean;
|
|
79
83
|
readonly state: "reported" | "ended" | "owed";
|
|
80
84
|
readonly status?: string | undefined;
|
|
81
85
|
} | undefined;
|
|
86
|
+
readonly stalled?: number | undefined;
|
|
82
87
|
readonly outcome?: "failed" | "interrupted" | "succeeded" | undefined;
|
|
83
88
|
readonly tool?: {
|
|
84
89
|
readonly name: string;
|
|
@@ -86,6 +91,7 @@ export declare function registerTreeRpc(rpc: Pick<Plugin.Context["rpc"], "regist
|
|
|
86
91
|
} | undefined;
|
|
87
92
|
readonly cost?: number | undefined;
|
|
88
93
|
}[];
|
|
94
|
+
readonly stalled?: number | undefined;
|
|
89
95
|
readonly truncated?: number | undefined;
|
|
90
96
|
}, {
|
|
91
97
|
readonly rows: readonly {
|
|
@@ -95,7 +101,7 @@ export declare function registerTreeRpc(rpc: Pick<Plugin.Context["rpc"], "regist
|
|
|
95
101
|
readonly depth: number;
|
|
96
102
|
readonly created: number;
|
|
97
103
|
readonly isolated: boolean;
|
|
98
|
-
readonly state: "running" | "idle" | "gone" | "waiting";
|
|
104
|
+
readonly state: "running" | "idle" | "gone" | "stalled" | "waiting";
|
|
99
105
|
readonly waits: readonly ({
|
|
100
106
|
readonly type: "permission";
|
|
101
107
|
readonly action: string;
|
|
@@ -103,17 +109,22 @@ export declare function registerTreeRpc(rpc: Pick<Plugin.Context["rpc"], "regist
|
|
|
103
109
|
} | {
|
|
104
110
|
readonly type: "question";
|
|
105
111
|
readonly question: string;
|
|
112
|
+
} | {
|
|
113
|
+
readonly type: "form";
|
|
114
|
+
readonly title: string;
|
|
106
115
|
})[];
|
|
107
116
|
readonly group?: {
|
|
108
117
|
readonly name: string;
|
|
109
118
|
readonly standing: string;
|
|
110
119
|
} | undefined;
|
|
120
|
+
readonly stopped?: boolean | undefined;
|
|
111
121
|
readonly idle?: number | undefined;
|
|
112
122
|
readonly report?: {
|
|
113
123
|
readonly progressed: boolean;
|
|
114
124
|
readonly state: "reported" | "ended" | "owed";
|
|
115
125
|
readonly status?: string | undefined;
|
|
116
126
|
} | undefined;
|
|
127
|
+
readonly stalled?: number | undefined;
|
|
117
128
|
readonly outcome?: "failed" | "interrupted" | "succeeded" | undefined;
|
|
118
129
|
readonly tool?: {
|
|
119
130
|
readonly name: string;
|
|
@@ -121,6 +132,7 @@ export declare function registerTreeRpc(rpc: Pick<Plugin.Context["rpc"], "regist
|
|
|
121
132
|
} | undefined;
|
|
122
133
|
readonly cost?: number | undefined;
|
|
123
134
|
}[];
|
|
135
|
+
readonly stalled?: number | undefined;
|
|
124
136
|
readonly truncated?: number | undefined;
|
|
125
137
|
}> & import("effect/Schema").Struct<{
|
|
126
138
|
readonly rows: import("effect/Schema").$Array<import("effect/Schema").Struct<{
|
|
@@ -128,8 +140,10 @@ export declare function registerTreeRpc(rpc: Pick<Plugin.Context["rpc"], "regist
|
|
|
128
140
|
readonly parentID: import("effect/Schema").String;
|
|
129
141
|
readonly title: import("effect/Schema").String;
|
|
130
142
|
readonly depth: import("effect/Schema").Int;
|
|
131
|
-
readonly state: import("effect/Schema").Literals<readonly ["running", "waiting", "idle", "gone"]>;
|
|
143
|
+
readonly state: import("effect/Schema").Literals<readonly ["running", "waiting", "idle", "stalled", "gone"]>;
|
|
144
|
+
readonly stalled: import("effect/Schema").optionalKey<import("effect/Schema").Number>;
|
|
132
145
|
readonly outcome: import("effect/Schema").optionalKey<import("effect/Schema").Literals<readonly ["succeeded", "failed", "interrupted"]>>;
|
|
146
|
+
readonly stopped: import("effect/Schema").optionalKey<import("effect/Schema").Boolean>;
|
|
133
147
|
readonly report: import("effect/Schema").optionalKey<import("effect/Schema").Struct<{
|
|
134
148
|
readonly state: import("effect/Schema").Literals<readonly ["owed", "reported", "ended"]>;
|
|
135
149
|
readonly status: import("effect/Schema").optionalKey<import("effect/Schema").String>;
|
|
@@ -154,9 +168,13 @@ export declare function registerTreeRpc(rpc: Pick<Plugin.Context["rpc"], "regist
|
|
|
154
168
|
}>, import("effect/Schema").Struct<{
|
|
155
169
|
readonly type: import("effect/Schema").Literal<"question">;
|
|
156
170
|
readonly question: import("effect/Schema").String;
|
|
171
|
+
}>, import("effect/Schema").Struct<{
|
|
172
|
+
readonly type: import("effect/Schema").Literal<"form">;
|
|
173
|
+
readonly title: import("effect/Schema").String;
|
|
157
174
|
}>]>>;
|
|
158
175
|
}>>;
|
|
159
176
|
readonly truncated: import("effect/Schema").optionalKey<import("effect/Schema").Int>;
|
|
177
|
+
readonly stalled: import("effect/Schema").optionalKey<import("effect/Schema").Number>;
|
|
160
178
|
}>;
|
|
161
179
|
};
|
|
162
180
|
readonly stop: {
|
|
@@ -196,6 +214,37 @@ export declare function registerTreeRpc(rpc: Pick<Plugin.Context["rpc"], "regist
|
|
|
196
214
|
readonly refused: import("effect/StandardSchema").StandardSchemaV1<{}, {}> & import("effect/Schema").Struct<{}>;
|
|
197
215
|
};
|
|
198
216
|
};
|
|
217
|
+
readonly cleanup: {
|
|
218
|
+
readonly input: import("effect/StandardSchema").StandardSchemaV1<{
|
|
219
|
+
readonly sessionID: string;
|
|
220
|
+
readonly by: string;
|
|
221
|
+
}, {
|
|
222
|
+
readonly sessionID: string;
|
|
223
|
+
readonly by: string;
|
|
224
|
+
}> & import("effect/Schema").Struct<{
|
|
225
|
+
readonly sessionID: import("effect/Schema").String;
|
|
226
|
+
readonly by: import("effect/Schema").String;
|
|
227
|
+
}>;
|
|
228
|
+
readonly output: import("effect/StandardSchema").StandardSchemaV1<{
|
|
229
|
+
readonly outcome: "removed" | "gone" | "forgotten";
|
|
230
|
+
} | {
|
|
231
|
+
readonly outcome: "kept";
|
|
232
|
+
readonly reason: string;
|
|
233
|
+
}, {
|
|
234
|
+
readonly outcome: "removed" | "gone" | "forgotten";
|
|
235
|
+
} | {
|
|
236
|
+
readonly outcome: "kept";
|
|
237
|
+
readonly reason: string;
|
|
238
|
+
}> & import("effect/Schema").Union<readonly [import("effect/Schema").Struct<{
|
|
239
|
+
readonly outcome: import("effect/Schema").Literals<readonly ["forgotten", "removed", "gone"]>;
|
|
240
|
+
}>, import("effect/Schema").Struct<{
|
|
241
|
+
readonly outcome: import("effect/Schema").Literal<"kept">;
|
|
242
|
+
readonly reason: import("effect/Schema").String;
|
|
243
|
+
}>]>;
|
|
244
|
+
readonly errors: {
|
|
245
|
+
readonly refused: import("effect/StandardSchema").StandardSchemaV1<{}, {}> & import("effect/Schema").Struct<{}>;
|
|
246
|
+
};
|
|
247
|
+
};
|
|
199
248
|
};
|
|
200
249
|
readonly events: {};
|
|
201
250
|
}>>;
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
import { describeFailure } from "../kernel/protocol.js";
|
|
2
|
+
import { isNotFound } from "../platform/json.js";
|
|
3
|
+
import { cleanup } from "./cleanup.js";
|
|
1
4
|
import { panel } from "./panel.js";
|
|
2
5
|
import { treeRpc } from "./rpc.js";
|
|
3
6
|
import { stop } from "./stop.js";
|
|
7
|
+
import { childStore } from "./store.js";
|
|
4
8
|
import { summary } from "./summary.js";
|
|
5
9
|
/** Serves the tree's RPC at the plugin's location, through the same use cases as the tools; disposed with the plugin. */
|
|
6
10
|
export function registerTreeRpc(rpc, ports) {
|
|
11
|
+
const refused = (cause) => (cause instanceof Error ? cause.message : String(cause));
|
|
7
12
|
return rpc.register(treeRpc, {
|
|
8
13
|
summary: ({ sessionID }) => summary(ports.courier, sessionID),
|
|
9
14
|
tree: ({ sessionID }) => panel(ports.courier, sessionID),
|
|
@@ -13,8 +18,32 @@ export function registerTreeRpc(rpc, ports) {
|
|
|
13
18
|
return { stopped: stopped.map(({ sessionID, title, outcome }) => ({ sessionID, title, outcome })), cancelled: cancelled.length };
|
|
14
19
|
}
|
|
15
20
|
catch (cause) {
|
|
16
|
-
return error("refused",
|
|
21
|
+
return error("refused", refused(cause), {});
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
cleanup: async ({ sessionID, by }, { error }) => {
|
|
25
|
+
try {
|
|
26
|
+
return await forget(ports, by, sessionID);
|
|
27
|
+
}
|
|
28
|
+
catch (cause) {
|
|
29
|
+
return error("refused", refused(cause), {});
|
|
17
30
|
}
|
|
18
31
|
},
|
|
19
32
|
});
|
|
20
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Forgets a session OpenCode no longer knows as courier_cleanup called from its own parent, once `by` is found above it,
|
|
36
|
+
* as courier_stop checks. A session OpenCode still has, or cannot say it lost, is refused: forgetting it loses its report.
|
|
37
|
+
*/
|
|
38
|
+
async function forget(ports, by, sessionID) {
|
|
39
|
+
const chain = await childStore(ports.courier.storage).lineage(sessionID);
|
|
40
|
+
if (!chain.length)
|
|
41
|
+
throw new Error(`${sessionID} was not started with courier_spawn, so there is nothing to forget.`);
|
|
42
|
+
if (!chain.some((entry) => entry.parentID === by))
|
|
43
|
+
throw new Error(`${by} is not above ${sessionID}: only a session above it, in the line of sessions that started it with courier_spawn, can forget it.`);
|
|
44
|
+
const known = await ports.courier.session.get({ sessionID }).then(() => `${sessionID} is still known to OpenCode: only a gone session is forgotten here.`, (error) => (isNotFound(error) ? undefined : describeFailure("session.get", error).message));
|
|
45
|
+
if (known)
|
|
46
|
+
throw new Error(known);
|
|
47
|
+
const result = await cleanup(ports.cleanup, chain[0].parentID, { sessionID });
|
|
48
|
+
return result.outcome === "kept" ? { outcome: "kept", reason: result.reason } : { outcome: result.outcome };
|
|
49
|
+
}
|
package/dist/tree/rpc.d.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
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;
|
|
10
|
+
/** Left a courier message waiting while idle, and did not take it once woken again; the session itself counts too. Absent at 0. */
|
|
11
|
+
readonly stalled: Schema.optionalKey<Schema.Int>;
|
|
10
12
|
readonly groups: Schema.$Array<Schema.Struct<{
|
|
11
13
|
readonly name: Schema.String;
|
|
12
14
|
readonly reported: Schema.Int;
|
|
13
15
|
readonly members: Schema.Int;
|
|
14
16
|
}>>;
|
|
15
|
-
/** Set when the subtree had more sessions than `maxTotal`, which were not counted. */
|
|
16
|
-
readonly truncated: Schema.optionalKey<Schema.Int>;
|
|
17
17
|
}>;
|
|
18
18
|
export type Summary = typeof Summary.Type;
|
|
19
|
-
/** A request a session waits on until the person answers it: a permission request,
|
|
19
|
+
/** A request a session waits on until the person answers it: a permission request, its first question, or a form it shows. */
|
|
20
20
|
declare const Wait: Schema.Union<readonly [Schema.Struct<{
|
|
21
21
|
readonly type: Schema.Literal<"permission">;
|
|
22
22
|
readonly action: Schema.String;
|
|
@@ -24,6 +24,9 @@ declare const Wait: Schema.Union<readonly [Schema.Struct<{
|
|
|
24
24
|
}>, Schema.Struct<{
|
|
25
25
|
readonly type: Schema.Literal<"question">;
|
|
26
26
|
readonly question: Schema.String;
|
|
27
|
+
}>, Schema.Struct<{
|
|
28
|
+
readonly type: Schema.Literal<"form">;
|
|
29
|
+
readonly title: Schema.String;
|
|
27
30
|
}>]>;
|
|
28
31
|
/** One session of the tree panel: what courier_tree shows of it, and what it is doing, in epoch milliseconds. */
|
|
29
32
|
declare const Row: Schema.Struct<{
|
|
@@ -32,10 +35,17 @@ declare const Row: Schema.Struct<{
|
|
|
32
35
|
readonly title: Schema.String;
|
|
33
36
|
/** A child of the panel's session is at depth 1. */
|
|
34
37
|
readonly depth: Schema.Int;
|
|
35
|
-
/**
|
|
36
|
-
|
|
38
|
+
/**
|
|
39
|
+
* `waiting` on a request to the person or a form it shows them; `stalled` when a courier message waits in its inbox and
|
|
40
|
+
* waking it again did not start a turn; `gone` when OpenCode no longer knows it.
|
|
41
|
+
*/
|
|
42
|
+
readonly state: Schema.Literals<readonly ["running", "waiting", "idle", "stalled", "gone"]>;
|
|
43
|
+
/** Since when its oldest message that did not wake it has waited, when it is stalled. */
|
|
44
|
+
readonly stalled: Schema.optionalKey<Schema.Number>;
|
|
37
45
|
/** How its last turn ended. */
|
|
38
46
|
readonly outcome: Schema.optionalKey<Schema.Literals<readonly ["succeeded", "failed", "interrupted"]>>;
|
|
47
|
+
/** Set when courier_stop stopped it since its last prompt. */
|
|
48
|
+
readonly stopped: Schema.optionalKey<Schema.Boolean>;
|
|
39
49
|
/** Its report since its last prompt: still owed, arrived (held with its group or delivered), or its turn ended without one. */
|
|
40
50
|
readonly report: Schema.optionalKey<Schema.Struct<{
|
|
41
51
|
readonly state: Schema.Literals<readonly ["owed", "reported", "ended"]>;
|
|
@@ -65,9 +75,12 @@ declare const Row: Schema.Struct<{
|
|
|
65
75
|
}>, Schema.Struct<{
|
|
66
76
|
readonly type: Schema.Literal<"question">;
|
|
67
77
|
readonly question: Schema.String;
|
|
78
|
+
}>, Schema.Struct<{
|
|
79
|
+
readonly type: Schema.Literal<"form">;
|
|
80
|
+
readonly title: Schema.String;
|
|
68
81
|
}>]>>;
|
|
69
82
|
}>;
|
|
70
|
-
/** The sessions under a session, as courier_tree
|
|
83
|
+
/** The sessions under a session, as courier_tree lists them, in the order a tree is drawn. */
|
|
71
84
|
declare const Tree: Schema.Struct<{
|
|
72
85
|
readonly rows: Schema.$Array<Schema.Struct<{
|
|
73
86
|
readonly sessionID: Schema.String;
|
|
@@ -75,10 +88,17 @@ declare const Tree: Schema.Struct<{
|
|
|
75
88
|
readonly title: Schema.String;
|
|
76
89
|
/** A child of the panel's session is at depth 1. */
|
|
77
90
|
readonly depth: Schema.Int;
|
|
78
|
-
/**
|
|
79
|
-
|
|
91
|
+
/**
|
|
92
|
+
* `waiting` on a request to the person or a form it shows them; `stalled` when a courier message waits in its inbox and
|
|
93
|
+
* waking it again did not start a turn; `gone` when OpenCode no longer knows it.
|
|
94
|
+
*/
|
|
95
|
+
readonly state: Schema.Literals<readonly ["running", "waiting", "idle", "stalled", "gone"]>;
|
|
96
|
+
/** Since when its oldest message that did not wake it has waited, when it is stalled. */
|
|
97
|
+
readonly stalled: Schema.optionalKey<Schema.Number>;
|
|
80
98
|
/** How its last turn ended. */
|
|
81
99
|
readonly outcome: Schema.optionalKey<Schema.Literals<readonly ["succeeded", "failed", "interrupted"]>>;
|
|
100
|
+
/** Set when courier_stop stopped it since its last prompt. */
|
|
101
|
+
readonly stopped: Schema.optionalKey<Schema.Boolean>;
|
|
82
102
|
/** Its report since its last prompt: still owed, arrived (held with its group or delivered), or its turn ended without one. */
|
|
83
103
|
readonly report: Schema.optionalKey<Schema.Struct<{
|
|
84
104
|
readonly state: Schema.Literals<readonly ["owed", "reported", "ended"]>;
|
|
@@ -108,10 +128,15 @@ declare const Tree: Schema.Struct<{
|
|
|
108
128
|
}>, Schema.Struct<{
|
|
109
129
|
readonly type: Schema.Literal<"question">;
|
|
110
130
|
readonly question: Schema.String;
|
|
131
|
+
}>, Schema.Struct<{
|
|
132
|
+
readonly type: Schema.Literal<"form">;
|
|
133
|
+
readonly title: Schema.String;
|
|
111
134
|
}>]>>;
|
|
112
135
|
}>>;
|
|
113
|
-
/**
|
|
136
|
+
/** How many older sessions the listing left out, when it had more than `maxTotal`: the live ones come first, then the newest. */
|
|
114
137
|
readonly truncated: Schema.optionalKey<Schema.Int>;
|
|
138
|
+
/** Since when a courier message has waited in the panel's own session, when that session is stalled. */
|
|
139
|
+
readonly stalled: Schema.optionalKey<Schema.Number>;
|
|
115
140
|
}>;
|
|
116
141
|
export type Row = typeof Row.Type;
|
|
117
142
|
export type Tree = typeof Tree.Type;
|
|
@@ -127,6 +152,14 @@ declare const Stopped: Schema.Struct<{
|
|
|
127
152
|
readonly cancelled: Schema.Int;
|
|
128
153
|
}>;
|
|
129
154
|
export type Stopped = typeof Stopped.Type;
|
|
155
|
+
/** What courier_cleanup did: forgot it, removed its worktree, found that already gone, or kept the worktree, saying why. */
|
|
156
|
+
declare const Forgotten: Schema.Union<readonly [Schema.Struct<{
|
|
157
|
+
readonly outcome: Schema.Literals<readonly ["forgotten", "removed", "gone"]>;
|
|
158
|
+
}>, Schema.Struct<{
|
|
159
|
+
readonly outcome: Schema.Literal<"kept">;
|
|
160
|
+
readonly reason: Schema.String;
|
|
161
|
+
}>]>;
|
|
162
|
+
export type Forgotten = typeof Forgotten.Type;
|
|
130
163
|
export declare const treeRpc: {
|
|
131
164
|
readonly id: "courier";
|
|
132
165
|
readonly methods: {
|
|
@@ -147,7 +180,7 @@ export declare const treeRpc: {
|
|
|
147
180
|
readonly members: number;
|
|
148
181
|
}[];
|
|
149
182
|
readonly waiting: number;
|
|
150
|
-
readonly
|
|
183
|
+
readonly stalled?: number | undefined;
|
|
151
184
|
}, {
|
|
152
185
|
readonly running: number;
|
|
153
186
|
readonly idle: number;
|
|
@@ -157,21 +190,21 @@ export declare const treeRpc: {
|
|
|
157
190
|
readonly members: number;
|
|
158
191
|
}[];
|
|
159
192
|
readonly waiting: number;
|
|
160
|
-
readonly
|
|
193
|
+
readonly stalled?: number | undefined;
|
|
161
194
|
}> & Schema.Struct<{
|
|
162
|
-
/** Running, and waiting on no request. */
|
|
195
|
+
/** Running, and waiting on no request or form. */
|
|
163
196
|
readonly running: Schema.Int;
|
|
164
|
-
/** Waiting on a permission request or a
|
|
197
|
+
/** Waiting on a permission request, a question or a form it shows, which go to the person. */
|
|
165
198
|
readonly waiting: Schema.Int;
|
|
166
199
|
/** Not running: done, or waiting for a message. */
|
|
167
200
|
readonly idle: Schema.Int;
|
|
201
|
+
/** Left a courier message waiting while idle, and did not take it once woken again; the session itself counts too. Absent at 0. */
|
|
202
|
+
readonly stalled: Schema.optionalKey<Schema.Int>;
|
|
168
203
|
readonly groups: Schema.$Array<Schema.Struct<{
|
|
169
204
|
readonly name: Schema.String;
|
|
170
205
|
readonly reported: Schema.Int;
|
|
171
206
|
readonly members: Schema.Int;
|
|
172
207
|
}>>;
|
|
173
|
-
/** Set when the subtree had more sessions than `maxTotal`, which were not counted. */
|
|
174
|
-
readonly truncated: Schema.optionalKey<Schema.Int>;
|
|
175
208
|
}>;
|
|
176
209
|
};
|
|
177
210
|
readonly tree: {
|
|
@@ -190,7 +223,7 @@ export declare const treeRpc: {
|
|
|
190
223
|
readonly depth: number;
|
|
191
224
|
readonly created: number;
|
|
192
225
|
readonly isolated: boolean;
|
|
193
|
-
readonly state: "running" | "idle" | "gone" | "waiting";
|
|
226
|
+
readonly state: "running" | "idle" | "gone" | "stalled" | "waiting";
|
|
194
227
|
readonly waits: readonly ({
|
|
195
228
|
readonly type: "permission";
|
|
196
229
|
readonly action: string;
|
|
@@ -198,17 +231,22 @@ export declare const treeRpc: {
|
|
|
198
231
|
} | {
|
|
199
232
|
readonly type: "question";
|
|
200
233
|
readonly question: string;
|
|
234
|
+
} | {
|
|
235
|
+
readonly type: "form";
|
|
236
|
+
readonly title: string;
|
|
201
237
|
})[];
|
|
202
238
|
readonly group?: {
|
|
203
239
|
readonly name: string;
|
|
204
240
|
readonly standing: string;
|
|
205
241
|
} | undefined;
|
|
242
|
+
readonly stopped?: boolean | undefined;
|
|
206
243
|
readonly idle?: number | undefined;
|
|
207
244
|
readonly report?: {
|
|
208
245
|
readonly progressed: boolean;
|
|
209
246
|
readonly state: "reported" | "ended" | "owed";
|
|
210
247
|
readonly status?: string | undefined;
|
|
211
248
|
} | undefined;
|
|
249
|
+
readonly stalled?: number | undefined;
|
|
212
250
|
readonly outcome?: "failed" | "interrupted" | "succeeded" | undefined;
|
|
213
251
|
readonly tool?: {
|
|
214
252
|
readonly name: string;
|
|
@@ -216,6 +254,7 @@ export declare const treeRpc: {
|
|
|
216
254
|
} | undefined;
|
|
217
255
|
readonly cost?: number | undefined;
|
|
218
256
|
}[];
|
|
257
|
+
readonly stalled?: number | undefined;
|
|
219
258
|
readonly truncated?: number | undefined;
|
|
220
259
|
}, {
|
|
221
260
|
readonly rows: readonly {
|
|
@@ -225,7 +264,7 @@ export declare const treeRpc: {
|
|
|
225
264
|
readonly depth: number;
|
|
226
265
|
readonly created: number;
|
|
227
266
|
readonly isolated: boolean;
|
|
228
|
-
readonly state: "running" | "idle" | "gone" | "waiting";
|
|
267
|
+
readonly state: "running" | "idle" | "gone" | "stalled" | "waiting";
|
|
229
268
|
readonly waits: readonly ({
|
|
230
269
|
readonly type: "permission";
|
|
231
270
|
readonly action: string;
|
|
@@ -233,17 +272,22 @@ export declare const treeRpc: {
|
|
|
233
272
|
} | {
|
|
234
273
|
readonly type: "question";
|
|
235
274
|
readonly question: string;
|
|
275
|
+
} | {
|
|
276
|
+
readonly type: "form";
|
|
277
|
+
readonly title: string;
|
|
236
278
|
})[];
|
|
237
279
|
readonly group?: {
|
|
238
280
|
readonly name: string;
|
|
239
281
|
readonly standing: string;
|
|
240
282
|
} | undefined;
|
|
283
|
+
readonly stopped?: boolean | undefined;
|
|
241
284
|
readonly idle?: number | undefined;
|
|
242
285
|
readonly report?: {
|
|
243
286
|
readonly progressed: boolean;
|
|
244
287
|
readonly state: "reported" | "ended" | "owed";
|
|
245
288
|
readonly status?: string | undefined;
|
|
246
289
|
} | undefined;
|
|
290
|
+
readonly stalled?: number | undefined;
|
|
247
291
|
readonly outcome?: "failed" | "interrupted" | "succeeded" | undefined;
|
|
248
292
|
readonly tool?: {
|
|
249
293
|
readonly name: string;
|
|
@@ -251,6 +295,7 @@ export declare const treeRpc: {
|
|
|
251
295
|
} | undefined;
|
|
252
296
|
readonly cost?: number | undefined;
|
|
253
297
|
}[];
|
|
298
|
+
readonly stalled?: number | undefined;
|
|
254
299
|
readonly truncated?: number | undefined;
|
|
255
300
|
}> & Schema.Struct<{
|
|
256
301
|
readonly rows: Schema.$Array<Schema.Struct<{
|
|
@@ -259,10 +304,17 @@ export declare const treeRpc: {
|
|
|
259
304
|
readonly title: Schema.String;
|
|
260
305
|
/** A child of the panel's session is at depth 1. */
|
|
261
306
|
readonly depth: Schema.Int;
|
|
262
|
-
/**
|
|
263
|
-
|
|
307
|
+
/**
|
|
308
|
+
* `waiting` on a request to the person or a form it shows them; `stalled` when a courier message waits in its inbox and
|
|
309
|
+
* waking it again did not start a turn; `gone` when OpenCode no longer knows it.
|
|
310
|
+
*/
|
|
311
|
+
readonly state: Schema.Literals<readonly ["running", "waiting", "idle", "stalled", "gone"]>;
|
|
312
|
+
/** Since when its oldest message that did not wake it has waited, when it is stalled. */
|
|
313
|
+
readonly stalled: Schema.optionalKey<Schema.Number>;
|
|
264
314
|
/** How its last turn ended. */
|
|
265
315
|
readonly outcome: Schema.optionalKey<Schema.Literals<readonly ["succeeded", "failed", "interrupted"]>>;
|
|
316
|
+
/** Set when courier_stop stopped it since its last prompt. */
|
|
317
|
+
readonly stopped: Schema.optionalKey<Schema.Boolean>;
|
|
266
318
|
/** Its report since its last prompt: still owed, arrived (held with its group or delivered), or its turn ended without one. */
|
|
267
319
|
readonly report: Schema.optionalKey<Schema.Struct<{
|
|
268
320
|
readonly state: Schema.Literals<readonly ["owed", "reported", "ended"]>;
|
|
@@ -292,10 +344,15 @@ export declare const treeRpc: {
|
|
|
292
344
|
}>, Schema.Struct<{
|
|
293
345
|
readonly type: Schema.Literal<"question">;
|
|
294
346
|
readonly question: Schema.String;
|
|
347
|
+
}>, Schema.Struct<{
|
|
348
|
+
readonly type: Schema.Literal<"form">;
|
|
349
|
+
readonly title: Schema.String;
|
|
295
350
|
}>]>>;
|
|
296
351
|
}>>;
|
|
297
|
-
/**
|
|
352
|
+
/** How many older sessions the listing left out, when it had more than `maxTotal`: the live ones come first, then the newest. */
|
|
298
353
|
readonly truncated: Schema.optionalKey<Schema.Int>;
|
|
354
|
+
/** Since when a courier message has waited in the panel's own session, when that session is stalled. */
|
|
355
|
+
readonly stalled: Schema.optionalKey<Schema.Number>;
|
|
299
356
|
}>;
|
|
300
357
|
};
|
|
301
358
|
/** Stops `sessionID` and everything under it, as courier_stop called from `by`, which must be above it. */
|
|
@@ -337,6 +394,38 @@ export declare const treeRpc: {
|
|
|
337
394
|
readonly refused: import("effect/StandardSchema").StandardSchemaV1<{}, {}> & Schema.Struct<{}>;
|
|
338
395
|
};
|
|
339
396
|
};
|
|
397
|
+
/** Forgets `sessionID` as courier_cleanup called from its parent, without `force`; `by` must be above it. */
|
|
398
|
+
readonly cleanup: {
|
|
399
|
+
readonly input: import("effect/StandardSchema").StandardSchemaV1<{
|
|
400
|
+
readonly sessionID: string;
|
|
401
|
+
readonly by: string;
|
|
402
|
+
}, {
|
|
403
|
+
readonly sessionID: string;
|
|
404
|
+
readonly by: string;
|
|
405
|
+
}> & Schema.Struct<{
|
|
406
|
+
readonly sessionID: Schema.String;
|
|
407
|
+
readonly by: Schema.String;
|
|
408
|
+
}>;
|
|
409
|
+
readonly output: import("effect/StandardSchema").StandardSchemaV1<{
|
|
410
|
+
readonly outcome: "removed" | "gone" | "forgotten";
|
|
411
|
+
} | {
|
|
412
|
+
readonly outcome: "kept";
|
|
413
|
+
readonly reason: string;
|
|
414
|
+
}, {
|
|
415
|
+
readonly outcome: "removed" | "gone" | "forgotten";
|
|
416
|
+
} | {
|
|
417
|
+
readonly outcome: "kept";
|
|
418
|
+
readonly reason: string;
|
|
419
|
+
}> & Schema.Union<readonly [Schema.Struct<{
|
|
420
|
+
readonly outcome: Schema.Literals<readonly ["forgotten", "removed", "gone"]>;
|
|
421
|
+
}>, Schema.Struct<{
|
|
422
|
+
readonly outcome: Schema.Literal<"kept">;
|
|
423
|
+
readonly reason: Schema.String;
|
|
424
|
+
}>]>;
|
|
425
|
+
readonly errors: {
|
|
426
|
+
readonly refused: import("effect/StandardSchema").StandardSchemaV1<{}, {}> & Schema.Struct<{}>;
|
|
427
|
+
};
|
|
428
|
+
};
|
|
340
429
|
};
|
|
341
430
|
readonly events: {};
|
|
342
431
|
};
|
package/dist/tree/rpc.js
CHANGED
|
@@ -9,20 +9,21 @@ 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
|
+
/** Left a courier message waiting while idle, and did not take it once woken again; the session itself counts too. Absent at 0. */
|
|
19
|
+
stalled: Schema.optionalKey(Count),
|
|
18
20
|
groups: Schema.Array(Group),
|
|
19
|
-
/** Set when the subtree had more sessions than `maxTotal`, which were not counted. */
|
|
20
|
-
truncated: Schema.optionalKey(Count),
|
|
21
21
|
});
|
|
22
|
-
/** A request a session waits on until the person answers it: a permission request,
|
|
22
|
+
/** A request a session waits on until the person answers it: a permission request, its first question, or a form it shows. */
|
|
23
23
|
const Wait = Schema.Union([
|
|
24
24
|
Schema.Struct({ type: Schema.Literal("permission"), action: Schema.String, resources: Schema.Array(Schema.String) }),
|
|
25
25
|
Schema.Struct({ type: Schema.Literal("question"), question: Schema.String }),
|
|
26
|
+
Schema.Struct({ type: Schema.Literal("form"), title: Schema.String }),
|
|
26
27
|
]);
|
|
27
28
|
/** One session of the tree panel: what courier_tree shows of it, and what it is doing, in epoch milliseconds. */
|
|
28
29
|
const Row = Schema.Struct({
|
|
@@ -31,10 +32,17 @@ const Row = Schema.Struct({
|
|
|
31
32
|
title: Schema.String,
|
|
32
33
|
/** A child of the panel's session is at depth 1. */
|
|
33
34
|
depth: Count,
|
|
34
|
-
/**
|
|
35
|
-
|
|
35
|
+
/**
|
|
36
|
+
* `waiting` on a request to the person or a form it shows them; `stalled` when a courier message waits in its inbox and
|
|
37
|
+
* waking it again did not start a turn; `gone` when OpenCode no longer knows it.
|
|
38
|
+
*/
|
|
39
|
+
state: Schema.Literals(["running", "waiting", "idle", "stalled", "gone"]),
|
|
40
|
+
/** Since when its oldest message that did not wake it has waited, when it is stalled. */
|
|
41
|
+
stalled: Schema.optionalKey(Schema.Number),
|
|
36
42
|
/** How its last turn ended. */
|
|
37
43
|
outcome: Schema.optionalKey(Schema.Literals(["succeeded", "failed", "interrupted"])),
|
|
44
|
+
/** Set when courier_stop stopped it since its last prompt. */
|
|
45
|
+
stopped: Schema.optionalKey(Schema.Boolean),
|
|
38
46
|
/** Its report since its last prompt: still owed, arrived (held with its group or delivered), or its turn ended without one. */
|
|
39
47
|
report: Schema.optionalKey(Schema.Struct({ state: Schema.Literals(["owed", "reported", "ended"]), status: Schema.optionalKey(Schema.String), progressed: Schema.Boolean })),
|
|
40
48
|
/** Its join group, and its standing there: `held`, `out`, how it left, or `released`. */
|
|
@@ -49,11 +57,13 @@ const Row = Schema.Struct({
|
|
|
49
57
|
tool: Schema.optionalKey(Schema.Struct({ name: Schema.String, at: Schema.Number })),
|
|
50
58
|
waits: Schema.Array(Wait),
|
|
51
59
|
});
|
|
52
|
-
/** The sessions under a session, as courier_tree
|
|
60
|
+
/** The sessions under a session, as courier_tree lists them, in the order a tree is drawn. */
|
|
53
61
|
const Tree = Schema.Struct({
|
|
54
62
|
rows: Schema.Array(Row),
|
|
55
|
-
/**
|
|
63
|
+
/** How many older sessions the listing left out, when it had more than `maxTotal`: the live ones come first, then the newest. */
|
|
56
64
|
truncated: Schema.optionalKey(Count),
|
|
65
|
+
/** Since when a courier message has waited in the panel's own session, when that session is stalled. */
|
|
66
|
+
stalled: Schema.optionalKey(Schema.Number),
|
|
57
67
|
});
|
|
58
68
|
/** What a stop did to each session, deepest first, as courier_stop reports it. */
|
|
59
69
|
const Stopped = Schema.Struct({
|
|
@@ -61,6 +71,11 @@ const Stopped = Schema.Struct({
|
|
|
61
71
|
/** How many scheduled messages were cancelled. */
|
|
62
72
|
cancelled: Count,
|
|
63
73
|
});
|
|
74
|
+
/** What courier_cleanup did: forgot it, removed its worktree, found that already gone, or kept the worktree, saying why. */
|
|
75
|
+
const Forgotten = Schema.Union([
|
|
76
|
+
Schema.Struct({ outcome: Schema.Literals(["forgotten", "removed", "gone"]) }),
|
|
77
|
+
Schema.Struct({ outcome: Schema.Literal("kept"), reason: Schema.String }),
|
|
78
|
+
]);
|
|
64
79
|
export const treeRpc = Rpc.define({
|
|
65
80
|
id: "courier",
|
|
66
81
|
methods: {
|
|
@@ -78,6 +93,12 @@ export const treeRpc = Rpc.define({
|
|
|
78
93
|
output: Schema.toStandardSchemaV1(Stopped),
|
|
79
94
|
errors: { refused: Schema.toStandardSchemaV1(Schema.Struct({})) },
|
|
80
95
|
},
|
|
96
|
+
/** Forgets `sessionID` as courier_cleanup called from its parent, without `force`; `by` must be above it. */
|
|
97
|
+
cleanup: {
|
|
98
|
+
input: Schema.toStandardSchemaV1(Schema.Struct({ sessionID: Schema.String, by: Schema.String })),
|
|
99
|
+
output: Schema.toStandardSchemaV1(Forgotten),
|
|
100
|
+
errors: { refused: Schema.toStandardSchemaV1(Schema.Struct({})) },
|
|
101
|
+
},
|
|
81
102
|
},
|
|
82
103
|
events: {},
|
|
83
104
|
});
|
package/dist/tree/stop.js
CHANGED
|
@@ -4,6 +4,7 @@ import { cleanup } from "./cleanup.js";
|
|
|
4
4
|
import { childStore } from "./store.js";
|
|
5
5
|
import { subtree } from "./subtree.js";
|
|
6
6
|
import { stoppedNotice } from "./text.js";
|
|
7
|
+
import { forgetWakes } from "./wake.js";
|
|
7
8
|
/** Rounds of looking again for sessions started while others were being stopped. */
|
|
8
9
|
const ROUNDS = 3;
|
|
9
10
|
/**
|
|
@@ -62,6 +63,7 @@ async function silence(ports, sessionID, cancelled) {
|
|
|
62
63
|
catch (error) {
|
|
63
64
|
log(`courier_stop: could not cancel the messages scheduled for ${sessionID}: ${String(error)}`);
|
|
64
65
|
}
|
|
66
|
+
await forgetWakes(ports.courier, sessionID).catch((error) => log(`courier_stop: could not drop the wake watch of ${sessionID}: ${String(error)}`));
|
|
65
67
|
}
|
|
66
68
|
async function interrupt(ports, { entry, depth }) {
|
|
67
69
|
const { sessionID, title } = entry;
|