opencode-courier 0.13.7 → 0.14.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 +10 -11
- package/dist/index.d.ts +0 -8
- package/dist/index.js +6 -53
- package/dist/kernel/protocol.d.ts +0 -14
- package/dist/kernel/protocol.js +1 -15
- package/dist/kernel/tool.d.ts +0 -2
- package/dist/kernel/tool.js +0 -1
- package/dist/memory/domain.d.ts +6 -85
- package/dist/memory/domain.js +7 -63
- package/dist/memory/events.d.ts +0 -11
- package/dist/memory/events.js +1 -12
- package/dist/memory/forget.d.ts +0 -5
- package/dist/memory/forget.js +0 -4
- package/dist/memory/index.js +0 -2
- package/dist/memory/lessons.d.ts +0 -8
- package/dist/memory/lessons.js +0 -9
- package/dist/memory/note.d.ts +0 -9
- package/dist/memory/note.js +0 -5
- package/dist/memory/pin.d.ts +0 -5
- package/dist/memory/pin.js +0 -4
- package/dist/memory/ports.d.ts +2 -22
- package/dist/memory/recall.d.ts +0 -5
- package/dist/memory/recall.js +0 -12
- package/dist/memory/record.d.ts +0 -4
- package/dist/memory/record.js +8 -31
- package/dist/memory/rpc-handlers.d.ts +3 -6
- package/dist/memory/rpc-handlers.js +0 -6
- package/dist/memory/rpc.d.ts +6 -19
- package/dist/memory/rpc.js +1 -16
- package/dist/memory/store.d.ts +0 -5
- package/dist/memory/store.js +1 -16
- package/dist/memory/sweep.d.ts +0 -4
- package/dist/memory/sweep.js +0 -4
- package/dist/memory/text.d.ts +0 -25
- package/dist/memory/text.js +6 -36
- package/dist/memory/tools.d.ts +0 -2
- package/dist/memory/tools.js +0 -2
- package/dist/memory/tui.d.ts +1 -35
- package/dist/person/events.d.ts +0 -16
- package/dist/person/events.js +3 -30
- package/dist/person/form.d.ts +0 -9
- package/dist/person/form.js +0 -10
- package/dist/person/index.d.ts +0 -2
- package/dist/person/permission.d.ts +0 -34
- package/dist/person/permission.js +2 -28
- package/dist/person/ports.d.ts +0 -16
- package/dist/person/ports.js +0 -1
- package/dist/person/question/answer.d.ts +0 -28
- package/dist/person/question/answer.js +0 -49
- package/dist/person/question/index.js +0 -2
- package/dist/person/question/lifecycle.d.ts +0 -26
- package/dist/person/question/lifecycle.js +1 -32
- package/dist/person/question/pure.d.ts +0 -11
- package/dist/person/question/pure.js +0 -11
- package/dist/person/question/relay.d.ts +0 -1
- package/dist/person/question/relay.js +5 -67
- package/dist/person/question/runtime.d.ts +0 -14
- package/dist/person/question/runtime.js +1 -26
- package/dist/person/question/shared.d.ts +0 -17
- package/dist/person/question/shared.js +0 -20
- package/dist/person/question/types.d.ts +0 -44
- package/dist/person/rpc-handlers.d.ts +0 -7
- package/dist/person/rpc-handlers.js +0 -6
- package/dist/person/rpc.d.ts +0 -20
- package/dist/person/rpc.js +0 -16
- package/dist/person/text.d.ts +0 -45
- package/dist/person/text.js +2 -54
- package/dist/person/tools.d.ts +0 -3
- package/dist/person/tools.js +1 -3
- package/dist/person/tui.d.ts +0 -21
- package/dist/platform/bounded.d.ts +0 -8
- package/dist/platform/bounded.js +0 -8
- package/dist/platform/events.d.ts +0 -18
- package/dist/platform/events.js +3 -22
- package/dist/platform/hub.d.ts +0 -113
- package/dist/platform/hub.js +1 -76
- package/dist/platform/json.d.ts +0 -3
- package/dist/platform/json.js +1 -3
- package/dist/platform/storage.d.ts +0 -7
- package/dist/platform/storage.js +0 -6
- package/dist/platform/version.d.ts +0 -9
- package/dist/platform/version.js +0 -8
- package/dist/rpc.js +0 -1
- package/dist/scheduling/index.d.ts +0 -1
- package/dist/scheduling/index.js +0 -1
- package/dist/scheduling/later.d.ts +0 -11
- package/dist/scheduling/later.js +0 -14
- package/dist/scheduling/text.d.ts +0 -1
- package/dist/scheduling/text.js +0 -1
- package/dist/scheduling/tools.d.ts +0 -1
- package/dist/scheduling/tools.js +1 -5
- package/dist/skill.d.ts +1 -9
- package/dist/skill.js +97 -118
- package/dist/tree/cleanup.d.ts +0 -20
- package/dist/tree/cleanup.js +0 -26
- package/dist/tree/context.d.ts +0 -5
- package/dist/tree/context.js +0 -8
- package/dist/tree/domain.d.ts +0 -64
- package/dist/tree/domain.js +7 -45
- package/dist/tree/events.d.ts +0 -36
- package/dist/tree/events.js +4 -49
- package/dist/tree/forget.d.ts +0 -15
- package/dist/tree/forget.js +0 -18
- package/dist/tree/group.d.ts +0 -22
- package/dist/tree/group.js +1 -37
- package/dist/tree/index.d.ts +2 -2
- package/dist/tree/index.js +1 -3
- package/dist/tree/limits.d.ts +0 -4
- package/dist/tree/limits.js +1 -12
- package/dist/tree/mascot.d.ts +0 -25
- package/dist/tree/mascot.js +1 -32
- package/dist/tree/model.d.ts +0 -5
- package/dist/tree/model.js +2 -15
- package/dist/tree/nudge.d.ts +0 -11
- package/dist/tree/nudge.js +3 -16
- package/dist/tree/panel.d.ts +0 -8
- package/dist/tree/panel.js +3 -16
- package/dist/tree/ports.d.ts +2 -138
- package/dist/tree/report.d.ts +0 -10
- package/dist/tree/report.js +0 -11
- package/dist/tree/roster.d.ts +0 -21
- package/dist/tree/roster.js +0 -21
- package/dist/tree/rpc-handlers.d.ts +6 -1
- package/dist/tree/rpc-handlers.js +0 -5
- package/dist/tree/rpc.d.ts +9 -109
- package/dist/tree/rpc.js +2 -38
- package/dist/tree/running.d.ts +0 -6
- package/dist/tree/running.js +2 -10
- package/dist/tree/send.d.ts +0 -4
- package/dist/tree/send.js +4 -31
- package/dist/tree/spawn.d.ts +0 -7
- package/dist/tree/spawn.js +6 -47
- package/dist/tree/standing.d.ts +0 -8
- package/dist/tree/standing.js +1 -11
- package/dist/tree/status.d.ts +0 -8
- package/dist/tree/status.js +1 -9
- package/dist/tree/stop.d.ts +2 -9
- package/dist/tree/stop.js +58 -25
- package/dist/tree/store.d.ts +0 -8
- package/dist/tree/store.js +4 -38
- package/dist/tree/subtree.d.ts +8 -26
- package/dist/tree/subtree.js +37 -35
- package/dist/tree/summary.d.ts +0 -4
- package/dist/tree/summary.js +0 -8
- package/dist/tree/text.d.ts +1 -44
- package/dist/tree/text.js +6 -66
- package/dist/tree/tools.d.ts +0 -6
- package/dist/tree/tools.js +4 -8
- package/dist/tree/tui.d.ts +0 -81
- package/dist/tree/wake.d.ts +0 -30
- package/dist/tree/wake.js +5 -39
- package/dist/tui.js +22 -8
- package/package.json +8 -9
- package/dist/webhook/index.d.ts +0 -5
- package/dist/webhook/index.js +0 -3
- package/dist/webhook/receiver.d.ts +0 -80
- package/dist/webhook/receiver.js +0 -339
- package/dist/webhook/subscriptions.d.ts +0 -29
- package/dist/webhook/subscriptions.js +0 -52
- package/dist/webhook/text.d.ts +0 -23
- package/dist/webhook/text.js +0 -82
- package/dist/webhook/tools.d.ts +0 -19
- package/dist/webhook/tools.js +0 -46
package/dist/tree/text.js
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
/** The tree's model-facing texts: the child brief, the role part, refusals, reports, notices and tool results. */
|
|
2
1
|
import { obj, str } from "../platform/json.js";
|
|
3
2
|
import { clipText, defuse, defuseBlock, END_TURN, ROOT_SPLIT_LINE, SKILL_ID, SPLIT_LINE, STATUSES } from "../kernel/protocol.js";
|
|
4
3
|
import { retryDelay } from "./domain.js";
|
|
5
|
-
// The envelope and the child brief.
|
|
6
|
-
/** How a text names the statuses a report may carry. */
|
|
7
4
|
const STATUS_LIST = `${STATUSES.slice(0, -1).join(", ")} or ${STATUSES.at(-1)}`;
|
|
8
|
-
/** The branch an isolated child commits its work on, and names in the `branch` of its report. */
|
|
9
5
|
export const childBranch = (sessionID) => `courier/${sessionID}`;
|
|
10
|
-
/** What a spawned session at `depth` is told; `depth` 1 is a child of a session nobody spawned. `branch` is for an isolated one. */
|
|
11
6
|
export function childBrief(parentID, task, depth, limits, branch) {
|
|
12
7
|
return [
|
|
13
8
|
`You were started by session ${parentID} through opencode-courier.`,
|
|
@@ -63,19 +58,13 @@ function splitRule(parentID, depth, limits) {
|
|
|
63
58
|
`session), then send ${parentID} one combined report.`,
|
|
64
59
|
];
|
|
65
60
|
}
|
|
66
|
-
/** How every role part begins, in the role entry and in the part the context hook adds without one, so no second copy is added. */
|
|
67
61
|
export const ROLE_PREFIX = "opencode-courier role:";
|
|
68
|
-
/** The key of the session instruction entry carrying a spawned session's role part, `<context key="role">` in its system prompt. */
|
|
69
62
|
export const ROLE_KEY = "role";
|
|
70
|
-
/**
|
|
71
|
-
* The system part naming a session's place in its tree: `depth` 0 for a session nobody spawned that
|
|
72
|
-
* has started one, `null` for one that has started none, which is pointed to the skill. The same on every request.
|
|
73
|
-
*/
|
|
74
63
|
export function rolePart(depth, limits) {
|
|
75
64
|
const { maxDepth, maxChildren, maxTotal } = limits;
|
|
76
65
|
const budget = `At most ${maxChildren} of the sessions you start run at once, and ${maxTotal} in the whole tree.`;
|
|
77
66
|
if (depth === null)
|
|
78
|
-
return (`${ROLE_PREFIX} root, no sessions started yet. Before a task
|
|
67
|
+
return (`${ROLE_PREFIX} root, no sessions started yet. Before a task with 2 or more independent, substantial parts touching separate files or areas, load the ` +
|
|
79
68
|
`${SKILL_ID} skill, call courier_recall once for how earlier trees in this project were split and how they went, ` +
|
|
80
69
|
`and decide whether to split it across sessions (doing it yourself is fine; so is handing a heavy task, with long ` +
|
|
81
70
|
`reading, many edits or long runs, whole to one session to keep your context, but never a small one), and say ` +
|
|
@@ -89,14 +78,9 @@ export function rolePart(depth, limits) {
|
|
|
89
78
|
return (`${ROLE_PREFIX} leaf, at depth ${depth}, the deepest the session tree goes. You cannot start sessions: do your ` +
|
|
90
79
|
"task yourself and report with courier_send to the session that started you.");
|
|
91
80
|
}
|
|
92
|
-
// The standing entry: what a parent's system prompt says of the sessions it started.
|
|
93
|
-
/** The key of the session instruction entry on a parent listing the sessions it started, `<context key="standing">`. */
|
|
94
81
|
export const STANDING_KEY = "standing";
|
|
95
|
-
/** How every standing entry begins. */
|
|
96
82
|
export const STANDING_PREFIX = "opencode-courier standing:";
|
|
97
|
-
/** How many children the entry lists; older ones past that are counted. */
|
|
98
83
|
export const STANDING_MAX = 10;
|
|
99
|
-
/** The most characters of a child's title the entry shows. */
|
|
100
84
|
const TITLE_MAX = 40;
|
|
101
85
|
function stateWords(state) {
|
|
102
86
|
const progressed = state.progressed ? ", sent progress" : "";
|
|
@@ -132,10 +116,6 @@ function groupWords(name, standing) {
|
|
|
132
116
|
return `out of ${group} (${LEFT_HOW[standing]})`;
|
|
133
117
|
}
|
|
134
118
|
}
|
|
135
|
-
/**
|
|
136
|
-
* The standing entry: one line per session the parent started, oldest first, with its state and its place in its join group,
|
|
137
|
-
* in the same words for the same state, so an unchanged standing is not put again.
|
|
138
|
-
*/
|
|
139
119
|
export function standingEntry(rows) {
|
|
140
120
|
const shown = rows.slice(-STANDING_MAX);
|
|
141
121
|
const older = rows.length - shown.length;
|
|
@@ -150,22 +130,17 @@ export function standingEntry(rows) {
|
|
|
150
130
|
...(older ? [`${count(older, "older session")} not listed; courier_children lists them.`] : []),
|
|
151
131
|
].join("\n");
|
|
152
132
|
}
|
|
153
|
-
// courier_spawn's refusals, one per limit.
|
|
154
133
|
export const depthRefusal = (depth, maxDepth) => `Not started: this session is at depth ${depth} of its session tree, and the tree goes at most ${maxDepth} deep ` +
|
|
155
134
|
"(maxDepth), so it cannot start sessions. Do the task yourself, and report with courier_send.";
|
|
156
|
-
/** How a refusal names sessions that count against a limit: those running, and those that have not reported yet. */
|
|
157
135
|
const live = (n) => (n === 1 ? "is running or has not reported yet" : "are running or have not reported yet");
|
|
158
136
|
export const childrenRefusal = (running, maxChildren) => `Not started: ${count(running, "session")} you started ${live(running)}, the most allowed at once ` +
|
|
159
137
|
`(maxChildren ${maxChildren}). Do this part yourself, or end your turn and start it once one of them has reported.`;
|
|
160
138
|
export const totalRefusal = (running, maxTotal) => `Not started: ${count(running, "session")} in this session tree ${live(running)}, the most allowed at once ` +
|
|
161
139
|
`(maxTotal ${maxTotal}). Do this part yourself, or end your turn and try again once a report has arrived.`;
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const NAMED = 12;
|
|
165
|
-
const some = (items) => (items.length > NAMED ? `${items.slice(0, NAMED).join(", ")} and ${items.length - NAMED} more` : items.join(", "));
|
|
140
|
+
const LISTED_MAX = 12;
|
|
141
|
+
const some = (items) => (items.length > LISTED_MAX ? `${items.slice(0, LISTED_MAX).join(", ")} and ${items.length - LISTED_MAX} more` : items.join(", "));
|
|
166
142
|
export const modelFormatRefusal = (given) => `Not started: model must be provider/model, as OpenCode names them (opencode/gpt-5-nano, anthropic/claude-sonnet-4-5), not ${JSON.stringify(given)}. ` +
|
|
167
143
|
"Leave it unset to run the session on your own model.";
|
|
168
|
-
/** The model is not among those OpenCode lists; `named` says the caller named it, rather than inherited it and named a variant. */
|
|
169
144
|
export function unknownModelRefusal(model, known, named) {
|
|
170
145
|
const name = `${model.providerID}/${model.id}`;
|
|
171
146
|
const ids = known.filter((item) => item.providerID === model.providerID).map((item) => item.id);
|
|
@@ -184,19 +159,12 @@ export function unknownVariantRefusal(model, variants) {
|
|
|
184
159
|
return (`Not started: the model ${model.providerID}/${model.id} has no variant ${JSON.stringify(model.variant)}. ` +
|
|
185
160
|
`Its variants are ${listed}; leave variant unset for the model's default.`);
|
|
186
161
|
}
|
|
187
|
-
/** A variant was named, but the model it would apply to could not be read: the named agent's, else the caller's own or OpenCode's default. */
|
|
188
162
|
export function variantWithoutModelRefusal(variant, agent) {
|
|
189
163
|
const why = agent ? `the agent ${agent} could not be looked up` : "neither your own model nor OpenCode's default could be read";
|
|
190
164
|
return `Not started: variant ${JSON.stringify(variant)} needs a model to apply to, and ${why}. Name a model as provider/model, or leave variant unset.`;
|
|
191
165
|
}
|
|
192
|
-
/** The strings of a list given as artifacts, whatever else the model put in it. */
|
|
193
166
|
const strings = (value) => (Array.isArray(value) ? value.flatMap((item) => (typeof item === "string" ? [item.trim()] : [])) : []).filter(Boolean);
|
|
194
|
-
/** A list's line in the artifacts block, or none when it is empty. */
|
|
195
167
|
const listed = (name, items) => (items.length ? [`- ${name}: ${items.join(", ")}`] : []);
|
|
196
|
-
/**
|
|
197
|
-
* The body of a report: its text, then the artifacts in a fixed layout, the same for every report,
|
|
198
|
-
* so a parent finds the branch, the commits, the files and the checks without reading prose.
|
|
199
|
-
*/
|
|
200
168
|
export function reportBody(message, artifacts) {
|
|
201
169
|
const given = obj(artifacts);
|
|
202
170
|
const checks = (Array.isArray(given.checks) ? given.checks : []).flatMap((check) => {
|
|
@@ -211,8 +179,6 @@ export function reportBody(message, artifacts) {
|
|
|
211
179
|
];
|
|
212
180
|
return lines.length ? [message, "", "Artifacts:", ...lines].join("\n") : message;
|
|
213
181
|
}
|
|
214
|
-
// Tool results.
|
|
215
|
-
/** courier_spawn's refusal of `native: true` with `isolate: true`: OpenCode gives a session a worktree or a parent, never both. */
|
|
216
182
|
export const nativeIsolateRefusal = () => "Not started: native: true and isolate: true cannot go together. OpenCode runs a session in a worktree of its own or as a " +
|
|
217
183
|
"subagent of its parent, never both. Start it with isolate: true alone for a worktree of its own, or with native: true alone for a subagent in your directory.";
|
|
218
184
|
export function spawnText(child) {
|
|
@@ -231,7 +197,6 @@ export function spawnText(child) {
|
|
|
231
197
|
return (`Started session ${child.sessionID} in ${child.directory}${on}. ${reports} Once you have started every session you need, ` +
|
|
232
198
|
`end your turn: reply without calling more tools. That does not drop the task; you carry on with it when the reports arrive.${warning}`);
|
|
233
199
|
}
|
|
234
|
-
/** courier_send's result: for a message to the session that started the sender, whether it was its report; below it, the status dropped. */
|
|
235
200
|
export function sendText(sessionID, sent = {}) {
|
|
236
201
|
if (sent.dropped)
|
|
237
202
|
return (`Delivered to ${sessionID}, without the status ${sent.dropped}: a status belongs on a report to the session that ` +
|
|
@@ -266,7 +231,6 @@ export function cleanupText(result) {
|
|
|
266
231
|
return done;
|
|
267
232
|
return `${done} Dropped it from group "${result.group}" without a report: the group's other reports reach you once they are in and your turn has ended, the message naming it, and a report it sends after all comes on its own.`;
|
|
268
233
|
}
|
|
269
|
-
/** courier_tree's result: the sessions under a session, drawn depth first, as JSON. */
|
|
270
234
|
export function treeText(tree) {
|
|
271
235
|
if (!tree.sessions.length)
|
|
272
236
|
return "No sessions started with courier_spawn.";
|
|
@@ -276,14 +240,13 @@ export function treeText(tree) {
|
|
|
276
240
|
const note = `\n${older} not listed: at most maxTotal are, the live ones first, then the newest; courier_tree on a listed session lists what is under it.`;
|
|
277
241
|
return JSON.stringify(tree, null, 2) + note;
|
|
278
242
|
}
|
|
279
|
-
/** What courier_stop did to each session, and to the messages and worktrees. */
|
|
280
243
|
export function stopText(result) {
|
|
281
244
|
const interrupted = result.stopped.filter((one) => one.outcome === "interrupted").length;
|
|
282
245
|
const failed = result.stopped.filter((one) => one.outcome === "failed");
|
|
283
246
|
return [
|
|
284
247
|
`Stopped ${result.sessionID} and ${count(result.stopped.length - 1, "session")} under it, deepest first: ${interrupted} had a turn running and was interrupted, ` +
|
|
285
248
|
`${result.stopped.filter((one) => one.outcome === "idle" || one.outcome === "gone").length} did not run.`,
|
|
286
|
-
...result.stopped.map((one) => `- ${one.sessionID}: ${one.outcome}${one.error ? " (" + one.error + ")" : ""}`),
|
|
249
|
+
...result.stopped.map((one) => `- ${one.sessionID}${one.subagent ? " (subagent)" : ""}: ${one.outcome}${one.error ? " (" + one.error + ")" : ""}`),
|
|
287
250
|
...(failed.length ? ["Those that failed may still run: try courier_stop again."] : []),
|
|
288
251
|
result.cancelled.length
|
|
289
252
|
? `Cancelled ${count(result.cancelled.length, "scheduled message")}: ${result.cancelled.join(", ")}.`
|
|
@@ -293,7 +256,6 @@ export function stopText(result) {
|
|
|
293
256
|
].join("\n");
|
|
294
257
|
}
|
|
295
258
|
const FORCE_HINT = " Commit or branch what you want to keep, or call courier_cleanup again with force: true to discard it.";
|
|
296
|
-
/** courier_stop's lines on the worktrees it was asked to remove. */
|
|
297
259
|
function worktreeLines(cleanup) {
|
|
298
260
|
if (!cleanup.length)
|
|
299
261
|
return ["None of them ran in a worktree of its own."];
|
|
@@ -301,12 +263,10 @@ function worktreeLines(cleanup) {
|
|
|
301
263
|
? `Worktree of ${one.sessionID}: not removed (${one.error}).`
|
|
302
264
|
: cleanupText(one).replace(FORCE_HINT, " Kept; courier_cleanup with force: true discards it."));
|
|
303
265
|
}
|
|
304
|
-
/** What the parent of a stopped session is told when the stop was ordered by a session above both. */
|
|
305
266
|
export const stoppedNotice = (title, by) => [
|
|
306
267
|
`This session, "${title}", which you started with courier_spawn, was stopped by ${by}, a session above you, together with the sessions under it.`,
|
|
307
268
|
"It was not a failure and it will not report back. Carry on without it, or start a replacement if you still need what it was doing.",
|
|
308
269
|
].join("\n");
|
|
309
|
-
/** Why a worktree in this state must be kept, or undefined when removing it loses nothing. */
|
|
310
270
|
export function keepReason(state) {
|
|
311
271
|
const reasons = [
|
|
312
272
|
state.changes.length ? `${count(state.changes.length, "uncommitted change")} (${preview(state.changes)})` : "",
|
|
@@ -322,8 +282,6 @@ function count(n, noun) {
|
|
|
322
282
|
function preview(items) {
|
|
323
283
|
return items.length > 5 ? `${items.slice(0, 5).join(", ")}, ...` : items.join(", ");
|
|
324
284
|
}
|
|
325
|
-
// Turn failures.
|
|
326
|
-
/** A wait in whole minutes, rounded up: "1 minute", "45 minutes", "2 hours 5 minutes". */
|
|
327
285
|
function wait(ms) {
|
|
328
286
|
const minutes = Math.ceil(ms / 60_000);
|
|
329
287
|
if (minutes < 60)
|
|
@@ -331,20 +289,14 @@ function wait(ms) {
|
|
|
331
289
|
const rest = minutes % 60;
|
|
332
290
|
return [count(Math.floor(minutes / 60), "hour"), rest ? count(rest, "minute") : ""].filter(Boolean).join(" ");
|
|
333
291
|
}
|
|
334
|
-
/** A time as the notices say it, in UTC, with its date when it is not the day of `from`. */
|
|
335
292
|
function clock(at, from) {
|
|
336
293
|
const iso = new Date(at).toISOString();
|
|
337
294
|
return iso.slice(0, 10) === new Date(from).toISOString().slice(0, 10) ? `${iso.slice(11, 16)} UTC` : `${iso.slice(0, 10)} ${iso.slice(11, 16)} UTC`;
|
|
338
295
|
}
|
|
339
|
-
/** The line saying how long the provider asked to wait, and until when if the failure's time `at` is known. */
|
|
340
296
|
function waitLine(delay, at) {
|
|
341
297
|
const until = at === undefined ? "" : `, until about ${clock(at + delay, at)}`;
|
|
342
298
|
return `The provider asked to wait about ${wait(delay)} before trying again${until}.`;
|
|
343
299
|
}
|
|
344
|
-
/**
|
|
345
|
-
* What the parent is told when a session it started failed its turn; `at` is when the failure happened, which the provider's
|
|
346
|
-
* retry time (`retryAfterMs`) counts from. Message the child before that and it fails again, so the notice says to wait.
|
|
347
|
-
*/
|
|
348
300
|
export function failureNotice(title, error, group, at) {
|
|
349
301
|
const status = error.status === undefined ? "" : `, status ${error.status}`;
|
|
350
302
|
const delay = retryDelay(error);
|
|
@@ -364,7 +316,6 @@ export function failureNotice(title, error, group, at) {
|
|
|
364
316
|
: []),
|
|
365
317
|
].join("\n");
|
|
366
318
|
}
|
|
367
|
-
/** The one reminder a spawned session gets as it is about to end its turn owing its parent a report; it carries on in the same turn. */
|
|
368
319
|
export function reportReminder(parentID) {
|
|
369
320
|
return [
|
|
370
321
|
`You are about to end your turn without reporting to session ${parentID}, which started you.`,
|
|
@@ -373,12 +324,7 @@ export function reportReminder(parentID) {
|
|
|
373
324
|
"This reminder comes once: if you end your turn without a report, the session that started you is told.",
|
|
374
325
|
].join("\n");
|
|
375
326
|
}
|
|
376
|
-
|
|
377
|
-
const MAX_REPLY = 2000;
|
|
378
|
-
/**
|
|
379
|
-
* What the parent is told when a session it started ends its turn without a report to it;
|
|
380
|
-
* `progressed` when it messaged the parent without a status since its last prompt.
|
|
381
|
-
*/
|
|
327
|
+
const QUOTED_REPLY_MAX = 2000;
|
|
382
328
|
export function silentNotice(title, lastText, progressed = false, group) {
|
|
383
329
|
const reply = lastText?.trim();
|
|
384
330
|
return [
|
|
@@ -386,7 +332,7 @@ export function silentNotice(title, lastText, progressed = false, group) {
|
|
|
386
332
|
...(progressed
|
|
387
333
|
? [`Its last message to you had no status, so it was progress, not its report: a report carries status ${STATUS_LIST}.`]
|
|
388
334
|
: []),
|
|
389
|
-
...(reply ? ["Its last reply:", defuse(clipText(reply,
|
|
335
|
+
...(reply ? ["Its last reply:", defuse(clipText(reply, QUOTED_REPLY_MAX))] : ["It ended without a reply."]),
|
|
390
336
|
"",
|
|
391
337
|
"Decide what it needs: message it with courier_send to have it carry on, or to report if its last reply is what you needed; or start a replacement.",
|
|
392
338
|
"Until it reports, it counts toward your limits on the sessions you run at once.",
|
|
@@ -398,8 +344,6 @@ export function silentNotice(title, lastText, progressed = false, group) {
|
|
|
398
344
|
: []),
|
|
399
345
|
].join("\n");
|
|
400
346
|
}
|
|
401
|
-
// Join groups.
|
|
402
|
-
/** How a release names each status among its reports: `2 done, 1 failed`. */
|
|
403
347
|
function statusCounts(reports) {
|
|
404
348
|
return STATUSES.flatMap((status) => {
|
|
405
349
|
const n = reports.filter((report) => report.status === status).length;
|
|
@@ -412,10 +356,6 @@ const LEFT_HOW = {
|
|
|
412
356
|
deleted: "it was deleted",
|
|
413
357
|
dropped: "you dropped it with courier_cleanup",
|
|
414
358
|
};
|
|
415
|
-
/**
|
|
416
|
-
* What the parent gets when a group it named is released: every report, with its status, text and artifacts in
|
|
417
|
-
* `reportBody`'s layout, and the members that left without one, in the order they joined.
|
|
418
|
-
*/
|
|
419
359
|
export function groupNotice(group, reports, left = []) {
|
|
420
360
|
const total = reports.length + left.length;
|
|
421
361
|
const listed = reports.flatMap((report, index) => [
|
package/dist/tree/tools.d.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
2
|
import { type ToolEditor } from "../kernel/tool.js";
|
|
3
3
|
import type { CleanupPorts, CourierPorts, StopPorts } from "./ports.js";
|
|
4
|
-
/**
|
|
5
|
-
* The tree's courier tools: their input schemas, descriptions, and what each returns. The descriptions are
|
|
6
|
-
* model-facing like the texts in `text.ts`, and snapshotted with them in `test/notices.test.ts`.
|
|
7
|
-
*/
|
|
8
4
|
export declare const SpawnInput: Schema.Struct<{
|
|
9
5
|
readonly task: Schema.String;
|
|
10
6
|
readonly title: Schema.optional<Schema.String>;
|
|
@@ -44,11 +40,9 @@ export declare const CleanupInput: Schema.Struct<{
|
|
|
44
40
|
readonly sessionID: Schema.String;
|
|
45
41
|
readonly force: Schema.optional<Schema.Boolean>;
|
|
46
42
|
}>;
|
|
47
|
-
/** What the tree's tools run on: one plugin instance's ports. */
|
|
48
43
|
export interface TreeToolPorts {
|
|
49
44
|
readonly courier: CourierPorts;
|
|
50
45
|
readonly cleanup: CleanupPorts;
|
|
51
46
|
readonly stop: StopPorts;
|
|
52
47
|
}
|
|
53
|
-
/** Adds the tree's courier tools, each a direct tool rather than a code-mode one. */
|
|
54
48
|
export declare function addTreeTools(tools: ToolEditor, ports: TreeToolPorts): void;
|
package/dist/tree/tools.js
CHANGED
|
@@ -8,10 +8,6 @@ import { listChildren } from "./status.js";
|
|
|
8
8
|
import { stop } from "./stop.js";
|
|
9
9
|
import { tree } from "./subtree.js";
|
|
10
10
|
import { childrenText, cleanupText, sendText, spawnText, stopText, treeText } from "./text.js";
|
|
11
|
-
/**
|
|
12
|
-
* The tree's courier tools: their input schemas, descriptions, and what each returns. The descriptions are
|
|
13
|
-
* model-facing like the texts in `text.ts`, and snapshotted with them in `test/notices.test.ts`.
|
|
14
|
-
*/
|
|
15
11
|
export const SpawnInput = Schema.Struct({
|
|
16
12
|
task: Schema.String.annotate({ description: "What the new session should do. It is told who started it and how to report back." }),
|
|
17
13
|
title: Schema.optional(Schema.String.annotate({ description: "Session title; defaults to the task's first line." })),
|
|
@@ -80,7 +76,6 @@ export const CleanupInput = Schema.Struct({
|
|
|
80
76
|
description: "Remove it even with uncommitted changes or commits on no branch; that work is lost.",
|
|
81
77
|
})),
|
|
82
78
|
});
|
|
83
|
-
/** Adds the tree's courier tools, each a direct tool rather than a code-mode one. */
|
|
84
79
|
export function addTreeTools(tools, ports) {
|
|
85
80
|
tools.add({
|
|
86
81
|
name: "courier_spawn",
|
|
@@ -132,7 +127,8 @@ export function addTreeTools(tools, ports) {
|
|
|
132
127
|
options: { codemode: false },
|
|
133
128
|
description: "List the whole tree of sessions under this one (or under sessionID): every session started with courier_spawn " +
|
|
134
129
|
"from it, directly or through others, each with its depth, what courier_children shows, and whether it still " +
|
|
135
|
-
"owes a report, sent progress, or ended without one
|
|
130
|
+
"owes a report, sent progress, or ended without one, and the subagents OpenCode's subagent tool started in it, " +
|
|
131
|
+
"marked subagent: true, which owe no report. For a one-off look, not for waiting. A long tree lists at most " +
|
|
136
132
|
"maxTotal sessions, the live ones first, then the newest, and says how many older ones are left out.",
|
|
137
133
|
input: TreeInput,
|
|
138
134
|
execute: async (input, context) => {
|
|
@@ -143,8 +139,8 @@ export function addTreeTools(tools, ports) {
|
|
|
143
139
|
tools.add({
|
|
144
140
|
name: "courier_stop",
|
|
145
141
|
options: { codemode: false },
|
|
146
|
-
description: "Stop a session you started, directly or through others, and every session under it: each
|
|
147
|
-
"interrupted, deepest first, and the messages scheduled for them with courier_later are cancelled. Use it when a " +
|
|
142
|
+
description: "Stop a session you started, directly or through others, and every session under it, subagents included: each " +
|
|
143
|
+
"running turn is interrupted, deepest first, and the messages scheduled for them with courier_later are cancelled. Use it when a " +
|
|
148
144
|
"subtree went wrong or is no longer needed. They do not report back, and you are not told of what you stopped; a " +
|
|
149
145
|
"session between you and the target is. A stopped session can be woken again with courier_send. With " +
|
|
150
146
|
"cleanup: true their worktrees are removed too, unless they hold work that is on no branch.",
|
package/dist/tree/tui.d.ts
CHANGED
|
@@ -4,106 +4,62 @@ import { type Accessor } from "solid-js";
|
|
|
4
4
|
import { type MascotState, type Token } from "./mascot.js";
|
|
5
5
|
import { type Forgotten, type Row, type Stopped, type Summary, type Wait } from "./rpc.js";
|
|
6
6
|
type Context = Plugin.Context;
|
|
7
|
-
/**
|
|
8
|
-
* The events after which a summary may read differently: a turn started or ended, a request or form, a session made, removed,
|
|
9
|
-
* archived or unarchived.
|
|
10
|
-
*/
|
|
11
7
|
export declare const CHANGES: Set<string>;
|
|
12
|
-
/** How long after the first of a burst of changes the entry asks the server again. */
|
|
13
8
|
export declare const SETTLE_MS = 250;
|
|
14
|
-
/** The panel's settle: each of its asks reads every row's messages, so a busy tree is asked at most once a second. */
|
|
15
9
|
export declare const PANEL_SETTLE_MS = 1000;
|
|
16
|
-
/** The name of the tree panel in the `session.panel` slot. */
|
|
17
10
|
export declare const PANEL = "courier-tree";
|
|
18
|
-
/** How often the panel redraws its running times and how long ago each last tool call was. */
|
|
19
11
|
export declare const TICK_MS = 1000;
|
|
20
|
-
/** The panel's animation frame: the spinner's step, and how often a flash or the bar's easing moves. */
|
|
21
12
|
export declare const FRAME_MS = 90;
|
|
22
|
-
/** How long a row's background takes to fade back from its flash after its report arrives: the report's hold. */
|
|
23
13
|
export declare const FLASH_MS = 1500;
|
|
24
|
-
/** How long the header's bar takes to grow, or shrink, to its new length. */
|
|
25
14
|
export declare const BAR_MS = 450;
|
|
26
|
-
/** Whether the panel animates: unless the TUI part's options say `"animations": false`, as the plugin API has no TUI setting for it. */
|
|
27
15
|
export declare function animationsOn(options: Readonly<Record<string, unknown>> | undefined): boolean;
|
|
28
|
-
/** A value eased over the panel's frames by OpenTUI's `Timeline`; reading it in a computation follows the frames. */
|
|
29
16
|
export type Tween = {
|
|
30
17
|
readonly value: () => number;
|
|
31
18
|
readonly done: () => boolean;
|
|
32
19
|
};
|
|
33
|
-
/**
|
|
34
|
-
* The panel's one timer: a frame every `FRAME_MS` while a tween moves or an `animates` predicate holds, every `every` while
|
|
35
|
-
* only slower ones do, none otherwise, with animations off or once the panel is gone. `frame` counts in `FRAME_MS`.
|
|
36
|
-
*/
|
|
37
20
|
export type Motion = {
|
|
38
21
|
readonly enabled: boolean;
|
|
39
22
|
readonly frame: Accessor<number>;
|
|
40
23
|
readonly animates: (when: Accessor<boolean>, every?: number) => void;
|
|
41
24
|
readonly tween: (from: number, to: number, duration: number, ease: EasingFunctions) => Tween;
|
|
42
25
|
};
|
|
43
|
-
/** The panel's `Motion`, owned by the computation it is made in. */
|
|
44
26
|
export declare function createMotion(enabled: boolean): Motion;
|
|
45
|
-
/**
|
|
46
|
-
* Each row's flash, by session, from a read of the rows to the next that finds its report turned to `reported`; not on
|
|
47
|
-
* the first read. `strength` is a row's, 1 when its report arrives down to 0; `reported` holds for `FLASH_MS` after one.
|
|
48
|
-
*/
|
|
49
27
|
export declare function createFlashes(motion: Motion, rows: Accessor<ReadonlyArray<Row>>): {
|
|
50
28
|
strength: (sessionID: string) => number;
|
|
51
29
|
reported: () => boolean;
|
|
52
30
|
};
|
|
53
|
-
/** The header bar's filled cells, eased over `BAR_MS` to its new length once it is shown, at once when it first is. */
|
|
54
31
|
export declare function createBarFill(motion: Motion, counts: Accessor<{
|
|
55
32
|
reported: number;
|
|
56
33
|
started: number;
|
|
57
34
|
}>): () => number;
|
|
58
|
-
/** True for `FLASH_MS` after a read of the tree finds a session the one before it did not have; not on the first read. */
|
|
59
35
|
export declare function createSpawns(motion: Motion, rows: Accessor<ReadonlyArray<Row> | undefined>): () => boolean;
|
|
60
|
-
/**
|
|
61
|
-
* Digby's state for the tree's rows and its `top`, by `summaryLine`'s priority, unless a report or a spawn just arrived;
|
|
62
|
-
* gone when every row under the top is.
|
|
63
|
-
*/
|
|
64
36
|
export declare function mascotState(rows: ReadonlyArray<Row>, { top, reported, spawned }?: {
|
|
65
37
|
top?: Row;
|
|
66
38
|
reported?: boolean;
|
|
67
39
|
spawned?: boolean;
|
|
68
40
|
}): MascotState;
|
|
69
|
-
/** What the tree's sessions do, as the header's second line says it: "1 waiting on you · 2 running"; empty with none live. */
|
|
70
41
|
export declare function countsLine(rows: ReadonlyArray<Row>): string;
|
|
71
|
-
/** The panel's size below which it shows no header glyph, so the header keeps to one line and its bar is not cut. */
|
|
72
42
|
export declare const GLYPH_ROWS = 12;
|
|
73
43
|
export declare const GLYPH_COLUMNS = 54;
|
|
74
|
-
/** The empty panel's height from which it shows the 16×16. */
|
|
75
44
|
export declare const ART_ROWS = 14;
|
|
76
|
-
/** The rows left free below the tree's last row from which the 16×16 shows there. */
|
|
77
45
|
export declare const BELOW_ROWS = 10;
|
|
78
|
-
/** `tint` over `rest` by `amount`, from 0 (all `rest`) to 1 (all `tint`). */
|
|
79
46
|
export declare function blend(tint: RGBA, rest: RGBA, amount: number): RGBA;
|
|
80
|
-
/**
|
|
81
|
-
* The status entry's text, such as "courier 1 waiting on you · 2 running · group pair 1/2"; empty when there is nothing to show.
|
|
82
|
-
* Within `maxWidth` it keeps whole parts, most important first, and counts the groups it drops: "· +2 groups".
|
|
83
|
-
*/
|
|
84
47
|
export declare function summaryLine(summary: Summary, maxWidth?: number): string;
|
|
85
|
-
/** A span of time, coarsest first: "45s", "3m 05s", "2h 07m". */
|
|
86
48
|
export declare function duration(ms: number): string;
|
|
87
|
-
/** How many of a session's children have reported, out of those it started, among the rows read. */
|
|
88
49
|
export declare function parts(rows: ReadonlyArray<Row>, parentID: string): {
|
|
89
50
|
reported: number;
|
|
90
51
|
started: number;
|
|
91
52
|
};
|
|
92
|
-
/** How many of a bar's `width` cells are filled for the parts reported. */
|
|
93
53
|
export declare function filledCells({ reported, started }: {
|
|
94
54
|
reported: number;
|
|
95
55
|
started: number;
|
|
96
56
|
}, width?: number): number;
|
|
97
|
-
/** A bar of parts reported, `width` cells wide: "[████░░░░░░] 2/5 reported"; `filled` cells of it while it eases to its length. */
|
|
98
57
|
export declare function bar(counts: {
|
|
99
58
|
reported: number;
|
|
100
59
|
started: number;
|
|
101
60
|
}, width?: number, filled?: number): string;
|
|
102
|
-
/** What a paused session waits on, such as "asks permission: shell echo hi" or "shows a form: Web Search". */
|
|
103
61
|
export declare function waitLine(wait: Wait): string;
|
|
104
|
-
/** What a row's session is doing, its report and its group standing: "idle · reported done · group pair held". */
|
|
105
62
|
export declare function statusLine(row: Row, now?: number): string;
|
|
106
|
-
/** The parts of `statusLine`, each with the row part the panel colours it as. */
|
|
107
63
|
export declare function statusParts(row: Row, now?: number): {
|
|
108
64
|
text: string;
|
|
109
65
|
kind: "state" | "report" | "plain";
|
|
@@ -115,72 +71,35 @@ type Feedback<Color> = {
|
|
|
115
71
|
}>;
|
|
116
72
|
};
|
|
117
73
|
};
|
|
118
|
-
/** The running mark's frames, one every `FRAME_MS`. */
|
|
119
74
|
export declare const SPINNER: string[];
|
|
120
|
-
/**
|
|
121
|
-
* The one cell a row's state shows and its theme colour, the blank cell of one with no mark: this is the only place that
|
|
122
|
-
* chooses them. A running row spins through `SPINNER` at the panel's `frame`, and shows `•` with none (animations off).
|
|
123
|
-
*/
|
|
124
75
|
export declare function rowMark<Color>(row: Row, theme: Feedback<Color>, frame?: number): {
|
|
125
76
|
mark: string;
|
|
126
77
|
color: Color | undefined;
|
|
127
78
|
};
|
|
128
|
-
/** Past this fraction of its window, a session's context use is shown in the warning colour. */
|
|
129
79
|
export declare const CONTEXT_WARN = 0.8;
|
|
130
|
-
/** A leaf's activity: how long it has run, its last tool call and how long ago, its context use and its cost. */
|
|
131
80
|
export declare function activityParts(row: Row, now: number): string[];
|
|
132
81
|
export declare const activityLine: (row: Row, now: number) => string;
|
|
133
|
-
/** What a stalled session's row, or the panel of one, says of it: "a message waits in its inbox since 2m 05s, woken again in vain". */
|
|
134
82
|
export declare function stalledLine(since: number, now: number): string;
|
|
135
|
-
/** 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. */
|
|
136
83
|
export declare function detailLines(row: Row, rows: ReadonlyArray<Row>, now: number): string[];
|
|
137
|
-
/**
|
|
138
|
-
* Each row's tree guides, by session, for rows in the order a tree is drawn, below depth `base`: before its mark ("│ ├ "),
|
|
139
|
-
* and before its detail lines, which carry a line down to its first child ("│ │ ").
|
|
140
|
-
*/
|
|
141
84
|
export declare function guides(rows: ReadonlyArray<Row>, base: number): Map<string, {
|
|
142
85
|
row: string;
|
|
143
86
|
detail: string;
|
|
144
87
|
}>;
|
|
145
|
-
/** How often the footer and the panel ask again with no event: the scheduler flags a stalled session without one. */
|
|
146
88
|
export declare const REREAD_MS = 15000;
|
|
147
|
-
/**
|
|
148
|
-
* Adds the tree's entry to the prompt's footer: what the sessions under the open session do, asked of the RPC after each
|
|
149
|
-
* change and every `REREAD_MS`; nothing on the home screen. Clicked while some wait on the person, it calls `onWaiting`.
|
|
150
|
-
*/
|
|
151
89
|
export declare function addTreeStatus(ctx: Context, onWaiting?: (sessionID: string) => void): () => void;
|
|
152
|
-
/** The toast after a stop: how many sessions were interrupted, and how many scheduled messages were cancelled. */
|
|
153
90
|
export declare function stoppedLine({ stopped, cancelled }: Stopped): string;
|
|
154
|
-
/** The toast after a forget, as courier_cleanup reports it: forgotten, its worktree removed or already gone, or kept and why. */
|
|
155
91
|
export declare function forgottenLine(title: string, result: Forgotten): string;
|
|
156
|
-
/** The one place Digby's pixel tokens take a theme colour. */
|
|
157
92
|
export declare const digbyColours: (theme: Context["theme"]) => Record<Token, RGBA>;
|
|
158
|
-
/**
|
|
159
|
-
* A row's background at rest: the selection's while the panel has the keyboard, else one step quieter under the pointer,
|
|
160
|
-
* else none, the panel's.
|
|
161
|
-
*/
|
|
162
93
|
export declare function restBackground(theme: Context["theme"], { selected, hovered }: {
|
|
163
94
|
selected: boolean;
|
|
164
95
|
hovered: boolean;
|
|
165
96
|
}): RGBA | undefined;
|
|
166
|
-
/** The usage the `/courier` command shows for an input it does not know, before the further verbs' lines. */
|
|
167
97
|
export declare const USAGE = "/courier tree opens the session tree; /courier stop [session] stops a session and those under it";
|
|
168
|
-
/** A further verb of the `/courier` command, which another module's TUI part supplies: what it runs, and its line of the usage. */
|
|
169
98
|
export type Verb = {
|
|
170
99
|
readonly run: () => void;
|
|
171
100
|
readonly usage: string;
|
|
172
101
|
};
|
|
173
|
-
/** The usage with the further verbs' lines. */
|
|
174
102
|
export declare const usageWith: (verbs: Readonly<Record<string, Verb>>) => string;
|
|
175
|
-
/**
|
|
176
|
-
* Adds the tree panel to the `session.panel` slot, opened by `/courier tree` or the palette, which follows the person
|
|
177
|
-
* between sessions until closed, and `/courier stop <session>`, which stops a session under the open one once confirmed;
|
|
178
|
-
* `verbs` are the command's further verbs, by name.
|
|
179
|
-
*/
|
|
180
103
|
export declare function addTreePanel(ctx: Context, verbs?: Readonly<Record<string, Verb>>): () => void;
|
|
181
|
-
/**
|
|
182
|
-
* Draws the person's attention when reports arrive: a join group's reports, released to the session that started them,
|
|
183
|
-
* and a child's report to its parent, with the `subagent_done` sound. Read from the courier's own delivery metadata.
|
|
184
|
-
*/
|
|
185
104
|
export declare function addTreeAttention(ctx: Context): () => void;
|
|
186
105
|
export {};
|
package/dist/tree/wake.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { GroupPorts, Wake, WatchPorts } from "./ports.js";
|
|
2
|
-
/** How long a courier message may wait in an idle session's inbox before its wake counts as missed. */
|
|
3
2
|
export declare const WAKE_MS = 30000;
|
|
4
|
-
/** OpenCode's `session.inbox.enqueued`, with the item's payload, which carries the courier's metadata. */
|
|
5
3
|
export interface Enqueued {
|
|
6
4
|
readonly created?: number;
|
|
7
5
|
readonly data: {
|
|
@@ -20,68 +18,40 @@ export interface Enqueued {
|
|
|
20
18
|
};
|
|
21
19
|
};
|
|
22
20
|
}
|
|
23
|
-
/** OpenCode's `session.inbox.delivered` and `session.inbox.cancelled`. */
|
|
24
21
|
export interface InboxSettled {
|
|
25
22
|
readonly data: {
|
|
26
23
|
readonly sessionID: string;
|
|
27
24
|
readonly inboxID: string;
|
|
28
25
|
};
|
|
29
26
|
}
|
|
30
|
-
/** OpenCode's `session.execution.*` events, which frame a session's busy period. */
|
|
31
27
|
export interface Execution {
|
|
32
28
|
readonly created?: number;
|
|
33
29
|
readonly data: {
|
|
34
30
|
readonly sessionID: string;
|
|
35
31
|
};
|
|
36
32
|
}
|
|
37
|
-
/**
|
|
38
|
-
* Watches a courier message enqueued for a session until it is delivered, noting whether the session runs.
|
|
39
|
-
* Returns whether it is watched, which one sent with `resume: false` is not.
|
|
40
|
-
*/
|
|
41
33
|
export declare function watchWake(ports: WatchPorts, event: Enqueued): Promise<boolean>;
|
|
42
|
-
/**
|
|
43
|
-
* Watches a message `courier_send` has just had enqueued, without waiting for its enqueued event, so the limits see a reported child woken
|
|
44
|
-
* for it at once; the event leaves this row be. Dropped again if the message is already stored, delivered before it was written.
|
|
45
|
-
*/
|
|
46
34
|
export declare function noteSent(ports: Pick<WatchPorts, "storage" | "session" | "now">, sent: {
|
|
47
35
|
readonly sessionID: string;
|
|
48
36
|
readonly inboxID: string;
|
|
49
37
|
readonly text: string;
|
|
50
38
|
readonly description?: string;
|
|
51
39
|
}): Promise<void>;
|
|
52
|
-
/** Stops watching a message once it is delivered or cancelled. */
|
|
53
40
|
export declare function settleWake(ports: Pick<WatchPorts, "storage">, event: InboxSettled): Promise<void>;
|
|
54
|
-
/** A turn started in a session: the messages waiting there are its to take. */
|
|
55
41
|
export declare function wakeStarted(ports: Pick<WatchPorts, "storage">, event: Execution): Promise<void>;
|
|
56
|
-
/**
|
|
57
|
-
* A session's turn ended: a message it took is no longer watched, as its delivery may have been missed by this
|
|
58
|
-
* subscription; one still waiting is watched as waiting in an idle session from now.
|
|
59
|
-
*/
|
|
60
42
|
export declare function wakeEnded(ports: WatchPorts, event: Execution & {
|
|
61
43
|
readonly data: {
|
|
62
44
|
readonly reason?: string;
|
|
63
45
|
};
|
|
64
46
|
}): Promise<void>;
|
|
65
|
-
/** Forgets the messages watched in a session's inbox: it was deleted, or stopped, which nothing is to wake again. */
|
|
66
47
|
export declare function forgetWakes(ports: Pick<WatchPorts, "storage">, sessionID: string): Promise<void>;
|
|
67
|
-
/** The ports the scheduler's tick wakes sessions through: what every hub-v2 member's `later` ports have, whose session is its `ctx.session`. */
|
|
68
48
|
export type WakePorts = GroupPorts & {
|
|
69
49
|
readonly session: Pick<WatchPorts["session"], "get" | "context">;
|
|
70
50
|
readonly now: () => number;
|
|
71
51
|
};
|
|
72
|
-
/**
|
|
73
|
-
* Sends once more, under its inbox id, each courier message an idle session has left waiting for `WAKE_MS`, flags stalled one still
|
|
74
|
-
* waiting `WAKE_MS` later, and marks running one a turn it shows will take; run by the scheduler's owner, `claimed` keeping a tick alongside off it.
|
|
75
|
-
*/
|
|
76
52
|
export declare function wakeMissed(ports: WakePorts, claimed: Set<string>): Promise<void>;
|
|
77
|
-
/** 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. */
|
|
78
53
|
export declare function missed(wake: Wake, now: number): boolean;
|
|
79
|
-
/**
|
|
80
|
-
* Whether a courier message sent with a wake waits undelivered in the session's inbox while it is idle, waiting or, unless
|
|
81
|
-
* `stalled` is false, stalled; one a running turn is to take is not counted, as `runs` says that turn runs.
|
|
82
|
-
*/
|
|
83
54
|
export declare function waitsInInbox(ports: Pick<WatchPorts, "storage">, sessionID: string, { stalled }?: {
|
|
84
55
|
stalled?: boolean | undefined;
|
|
85
56
|
}): Promise<boolean>;
|
|
86
|
-
/** The sessions among `sessionIDs` flagged stalled, each with when its oldest stalled message was enqueued. */
|
|
87
57
|
export declare function stalledAmong(ports: Pick<WatchPorts, "storage">, sessionIDs: ReadonlyArray<string>): Promise<Map<string, number>>;
|