@h-rig/run-worker 0.0.6-alpha.132 → 0.0.6-alpha.133
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 +14 -0
- package/dist/src/autohost.js +124 -13
- package/dist/src/extension.js +123 -13
- package/dist/src/index.js +124 -13
- package/dist/src/journal.d.ts +2 -0
- package/dist/src/journal.js +18 -1
- package/package.json +6 -4
package/dist/src/autohost.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionContext, AgentEndEvent } from "@oh-my-pi/pi-coding-agent";
|
|
2
2
|
import { type RigRunTimelineEntry, type RunInboxResolutionSentinel, type RunSessionCustomEntry } from "@rig/contracts";
|
|
3
3
|
import { projectRunFromSession } from "@rig/runtime/control-plane/run-session-projection";
|
|
4
|
+
import { updateRunTaskSourceLifecycle } from "@rig/runtime/control-plane/tasks/source-lifecycle";
|
|
4
5
|
import { type RegistryRunProjection } from "@rig/relay-registry";
|
|
5
6
|
export interface RunProcessWorkerHooks {
|
|
6
7
|
readonly beforeAgentStart: () => void;
|
|
@@ -8,6 +9,18 @@ export interface RunProcessWorkerHooks {
|
|
|
8
9
|
readonly agentEnd: (event: AgentEndEvent) => Promise<void>;
|
|
9
10
|
}
|
|
10
11
|
export declare const REGISTRY_PROJECTION_TIMELINE_LIMIT = 100;
|
|
12
|
+
type RunTaskSourceLifecycleUpdater = typeof updateRunTaskSourceLifecycle;
|
|
13
|
+
export declare function reflectStoppedRunTaskSource(input: {
|
|
14
|
+
readonly projectRoot: string;
|
|
15
|
+
readonly runId: string;
|
|
16
|
+
readonly taskId?: string | null;
|
|
17
|
+
readonly sourceTask?: unknown;
|
|
18
|
+
readonly worktreePath?: string | null;
|
|
19
|
+
readonly logRoot?: string | null;
|
|
20
|
+
readonly sessionPath?: string | null;
|
|
21
|
+
readonly reason?: string | null;
|
|
22
|
+
readonly updateLifecycle?: RunTaskSourceLifecycleUpdater;
|
|
23
|
+
}): Promise<boolean>;
|
|
11
24
|
export declare function registryRunProjection(input: {
|
|
12
25
|
readonly runId: string;
|
|
13
26
|
readonly folded: ReturnType<typeof projectRunFromSession>;
|
|
@@ -32,3 +45,4 @@ export declare function detectRunControlText(text: string, runId: string): {
|
|
|
32
45
|
} | null;
|
|
33
46
|
export declare function maybeStartRunProcessAutohost(api: ExtensionAPI, ctx: ExtensionContext): Promise<RunProcessWorkerHooks | null>;
|
|
34
47
|
export declare function maybeStartSpikeAutohost(ctx: ExtensionContext): Promise<void>;
|
|
48
|
+
export {};
|
package/dist/src/autohost.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/run-worker/src/autohost.ts
|
|
3
|
+
import { runStagedCloseout } from "@rig/bundle-default-lifecycle/staged-closeout";
|
|
3
4
|
import { latestTimelineEntriesFromCustomEntries, parseInboxResolutionSentinel, parsePauseSentinel, parseResumeSentinel, parseStopSentinel, sessionIdFromSessionFile } from "@rig/contracts";
|
|
4
5
|
import { Duration, Effect, Fiber, Stream } from "effect";
|
|
5
6
|
import { createEnvCloseoutRunners } from "@rig/runtime/control-plane/native/closeout-runners";
|
|
6
|
-
import { CloseoutValidationError
|
|
7
|
+
import { CloseoutValidationError } from "@rig/runtime/control-plane/native/in-process-closeout";
|
|
7
8
|
import { projectRunFromSession } from "@rig/runtime/control-plane/run-session-projection";
|
|
8
9
|
import { localRunChanges } from "@rig/runtime/control-plane/run-discovery-stream";
|
|
9
10
|
import { updateRunTaskSourceLifecycle } from "@rig/runtime/control-plane/tasks/source-lifecycle";
|
|
@@ -11,12 +12,30 @@ import { resolveOwnerNamespaceKey } from "@rig/runtime/control-plane/remote-conf
|
|
|
11
12
|
import { resolveRigIdentity } from "@rig/runtime/control-plane/identity";
|
|
12
13
|
import { connectWorkerProjection, createRegistryClient } from "@rig/relay-registry";
|
|
13
14
|
import { coerceRegistryStatus } from "@rig/relay-registry/schema";
|
|
15
|
+
import { bootDefaultKernelIntoProcess } from "@rig/kernel/boot-default";
|
|
14
16
|
|
|
15
17
|
// packages/run-worker/src/journal.ts
|
|
18
|
+
import { createJournalSessionProvider } from "@rig/kernel/journal-session-provider";
|
|
16
19
|
import { RunSessionJournal } from "@rig/runtime/control-plane/run-session-writer";
|
|
17
20
|
async function createRunJournal(sessionManager, runId) {
|
|
18
21
|
try {
|
|
19
|
-
|
|
22
|
+
const journal = new RunSessionJournal(sessionManager, runId);
|
|
23
|
+
const kernel = createJournalSessionProvider({
|
|
24
|
+
runId,
|
|
25
|
+
store: {
|
|
26
|
+
appendCustomEntry: (customType, data) => sessionManager.appendCustomEntry(customType, data),
|
|
27
|
+
getEntries: () => sessionManager.getEntries?.() ?? sessionManager.getBranch?.() ?? []
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
return {
|
|
31
|
+
kernel,
|
|
32
|
+
appendStatus: journal.appendStatus.bind(journal),
|
|
33
|
+
appendTimeline: journal.appendTimeline.bind(journal),
|
|
34
|
+
appendCloseoutPhase: journal.appendCloseoutPhase.bind(journal),
|
|
35
|
+
appendApprovalResolved: journal.appendApprovalResolved.bind(journal),
|
|
36
|
+
appendInputResolved: journal.appendInputResolved.bind(journal),
|
|
37
|
+
appendStall: journal.appendStall.bind(journal)
|
|
38
|
+
};
|
|
20
39
|
} catch (error) {
|
|
21
40
|
console.warn(`[rig-run] RunSessionJournal unavailable; run-state arming deferred: ${error instanceof Error ? error.message : String(error)}`);
|
|
22
41
|
return null;
|
|
@@ -111,7 +130,32 @@ function rigRelayUrl() {
|
|
|
111
130
|
}
|
|
112
131
|
|
|
113
132
|
// packages/run-worker/src/autohost.ts
|
|
133
|
+
var RIG_PANELS_CUSTOM_MESSAGE_TYPE = "rig-panels";
|
|
134
|
+
var RIG_RUN_STOP_PANEL_ACTION = "rig-run:stop";
|
|
135
|
+
function syntheticRegistryOwner(namespaceKey) {
|
|
136
|
+
const githubUserId = namespaceKey.startsWith("gh:") ? namespaceKey.slice(3) : namespaceKey;
|
|
137
|
+
return {
|
|
138
|
+
githubUserId: githubUserId || "anonymous",
|
|
139
|
+
login: "anonymous",
|
|
140
|
+
namespaceKey
|
|
141
|
+
};
|
|
142
|
+
}
|
|
114
143
|
var REGISTRY_PROJECTION_TIMELINE_LIMIT = 100;
|
|
144
|
+
async function reflectStoppedRunTaskSource(input) {
|
|
145
|
+
const taskId = input.taskId?.trim();
|
|
146
|
+
if (!taskId)
|
|
147
|
+
return false;
|
|
148
|
+
const reason = input.reason?.trim();
|
|
149
|
+
await (input.updateLifecycle ?? updateRunTaskSourceLifecycle)(input.projectRoot, {
|
|
150
|
+
runId: input.runId,
|
|
151
|
+
taskId,
|
|
152
|
+
sourceTask: input.sourceTask,
|
|
153
|
+
worktreePath: input.worktreePath,
|
|
154
|
+
logRoot: input.logRoot,
|
|
155
|
+
sessionPath: input.sessionPath
|
|
156
|
+
}, "cancelled", reason ? `Rig stopped by operator: ${reason}` : "Rig stopped by operator.");
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
115
159
|
function registryRunProjection(input) {
|
|
116
160
|
const timeline = input.timeline ?? latestTimelineEntriesFromCustomEntries(input.entries, REGISTRY_PROJECTION_TIMELINE_LIMIT);
|
|
117
161
|
return {
|
|
@@ -185,7 +229,6 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
185
229
|
if (!envRunId)
|
|
186
230
|
throw new Error("RIG_RUN_ID is required when RIG_RUN_PROCESS=1");
|
|
187
231
|
const runId = sessionIdFromSessionFile(ctx.sessionManager.getSessionFile()) ?? envRunId;
|
|
188
|
-
console.log(`[rig-run] session_start hasUI=${ctx.hasUI ? "true" : "false"}`);
|
|
189
232
|
if (!ctx.hasUI)
|
|
190
233
|
return null;
|
|
191
234
|
const collab = ctx.collab;
|
|
@@ -194,6 +237,10 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
194
237
|
throw new Error("OMP collab host facade is unavailable for Rig run process.");
|
|
195
238
|
const identity = resolveRigIdentity(ctx);
|
|
196
239
|
const journal = await createRunJournal(ctx.sessionManager, runId);
|
|
240
|
+
await bootDefaultKernelIntoProcess({
|
|
241
|
+
entrypoint: "run-worker",
|
|
242
|
+
...journal ? { journal: journal.kernel } : {}
|
|
243
|
+
});
|
|
197
244
|
const projectRoot = process.env.PROJECT_RIG_ROOT ?? process.cwd();
|
|
198
245
|
let runProjection = projectRunFromSession(customEntries(ctx.sessionManager.getBranch()), runId);
|
|
199
246
|
const taskIdAtStart = process.env.RIG_TASK_ID?.trim() || runProjection.record.taskId;
|
|
@@ -212,8 +259,10 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
212
259
|
let runRegistryRoomId = null;
|
|
213
260
|
let workerProjectionConnection = null;
|
|
214
261
|
let workerProjectionFiber = null;
|
|
215
|
-
const runRegistryNamespace = identity?.owner?.namespaceKey ?? resolveOwnerNamespaceKey(rigProjectRoot()) ??
|
|
216
|
-
const
|
|
262
|
+
const runRegistryNamespace = identity?.owner?.namespaceKey ?? resolveOwnerNamespaceKey(rigProjectRoot()) ?? "anonymous";
|
|
263
|
+
const runRegistryOwner = identity?.owner ?? syntheticRegistryOwner(runRegistryNamespace);
|
|
264
|
+
const runRegistryRepo = identity?.selectedRepo ?? "";
|
|
265
|
+
const runRegistry = createRegistryClient({ baseUrl: registryBaseUrl(), namespaceKey: runRegistryNamespace });
|
|
217
266
|
let runRegistryLinks = {};
|
|
218
267
|
const processedControlEntryIds = new Set((ctx.sessionManager.getEntries?.() ?? []).map((entry) => entry && typeof entry === "object" && typeof entry.id === "string" ? entry.id : null).filter((id) => id !== null));
|
|
219
268
|
const processedControlEntryObjects = new WeakSet;
|
|
@@ -251,6 +300,38 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
251
300
|
timeline
|
|
252
301
|
});
|
|
253
302
|
};
|
|
303
|
+
let lastRigPanelsSnapshotJson = "";
|
|
304
|
+
const publishRigPanelsSnapshot = () => {
|
|
305
|
+
const appendCustomMessageEntry = ctx.sessionManager.appendCustomMessageEntry?.bind(ctx.sessionManager);
|
|
306
|
+
if (!appendCustomMessageEntry)
|
|
307
|
+
return;
|
|
308
|
+
const { folded } = currentProjectionParts();
|
|
309
|
+
const status = folded.status ?? "unknown";
|
|
310
|
+
const taskId = folded.record.taskId ?? taskIdAtStart;
|
|
311
|
+
const operatorActive = status === "running" || status === "validating" || status === "closing-out" || status === "needs-attention";
|
|
312
|
+
const frameBody = {
|
|
313
|
+
kind: "snapshot",
|
|
314
|
+
activePanel: "supervisor",
|
|
315
|
+
registrations: [{ id: "supervisor", title: "Supervisor" }],
|
|
316
|
+
supervisor: {
|
|
317
|
+
status,
|
|
318
|
+
currentTask: taskId ? { id: taskId, title: runDisplayTitle } : null,
|
|
319
|
+
processed: folded.closeoutPhases.length,
|
|
320
|
+
succeeded: folded.closeoutPhases.filter((phase) => phase.outcome === "completed").length,
|
|
321
|
+
failed: folded.closeoutPhases.filter((phase) => phase.outcome === "failed").length,
|
|
322
|
+
skipped: 0,
|
|
323
|
+
plannedOrder: taskId ? [{ id: taskId, title: runDisplayTitle, status }] : [],
|
|
324
|
+
idleReason: operatorActive ? null : status,
|
|
325
|
+
stopActionId: operatorActive ? RIG_RUN_STOP_PANEL_ACTION : null,
|
|
326
|
+
closures: []
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
const serialized = JSON.stringify(frameBody);
|
|
330
|
+
if (serialized === lastRigPanelsSnapshotJson)
|
|
331
|
+
return;
|
|
332
|
+
lastRigPanelsSnapshotJson = serialized;
|
|
333
|
+
appendCustomMessageEntry(RIG_PANELS_CUSTOM_MESSAGE_TYPE, "", false, { ...frameBody, updatedAt: new Date().toISOString() }, "agent");
|
|
334
|
+
};
|
|
254
335
|
const pushWorkerProjection = (links = runRegistryLinks) => {
|
|
255
336
|
if (!workerProjectionConnection)
|
|
256
337
|
return;
|
|
@@ -258,6 +339,7 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
258
339
|
};
|
|
259
340
|
const publishRunProjection = async (status) => {
|
|
260
341
|
const projection = buildCurrentRegistryProjection();
|
|
342
|
+
publishRigPanelsSnapshot();
|
|
261
343
|
if (workerProjectionConnection)
|
|
262
344
|
workerProjectionConnection.push(projection);
|
|
263
345
|
if (runRegistry && runRegistryRoomId) {
|
|
@@ -360,13 +442,23 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
360
442
|
};
|
|
361
443
|
process.once("uncaughtException", publishFatalTerminal);
|
|
362
444
|
process.once("unhandledRejection", publishFatalTerminal);
|
|
445
|
+
const handlePanelAction = async (input) => {
|
|
446
|
+
if (input.actionId !== RIG_RUN_STOP_PANEL_ACTION && input.actionId !== "stop-supervisor") {
|
|
447
|
+
throw new Error(`Unsupported Rig panel action: ${input.actionId}`);
|
|
448
|
+
}
|
|
449
|
+
pendingStopReason = `operator ${input.from.name} requested stop`;
|
|
450
|
+
journal?.appendTimeline({ type: "interrupted", stage: "panel-action", status: "running", detail: pendingStopReason });
|
|
451
|
+
ctx.abort();
|
|
452
|
+
await publishRunProjection("running");
|
|
453
|
+
};
|
|
363
454
|
const startRunCollabHost = async () => {
|
|
364
455
|
try {
|
|
365
456
|
const projection = await startHost.call(collab, {
|
|
366
457
|
title: runDisplayTitle,
|
|
367
458
|
...identity?.owner ? { owner: identity.owner } : {},
|
|
368
459
|
...identity?.selectedRepo ? { selectedRepo: identity.selectedRepo } : {},
|
|
369
|
-
relayUrl: rigRelayUrl()
|
|
460
|
+
relayUrl: rigRelayUrl(),
|
|
461
|
+
onPanelAction: handlePanelAction
|
|
370
462
|
});
|
|
371
463
|
runRegistryLinks = { joinLink: projection.joinLink, webLink: projection.webLink, relayUrl: projection.relayUrl ?? rigRelayUrl() };
|
|
372
464
|
const timeline = {
|
|
@@ -379,14 +471,15 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
379
471
|
journal?.appendTimeline(timeline);
|
|
380
472
|
console.log(`[rig-run] collab-host-started joinLink=${projection.joinLink || "(empty)"} relayUrl=${projection.relayUrl || "(empty)"}`);
|
|
381
473
|
ctx.ui.notify("Rig run collab host started.", "info");
|
|
382
|
-
|
|
474
|
+
publishRigPanelsSnapshot();
|
|
475
|
+
if (runRegistry) {
|
|
383
476
|
try {
|
|
384
477
|
runRegistryRoomId = projection.sessionId;
|
|
385
478
|
const initialProjection = buildCurrentRegistryProjection();
|
|
386
479
|
await runRegistry.registerRoom({
|
|
387
480
|
roomId: projection.sessionId,
|
|
388
|
-
owner:
|
|
389
|
-
repo:
|
|
481
|
+
owner: runRegistryOwner,
|
|
482
|
+
repo: runRegistryRepo,
|
|
390
483
|
title: runDisplayTitle,
|
|
391
484
|
status: "running",
|
|
392
485
|
joinLink: projection.joinLink ?? "",
|
|
@@ -414,9 +507,6 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
414
507
|
console.error(`[rig-run] registry-register-failed ${error instanceof Error ? error.message : String(error)}`);
|
|
415
508
|
ctx.ui.notify("Rig run could not register to the discovery registry; it may not appear in Runs.", "warning");
|
|
416
509
|
}
|
|
417
|
-
} else {
|
|
418
|
-
console.error(`[rig-run] registry-skip namespace=${runRegistryNamespace ? "set" : "MISSING"}`);
|
|
419
|
-
ctx.ui.notify("Rig run NOT registered (registry namespace missing) \u2014 it won't appear in Runs.", "warning");
|
|
420
510
|
}
|
|
421
511
|
} catch (error) {
|
|
422
512
|
console.error(`[rig-run] collab-host-start-failed ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -463,6 +553,26 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
463
553
|
closeoutStarted = true;
|
|
464
554
|
journal?.appendTimeline({ type: "interrupted", stage: "stopped", status: "stopped", detail: reason });
|
|
465
555
|
journal?.appendStatus("stopped", { actor: OPERATOR_ACTOR, reason, force: true });
|
|
556
|
+
if (taskIdAtStart) {
|
|
557
|
+
journal?.appendTimeline({ type: "stage", stage: "Task-source", status: "running", detail: "reflecting operator stop to task source" });
|
|
558
|
+
try {
|
|
559
|
+
await reflectStoppedRunTaskSource({
|
|
560
|
+
projectRoot,
|
|
561
|
+
runId,
|
|
562
|
+
taskId: taskIdAtStart,
|
|
563
|
+
sourceTask: runProjection.record.sourceTask,
|
|
564
|
+
worktreePath: process.cwd(),
|
|
565
|
+
logRoot: runProjection.record.logRoot ?? null,
|
|
566
|
+
sessionPath: runProjection.record.sessionPath ?? null,
|
|
567
|
+
reason
|
|
568
|
+
});
|
|
569
|
+
journal?.appendTimeline({ type: "stage", stage: "Task-source", status: "completed", detail: "reflected operator stop" });
|
|
570
|
+
} catch (error) {
|
|
571
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
572
|
+
journal?.appendTimeline({ type: "stage", stage: "Task-source", status: "failed", detail });
|
|
573
|
+
console.error(`[rig-run] stopped-reflection-failed ${detail}`);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
466
576
|
await publishRunProjection("stopped");
|
|
467
577
|
stopRunStallMonitor();
|
|
468
578
|
stopRunRegistry({ removeRoom: false });
|
|
@@ -506,7 +616,7 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
506
616
|
const { command, gitCommand } = createEnvCloseoutRunners(process.env);
|
|
507
617
|
let closeoutStatusAdvanced = false;
|
|
508
618
|
try {
|
|
509
|
-
await
|
|
619
|
+
await runStagedCloseout({
|
|
510
620
|
projectRoot,
|
|
511
621
|
runId,
|
|
512
622
|
taskId,
|
|
@@ -585,6 +695,7 @@ async function maybeStartSpikeAutohost(ctx) {
|
|
|
585
695
|
}
|
|
586
696
|
export {
|
|
587
697
|
registryRunProjection,
|
|
698
|
+
reflectStoppedRunTaskSource,
|
|
588
699
|
maybeStartSpikeAutohost,
|
|
589
700
|
maybeStartRunProcessAutohost,
|
|
590
701
|
detectRunControlText,
|
package/dist/src/extension.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/run-worker/src/autohost.ts
|
|
3
|
+
import { runStagedCloseout } from "@rig/bundle-default-lifecycle/staged-closeout";
|
|
3
4
|
import { latestTimelineEntriesFromCustomEntries, parseInboxResolutionSentinel, parsePauseSentinel, parseResumeSentinel, parseStopSentinel, sessionIdFromSessionFile } from "@rig/contracts";
|
|
4
5
|
import { Duration, Effect, Fiber, Stream } from "effect";
|
|
5
6
|
import { createEnvCloseoutRunners } from "@rig/runtime/control-plane/native/closeout-runners";
|
|
6
|
-
import { CloseoutValidationError
|
|
7
|
+
import { CloseoutValidationError } from "@rig/runtime/control-plane/native/in-process-closeout";
|
|
7
8
|
import { projectRunFromSession } from "@rig/runtime/control-plane/run-session-projection";
|
|
8
9
|
import { localRunChanges } from "@rig/runtime/control-plane/run-discovery-stream";
|
|
9
10
|
import { updateRunTaskSourceLifecycle } from "@rig/runtime/control-plane/tasks/source-lifecycle";
|
|
@@ -11,12 +12,30 @@ import { resolveOwnerNamespaceKey } from "@rig/runtime/control-plane/remote-conf
|
|
|
11
12
|
import { resolveRigIdentity } from "@rig/runtime/control-plane/identity";
|
|
12
13
|
import { connectWorkerProjection, createRegistryClient } from "@rig/relay-registry";
|
|
13
14
|
import { coerceRegistryStatus } from "@rig/relay-registry/schema";
|
|
15
|
+
import { bootDefaultKernelIntoProcess } from "@rig/kernel/boot-default";
|
|
14
16
|
|
|
15
17
|
// packages/run-worker/src/journal.ts
|
|
18
|
+
import { createJournalSessionProvider } from "@rig/kernel/journal-session-provider";
|
|
16
19
|
import { RunSessionJournal } from "@rig/runtime/control-plane/run-session-writer";
|
|
17
20
|
async function createRunJournal(sessionManager, runId) {
|
|
18
21
|
try {
|
|
19
|
-
|
|
22
|
+
const journal = new RunSessionJournal(sessionManager, runId);
|
|
23
|
+
const kernel = createJournalSessionProvider({
|
|
24
|
+
runId,
|
|
25
|
+
store: {
|
|
26
|
+
appendCustomEntry: (customType, data) => sessionManager.appendCustomEntry(customType, data),
|
|
27
|
+
getEntries: () => sessionManager.getEntries?.() ?? sessionManager.getBranch?.() ?? []
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
return {
|
|
31
|
+
kernel,
|
|
32
|
+
appendStatus: journal.appendStatus.bind(journal),
|
|
33
|
+
appendTimeline: journal.appendTimeline.bind(journal),
|
|
34
|
+
appendCloseoutPhase: journal.appendCloseoutPhase.bind(journal),
|
|
35
|
+
appendApprovalResolved: journal.appendApprovalResolved.bind(journal),
|
|
36
|
+
appendInputResolved: journal.appendInputResolved.bind(journal),
|
|
37
|
+
appendStall: journal.appendStall.bind(journal)
|
|
38
|
+
};
|
|
20
39
|
} catch (error) {
|
|
21
40
|
console.warn(`[rig-run] RunSessionJournal unavailable; run-state arming deferred: ${error instanceof Error ? error.message : String(error)}`);
|
|
22
41
|
return null;
|
|
@@ -111,7 +130,32 @@ function rigRelayUrl() {
|
|
|
111
130
|
}
|
|
112
131
|
|
|
113
132
|
// packages/run-worker/src/autohost.ts
|
|
133
|
+
var RIG_PANELS_CUSTOM_MESSAGE_TYPE = "rig-panels";
|
|
134
|
+
var RIG_RUN_STOP_PANEL_ACTION = "rig-run:stop";
|
|
135
|
+
function syntheticRegistryOwner(namespaceKey) {
|
|
136
|
+
const githubUserId = namespaceKey.startsWith("gh:") ? namespaceKey.slice(3) : namespaceKey;
|
|
137
|
+
return {
|
|
138
|
+
githubUserId: githubUserId || "anonymous",
|
|
139
|
+
login: "anonymous",
|
|
140
|
+
namespaceKey
|
|
141
|
+
};
|
|
142
|
+
}
|
|
114
143
|
var REGISTRY_PROJECTION_TIMELINE_LIMIT = 100;
|
|
144
|
+
async function reflectStoppedRunTaskSource(input) {
|
|
145
|
+
const taskId = input.taskId?.trim();
|
|
146
|
+
if (!taskId)
|
|
147
|
+
return false;
|
|
148
|
+
const reason = input.reason?.trim();
|
|
149
|
+
await (input.updateLifecycle ?? updateRunTaskSourceLifecycle)(input.projectRoot, {
|
|
150
|
+
runId: input.runId,
|
|
151
|
+
taskId,
|
|
152
|
+
sourceTask: input.sourceTask,
|
|
153
|
+
worktreePath: input.worktreePath,
|
|
154
|
+
logRoot: input.logRoot,
|
|
155
|
+
sessionPath: input.sessionPath
|
|
156
|
+
}, "cancelled", reason ? `Rig stopped by operator: ${reason}` : "Rig stopped by operator.");
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
115
159
|
function registryRunProjection(input) {
|
|
116
160
|
const timeline = input.timeline ?? latestTimelineEntriesFromCustomEntries(input.entries, REGISTRY_PROJECTION_TIMELINE_LIMIT);
|
|
117
161
|
return {
|
|
@@ -185,7 +229,6 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
185
229
|
if (!envRunId)
|
|
186
230
|
throw new Error("RIG_RUN_ID is required when RIG_RUN_PROCESS=1");
|
|
187
231
|
const runId = sessionIdFromSessionFile(ctx.sessionManager.getSessionFile()) ?? envRunId;
|
|
188
|
-
console.log(`[rig-run] session_start hasUI=${ctx.hasUI ? "true" : "false"}`);
|
|
189
232
|
if (!ctx.hasUI)
|
|
190
233
|
return null;
|
|
191
234
|
const collab = ctx.collab;
|
|
@@ -194,6 +237,10 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
194
237
|
throw new Error("OMP collab host facade is unavailable for Rig run process.");
|
|
195
238
|
const identity = resolveRigIdentity(ctx);
|
|
196
239
|
const journal = await createRunJournal(ctx.sessionManager, runId);
|
|
240
|
+
await bootDefaultKernelIntoProcess({
|
|
241
|
+
entrypoint: "run-worker",
|
|
242
|
+
...journal ? { journal: journal.kernel } : {}
|
|
243
|
+
});
|
|
197
244
|
const projectRoot = process.env.PROJECT_RIG_ROOT ?? process.cwd();
|
|
198
245
|
let runProjection = projectRunFromSession(customEntries(ctx.sessionManager.getBranch()), runId);
|
|
199
246
|
const taskIdAtStart = process.env.RIG_TASK_ID?.trim() || runProjection.record.taskId;
|
|
@@ -212,8 +259,10 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
212
259
|
let runRegistryRoomId = null;
|
|
213
260
|
let workerProjectionConnection = null;
|
|
214
261
|
let workerProjectionFiber = null;
|
|
215
|
-
const runRegistryNamespace = identity?.owner?.namespaceKey ?? resolveOwnerNamespaceKey(rigProjectRoot()) ??
|
|
216
|
-
const
|
|
262
|
+
const runRegistryNamespace = identity?.owner?.namespaceKey ?? resolveOwnerNamespaceKey(rigProjectRoot()) ?? "anonymous";
|
|
263
|
+
const runRegistryOwner = identity?.owner ?? syntheticRegistryOwner(runRegistryNamespace);
|
|
264
|
+
const runRegistryRepo = identity?.selectedRepo ?? "";
|
|
265
|
+
const runRegistry = createRegistryClient({ baseUrl: registryBaseUrl(), namespaceKey: runRegistryNamespace });
|
|
217
266
|
let runRegistryLinks = {};
|
|
218
267
|
const processedControlEntryIds = new Set((ctx.sessionManager.getEntries?.() ?? []).map((entry) => entry && typeof entry === "object" && typeof entry.id === "string" ? entry.id : null).filter((id) => id !== null));
|
|
219
268
|
const processedControlEntryObjects = new WeakSet;
|
|
@@ -251,6 +300,38 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
251
300
|
timeline
|
|
252
301
|
});
|
|
253
302
|
};
|
|
303
|
+
let lastRigPanelsSnapshotJson = "";
|
|
304
|
+
const publishRigPanelsSnapshot = () => {
|
|
305
|
+
const appendCustomMessageEntry = ctx.sessionManager.appendCustomMessageEntry?.bind(ctx.sessionManager);
|
|
306
|
+
if (!appendCustomMessageEntry)
|
|
307
|
+
return;
|
|
308
|
+
const { folded } = currentProjectionParts();
|
|
309
|
+
const status = folded.status ?? "unknown";
|
|
310
|
+
const taskId = folded.record.taskId ?? taskIdAtStart;
|
|
311
|
+
const operatorActive = status === "running" || status === "validating" || status === "closing-out" || status === "needs-attention";
|
|
312
|
+
const frameBody = {
|
|
313
|
+
kind: "snapshot",
|
|
314
|
+
activePanel: "supervisor",
|
|
315
|
+
registrations: [{ id: "supervisor", title: "Supervisor" }],
|
|
316
|
+
supervisor: {
|
|
317
|
+
status,
|
|
318
|
+
currentTask: taskId ? { id: taskId, title: runDisplayTitle } : null,
|
|
319
|
+
processed: folded.closeoutPhases.length,
|
|
320
|
+
succeeded: folded.closeoutPhases.filter((phase) => phase.outcome === "completed").length,
|
|
321
|
+
failed: folded.closeoutPhases.filter((phase) => phase.outcome === "failed").length,
|
|
322
|
+
skipped: 0,
|
|
323
|
+
plannedOrder: taskId ? [{ id: taskId, title: runDisplayTitle, status }] : [],
|
|
324
|
+
idleReason: operatorActive ? null : status,
|
|
325
|
+
stopActionId: operatorActive ? RIG_RUN_STOP_PANEL_ACTION : null,
|
|
326
|
+
closures: []
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
const serialized = JSON.stringify(frameBody);
|
|
330
|
+
if (serialized === lastRigPanelsSnapshotJson)
|
|
331
|
+
return;
|
|
332
|
+
lastRigPanelsSnapshotJson = serialized;
|
|
333
|
+
appendCustomMessageEntry(RIG_PANELS_CUSTOM_MESSAGE_TYPE, "", false, { ...frameBody, updatedAt: new Date().toISOString() }, "agent");
|
|
334
|
+
};
|
|
254
335
|
const pushWorkerProjection = (links = runRegistryLinks) => {
|
|
255
336
|
if (!workerProjectionConnection)
|
|
256
337
|
return;
|
|
@@ -258,6 +339,7 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
258
339
|
};
|
|
259
340
|
const publishRunProjection = async (status) => {
|
|
260
341
|
const projection = buildCurrentRegistryProjection();
|
|
342
|
+
publishRigPanelsSnapshot();
|
|
261
343
|
if (workerProjectionConnection)
|
|
262
344
|
workerProjectionConnection.push(projection);
|
|
263
345
|
if (runRegistry && runRegistryRoomId) {
|
|
@@ -360,13 +442,23 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
360
442
|
};
|
|
361
443
|
process.once("uncaughtException", publishFatalTerminal);
|
|
362
444
|
process.once("unhandledRejection", publishFatalTerminal);
|
|
445
|
+
const handlePanelAction = async (input) => {
|
|
446
|
+
if (input.actionId !== RIG_RUN_STOP_PANEL_ACTION && input.actionId !== "stop-supervisor") {
|
|
447
|
+
throw new Error(`Unsupported Rig panel action: ${input.actionId}`);
|
|
448
|
+
}
|
|
449
|
+
pendingStopReason = `operator ${input.from.name} requested stop`;
|
|
450
|
+
journal?.appendTimeline({ type: "interrupted", stage: "panel-action", status: "running", detail: pendingStopReason });
|
|
451
|
+
ctx.abort();
|
|
452
|
+
await publishRunProjection("running");
|
|
453
|
+
};
|
|
363
454
|
const startRunCollabHost = async () => {
|
|
364
455
|
try {
|
|
365
456
|
const projection = await startHost.call(collab, {
|
|
366
457
|
title: runDisplayTitle,
|
|
367
458
|
...identity?.owner ? { owner: identity.owner } : {},
|
|
368
459
|
...identity?.selectedRepo ? { selectedRepo: identity.selectedRepo } : {},
|
|
369
|
-
relayUrl: rigRelayUrl()
|
|
460
|
+
relayUrl: rigRelayUrl(),
|
|
461
|
+
onPanelAction: handlePanelAction
|
|
370
462
|
});
|
|
371
463
|
runRegistryLinks = { joinLink: projection.joinLink, webLink: projection.webLink, relayUrl: projection.relayUrl ?? rigRelayUrl() };
|
|
372
464
|
const timeline = {
|
|
@@ -379,14 +471,15 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
379
471
|
journal?.appendTimeline(timeline);
|
|
380
472
|
console.log(`[rig-run] collab-host-started joinLink=${projection.joinLink || "(empty)"} relayUrl=${projection.relayUrl || "(empty)"}`);
|
|
381
473
|
ctx.ui.notify("Rig run collab host started.", "info");
|
|
382
|
-
|
|
474
|
+
publishRigPanelsSnapshot();
|
|
475
|
+
if (runRegistry) {
|
|
383
476
|
try {
|
|
384
477
|
runRegistryRoomId = projection.sessionId;
|
|
385
478
|
const initialProjection = buildCurrentRegistryProjection();
|
|
386
479
|
await runRegistry.registerRoom({
|
|
387
480
|
roomId: projection.sessionId,
|
|
388
|
-
owner:
|
|
389
|
-
repo:
|
|
481
|
+
owner: runRegistryOwner,
|
|
482
|
+
repo: runRegistryRepo,
|
|
390
483
|
title: runDisplayTitle,
|
|
391
484
|
status: "running",
|
|
392
485
|
joinLink: projection.joinLink ?? "",
|
|
@@ -414,9 +507,6 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
414
507
|
console.error(`[rig-run] registry-register-failed ${error instanceof Error ? error.message : String(error)}`);
|
|
415
508
|
ctx.ui.notify("Rig run could not register to the discovery registry; it may not appear in Runs.", "warning");
|
|
416
509
|
}
|
|
417
|
-
} else {
|
|
418
|
-
console.error(`[rig-run] registry-skip namespace=${runRegistryNamespace ? "set" : "MISSING"}`);
|
|
419
|
-
ctx.ui.notify("Rig run NOT registered (registry namespace missing) \u2014 it won't appear in Runs.", "warning");
|
|
420
510
|
}
|
|
421
511
|
} catch (error) {
|
|
422
512
|
console.error(`[rig-run] collab-host-start-failed ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -463,6 +553,26 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
463
553
|
closeoutStarted = true;
|
|
464
554
|
journal?.appendTimeline({ type: "interrupted", stage: "stopped", status: "stopped", detail: reason });
|
|
465
555
|
journal?.appendStatus("stopped", { actor: OPERATOR_ACTOR, reason, force: true });
|
|
556
|
+
if (taskIdAtStart) {
|
|
557
|
+
journal?.appendTimeline({ type: "stage", stage: "Task-source", status: "running", detail: "reflecting operator stop to task source" });
|
|
558
|
+
try {
|
|
559
|
+
await reflectStoppedRunTaskSource({
|
|
560
|
+
projectRoot,
|
|
561
|
+
runId,
|
|
562
|
+
taskId: taskIdAtStart,
|
|
563
|
+
sourceTask: runProjection.record.sourceTask,
|
|
564
|
+
worktreePath: process.cwd(),
|
|
565
|
+
logRoot: runProjection.record.logRoot ?? null,
|
|
566
|
+
sessionPath: runProjection.record.sessionPath ?? null,
|
|
567
|
+
reason
|
|
568
|
+
});
|
|
569
|
+
journal?.appendTimeline({ type: "stage", stage: "Task-source", status: "completed", detail: "reflected operator stop" });
|
|
570
|
+
} catch (error) {
|
|
571
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
572
|
+
journal?.appendTimeline({ type: "stage", stage: "Task-source", status: "failed", detail });
|
|
573
|
+
console.error(`[rig-run] stopped-reflection-failed ${detail}`);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
466
576
|
await publishRunProjection("stopped");
|
|
467
577
|
stopRunStallMonitor();
|
|
468
578
|
stopRunRegistry({ removeRoom: false });
|
|
@@ -506,7 +616,7 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
506
616
|
const { command, gitCommand } = createEnvCloseoutRunners(process.env);
|
|
507
617
|
let closeoutStatusAdvanced = false;
|
|
508
618
|
try {
|
|
509
|
-
await
|
|
619
|
+
await runStagedCloseout({
|
|
510
620
|
projectRoot,
|
|
511
621
|
runId,
|
|
512
622
|
taskId,
|
package/dist/src/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/run-worker/src/autohost.ts
|
|
3
|
+
import { runStagedCloseout } from "@rig/bundle-default-lifecycle/staged-closeout";
|
|
3
4
|
import { latestTimelineEntriesFromCustomEntries, parseInboxResolutionSentinel, parsePauseSentinel, parseResumeSentinel, parseStopSentinel, sessionIdFromSessionFile } from "@rig/contracts";
|
|
4
5
|
import { Duration, Effect, Fiber, Stream } from "effect";
|
|
5
6
|
import { createEnvCloseoutRunners } from "@rig/runtime/control-plane/native/closeout-runners";
|
|
6
|
-
import { CloseoutValidationError
|
|
7
|
+
import { CloseoutValidationError } from "@rig/runtime/control-plane/native/in-process-closeout";
|
|
7
8
|
import { projectRunFromSession } from "@rig/runtime/control-plane/run-session-projection";
|
|
8
9
|
import { localRunChanges } from "@rig/runtime/control-plane/run-discovery-stream";
|
|
9
10
|
import { updateRunTaskSourceLifecycle } from "@rig/runtime/control-plane/tasks/source-lifecycle";
|
|
@@ -11,12 +12,30 @@ import { resolveOwnerNamespaceKey } from "@rig/runtime/control-plane/remote-conf
|
|
|
11
12
|
import { resolveRigIdentity } from "@rig/runtime/control-plane/identity";
|
|
12
13
|
import { connectWorkerProjection, createRegistryClient } from "@rig/relay-registry";
|
|
13
14
|
import { coerceRegistryStatus } from "@rig/relay-registry/schema";
|
|
15
|
+
import { bootDefaultKernelIntoProcess } from "@rig/kernel/boot-default";
|
|
14
16
|
|
|
15
17
|
// packages/run-worker/src/journal.ts
|
|
18
|
+
import { createJournalSessionProvider } from "@rig/kernel/journal-session-provider";
|
|
16
19
|
import { RunSessionJournal } from "@rig/runtime/control-plane/run-session-writer";
|
|
17
20
|
async function createRunJournal(sessionManager, runId) {
|
|
18
21
|
try {
|
|
19
|
-
|
|
22
|
+
const journal = new RunSessionJournal(sessionManager, runId);
|
|
23
|
+
const kernel = createJournalSessionProvider({
|
|
24
|
+
runId,
|
|
25
|
+
store: {
|
|
26
|
+
appendCustomEntry: (customType, data) => sessionManager.appendCustomEntry(customType, data),
|
|
27
|
+
getEntries: () => sessionManager.getEntries?.() ?? sessionManager.getBranch?.() ?? []
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
return {
|
|
31
|
+
kernel,
|
|
32
|
+
appendStatus: journal.appendStatus.bind(journal),
|
|
33
|
+
appendTimeline: journal.appendTimeline.bind(journal),
|
|
34
|
+
appendCloseoutPhase: journal.appendCloseoutPhase.bind(journal),
|
|
35
|
+
appendApprovalResolved: journal.appendApprovalResolved.bind(journal),
|
|
36
|
+
appendInputResolved: journal.appendInputResolved.bind(journal),
|
|
37
|
+
appendStall: journal.appendStall.bind(journal)
|
|
38
|
+
};
|
|
20
39
|
} catch (error) {
|
|
21
40
|
console.warn(`[rig-run] RunSessionJournal unavailable; run-state arming deferred: ${error instanceof Error ? error.message : String(error)}`);
|
|
22
41
|
return null;
|
|
@@ -111,7 +130,32 @@ function rigRelayUrl() {
|
|
|
111
130
|
}
|
|
112
131
|
|
|
113
132
|
// packages/run-worker/src/autohost.ts
|
|
133
|
+
var RIG_PANELS_CUSTOM_MESSAGE_TYPE = "rig-panels";
|
|
134
|
+
var RIG_RUN_STOP_PANEL_ACTION = "rig-run:stop";
|
|
135
|
+
function syntheticRegistryOwner(namespaceKey) {
|
|
136
|
+
const githubUserId = namespaceKey.startsWith("gh:") ? namespaceKey.slice(3) : namespaceKey;
|
|
137
|
+
return {
|
|
138
|
+
githubUserId: githubUserId || "anonymous",
|
|
139
|
+
login: "anonymous",
|
|
140
|
+
namespaceKey
|
|
141
|
+
};
|
|
142
|
+
}
|
|
114
143
|
var REGISTRY_PROJECTION_TIMELINE_LIMIT = 100;
|
|
144
|
+
async function reflectStoppedRunTaskSource(input) {
|
|
145
|
+
const taskId = input.taskId?.trim();
|
|
146
|
+
if (!taskId)
|
|
147
|
+
return false;
|
|
148
|
+
const reason = input.reason?.trim();
|
|
149
|
+
await (input.updateLifecycle ?? updateRunTaskSourceLifecycle)(input.projectRoot, {
|
|
150
|
+
runId: input.runId,
|
|
151
|
+
taskId,
|
|
152
|
+
sourceTask: input.sourceTask,
|
|
153
|
+
worktreePath: input.worktreePath,
|
|
154
|
+
logRoot: input.logRoot,
|
|
155
|
+
sessionPath: input.sessionPath
|
|
156
|
+
}, "cancelled", reason ? `Rig stopped by operator: ${reason}` : "Rig stopped by operator.");
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
115
159
|
function registryRunProjection(input) {
|
|
116
160
|
const timeline = input.timeline ?? latestTimelineEntriesFromCustomEntries(input.entries, REGISTRY_PROJECTION_TIMELINE_LIMIT);
|
|
117
161
|
return {
|
|
@@ -185,7 +229,6 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
185
229
|
if (!envRunId)
|
|
186
230
|
throw new Error("RIG_RUN_ID is required when RIG_RUN_PROCESS=1");
|
|
187
231
|
const runId = sessionIdFromSessionFile(ctx.sessionManager.getSessionFile()) ?? envRunId;
|
|
188
|
-
console.log(`[rig-run] session_start hasUI=${ctx.hasUI ? "true" : "false"}`);
|
|
189
232
|
if (!ctx.hasUI)
|
|
190
233
|
return null;
|
|
191
234
|
const collab = ctx.collab;
|
|
@@ -194,6 +237,10 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
194
237
|
throw new Error("OMP collab host facade is unavailable for Rig run process.");
|
|
195
238
|
const identity = resolveRigIdentity(ctx);
|
|
196
239
|
const journal = await createRunJournal(ctx.sessionManager, runId);
|
|
240
|
+
await bootDefaultKernelIntoProcess({
|
|
241
|
+
entrypoint: "run-worker",
|
|
242
|
+
...journal ? { journal: journal.kernel } : {}
|
|
243
|
+
});
|
|
197
244
|
const projectRoot = process.env.PROJECT_RIG_ROOT ?? process.cwd();
|
|
198
245
|
let runProjection = projectRunFromSession(customEntries(ctx.sessionManager.getBranch()), runId);
|
|
199
246
|
const taskIdAtStart = process.env.RIG_TASK_ID?.trim() || runProjection.record.taskId;
|
|
@@ -212,8 +259,10 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
212
259
|
let runRegistryRoomId = null;
|
|
213
260
|
let workerProjectionConnection = null;
|
|
214
261
|
let workerProjectionFiber = null;
|
|
215
|
-
const runRegistryNamespace = identity?.owner?.namespaceKey ?? resolveOwnerNamespaceKey(rigProjectRoot()) ??
|
|
216
|
-
const
|
|
262
|
+
const runRegistryNamespace = identity?.owner?.namespaceKey ?? resolveOwnerNamespaceKey(rigProjectRoot()) ?? "anonymous";
|
|
263
|
+
const runRegistryOwner = identity?.owner ?? syntheticRegistryOwner(runRegistryNamespace);
|
|
264
|
+
const runRegistryRepo = identity?.selectedRepo ?? "";
|
|
265
|
+
const runRegistry = createRegistryClient({ baseUrl: registryBaseUrl(), namespaceKey: runRegistryNamespace });
|
|
217
266
|
let runRegistryLinks = {};
|
|
218
267
|
const processedControlEntryIds = new Set((ctx.sessionManager.getEntries?.() ?? []).map((entry) => entry && typeof entry === "object" && typeof entry.id === "string" ? entry.id : null).filter((id) => id !== null));
|
|
219
268
|
const processedControlEntryObjects = new WeakSet;
|
|
@@ -251,6 +300,38 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
251
300
|
timeline
|
|
252
301
|
});
|
|
253
302
|
};
|
|
303
|
+
let lastRigPanelsSnapshotJson = "";
|
|
304
|
+
const publishRigPanelsSnapshot = () => {
|
|
305
|
+
const appendCustomMessageEntry = ctx.sessionManager.appendCustomMessageEntry?.bind(ctx.sessionManager);
|
|
306
|
+
if (!appendCustomMessageEntry)
|
|
307
|
+
return;
|
|
308
|
+
const { folded } = currentProjectionParts();
|
|
309
|
+
const status = folded.status ?? "unknown";
|
|
310
|
+
const taskId = folded.record.taskId ?? taskIdAtStart;
|
|
311
|
+
const operatorActive = status === "running" || status === "validating" || status === "closing-out" || status === "needs-attention";
|
|
312
|
+
const frameBody = {
|
|
313
|
+
kind: "snapshot",
|
|
314
|
+
activePanel: "supervisor",
|
|
315
|
+
registrations: [{ id: "supervisor", title: "Supervisor" }],
|
|
316
|
+
supervisor: {
|
|
317
|
+
status,
|
|
318
|
+
currentTask: taskId ? { id: taskId, title: runDisplayTitle } : null,
|
|
319
|
+
processed: folded.closeoutPhases.length,
|
|
320
|
+
succeeded: folded.closeoutPhases.filter((phase) => phase.outcome === "completed").length,
|
|
321
|
+
failed: folded.closeoutPhases.filter((phase) => phase.outcome === "failed").length,
|
|
322
|
+
skipped: 0,
|
|
323
|
+
plannedOrder: taskId ? [{ id: taskId, title: runDisplayTitle, status }] : [],
|
|
324
|
+
idleReason: operatorActive ? null : status,
|
|
325
|
+
stopActionId: operatorActive ? RIG_RUN_STOP_PANEL_ACTION : null,
|
|
326
|
+
closures: []
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
const serialized = JSON.stringify(frameBody);
|
|
330
|
+
if (serialized === lastRigPanelsSnapshotJson)
|
|
331
|
+
return;
|
|
332
|
+
lastRigPanelsSnapshotJson = serialized;
|
|
333
|
+
appendCustomMessageEntry(RIG_PANELS_CUSTOM_MESSAGE_TYPE, "", false, { ...frameBody, updatedAt: new Date().toISOString() }, "agent");
|
|
334
|
+
};
|
|
254
335
|
const pushWorkerProjection = (links = runRegistryLinks) => {
|
|
255
336
|
if (!workerProjectionConnection)
|
|
256
337
|
return;
|
|
@@ -258,6 +339,7 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
258
339
|
};
|
|
259
340
|
const publishRunProjection = async (status) => {
|
|
260
341
|
const projection = buildCurrentRegistryProjection();
|
|
342
|
+
publishRigPanelsSnapshot();
|
|
261
343
|
if (workerProjectionConnection)
|
|
262
344
|
workerProjectionConnection.push(projection);
|
|
263
345
|
if (runRegistry && runRegistryRoomId) {
|
|
@@ -360,13 +442,23 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
360
442
|
};
|
|
361
443
|
process.once("uncaughtException", publishFatalTerminal);
|
|
362
444
|
process.once("unhandledRejection", publishFatalTerminal);
|
|
445
|
+
const handlePanelAction = async (input) => {
|
|
446
|
+
if (input.actionId !== RIG_RUN_STOP_PANEL_ACTION && input.actionId !== "stop-supervisor") {
|
|
447
|
+
throw new Error(`Unsupported Rig panel action: ${input.actionId}`);
|
|
448
|
+
}
|
|
449
|
+
pendingStopReason = `operator ${input.from.name} requested stop`;
|
|
450
|
+
journal?.appendTimeline({ type: "interrupted", stage: "panel-action", status: "running", detail: pendingStopReason });
|
|
451
|
+
ctx.abort();
|
|
452
|
+
await publishRunProjection("running");
|
|
453
|
+
};
|
|
363
454
|
const startRunCollabHost = async () => {
|
|
364
455
|
try {
|
|
365
456
|
const projection = await startHost.call(collab, {
|
|
366
457
|
title: runDisplayTitle,
|
|
367
458
|
...identity?.owner ? { owner: identity.owner } : {},
|
|
368
459
|
...identity?.selectedRepo ? { selectedRepo: identity.selectedRepo } : {},
|
|
369
|
-
relayUrl: rigRelayUrl()
|
|
460
|
+
relayUrl: rigRelayUrl(),
|
|
461
|
+
onPanelAction: handlePanelAction
|
|
370
462
|
});
|
|
371
463
|
runRegistryLinks = { joinLink: projection.joinLink, webLink: projection.webLink, relayUrl: projection.relayUrl ?? rigRelayUrl() };
|
|
372
464
|
const timeline = {
|
|
@@ -379,14 +471,15 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
379
471
|
journal?.appendTimeline(timeline);
|
|
380
472
|
console.log(`[rig-run] collab-host-started joinLink=${projection.joinLink || "(empty)"} relayUrl=${projection.relayUrl || "(empty)"}`);
|
|
381
473
|
ctx.ui.notify("Rig run collab host started.", "info");
|
|
382
|
-
|
|
474
|
+
publishRigPanelsSnapshot();
|
|
475
|
+
if (runRegistry) {
|
|
383
476
|
try {
|
|
384
477
|
runRegistryRoomId = projection.sessionId;
|
|
385
478
|
const initialProjection = buildCurrentRegistryProjection();
|
|
386
479
|
await runRegistry.registerRoom({
|
|
387
480
|
roomId: projection.sessionId,
|
|
388
|
-
owner:
|
|
389
|
-
repo:
|
|
481
|
+
owner: runRegistryOwner,
|
|
482
|
+
repo: runRegistryRepo,
|
|
390
483
|
title: runDisplayTitle,
|
|
391
484
|
status: "running",
|
|
392
485
|
joinLink: projection.joinLink ?? "",
|
|
@@ -414,9 +507,6 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
414
507
|
console.error(`[rig-run] registry-register-failed ${error instanceof Error ? error.message : String(error)}`);
|
|
415
508
|
ctx.ui.notify("Rig run could not register to the discovery registry; it may not appear in Runs.", "warning");
|
|
416
509
|
}
|
|
417
|
-
} else {
|
|
418
|
-
console.error(`[rig-run] registry-skip namespace=${runRegistryNamespace ? "set" : "MISSING"}`);
|
|
419
|
-
ctx.ui.notify("Rig run NOT registered (registry namespace missing) \u2014 it won't appear in Runs.", "warning");
|
|
420
510
|
}
|
|
421
511
|
} catch (error) {
|
|
422
512
|
console.error(`[rig-run] collab-host-start-failed ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -463,6 +553,26 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
463
553
|
closeoutStarted = true;
|
|
464
554
|
journal?.appendTimeline({ type: "interrupted", stage: "stopped", status: "stopped", detail: reason });
|
|
465
555
|
journal?.appendStatus("stopped", { actor: OPERATOR_ACTOR, reason, force: true });
|
|
556
|
+
if (taskIdAtStart) {
|
|
557
|
+
journal?.appendTimeline({ type: "stage", stage: "Task-source", status: "running", detail: "reflecting operator stop to task source" });
|
|
558
|
+
try {
|
|
559
|
+
await reflectStoppedRunTaskSource({
|
|
560
|
+
projectRoot,
|
|
561
|
+
runId,
|
|
562
|
+
taskId: taskIdAtStart,
|
|
563
|
+
sourceTask: runProjection.record.sourceTask,
|
|
564
|
+
worktreePath: process.cwd(),
|
|
565
|
+
logRoot: runProjection.record.logRoot ?? null,
|
|
566
|
+
sessionPath: runProjection.record.sessionPath ?? null,
|
|
567
|
+
reason
|
|
568
|
+
});
|
|
569
|
+
journal?.appendTimeline({ type: "stage", stage: "Task-source", status: "completed", detail: "reflected operator stop" });
|
|
570
|
+
} catch (error) {
|
|
571
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
572
|
+
journal?.appendTimeline({ type: "stage", stage: "Task-source", status: "failed", detail });
|
|
573
|
+
console.error(`[rig-run] stopped-reflection-failed ${detail}`);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
466
576
|
await publishRunProjection("stopped");
|
|
467
577
|
stopRunStallMonitor();
|
|
468
578
|
stopRunRegistry({ removeRoom: false });
|
|
@@ -506,7 +616,7 @@ async function maybeStartRunProcessAutohost(api, ctx) {
|
|
|
506
616
|
const { command, gitCommand } = createEnvCloseoutRunners(process.env);
|
|
507
617
|
let closeoutStatusAdvanced = false;
|
|
508
618
|
try {
|
|
509
|
-
await
|
|
619
|
+
await runStagedCloseout({
|
|
510
620
|
projectRoot,
|
|
511
621
|
runId,
|
|
512
622
|
taskId,
|
|
@@ -611,6 +721,7 @@ export {
|
|
|
611
721
|
timestampMs,
|
|
612
722
|
startRunProcessStallMonitor,
|
|
613
723
|
registryRunProjection,
|
|
724
|
+
reflectStoppedRunTaskSource,
|
|
614
725
|
maybeStartSpikeAutohost,
|
|
615
726
|
maybeStartRunProcessAutohost,
|
|
616
727
|
dispatchRunNotifications,
|
package/dist/src/journal.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@oh-my-pi/pi-coding-agent";
|
|
2
2
|
import type { ApprovalDecision, RunActor, RunCloseoutPhase, RunCloseoutPhaseOutcome, RunStatus } from "@rig/contracts";
|
|
3
|
+
import { type JournalSessionProvider } from "@rig/kernel/journal-session-provider";
|
|
3
4
|
export type RunJournal = {
|
|
5
|
+
readonly kernel: JournalSessionProvider;
|
|
4
6
|
appendStatus(to: RunStatus, opts?: {
|
|
5
7
|
reason?: string | null;
|
|
6
8
|
actor?: RunActor;
|
package/dist/src/journal.js
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/run-worker/src/journal.ts
|
|
3
|
+
import { createJournalSessionProvider } from "@rig/kernel/journal-session-provider";
|
|
3
4
|
import { RunSessionJournal } from "@rig/runtime/control-plane/run-session-writer";
|
|
4
5
|
async function createRunJournal(sessionManager, runId) {
|
|
5
6
|
try {
|
|
6
|
-
|
|
7
|
+
const journal = new RunSessionJournal(sessionManager, runId);
|
|
8
|
+
const kernel = createJournalSessionProvider({
|
|
9
|
+
runId,
|
|
10
|
+
store: {
|
|
11
|
+
appendCustomEntry: (customType, data) => sessionManager.appendCustomEntry(customType, data),
|
|
12
|
+
getEntries: () => sessionManager.getEntries?.() ?? sessionManager.getBranch?.() ?? []
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
return {
|
|
16
|
+
kernel,
|
|
17
|
+
appendStatus: journal.appendStatus.bind(journal),
|
|
18
|
+
appendTimeline: journal.appendTimeline.bind(journal),
|
|
19
|
+
appendCloseoutPhase: journal.appendCloseoutPhase.bind(journal),
|
|
20
|
+
appendApprovalResolved: journal.appendApprovalResolved.bind(journal),
|
|
21
|
+
appendInputResolved: journal.appendInputResolved.bind(journal),
|
|
22
|
+
appendStall: journal.appendStall.bind(journal)
|
|
23
|
+
};
|
|
7
24
|
} catch (error) {
|
|
8
25
|
console.warn(`[rig-run] RunSessionJournal unavailable; run-state arming deferred: ${error instanceof Error ? error.message : String(error)}`);
|
|
9
26
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-rig/run-worker",
|
|
3
|
-
"version": "0.0.6-alpha.
|
|
3
|
+
"version": "0.0.6-alpha.133",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Rig package",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -26,9 +26,11 @@
|
|
|
26
26
|
]
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@rig/
|
|
30
|
-
"@rig/
|
|
31
|
-
"@rig/
|
|
29
|
+
"@rig/bundle-default-lifecycle": "npm:@h-rig/bundle-default-lifecycle@0.0.6-alpha.133",
|
|
30
|
+
"@rig/contracts": "npm:@h-rig/contracts@0.0.6-alpha.133",
|
|
31
|
+
"@rig/kernel": "npm:@h-rig/kernel@0.0.6-alpha.133",
|
|
32
|
+
"@rig/runtime": "npm:@h-rig/runtime@0.0.6-alpha.133",
|
|
33
|
+
"@rig/relay-registry": "npm:@h-rig/relay-registry@0.0.6-alpha.133",
|
|
32
34
|
"@oh-my-pi/pi-coding-agent": "16.0.4",
|
|
33
35
|
"effect": "4.0.0-beta.78"
|
|
34
36
|
}
|