@h-rig/run-worker 0.0.6-alpha.154 → 0.0.6-alpha.156

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,27 @@
1
+ import { type RunSessionCustomEntry } from "@rig/contracts";
2
+ import { readSessionRunEntries, type RunRecord } from "./projection";
3
+ export declare function stringifyLogPayload(value: unknown): string | null;
4
+ export declare function logLineFromValue(value: unknown): string | null;
5
+ export declare function logLineFromSessionEntry(entry: RunSessionCustomEntry): string | null;
6
+ export declare function logLinesFromProjection(projection: RunRecord["projection"]): string[];
7
+ export declare function extractRunLogs(run: RunRecord, deps?: {
8
+ readonly readSessionRunEntries?: typeof readSessionRunEntries;
9
+ }): string[];
10
+ export declare function summarizeRunFailures(run: RunRecord): string[];
11
+ export declare const summarizeProjectionFailures: typeof summarizeRunFailures;
12
+ export declare function runsForTask(projectRoot: string, taskId: string, deps?: {
13
+ readonly listRuns?: (projectRoot: string) => Promise<readonly RunRecord[]>;
14
+ readonly getRun?: (projectRoot: string, runId: string) => Promise<RunRecord | null>;
15
+ }): Promise<RunRecord[]>;
16
+ export interface RunInspectSummaryRow {
17
+ readonly id: string;
18
+ readonly label: string;
19
+ readonly currentValue: string;
20
+ readonly values?: readonly string[];
21
+ readonly heading?: boolean;
22
+ readonly description?: string;
23
+ }
24
+ export declare function runInspectSummaryRows(runs: readonly RunRecord[], options?: {
25
+ readonly projectRoot?: string;
26
+ readonly pendingInbox?: number | null;
27
+ }): RunInspectSummaryRow[];
@@ -0,0 +1,459 @@
1
+ // @bun
2
+ // packages/run-worker/src/runs/inspect.ts
3
+ import { RIG_RUN_LOG_ENTRY } from "@rig/contracts";
4
+
5
+ // packages/run-worker/src/runs/projection.ts
6
+ import { existsSync, readFileSync } from "fs";
7
+ import { isAbsolute, relative, resolve } from "path";
8
+ import { Duration, Effect, Option, Stream } from "effect";
9
+ import {
10
+ foldRunSessionEntries,
11
+ isTerminalRunStatus,
12
+ timelineEntriesFromCustomEntries
13
+ } from "@rig/contracts";
14
+ import { registrySnapshotStream } from "@rig/runtime/control-plane/discovery";
15
+
16
+ // packages/run-worker/src/runs/diagnostics.ts
17
+ function normalizeString(value) {
18
+ if (typeof value !== "string")
19
+ return null;
20
+ const normalized = value.replace(/\s+/g, " ").trim();
21
+ return normalized.length > 0 ? normalized : null;
22
+ }
23
+ function isGenericRunFailure(value) {
24
+ const text = normalizeString(value);
25
+ return Boolean(text && /^Task run failed \([^)]*\)$/i.test(text));
26
+ }
27
+ function appendCandidate(candidates, value) {
28
+ const text = normalizeString(value);
29
+ if (text && !candidates.includes(text))
30
+ candidates.push(text);
31
+ }
32
+ function categorizeUsefulRunError(lines) {
33
+ const taskSourceFailure = lines.find((line) => /failed to update task source/i.test(line));
34
+ if (taskSourceFailure)
35
+ return `Task source update failed: ${taskSourceFailure}`;
36
+ const moduleFailure = lines.find((line) => /cannot find module/i.test(line));
37
+ if (moduleFailure)
38
+ return `Runtime module resolution failed: ${moduleFailure}`;
39
+ const providerFailure = lines.find((line) => /no api key found|unauthorized|authentication failed|invalid api key/i.test(line));
40
+ if (providerFailure)
41
+ return `Provider authentication failed: ${providerFailure}`;
42
+ return null;
43
+ }
44
+ function summarizeRunError(projection) {
45
+ if (projection.status !== "failed")
46
+ return null;
47
+ const candidates = [];
48
+ for (const anomaly of projection.anomalies) {
49
+ appendCandidate(candidates, `Journal anomaly (${anomaly.kind}): ${anomaly.detail}`);
50
+ }
51
+ for (const phase of projection.closeoutPhases) {
52
+ if (phase.outcome === "failed")
53
+ appendCandidate(candidates, phase.detail);
54
+ }
55
+ for (const entry of projection.statusHistory) {
56
+ appendCandidate(candidates, entry.reason);
57
+ }
58
+ appendCandidate(candidates, projection.record.statusDetail);
59
+ appendCandidate(candidates, projection.record.errorText);
60
+ const nonGeneric = candidates.filter((candidate) => !isGenericRunFailure(candidate));
61
+ return categorizeUsefulRunError(nonGeneric) ?? nonGeneric.at(-1) ?? normalizeString(projection.record.errorText);
62
+ }
63
+
64
+ // packages/run-worker/src/runs/projection.ts
65
+ var EMPTY_PROJECTION = foldRunSessionEntries([], "");
66
+ var DISCOVERY_DIAGNOSTIC_RUN_ID = "__registry_discovery_error__";
67
+ function readSessionRunEntries(sessionPath) {
68
+ if (!sessionPath || !existsSync(sessionPath))
69
+ return [];
70
+ try {
71
+ return parseSessionRunEntries(readFileSync(sessionPath, "utf8"));
72
+ } catch {
73
+ return [];
74
+ }
75
+ }
76
+ function parseSessionRunEntries(raw) {
77
+ const entries = [];
78
+ for (const line of raw.split(`
79
+ `)) {
80
+ if (!line.trim())
81
+ continue;
82
+ try {
83
+ const parsed = JSON.parse(line);
84
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
85
+ continue;
86
+ entries.push({
87
+ type: "type" in parsed && typeof parsed.type === "string" ? parsed.type : "",
88
+ ..."customType" in parsed && typeof parsed.customType === "string" ? { customType: parsed.customType } : {},
89
+ ..."data" in parsed ? { data: parsed.data } : {}
90
+ });
91
+ } catch {
92
+ continue;
93
+ }
94
+ }
95
+ return entries;
96
+ }
97
+ function stringOrNull(value) {
98
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
99
+ }
100
+ function numberOrNull(value) {
101
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
102
+ }
103
+ function objectRecord(value) {
104
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
105
+ }
106
+ function registryStatusAsRunStatus(status) {
107
+ if (status === "waiting-input")
108
+ return "waiting-user-input";
109
+ if (status === "starting")
110
+ return "preparing";
111
+ return typeof status === "string" && [
112
+ "created",
113
+ "queued",
114
+ "preparing",
115
+ "running",
116
+ "waiting-approval",
117
+ "waiting-user-input",
118
+ "paused",
119
+ "validating",
120
+ "reviewing",
121
+ "closing-out",
122
+ "needs-attention",
123
+ "completed",
124
+ "failed",
125
+ "stopped"
126
+ ].includes(status) ? status : null;
127
+ }
128
+ function payloadString(payload, keys) {
129
+ if (!payload || typeof payload !== "object")
130
+ return null;
131
+ const record = payload;
132
+ for (const key of keys) {
133
+ const value = record[key];
134
+ if (typeof value === "string" && value.trim())
135
+ return value.trim();
136
+ }
137
+ return null;
138
+ }
139
+ function payloadOptions(payload) {
140
+ if (!payload || typeof payload !== "object")
141
+ return;
142
+ const record = payload;
143
+ const options = Array.isArray(record.options) ? record.options : Array.isArray(record.choices) ? record.choices : null;
144
+ const values = options?.filter((value) => typeof value === "string" && value.trim().length > 0) ?? [];
145
+ return values.length > 0 ? values : undefined;
146
+ }
147
+ function inboxRequest(request, kind) {
148
+ const fallback = kind === "approval" ? "Approval requested" : "Input requested";
149
+ return {
150
+ requestId: request.requestId,
151
+ kind,
152
+ title: payloadString(request.payload, ["title", "message", "reason", "prompt", "summary"]) ?? fallback,
153
+ body: payloadString(request.payload, ["body", "description", "detail", "details"]),
154
+ ...payloadOptions(request.payload) ? { options: payloadOptions(request.payload) } : {},
155
+ requestedAt: request.requestedAt ?? null,
156
+ source: "run"
157
+ };
158
+ }
159
+ function inboxFromProjection(projection) {
160
+ return [
161
+ ...projection.pendingApprovals.map((request) => inboxRequest(request, "approval")),
162
+ ...projection.pendingUserInputs.map((request) => inboxRequest(request, "input"))
163
+ ].sort((a, b) => (Date.parse(a.requestedAt ?? "") || 0) - (Date.parse(b.requestedAt ?? "") || 0));
164
+ }
165
+ function isProjectPath(projectRoot, cwd) {
166
+ const root = resolve(projectRoot);
167
+ const candidate = resolve(cwd);
168
+ const pathFromRoot = relative(root, candidate);
169
+ return pathFromRoot === "" || !pathFromRoot.startsWith("../") && pathFromRoot !== ".." && !isAbsolute(pathFromRoot);
170
+ }
171
+ function sourceFromEntry(projectRoot, projection, entry) {
172
+ const candidates = [
173
+ stringOrNull(projection.collabCwd),
174
+ stringOrNull(projection.cwd),
175
+ stringOrNull(entry.cwd),
176
+ stringOrNull(projection.worktreePath)
177
+ ].filter((cwd) => cwd !== null);
178
+ return candidates.some((cwd) => isProjectPath(projectRoot, cwd)) ? "local" : "remote";
179
+ }
180
+ function pendingRequests(value, fallbackKind) {
181
+ if (!Array.isArray(value))
182
+ return [];
183
+ return value.flatMap((item) => {
184
+ const record = objectRecord(item);
185
+ const requestId = stringOrNull(record?.requestId) ?? stringOrNull(record?.id);
186
+ if (!record || !requestId)
187
+ return [];
188
+ return [{
189
+ requestId,
190
+ requestKind: stringOrNull(record.requestKind) ?? stringOrNull(record.kind) ?? fallbackKind,
191
+ actionId: stringOrNull(record.actionId),
192
+ payload: "payload" in record ? record.payload : record,
193
+ requestedAt: stringOrNull(record.requestedAt) ?? stringOrNull(record.at) ?? ""
194
+ }];
195
+ });
196
+ }
197
+ function emptyFoldedProjection(runId, projection) {
198
+ const projectionRecord = projection;
199
+ const nestedProjection = objectRecord(projectionRecord.projection);
200
+ const pendingApprovals = pendingRequests(nestedProjection?.pendingApprovals ?? projectionRecord.pendingApprovals, "approval");
201
+ const pendingUserInputs = pendingRequests(nestedProjection?.pendingUserInputs ?? nestedProjection?.pendingInputs ?? projectionRecord.pendingUserInputs ?? (Array.isArray(projectionRecord.pendingInputs) ? projectionRecord.pendingInputs : undefined), "user-input");
202
+ const nestedRecord = objectRecord(nestedProjection?.record);
203
+ const nestedFolded = nestedProjection;
204
+ return {
205
+ ...EMPTY_PROJECTION,
206
+ ...nestedFolded ?? {},
207
+ record: {
208
+ ...nestedRecord ?? {},
209
+ runId,
210
+ ...projection.taskId ? { taskId: projection.taskId } : {},
211
+ ...projection.title ? { title: projection.title } : {},
212
+ ...projection.startedAt ? { startedAt: projection.startedAt } : {},
213
+ ...projection.updatedAt ? { updatedAt: projection.updatedAt } : {},
214
+ ...projection.completedAt ? { completedAt: projection.completedAt } : {},
215
+ ...projection.sessionPath ? { sessionPath: projection.sessionPath } : {},
216
+ ...projection.worktreePath ? { worktreePath: projection.worktreePath } : {},
217
+ ...projection.prUrl ? { prUrl: projection.prUrl } : {}
218
+ },
219
+ status: registryStatusAsRunStatus(projection.status) ?? registryStatusAsRunStatus(nestedProjection?.status),
220
+ pendingApprovals,
221
+ pendingUserInputs,
222
+ steeringCount: projection.steeringCount ?? numberOrNull(nestedProjection?.steeringCount) ?? 0,
223
+ stallCount: projection.stallCount ?? numberOrNull(nestedProjection?.stallCount) ?? 0,
224
+ lastEventAt: projection.updatedAt ?? stringOrNull(nestedProjection?.lastEventAt)
225
+ };
226
+ }
227
+ function runRecordFromRegistryEntry(projectRoot, entry) {
228
+ const projection = entry.projection && typeof entry.projection === "object" ? entry.projection : {};
229
+ const runId = stringOrNull(projection.runId) ?? entry.roomId;
230
+ const folded = emptyFoldedProjection(runId, projection);
231
+ const pushedStatus = registryStatusAsRunStatus(projection.status) ?? folded.status ?? registryStatusAsRunStatus(entry.status);
232
+ const status = entry.stale ? pushedStatus && isTerminalRunStatus(pushedStatus) ? pushedStatus : "stale" : pushedStatus ?? "running";
233
+ const sessionPath = stringOrNull(projection.sessionPath) ?? stringOrNull(entry.sessionPath) ?? null;
234
+ const collabCwd = stringOrNull(projection.collabCwd) ?? stringOrNull(projection.cwd) ?? stringOrNull(entry.cwd) ?? stringOrNull(projection.worktreePath);
235
+ return {
236
+ runId,
237
+ taskId: stringOrNull(projection.taskId),
238
+ title: stringOrNull(projection.title) ?? entry.title,
239
+ status,
240
+ source: sourceFromEntry(projectRoot, projection, entry),
241
+ live: !entry.stale,
242
+ stale: entry.stale,
243
+ startedAt: stringOrNull(projection.startedAt) ?? entry.startedAt ?? null,
244
+ updatedAt: stringOrNull(projection.updatedAt) ?? entry.heartbeatAt ?? null,
245
+ completedAt: stringOrNull(projection.completedAt),
246
+ joinLink: stringOrNull(projection.joinLink) ?? entry.joinLink ?? null,
247
+ webLink: stringOrNull(projection.webLink) ?? entry.webLink ?? null,
248
+ relayUrl: stringOrNull(projection.relayUrl) ?? entry.relayUrl ?? null,
249
+ sessionPath,
250
+ prUrl: stringOrNull(projection.prUrl),
251
+ worktreePath: stringOrNull(projection.worktreePath) ?? collabCwd,
252
+ pendingApprovals: numberOrNull(projection.pendingApprovals) ?? folded.pendingApprovals.length,
253
+ pendingInputs: numberOrNull(projection.pendingInputs) ?? folded.pendingUserInputs.length,
254
+ steeringCount: projection.steeringCount ?? 0,
255
+ stallCount: projection.stallCount ?? 0,
256
+ errorSummary: stringOrNull(projection.errorSummary) ?? summarizeRunError(folded),
257
+ timeline: Array.isArray(projection.timeline) ? [...projection.timeline] : [...timelineEntriesFromCustomEntries([])],
258
+ inbox: inboxFromProjection(folded),
259
+ collabCwd: collabCwd ?? null,
260
+ projection: folded
261
+ };
262
+ }
263
+ function runRecordsFromRegistrySnapshot(projectRoot, snapshot) {
264
+ return sortByRecency(snapshot.entries.map((entry) => runRecordFromRegistryEntry(projectRoot, entry)).filter((record) => record !== null));
265
+ }
266
+ function sortByRecency(records) {
267
+ return [...records].sort((a, b) => {
268
+ const at = Date.parse(b.updatedAt ?? b.startedAt ?? "") || 0;
269
+ const bt = Date.parse(a.updatedAt ?? a.startedAt ?? "") || 0;
270
+ return at - bt;
271
+ });
272
+ }
273
+ function discoveryDiagnosticRunRecord(projectRoot, error) {
274
+ const detail = error instanceof Error ? error.message : String(error);
275
+ const runId = DISCOVERY_DIAGNOSTIC_RUN_ID;
276
+ const projection = {
277
+ ...EMPTY_PROJECTION,
278
+ record: { runId, title: "Registry discovery unavailable" },
279
+ status: "needs-attention",
280
+ stallCount: 1
281
+ };
282
+ return {
283
+ runId,
284
+ taskId: null,
285
+ title: "Registry discovery unavailable",
286
+ status: "needs-attention",
287
+ source: "remote",
288
+ live: false,
289
+ stale: true,
290
+ startedAt: null,
291
+ updatedAt: null,
292
+ completedAt: null,
293
+ joinLink: null,
294
+ webLink: null,
295
+ relayUrl: null,
296
+ sessionPath: null,
297
+ prUrl: null,
298
+ worktreePath: null,
299
+ pendingApprovals: 0,
300
+ pendingInputs: 0,
301
+ steeringCount: 0,
302
+ stallCount: 1,
303
+ errorSummary: `registry discovery unavailable: ${detail}`,
304
+ timeline: [],
305
+ inbox: [],
306
+ collabCwd: null,
307
+ projection
308
+ };
309
+ }
310
+ async function listRunProjections(projectRoot, filter = {}) {
311
+ try {
312
+ const snapshot = await Effect.runPromise(registrySnapshotStream(projectRoot, filter).pipe(Stream.runHead, Effect.timeout(Duration.seconds(15)), Effect.map(Option.getOrNull)));
313
+ return snapshot ? runRecordsFromRegistrySnapshot(projectRoot, snapshot) : [discoveryDiagnosticRunRecord(projectRoot, "registry discovery stream ended without a snapshot")];
314
+ } catch (error) {
315
+ return [discoveryDiagnosticRunRecord(projectRoot, error)];
316
+ }
317
+ }
318
+ function selectRunProjection(runs, runId) {
319
+ const exactRun = runs.find((run) => run.runId === runId);
320
+ if (exactRun)
321
+ return exactRun;
322
+ const exactTask = runs.find((run) => run.taskId === runId);
323
+ if (exactTask)
324
+ return exactTask;
325
+ const prefixMatches = runs.filter((run) => run.runId.startsWith(runId));
326
+ if (prefixMatches.length === 1)
327
+ return prefixMatches[0] ?? null;
328
+ if (prefixMatches.length > 1) {
329
+ const matches = prefixMatches.map((run) => run.runId).join(", ");
330
+ throw new Error(`Ambiguous run id prefix "${runId}" matched ${prefixMatches.length} runs: ${matches}`);
331
+ }
332
+ return runs.find((run) => run.runId === DISCOVERY_DIAGNOSTIC_RUN_ID) ?? null;
333
+ }
334
+ async function getRunProjection(projectRoot, runId, filter = {}) {
335
+ const runs = await listRunProjections(projectRoot, filter);
336
+ return selectRunProjection(runs, runId);
337
+ }
338
+ var listRuns = listRunProjections;
339
+ var getRun = getRunProjection;
340
+
341
+ // packages/run-worker/src/runs/inspect.ts
342
+ function asRecord(value) {
343
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
344
+ }
345
+ function firstString(record, keys) {
346
+ for (const key of keys) {
347
+ const value = record[key];
348
+ if (typeof value === "string" && value.trim().length > 0)
349
+ return value;
350
+ }
351
+ return null;
352
+ }
353
+ function stringifyLogPayload(value) {
354
+ if (typeof value === "string")
355
+ return value;
356
+ if (typeof value === "number" || typeof value === "boolean")
357
+ return String(value);
358
+ const record = asRecord(value);
359
+ if (!record)
360
+ return null;
361
+ const direct = firstString(record, ["line", "message", "text", "content", "output", "summary", "detail"]);
362
+ if (direct)
363
+ return direct;
364
+ try {
365
+ return JSON.stringify(record);
366
+ } catch {
367
+ return String(record);
368
+ }
369
+ }
370
+ function logLineFromValue(value) {
371
+ const record = asRecord(value);
372
+ if (!record)
373
+ return stringifyLogPayload(value);
374
+ const direct = firstString(record, ["line", "message", "text", "content", "output", "summary", "detail"]);
375
+ if (direct)
376
+ return direct;
377
+ if ("payload" in record)
378
+ return stringifyLogPayload(record.payload);
379
+ if ("data" in record)
380
+ return stringifyLogPayload(record.data);
381
+ return stringifyLogPayload(record);
382
+ }
383
+ function logLineFromSessionEntry(entry) {
384
+ if (entry.type !== "custom" || entry.customType !== RIG_RUN_LOG_ENTRY)
385
+ return null;
386
+ return logLineFromValue(entry.data);
387
+ }
388
+ function logLinesFromProjection(projection) {
389
+ const projected = projection;
390
+ const lines = [];
391
+ for (const key of ["logs", "logEntries", "journalLogs", "runLogs"]) {
392
+ const entries = projected[key];
393
+ if (!Array.isArray(entries))
394
+ continue;
395
+ for (const entry of entries) {
396
+ const line = logLineFromValue(entry);
397
+ if (line !== null)
398
+ lines.push(line);
399
+ }
400
+ }
401
+ return lines;
402
+ }
403
+ function extractRunLogs(run, deps = {}) {
404
+ const projectedLines = logLinesFromProjection(run.projection);
405
+ if (projectedLines.length > 0)
406
+ return projectedLines;
407
+ return (deps.readSessionRunEntries ?? readSessionRunEntries)(run.sessionPath).map(logLineFromSessionEntry).filter((line) => line !== null);
408
+ }
409
+ function summarizeRunFailures(run) {
410
+ const failures = [];
411
+ const useful = summarizeRunError(run.projection);
412
+ if (useful)
413
+ failures.push(`${run.runId}: ${useful}`);
414
+ if (run.status === "failed" || run.projection.status === "failed")
415
+ failures.push(`${run.runId}: run status failed`);
416
+ for (const phase of run.projection.closeoutPhases) {
417
+ if (phase.outcome === "failed")
418
+ failures.push(`${run.runId}: closeout ${phase.phase} failed${phase.detail ? ` \u2014 ${phase.detail}` : ""}`);
419
+ }
420
+ for (const anomaly of run.projection.anomalies) {
421
+ failures.push(`${run.runId}: anomaly ${anomaly.kind}${anomaly.detail ? ` \u2014 ${anomaly.detail}` : ""}`);
422
+ }
423
+ return failures;
424
+ }
425
+ var summarizeProjectionFailures = summarizeRunFailures;
426
+ async function runsForTask(projectRoot, taskId, deps = {}) {
427
+ const list = deps.listRuns ?? listRuns;
428
+ try {
429
+ const runs = await list(projectRoot);
430
+ const filtered = runs.filter((run2) => run2.taskId === taskId || run2.runId === taskId);
431
+ if (filtered.length > 0)
432
+ return [...filtered];
433
+ } catch {}
434
+ const run = await (deps.getRun ?? getRun)(projectRoot, taskId);
435
+ return run ? [run] : [];
436
+ }
437
+ function runInspectSummaryRows(runs, options = {}) {
438
+ const attachable = runs.filter((run) => Boolean(run.joinLink && !run.stale)).length;
439
+ const pendingInbox = options.pendingInbox ?? runs.reduce((total, run) => total + run.pendingApprovals + run.pendingInputs, 0);
440
+ return [
441
+ { id: "title", label: "Inspect", currentValue: "runtime", heading: true, description: "session/runtime inspection rows from @rig/client" },
442
+ { id: "inspect:sessions", label: "RUNS", currentValue: String(runs.length), heading: true, description: `${attachable} attachable OMP collab links` },
443
+ { id: "inspect:cwd", label: "PROJECT ROOT", currentValue: options.projectRoot ?? "", heading: true, description: "selected target/project root used by Rig chrome" },
444
+ { id: "inspect:inbox", label: "INBOX", currentValue: String(pendingInbox), values: ["open"], description: "pending run gates; open Inbox to resolve" },
445
+ { id: "inspect:runs", label: "RUNS", currentValue: String(runs.length), values: ["open"], description: "open Runs to inspect individual run detail, logs, and attach controls" },
446
+ { id: "inspect:audit", label: "AUDIT", currentValue: "unavailable", heading: true, description: "CLI inspect audit has no cockpit equivalent; use rig inspect audit" }
447
+ ];
448
+ }
449
+ export {
450
+ summarizeRunFailures,
451
+ summarizeProjectionFailures,
452
+ stringifyLogPayload,
453
+ runsForTask,
454
+ runInspectSummaryRows,
455
+ logLinesFromProjection,
456
+ logLineFromValue,
457
+ logLineFromSessionEntry,
458
+ extractRunLogs
459
+ };
@@ -0,0 +1,24 @@
1
+ import { type RunRecord, type RunSessionCustomEntry } from "@rig/contracts";
2
+ import type { CollabRegistryFilter } from "@oh-my-pi/pi-coding-agent/collab/api";
3
+ import type { ListedRegistryEntry, RegistrySnapshotFrame } from "@rig/relay-registry";
4
+ export type { RunRecord, UnifiedInboxRequest } from "@rig/contracts";
5
+ export type RunProjectionRecord = RunRecord;
6
+ /** What an attach/steer caller needs to reach a live run over collab. */
7
+ export interface RunJoinTarget {
8
+ readonly runId: string;
9
+ readonly taskId: string | null;
10
+ readonly joinLink: string;
11
+ readonly cwd: string | null;
12
+ readonly stale: boolean;
13
+ }
14
+ export declare function readSessionRunEntries(sessionPath: string | null): RunSessionCustomEntry[];
15
+ export declare function runRecordFromRegistryEntry(projectRoot: string, entry: ListedRegistryEntry): RunRecord | null;
16
+ export declare function runRecordsFromRegistrySnapshot(projectRoot: string, snapshot: RegistrySnapshotFrame): RunRecord[];
17
+ export declare function discoveryDiagnosticRunRecord(projectRoot: string, error: unknown): RunRecord;
18
+ export declare function listRunProjections(projectRoot: string, filter?: CollabRegistryFilter): Promise<RunRecord[]>;
19
+ export declare function selectRunProjection(runs: readonly RunRecord[], runId: string): RunRecord | null;
20
+ export declare function getRunProjection(projectRoot: string, runId: string, filter?: CollabRegistryFilter): Promise<RunRecord | null>;
21
+ export declare function resolveRunJoinTarget(projectRoot: string, runId: string, filter?: CollabRegistryFilter): Promise<RunJoinTarget | null>;
22
+ export declare const listRuns: typeof listRunProjections;
23
+ export declare const getRun: typeof getRunProjection;
24
+ export declare const resolveJoinTarget: typeof resolveRunJoinTarget;