opencode-courier 0.10.1 → 0.10.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 +25 -13
- package/dist/memory/domain.d.ts +4 -1
- package/dist/memory/events.js +7 -5
- package/dist/memory/record.js +33 -14
- package/dist/scheduling/later.d.ts +2 -2
- package/dist/tree/domain.d.ts +29 -5
- package/dist/tree/domain.js +23 -4
- package/dist/tree/events.d.ts +7 -2
- package/dist/tree/events.js +19 -5
- package/dist/tree/group.js +2 -2
- package/dist/tree/index.d.ts +3 -2
- package/dist/tree/index.js +3 -2
- package/dist/tree/limits.js +10 -7
- package/dist/tree/panel.js +3 -5
- package/dist/tree/ports.d.ts +1 -1
- package/dist/tree/running.d.ts +18 -0
- package/dist/tree/running.js +58 -0
- package/dist/tree/send.js +7 -2
- package/dist/tree/status.d.ts +5 -0
- package/dist/tree/status.js +1 -0
- package/dist/tree/subtree.d.ts +6 -1
- package/dist/tree/subtree.js +6 -3
- package/dist/tree/summary.js +3 -4
- package/dist/tree/tui.d.ts +4 -1
- package/dist/tree/wake.d.ts +21 -3
- package/dist/tree/wake.js +51 -18
- package/dist/tui.js +47 -47
- package/package.json +5 -5
package/dist/tui.js
CHANGED
|
@@ -312,7 +312,7 @@ function addMemoryView(ctx) {
|
|
|
312
312
|
} : chosen(value)), requested]);
|
|
313
313
|
}
|
|
314
314
|
const showList = (read, current) => {
|
|
315
|
-
const
|
|
315
|
+
const open = openSession();
|
|
316
316
|
const now = Date.now();
|
|
317
317
|
return show({
|
|
318
318
|
title: `Memory (${read.records.length})`,
|
|
@@ -321,7 +321,7 @@ function addMemoryView(ctx) {
|
|
|
321
321
|
current
|
|
322
322
|
} : {},
|
|
323
323
|
options: read.records.map((record) => ({
|
|
324
|
-
title: recordTitle(record,
|
|
324
|
+
title: recordTitle(record, open),
|
|
325
325
|
value: record,
|
|
326
326
|
category: recordCategory(record, now),
|
|
327
327
|
description: recordDescription(record),
|
|
@@ -865,12 +865,12 @@ function addAsksInbox(ctx, follows) {
|
|
|
865
865
|
} = ask;
|
|
866
866
|
const answers = [];
|
|
867
867
|
for (const [index, prompt] of question.questions.entries()) {
|
|
868
|
-
const
|
|
868
|
+
const count = question.questions.length > 1 ? ` (${index + 1}/${question.questions.length})` : "";
|
|
869
869
|
const choices = prompt.options.map((option) => ({
|
|
870
870
|
...option,
|
|
871
871
|
value: option.label
|
|
872
872
|
}));
|
|
873
|
-
const picked = await choose(`${prompt.header}: ${prompt.question}${
|
|
873
|
+
const picked = await choose(`${prompt.header}: ${prompt.question}${count}`, choices, {
|
|
874
874
|
multiple: !!prompt.multiple,
|
|
875
875
|
own: true
|
|
876
876
|
});
|
|
@@ -1025,26 +1025,26 @@ function addAsksInbox(ctx, follows) {
|
|
|
1025
1025
|
const {
|
|
1026
1026
|
form
|
|
1027
1027
|
} = ask;
|
|
1028
|
-
const
|
|
1028
|
+
const answer = {};
|
|
1029
1029
|
for (const field of form.fields) {
|
|
1030
|
-
if (!active(field,
|
|
1030
|
+
if (!active(field, answer))
|
|
1031
1031
|
continue;
|
|
1032
1032
|
if ("hidden" in field && field.hidden) {
|
|
1033
1033
|
if ("default" in field && field.default !== undefined)
|
|
1034
|
-
|
|
1034
|
+
answer[field.key] = field.default;
|
|
1035
1035
|
continue;
|
|
1036
1036
|
}
|
|
1037
1037
|
const value = await answerField(form, field);
|
|
1038
1038
|
if (value === undefined)
|
|
1039
1039
|
return false;
|
|
1040
1040
|
if (value !== SKIP)
|
|
1041
|
-
|
|
1041
|
+
answer[field.key] = value;
|
|
1042
1042
|
}
|
|
1043
1043
|
try {
|
|
1044
1044
|
await ctx.client.session.form.reply({
|
|
1045
1045
|
sessionID: form.sessionID,
|
|
1046
1046
|
formID: form.id,
|
|
1047
|
-
answer
|
|
1047
|
+
answer
|
|
1048
1048
|
});
|
|
1049
1049
|
} catch (error) {
|
|
1050
1050
|
const tag = error?._tag;
|
|
@@ -1116,8 +1116,8 @@ function addAsksInbox(ctx, follows) {
|
|
|
1116
1116
|
try {
|
|
1117
1117
|
return await Promise.race([choosing.then((chosen) => ({
|
|
1118
1118
|
chosen
|
|
1119
|
-
})), newer.then((
|
|
1120
|
-
read
|
|
1119
|
+
})), newer.then((read) => ({
|
|
1120
|
+
read
|
|
1121
1121
|
}))]);
|
|
1122
1122
|
} finally {
|
|
1123
1123
|
listing = undefined;
|
|
@@ -1502,7 +1502,7 @@ var treeRpc = Rpc3.define({
|
|
|
1502
1502
|
});
|
|
1503
1503
|
|
|
1504
1504
|
// src/tree/tui.tsx
|
|
1505
|
-
var CHANGES = new Set(["session.created", "session.deleted", "session.status", "session.idle", "session.execution.started", "session.execution.succeeded", "session.execution.failed", "session.execution.interrupted", "session.inbox.delivered", "session.synthetic", "permission.asked", "permission.replied", "form.created", "form.replied", "form.cancelled"]);
|
|
1505
|
+
var CHANGES = new Set(["session.created", "session.deleted", "session.status", "session.idle", "session.execution.started", "session.execution.succeeded", "session.execution.failed", "session.execution.interrupted", "session.inbox.delivered", "session.synthetic", "session.archived", "session.unarchived", "permission.asked", "permission.replied", "form.created", "form.replied", "form.cancelled"]);
|
|
1506
1506
|
var PANEL_CHANGES = new Set([...CHANGES, "session.tool.called", "session.tool.success", "session.tool.failed", "session.usage.updated", "session.renamed"]);
|
|
1507
1507
|
var SETTLE_MS2 = 250;
|
|
1508
1508
|
var PANEL_SETTLE_MS = 1000;
|
|
@@ -1534,14 +1534,14 @@ function createMotion(enabled) {
|
|
|
1534
1534
|
const now = untrack(moving);
|
|
1535
1535
|
for (const one of now)
|
|
1536
1536
|
one.step(FRAME_MS * every);
|
|
1537
|
-
setFrame((
|
|
1537
|
+
setFrame((count) => count + every);
|
|
1538
1538
|
const left = now.filter((one) => !one.done());
|
|
1539
1539
|
if (left.length !== now.length)
|
|
1540
1540
|
setMoving(left);
|
|
1541
1541
|
}), FRAME_MS * every);
|
|
1542
1542
|
onCleanup(() => clearInterval(timer));
|
|
1543
1543
|
});
|
|
1544
|
-
const tween = (from, to,
|
|
1544
|
+
const tween = (from, to, duration, ease) => {
|
|
1545
1545
|
if (!enabled || from === to)
|
|
1546
1546
|
return {
|
|
1547
1547
|
value: () => to,
|
|
@@ -1551,11 +1551,11 @@ function createMotion(enabled) {
|
|
|
1551
1551
|
value: from
|
|
1552
1552
|
};
|
|
1553
1553
|
const timeline = new Timeline({
|
|
1554
|
-
duration
|
|
1554
|
+
duration,
|
|
1555
1555
|
autoplay: false
|
|
1556
1556
|
});
|
|
1557
1557
|
timeline.add(target, {
|
|
1558
|
-
duration
|
|
1558
|
+
duration,
|
|
1559
1559
|
ease,
|
|
1560
1560
|
value: to
|
|
1561
1561
|
});
|
|
@@ -1568,7 +1568,7 @@ function createMotion(enabled) {
|
|
|
1568
1568
|
},
|
|
1569
1569
|
done: () => {
|
|
1570
1570
|
frame();
|
|
1571
|
-
return elapsed >=
|
|
1571
|
+
return elapsed >= duration;
|
|
1572
1572
|
},
|
|
1573
1573
|
step: (ms) => {
|
|
1574
1574
|
elapsed += ms;
|
|
@@ -1620,14 +1620,14 @@ function createBarFill(motion, counts) {
|
|
|
1620
1620
|
const [easing, setEasing] = createSignal();
|
|
1621
1621
|
let last;
|
|
1622
1622
|
createEffect(() => {
|
|
1623
|
-
const
|
|
1623
|
+
const cells = target();
|
|
1624
1624
|
const shown = counts().started > 0;
|
|
1625
|
-
if (last &&
|
|
1625
|
+
if (last && cells !== last.cells) {
|
|
1626
1626
|
const from = untrack(() => easing()?.value()) ?? last.cells;
|
|
1627
|
-
setEasing(last.shown ? motion.tween(from,
|
|
1627
|
+
setEasing(last.shown ? motion.tween(from, cells, BAR_MS, "outQuad") : undefined);
|
|
1628
1628
|
}
|
|
1629
1629
|
last = {
|
|
1630
|
-
cells
|
|
1630
|
+
cells,
|
|
1631
1631
|
shown
|
|
1632
1632
|
};
|
|
1633
1633
|
});
|
|
@@ -1667,8 +1667,8 @@ function mascotState(rows, {
|
|
|
1667
1667
|
return rows.length && rows.every((row) => row.state === "gone") ? "gone" : "idle";
|
|
1668
1668
|
}
|
|
1669
1669
|
function countsLine(rows) {
|
|
1670
|
-
const
|
|
1671
|
-
return [
|
|
1670
|
+
const count = (state) => rows.filter((row) => row.state === state).length;
|
|
1671
|
+
return [count("waiting") ? `${count("waiting")} waiting on you` : "", count("stalled") ? `${count("stalled")} stalled` : "", count("running") ? `${count("running")} running` : "", count("idle") ? `${count("idle")} idle` : ""].filter(Boolean).join(" \xB7 ");
|
|
1672
1672
|
}
|
|
1673
1673
|
var GLYPH_ROWS = 12;
|
|
1674
1674
|
var GLYPH_COLUMNS = 54;
|
|
@@ -1694,12 +1694,12 @@ function summaryLine(summary, maxWidth = Infinity) {
|
|
|
1694
1694
|
}
|
|
1695
1695
|
function duration2(ms) {
|
|
1696
1696
|
const seconds = Math.max(0, Math.floor(ms / 1000));
|
|
1697
|
-
const
|
|
1697
|
+
const pad = (value) => String(value).padStart(2, "0");
|
|
1698
1698
|
if (seconds < 60)
|
|
1699
1699
|
return `${seconds}s`;
|
|
1700
1700
|
if (seconds < 3600)
|
|
1701
|
-
return `${Math.floor(seconds / 60)}m ${
|
|
1702
|
-
return `${Math.floor(seconds / 3600)}h ${
|
|
1701
|
+
return `${Math.floor(seconds / 60)}m ${pad(seconds % 60)}s`;
|
|
1702
|
+
return `${Math.floor(seconds / 3600)}h ${pad(Math.floor(seconds / 60) % 60)}m`;
|
|
1703
1703
|
}
|
|
1704
1704
|
function parts(rows, parentID) {
|
|
1705
1705
|
const children = rows.filter((row) => row.parentID === parentID);
|
|
@@ -1715,8 +1715,8 @@ function filledCells({
|
|
|
1715
1715
|
return started ? Math.round(reported / started * width) : 0;
|
|
1716
1716
|
}
|
|
1717
1717
|
function bar(counts, width = 10, filled = filledCells(counts, width)) {
|
|
1718
|
-
const
|
|
1719
|
-
return `[${"\u2588".repeat(
|
|
1718
|
+
const cells = Math.max(0, Math.min(width, Math.round(filled)));
|
|
1719
|
+
return `[${"\u2588".repeat(cells)}${"\u2591".repeat(width - cells)}] ${counts.reported}/${counts.started} reported`;
|
|
1720
1720
|
}
|
|
1721
1721
|
function waitLine(wait) {
|
|
1722
1722
|
if (wait.type === "permission")
|
|
@@ -1727,7 +1727,7 @@ function statusLine(row) {
|
|
|
1727
1727
|
return statusParts(row).map((part) => part.text).join(" \xB7 ");
|
|
1728
1728
|
}
|
|
1729
1729
|
function statusParts(row) {
|
|
1730
|
-
const
|
|
1730
|
+
const parts = [{
|
|
1731
1731
|
text: stateWord(row),
|
|
1732
1732
|
kind: "state"
|
|
1733
1733
|
}, {
|
|
@@ -1740,7 +1740,7 @@ function statusParts(row) {
|
|
|
1740
1740
|
text: row.isolated ? "isolated" : "",
|
|
1741
1741
|
kind: "plain"
|
|
1742
1742
|
}];
|
|
1743
|
-
return
|
|
1743
|
+
return parts.filter((part) => part.text);
|
|
1744
1744
|
}
|
|
1745
1745
|
var SPINNER = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
1746
1746
|
function rowMark(row, theme, frame) {
|
|
@@ -1796,16 +1796,16 @@ function stateWord(row) {
|
|
|
1796
1796
|
return row.outcome;
|
|
1797
1797
|
return row.state;
|
|
1798
1798
|
}
|
|
1799
|
-
function reportWords(
|
|
1800
|
-
if (!
|
|
1799
|
+
function reportWords(report, stopped) {
|
|
1800
|
+
if (!report)
|
|
1801
1801
|
return "";
|
|
1802
|
-
if (
|
|
1802
|
+
if (report.state === "owed")
|
|
1803
1803
|
return "owes a report";
|
|
1804
|
-
if (
|
|
1804
|
+
if (report.state === "ended")
|
|
1805
1805
|
return stopped ? "" : "ended without a report";
|
|
1806
|
-
return ["reported",
|
|
1806
|
+
return ["reported", report.status].filter(Boolean).join(" ");
|
|
1807
1807
|
}
|
|
1808
|
-
var counted = (
|
|
1808
|
+
var counted = (count, noun) => `${count} ${noun}${count === 1 ? "" : "s"}`;
|
|
1809
1809
|
var CONTEXT_WARN = 0.8;
|
|
1810
1810
|
function activityParts(row, now) {
|
|
1811
1811
|
return [`ran ${duration2((row.idle ?? now) - row.created)}`, row.tool ? `last ${row.tool.name} ${duration2(now - row.tool.at)} ago` : "no tool call yet", row.context !== undefined ? `ctx ${Math.round(row.context * 100)}%` : "", row.cost !== undefined ? `$${row.cost.toFixed(2)}` : ""].filter(Boolean);
|
|
@@ -1835,7 +1835,7 @@ function courierOf(ctx) {
|
|
|
1835
1835
|
var REREAD_MS = 15000;
|
|
1836
1836
|
function changes(ctx, types, settle) {
|
|
1837
1837
|
const [changed, setChanged] = createSignal(0);
|
|
1838
|
-
const reread = setInterval(() => setChanged((
|
|
1838
|
+
const reread = setInterval(() => setChanged((count) => count + 1), REREAD_MS);
|
|
1839
1839
|
let settling;
|
|
1840
1840
|
const unlisten = ctx.data.listen(({
|
|
1841
1841
|
details
|
|
@@ -1844,7 +1844,7 @@ function changes(ctx, types, settle) {
|
|
|
1844
1844
|
return;
|
|
1845
1845
|
settling = setTimeout(() => {
|
|
1846
1846
|
settling = undefined;
|
|
1847
|
-
setChanged((
|
|
1847
|
+
setChanged((count) => count + 1);
|
|
1848
1848
|
}, settle);
|
|
1849
1849
|
});
|
|
1850
1850
|
return [changed, () => {
|
|
@@ -2487,9 +2487,9 @@ function TreePanel(props) {
|
|
|
2487
2487
|
get each() {
|
|
2488
2488
|
return statusParts(row);
|
|
2489
2489
|
},
|
|
2490
|
-
children: (part,
|
|
2490
|
+
children: (part, at) => [_$createComponent(Show, {
|
|
2491
2491
|
get when() {
|
|
2492
|
-
return
|
|
2492
|
+
return at();
|
|
2493
2493
|
},
|
|
2494
2494
|
get children() {
|
|
2495
2495
|
var _el$32 = _$createElement("text");
|
|
@@ -2527,7 +2527,7 @@ function TreePanel(props) {
|
|
|
2527
2527
|
get each() {
|
|
2528
2528
|
return line.split(" \xB7 ");
|
|
2529
2529
|
},
|
|
2530
|
-
children: (part,
|
|
2530
|
+
children: (part, at) => [_$memo(() => at() ? " \xB7 " : ""), _$memo(() => _$memo(() => part === `ctx ${Math.round(row.context * 100)}%`)() ? (() => {
|
|
2531
2531
|
var _el$37 = _$createElement("span");
|
|
2532
2532
|
_$insert(_el$37, part);
|
|
2533
2533
|
_$effect((_$p) => _$setProp(_el$37, "style", {
|
|
@@ -2664,7 +2664,7 @@ function addTreePanel(ctx, verbs = {}) {
|
|
|
2664
2664
|
return;
|
|
2665
2665
|
});
|
|
2666
2666
|
const follow = (from, sessionID) => {
|
|
2667
|
-
const
|
|
2667
|
+
const token = ++attempt;
|
|
2668
2668
|
const under = (tree) => tree?.rows.some((row) => row.sessionID === sessionID) === true;
|
|
2669
2669
|
Object.assign(from, {
|
|
2670
2670
|
at: undefined,
|
|
@@ -2675,7 +2675,7 @@ function addTreePanel(ctx, verbs = {}) {
|
|
|
2675
2675
|
(async () => {
|
|
2676
2676
|
const inside = await treeOf(from.root);
|
|
2677
2677
|
const own = under(inside) ? undefined : await treeOf(sessionID);
|
|
2678
|
-
if (
|
|
2678
|
+
if (token !== attempt || following !== from)
|
|
2679
2679
|
return;
|
|
2680
2680
|
if (under(inside))
|
|
2681
2681
|
show(from, sessionID, from.root, inside);
|
|
@@ -2769,10 +2769,10 @@ function addTreePanel(ctx, verbs = {}) {
|
|
|
2769
2769
|
});
|
|
2770
2770
|
const sessionID = target || await ctx.ui.dialog.select({
|
|
2771
2771
|
title: "Stop which session?",
|
|
2772
|
-
options: rows.map((
|
|
2773
|
-
title:
|
|
2774
|
-
value:
|
|
2775
|
-
description: `${
|
|
2772
|
+
options: rows.map((row) => ({
|
|
2773
|
+
title: row.title,
|
|
2774
|
+
value: row.sessionID,
|
|
2775
|
+
description: `${row.sessionID} \xB7 ${statusLine(row)}`
|
|
2776
2776
|
}))
|
|
2777
2777
|
});
|
|
2778
2778
|
if (!sessionID)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-courier",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.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,15 +56,15 @@
|
|
|
56
56
|
"test:e2e": "e2e/run.sh"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@opencode/plugin": "2.1.
|
|
59
|
+
"@opencode/plugin": "2.1.2",
|
|
60
60
|
"effect": "4.0.1"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
-
"@opencode/plugin": "2.1.
|
|
64
|
-
"@opencode/theme": "2.1.
|
|
63
|
+
"@opencode/plugin": "2.1.2",
|
|
64
|
+
"@opencode/theme": "2.1.2",
|
|
65
65
|
"@opentui/core": "0.6.6",
|
|
66
66
|
"@opentui/solid": "0.6.6",
|
|
67
|
-
"@types/bun": "1.
|
|
67
|
+
"@types/bun": "1.4.2",
|
|
68
68
|
"@types/node": "26.6.4",
|
|
69
69
|
"effect": "4.0.1",
|
|
70
70
|
"solid-js": "1.9.15",
|