@h-rig/run-worker 0.0.6-alpha.156 → 0.0.6-alpha.158
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/src/autohost.d.ts +8 -10
- package/dist/src/autohost.js +683 -95
- package/dist/src/constants.d.ts +0 -1
- package/dist/src/constants.js +0 -2
- package/dist/src/extension.js +683 -95
- package/dist/src/host-kernel.d.ts +22 -0
- package/dist/src/host-kernel.js +78 -0
- package/dist/src/host.d.ts +2 -0
- package/dist/src/host.js +419 -0
- package/dist/src/index.d.ts +0 -6
- package/dist/src/index.js +1913 -133
- package/dist/src/local-run-changes.d.ts +3 -0
- package/dist/src/local-run-changes.js +65 -0
- package/dist/src/notifications.js +13 -5
- package/dist/src/notify-cap.d.ts +11 -0
- package/dist/src/notify-cap.js +13 -0
- package/dist/src/panel-plugin.js +3 -7
- package/dist/src/plugin.d.ts +0 -11
- package/dist/src/plugin.js +1910 -101
- package/dist/src/{runs → read-model-backend}/control.d.ts +0 -1
- package/dist/src/{runs → read-model-backend}/control.js +361 -38
- package/dist/src/{runs → read-model-backend}/diagnostics.d.ts +0 -1
- package/dist/src/{runs → read-model-backend}/diagnostics.js +1 -3
- package/dist/src/{runs → read-model-backend}/guard.js +2 -3
- package/dist/src/{runs → read-model-backend}/inbox.js +366 -36
- package/dist/src/{runs → read-model-backend}/index.js +552 -223
- package/dist/src/{runs → read-model-backend}/inspect.d.ts +0 -1
- package/dist/src/{runs → read-model-backend}/inspect.js +350 -34
- package/dist/src/{runs → read-model-backend}/projection.d.ts +21 -7
- package/dist/src/{runs → read-model-backend}/projection.js +349 -31
- package/dist/src/{runs → read-model-backend}/run-status.d.ts +6 -3
- package/dist/src/{runs → read-model-backend}/run-status.js +53 -33
- package/dist/src/{runs → read-model-backend}/stats.d.ts +0 -1
- package/dist/src/{runs → read-model-backend}/stats.js +373 -58
- package/dist/src/read-model-service.d.ts +2 -0
- package/dist/src/read-model-service.js +1433 -0
- package/dist/src/session-journal.d.ts +60 -0
- package/dist/src/session-journal.js +471 -0
- package/dist/src/stall.d.ts +8 -3
- package/dist/src/stall.js +0 -1
- package/dist/src/utils.js +282 -3
- package/package.json +9 -12
- package/dist/src/journal.d.ts +0 -33
- package/dist/src/journal.js +0 -31
- /package/dist/src/{runs → read-model-backend}/guard.d.ts +0 -0
- /package/dist/src/{runs → read-model-backend}/inbox.d.ts +0 -0
- /package/dist/src/{runs → read-model-backend}/index.d.ts +0 -0
|
@@ -1,23 +1,331 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
var __require = import.meta.require;
|
|
3
3
|
|
|
4
|
-
// packages/run-worker/src/
|
|
5
|
-
import {
|
|
4
|
+
// packages/run-worker/src/read-model-backend/inbox.ts
|
|
5
|
+
import { RIG_CONTROL_SENTINEL_END as RIG_CONTROL_SENTINEL_END3, RIG_INBOX_RESOLUTION_SENTINEL as RIG_INBOX_RESOLUTION_SENTINEL2 } from "@rig/contracts";
|
|
6
6
|
|
|
7
|
-
// packages/run-worker/src/
|
|
8
|
-
import {
|
|
7
|
+
// packages/run-worker/src/read-model-backend/control.ts
|
|
8
|
+
import { RIG_CONTROL_SENTINEL_END as RIG_CONTROL_SENTINEL_END2, RIG_PAUSE_SENTINEL as RIG_PAUSE_SENTINEL2, RIG_RESUME_SENTINEL as RIG_RESUME_SENTINEL2, RIG_STOP_SENTINEL as RIG_STOP_SENTINEL2, RIG_STOP_SENTINEL_END as RIG_STOP_SENTINEL_END2 } from "@rig/contracts";
|
|
9
9
|
|
|
10
|
-
// packages/run-worker/src/
|
|
10
|
+
// packages/run-worker/src/read-model-backend/projection.ts
|
|
11
11
|
import { isAbsolute, relative, resolve } from "path";
|
|
12
|
-
import {
|
|
12
|
+
import { RUN_DISCOVERY } from "@rig/contracts";
|
|
13
|
+
|
|
14
|
+
// packages/run-worker/src/session-journal.ts
|
|
15
|
+
import { Schema } from "effect";
|
|
13
16
|
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
CUSTOM_TYPE_FOR,
|
|
18
|
+
RIG_CONTROL_SENTINEL_END,
|
|
19
|
+
RIG_INBOX_RESOLUTION_SENTINEL,
|
|
20
|
+
RIG_PAUSE_SENTINEL,
|
|
21
|
+
RIG_RESUME_SENTINEL,
|
|
22
|
+
RIG_STOP_SENTINEL,
|
|
23
|
+
RIG_STOP_SENTINEL_END,
|
|
24
|
+
RIG_WORKFLOW_STATUS_CHANGED,
|
|
25
|
+
RunJournalEvent,
|
|
26
|
+
TYPE_FOR_CUSTOM
|
|
17
27
|
} from "@rig/contracts";
|
|
18
|
-
|
|
28
|
+
var decodeRunJournalEvent = Schema.decodeUnknownSync(RunJournalEvent);
|
|
29
|
+
var RUN_STATUS_TRANSITIONS = {
|
|
30
|
+
created: ["queued", "preparing", "running", "failed", "stopped"],
|
|
31
|
+
queued: ["preparing", "running", "failed", "stopped"],
|
|
32
|
+
preparing: ["queued", "running", "needs-attention", "failed", "stopped"],
|
|
33
|
+
running: [
|
|
34
|
+
"queued",
|
|
35
|
+
"waiting-approval",
|
|
36
|
+
"waiting-user-input",
|
|
37
|
+
"paused",
|
|
38
|
+
"validating",
|
|
39
|
+
"reviewing",
|
|
40
|
+
"closing-out",
|
|
41
|
+
"needs-attention",
|
|
42
|
+
"completed",
|
|
43
|
+
"failed",
|
|
44
|
+
"stopped"
|
|
45
|
+
],
|
|
46
|
+
"waiting-approval": ["running", "needs-attention", "failed", "stopped"],
|
|
47
|
+
"waiting-user-input": ["running", "needs-attention", "failed", "stopped"],
|
|
48
|
+
paused: ["running", "failed", "stopped"],
|
|
49
|
+
validating: ["running", "reviewing", "closing-out", "needs-attention", "completed", "failed", "stopped"],
|
|
50
|
+
reviewing: ["running", "validating", "closing-out", "needs-attention", "completed", "failed", "stopped"],
|
|
51
|
+
"closing-out": ["running", "needs-attention", "completed", "failed", "stopped"],
|
|
52
|
+
"needs-attention": ["queued", "preparing", "running", "closing-out", "completed", "failed", "stopped"],
|
|
53
|
+
completed: [],
|
|
54
|
+
failed: ["queued", "preparing", "running", "closing-out"],
|
|
55
|
+
stopped: ["queued", "preparing", "running", "closing-out"]
|
|
56
|
+
};
|
|
57
|
+
var TERMINAL_RUN_STATUSES = ["completed", "failed", "stopped"];
|
|
58
|
+
function isTerminalRunStatus(status) {
|
|
59
|
+
return TERMINAL_RUN_STATUSES.includes(status);
|
|
60
|
+
}
|
|
61
|
+
function canTransitionRunStatus(from, to) {
|
|
62
|
+
if (from === null)
|
|
63
|
+
return true;
|
|
64
|
+
if (from === to)
|
|
65
|
+
return true;
|
|
66
|
+
return RUN_STATUS_TRANSITIONS[from].includes(to);
|
|
67
|
+
}
|
|
68
|
+
function assertRunStatusTransition(from, to) {
|
|
69
|
+
if (!canTransitionRunStatus(from, to)) {
|
|
70
|
+
throw new Error(`Illegal run status transition: ${from ?? "(none)"} -> ${to}. ` + `Allowed from ${from ?? "(none)"}: ${from ? RUN_STATUS_TRANSITIONS[from].join(", ") : "(any)"}.`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function reduceRunJournal(events, runId = null) {
|
|
74
|
+
let record = {};
|
|
75
|
+
let status = null;
|
|
76
|
+
const statusHistory = [];
|
|
77
|
+
const pendingApprovals = new Map;
|
|
78
|
+
const resolvedApprovals = [];
|
|
79
|
+
const pendingUserInputs = new Map;
|
|
80
|
+
const resolvedUserInputs = [];
|
|
81
|
+
const closeoutPhases = [];
|
|
82
|
+
let resolvedPipeline = null;
|
|
83
|
+
const stageOutcomes = [];
|
|
84
|
+
const anomalies = [];
|
|
85
|
+
let steeringCount = 0;
|
|
86
|
+
let stallCount = 0;
|
|
87
|
+
let lastSeq = 0;
|
|
88
|
+
let lastEventAt = null;
|
|
89
|
+
const projectedRunId = runId ?? events[0]?.runId ?? null;
|
|
90
|
+
for (const event of events) {
|
|
91
|
+
lastSeq = event.seq;
|
|
92
|
+
lastEventAt = event.at;
|
|
93
|
+
switch (event.type) {
|
|
94
|
+
case "status-changed": {
|
|
95
|
+
if (!canTransitionRunStatus(status, event.to)) {
|
|
96
|
+
anomalies.push({ seq: event.seq, kind: "illegal-transition", detail: `${status ?? "(none)"} -> ${event.to}` });
|
|
97
|
+
}
|
|
98
|
+
statusHistory.push({ seq: event.seq, at: event.at, from: status, to: event.to, reason: event.reason ?? null });
|
|
99
|
+
const wasTerminal = status !== null && isTerminalRunStatus(status);
|
|
100
|
+
status = event.to;
|
|
101
|
+
record = { ...record, updatedAt: event.at };
|
|
102
|
+
if (isTerminalRunStatus(event.to) && !record.completedAt)
|
|
103
|
+
record = { ...record, completedAt: event.at };
|
|
104
|
+
if (!isTerminalRunStatus(event.to) && wasTerminal)
|
|
105
|
+
record = { ...record, completedAt: null };
|
|
106
|
+
if (event.to === "running" && !record.startedAt)
|
|
107
|
+
record = { ...record, startedAt: event.at };
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
case "record-patch": {
|
|
111
|
+
const next = { ...record };
|
|
112
|
+
for (const [key, value] of Object.entries(event.patch)) {
|
|
113
|
+
if (value !== undefined)
|
|
114
|
+
next[key] = value;
|
|
115
|
+
}
|
|
116
|
+
next.updatedAt = event.patch.updatedAt ?? event.at;
|
|
117
|
+
record = next;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
case "approval-requested": {
|
|
121
|
+
pendingApprovals.set(event.requestId, {
|
|
122
|
+
requestId: event.requestId,
|
|
123
|
+
requestKind: event.requestKind,
|
|
124
|
+
actionId: event.actionId ?? null,
|
|
125
|
+
payload: event.payload,
|
|
126
|
+
requestedAt: event.at
|
|
127
|
+
});
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
case "approval-resolved": {
|
|
131
|
+
const pending = pendingApprovals.get(event.requestId);
|
|
132
|
+
if (!pending) {
|
|
133
|
+
const alreadyResolved = resolvedApprovals.some((entry) => entry.requestId === event.requestId);
|
|
134
|
+
anomalies.push({ seq: event.seq, kind: alreadyResolved ? "duplicate-resolution" : "unknown-request", detail: `approval ${event.requestId}` });
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
pendingApprovals.delete(event.requestId);
|
|
138
|
+
resolvedApprovals.push({ ...pending, decision: event.decision, note: event.note ?? null, actor: event.actor, resolvedAt: event.at });
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
case "input-requested": {
|
|
142
|
+
pendingUserInputs.set(event.requestId, {
|
|
143
|
+
requestId: event.requestId,
|
|
144
|
+
requestKind: "user-input",
|
|
145
|
+
actionId: null,
|
|
146
|
+
payload: event.payload,
|
|
147
|
+
requestedAt: event.at
|
|
148
|
+
});
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
case "input-resolved": {
|
|
152
|
+
const pending = pendingUserInputs.get(event.requestId);
|
|
153
|
+
if (!pending) {
|
|
154
|
+
const alreadyResolved = resolvedUserInputs.some((entry) => entry.requestId === event.requestId);
|
|
155
|
+
anomalies.push({ seq: event.seq, kind: alreadyResolved ? "duplicate-resolution" : "unknown-request", detail: `user-input ${event.requestId}` });
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
pendingUserInputs.delete(event.requestId);
|
|
159
|
+
resolvedUserInputs.push({ ...pending, answers: event.answers, actor: event.actor, resolvedAt: event.at });
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
case "steering":
|
|
163
|
+
steeringCount += 1;
|
|
164
|
+
break;
|
|
165
|
+
case "adopted":
|
|
166
|
+
record = { ...record, pid: event.pid, updatedAt: event.at };
|
|
167
|
+
break;
|
|
168
|
+
case "stall-detected":
|
|
169
|
+
stallCount += 1;
|
|
170
|
+
break;
|
|
171
|
+
case "closeout-phase":
|
|
172
|
+
closeoutPhases.push({ seq: event.seq, at: event.at, phase: event.phase, outcome: event.outcome, detail: event.detail ?? null });
|
|
173
|
+
break;
|
|
174
|
+
case "pipeline-resolved":
|
|
175
|
+
resolvedPipeline = event.pipeline;
|
|
176
|
+
break;
|
|
177
|
+
case "stage-outcome":
|
|
178
|
+
stageOutcomes.push({ seq: event.seq, at: event.at, outcome: event.outcome });
|
|
179
|
+
break;
|
|
180
|
+
case "timeline-entry":
|
|
181
|
+
case "log-entry":
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
runId: projectedRunId,
|
|
187
|
+
record,
|
|
188
|
+
status,
|
|
189
|
+
statusHistory,
|
|
190
|
+
pendingApprovals: [...pendingApprovals.values()],
|
|
191
|
+
resolvedApprovals,
|
|
192
|
+
pendingUserInputs: [...pendingUserInputs.values()],
|
|
193
|
+
resolvedUserInputs,
|
|
194
|
+
steeringCount,
|
|
195
|
+
stallCount,
|
|
196
|
+
closeoutPhases,
|
|
197
|
+
resolvedPipeline,
|
|
198
|
+
stageOutcomes,
|
|
199
|
+
lastSeq,
|
|
200
|
+
lastEventAt,
|
|
201
|
+
anomalies
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function isRunSessionCustomType(customType) {
|
|
205
|
+
return customType !== undefined && Object.hasOwn(TYPE_FOR_CUSTOM, customType);
|
|
206
|
+
}
|
|
207
|
+
function foldRunSessionEntries(entries, runId) {
|
|
208
|
+
const events = [];
|
|
209
|
+
entries.forEach((entry, index) => {
|
|
210
|
+
if (entry.type !== "custom" || !isRunSessionCustomType(entry.customType))
|
|
211
|
+
return;
|
|
212
|
+
const data = entry.data !== null && typeof entry.data === "object" ? entry.data : {};
|
|
213
|
+
const stamped = {
|
|
214
|
+
v: 1,
|
|
215
|
+
seq: index + 1,
|
|
216
|
+
at: typeof data.at === "string" ? data.at : new Date(0).toISOString(),
|
|
217
|
+
runId,
|
|
218
|
+
...data,
|
|
219
|
+
type: TYPE_FOR_CUSTOM[entry.customType]
|
|
220
|
+
};
|
|
221
|
+
try {
|
|
222
|
+
events.push(decodeRunJournalEvent(stamped));
|
|
223
|
+
} catch {}
|
|
224
|
+
});
|
|
225
|
+
return reduceRunJournal(events, runId);
|
|
226
|
+
}
|
|
227
|
+
function isRecord(value) {
|
|
228
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
229
|
+
}
|
|
230
|
+
function timelineEntryFromCustomEntry(entry) {
|
|
231
|
+
if (entry.customType !== CUSTOM_TYPE_FOR["timeline-entry"] || !isRecord(entry.data))
|
|
232
|
+
return null;
|
|
233
|
+
const payload = isRecord(entry.data.payload) ? entry.data.payload : entry.data;
|
|
234
|
+
const type = typeof payload.type === "string" ? payload.type : "timeline";
|
|
235
|
+
const stage = typeof payload.stage === "string" ? payload.stage : typeof payload.name === "string" ? payload.name : null;
|
|
236
|
+
const status = typeof payload.status === "string" ? payload.status : typeof payload.outcome === "string" ? payload.outcome : null;
|
|
237
|
+
const detail = typeof payload.detail === "string" ? payload.detail : typeof payload.message === "string" ? payload.message : null;
|
|
238
|
+
const at = typeof entry.data.at === "string" ? entry.data.at : typeof payload.at === "string" ? payload.at : null;
|
|
239
|
+
return { at, type, stage, status, detail };
|
|
240
|
+
}
|
|
241
|
+
function timelineEntriesFromCustomEntries(entries) {
|
|
242
|
+
return entries.flatMap((entry) => {
|
|
243
|
+
const timelineEntry = timelineEntryFromCustomEntry(entry);
|
|
244
|
+
return timelineEntry ? [timelineEntry] : [];
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
function asCustomEntries(entries) {
|
|
248
|
+
return entries.filter((entry) => entry.type === "custom");
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
class RunSessionJournal {
|
|
252
|
+
sm;
|
|
253
|
+
runId;
|
|
254
|
+
constructor(sm, runId) {
|
|
255
|
+
this.sm = sm;
|
|
256
|
+
this.runId = runId;
|
|
257
|
+
}
|
|
258
|
+
#append(init) {
|
|
259
|
+
this.sm.appendCustomEntry(CUSTOM_TYPE_FOR[init.type], { ...init, at: new Date().toISOString() });
|
|
260
|
+
}
|
|
261
|
+
appendStatus(to, opts = {}) {
|
|
262
|
+
const from = foldRunSessionEntries(asCustomEntries(this.sm.getEntries()), this.runId).status;
|
|
263
|
+
if (!opts.force)
|
|
264
|
+
assertRunStatusTransition(from, to);
|
|
265
|
+
if (opts.errorText !== undefined)
|
|
266
|
+
this.#append({ type: "record-patch", patch: { errorText: opts.errorText } });
|
|
267
|
+
this.#append({
|
|
268
|
+
type: "status-changed",
|
|
269
|
+
from,
|
|
270
|
+
to,
|
|
271
|
+
...opts.reason !== undefined ? { reason: opts.reason } : {},
|
|
272
|
+
...opts.actor !== undefined ? { actor: opts.actor } : {}
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
appendTimeline(payload) {
|
|
276
|
+
this.#append({ type: "timeline-entry", payload });
|
|
277
|
+
}
|
|
278
|
+
appendCloseoutPhase(input) {
|
|
279
|
+
this.#append({
|
|
280
|
+
type: "closeout-phase",
|
|
281
|
+
phase: input.phase,
|
|
282
|
+
outcome: input.outcome,
|
|
283
|
+
...input.detail !== undefined ? { detail: input.detail } : {}
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
appendApprovalResolved(input) {
|
|
287
|
+
this.#append({
|
|
288
|
+
type: "approval-resolved",
|
|
289
|
+
requestId: input.requestId,
|
|
290
|
+
decision: input.decision,
|
|
291
|
+
actor: input.actor,
|
|
292
|
+
...input.note !== undefined ? { note: input.note } : {}
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
appendInputResolved(input) {
|
|
296
|
+
this.#append({ type: "input-resolved", requestId: input.requestId, answers: input.answers, actor: input.actor });
|
|
297
|
+
}
|
|
298
|
+
appendStall(input) {
|
|
299
|
+
this.#append({ type: "stall-detected", detail: input.detail });
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// packages/run-worker/src/read-model-backend/projection.ts
|
|
304
|
+
import { loadCapabilityForRoot } from "@rig/core/capability-loaders";
|
|
305
|
+
import { defineCapability } from "@rig/core/capability";
|
|
306
|
+
|
|
307
|
+
// packages/run-worker/src/read-model-backend/run-status.ts
|
|
308
|
+
import { OPERATOR_INACTIVE_RUN_STATUSES } from "@rig/contracts";
|
|
309
|
+
var TERMINAL_RUN_STATUSES2 = ["completed", "failed", "stopped"];
|
|
310
|
+
var ACTIVE_RUN_STATUSES = [
|
|
311
|
+
"created",
|
|
312
|
+
"queued",
|
|
313
|
+
"preparing",
|
|
314
|
+
"running",
|
|
315
|
+
"waiting-approval",
|
|
316
|
+
"waiting-user-input",
|
|
317
|
+
"paused",
|
|
318
|
+
"validating",
|
|
319
|
+
"reviewing",
|
|
320
|
+
"closing-out",
|
|
321
|
+
"needs-attention"
|
|
322
|
+
];
|
|
323
|
+
var KNOWN_RUN_STATUS = Object.fromEntries([...ACTIVE_RUN_STATUSES, ...TERMINAL_RUN_STATUSES2].map((status) => [status, true]));
|
|
324
|
+
function asRunStatus(status) {
|
|
325
|
+
return KNOWN_RUN_STATUS[status] ? status : null;
|
|
326
|
+
}
|
|
19
327
|
|
|
20
|
-
// packages/run-worker/src/
|
|
328
|
+
// packages/run-worker/src/read-model-backend/diagnostics.ts
|
|
21
329
|
function normalizeString(value) {
|
|
22
330
|
if (typeof value !== "string")
|
|
23
331
|
return null;
|
|
@@ -65,7 +373,27 @@ function summarizeRunError(projection) {
|
|
|
65
373
|
return categorizeUsefulRunError(nonGeneric) ?? nonGeneric.at(-1) ?? normalizeString(projection.record.errorText);
|
|
66
374
|
}
|
|
67
375
|
|
|
68
|
-
// packages/run-worker/src/
|
|
376
|
+
// packages/run-worker/src/read-model-backend/projection.ts
|
|
377
|
+
var RunDiscoveryCap = defineCapability(RUN_DISCOVERY);
|
|
378
|
+
function registryEntryFromCollab(collab) {
|
|
379
|
+
const record = collab;
|
|
380
|
+
return {
|
|
381
|
+
roomId: collab.sessionId,
|
|
382
|
+
title: collab.title,
|
|
383
|
+
status: record.registryStatus ?? (collab.stale ? "stale" : "running"),
|
|
384
|
+
startedAt: collab.startedAt ?? null,
|
|
385
|
+
heartbeatAt: collab.updatedAt ?? null,
|
|
386
|
+
sessionPath: collab.sessionPath ?? null,
|
|
387
|
+
cwd: collab.cwd ?? null,
|
|
388
|
+
joinLink: collab.joinLink ?? null,
|
|
389
|
+
webLink: collab.webLink ?? null,
|
|
390
|
+
relayUrl: collab.relayUrl ?? null,
|
|
391
|
+
stale: collab.stale,
|
|
392
|
+
repo: collab.selectedRepo ?? null,
|
|
393
|
+
...collab.pid === undefined ? {} : { pid: collab.pid },
|
|
394
|
+
projection: record.registryProjection ?? null
|
|
395
|
+
};
|
|
396
|
+
}
|
|
69
397
|
var EMPTY_PROJECTION = foldRunSessionEntries([], "");
|
|
70
398
|
var DISCOVERY_DIAGNOSTIC_RUN_ID = "__registry_discovery_error__";
|
|
71
399
|
function stringOrNull(value) {
|
|
@@ -82,22 +410,7 @@ function registryStatusAsRunStatus(status) {
|
|
|
82
410
|
return "waiting-user-input";
|
|
83
411
|
if (status === "starting")
|
|
84
412
|
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;
|
|
413
|
+
return typeof status === "string" ? asRunStatus(status) : null;
|
|
101
414
|
}
|
|
102
415
|
function payloadString(payload, keys) {
|
|
103
416
|
if (!payload || typeof payload !== "object")
|
|
@@ -120,12 +433,14 @@ function payloadOptions(payload) {
|
|
|
120
433
|
}
|
|
121
434
|
function inboxRequest(request, kind) {
|
|
122
435
|
const fallback = kind === "approval" ? "Approval requested" : "Input requested";
|
|
436
|
+
const body = payloadString(request.payload, ["body", "description", "detail", "details"]);
|
|
437
|
+
const options = payloadOptions(request.payload);
|
|
123
438
|
return {
|
|
124
439
|
requestId: request.requestId,
|
|
125
440
|
kind,
|
|
126
441
|
title: payloadString(request.payload, ["title", "message", "reason", "prompt", "summary"]) ?? fallback,
|
|
127
|
-
body
|
|
128
|
-
...
|
|
442
|
+
...body !== undefined ? { body } : {},
|
|
443
|
+
...options ? { options } : {},
|
|
129
444
|
requestedAt: request.requestedAt ?? null,
|
|
130
445
|
source: "run"
|
|
131
446
|
};
|
|
@@ -234,8 +549,8 @@ function runRecordFromRegistryEntry(projectRoot, entry) {
|
|
|
234
549
|
projection: folded
|
|
235
550
|
};
|
|
236
551
|
}
|
|
237
|
-
function
|
|
238
|
-
return sortByRecency(
|
|
552
|
+
function runRecordsFromCollab(projectRoot, collabs) {
|
|
553
|
+
return sortByRecency(collabs.map((collab) => runRecordFromRegistryEntry(projectRoot, registryEntryFromCollab(collab))).filter((record) => record !== null));
|
|
239
554
|
}
|
|
240
555
|
function sortByRecency(records) {
|
|
241
556
|
return [...records].sort((a, b) => {
|
|
@@ -283,8 +598,11 @@ function discoveryDiagnosticRunRecord(projectRoot, error) {
|
|
|
283
598
|
}
|
|
284
599
|
async function listRunProjections(projectRoot, filter = {}) {
|
|
285
600
|
try {
|
|
286
|
-
const
|
|
287
|
-
|
|
601
|
+
const discovery = await loadCapabilityForRoot(projectRoot, RunDiscoveryCap);
|
|
602
|
+
if (!discovery)
|
|
603
|
+
return [discoveryDiagnosticRunRecord(projectRoot, "run discovery capability unavailable")];
|
|
604
|
+
const collabs = await discovery.listActiveRunCollab(projectRoot, filter);
|
|
605
|
+
return runRecordsFromCollab(projectRoot, collabs);
|
|
288
606
|
} catch (error) {
|
|
289
607
|
return [discoveryDiagnosticRunRecord(projectRoot, error)];
|
|
290
608
|
}
|
|
@@ -312,7 +630,16 @@ async function getRunProjection(projectRoot, runId, filter = {}) {
|
|
|
312
630
|
var listRuns = listRunProjections;
|
|
313
631
|
var getRun = getRunProjection;
|
|
314
632
|
|
|
315
|
-
// packages/run-worker/src/
|
|
633
|
+
// packages/run-worker/src/read-model-backend/control.ts
|
|
634
|
+
function buildPauseSentinel(runId) {
|
|
635
|
+
return `${RIG_PAUSE_SENTINEL2} runId=${runId} requestedBy=operator ${RIG_CONTROL_SENTINEL_END2}`;
|
|
636
|
+
}
|
|
637
|
+
function buildResumeSentinel(runId) {
|
|
638
|
+
return `${RIG_RESUME_SENTINEL2} runId=${runId} requestedBy=operator ${RIG_CONTROL_SENTINEL_END2}`;
|
|
639
|
+
}
|
|
640
|
+
function buildStopSentinel(runId, reason) {
|
|
641
|
+
return `${RIG_STOP_SENTINEL2} runId=${runId} reason=${reason} ${RIG_STOP_SENTINEL_END2}`;
|
|
642
|
+
}
|
|
316
643
|
async function loadCollabControlDeps() {
|
|
317
644
|
const [{ importRoomKey, seal }, { COLLAB_PROTO, packEnvelope, parseCollabLink }] = await Promise.all([
|
|
318
645
|
import("@oh-my-pi/pi-coding-agent/collab/crypto"),
|
|
@@ -392,7 +719,10 @@ async function deliverRunControl(projectRoot, target, control, deps = {}) {
|
|
|
392
719
|
}
|
|
393
720
|
}
|
|
394
721
|
|
|
395
|
-
// packages/run-worker/src/
|
|
722
|
+
// packages/run-worker/src/read-model-backend/inbox.ts
|
|
723
|
+
function buildInboxResolutionSentinel(runId, payload) {
|
|
724
|
+
return `${RIG_INBOX_RESOLUTION_SENTINEL2} runId=${runId} data=${encodeURIComponent(JSON.stringify(payload))} requestedBy=operator ${RIG_CONTROL_SENTINEL_END3}`;
|
|
725
|
+
}
|
|
396
726
|
function promptFromPayload(payload, fallback) {
|
|
397
727
|
if (payload && typeof payload === "object") {
|
|
398
728
|
const record = payload;
|