opencode-courier 0.13.1 → 0.13.3
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 +6 -6
- package/dist/tree/domain.d.ts +4 -4
- package/dist/tree/domain.js +3 -3
- package/dist/tree/mascot.d.ts +2 -0
- package/dist/tree/mascot.js +26 -9
- package/dist/tree/panel.d.ts +2 -2
- package/dist/tree/panel.js +9 -6
- package/dist/tree/rpc-handlers.d.ts +126 -0
- package/dist/tree/rpc.d.ts +204 -0
- package/dist/tree/rpc.js +2 -0
- package/dist/tree/running.js +1 -1
- package/dist/tree/subtree.d.ts +7 -0
- package/dist/tree/subtree.js +35 -11
- package/dist/tree/tui.d.ts +8 -0
- package/dist/tree/wake.js +16 -6
- package/dist/tui.js +154 -87
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ A narrated tour of the terminal UI: the tree panel, the asks inbox, failing chil
|
|
|
18
18
|
## Quickstart
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
npm install -g @opencode/cli@2.2.
|
|
21
|
+
npm install -g @opencode/cli@2.2.2 # OpenCode V2, the version courier is tested on
|
|
22
22
|
opencode plugin add opencode-courier
|
|
23
23
|
opencode
|
|
24
24
|
```
|
|
@@ -62,10 +62,10 @@ split a task and how to check and merge the parts. Every detail: [the reference]
|
|
|
62
62
|
## Install
|
|
63
63
|
|
|
64
64
|
Requires OpenCode V2: the `opencode` command from `@opencode/cli`. Each release is tested against
|
|
65
|
-
one OpenCode version; this one is tested on **OpenCode 2.2.
|
|
65
|
+
one OpenCode version; this one is tested on **OpenCode 2.2.2** (check with `opencode --version`).
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
|
-
npm install -g @opencode/cli@2.2.
|
|
68
|
+
npm install -g @opencode/cli@2.2.2
|
|
69
69
|
opencode plugin add opencode-courier
|
|
70
70
|
```
|
|
71
71
|
|
|
@@ -78,13 +78,13 @@ name, without a version: OpenCode offers updates only for an entry without an ex
|
|
|
78
78
|
<!-- compat-table:start rows=3: generated by script/compat-table.ts from the release tags -->
|
|
79
79
|
| opencode-courier | OpenCode V2 (`opencode` and `@opencode/plugin`) |
|
|
80
80
|
|---|---|
|
|
81
|
+
| 0.13.2, 0.13.3 | 2.2.2 |
|
|
81
82
|
| 0.13.1 | 2.2.1 |
|
|
82
83
|
| 0.13.0 | 2.2.0 |
|
|
83
|
-
| 0.11.1, 0.12.0 | 2.1.4 |
|
|
84
84
|
<!-- compat-table:end -->
|
|
85
85
|
|
|
86
86
|
Every release: [the full table](docs/reference.md#the-opencode-version). The server part loads on
|
|
87
|
-
any V2 host from 2.0.4 on. The terminal part is tested on OpenCode 2.2.
|
|
87
|
+
any V2 host from 2.0.4 on. The terminal part is tested on OpenCode 2.2.2 only.
|
|
88
88
|
|
|
89
89
|
## Options
|
|
90
90
|
|
|
@@ -128,7 +128,7 @@ Parameters and behaviour: [the reference](docs/reference.md#the-tools).
|
|
|
128
128
|
## In the terminal
|
|
129
129
|
|
|
130
130
|
- **Footer:** `courier 1 waiting on you · 2 running · group pair 1/2`.
|
|
131
|
-
- **`/courier tree`:** a panel with the tree. `enter` opens a session, `s` stops it, `q` closes.
|
|
131
|
+
- **`/courier tree`:** a panel with the tree, the session it was opened in as its first row. `enter` opens a session, `s` stops it, `q` closes.
|
|
132
132
|
- **`/courier stop <session>`:** stops a session and everything under it.
|
|
133
133
|
- **`ctrl+x k`** or **`/asks`:** every ask waiting on you in the tree, answered in a dialog.
|
|
134
134
|
- **`/courier memory`:** the project's tree records. `p` pins one, `x` forgets one.
|
package/dist/tree/domain.d.ts
CHANGED
|
@@ -24,11 +24,11 @@ export declare function readNativeChildren(options: unknown): {
|
|
|
24
24
|
};
|
|
25
25
|
/** A session's times, as `session.get` gives them. */
|
|
26
26
|
type Times = Awaited<ReturnType<Context["session"]["get"]>>["time"];
|
|
27
|
-
/** A session's times as `busy` reads them. */
|
|
28
|
-
export type BusyTimes = Pick<Times, "updated" | "idle">;
|
|
27
|
+
/** A session's times as `busy` reads them; `busy`, when its latest execution started, is stamped since OpenCode 2.2.2. */
|
|
28
|
+
export type BusyTimes = Pick<Times, "updated" | "idle" | "busy">;
|
|
29
29
|
/**
|
|
30
|
-
* Whether a session may run by its times: it has never finished a turn, or
|
|
31
|
-
*
|
|
30
|
+
* Whether a session may run by its times: it has never finished a turn, or its latest execution started after the last one ended
|
|
31
|
+
* (`busy`; without it `updated`, which a rename, an archive or a waiting inbox item also stamp); only its transcript then tells.
|
|
32
32
|
*/
|
|
33
33
|
export declare const busy: (time: BusyTimes) => boolean;
|
|
34
34
|
/** A stored message as `turnEnd` reads it: an assistant message's `error` says how its step ended. */
|
package/dist/tree/domain.js
CHANGED
|
@@ -24,10 +24,10 @@ export function readNativeChildren(options) {
|
|
|
24
24
|
return { nativeChildren: false, problems: [`nativeChildren must be true or false, not ${JSON.stringify(value)}; using false`] };
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
* Whether a session may run by its times: it has never finished a turn, or
|
|
28
|
-
*
|
|
27
|
+
* Whether a session may run by its times: it has never finished a turn, or its latest execution started after the last one ended
|
|
28
|
+
* (`busy`; without it `updated`, which a rename, an archive or a waiting inbox item also stamp); only its transcript then tells.
|
|
29
29
|
*/
|
|
30
|
-
export const busy = (time) => time.idle === undefined || millis(time.updated) > millis(time.idle);
|
|
30
|
+
export const busy = (time) => time.idle === undefined || millis(time.busy ?? time.updated) > millis(time.idle);
|
|
31
31
|
/** The messages the person's switch of agent or model, move or shell command appends, at rest or mid-turn alike. */
|
|
32
32
|
const ASIDES = new Set(["agent-switched", "model-switched", "location-switched", "shell"]);
|
|
33
33
|
/**
|
package/dist/tree/mascot.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export type Cell = {
|
|
|
15
15
|
export declare const MASCOT_EVERY = 5;
|
|
16
16
|
/** He blinks on every this-many-th of his frames where his eyes are open. */
|
|
17
17
|
export declare const BLINK_EVERY = 11;
|
|
18
|
+
/** Running, he is still and awake for this many of his frames, about 8 s, then digs for one cycle of six. */
|
|
19
|
+
export declare const DIG_EVERY = 18;
|
|
18
20
|
/**
|
|
19
21
|
* The 8×4 glyph's frames by state, pixel rows top to bottom; a state with several cycles through them, one per mascot frame.
|
|
20
22
|
* No muted pixel touches the mound, here or in the 16×16, as `text.muted` is close to `background.raised.max`.
|
package/dist/tree/mascot.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
export const MASCOT_EVERY = 5;
|
|
3
3
|
/** He blinks on every this-many-th of his frames where his eyes are open. */
|
|
4
4
|
export const BLINK_EVERY = 11;
|
|
5
|
+
/** Running, he is still and awake for this many of his frames, about 8 s, then digs for one cycle of six. */
|
|
6
|
+
export const DIG_EVERY = 18;
|
|
5
7
|
/**
|
|
6
8
|
* The 8×4 glyph's frames by state, pixel rows top to bottom; a state with several cycles through them, one per mascot frame.
|
|
7
9
|
* No muted pixel touches the mound, here or in the 16×16, as `text.muted` is close to `background.raised.max`.
|
|
@@ -13,8 +15,8 @@ export const GLYPH = {
|
|
|
13
15
|
[".g....g.", "...bb...", "ggbbbbgg", "gggggggg"],
|
|
14
16
|
],
|
|
15
17
|
running: [
|
|
16
|
-
["..
|
|
17
|
-
[".
|
|
18
|
+
...Array.from({ length: DIG_EVERY }, () => ["..bbbb..", ".bkbbkb.", "gbbaabbg", "gggggggg"]),
|
|
19
|
+
...["m.bbbb.m", ".mbbbbm.", "..bbbb..", "m.bbbb.m", ".mbbbbm.", "..bbbb.."].map((top) => [top, ".bkbbkb.", "gbbaabbg", "gggggggg"]),
|
|
18
20
|
],
|
|
19
21
|
waiting: [
|
|
20
22
|
[".bbbbbbw", ".bkbbkbw", ".bbaabbm", "ggggggg."],
|
|
@@ -32,7 +34,7 @@ export const GLYPH = {
|
|
|
32
34
|
gone: [["........", ".mmmmmm.", ".mkmmkm.", "mmmmmmmm"]],
|
|
33
35
|
};
|
|
34
36
|
/** The states in which his eyes are open, so he blinks. */
|
|
35
|
-
const OPEN_EYES = new Set(["waiting", "report"]);
|
|
37
|
+
const OPEN_EYES = new Set(["waiting", "report", "running"]);
|
|
36
38
|
/** The 8×4 glyph's pixels for `state` at mascot frame `frame`, its first frame with none: animations off. */
|
|
37
39
|
export function glyph(state, frame) {
|
|
38
40
|
const frames = GLYPH[state];
|
|
@@ -114,9 +116,27 @@ export function paint(pixels, spots) {
|
|
|
114
116
|
}
|
|
115
117
|
/** A column of `length` pixels of `pixel` from row `row`. */
|
|
116
118
|
const post = (row, column, length, pixel) => Array.from({ length }, (_, at) => [row + at, column, pixel]);
|
|
117
|
-
/** The head's top row at `rise
|
|
119
|
+
/** The head's top row at `rise`. */
|
|
118
120
|
const headTop = (rise) => Math.round(10 - 8 * rise);
|
|
119
|
-
|
|
121
|
+
/** Up and awake at `rise`, his eyes `shift` columns over (0 straight ahead) when `open`. */
|
|
122
|
+
const awake = (rise, shift) => (open) => {
|
|
123
|
+
const row = headTop(rise) + 3;
|
|
124
|
+
return paint(digby(rise, { eyes: "open" }), [[row, 6, "b"], [row, 9, "b"], ...(open ? [[row, 6 + shift, "k"], [row, 9 + shift, "k"]] : [])]);
|
|
125
|
+
};
|
|
126
|
+
/** Where a clod flies on each side, frame by frame: out of the hole, up, over and down, a row clear of the mound's rim. */
|
|
127
|
+
const CLOD_LEFT = [[8, 3], [7, 2], [6, 1], [5, 0], [7, 0], [9, 0]];
|
|
128
|
+
const CLOD_RIGHT = [[8, 12], [7, 13], [6, 14], [5, 15], [7, 15], [9, 15]];
|
|
129
|
+
const CLODS = [[CLOD_LEFT, 0], [CLOD_LEFT, 3], [CLOD_RIGHT, 1], [CLOD_RIGHT, 4]];
|
|
130
|
+
/** Digging at frame `at`: up with his eyes open, the mound still, four clods on their arcs, one always in the air. */
|
|
131
|
+
const digging = (at) => (open) => paint(digby(0.6, { eyes: open ? "open" : "none" }), CLODS.map(([path, phase]) => {
|
|
132
|
+
const [row, column] = path[(at + phase) % path.length];
|
|
133
|
+
return [row, column, "m"];
|
|
134
|
+
}));
|
|
135
|
+
/** Running: still and awake, a glance left then right over twelve frames, then one dig cycle; the mound never moves. */
|
|
136
|
+
const running = [
|
|
137
|
+
...Array.from({ length: DIG_EVERY }, (_, at) => [0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 1, 1][at % 12]).map((shift) => awake(0.6, shift)),
|
|
138
|
+
...Array.from({ length: CLOD_LEFT.length }, (_, at) => digging(at)),
|
|
139
|
+
];
|
|
120
140
|
/** A child's head peeking out of a side mound at columns `column`–`column + 2`, `up` or half sunk. */
|
|
121
141
|
const peek = (column, up) => [
|
|
122
142
|
...(up ? [[8, column, ".b."], [9, column, "bkb"]] : [[9, column, ".b."]]),
|
|
@@ -143,10 +163,7 @@ export const ART = {
|
|
|
143
163
|
() => spawn(true, [[3, 1, "m"], [5, 3, "m"], [2, 14, "m"], [5, 12, "m"]]),
|
|
144
164
|
() => spawn(false, [[1, 0, "m"], [4, 2, "m"], [3, 15, "m"], [6, 13, "m"]]),
|
|
145
165
|
],
|
|
146
|
-
running
|
|
147
|
-
() => running(0.22, 0, [[5, 2, "m"], [7, 1, "m"], [4, 13, "m"], [6, 14, "m"]]),
|
|
148
|
-
() => running(0.12, 1, [[3, 1, "m"], [6, 3, "m"], [5, 12, "m"], [3, 15, "m"]]),
|
|
149
|
-
],
|
|
166
|
+
running,
|
|
150
167
|
waiting: [waiting(true), waiting(false)],
|
|
151
168
|
stalled: [stalled("e.e.e"), stalled("e"), stalled("e.e")],
|
|
152
169
|
report: [report(1, [".s.", "sss", ".s."]), report(1.25, ["s.s", ".s.", "s.s"]), report(1.1, [".s.", "sss", ".s."])],
|
package/dist/tree/panel.d.ts
CHANGED
|
@@ -13,8 +13,8 @@ export declare const waitOf: (pending: Pending) => Wait;
|
|
|
13
13
|
/** A form a session shows, as the panel says what it waits on. */
|
|
14
14
|
export declare const formWait: (form: ShownForm) => Wait;
|
|
15
15
|
/**
|
|
16
|
-
* The tree panel's rows: the sessions under a session as courier_tree lists them, at most `maxTotal`,
|
|
17
|
-
*
|
|
16
|
+
* The tree panel's rows: the sessions under a session as courier_tree lists them, at most `maxTotal`, live ones first,
|
|
17
|
+
* then the newest, each as `row` reads it; `top` the session itself, `truncated` the ones left out, `stalled` its stall.
|
|
18
18
|
*/
|
|
19
19
|
export declare function panel(ports: CourierPorts, rootID: string): Promise<Tree>;
|
|
20
20
|
export {};
|
package/dist/tree/panel.js
CHANGED
|
@@ -2,7 +2,7 @@ import { startedAs } from "./domain.js";
|
|
|
2
2
|
import { lastStatus, stoppedSincePrompt } from "./report.js";
|
|
3
3
|
import { standingIn } from "./status.js";
|
|
4
4
|
import { childStore } from "./store.js";
|
|
5
|
-
import { readTree } from "./subtree.js";
|
|
5
|
+
import { readTop, readTree } from "./subtree.js";
|
|
6
6
|
import { stalledAmong } from "./wake.js";
|
|
7
7
|
/** The last tool call in a session's messages, and when it was made. */
|
|
8
8
|
export function lastTool(messages) {
|
|
@@ -91,14 +91,17 @@ async function row(ports, windows, { entry, depth, info, running, endedAt, pendi
|
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
93
|
/**
|
|
94
|
-
* The tree panel's rows: the sessions under a session as courier_tree lists them, at most `maxTotal`,
|
|
95
|
-
*
|
|
94
|
+
* The tree panel's rows: the sessions under a session as courier_tree lists them, at most `maxTotal`, live ones first,
|
|
95
|
+
* then the newest, each as `row` reads it; `top` the session itself, `truncated` the ones left out, `stalled` its stall.
|
|
96
96
|
*/
|
|
97
97
|
export async function panel(ports, rootID) {
|
|
98
|
-
const { kept, leftOut } = await readTree(ports, rootID);
|
|
98
|
+
const [{ kept, leftOut }, root] = await Promise.all([readTree(ports, rootID), readTop(ports, rootID)]);
|
|
99
99
|
const stalled = await stalledAmong(ports, [rootID, ...kept.map((node) => node.entry.sessionID)]);
|
|
100
100
|
const windows = await ports.models().catch(() => []);
|
|
101
|
-
const rows = await Promise.all(
|
|
101
|
+
const [rows, top] = await Promise.all([
|
|
102
|
+
Promise.all(kept.map((node) => row(ports, windows, node, stalled.get(node.entry.sessionID)))),
|
|
103
|
+
root && row(ports, windows, root, stalled.get(rootID)),
|
|
104
|
+
]);
|
|
102
105
|
const own = stalled.get(rootID);
|
|
103
|
-
return { rows, ...(leftOut ? { truncated: leftOut } : {}), ...(own !== undefined ? { stalled: own } : {}) };
|
|
106
|
+
return { rows, ...(top ? { top } : {}), ...(leftOut ? { truncated: leftOut } : {}), ...(own !== undefined ? { stalled: own } : {}) };
|
|
104
107
|
}
|
|
@@ -96,6 +96,48 @@ export declare function registerTreeRpc(rpc: Pick<Plugin.Context["rpc"], "regist
|
|
|
96
96
|
readonly resumes?: number | undefined;
|
|
97
97
|
}[];
|
|
98
98
|
readonly stalled?: number | undefined;
|
|
99
|
+
readonly top?: {
|
|
100
|
+
readonly sessionID: string;
|
|
101
|
+
readonly title: string;
|
|
102
|
+
readonly depth: number;
|
|
103
|
+
readonly isolated: boolean;
|
|
104
|
+
readonly parentID: string;
|
|
105
|
+
readonly created: number;
|
|
106
|
+
readonly state: "gone" | "stalled" | "running" | "idle" | "waiting";
|
|
107
|
+
readonly waits: readonly ({
|
|
108
|
+
readonly type: "permission";
|
|
109
|
+
readonly action: string;
|
|
110
|
+
readonly resources: readonly string[];
|
|
111
|
+
} | {
|
|
112
|
+
readonly type: "question";
|
|
113
|
+
readonly question: string;
|
|
114
|
+
} | {
|
|
115
|
+
readonly type: "form";
|
|
116
|
+
readonly title: string;
|
|
117
|
+
})[];
|
|
118
|
+
readonly stopped?: boolean | undefined;
|
|
119
|
+
readonly stalled?: number | undefined;
|
|
120
|
+
readonly group?: {
|
|
121
|
+
readonly name: string;
|
|
122
|
+
readonly standing: string;
|
|
123
|
+
} | undefined;
|
|
124
|
+
readonly cost?: number | undefined;
|
|
125
|
+
readonly context?: number | undefined;
|
|
126
|
+
readonly outcome?: "failed" | "interrupted" | "succeeded" | undefined;
|
|
127
|
+
readonly report?: {
|
|
128
|
+
readonly progressed: boolean;
|
|
129
|
+
readonly state: "ended" | "reported" | "owed";
|
|
130
|
+
readonly status?: string | undefined;
|
|
131
|
+
} | undefined;
|
|
132
|
+
readonly idle?: number | undefined;
|
|
133
|
+
readonly native?: boolean | undefined;
|
|
134
|
+
readonly model?: string | undefined;
|
|
135
|
+
readonly tool?: {
|
|
136
|
+
readonly name: string;
|
|
137
|
+
readonly at: number;
|
|
138
|
+
} | undefined;
|
|
139
|
+
readonly resumes?: number | undefined;
|
|
140
|
+
} | undefined;
|
|
99
141
|
readonly truncated?: number | undefined;
|
|
100
142
|
}, {
|
|
101
143
|
readonly rows: readonly {
|
|
@@ -141,6 +183,48 @@ export declare function registerTreeRpc(rpc: Pick<Plugin.Context["rpc"], "regist
|
|
|
141
183
|
readonly resumes?: number | undefined;
|
|
142
184
|
}[];
|
|
143
185
|
readonly stalled?: number | undefined;
|
|
186
|
+
readonly top?: {
|
|
187
|
+
readonly sessionID: string;
|
|
188
|
+
readonly title: string;
|
|
189
|
+
readonly depth: number;
|
|
190
|
+
readonly isolated: boolean;
|
|
191
|
+
readonly parentID: string;
|
|
192
|
+
readonly created: number;
|
|
193
|
+
readonly state: "gone" | "stalled" | "running" | "idle" | "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 type: "form";
|
|
203
|
+
readonly title: string;
|
|
204
|
+
})[];
|
|
205
|
+
readonly stopped?: boolean | undefined;
|
|
206
|
+
readonly stalled?: number | undefined;
|
|
207
|
+
readonly group?: {
|
|
208
|
+
readonly name: string;
|
|
209
|
+
readonly standing: string;
|
|
210
|
+
} | undefined;
|
|
211
|
+
readonly cost?: number | undefined;
|
|
212
|
+
readonly context?: number | undefined;
|
|
213
|
+
readonly outcome?: "failed" | "interrupted" | "succeeded" | undefined;
|
|
214
|
+
readonly report?: {
|
|
215
|
+
readonly progressed: boolean;
|
|
216
|
+
readonly state: "ended" | "reported" | "owed";
|
|
217
|
+
readonly status?: string | undefined;
|
|
218
|
+
} | undefined;
|
|
219
|
+
readonly idle?: number | undefined;
|
|
220
|
+
readonly native?: boolean | undefined;
|
|
221
|
+
readonly model?: string | undefined;
|
|
222
|
+
readonly tool?: {
|
|
223
|
+
readonly name: string;
|
|
224
|
+
readonly at: number;
|
|
225
|
+
} | undefined;
|
|
226
|
+
readonly resumes?: number | undefined;
|
|
227
|
+
} | undefined;
|
|
144
228
|
readonly truncated?: number | undefined;
|
|
145
229
|
}> & import("effect/Schema").Struct<{
|
|
146
230
|
readonly rows: import("effect/Schema").$Array<import("effect/Schema").Struct<{
|
|
@@ -185,6 +269,48 @@ export declare function registerTreeRpc(rpc: Pick<Plugin.Context["rpc"], "regist
|
|
|
185
269
|
readonly title: import("effect/Schema").String;
|
|
186
270
|
}>]>>;
|
|
187
271
|
}>>;
|
|
272
|
+
readonly top: import("effect/Schema").optionalKey<import("effect/Schema").Struct<{
|
|
273
|
+
readonly sessionID: import("effect/Schema").String;
|
|
274
|
+
readonly parentID: import("effect/Schema").String;
|
|
275
|
+
readonly title: import("effect/Schema").String;
|
|
276
|
+
readonly depth: import("effect/Schema").Int;
|
|
277
|
+
readonly state: import("effect/Schema").Literals<readonly ["running", "waiting", "idle", "stalled", "gone"]>;
|
|
278
|
+
readonly stalled: import("effect/Schema").optionalKey<import("effect/Schema").Number>;
|
|
279
|
+
readonly outcome: import("effect/Schema").optionalKey<import("effect/Schema").Literals<readonly ["succeeded", "failed", "interrupted"]>>;
|
|
280
|
+
readonly resumes: import("effect/Schema").optionalKey<import("effect/Schema").Number>;
|
|
281
|
+
readonly stopped: import("effect/Schema").optionalKey<import("effect/Schema").Boolean>;
|
|
282
|
+
readonly report: import("effect/Schema").optionalKey<import("effect/Schema").Struct<{
|
|
283
|
+
readonly state: import("effect/Schema").Literals<readonly ["owed", "reported", "ended"]>;
|
|
284
|
+
readonly status: import("effect/Schema").optionalKey<import("effect/Schema").String>;
|
|
285
|
+
readonly progressed: import("effect/Schema").Boolean;
|
|
286
|
+
}>>;
|
|
287
|
+
readonly group: import("effect/Schema").optionalKey<import("effect/Schema").Struct<{
|
|
288
|
+
readonly name: import("effect/Schema").String;
|
|
289
|
+
readonly standing: import("effect/Schema").String;
|
|
290
|
+
}>>;
|
|
291
|
+
readonly isolated: import("effect/Schema").Boolean;
|
|
292
|
+
readonly native: import("effect/Schema").optionalKey<import("effect/Schema").Boolean>;
|
|
293
|
+
readonly model: import("effect/Schema").optionalKey<import("effect/Schema").String>;
|
|
294
|
+
readonly created: import("effect/Schema").Number;
|
|
295
|
+
readonly idle: import("effect/Schema").optionalKey<import("effect/Schema").Number>;
|
|
296
|
+
readonly cost: import("effect/Schema").optionalKey<import("effect/Schema").Number>;
|
|
297
|
+
readonly context: import("effect/Schema").optionalKey<import("effect/Schema").Number>;
|
|
298
|
+
readonly tool: import("effect/Schema").optionalKey<import("effect/Schema").Struct<{
|
|
299
|
+
readonly name: import("effect/Schema").String;
|
|
300
|
+
readonly at: import("effect/Schema").Number;
|
|
301
|
+
}>>;
|
|
302
|
+
readonly waits: import("effect/Schema").$Array<import("effect/Schema").Union<readonly [import("effect/Schema").Struct<{
|
|
303
|
+
readonly type: import("effect/Schema").Literal<"permission">;
|
|
304
|
+
readonly action: import("effect/Schema").String;
|
|
305
|
+
readonly resources: import("effect/Schema").$Array<import("effect/Schema").String>;
|
|
306
|
+
}>, import("effect/Schema").Struct<{
|
|
307
|
+
readonly type: import("effect/Schema").Literal<"question">;
|
|
308
|
+
readonly question: import("effect/Schema").String;
|
|
309
|
+
}>, import("effect/Schema").Struct<{
|
|
310
|
+
readonly type: import("effect/Schema").Literal<"form">;
|
|
311
|
+
readonly title: import("effect/Schema").String;
|
|
312
|
+
}>]>>;
|
|
313
|
+
}>>;
|
|
188
314
|
readonly truncated: import("effect/Schema").optionalKey<import("effect/Schema").Int>;
|
|
189
315
|
readonly stalled: import("effect/Schema").optionalKey<import("effect/Schema").Number>;
|
|
190
316
|
}>;
|
package/dist/tree/rpc.d.ts
CHANGED
|
@@ -149,6 +149,66 @@ declare const Tree: Schema.Struct<{
|
|
|
149
149
|
readonly title: Schema.String;
|
|
150
150
|
}>]>>;
|
|
151
151
|
}>>;
|
|
152
|
+
/** The panel's own session, at depth 0; absent when OpenCode no longer knows it, and from an older server. */
|
|
153
|
+
readonly top: Schema.optionalKey<Schema.Struct<{
|
|
154
|
+
readonly sessionID: Schema.String;
|
|
155
|
+
readonly parentID: Schema.String;
|
|
156
|
+
readonly title: Schema.String;
|
|
157
|
+
/** A child of the panel's session is at depth 1. */
|
|
158
|
+
readonly depth: Schema.Int;
|
|
159
|
+
/**
|
|
160
|
+
* `waiting` on a request to the person or a form it shows them; `stalled` when a courier message waits in its inbox and
|
|
161
|
+
* waking it again did not start a turn; `gone` when OpenCode no longer knows it.
|
|
162
|
+
*/
|
|
163
|
+
readonly state: Schema.Literals<readonly ["running", "waiting", "idle", "stalled", "gone"]>;
|
|
164
|
+
/** Since when its oldest message that did not wake it has waited, when it is stalled. */
|
|
165
|
+
readonly stalled: Schema.optionalKey<Schema.Number>;
|
|
166
|
+
/** How its last turn ended. */
|
|
167
|
+
readonly outcome: Schema.optionalKey<Schema.Literals<readonly ["succeeded", "failed", "interrupted"]>>;
|
|
168
|
+
/** When the provider limit that failed its last turn lifts; left out once that has passed, or when it runs again or was stopped. */
|
|
169
|
+
readonly resumes: Schema.optionalKey<Schema.Number>;
|
|
170
|
+
/** Set when courier_stop stopped it since its last prompt. */
|
|
171
|
+
readonly stopped: Schema.optionalKey<Schema.Boolean>;
|
|
172
|
+
/** Its report since its last prompt: still owed, arrived (held with its group or delivered), or its turn ended without one. */
|
|
173
|
+
readonly report: Schema.optionalKey<Schema.Struct<{
|
|
174
|
+
readonly state: Schema.Literals<readonly ["owed", "reported", "ended"]>;
|
|
175
|
+
readonly status: Schema.optionalKey<Schema.String>;
|
|
176
|
+
readonly progressed: Schema.Boolean;
|
|
177
|
+
}>>;
|
|
178
|
+
/** Its join group, and its standing there: `held`, `out`, how it left, or `released`. */
|
|
179
|
+
readonly group: Schema.optionalKey<Schema.Struct<{
|
|
180
|
+
readonly name: Schema.String;
|
|
181
|
+
readonly standing: Schema.String;
|
|
182
|
+
}>>;
|
|
183
|
+
readonly isolated: Schema.Boolean;
|
|
184
|
+
/** Set when it is OpenCode's subagent of its parent (a native child), which OpenCode's session lists leave out. */
|
|
185
|
+
readonly native: Schema.optionalKey<Schema.Boolean>;
|
|
186
|
+
/** The model it was started on, `provider/model` with `#variant` when one is set, when that is not its parent's. */
|
|
187
|
+
readonly model: Schema.optionalKey<Schema.String>;
|
|
188
|
+
readonly created: Schema.Number;
|
|
189
|
+
/** When its last turn ended, if it is not running. */
|
|
190
|
+
readonly idle: Schema.optionalKey<Schema.Number>;
|
|
191
|
+
/** What it has cost so far, in US dollars. */
|
|
192
|
+
readonly cost: Schema.optionalKey<Schema.Number>;
|
|
193
|
+
/** How full its context is, as a fraction of the model's window; left out when the model or its limit cannot be read. */
|
|
194
|
+
readonly context: Schema.optionalKey<Schema.Number>;
|
|
195
|
+
/** Its last tool call, and when it was made. */
|
|
196
|
+
readonly tool: Schema.optionalKey<Schema.Struct<{
|
|
197
|
+
readonly name: Schema.String;
|
|
198
|
+
readonly at: Schema.Number;
|
|
199
|
+
}>>;
|
|
200
|
+
readonly waits: Schema.$Array<Schema.Union<readonly [Schema.Struct<{
|
|
201
|
+
readonly type: Schema.Literal<"permission">;
|
|
202
|
+
readonly action: Schema.String;
|
|
203
|
+
readonly resources: Schema.$Array<Schema.String>;
|
|
204
|
+
}>, Schema.Struct<{
|
|
205
|
+
readonly type: Schema.Literal<"question">;
|
|
206
|
+
readonly question: Schema.String;
|
|
207
|
+
}>, Schema.Struct<{
|
|
208
|
+
readonly type: Schema.Literal<"form">;
|
|
209
|
+
readonly title: Schema.String;
|
|
210
|
+
}>]>>;
|
|
211
|
+
}>>;
|
|
152
212
|
/** How many older sessions the listing left out, when it had more than `maxTotal`: the live ones come first, then the newest. */
|
|
153
213
|
readonly truncated: Schema.optionalKey<Schema.Int>;
|
|
154
214
|
/** Since when a courier message has waited in the panel's own session, when that session is stalled. */
|
|
@@ -275,6 +335,48 @@ export declare const treeRpc: {
|
|
|
275
335
|
readonly resumes?: number | undefined;
|
|
276
336
|
}[];
|
|
277
337
|
readonly stalled?: number | undefined;
|
|
338
|
+
readonly top?: {
|
|
339
|
+
readonly sessionID: string;
|
|
340
|
+
readonly title: string;
|
|
341
|
+
readonly depth: number;
|
|
342
|
+
readonly isolated: boolean;
|
|
343
|
+
readonly parentID: string;
|
|
344
|
+
readonly created: number;
|
|
345
|
+
readonly state: "gone" | "stalled" | "running" | "idle" | "waiting";
|
|
346
|
+
readonly waits: readonly ({
|
|
347
|
+
readonly type: "permission";
|
|
348
|
+
readonly action: string;
|
|
349
|
+
readonly resources: readonly string[];
|
|
350
|
+
} | {
|
|
351
|
+
readonly type: "question";
|
|
352
|
+
readonly question: string;
|
|
353
|
+
} | {
|
|
354
|
+
readonly type: "form";
|
|
355
|
+
readonly title: string;
|
|
356
|
+
})[];
|
|
357
|
+
readonly stopped?: boolean | undefined;
|
|
358
|
+
readonly stalled?: number | undefined;
|
|
359
|
+
readonly group?: {
|
|
360
|
+
readonly name: string;
|
|
361
|
+
readonly standing: string;
|
|
362
|
+
} | undefined;
|
|
363
|
+
readonly cost?: number | undefined;
|
|
364
|
+
readonly context?: number | undefined;
|
|
365
|
+
readonly outcome?: "failed" | "interrupted" | "succeeded" | undefined;
|
|
366
|
+
readonly report?: {
|
|
367
|
+
readonly progressed: boolean;
|
|
368
|
+
readonly state: "ended" | "reported" | "owed";
|
|
369
|
+
readonly status?: string | undefined;
|
|
370
|
+
} | undefined;
|
|
371
|
+
readonly idle?: number | undefined;
|
|
372
|
+
readonly native?: boolean | undefined;
|
|
373
|
+
readonly model?: string | undefined;
|
|
374
|
+
readonly tool?: {
|
|
375
|
+
readonly name: string;
|
|
376
|
+
readonly at: number;
|
|
377
|
+
} | undefined;
|
|
378
|
+
readonly resumes?: number | undefined;
|
|
379
|
+
} | undefined;
|
|
278
380
|
readonly truncated?: number | undefined;
|
|
279
381
|
}, {
|
|
280
382
|
readonly rows: readonly {
|
|
@@ -320,6 +422,48 @@ export declare const treeRpc: {
|
|
|
320
422
|
readonly resumes?: number | undefined;
|
|
321
423
|
}[];
|
|
322
424
|
readonly stalled?: number | undefined;
|
|
425
|
+
readonly top?: {
|
|
426
|
+
readonly sessionID: string;
|
|
427
|
+
readonly title: string;
|
|
428
|
+
readonly depth: number;
|
|
429
|
+
readonly isolated: boolean;
|
|
430
|
+
readonly parentID: string;
|
|
431
|
+
readonly created: number;
|
|
432
|
+
readonly state: "gone" | "stalled" | "running" | "idle" | "waiting";
|
|
433
|
+
readonly waits: readonly ({
|
|
434
|
+
readonly type: "permission";
|
|
435
|
+
readonly action: string;
|
|
436
|
+
readonly resources: readonly string[];
|
|
437
|
+
} | {
|
|
438
|
+
readonly type: "question";
|
|
439
|
+
readonly question: string;
|
|
440
|
+
} | {
|
|
441
|
+
readonly type: "form";
|
|
442
|
+
readonly title: string;
|
|
443
|
+
})[];
|
|
444
|
+
readonly stopped?: boolean | undefined;
|
|
445
|
+
readonly stalled?: number | undefined;
|
|
446
|
+
readonly group?: {
|
|
447
|
+
readonly name: string;
|
|
448
|
+
readonly standing: string;
|
|
449
|
+
} | undefined;
|
|
450
|
+
readonly cost?: number | undefined;
|
|
451
|
+
readonly context?: number | undefined;
|
|
452
|
+
readonly outcome?: "failed" | "interrupted" | "succeeded" | undefined;
|
|
453
|
+
readonly report?: {
|
|
454
|
+
readonly progressed: boolean;
|
|
455
|
+
readonly state: "ended" | "reported" | "owed";
|
|
456
|
+
readonly status?: string | undefined;
|
|
457
|
+
} | undefined;
|
|
458
|
+
readonly idle?: number | undefined;
|
|
459
|
+
readonly native?: boolean | undefined;
|
|
460
|
+
readonly model?: string | undefined;
|
|
461
|
+
readonly tool?: {
|
|
462
|
+
readonly name: string;
|
|
463
|
+
readonly at: number;
|
|
464
|
+
} | undefined;
|
|
465
|
+
readonly resumes?: number | undefined;
|
|
466
|
+
} | undefined;
|
|
323
467
|
readonly truncated?: number | undefined;
|
|
324
468
|
}> & Schema.Struct<{
|
|
325
469
|
readonly rows: Schema.$Array<Schema.Struct<{
|
|
@@ -381,6 +525,66 @@ export declare const treeRpc: {
|
|
|
381
525
|
readonly title: Schema.String;
|
|
382
526
|
}>]>>;
|
|
383
527
|
}>>;
|
|
528
|
+
/** The panel's own session, at depth 0; absent when OpenCode no longer knows it, and from an older server. */
|
|
529
|
+
readonly top: Schema.optionalKey<Schema.Struct<{
|
|
530
|
+
readonly sessionID: Schema.String;
|
|
531
|
+
readonly parentID: Schema.String;
|
|
532
|
+
readonly title: Schema.String;
|
|
533
|
+
/** A child of the panel's session is at depth 1. */
|
|
534
|
+
readonly depth: Schema.Int;
|
|
535
|
+
/**
|
|
536
|
+
* `waiting` on a request to the person or a form it shows them; `stalled` when a courier message waits in its inbox and
|
|
537
|
+
* waking it again did not start a turn; `gone` when OpenCode no longer knows it.
|
|
538
|
+
*/
|
|
539
|
+
readonly state: Schema.Literals<readonly ["running", "waiting", "idle", "stalled", "gone"]>;
|
|
540
|
+
/** Since when its oldest message that did not wake it has waited, when it is stalled. */
|
|
541
|
+
readonly stalled: Schema.optionalKey<Schema.Number>;
|
|
542
|
+
/** How its last turn ended. */
|
|
543
|
+
readonly outcome: Schema.optionalKey<Schema.Literals<readonly ["succeeded", "failed", "interrupted"]>>;
|
|
544
|
+
/** When the provider limit that failed its last turn lifts; left out once that has passed, or when it runs again or was stopped. */
|
|
545
|
+
readonly resumes: Schema.optionalKey<Schema.Number>;
|
|
546
|
+
/** Set when courier_stop stopped it since its last prompt. */
|
|
547
|
+
readonly stopped: Schema.optionalKey<Schema.Boolean>;
|
|
548
|
+
/** Its report since its last prompt: still owed, arrived (held with its group or delivered), or its turn ended without one. */
|
|
549
|
+
readonly report: Schema.optionalKey<Schema.Struct<{
|
|
550
|
+
readonly state: Schema.Literals<readonly ["owed", "reported", "ended"]>;
|
|
551
|
+
readonly status: Schema.optionalKey<Schema.String>;
|
|
552
|
+
readonly progressed: Schema.Boolean;
|
|
553
|
+
}>>;
|
|
554
|
+
/** Its join group, and its standing there: `held`, `out`, how it left, or `released`. */
|
|
555
|
+
readonly group: Schema.optionalKey<Schema.Struct<{
|
|
556
|
+
readonly name: Schema.String;
|
|
557
|
+
readonly standing: Schema.String;
|
|
558
|
+
}>>;
|
|
559
|
+
readonly isolated: Schema.Boolean;
|
|
560
|
+
/** Set when it is OpenCode's subagent of its parent (a native child), which OpenCode's session lists leave out. */
|
|
561
|
+
readonly native: Schema.optionalKey<Schema.Boolean>;
|
|
562
|
+
/** The model it was started on, `provider/model` with `#variant` when one is set, when that is not its parent's. */
|
|
563
|
+
readonly model: Schema.optionalKey<Schema.String>;
|
|
564
|
+
readonly created: Schema.Number;
|
|
565
|
+
/** When its last turn ended, if it is not running. */
|
|
566
|
+
readonly idle: Schema.optionalKey<Schema.Number>;
|
|
567
|
+
/** What it has cost so far, in US dollars. */
|
|
568
|
+
readonly cost: Schema.optionalKey<Schema.Number>;
|
|
569
|
+
/** How full its context is, as a fraction of the model's window; left out when the model or its limit cannot be read. */
|
|
570
|
+
readonly context: Schema.optionalKey<Schema.Number>;
|
|
571
|
+
/** Its last tool call, and when it was made. */
|
|
572
|
+
readonly tool: Schema.optionalKey<Schema.Struct<{
|
|
573
|
+
readonly name: Schema.String;
|
|
574
|
+
readonly at: Schema.Number;
|
|
575
|
+
}>>;
|
|
576
|
+
readonly waits: Schema.$Array<Schema.Union<readonly [Schema.Struct<{
|
|
577
|
+
readonly type: Schema.Literal<"permission">;
|
|
578
|
+
readonly action: Schema.String;
|
|
579
|
+
readonly resources: Schema.$Array<Schema.String>;
|
|
580
|
+
}>, Schema.Struct<{
|
|
581
|
+
readonly type: Schema.Literal<"question">;
|
|
582
|
+
readonly question: Schema.String;
|
|
583
|
+
}>, Schema.Struct<{
|
|
584
|
+
readonly type: Schema.Literal<"form">;
|
|
585
|
+
readonly title: Schema.String;
|
|
586
|
+
}>]>>;
|
|
587
|
+
}>>;
|
|
384
588
|
/** How many older sessions the listing left out, when it had more than `maxTotal`: the live ones come first, then the newest. */
|
|
385
589
|
readonly truncated: Schema.optionalKey<Schema.Int>;
|
|
386
590
|
/** Since when a courier message has waited in the panel's own session, when that session is stalled. */
|
package/dist/tree/rpc.js
CHANGED
|
@@ -68,6 +68,8 @@ const Row = Schema.Struct({
|
|
|
68
68
|
/** The sessions under a session, as courier_tree lists them, in the order a tree is drawn. */
|
|
69
69
|
const Tree = Schema.Struct({
|
|
70
70
|
rows: Schema.Array(Row),
|
|
71
|
+
/** The panel's own session, at depth 0; absent when OpenCode no longer knows it, and from an older server. */
|
|
72
|
+
top: Schema.optionalKey(Row),
|
|
71
73
|
/** How many older sessions the listing left out, when it had more than `maxTotal`: the live ones come first, then the newest. */
|
|
72
74
|
truncated: Schema.optionalKey(Count),
|
|
73
75
|
/** Since when a courier message has waited in the panel's own session, when that session is stalled. */
|
package/dist/tree/running.js
CHANGED
|
@@ -27,7 +27,7 @@ function resolve(session, sessionID, time, now, load, cached) {
|
|
|
27
27
|
return Promise.resolve(rest(millis(time.idle)));
|
|
28
28
|
const known = answers.get(session) ?? new Map();
|
|
29
29
|
answers.set(session, known);
|
|
30
|
-
const stamp =
|
|
30
|
+
const stamp = [time.updated, time.idle, time.busy].map(millis).join(" ");
|
|
31
31
|
const found = known.get(sessionID);
|
|
32
32
|
if (cached && found?.stamp === stamp && now < found.until)
|
|
33
33
|
return found.turn;
|
package/dist/tree/subtree.d.ts
CHANGED
|
@@ -37,6 +37,13 @@ export interface Listed extends Looked {
|
|
|
37
37
|
export type ReadPorts = Pick<CourierPorts, "storage" | "session" | "pending" | "forms" | "now" | "limits">;
|
|
38
38
|
/** Every session under a session, without those past retention, each looked up, in the order a tree is drawn. */
|
|
39
39
|
export declare function lookUp(ports: ReadPorts, rootID: string): Promise<Looked[]>;
|
|
40
|
+
/** One session looked up, as `lookUp` does each; `info` when the caller already has it. */
|
|
41
|
+
export declare function look(ports: ReadPorts, node: Below, known?: Info): Promise<Looked>;
|
|
42
|
+
/**
|
|
43
|
+
* The session a subtree is read from, looked up and listed as its own sessions are, at depth 0: its roster entry when it
|
|
44
|
+
* was spawned, else one made of OpenCode's info of it; none when OpenCode does not know it.
|
|
45
|
+
*/
|
|
46
|
+
export declare function readTop(ports: ReadPorts, rootID: string): Promise<Listed | undefined>;
|
|
40
47
|
/**
|
|
41
48
|
* The listing of at most `max` of the sessions under a session: the live ones first, then the newest, with what is
|
|
42
49
|
* above them, in the order a tree is drawn (`cut`); `leftOut` counts the rest.
|
package/dist/tree/subtree.js
CHANGED
|
@@ -37,17 +37,41 @@ function drawn(byParent, parentID) {
|
|
|
37
37
|
/** Every session under a session, without those past retention, each looked up, in the order a tree is drawn. */
|
|
38
38
|
export async function lookUp(ports, rootID) {
|
|
39
39
|
const { nodes } = await subtree(ports.storage, rootID, { now: ports.now() });
|
|
40
|
-
return Promise.all(nodes.map(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
40
|
+
return Promise.all(nodes.map((node) => look(ports, node)));
|
|
41
|
+
}
|
|
42
|
+
/** One session looked up, as `lookUp` does each; `info` when the caller already has it. */
|
|
43
|
+
export async function look(ports, node, known) {
|
|
44
|
+
const [info, pending, forms] = await Promise.all([
|
|
45
|
+
known ?? ports.session.get({ sessionID: node.entry.sessionID }).catch(() => undefined),
|
|
46
|
+
ports.pending(node.entry.sessionID).catch(() => []),
|
|
47
|
+
ports.forms(node.entry.sessionID).catch(() => []),
|
|
48
|
+
]);
|
|
49
|
+
const turn = info === undefined ? undefined : await turnOf(ports.session, node.entry.sessionID, info.time);
|
|
50
|
+
const running = turn?.running ?? false;
|
|
51
|
+
// A form outlives its session's turn only when its withdrawal was missed, as while no instance followed the events.
|
|
52
|
+
return { ...node, info, running, ...(turn?.endedAt !== undefined ? { endedAt: turn.endedAt } : {}), pending, forms: running ? forms : [] };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The session a subtree is read from, looked up and listed as its own sessions are, at depth 0: its roster entry when it
|
|
56
|
+
* was spawned, else one made of OpenCode's info of it; none when OpenCode does not know it.
|
|
57
|
+
*/
|
|
58
|
+
export async function readTop(ports, rootID) {
|
|
59
|
+
const info = await ports.session.get({ sessionID: rootID }).catch(() => undefined);
|
|
60
|
+
if (!info)
|
|
61
|
+
return undefined;
|
|
62
|
+
const children = childStore(ports.storage);
|
|
63
|
+
const spawned = await children.indexedEntry(rootID).catch(() => undefined);
|
|
64
|
+
const entry = spawned ?? {
|
|
65
|
+
sessionID: rootID,
|
|
66
|
+
parentID: info.parentID ?? "",
|
|
67
|
+
title: info.title ?? "",
|
|
68
|
+
directory: info.location.directory,
|
|
69
|
+
isolated: false,
|
|
70
|
+
createdAt: info.time.created,
|
|
71
|
+
};
|
|
72
|
+
const looked = await look(ports, { entry, depth: 0 }, info);
|
|
73
|
+
const report = await reportOf(children, rootID).catch(() => undefined);
|
|
74
|
+
return { ...looked, report, live: isLive(looked.running, looked.pending.length + looked.forms.length, report) };
|
|
51
75
|
}
|
|
52
76
|
/**
|
|
53
77
|
* The listing of at most `max` of the sessions under a session: the live ones first, then the newest, with what is
|
package/dist/tree/tui.d.ts
CHANGED
|
@@ -130,6 +130,14 @@ export declare const activityLine: (row: Row, now: number) => string;
|
|
|
130
130
|
export declare function stalledLine(since: number, now: number): string;
|
|
131
131
|
/** The lines a row shows under its title: an orchestrator's bar, a paused or stalled session's wait, or else a live leaf's activity. */
|
|
132
132
|
export declare function detailLines(row: Row, rows: ReadonlyArray<Row>, now: number): string[];
|
|
133
|
+
/**
|
|
134
|
+
* Each row's tree guides, by session, for rows in the order a tree is drawn, below depth `base`: before its mark ("│ ├ "),
|
|
135
|
+
* and before its detail lines, which carry a line down to its first child ("│ │ ").
|
|
136
|
+
*/
|
|
137
|
+
export declare function guides(rows: ReadonlyArray<Row>, base: number): Map<string, {
|
|
138
|
+
row: string;
|
|
139
|
+
detail: string;
|
|
140
|
+
}>;
|
|
133
141
|
/** How often the footer and the panel ask again with no event: the scheduler flags a stalled session without one. */
|
|
134
142
|
export declare const REREAD_MS = 15000;
|
|
135
143
|
/**
|
package/dist/tree/wake.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { millis } from "../platform/json.js";
|
|
1
2
|
import { busy, endsIdle } from "./domain.js";
|
|
2
3
|
import { wakeStore } from "./store.js";
|
|
3
4
|
/** How long a courier message may wait in an idle session's inbox before its wake counts as missed. */
|
|
@@ -86,12 +87,13 @@ export async function wakeMissed(ports, claimed) {
|
|
|
86
87
|
await Promise.all(due.map((wake) => wakeAgain(ports, store, wake, now).finally(() => claimed.delete(claimOf(wake)))));
|
|
87
88
|
}
|
|
88
89
|
const claimOf = (wake) => `wake ${wake.sessionID} ${wake.inboxID}`;
|
|
90
|
+
/** Since when a message has waited in an idle session: it was enqueued, seen waiting as the turn ended, or sent again, whichever is last. */
|
|
91
|
+
const waitingSince = (wake) => Math.max(wake.idleAt ?? wake.at, wake.rewoken ?? 0);
|
|
89
92
|
/** Whether a message has waited in an idle session past `WAKE_MS`, and since a wake again, if one was sent; a stalled one is done. */
|
|
90
93
|
export function missed(wake, now) {
|
|
91
94
|
if (wake.running || wake.stalled !== undefined)
|
|
92
95
|
return false;
|
|
93
|
-
|
|
94
|
-
return now - since >= WAKE_MS;
|
|
96
|
+
return now - waitingSince(wake) >= WAKE_MS;
|
|
95
97
|
}
|
|
96
98
|
async function wakeAgain(ports, store, wake, now) {
|
|
97
99
|
try {
|
|
@@ -100,7 +102,7 @@ async function wakeAgain(ports, store, wake, now) {
|
|
|
100
102
|
if (!current || !missed(current, now))
|
|
101
103
|
return;
|
|
102
104
|
// A shutdown during a step reads as an end, and the turn the next boot resumes may start unseen: that turn takes the message.
|
|
103
|
-
if (await runsNow(ports,
|
|
105
|
+
if (await runsNow(ports, current)) {
|
|
104
106
|
const { idleAt: _, ...running } = current;
|
|
105
107
|
return await store.put({ ...running, running: true });
|
|
106
108
|
}
|
|
@@ -127,10 +129,18 @@ async function wakeAgain(ports, store, wake, now) {
|
|
|
127
129
|
ports.log(`courier wake: could not wake ${wake.sessionID} again for ${wake.inboxID}: ${String(error)}`);
|
|
128
130
|
}
|
|
129
131
|
}
|
|
130
|
-
/**
|
|
131
|
-
|
|
132
|
+
/**
|
|
133
|
+
* Whether a session shows a turn running that takes the message: by `time.busy` (2.2.2), an execution started since the message was
|
|
134
|
+
* last left waiting and not ended; without it, by its times and its transcript read now. One that cannot be read does not, and is woken again.
|
|
135
|
+
*/
|
|
136
|
+
async function runsNow(ports, wake) {
|
|
137
|
+
const { sessionID } = wake;
|
|
132
138
|
const info = await ports.session.get({ sessionID }).catch(() => undefined);
|
|
133
|
-
if (!info
|
|
139
|
+
if (!info)
|
|
140
|
+
return false;
|
|
141
|
+
if (info.time.busy !== undefined)
|
|
142
|
+
return busy(info.time) && millis(info.time.busy) >= waitingSince(wake);
|
|
143
|
+
if (!busy(info.time))
|
|
134
144
|
return false;
|
|
135
145
|
const messages = await ports.session.context({ sessionID }).catch(() => []);
|
|
136
146
|
return messages.length > 0 && !endsIdle(messages);
|
package/dist/tui.js
CHANGED
|
@@ -1284,6 +1284,7 @@ import { batch, createEffect, createMemo, createResource, createRoot, createSign
|
|
|
1284
1284
|
// src/tree/mascot.ts
|
|
1285
1285
|
var MASCOT_EVERY = 5;
|
|
1286
1286
|
var BLINK_EVERY = 11;
|
|
1287
|
+
var DIG_EVERY = 18;
|
|
1287
1288
|
var GLYPH = {
|
|
1288
1289
|
idle: [["........", "........", "..gggg..", "gggggggg"]],
|
|
1289
1290
|
spawn: [
|
|
@@ -1291,8 +1292,8 @@ var GLYPH = {
|
|
|
1291
1292
|
[".g....g.", "...bb...", "ggbbbbgg", "gggggggg"]
|
|
1292
1293
|
],
|
|
1293
1294
|
running: [
|
|
1294
|
-
["..
|
|
1295
|
-
[".
|
|
1295
|
+
...Array.from({ length: DIG_EVERY }, () => ["..bbbb..", ".bkbbkb.", "gbbaabbg", "gggggggg"]),
|
|
1296
|
+
...["m.bbbb.m", ".mbbbbm.", "..bbbb..", "m.bbbb.m", ".mbbbbm.", "..bbbb.."].map((top) => [top, ".bkbbkb.", "gbbaabbg", "gggggggg"])
|
|
1296
1297
|
],
|
|
1297
1298
|
waiting: [
|
|
1298
1299
|
[".bbbbbbw", ".bkbbkbw", ".bbaabbm", "ggggggg."],
|
|
@@ -1309,7 +1310,7 @@ var GLYPH = {
|
|
|
1309
1310
|
],
|
|
1310
1311
|
gone: [["........", ".mmmmmm.", ".mkmmkm.", "mmmmmmmm"]]
|
|
1311
1312
|
};
|
|
1312
|
-
var OPEN_EYES = new Set(["waiting", "report"]);
|
|
1313
|
+
var OPEN_EYES = new Set(["waiting", "report", "running"]);
|
|
1313
1314
|
function glyph(state, frame) {
|
|
1314
1315
|
const frames = GLYPH[state];
|
|
1315
1316
|
const pixels = frames[(frame ?? 0) % frames.length];
|
|
@@ -1381,7 +1382,21 @@ function paint(pixels, spots) {
|
|
|
1381
1382
|
}
|
|
1382
1383
|
var post = (row, column, length, pixel) => Array.from({ length }, (_, at) => [row + at, column, pixel]);
|
|
1383
1384
|
var headTop = (rise) => Math.round(10 - 8 * rise);
|
|
1384
|
-
var
|
|
1385
|
+
var awake = (rise, shift) => (open) => {
|
|
1386
|
+
const row = headTop(rise) + 3;
|
|
1387
|
+
return paint(digby(rise, { eyes: "open" }), [[row, 6, "b"], [row, 9, "b"], ...open ? [[row, 6 + shift, "k"], [row, 9 + shift, "k"]] : []]);
|
|
1388
|
+
};
|
|
1389
|
+
var CLOD_LEFT = [[8, 3], [7, 2], [6, 1], [5, 0], [7, 0], [9, 0]];
|
|
1390
|
+
var CLOD_RIGHT = [[8, 12], [7, 13], [6, 14], [5, 15], [7, 15], [9, 15]];
|
|
1391
|
+
var CLODS = [[CLOD_LEFT, 0], [CLOD_LEFT, 3], [CLOD_RIGHT, 1], [CLOD_RIGHT, 4]];
|
|
1392
|
+
var digging = (at) => (open) => paint(digby(0.6, { eyes: open ? "open" : "none" }), CLODS.map(([path, phase]) => {
|
|
1393
|
+
const [row, column] = path[(at + phase) % path.length];
|
|
1394
|
+
return [row, column, "m"];
|
|
1395
|
+
}));
|
|
1396
|
+
var running = [
|
|
1397
|
+
...Array.from({ length: DIG_EVERY }, (_, at) => [0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 1, 1][at % 12]).map((shift) => awake(0.6, shift)),
|
|
1398
|
+
...Array.from({ length: CLOD_LEFT.length }, (_, at) => digging(at))
|
|
1399
|
+
];
|
|
1385
1400
|
var peek = (column, up) => [
|
|
1386
1401
|
...up ? [[8, column, ".b."], [9, column, "bkb"]] : [[9, column, ".b."]],
|
|
1387
1402
|
[10, column, "gbg"],
|
|
@@ -1403,10 +1418,7 @@ var ART = {
|
|
|
1403
1418
|
() => spawn(true, [[3, 1, "m"], [5, 3, "m"], [2, 14, "m"], [5, 12, "m"]]),
|
|
1404
1419
|
() => spawn(false, [[1, 0, "m"], [4, 2, "m"], [3, 15, "m"], [6, 13, "m"]])
|
|
1405
1420
|
],
|
|
1406
|
-
running
|
|
1407
|
-
() => running(0.22, 0, [[5, 2, "m"], [7, 1, "m"], [4, 13, "m"], [6, 14, "m"]]),
|
|
1408
|
-
() => running(0.12, 1, [[3, 1, "m"], [6, 3, "m"], [5, 12, "m"], [3, 15, "m"]])
|
|
1409
|
-
],
|
|
1421
|
+
running,
|
|
1410
1422
|
waiting: [waiting(true), waiting(false)],
|
|
1411
1423
|
stalled: [stalled("e.e.e"), stalled("e"), stalled("e.e")],
|
|
1412
1424
|
report: [report(1, [".s.", "sss", ".s."]), report(1.25, ["s.s", ".s.", "s.s"]), report(1.1, [".s.", "sss", ".s."])],
|
|
@@ -1468,6 +1480,7 @@ var Row = Schema3.Struct({
|
|
|
1468
1480
|
});
|
|
1469
1481
|
var Tree = Schema3.Struct({
|
|
1470
1482
|
rows: Schema3.Array(Row),
|
|
1483
|
+
top: Schema3.optionalKey(Row),
|
|
1471
1484
|
truncated: Schema3.optionalKey(Count3),
|
|
1472
1485
|
stalled: Schema3.optionalKey(Schema3.Number)
|
|
1473
1486
|
});
|
|
@@ -1841,6 +1854,31 @@ function detailLines(row, rows, now) {
|
|
|
1841
1854
|
return [bar(started)];
|
|
1842
1855
|
return row.state === "gone" ? [] : [activityLine(row, now)];
|
|
1843
1856
|
}
|
|
1857
|
+
function guides(rows, base) {
|
|
1858
|
+
const byID = new Map(rows.map((row) => [row.sessionID, row]));
|
|
1859
|
+
const later = new Set;
|
|
1860
|
+
const parents = new Set;
|
|
1861
|
+
rows.forEach((row, index) => {
|
|
1862
|
+
if (rows.slice(index + 1).some((next) => next.parentID === row.parentID))
|
|
1863
|
+
later.add(row.sessionID);
|
|
1864
|
+
parents.add(row.parentID);
|
|
1865
|
+
});
|
|
1866
|
+
const above = (row) => {
|
|
1867
|
+
const parent = row.depth > base + 1 ? byID.get(row.parentID) : undefined;
|
|
1868
|
+
return parent ? [...above(parent), parent] : [];
|
|
1869
|
+
};
|
|
1870
|
+
const line = (row) => later.has(row.sessionID) ? "\u2502 " : " ";
|
|
1871
|
+
const branch = (row) => later.has(row.sessionID) ? "\u251C " : "\u2514 ";
|
|
1872
|
+
return new Map(rows.map((row) => {
|
|
1873
|
+
const through = above(row).map(line).join("");
|
|
1874
|
+
const below = row.depth > base;
|
|
1875
|
+
const down = parents.has(row.sessionID) ? "\u2502 " : " ";
|
|
1876
|
+
return [row.sessionID, {
|
|
1877
|
+
row: through + (below ? branch(row) : ""),
|
|
1878
|
+
detail: through + (below ? line(row) : "") + down
|
|
1879
|
+
}];
|
|
1880
|
+
}));
|
|
1881
|
+
}
|
|
1844
1882
|
function courierOf(ctx) {
|
|
1845
1883
|
const courier = ctx.client.rpc(treeRpc);
|
|
1846
1884
|
const location = (sessionID) => ctx.data.session.get(sessionID)?.location ?? ctx.location ?? ctx.data.location.default();
|
|
@@ -2084,6 +2122,11 @@ function TreePanel(props) {
|
|
|
2084
2122
|
tree: view.tree
|
|
2085
2123
|
};
|
|
2086
2124
|
const rows = () => latest()?.tree?.rows ?? [];
|
|
2125
|
+
const top = () => latest()?.tree?.top;
|
|
2126
|
+
const listed = () => {
|
|
2127
|
+
const own = top();
|
|
2128
|
+
return own ? [own, ...rows()] : rows();
|
|
2129
|
+
};
|
|
2087
2130
|
createEffect(() => {
|
|
2088
2131
|
const tree = latest()?.tree;
|
|
2089
2132
|
if (tree)
|
|
@@ -2115,7 +2158,7 @@ function TreePanel(props) {
|
|
|
2115
2158
|
const [selectedID, setSelectedID] = createSignal();
|
|
2116
2159
|
let placed = false;
|
|
2117
2160
|
createEffect(() => {
|
|
2118
|
-
const found = placed ? undefined :
|
|
2161
|
+
const found = placed ? undefined : listed().find((row) => row.sessionID === input.sessionID);
|
|
2119
2162
|
if (!found)
|
|
2120
2163
|
return;
|
|
2121
2164
|
placed = true;
|
|
@@ -2124,24 +2167,24 @@ function TreePanel(props) {
|
|
|
2124
2167
|
let at = 0;
|
|
2125
2168
|
const selected = createMemo(() => {
|
|
2126
2169
|
const id = selectedID();
|
|
2127
|
-
const found =
|
|
2128
|
-
const index = found >= 0 ? found : Math.min(at,
|
|
2170
|
+
const found = listed().findIndex((row) => row.sessionID === id);
|
|
2171
|
+
const index = found >= 0 ? found : Math.min(at, listed().length - 1);
|
|
2129
2172
|
at = Math.max(index, 0);
|
|
2130
2173
|
return index;
|
|
2131
2174
|
});
|
|
2132
2175
|
createEffect(() => {
|
|
2133
|
-
const row =
|
|
2176
|
+
const row = listed()[selected()];
|
|
2134
2177
|
if (row && row.sessionID !== selectedID())
|
|
2135
2178
|
setSelectedID(row.sessionID);
|
|
2136
2179
|
});
|
|
2137
|
-
const current = () =>
|
|
2180
|
+
const current = () => listed()[selected()];
|
|
2138
2181
|
let scroll;
|
|
2139
2182
|
createEffect(() => {
|
|
2140
2183
|
if (selected() >= 0)
|
|
2141
2184
|
scroll?.scrollChildIntoView(`courier-row-${selected()}`);
|
|
2142
2185
|
});
|
|
2143
2186
|
const move = (by) => {
|
|
2144
|
-
const next =
|
|
2187
|
+
const next = listed()[Math.max(0, Math.min(listed().length - 1, selected() + by))];
|
|
2145
2188
|
if (next)
|
|
2146
2189
|
setSelectedID(next.sessionID);
|
|
2147
2190
|
};
|
|
@@ -2157,7 +2200,7 @@ function TreePanel(props) {
|
|
|
2157
2200
|
const [hovered, setHovered] = createSignal();
|
|
2158
2201
|
createEffect(() => {
|
|
2159
2202
|
const id = hovered();
|
|
2160
|
-
if (id !== undefined && !
|
|
2203
|
+
if (id !== undefined && !listed().some((row) => row.sessionID === id))
|
|
2161
2204
|
setHovered(undefined);
|
|
2162
2205
|
});
|
|
2163
2206
|
let pressed;
|
|
@@ -2165,9 +2208,19 @@ function TreePanel(props) {
|
|
|
2165
2208
|
setSelectedID(row.sessionID);
|
|
2166
2209
|
openRow(row);
|
|
2167
2210
|
};
|
|
2211
|
+
const ownRow = (row, key) => {
|
|
2212
|
+
if (row.sessionID !== view.root)
|
|
2213
|
+
return false;
|
|
2214
|
+
ctx.ui.toast.show({
|
|
2215
|
+
title: "courier",
|
|
2216
|
+
message: `${key} acts on a session under "${oneLine3(row.title)}", the panel's own.`,
|
|
2217
|
+
variant: "warning"
|
|
2218
|
+
});
|
|
2219
|
+
return true;
|
|
2220
|
+
};
|
|
2168
2221
|
const stopSelected = () => {
|
|
2169
2222
|
const row = current();
|
|
2170
|
-
if (row)
|
|
2223
|
+
if (row && !ownRow(row, "s"))
|
|
2171
2224
|
confirmStop(ctx, courier, location, view.root, {
|
|
2172
2225
|
sessionID: row.sessionID,
|
|
2173
2226
|
title: row.title,
|
|
@@ -2176,7 +2229,7 @@ function TreePanel(props) {
|
|
|
2176
2229
|
};
|
|
2177
2230
|
const forgetSelected = () => {
|
|
2178
2231
|
const row = current();
|
|
2179
|
-
if (!row)
|
|
2232
|
+
if (!row || ownRow(row, "x"))
|
|
2180
2233
|
return;
|
|
2181
2234
|
if (row.state !== "gone")
|
|
2182
2235
|
return ctx.ui.toast.show({
|
|
@@ -2261,7 +2314,9 @@ function TreePanel(props) {
|
|
|
2261
2314
|
const glyphShown = () => height() >= GLYPH_ROWS && size().width >= GLYPH_COLUMNS;
|
|
2262
2315
|
const artShown = () => empty() && height() >= ART_ROWS;
|
|
2263
2316
|
const [listHeight, setListHeight] = createSignal(0);
|
|
2264
|
-
const
|
|
2317
|
+
const lines = (row) => detailLines(row, row.depth ? rows() : [], now());
|
|
2318
|
+
const guided = createMemo(() => guides(listed(), top() ? 0 : 1));
|
|
2319
|
+
const treeLines = () => listed().reduce((count, row) => count + 1 + lines(row).length, 0);
|
|
2265
2320
|
const belowShown = () => rows().length > 0 && listHeight() - treeLines() >= BELOW_ROWS;
|
|
2266
2321
|
const headerGlyph = () => glyphShown() && !artShown() && !belowShown();
|
|
2267
2322
|
const mascot = createMemo(() => mascotState(rows(), {
|
|
@@ -2317,9 +2372,9 @@ function TreePanel(props) {
|
|
|
2317
2372
|
return theme.text.muted;
|
|
2318
2373
|
};
|
|
2319
2374
|
return (() => {
|
|
2320
|
-
var _el$6 = _$createElement("box"), _el$7 = _$createElement("box"), _el$8 = _$createElement("text"), _el$
|
|
2375
|
+
var _el$6 = _$createElement("box"), _el$7 = _$createElement("box"), _el$8 = _$createElement("text"), _el$17 = _$createElement("scrollbox"), _el$22 = _$createElement("text");
|
|
2321
2376
|
_$insertNode(_el$6, _el$7);
|
|
2322
|
-
_$insertNode(_el$6, _el$
|
|
2377
|
+
_$insertNode(_el$6, _el$17);
|
|
2323
2378
|
_$insertNode(_el$6, _el$22);
|
|
2324
2379
|
_$setProp(_el$6, "flexDirection", "column");
|
|
2325
2380
|
_$setProp(_el$6, "flexGrow", 1);
|
|
@@ -2394,7 +2449,7 @@ function TreePanel(props) {
|
|
|
2394
2449
|
_$effect((_$p) => _$setProp(_el$12, "fg", theme.text.muted, _$p));
|
|
2395
2450
|
return _el$11;
|
|
2396
2451
|
}
|
|
2397
|
-
}), _el$
|
|
2452
|
+
}), _el$17);
|
|
2398
2453
|
_$insert(_el$6, _$createComponent(Show, {
|
|
2399
2454
|
get when() {
|
|
2400
2455
|
return latest()?.error;
|
|
@@ -2406,10 +2461,10 @@ function TreePanel(props) {
|
|
|
2406
2461
|
_$effect((_$p) => _$setProp(_el$13, "fg", theme.text.feedback.error.base, _$p));
|
|
2407
2462
|
return _el$13;
|
|
2408
2463
|
}
|
|
2409
|
-
}), _el$
|
|
2464
|
+
}), _el$17);
|
|
2410
2465
|
_$insert(_el$6, _$createComponent(Show, {
|
|
2411
2466
|
get when() {
|
|
2412
|
-
return latest()?.tree?.stalled;
|
|
2467
|
+
return _$memo(() => !!!top())() && latest()?.tree?.stalled;
|
|
2413
2468
|
},
|
|
2414
2469
|
get children() {
|
|
2415
2470
|
var _el$15 = _$createElement("text"), _el$16 = _$createTextNode(`This session is stalled: `);
|
|
@@ -2418,49 +2473,18 @@ function TreePanel(props) {
|
|
|
2418
2473
|
_$effect((_$p) => _$setProp(_el$15, "fg", theme.text.feedback.error.base, _$p));
|
|
2419
2474
|
return _el$15;
|
|
2420
2475
|
}
|
|
2421
|
-
}), _el$
|
|
2422
|
-
_$
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
},
|
|
2426
|
-
get children() {
|
|
2427
|
-
return [(() => {
|
|
2428
|
-
var _el$17 = _$createElement("text");
|
|
2429
|
-
_$insertNode(_el$17, _$createTextNode(`No session started with courier_spawn under this one.`));
|
|
2430
|
-
_$effect((_$p) => _$setProp(_el$17, "fg", theme.text.muted, _$p));
|
|
2431
|
-
return _el$17;
|
|
2432
|
-
})(), _$createComponent(Show, {
|
|
2433
|
-
get when() {
|
|
2434
|
-
return artShown();
|
|
2435
|
-
},
|
|
2436
|
-
get children() {
|
|
2437
|
-
var _el$19 = _$createElement("box");
|
|
2438
|
-
_$setProp(_el$19, "flexDirection", "column");
|
|
2439
|
-
_$setProp(_el$19, "flexShrink", 0);
|
|
2440
|
-
_$setProp(_el$19, "paddingTop", 1);
|
|
2441
|
-
_$insert(_el$19, _$createComponent(Index, {
|
|
2442
|
-
get each() {
|
|
2443
|
-
return art2();
|
|
2444
|
-
},
|
|
2445
|
-
children: (line) => drawn(line)
|
|
2446
|
-
}));
|
|
2447
|
-
return _el$19;
|
|
2448
|
-
}
|
|
2449
|
-
})];
|
|
2450
|
-
}
|
|
2451
|
-
}), _el$20);
|
|
2452
|
-
_$use((value) => scroll = value, _el$20);
|
|
2453
|
-
_$setProp(_el$20, "flexGrow", 1);
|
|
2454
|
-
_$setProp(_el$20, "onSizeChange", function() {
|
|
2476
|
+
}), _el$17);
|
|
2477
|
+
_$use((value) => scroll = value, _el$17);
|
|
2478
|
+
_$setProp(_el$17, "flexGrow", 1);
|
|
2479
|
+
_$setProp(_el$17, "onSizeChange", function() {
|
|
2455
2480
|
setListHeight(this.height);
|
|
2456
2481
|
});
|
|
2457
|
-
_$insert(_el$
|
|
2482
|
+
_$insert(_el$17, _$createComponent(For, {
|
|
2458
2483
|
get each() {
|
|
2459
|
-
return
|
|
2484
|
+
return listed();
|
|
2460
2485
|
},
|
|
2461
2486
|
children: (row, index) => {
|
|
2462
2487
|
const chosen = () => index() === selected();
|
|
2463
|
-
const indent = " ".repeat(row.depth - 1);
|
|
2464
2488
|
return (() => {
|
|
2465
2489
|
var _el$24 = _$createElement("box"), _el$25 = _$createElement("box"), _el$26 = _$createElement("text"), _el$27 = _$createElement("text"), _el$28 = _$createTextNode(` `), _el$29 = _$createElement("text"), _el$30 = _$createElement("text");
|
|
2466
2490
|
_$insertNode(_el$24, _el$25);
|
|
@@ -2486,8 +2510,20 @@ function TreePanel(props) {
|
|
|
2486
2510
|
_$setProp(_el$25, "flexShrink", 0);
|
|
2487
2511
|
_$setProp(_el$26, "wrapMode", "none");
|
|
2488
2512
|
_$setProp(_el$26, "flexShrink", 0);
|
|
2489
|
-
_$insert(_el$26,
|
|
2490
|
-
_$insert(_el$
|
|
2513
|
+
_$insert(_el$26, () => chosen() ? "\u25B8 " : " ");
|
|
2514
|
+
_$insert(_el$25, _$createComponent(Show, {
|
|
2515
|
+
get when() {
|
|
2516
|
+
return guided().get(row.sessionID)?.row;
|
|
2517
|
+
},
|
|
2518
|
+
children: (guide) => (() => {
|
|
2519
|
+
var _el$32 = _$createElement("text");
|
|
2520
|
+
_$setProp(_el$32, "wrapMode", "none");
|
|
2521
|
+
_$setProp(_el$32, "flexShrink", 0);
|
|
2522
|
+
_$insert(_el$32, guide);
|
|
2523
|
+
_$effect((_$p) => _$setProp(_el$32, "fg", theme.text.muted, _$p));
|
|
2524
|
+
return _el$32;
|
|
2525
|
+
})()
|
|
2526
|
+
}), _el$27);
|
|
2491
2527
|
_$insertNode(_el$27, _el$28);
|
|
2492
2528
|
_$setProp(_el$27, "wrapMode", "none");
|
|
2493
2529
|
_$setProp(_el$27, "flexShrink", 0);
|
|
@@ -2509,32 +2545,32 @@ function TreePanel(props) {
|
|
|
2509
2545
|
return at();
|
|
2510
2546
|
},
|
|
2511
2547
|
get children() {
|
|
2512
|
-
var _el$
|
|
2513
|
-
_$insertNode(_el$
|
|
2514
|
-
_$setProp(_el$
|
|
2515
|
-
_$setProp(_el$
|
|
2516
|
-
_$effect((_$p) => _$setProp(_el$
|
|
2517
|
-
return _el$
|
|
2548
|
+
var _el$33 = _$createElement("text");
|
|
2549
|
+
_$insertNode(_el$33, _$createTextNode(` \xB7 `));
|
|
2550
|
+
_$setProp(_el$33, "wrapMode", "none");
|
|
2551
|
+
_$setProp(_el$33, "flexShrink", 0);
|
|
2552
|
+
_$effect((_$p) => _$setProp(_el$33, "fg", theme.text.muted, _$p));
|
|
2553
|
+
return _el$33;
|
|
2518
2554
|
}
|
|
2519
2555
|
}), (() => {
|
|
2520
|
-
var _el$
|
|
2521
|
-
_$setProp(_el$
|
|
2522
|
-
_$setProp(_el$
|
|
2523
|
-
_$insert(_el$
|
|
2524
|
-
_$effect((_$p) => _$setProp(_el$
|
|
2525
|
-
return _el$
|
|
2556
|
+
var _el$35 = _$createElement("text");
|
|
2557
|
+
_$setProp(_el$35, "wrapMode", "none");
|
|
2558
|
+
_$setProp(_el$35, "flexShrink", 0);
|
|
2559
|
+
_$insert(_el$35, () => part.text);
|
|
2560
|
+
_$effect((_$p) => _$setProp(_el$35, "fg", partColor(row, part.kind), _$p));
|
|
2561
|
+
return _el$35;
|
|
2526
2562
|
})()]
|
|
2527
2563
|
}), null);
|
|
2528
2564
|
_$insert(_el$24, _$createComponent(For, {
|
|
2529
2565
|
get each() {
|
|
2530
|
-
return
|
|
2566
|
+
return lines(row);
|
|
2531
2567
|
},
|
|
2532
2568
|
children: (line) => (() => {
|
|
2533
|
-
var _el$
|
|
2534
|
-
_$insertNode(_el$
|
|
2535
|
-
_$setProp(_el$
|
|
2536
|
-
_$insert(_el$
|
|
2537
|
-
_$insert(_el$
|
|
2569
|
+
var _el$36 = _$createElement("text"), _el$37 = _$createTextNode(` `);
|
|
2570
|
+
_$insertNode(_el$36, _el$37);
|
|
2571
|
+
_$setProp(_el$36, "wrapMode", "none");
|
|
2572
|
+
_$insert(_el$36, () => guided().get(row.sessionID)?.detail ?? " ", null);
|
|
2573
|
+
_$insert(_el$36, _$createComponent(Show, {
|
|
2538
2574
|
get when() {
|
|
2539
2575
|
return _$memo(() => row.context !== undefined)() && Math.round(row.context * 100) > CONTEXT_WARN * 100;
|
|
2540
2576
|
},
|
|
@@ -2545,18 +2581,18 @@ function TreePanel(props) {
|
|
|
2545
2581
|
return line.split(" \xB7 ");
|
|
2546
2582
|
},
|
|
2547
2583
|
children: (part, at) => [_$memo(() => at() ? " \xB7 " : ""), _$memo(() => _$memo(() => part === `ctx ${Math.round(row.context * 100)}%`)() ? (() => {
|
|
2548
|
-
var _el$
|
|
2549
|
-
_$insert(_el$
|
|
2550
|
-
_$effect((_$p) => _$setProp(_el$
|
|
2584
|
+
var _el$38 = _$createElement("span");
|
|
2585
|
+
_$insert(_el$38, part);
|
|
2586
|
+
_$effect((_$p) => _$setProp(_el$38, "style", {
|
|
2551
2587
|
fg: theme.text.feedback.warning.base
|
|
2552
2588
|
}, _$p));
|
|
2553
|
-
return _el$
|
|
2589
|
+
return _el$38;
|
|
2554
2590
|
})() : part)]
|
|
2555
2591
|
});
|
|
2556
2592
|
}
|
|
2557
2593
|
}), null);
|
|
2558
|
-
_$effect((_$p) => _$setProp(_el$
|
|
2559
|
-
return _el$
|
|
2594
|
+
_$effect((_$p) => _$setProp(_el$36, "fg", theme.text.muted, _$p));
|
|
2595
|
+
return _el$36;
|
|
2560
2596
|
})()
|
|
2561
2597
|
}), null);
|
|
2562
2598
|
_$effect((_p$) => {
|
|
@@ -2580,7 +2616,38 @@ function TreePanel(props) {
|
|
|
2580
2616
|
})();
|
|
2581
2617
|
}
|
|
2582
2618
|
}), null);
|
|
2583
|
-
_$insert(_el$
|
|
2619
|
+
_$insert(_el$17, _$createComponent(Show, {
|
|
2620
|
+
get when() {
|
|
2621
|
+
return _$memo(() => !!latest()?.tree)() && !rows().length;
|
|
2622
|
+
},
|
|
2623
|
+
get children() {
|
|
2624
|
+
return [(() => {
|
|
2625
|
+
var _el$18 = _$createElement("text"), _el$19 = _$createTextNode(`No session started with courier_spawn under this one.`);
|
|
2626
|
+
_$insertNode(_el$18, _el$19);
|
|
2627
|
+
_$insert(_el$18, () => top() ? " " : "", _el$19);
|
|
2628
|
+
_$effect((_$p) => _$setProp(_el$18, "fg", theme.text.muted, _$p));
|
|
2629
|
+
return _el$18;
|
|
2630
|
+
})(), _$createComponent(Show, {
|
|
2631
|
+
get when() {
|
|
2632
|
+
return artShown();
|
|
2633
|
+
},
|
|
2634
|
+
get children() {
|
|
2635
|
+
var _el$20 = _$createElement("box");
|
|
2636
|
+
_$setProp(_el$20, "flexDirection", "column");
|
|
2637
|
+
_$setProp(_el$20, "flexShrink", 0);
|
|
2638
|
+
_$setProp(_el$20, "paddingTop", 1);
|
|
2639
|
+
_$insert(_el$20, _$createComponent(Index, {
|
|
2640
|
+
get each() {
|
|
2641
|
+
return art2();
|
|
2642
|
+
},
|
|
2643
|
+
children: (line) => drawn(line)
|
|
2644
|
+
}));
|
|
2645
|
+
return _el$20;
|
|
2646
|
+
}
|
|
2647
|
+
})];
|
|
2648
|
+
}
|
|
2649
|
+
}), null);
|
|
2650
|
+
_$insert(_el$17, _$createComponent(Show, {
|
|
2584
2651
|
get when() {
|
|
2585
2652
|
return belowShown();
|
|
2586
2653
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-courier",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.3",
|
|
4
4
|
"description": "Multi-session orchestration for OpenCode V2: spawn child sessions, be woken by them. No polling.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ivo Pogace <71701666+ivopogace@users.noreply.github.com>",
|
|
@@ -56,17 +56,17 @@
|
|
|
56
56
|
"test:e2e": "e2e/run.sh"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@opencode/plugin": "2.2.
|
|
60
|
-
"effect": "4.0.
|
|
59
|
+
"@opencode/plugin": "2.2.2",
|
|
60
|
+
"effect": "4.0.6"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
-
"@opencode/plugin": "2.2.
|
|
64
|
-
"@opencode/theme": "2.2.
|
|
63
|
+
"@opencode/plugin": "2.2.2",
|
|
64
|
+
"@opencode/theme": "2.2.2",
|
|
65
65
|
"@opentui/core": "0.7.0",
|
|
66
66
|
"@opentui/solid": "0.7.0",
|
|
67
67
|
"@types/bun": "1.4.2",
|
|
68
68
|
"@types/node": "26.6.4",
|
|
69
|
-
"effect": "4.0.
|
|
69
|
+
"effect": "4.0.6",
|
|
70
70
|
"solid-js": "1.9.17",
|
|
71
71
|
"typescript": "5.9.3"
|
|
72
72
|
}
|