@h-rig/run-worker 0.0.6-alpha.155 → 0.0.6-alpha.157

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.
@@ -0,0 +1,499 @@
1
+ // @bun
2
+ var __require = import.meta.require;
3
+
4
+ // packages/run-worker/src/runs/inbox.ts
5
+ import { buildInboxResolutionSentinel } from "@rig/contracts";
6
+
7
+ // packages/run-worker/src/runs/control.ts
8
+ import { buildPauseSentinel, buildResumeSentinel, buildStopSentinel } from "@rig/contracts";
9
+
10
+ // packages/run-worker/src/runs/projection.ts
11
+ import { isAbsolute, relative, resolve } from "path";
12
+ import { Duration, Effect, Option, Stream } from "effect";
13
+ import {
14
+ foldRunSessionEntries,
15
+ isTerminalRunStatus,
16
+ timelineEntriesFromCustomEntries
17
+ } from "@rig/contracts";
18
+ import { registrySnapshotStream } from "@rig/runtime/control-plane/discovery";
19
+
20
+ // packages/run-worker/src/runs/diagnostics.ts
21
+ function normalizeString(value) {
22
+ if (typeof value !== "string")
23
+ return null;
24
+ const normalized = value.replace(/\s+/g, " ").trim();
25
+ return normalized.length > 0 ? normalized : null;
26
+ }
27
+ function isGenericRunFailure(value) {
28
+ const text = normalizeString(value);
29
+ return Boolean(text && /^Task run failed \([^)]*\)$/i.test(text));
30
+ }
31
+ function appendCandidate(candidates, value) {
32
+ const text = normalizeString(value);
33
+ if (text && !candidates.includes(text))
34
+ candidates.push(text);
35
+ }
36
+ function categorizeUsefulRunError(lines) {
37
+ const taskSourceFailure = lines.find((line) => /failed to update task source/i.test(line));
38
+ if (taskSourceFailure)
39
+ return `Task source update failed: ${taskSourceFailure}`;
40
+ const moduleFailure = lines.find((line) => /cannot find module/i.test(line));
41
+ if (moduleFailure)
42
+ return `Runtime module resolution failed: ${moduleFailure}`;
43
+ const providerFailure = lines.find((line) => /no api key found|unauthorized|authentication failed|invalid api key/i.test(line));
44
+ if (providerFailure)
45
+ return `Provider authentication failed: ${providerFailure}`;
46
+ return null;
47
+ }
48
+ function summarizeRunError(projection) {
49
+ if (projection.status !== "failed")
50
+ return null;
51
+ const candidates = [];
52
+ for (const anomaly of projection.anomalies) {
53
+ appendCandidate(candidates, `Journal anomaly (${anomaly.kind}): ${anomaly.detail}`);
54
+ }
55
+ for (const phase of projection.closeoutPhases) {
56
+ if (phase.outcome === "failed")
57
+ appendCandidate(candidates, phase.detail);
58
+ }
59
+ for (const entry of projection.statusHistory) {
60
+ appendCandidate(candidates, entry.reason);
61
+ }
62
+ appendCandidate(candidates, projection.record.statusDetail);
63
+ appendCandidate(candidates, projection.record.errorText);
64
+ const nonGeneric = candidates.filter((candidate) => !isGenericRunFailure(candidate));
65
+ return categorizeUsefulRunError(nonGeneric) ?? nonGeneric.at(-1) ?? normalizeString(projection.record.errorText);
66
+ }
67
+
68
+ // packages/run-worker/src/runs/projection.ts
69
+ var EMPTY_PROJECTION = foldRunSessionEntries([], "");
70
+ var DISCOVERY_DIAGNOSTIC_RUN_ID = "__registry_discovery_error__";
71
+ function stringOrNull(value) {
72
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
73
+ }
74
+ function numberOrNull(value) {
75
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
76
+ }
77
+ function objectRecord(value) {
78
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
79
+ }
80
+ function registryStatusAsRunStatus(status) {
81
+ if (status === "waiting-input")
82
+ return "waiting-user-input";
83
+ if (status === "starting")
84
+ return "preparing";
85
+ return typeof status === "string" && [
86
+ "created",
87
+ "queued",
88
+ "preparing",
89
+ "running",
90
+ "waiting-approval",
91
+ "waiting-user-input",
92
+ "paused",
93
+ "validating",
94
+ "reviewing",
95
+ "closing-out",
96
+ "needs-attention",
97
+ "completed",
98
+ "failed",
99
+ "stopped"
100
+ ].includes(status) ? status : null;
101
+ }
102
+ function payloadString(payload, keys) {
103
+ if (!payload || typeof payload !== "object")
104
+ return null;
105
+ const record = payload;
106
+ for (const key of keys) {
107
+ const value = record[key];
108
+ if (typeof value === "string" && value.trim())
109
+ return value.trim();
110
+ }
111
+ return null;
112
+ }
113
+ function payloadOptions(payload) {
114
+ if (!payload || typeof payload !== "object")
115
+ return;
116
+ const record = payload;
117
+ const options = Array.isArray(record.options) ? record.options : Array.isArray(record.choices) ? record.choices : null;
118
+ const values = options?.filter((value) => typeof value === "string" && value.trim().length > 0) ?? [];
119
+ return values.length > 0 ? values : undefined;
120
+ }
121
+ function inboxRequest(request, kind) {
122
+ const fallback = kind === "approval" ? "Approval requested" : "Input requested";
123
+ return {
124
+ requestId: request.requestId,
125
+ kind,
126
+ title: payloadString(request.payload, ["title", "message", "reason", "prompt", "summary"]) ?? fallback,
127
+ body: payloadString(request.payload, ["body", "description", "detail", "details"]),
128
+ ...payloadOptions(request.payload) ? { options: payloadOptions(request.payload) } : {},
129
+ requestedAt: request.requestedAt ?? null,
130
+ source: "run"
131
+ };
132
+ }
133
+ function inboxFromProjection(projection) {
134
+ return [
135
+ ...projection.pendingApprovals.map((request) => inboxRequest(request, "approval")),
136
+ ...projection.pendingUserInputs.map((request) => inboxRequest(request, "input"))
137
+ ].sort((a, b) => (Date.parse(a.requestedAt ?? "") || 0) - (Date.parse(b.requestedAt ?? "") || 0));
138
+ }
139
+ function isProjectPath(projectRoot, cwd) {
140
+ const root = resolve(projectRoot);
141
+ const candidate = resolve(cwd);
142
+ const pathFromRoot = relative(root, candidate);
143
+ return pathFromRoot === "" || !pathFromRoot.startsWith("../") && pathFromRoot !== ".." && !isAbsolute(pathFromRoot);
144
+ }
145
+ function sourceFromEntry(projectRoot, projection, entry) {
146
+ const candidates = [
147
+ stringOrNull(projection.collabCwd),
148
+ stringOrNull(projection.cwd),
149
+ stringOrNull(entry.cwd),
150
+ stringOrNull(projection.worktreePath)
151
+ ].filter((cwd) => cwd !== null);
152
+ return candidates.some((cwd) => isProjectPath(projectRoot, cwd)) ? "local" : "remote";
153
+ }
154
+ function pendingRequests(value, fallbackKind) {
155
+ if (!Array.isArray(value))
156
+ return [];
157
+ return value.flatMap((item) => {
158
+ const record = objectRecord(item);
159
+ const requestId = stringOrNull(record?.requestId) ?? stringOrNull(record?.id);
160
+ if (!record || !requestId)
161
+ return [];
162
+ return [{
163
+ requestId,
164
+ requestKind: stringOrNull(record.requestKind) ?? stringOrNull(record.kind) ?? fallbackKind,
165
+ actionId: stringOrNull(record.actionId),
166
+ payload: "payload" in record ? record.payload : record,
167
+ requestedAt: stringOrNull(record.requestedAt) ?? stringOrNull(record.at) ?? ""
168
+ }];
169
+ });
170
+ }
171
+ function emptyFoldedProjection(runId, projection) {
172
+ const projectionRecord = projection;
173
+ const nestedProjection = objectRecord(projectionRecord.projection);
174
+ const pendingApprovals = pendingRequests(nestedProjection?.pendingApprovals ?? projectionRecord.pendingApprovals, "approval");
175
+ const pendingUserInputs = pendingRequests(nestedProjection?.pendingUserInputs ?? nestedProjection?.pendingInputs ?? projectionRecord.pendingUserInputs ?? (Array.isArray(projectionRecord.pendingInputs) ? projectionRecord.pendingInputs : undefined), "user-input");
176
+ const nestedRecord = objectRecord(nestedProjection?.record);
177
+ const nestedFolded = nestedProjection;
178
+ return {
179
+ ...EMPTY_PROJECTION,
180
+ ...nestedFolded ?? {},
181
+ record: {
182
+ ...nestedRecord ?? {},
183
+ runId,
184
+ ...projection.taskId ? { taskId: projection.taskId } : {},
185
+ ...projection.title ? { title: projection.title } : {},
186
+ ...projection.startedAt ? { startedAt: projection.startedAt } : {},
187
+ ...projection.updatedAt ? { updatedAt: projection.updatedAt } : {},
188
+ ...projection.completedAt ? { completedAt: projection.completedAt } : {},
189
+ ...projection.sessionPath ? { sessionPath: projection.sessionPath } : {},
190
+ ...projection.worktreePath ? { worktreePath: projection.worktreePath } : {},
191
+ ...projection.prUrl ? { prUrl: projection.prUrl } : {}
192
+ },
193
+ status: registryStatusAsRunStatus(projection.status) ?? registryStatusAsRunStatus(nestedProjection?.status),
194
+ pendingApprovals,
195
+ pendingUserInputs,
196
+ steeringCount: projection.steeringCount ?? numberOrNull(nestedProjection?.steeringCount) ?? 0,
197
+ stallCount: projection.stallCount ?? numberOrNull(nestedProjection?.stallCount) ?? 0,
198
+ lastEventAt: projection.updatedAt ?? stringOrNull(nestedProjection?.lastEventAt)
199
+ };
200
+ }
201
+ function runRecordFromRegistryEntry(projectRoot, entry) {
202
+ const projection = entry.projection && typeof entry.projection === "object" ? entry.projection : {};
203
+ const runId = stringOrNull(projection.runId) ?? entry.roomId;
204
+ const folded = emptyFoldedProjection(runId, projection);
205
+ const pushedStatus = registryStatusAsRunStatus(projection.status) ?? folded.status ?? registryStatusAsRunStatus(entry.status);
206
+ const status = entry.stale ? pushedStatus && isTerminalRunStatus(pushedStatus) ? pushedStatus : "stale" : pushedStatus ?? "running";
207
+ const sessionPath = stringOrNull(projection.sessionPath) ?? stringOrNull(entry.sessionPath) ?? null;
208
+ const collabCwd = stringOrNull(projection.collabCwd) ?? stringOrNull(projection.cwd) ?? stringOrNull(entry.cwd) ?? stringOrNull(projection.worktreePath);
209
+ return {
210
+ runId,
211
+ taskId: stringOrNull(projection.taskId),
212
+ title: stringOrNull(projection.title) ?? entry.title,
213
+ status,
214
+ source: sourceFromEntry(projectRoot, projection, entry),
215
+ live: !entry.stale,
216
+ stale: entry.stale,
217
+ startedAt: stringOrNull(projection.startedAt) ?? entry.startedAt ?? null,
218
+ updatedAt: stringOrNull(projection.updatedAt) ?? entry.heartbeatAt ?? null,
219
+ completedAt: stringOrNull(projection.completedAt),
220
+ joinLink: stringOrNull(projection.joinLink) ?? entry.joinLink ?? null,
221
+ webLink: stringOrNull(projection.webLink) ?? entry.webLink ?? null,
222
+ relayUrl: stringOrNull(projection.relayUrl) ?? entry.relayUrl ?? null,
223
+ sessionPath,
224
+ prUrl: stringOrNull(projection.prUrl),
225
+ worktreePath: stringOrNull(projection.worktreePath) ?? collabCwd,
226
+ pendingApprovals: numberOrNull(projection.pendingApprovals) ?? folded.pendingApprovals.length,
227
+ pendingInputs: numberOrNull(projection.pendingInputs) ?? folded.pendingUserInputs.length,
228
+ steeringCount: projection.steeringCount ?? 0,
229
+ stallCount: projection.stallCount ?? 0,
230
+ errorSummary: stringOrNull(projection.errorSummary) ?? summarizeRunError(folded),
231
+ timeline: Array.isArray(projection.timeline) ? [...projection.timeline] : [...timelineEntriesFromCustomEntries([])],
232
+ inbox: inboxFromProjection(folded),
233
+ collabCwd: collabCwd ?? null,
234
+ projection: folded
235
+ };
236
+ }
237
+ function runRecordsFromRegistrySnapshot(projectRoot, snapshot) {
238
+ return sortByRecency(snapshot.entries.map((entry) => runRecordFromRegistryEntry(projectRoot, entry)).filter((record) => record !== null));
239
+ }
240
+ function sortByRecency(records) {
241
+ return [...records].sort((a, b) => {
242
+ const at = Date.parse(b.updatedAt ?? b.startedAt ?? "") || 0;
243
+ const bt = Date.parse(a.updatedAt ?? a.startedAt ?? "") || 0;
244
+ return at - bt;
245
+ });
246
+ }
247
+ function discoveryDiagnosticRunRecord(projectRoot, error) {
248
+ const detail = error instanceof Error ? error.message : String(error);
249
+ const runId = DISCOVERY_DIAGNOSTIC_RUN_ID;
250
+ const projection = {
251
+ ...EMPTY_PROJECTION,
252
+ record: { runId, title: "Registry discovery unavailable" },
253
+ status: "needs-attention",
254
+ stallCount: 1
255
+ };
256
+ return {
257
+ runId,
258
+ taskId: null,
259
+ title: "Registry discovery unavailable",
260
+ status: "needs-attention",
261
+ source: "remote",
262
+ live: false,
263
+ stale: true,
264
+ startedAt: null,
265
+ updatedAt: null,
266
+ completedAt: null,
267
+ joinLink: null,
268
+ webLink: null,
269
+ relayUrl: null,
270
+ sessionPath: null,
271
+ prUrl: null,
272
+ worktreePath: null,
273
+ pendingApprovals: 0,
274
+ pendingInputs: 0,
275
+ steeringCount: 0,
276
+ stallCount: 1,
277
+ errorSummary: `registry discovery unavailable: ${detail}`,
278
+ timeline: [],
279
+ inbox: [],
280
+ collabCwd: null,
281
+ projection
282
+ };
283
+ }
284
+ async function listRunProjections(projectRoot, filter = {}) {
285
+ try {
286
+ const snapshot = await Effect.runPromise(registrySnapshotStream(projectRoot, filter).pipe(Stream.runHead, Effect.timeout(Duration.seconds(15)), Effect.map(Option.getOrNull)));
287
+ return snapshot ? runRecordsFromRegistrySnapshot(projectRoot, snapshot) : [discoveryDiagnosticRunRecord(projectRoot, "registry discovery stream ended without a snapshot")];
288
+ } catch (error) {
289
+ return [discoveryDiagnosticRunRecord(projectRoot, error)];
290
+ }
291
+ }
292
+ function selectRunProjection(runs, runId) {
293
+ const exactRun = runs.find((run) => run.runId === runId);
294
+ if (exactRun)
295
+ return exactRun;
296
+ const exactTask = runs.find((run) => run.taskId === runId);
297
+ if (exactTask)
298
+ return exactTask;
299
+ const prefixMatches = runs.filter((run) => run.runId.startsWith(runId));
300
+ if (prefixMatches.length === 1)
301
+ return prefixMatches[0] ?? null;
302
+ if (prefixMatches.length > 1) {
303
+ const matches = prefixMatches.map((run) => run.runId).join(", ");
304
+ throw new Error(`Ambiguous run id prefix "${runId}" matched ${prefixMatches.length} runs: ${matches}`);
305
+ }
306
+ return runs.find((run) => run.runId === DISCOVERY_DIAGNOSTIC_RUN_ID) ?? null;
307
+ }
308
+ async function getRunProjection(projectRoot, runId, filter = {}) {
309
+ const runs = await listRunProjections(projectRoot, filter);
310
+ return selectRunProjection(runs, runId);
311
+ }
312
+ var listRuns = listRunProjections;
313
+ var getRun = getRunProjection;
314
+
315
+ // packages/run-worker/src/runs/control.ts
316
+ async function loadCollabControlDeps() {
317
+ const [{ importRoomKey, seal }, { COLLAB_PROTO, packEnvelope, parseCollabLink }] = await Promise.all([
318
+ import("@oh-my-pi/pi-coding-agent/collab/crypto"),
319
+ import("@oh-my-pi/pi-coding-agent/collab/protocol")
320
+ ]);
321
+ return { importRoomKey, seal, COLLAB_PROTO, packEnvelope, parseCollabLink };
322
+ }
323
+ function collabControlFrames(runId, control) {
324
+ switch (control.kind) {
325
+ case "steer":
326
+ return [{ t: "prompt", text: control.message }];
327
+ case "resume":
328
+ return [{ t: "prompt", text: `${buildResumeSentinel(runId)}
329
+ Continue the run from where it paused.` }];
330
+ case "pause":
331
+ return [
332
+ { t: "prompt", text: `${buildPauseSentinel(runId)}
333
+ Pause this run after the current interruption settles.` },
334
+ { t: "abort" }
335
+ ];
336
+ case "stop":
337
+ return [
338
+ { t: "prompt", text: `${buildStopSentinel(runId, control.reason)}
339
+ Stop this run and do not continue after the interruption settles.` },
340
+ { t: "abort" }
341
+ ];
342
+ }
343
+ }
344
+ async function sendSealedCollabFrames(joinLink, frames, deps = {}) {
345
+ const { importRoomKey, seal, COLLAB_PROTO, packEnvelope, parseCollabLink } = await loadCollabControlDeps();
346
+ const parsed = parseCollabLink(joinLink);
347
+ if ("error" in parsed)
348
+ throw new Error(parsed.error);
349
+ if (!parsed.writeToken)
350
+ throw new Error("Run collab link is read-only; cannot send control.");
351
+ const key = await importRoomKey(parsed.key);
352
+ const WebSocketCtor = deps.WebSocket ?? WebSocket;
353
+ const ws = new WebSocketCtor(`${parsed.wsUrl}?role=guest`);
354
+ await new Promise((resolveOpen, rejectOpen) => {
355
+ ws.addEventListener("open", () => resolveOpen(), { once: true });
356
+ ws.addEventListener("error", () => rejectOpen(new Error("collab websocket error")), { once: true });
357
+ });
358
+ const hello = {
359
+ t: "hello",
360
+ proto: COLLAB_PROTO,
361
+ name: "rig-operator",
362
+ writeToken: Buffer.from(parsed.writeToken).toString("base64url")
363
+ };
364
+ ws.send(packEnvelope(0, await seal(key, hello)));
365
+ for (const frame of frames)
366
+ ws.send(packEnvelope(0, await seal(key, frame)));
367
+ try {
368
+ ws.close();
369
+ } catch {}
370
+ }
371
+ async function deliverRemoteRunControl(projectRoot, target, control, deps = {}) {
372
+ const record = typeof target === "string" ? await getRun(projectRoot, target) : target;
373
+ const runId = typeof target === "string" ? target : target.runId;
374
+ if (!record)
375
+ throw new Error(`Run not found: ${runId}`);
376
+ if (!record.joinLink)
377
+ throw new Error(`Run ${record.runId} has no writable collab join link.`);
378
+ await sendSealedCollabFrames(record.joinLink, collabControlFrames(record.runId, control), deps);
379
+ }
380
+ async function deliverRunControl(projectRoot, target, control, deps = {}) {
381
+ const record = typeof target === "string" ? await (deps.getRun ?? getRun)(projectRoot, target) : target;
382
+ const runId = typeof target === "string" ? target : target.runId;
383
+ if (!record)
384
+ throw new Error(`Run not found: ${runId}`);
385
+ if (!record.joinLink)
386
+ throw new Error(`Run ${record.runId} has no writable collab join link; attach interactively to ${control.kind}.`);
387
+ try {
388
+ await (deps.deliverRemote ?? deliverRemoteRunControl)(projectRoot, record, control);
389
+ } catch (error) {
390
+ const detail = error instanceof Error ? error.message : `Attach to ${control.kind} interactively: rig run attach ${record.runId}`;
391
+ throw new Error(`Could not ${control.kind} run ${record.runId}. ${detail}`);
392
+ }
393
+ }
394
+
395
+ // packages/run-worker/src/runs/inbox.ts
396
+ function promptFromPayload(payload, fallback) {
397
+ if (payload && typeof payload === "object") {
398
+ const record = payload;
399
+ for (const key of ["title", "message", "reason", "prompt", "summary"]) {
400
+ const value = record[key];
401
+ if (typeof value === "string" && value.trim().length > 0)
402
+ return value.trim();
403
+ }
404
+ }
405
+ return fallback;
406
+ }
407
+ function recordsFromRun(run, kind) {
408
+ const pending = kind === "approvals" ? run.projection.pendingApprovals : run.projection.pendingUserInputs;
409
+ return pending.map((request) => ({
410
+ runId: run.runId,
411
+ taskId: run.taskId,
412
+ requestId: request.requestId,
413
+ status: "pending",
414
+ prompt: promptFromPayload(request.payload, kind === "approvals" ? "Approval requested" : "Input requested"),
415
+ requestedAt: request.requestedAt,
416
+ payload: request.payload,
417
+ kind: kind === "approvals" ? "approval" : "input"
418
+ }));
419
+ }
420
+ async function listInboxRecords(context, kind, filters = {}, deps = {}) {
421
+ const projectRoot = typeof context === "string" ? context : context.projectRoot;
422
+ const runs = await (deps.listRuns ?? listRuns)(projectRoot);
423
+ const out = [];
424
+ for (const run of runs) {
425
+ if (filters.run && run.runId !== filters.run)
426
+ continue;
427
+ if (filters.task && run.taskId !== filters.task)
428
+ continue;
429
+ out.push(...recordsFromRun(run, kind));
430
+ }
431
+ return out;
432
+ }
433
+ async function listInbox(projectRoot, filters = {}, deps = {}) {
434
+ const runs = await (deps.listRuns ?? listRuns)(projectRoot);
435
+ const out = [];
436
+ for (const run of runs) {
437
+ if (filters.run && run.runId !== filters.run)
438
+ continue;
439
+ if (filters.task && run.taskId !== filters.task)
440
+ continue;
441
+ for (const request of run.inbox ?? []) {
442
+ if (request.source !== "run")
443
+ continue;
444
+ out.push(request);
445
+ }
446
+ }
447
+ return out;
448
+ }
449
+ async function readPendingInboxCounts(context, deps = {}) {
450
+ try {
451
+ const projectRoot = typeof context === "string" ? context : context.projectRoot;
452
+ const [approvals, inputs] = await Promise.all([
453
+ listInboxRecords(projectRoot, "approvals", {}, deps),
454
+ listInboxRecords(projectRoot, "inputs", {}, deps)
455
+ ]);
456
+ return { approvals: approvals.length, inputs: inputs.length };
457
+ } catch {
458
+ return null;
459
+ }
460
+ }
461
+ var readInboxCounts = readPendingInboxCounts;
462
+ function normalizedApprovalDecision(decision) {
463
+ return decision === "approved" || decision === "approve" ? "approve" : "reject";
464
+ }
465
+ function inputAnswers(answer) {
466
+ return typeof answer === "string" ? { answer } : answer;
467
+ }
468
+ function decisionText(runId, requestId, decision) {
469
+ if (decision.kind === "approval") {
470
+ const normalized = normalizedApprovalDecision(decision.decision);
471
+ const label = normalized === "approve" ? "approved" : "rejected";
472
+ return [
473
+ buildInboxResolutionSentinel(runId, { kind: "approval", requestId, decision: normalized, note: decision.note ?? null }),
474
+ `Rig inbox approval ${requestId} was ${label}.`,
475
+ decision.note ? `Operator note: ${decision.note}` : null,
476
+ "Continue using this approval decision."
477
+ ].filter((line) => Boolean(line)).join(`
478
+ `);
479
+ }
480
+ const answers = inputAnswers(decision.answer);
481
+ return [
482
+ buildInboxResolutionSentinel(runId, { kind: "input", requestId, answers }),
483
+ `Rig inbox input ${requestId} was answered with:`,
484
+ JSON.stringify(answers),
485
+ "Continue using this input answer."
486
+ ].join(`
487
+ `);
488
+ }
489
+ async function resolveInboxRequest(projectRoot, runId, requestId, decision, deps = {}) {
490
+ await (deps.deliverRunControl ?? deliverRunControl)(projectRoot, runId, { kind: "steer", message: decisionText(runId, requestId, decision) });
491
+ }
492
+ export {
493
+ resolveInboxRequest,
494
+ recordsFromRun,
495
+ readPendingInboxCounts,
496
+ readInboxCounts,
497
+ listInboxRecords,
498
+ listInbox
499
+ };
@@ -0,0 +1,9 @@
1
+ export * from "./control";
2
+ export * from "./guard";
3
+ export * from "./inbox";
4
+ export * from "./inspect";
5
+ export * from "./run-status";
6
+ export * from "./stats";
7
+ export { listRuns, getRun, resolveJoinTarget, resolveRunJoinTarget, readSessionRunEntries, } from "./projection";
8
+ export { summarizeRunError } from "./diagnostics";
9
+ export type { RunRecord, RunJoinTarget, UnifiedInboxRequest } from "./projection";