opencode-courier 0.13.8 → 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.
Files changed (163) hide show
  1. package/README.md +7 -9
  2. package/dist/index.d.ts +0 -8
  3. package/dist/index.js +6 -53
  4. package/dist/kernel/protocol.d.ts +0 -14
  5. package/dist/kernel/protocol.js +1 -15
  6. package/dist/kernel/tool.d.ts +0 -2
  7. package/dist/kernel/tool.js +0 -1
  8. package/dist/memory/domain.d.ts +6 -85
  9. package/dist/memory/domain.js +7 -63
  10. package/dist/memory/events.d.ts +0 -11
  11. package/dist/memory/events.js +1 -12
  12. package/dist/memory/forget.d.ts +0 -5
  13. package/dist/memory/forget.js +0 -4
  14. package/dist/memory/index.js +0 -2
  15. package/dist/memory/lessons.d.ts +0 -8
  16. package/dist/memory/lessons.js +0 -9
  17. package/dist/memory/note.d.ts +0 -9
  18. package/dist/memory/note.js +0 -5
  19. package/dist/memory/pin.d.ts +0 -5
  20. package/dist/memory/pin.js +0 -4
  21. package/dist/memory/ports.d.ts +2 -22
  22. package/dist/memory/recall.d.ts +0 -5
  23. package/dist/memory/recall.js +0 -12
  24. package/dist/memory/record.d.ts +0 -4
  25. package/dist/memory/record.js +8 -31
  26. package/dist/memory/rpc-handlers.d.ts +3 -6
  27. package/dist/memory/rpc-handlers.js +0 -6
  28. package/dist/memory/rpc.d.ts +6 -19
  29. package/dist/memory/rpc.js +1 -16
  30. package/dist/memory/store.d.ts +0 -5
  31. package/dist/memory/store.js +1 -16
  32. package/dist/memory/sweep.d.ts +0 -4
  33. package/dist/memory/sweep.js +0 -4
  34. package/dist/memory/text.d.ts +0 -25
  35. package/dist/memory/text.js +6 -36
  36. package/dist/memory/tools.d.ts +0 -2
  37. package/dist/memory/tools.js +0 -2
  38. package/dist/memory/tui.d.ts +1 -35
  39. package/dist/person/events.d.ts +0 -16
  40. package/dist/person/events.js +3 -30
  41. package/dist/person/form.d.ts +0 -9
  42. package/dist/person/form.js +0 -10
  43. package/dist/person/index.d.ts +0 -2
  44. package/dist/person/permission.d.ts +0 -34
  45. package/dist/person/permission.js +2 -28
  46. package/dist/person/ports.d.ts +0 -16
  47. package/dist/person/ports.js +0 -1
  48. package/dist/person/question/answer.d.ts +0 -28
  49. package/dist/person/question/answer.js +0 -49
  50. package/dist/person/question/index.js +0 -2
  51. package/dist/person/question/lifecycle.d.ts +0 -26
  52. package/dist/person/question/lifecycle.js +1 -32
  53. package/dist/person/question/pure.d.ts +0 -11
  54. package/dist/person/question/pure.js +0 -11
  55. package/dist/person/question/relay.d.ts +0 -1
  56. package/dist/person/question/relay.js +5 -67
  57. package/dist/person/question/runtime.d.ts +0 -14
  58. package/dist/person/question/runtime.js +1 -26
  59. package/dist/person/question/shared.d.ts +0 -17
  60. package/dist/person/question/shared.js +0 -20
  61. package/dist/person/question/types.d.ts +0 -44
  62. package/dist/person/rpc-handlers.d.ts +0 -7
  63. package/dist/person/rpc-handlers.js +0 -6
  64. package/dist/person/rpc.d.ts +0 -20
  65. package/dist/person/rpc.js +0 -16
  66. package/dist/person/text.d.ts +0 -45
  67. package/dist/person/text.js +2 -54
  68. package/dist/person/tools.d.ts +0 -3
  69. package/dist/person/tools.js +1 -3
  70. package/dist/person/tui.d.ts +0 -21
  71. package/dist/platform/bounded.d.ts +0 -8
  72. package/dist/platform/bounded.js +0 -8
  73. package/dist/platform/events.d.ts +0 -18
  74. package/dist/platform/events.js +3 -22
  75. package/dist/platform/hub.d.ts +0 -113
  76. package/dist/platform/hub.js +1 -76
  77. package/dist/platform/json.d.ts +0 -3
  78. package/dist/platform/json.js +1 -3
  79. package/dist/platform/storage.d.ts +0 -7
  80. package/dist/platform/storage.js +0 -6
  81. package/dist/platform/version.d.ts +0 -9
  82. package/dist/platform/version.js +0 -8
  83. package/dist/rpc.js +0 -1
  84. package/dist/scheduling/index.d.ts +0 -1
  85. package/dist/scheduling/index.js +0 -1
  86. package/dist/scheduling/later.d.ts +0 -11
  87. package/dist/scheduling/later.js +0 -14
  88. package/dist/scheduling/text.d.ts +0 -1
  89. package/dist/scheduling/text.js +0 -1
  90. package/dist/scheduling/tools.d.ts +0 -1
  91. package/dist/scheduling/tools.js +1 -5
  92. package/dist/skill.d.ts +1 -9
  93. package/dist/skill.js +4 -12
  94. package/dist/tree/cleanup.d.ts +0 -20
  95. package/dist/tree/cleanup.js +0 -26
  96. package/dist/tree/context.d.ts +0 -5
  97. package/dist/tree/context.js +0 -8
  98. package/dist/tree/domain.d.ts +0 -64
  99. package/dist/tree/domain.js +7 -45
  100. package/dist/tree/events.d.ts +0 -36
  101. package/dist/tree/events.js +4 -49
  102. package/dist/tree/forget.d.ts +0 -15
  103. package/dist/tree/forget.js +0 -18
  104. package/dist/tree/group.d.ts +0 -22
  105. package/dist/tree/group.js +1 -37
  106. package/dist/tree/index.d.ts +2 -2
  107. package/dist/tree/index.js +1 -3
  108. package/dist/tree/limits.d.ts +0 -4
  109. package/dist/tree/limits.js +1 -12
  110. package/dist/tree/mascot.d.ts +0 -25
  111. package/dist/tree/mascot.js +1 -32
  112. package/dist/tree/model.d.ts +0 -5
  113. package/dist/tree/model.js +2 -15
  114. package/dist/tree/nudge.d.ts +0 -11
  115. package/dist/tree/nudge.js +3 -16
  116. package/dist/tree/panel.d.ts +0 -8
  117. package/dist/tree/panel.js +3 -16
  118. package/dist/tree/ports.d.ts +2 -138
  119. package/dist/tree/report.d.ts +0 -10
  120. package/dist/tree/report.js +0 -11
  121. package/dist/tree/roster.d.ts +0 -21
  122. package/dist/tree/roster.js +0 -21
  123. package/dist/tree/rpc-handlers.d.ts +6 -1
  124. package/dist/tree/rpc-handlers.js +0 -5
  125. package/dist/tree/rpc.d.ts +9 -109
  126. package/dist/tree/rpc.js +2 -38
  127. package/dist/tree/running.d.ts +0 -6
  128. package/dist/tree/running.js +2 -10
  129. package/dist/tree/send.d.ts +0 -4
  130. package/dist/tree/send.js +4 -31
  131. package/dist/tree/spawn.d.ts +0 -7
  132. package/dist/tree/spawn.js +6 -47
  133. package/dist/tree/standing.d.ts +0 -8
  134. package/dist/tree/standing.js +1 -11
  135. package/dist/tree/status.d.ts +0 -8
  136. package/dist/tree/status.js +1 -9
  137. package/dist/tree/stop.d.ts +2 -9
  138. package/dist/tree/stop.js +58 -25
  139. package/dist/tree/store.d.ts +0 -8
  140. package/dist/tree/store.js +4 -38
  141. package/dist/tree/subtree.d.ts +8 -26
  142. package/dist/tree/subtree.js +37 -35
  143. package/dist/tree/summary.d.ts +0 -4
  144. package/dist/tree/summary.js +0 -8
  145. package/dist/tree/text.d.ts +1 -44
  146. package/dist/tree/text.js +5 -65
  147. package/dist/tree/tools.d.ts +0 -6
  148. package/dist/tree/tools.js +4 -8
  149. package/dist/tree/tui.d.ts +0 -81
  150. package/dist/tree/wake.d.ts +0 -30
  151. package/dist/tree/wake.js +5 -39
  152. package/dist/tui.js +22 -8
  153. package/package.json +8 -9
  154. package/dist/webhook/index.d.ts +0 -5
  155. package/dist/webhook/index.js +0 -3
  156. package/dist/webhook/receiver.d.ts +0 -80
  157. package/dist/webhook/receiver.js +0 -339
  158. package/dist/webhook/subscriptions.d.ts +0 -29
  159. package/dist/webhook/subscriptions.js +0 -52
  160. package/dist/webhook/text.d.ts +0 -23
  161. package/dist/webhook/text.js +0 -82
  162. package/dist/webhook/tools.d.ts +0 -19
  163. package/dist/webhook/tools.js +0 -46
package/dist/tree/wake.js CHANGED
@@ -1,31 +1,21 @@
1
1
  import { millis } from "../platform/json.js";
2
2
  import { busy, endsIdle } from "./domain.js";
3
3
  import { wakeStore } from "./store.js";
4
- /** How long a courier message may wait in an idle session's inbox before its wake counts as missed. */
5
4
  export const WAKE_MS = 30_000;
6
- /**
7
- * Watches a courier message enqueued for a session until it is delivered, noting whether the session runs.
8
- * Returns whether it is watched, which one sent with `resume: false` is not.
9
- */
10
5
  export async function watchWake(ports, event) {
11
6
  const { sessionID, inboxID, item } = event.data;
12
7
  const payload = item.payload;
13
8
  if (item.type !== "synthetic" || payload?.metadata?.source !== "courier" || typeof payload.text !== "string")
14
9
  return false;
15
- // Sent without a wake: it waits for the next turn, which nothing owes it.
10
+ // resume: false starts no turn: the item waits for the next (api-notes)
16
11
  if (payload.metadata.resume === false)
17
12
  return false;
18
13
  const at = event.created ?? ports.now();
19
- // A row `noteSent` wrote already is kept: it may have moved on since, and is no later than this one.
20
14
  if ((await wakeStore(ports.storage).of(sessionID)).some((wake) => wake.inboxID === inboxID))
21
15
  return true;
22
16
  await watch(ports, { sessionID, inboxID, at, text: payload.text, ...(typeof payload.description === "string" ? { description: payload.description } : {}) });
23
17
  return true;
24
18
  }
25
- /**
26
- * Watches a message `courier_send` has just had enqueued, without waiting for its enqueued event, so the limits see a reported child woken
27
- * for it at once; the event leaves this row be. Dropped again if the message is already stored, delivered before it was written.
28
- */
29
19
  export async function noteSent(ports, sent) {
30
20
  const store = wakeStore(ports.storage);
31
21
  if ((await store.of(sent.sessionID)).some((wake) => wake.inboxID === sent.inboxID))
@@ -36,24 +26,17 @@ export async function noteSent(ports, sent) {
36
26
  await store.remove(sent.sessionID, sent.inboxID);
37
27
  }
38
28
  async function watch(ports, wake) {
39
- // Read after the enqueue: a turn it started has stored messages since, and an unknown session is taken to run.
40
29
  const idle = await ports.session.context({ sessionID: wake.sessionID }).then(endsIdle, () => false);
41
30
  await wakeStore(ports.storage).put({ ...wake, running: !idle, ...(idle ? { idleAt: wake.at } : {}) });
42
31
  }
43
- /** Stops watching a message once it is delivered or cancelled. */
44
32
  export async function settleWake(ports, event) {
45
33
  await wakeStore(ports.storage).remove(event.data.sessionID, event.data.inboxID);
46
34
  }
47
- /** A turn started in a session: the messages waiting there are its to take. */
48
35
  export async function wakeStarted(ports, event) {
49
36
  const store = wakeStore(ports.storage);
50
37
  const waiting = await store.of(event.data.sessionID);
51
38
  await Promise.all(waiting.filter((wake) => !wake.running).map(({ idleAt: _, ...wake }) => store.put({ ...wake, running: true })));
52
39
  }
53
- /**
54
- * A session's turn ended: a message it took is no longer watched, as its delivery may have been missed by this
55
- * subscription; one still waiting is watched as waiting in an idle session from now.
56
- */
57
40
  export async function wakeEnded(ports, event) {
58
41
  const { sessionID } = event.data;
59
42
  const store = wakeStore(ports.storage);
@@ -62,22 +45,16 @@ export async function wakeEnded(ports, event) {
62
45
  return;
63
46
  const at = event.created ?? ports.now();
64
47
  const messages = await ports.session.context({ sessionID }).catch(() => []);
65
- // A plain decline reports a shutdown after the aborted step that ends its turn; a real one between steps ends none. One during a
66
- // step reads as ended too, until the turn the next boot resumes is seen to start or `wakeAgain` finds it running.
48
+ // a plain decline reports a shutdown after its aborted step (api-notes)
67
49
  if (event.data.reason === "shutdown" && !endsIdle(messages))
68
50
  return;
69
51
  const stored = new Set(messages.map((message) => message.id));
70
52
  await Promise.all(waiting.map((wake) => (stored.has(wake.inboxID) ? store.remove(sessionID, wake.inboxID) : store.put({ ...wake, running: false, idleAt: at }))));
71
53
  }
72
- /** Forgets the messages watched in a session's inbox: it was deleted, or stopped, which nothing is to wake again. */
73
54
  export async function forgetWakes(ports, sessionID) {
74
55
  const store = wakeStore(ports.storage);
75
56
  await Promise.all((await store.of(sessionID)).map((wake) => store.remove(sessionID, wake.inboxID)));
76
57
  }
77
- /**
78
- * Sends once more, under its inbox id, each courier message an idle session has left waiting for `WAKE_MS`, flags stalled one still
79
- * 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.
80
- */
81
58
  export async function wakeMissed(ports, claimed) {
82
59
  const store = wakeStore(ports.storage);
83
60
  const now = ports.now();
@@ -87,9 +64,7 @@ export async function wakeMissed(ports, claimed) {
87
64
  await Promise.all(due.map((wake) => wakeAgain(ports, store, wake, now).finally(() => claimed.delete(claimOf(wake)))));
88
65
  }
89
66
  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
67
  const waitingSince = (wake) => Math.max(wake.idleAt ?? wake.at, wake.rewoken ?? 0);
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. */
93
68
  export function missed(wake, now) {
94
69
  if (wake.running || wake.stalled !== undefined)
95
70
  return false;
@@ -97,11 +72,9 @@ export function missed(wake, now) {
97
72
  }
98
73
  async function wakeAgain(ports, store, wake, now) {
99
74
  try {
100
- // Re-read: the message may have been delivered, or the session woken, since the scan.
101
75
  const current = (await store.of(wake.sessionID)).find((one) => one.inboxID === wake.inboxID);
102
76
  if (!current || !missed(current, now))
103
77
  return;
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.
105
78
  if (await runsNow(ports, current)) {
106
79
  const { idleAt: _, ...running } = current;
107
80
  return await store.put({ ...running, running: true });
@@ -110,8 +83,9 @@ async function wakeAgain(ports, store, wake, now) {
110
83
  ports.log(`courier wake: ${wake.sessionID} has not taken message ${wake.inboxID} since it was woken again; flagged stalled`);
111
84
  return await store.put({ ...current, stalled: now });
112
85
  }
113
- // Noted before the send: the turn it starts may take the message, and drop the watch, before the send returns.
86
+ // the woken turn may take the message before synthetic returns
114
87
  await store.put({ ...current, rewoken: now });
88
+ // synthetic with a waiting item's id wakes again, adds no message (api-notes)
115
89
  await ports.session.synthetic({
116
90
  sessionID: wake.sessionID,
117
91
  id: wake.inboxID,
@@ -129,15 +103,12 @@ async function wakeAgain(ports, store, wake, now) {
129
103
  ports.log(`courier wake: could not wake ${wake.sessionID} again for ${wake.inboxID}: ${String(error)}`);
130
104
  }
131
105
  }
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
106
  async function runsNow(ports, wake) {
137
107
  const { sessionID } = wake;
138
108
  const info = await ports.session.get({ sessionID }).catch(() => undefined);
139
109
  if (!info)
140
110
  return false;
111
+ // time.busy, since 2.2.2, records a start whose event was missed (api-notes)
141
112
  if (info.time.busy !== undefined)
142
113
  return busy(info.time) && millis(info.time.busy) >= waitingSince(wake);
143
114
  if (!busy(info.time))
@@ -145,14 +116,9 @@ async function runsNow(ports, wake) {
145
116
  const messages = await ports.session.context({ sessionID }).catch(() => []);
146
117
  return messages.length > 0 && !endsIdle(messages);
147
118
  }
148
- /**
149
- * Whether a courier message sent with a wake waits undelivered in the session's inbox while it is idle, waiting or, unless
150
- * `stalled` is false, stalled; one a running turn is to take is not counted, as `runs` says that turn runs.
151
- */
152
119
  export async function waitsInInbox(ports, sessionID, { stalled = true } = {}) {
153
120
  return (await wakeStore(ports.storage).of(sessionID)).some((wake) => !wake.running && (stalled || wake.stalled === undefined));
154
121
  }
155
- /** The sessions among `sessionIDs` flagged stalled, each with when its oldest stalled message was enqueued. */
156
122
  export async function stalledAmong(ports, sessionIDs) {
157
123
  const wanted = new Set(sessionIDs);
158
124
  const stalled = new Map();
package/dist/tui.js CHANGED
@@ -12,6 +12,7 @@ var Part = Schema.Struct({
12
12
  title: Schema.String,
13
13
  depth: Count,
14
14
  isolated: Schema.Boolean,
15
+ subagent: Schema.optionalKey(Schema.Boolean),
15
16
  group: Schema.optionalKey(Schema.String),
16
17
  status: Schema.Literals(PART_STATUSES),
17
18
  duration: Schema.optionalKey(Schema.Number),
@@ -110,14 +111,14 @@ var count = (n, noun) => `${n} ${noun}${n === 1 ? "" : "s"}`;
110
111
  var times = (n) => n === 1 ? "once" : `${n} times`;
111
112
  var money = (cost) => `$${cost.toFixed(2)}`;
112
113
  var nameOf = (record) => clip(oneLine2(record.title) || record.sessionID, 60);
113
- function partsCounted(parts) {
114
- if (!parts.length)
115
- return "no parts";
114
+ function partsCounted(all) {
115
+ const parts = all.filter((part) => !part.subagent);
116
+ const subagents = all.length - parts.length;
116
117
  const statuses = PART_STATUSES.flatMap((status) => {
117
118
  const n = parts.filter((part) => part.status === status).length;
118
119
  return n ? [`${n} ${status}`] : [];
119
120
  }).join(", ");
120
- return `${count(parts.length, "part")}: ${statuses}`;
121
+ return [parts.length ? `${count(parts.length, "part")}: ${statuses}` : "no parts", ...subagents ? [count(subagents, "subagent")] : []].join(", ");
121
122
  }
122
123
  function costOf(record) {
123
124
  return record.parts.some((part) => part.cost !== undefined) ? record.parts.reduce((sum, part) => sum + (part.cost ?? 0), 0) : undefined;
@@ -146,7 +147,7 @@ function recordDetails(record) {
146
147
  return record.lesson ? [clip(`${lessonHeading(record.lesson)}: "${oneLine2(record.lesson.text)}"`, LESSON_LINE_MAX)] : [];
147
148
  }
148
149
  function partLine(part) {
149
- return [part.status, `depth ${part.depth}`, part.isolated ? "isolated" : "", part.group ? `group ${part.group}` : "", part.duration === undefined ? "" : duration(part.duration), part.cost === undefined ? "" : money(part.cost), part.context === undefined ? "" : `ctx ${Math.round(part.context * 100)}%`, part.refused ? `${count(part.refused, "spawn")} refused` : ""].filter(Boolean).join(" \xB7 ");
150
+ return [part.status, `depth ${part.depth}`, part.isolated ? "isolated" : "", part.subagent ? "subagent" : "", part.group ? `group ${part.group}` : "", part.duration === undefined ? "" : duration(part.duration), part.cost === undefined ? "" : money(part.cost), part.context === undefined ? "" : `ctx ${Math.round(part.context * 100)}%`, part.refused ? `${count(part.refused, "spawn")} refused` : ""].filter(Boolean).join(" \xB7 ");
150
151
  }
151
152
  function wrap(text, width) {
152
153
  const rows = [];
@@ -1470,6 +1471,7 @@ var Row = Schema3.Struct({
1470
1471
  group: Schema3.optionalKey(Schema3.Struct({ name: Schema3.String, standing: Schema3.String })),
1471
1472
  isolated: Schema3.Boolean,
1472
1473
  native: Schema3.optionalKey(Schema3.Boolean),
1474
+ subagent: Schema3.optionalKey(Schema3.Boolean),
1473
1475
  model: Schema3.optionalKey(Schema3.String),
1474
1476
  created: Schema3.Number,
1475
1477
  idle: Schema3.optionalKey(Schema3.Number),
@@ -1720,7 +1722,7 @@ function duration2(ms) {
1720
1722
  return `${Math.floor(seconds / 3600)}h ${pad(Math.floor(seconds / 60) % 60)}m`;
1721
1723
  }
1722
1724
  function parts(rows, parentID) {
1723
- const children = rows.filter((row) => row.parentID === parentID);
1725
+ const children = rows.filter((row) => row.parentID === parentID && !row.subagent);
1724
1726
  return {
1725
1727
  reported: children.filter((row) => row.report?.state === "reported").length,
1726
1728
  started: children.length
@@ -1760,6 +1762,9 @@ function statusParts(row, now = Date.now()) {
1760
1762
  }, {
1761
1763
  text: row.native ? "native" : "",
1762
1764
  kind: "plain"
1765
+ }, {
1766
+ text: row.subagent ? "subagent" : "",
1767
+ kind: "plain"
1763
1768
  }, {
1764
1769
  text: row.model ?? "",
1765
1770
  kind: "plain"
@@ -2211,6 +2216,14 @@ function TreePanel(props) {
2211
2216
  openRow(row);
2212
2217
  };
2213
2218
  const ownRow = (row, key) => {
2219
+ if (row.subagent) {
2220
+ ctx.ui.toast.show({
2221
+ title: "courier",
2222
+ message: `${key} acts on a session started with courier_spawn; "${oneLine3(row.title)}" is a subagent, stopped with the one above it.`,
2223
+ variant: "warning"
2224
+ });
2225
+ return true;
2226
+ }
2214
2227
  if (row.sessionID !== view.root)
2215
2228
  return false;
2216
2229
  ctx.ui.toast.show({
@@ -2842,13 +2855,14 @@ function addTreePanel(ctx, verbs = {}) {
2842
2855
  error
2843
2856
  }));
2844
2857
  const rows = read.rows;
2858
+ const spawned = rows.filter((row) => !row.subagent);
2845
2859
  if (!target && "error" in read)
2846
2860
  return ctx.ui.toast.show({
2847
2861
  title: "courier stop",
2848
2862
  message: reason(read.error),
2849
2863
  variant: "error"
2850
2864
  });
2851
- if (!target && !rows.length)
2865
+ if (!target && !spawned.length)
2852
2866
  return ctx.ui.toast.show({
2853
2867
  title: "courier stop",
2854
2868
  message: "No session started with courier_spawn under this one.",
@@ -2856,7 +2870,7 @@ function addTreePanel(ctx, verbs = {}) {
2856
2870
  });
2857
2871
  const sessionID = target || await ctx.ui.dialog.select({
2858
2872
  title: "Stop which session?",
2859
- options: rows.map((row) => ({
2873
+ options: spawned.map((row) => ({
2860
2874
  title: row.title,
2861
2875
  value: row.sessionID,
2862
2876
  description: `${row.sessionID} \xB7 ${statusLine(row)}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-courier",
3
- "version": "0.13.8",
3
+ "version": "0.14.0",
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>",
@@ -45,7 +45,6 @@
45
45
  "background-agents",
46
46
  "parallel",
47
47
  "worktree",
48
- "webhook",
49
48
  "scheduler",
50
49
  "ai-agents"
51
50
  ],
@@ -56,17 +55,17 @@
56
55
  "test:e2e": "e2e/run.sh"
57
56
  },
58
57
  "peerDependencies": {
59
- "@opencode/plugin": "2.2.5",
60
- "effect": "4.0.6"
58
+ "@opencode/plugin": "2.2.6",
59
+ "effect": "4.1.0"
61
60
  },
62
61
  "devDependencies": {
63
- "@opencode/plugin": "2.2.5",
64
- "@opencode/theme": "2.2.5",
65
- "@opentui/core": "0.8.0",
66
- "@opentui/solid": "0.8.0",
62
+ "@opencode/plugin": "2.2.6",
63
+ "@opencode/theme": "2.2.6",
64
+ "@opentui/core": "0.8.1",
65
+ "@opentui/solid": "0.8.1",
67
66
  "@types/bun": "1.4.2",
68
67
  "@types/node": "26.6.4",
69
- "effect": "4.0.6",
68
+ "effect": "4.1.0",
70
69
  "solid-js": "1.9.17",
71
70
  "typescript": "5.9.3"
72
71
  }
@@ -1,5 +0,0 @@
1
- export { joinReceiver, listen, readConfig, receiving } from "./receiver.js";
2
- export type { WebhookConfig } from "./receiver.js";
3
- export { subscribedSince } from "./subscriptions.js";
4
- export type { WebhookPorts } from "./subscriptions.js";
5
- export { addWebhookTools } from "./tools.js";
@@ -1,3 +0,0 @@
1
- export { joinReceiver, listen, readConfig, receiving } from "./receiver.js";
2
- export { subscribedSince } from "./subscriptions.js";
3
- export { addWebhookTools } from "./tools.js";
@@ -1,80 +0,0 @@
1
- import { type IncomingMessage, type Server } from "node:http";
2
- import { type WebhookPorts } from "./subscriptions.js";
3
- /** Bodies above this are refused; GitHub's own deliveries are capped at 25 MB, real ones are far smaller. */
4
- export declare const DEFAULT_MAX_BYTES: number;
5
- /**
6
- * The webhook receiver, one per process: every instance configured with a `webhook` option joins
7
- * `instances`, the first one starts the server, and the last one to unload stops it.
8
- */
9
- export interface Receiver {
10
- readonly config: WebhookConfig;
11
- readonly instances: Set<WebhookPorts>;
12
- readonly server: Promise<Server | undefined>;
13
- }
14
- /** The current receiver, if any, and the previous one while it closes, which a new one waits for. */
15
- export interface Receivers {
16
- current?: Receiver;
17
- closing?: Promise<void>;
18
- }
19
- /** The receiver's settings, from the plugin's `webhook` option. */
20
- export interface WebhookConfig {
21
- readonly port: number;
22
- readonly host: string;
23
- readonly secret: string;
24
- readonly maxBytes: number;
25
- }
26
- /**
27
- * Checks an `X-Hub-Signature-256` header (`sha256=` + 64 hex digits) in constant time, returning the
28
- * digest in lowercase hex, or undefined; replays are keyed by that digest, never by the header text.
29
- */
30
- export declare function checkSignature(secret: string, body: Uint8Array, header: string | undefined, name?: string): string | undefined;
31
- /** The `X-Hub-Signature-256` value for a body; give the topic name for `/hook/<name>`. */
32
- export declare function sign(secret: string, body: string | Uint8Array, name?: string): string;
33
- /** What an event means for subscribers: the topics it belongs to and a short summary. */
34
- export interface Event {
35
- readonly source: string;
36
- readonly name: string;
37
- readonly topics: readonly string[];
38
- readonly summary: string;
39
- }
40
- /**
41
- * Maps a GitHub delivery to its topics (`github:owner/repo`, plus `github:owner/repo#N` for PRs and
42
- * issues) and a summary; undefined for pings, unfinished CI events and actions outside `ITEM_ACTIONS`.
43
- */
44
- export declare function githubEvent(name: string, payload: unknown): Event | undefined;
45
- /** A delivery to `/hook/<topic>`: a JSON body's `text`, `summary` or `message` field, else the body itself. */
46
- export declare function genericEvent(topic: string, body: string): Event;
47
- /**
48
- * Delivers an event to every session subscribed to one of its topics, once per session. A session
49
- * OpenCode no longer knows loses its subscriptions.
50
- */
51
- export declare function dispatch(ports: WebhookPorts, event: Event, delivery?: string): Promise<{
52
- delivered: number;
53
- failed: number;
54
- }>;
55
- export interface Request {
56
- readonly method: string;
57
- readonly path: string;
58
- readonly headers: Readonly<Record<string, string | string[] | undefined>>;
59
- readonly body: Buffer;
60
- }
61
- export interface Response {
62
- readonly status: number;
63
- readonly body: string;
64
- }
65
- /**
66
- * Handles one request: `POST /github` with GitHub's headers, or `POST /hook/<name>` signed over name
67
- * and body; anything unsigned is refused before parsing, and a signature already accepted is ignored.
68
- */
69
- export declare function receive(ports: WebhookPorts, secret: string, request: Request, seen?: Set<string>): Promise<Response>;
70
- /** Starts the HTTP receiver; `ports()` picks a live plugin instance for each request. */
71
- export declare function listen(config: WebhookConfig, ports: () => WebhookPorts | undefined): Promise<Server<typeof IncomingMessage, typeof import("node:http").ServerResponse>>;
72
- /**
73
- * Reads the `webhook` option, undefined when the receiver is not configured; the secret comes from
74
- * `secretFile` or the env var `secretEnv` (default `COURIER_WEBHOOK_SECRET`), never from the option.
75
- */
76
- export declare function readConfig(options: unknown, env?: Record<string, string | undefined>): WebhookConfig | undefined;
77
- /** Joins this instance to the process's receiver, starting it if there is none; returns the leave. */
78
- export declare function joinReceiver(config: WebhookConfig, ports: WebhookPorts): () => Promise<void>;
79
- /** Whether a webhook receiver runs in this server. */
80
- export declare const receiving: () => Promise<boolean>;