opencode-courier 0.6.0 → 0.7.1

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/dist/tui.js CHANGED
@@ -808,6 +808,7 @@ var Summary = Schema2.Struct({
808
808
  running: Count2,
809
809
  waiting: Count2,
810
810
  idle: Count2,
811
+ stalled: Schema2.optionalKey(Count2),
811
812
  groups: Schema2.Array(Group)
812
813
  });
813
814
  var Wait = Schema2.Union([
@@ -820,7 +821,8 @@ var Row = Schema2.Struct({
820
821
  parentID: Schema2.String,
821
822
  title: Schema2.String,
822
823
  depth: Count2,
823
- state: Schema2.Literals(["running", "waiting", "idle", "gone"]),
824
+ state: Schema2.Literals(["running", "waiting", "idle", "stalled", "gone"]),
825
+ stalled: Schema2.optionalKey(Schema2.Number),
824
826
  outcome: Schema2.optionalKey(Schema2.Literals(["succeeded", "failed", "interrupted"])),
825
827
  stopped: Schema2.optionalKey(Schema2.Boolean),
826
828
  report: Schema2.optionalKey(Schema2.Struct({ state: Schema2.Literals(["owed", "reported", "ended"]), status: Schema2.optionalKey(Schema2.String), progressed: Schema2.Boolean })),
@@ -834,7 +836,8 @@ var Row = Schema2.Struct({
834
836
  });
835
837
  var Tree = Schema2.Struct({
836
838
  rows: Schema2.Array(Row),
837
- truncated: Schema2.optionalKey(Count2)
839
+ truncated: Schema2.optionalKey(Count2),
840
+ stalled: Schema2.optionalKey(Schema2.Number)
838
841
  });
839
842
  var Stopped = Schema2.Struct({
840
843
  stopped: Schema2.Array(Schema2.Struct({ sessionID: Schema2.String, title: Schema2.String, outcome: Schema2.String })),
@@ -878,7 +881,7 @@ var PANEL = "courier-tree";
878
881
  var TICK_MS = 1000;
879
882
  function summaryLine(summary, maxWidth = Infinity) {
880
883
  const groups = summary.groups.map((group) => `group ${group.name} ${group.reported}/${group.members}`);
881
- const parts = [summary.waiting ? `${summary.waiting} waiting on you` : "", summary.running ? `${summary.running} running` : "", ...groups, summary.idle ? `${summary.idle} idle` : ""].filter(Boolean);
884
+ const parts = [summary.waiting ? `${summary.waiting} waiting on you` : "", summary.stalled ? `${summary.stalled} stalled` : "", summary.running ? `${summary.running} running` : "", ...groups, summary.idle ? `${summary.idle} idle` : ""].filter(Boolean);
882
885
  if (!parts.length)
883
886
  return "";
884
887
  const line = (kept) => {
@@ -924,6 +927,8 @@ function statusLine(row) {
924
927
  function stateWord(row) {
925
928
  if (row.state === "waiting")
926
929
  return "waiting on you";
930
+ if (row.state === "stalled")
931
+ return "stalled";
927
932
  if (row.state === "idle" && row.stopped)
928
933
  return "stopped";
929
934
  if (row.state === "idle" && (row.outcome === "failed" || row.outcome === "interrupted"))
@@ -943,10 +948,15 @@ var counted = (count, noun) => `${count} ${noun}${count === 1 ? "" : "s"}`;
943
948
  function activityLine(row, now) {
944
949
  return [`ran ${duration((row.idle ?? now) - row.created)}`, row.tool ? `last ${row.tool.name} ${duration(now - row.tool.at)} ago` : "no tool call yet", row.cost !== undefined ? `$${row.cost.toFixed(2)}` : ""].filter(Boolean).join(" \xB7 ");
945
950
  }
951
+ function stalledLine(since, now) {
952
+ return `a message waits in its inbox since ${duration(now - since)}, woken again in vain`;
953
+ }
946
954
  function detailLines(row, rows, now) {
947
955
  const started = parts(rows, row.sessionID);
948
956
  if (row.waits.length)
949
957
  return [...started.started ? [bar(started)] : [], ...row.waits.map(waitLine)];
958
+ if (row.stalled !== undefined)
959
+ return [...started.started ? [bar(started)] : [], stalledLine(row.stalled, now)];
950
960
  if (started.started)
951
961
  return [bar(started)];
952
962
  return row.state === "gone" ? [] : [activityLine(row, now)];
@@ -959,8 +969,10 @@ function courierOf(ctx) {
959
969
  location
960
970
  };
961
971
  }
972
+ var REREAD_MS = 15000;
962
973
  function changes(ctx, types, settle) {
963
974
  const [changed, setChanged] = createSignal(0);
975
+ const reread = setInterval(() => setChanged((count) => count + 1), REREAD_MS);
964
976
  let settling;
965
977
  const unlisten = ctx.data.listen(({
966
978
  details
@@ -974,6 +986,7 @@ function changes(ctx, types, settle) {
974
986
  });
975
987
  return [changed, () => {
976
988
  clearTimeout(settling);
989
+ clearInterval(reread);
977
990
  unlisten();
978
991
  }];
979
992
  }
@@ -1138,7 +1151,7 @@ async function confirmForget(ctx, courier, location, by, target, done) {
1138
1151
  return true;
1139
1152
  }
1140
1153
  var FOCUS_PROMPT = "pane.focus.left";
1141
- var SPLIT_WIDTH = 80;
1154
+ var SPLIT_WIDTH = 108;
1142
1155
  var oneLine = (title) => title.replace(/[\r\n]+/g, " ");
1143
1156
  function TreePanel(props) {
1144
1157
  const {
@@ -1184,7 +1197,7 @@ function TreePanel(props) {
1184
1197
  presentation,
1185
1198
  focused
1186
1199
  } = input;
1187
- view.note(ctx.renderer.width > SPLIT_WIDTH ? {
1200
+ view.note(ctx.renderer.width >= SPLIT_WIDTH ? {
1188
1201
  presentation,
1189
1202
  focused
1190
1203
  } : {
@@ -1323,15 +1336,17 @@ function TreePanel(props) {
1323
1336
  }));
1324
1337
  const root = () => parts(rows(), view.root);
1325
1338
  const rowColor = (row) => {
1339
+ if (row.state === "stalled")
1340
+ return theme.text.feedback.error.base;
1326
1341
  if (row.state === "waiting")
1327
1342
  return theme.text.feedback.warning.base;
1328
1343
  return row.state === "gone" ? theme.text.muted : theme.text.base;
1329
1344
  };
1330
1345
  return (() => {
1331
- var _el$4 = _$createElement("box"), _el$5 = _$createElement("box"), _el$6 = _$createElement("text"), _el$13 = _$createElement("scrollbox"), _el$14 = _$createElement("text");
1346
+ var _el$4 = _$createElement("box"), _el$5 = _$createElement("box"), _el$6 = _$createElement("text"), _el$15 = _$createElement("scrollbox"), _el$16 = _$createElement("text");
1332
1347
  _$insertNode(_el$4, _el$5);
1333
- _$insertNode(_el$4, _el$13);
1334
- _$insertNode(_el$4, _el$14);
1348
+ _$insertNode(_el$4, _el$15);
1349
+ _$insertNode(_el$4, _el$16);
1335
1350
  _$setProp(_el$4, "flexDirection", "column");
1336
1351
  _$setProp(_el$4, "flexGrow", 1);
1337
1352
  _$setProp(_el$4, "paddingLeft", 1);
@@ -1378,21 +1393,33 @@ function TreePanel(props) {
1378
1393
  _$effect((_$p) => _$setProp(_el$1, "fg", theme.text.feedback.error.base, _$p));
1379
1394
  return _el$1;
1380
1395
  }
1381
- }), _el$13);
1396
+ }), _el$15);
1382
1397
  _$insert(_el$4, _$createComponent(Show, {
1383
1398
  get when() {
1384
- return _$memo(() => !!latest()?.tree)() && !rows().length;
1399
+ return latest()?.tree?.stalled;
1385
1400
  },
1386
1401
  get children() {
1387
- var _el$11 = _$createElement("text");
1388
- _$insertNode(_el$11, _$createTextNode(`No session started with courier_spawn under this one.`));
1389
- _$effect((_$p) => _$setProp(_el$11, "fg", theme.text.muted, _$p));
1402
+ var _el$11 = _$createElement("text"), _el$12 = _$createTextNode(`This session is stalled: `);
1403
+ _$insertNode(_el$11, _el$12);
1404
+ _$insert(_el$11, () => stalledLine(latest().tree.stalled, now()), null);
1405
+ _$effect((_$p) => _$setProp(_el$11, "fg", theme.text.feedback.error.base, _$p));
1390
1406
  return _el$11;
1391
1407
  }
1392
- }), _el$13);
1393
- _$use((value) => scroll = value, _el$13);
1394
- _$setProp(_el$13, "flexGrow", 1);
1395
- _$insert(_el$13, _$createComponent(For, {
1408
+ }), _el$15);
1409
+ _$insert(_el$4, _$createComponent(Show, {
1410
+ get when() {
1411
+ return _$memo(() => !!latest()?.tree)() && !rows().length;
1412
+ },
1413
+ get children() {
1414
+ var _el$13 = _$createElement("text");
1415
+ _$insertNode(_el$13, _$createTextNode(`No session started with courier_spawn under this one.`));
1416
+ _$effect((_$p) => _$setProp(_el$13, "fg", theme.text.muted, _$p));
1417
+ return _el$13;
1418
+ }
1419
+ }), _el$15);
1420
+ _$use((value) => scroll = value, _el$15);
1421
+ _$setProp(_el$15, "flexGrow", 1);
1422
+ _$insert(_el$15, _$createComponent(For, {
1396
1423
  get each() {
1397
1424
  return rows();
1398
1425
  },
@@ -1400,45 +1427,45 @@ function TreePanel(props) {
1400
1427
  const chosen = () => index() === selected();
1401
1428
  const indent = " ".repeat(row.depth - 1);
1402
1429
  return (() => {
1403
- var _el$16 = _$createElement("box"), _el$17 = _$createElement("box"), _el$18 = _$createElement("text"), _el$19 = _$createElement("text"), _el$20 = _$createTextNode(` `);
1404
- _$insertNode(_el$16, _el$17);
1405
- _$setProp(_el$16, "flexDirection", "column");
1406
- _$setProp(_el$16, "flexShrink", 0);
1407
- _$insertNode(_el$17, _el$18);
1408
- _$insertNode(_el$17, _el$19);
1409
- _$setProp(_el$17, "flexDirection", "row");
1410
- _$setProp(_el$17, "flexShrink", 0);
1411
- _$setProp(_el$18, "wrapMode", "none");
1412
- _$setProp(_el$18, "flexShrink", 1);
1413
- _$setProp(_el$18, "minWidth", 0);
1414
- _$insert(_el$18, indent, null);
1415
- _$insert(_el$18, () => chosen() ? "\u25B8 " : " ", null);
1416
- _$insert(_el$18, () => oneLine(row.title), null);
1417
- _$insert(_el$18, () => row.sessionID === input.sessionID ? " (on screen)" : "", null);
1430
+ var _el$18 = _$createElement("box"), _el$19 = _$createElement("box"), _el$20 = _$createElement("text"), _el$21 = _$createElement("text"), _el$22 = _$createTextNode(` `);
1431
+ _$insertNode(_el$18, _el$19);
1432
+ _$setProp(_el$18, "flexDirection", "column");
1433
+ _$setProp(_el$18, "flexShrink", 0);
1418
1434
  _$insertNode(_el$19, _el$20);
1419
- _$setProp(_el$19, "wrapMode", "none");
1435
+ _$insertNode(_el$19, _el$21);
1436
+ _$setProp(_el$19, "flexDirection", "row");
1420
1437
  _$setProp(_el$19, "flexShrink", 0);
1421
- _$insert(_el$19, () => statusLine(row), null);
1422
- _$insert(_el$16, _$createComponent(For, {
1438
+ _$setProp(_el$20, "wrapMode", "none");
1439
+ _$setProp(_el$20, "flexShrink", 1);
1440
+ _$setProp(_el$20, "minWidth", 0);
1441
+ _$insert(_el$20, indent, null);
1442
+ _$insert(_el$20, () => chosen() ? "\u25B8 " : " ", null);
1443
+ _$insert(_el$20, () => oneLine(row.title), null);
1444
+ _$insert(_el$20, () => row.sessionID === input.sessionID ? " (on screen)" : "", null);
1445
+ _$insertNode(_el$21, _el$22);
1446
+ _$setProp(_el$21, "wrapMode", "none");
1447
+ _$setProp(_el$21, "flexShrink", 0);
1448
+ _$insert(_el$21, () => statusLine(row), null);
1449
+ _$insert(_el$18, _$createComponent(For, {
1423
1450
  get each() {
1424
1451
  return detailLines(row, rows(), now());
1425
1452
  },
1426
1453
  children: (line) => (() => {
1427
- var _el$21 = _$createElement("text"), _el$22 = _$createTextNode(` `);
1428
- _$insertNode(_el$21, _el$22);
1429
- _$setProp(_el$21, "wrapMode", "none");
1430
- _$insert(_el$21, indent, _el$22);
1431
- _$insert(_el$21, line, null);
1432
- _$effect((_$p) => _$setProp(_el$21, "fg", theme.text.muted, _$p));
1433
- return _el$21;
1454
+ var _el$23 = _$createElement("text"), _el$24 = _$createTextNode(` `);
1455
+ _$insertNode(_el$23, _el$24);
1456
+ _$setProp(_el$23, "wrapMode", "none");
1457
+ _$insert(_el$23, indent, _el$24);
1458
+ _$insert(_el$23, line, null);
1459
+ _$effect((_$p) => _$setProp(_el$23, "fg", theme.text.muted, _$p));
1460
+ return _el$23;
1434
1461
  })()
1435
1462
  }), null);
1436
1463
  _$effect((_p$) => {
1437
1464
  var _v$3 = `courier-row-${index()}`, _v$4 = chosen() && input.focused ? theme.background.raised.high : undefined, _v$5 = rowColor(row), _v$6 = theme.text.muted;
1438
- _v$3 !== _p$.e && (_p$.e = _$setProp(_el$16, "id", _v$3, _p$.e));
1439
- _v$4 !== _p$.t && (_p$.t = _$setProp(_el$16, "backgroundColor", _v$4, _p$.t));
1440
- _v$5 !== _p$.a && (_p$.a = _$setProp(_el$18, "fg", _v$5, _p$.a));
1441
- _v$6 !== _p$.o && (_p$.o = _$setProp(_el$19, "fg", _v$6, _p$.o));
1465
+ _v$3 !== _p$.e && (_p$.e = _$setProp(_el$18, "id", _v$3, _p$.e));
1466
+ _v$4 !== _p$.t && (_p$.t = _$setProp(_el$18, "backgroundColor", _v$4, _p$.t));
1467
+ _v$5 !== _p$.a && (_p$.a = _$setProp(_el$20, "fg", _v$5, _p$.a));
1468
+ _v$6 !== _p$.o && (_p$.o = _$setProp(_el$21, "fg", _v$6, _p$.o));
1442
1469
  return _p$;
1443
1470
  }, {
1444
1471
  e: undefined,
@@ -1446,17 +1473,17 @@ function TreePanel(props) {
1446
1473
  a: undefined,
1447
1474
  o: undefined
1448
1475
  });
1449
- return _el$16;
1476
+ return _el$18;
1450
1477
  })();
1451
1478
  }
1452
1479
  }));
1453
- _$insertNode(_el$14, _$createTextNode(`\u2191\u2193 select \xB7 enter open \xB7 s stop \xB7 x forget \xB7 r refresh \xB7 f fullscreen \xB7 q close`));
1454
- _$setProp(_el$14, "wrapMode", "none");
1455
- _$setProp(_el$14, "flexShrink", 0);
1480
+ _$insertNode(_el$16, _$createTextNode(`\u2191\u2193 select \xB7 enter open \xB7 s stop \xB7 x forget \xB7 r refresh \xB7 f fullscreen \xB7 q close`));
1481
+ _$setProp(_el$16, "wrapMode", "none");
1482
+ _$setProp(_el$16, "flexShrink", 0);
1456
1483
  _$effect((_p$) => {
1457
1484
  var _v$ = theme.text.base, _v$2 = theme.text.muted;
1458
1485
  _v$ !== _p$.e && (_p$.e = _$setProp(_el$6, "fg", _v$, _p$.e));
1459
- _v$2 !== _p$.t && (_p$.t = _$setProp(_el$14, "fg", _v$2, _p$.t));
1486
+ _v$2 !== _p$.t && (_p$.t = _$setProp(_el$16, "fg", _v$2, _p$.t));
1460
1487
  return _p$;
1461
1488
  }, {
1462
1489
  e: undefined,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-courier",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
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,12 +56,12 @@
56
56
  "test:e2e": "e2e/run.sh"
57
57
  },
58
58
  "peerDependencies": {
59
- "@opencode/plugin": "2.0.29",
59
+ "@opencode/plugin": "2.0.30",
60
60
  "effect": "4.0.1"
61
61
  },
62
62
  "devDependencies": {
63
- "@opencode/plugin": "2.0.29",
64
- "@opencode/theme": "2.0.29",
63
+ "@opencode/plugin": "2.0.30",
64
+ "@opencode/theme": "2.0.30",
65
65
  "@opentui/core": "0.5.17",
66
66
  "@opentui/solid": "0.5.17",
67
67
  "@types/bun": "1.3.14",