@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.
Files changed (47) hide show
  1. package/dist/src/autohost.d.ts +8 -10
  2. package/dist/src/autohost.js +683 -95
  3. package/dist/src/constants.d.ts +0 -1
  4. package/dist/src/constants.js +0 -2
  5. package/dist/src/extension.js +683 -95
  6. package/dist/src/host-kernel.d.ts +22 -0
  7. package/dist/src/host-kernel.js +78 -0
  8. package/dist/src/host.d.ts +2 -0
  9. package/dist/src/host.js +419 -0
  10. package/dist/src/index.d.ts +0 -6
  11. package/dist/src/index.js +1913 -133
  12. package/dist/src/local-run-changes.d.ts +3 -0
  13. package/dist/src/local-run-changes.js +65 -0
  14. package/dist/src/notifications.js +13 -5
  15. package/dist/src/notify-cap.d.ts +11 -0
  16. package/dist/src/notify-cap.js +13 -0
  17. package/dist/src/panel-plugin.js +3 -7
  18. package/dist/src/plugin.d.ts +0 -11
  19. package/dist/src/plugin.js +1910 -101
  20. package/dist/src/{runs → read-model-backend}/control.d.ts +0 -1
  21. package/dist/src/{runs → read-model-backend}/control.js +361 -38
  22. package/dist/src/{runs → read-model-backend}/diagnostics.d.ts +0 -1
  23. package/dist/src/{runs → read-model-backend}/diagnostics.js +1 -3
  24. package/dist/src/{runs → read-model-backend}/guard.js +2 -3
  25. package/dist/src/{runs → read-model-backend}/inbox.js +366 -36
  26. package/dist/src/{runs → read-model-backend}/index.js +552 -223
  27. package/dist/src/{runs → read-model-backend}/inspect.d.ts +0 -1
  28. package/dist/src/{runs → read-model-backend}/inspect.js +350 -34
  29. package/dist/src/{runs → read-model-backend}/projection.d.ts +21 -7
  30. package/dist/src/{runs → read-model-backend}/projection.js +349 -31
  31. package/dist/src/{runs → read-model-backend}/run-status.d.ts +6 -3
  32. package/dist/src/{runs → read-model-backend}/run-status.js +53 -33
  33. package/dist/src/{runs → read-model-backend}/stats.d.ts +0 -1
  34. package/dist/src/{runs → read-model-backend}/stats.js +373 -58
  35. package/dist/src/read-model-service.d.ts +2 -0
  36. package/dist/src/read-model-service.js +1433 -0
  37. package/dist/src/session-journal.d.ts +60 -0
  38. package/dist/src/session-journal.js +471 -0
  39. package/dist/src/stall.d.ts +8 -3
  40. package/dist/src/stall.js +0 -1
  41. package/dist/src/utils.js +282 -3
  42. package/package.json +9 -12
  43. package/dist/src/journal.d.ts +0 -33
  44. package/dist/src/journal.js +0 -31
  45. /package/dist/src/{runs → read-model-backend}/guard.d.ts +0 -0
  46. /package/dist/src/{runs → read-model-backend}/inbox.d.ts +0 -0
  47. /package/dist/src/{runs → read-model-backend}/index.d.ts +0 -0
package/dist/src/utils.js CHANGED
@@ -1,7 +1,286 @@
1
1
  // @bun
2
2
  // packages/run-worker/src/utils.ts
3
- import { createWorkflowStatusChanged, RIG_WORKFLOW_STATUS_CHANGED } from "@rig/contracts";
4
- import { resolveRegistryBaseUrl, resolveRelayUrl } from "@rig/runtime/control-plane/remote-config";
3
+ import { RIG_WORKFLOW_STATUS_CHANGED as RIG_WORKFLOW_STATUS_CHANGED2 } from "@rig/contracts";
4
+
5
+ // packages/run-worker/src/session-journal.ts
6
+ import { Schema } from "effect";
7
+ import {
8
+ CUSTOM_TYPE_FOR,
9
+ RIG_CONTROL_SENTINEL_END,
10
+ RIG_INBOX_RESOLUTION_SENTINEL,
11
+ RIG_PAUSE_SENTINEL,
12
+ RIG_RESUME_SENTINEL,
13
+ RIG_STOP_SENTINEL,
14
+ RIG_STOP_SENTINEL_END,
15
+ RIG_WORKFLOW_STATUS_CHANGED,
16
+ RunJournalEvent,
17
+ TYPE_FOR_CUSTOM
18
+ } from "@rig/contracts";
19
+ var decodeRunJournalEvent = Schema.decodeUnknownSync(RunJournalEvent);
20
+ var RUN_STATUS_TRANSITIONS = {
21
+ created: ["queued", "preparing", "running", "failed", "stopped"],
22
+ queued: ["preparing", "running", "failed", "stopped"],
23
+ preparing: ["queued", "running", "needs-attention", "failed", "stopped"],
24
+ running: [
25
+ "queued",
26
+ "waiting-approval",
27
+ "waiting-user-input",
28
+ "paused",
29
+ "validating",
30
+ "reviewing",
31
+ "closing-out",
32
+ "needs-attention",
33
+ "completed",
34
+ "failed",
35
+ "stopped"
36
+ ],
37
+ "waiting-approval": ["running", "needs-attention", "failed", "stopped"],
38
+ "waiting-user-input": ["running", "needs-attention", "failed", "stopped"],
39
+ paused: ["running", "failed", "stopped"],
40
+ validating: ["running", "reviewing", "closing-out", "needs-attention", "completed", "failed", "stopped"],
41
+ reviewing: ["running", "validating", "closing-out", "needs-attention", "completed", "failed", "stopped"],
42
+ "closing-out": ["running", "needs-attention", "completed", "failed", "stopped"],
43
+ "needs-attention": ["queued", "preparing", "running", "closing-out", "completed", "failed", "stopped"],
44
+ completed: [],
45
+ failed: ["queued", "preparing", "running", "closing-out"],
46
+ stopped: ["queued", "preparing", "running", "closing-out"]
47
+ };
48
+ var TERMINAL_RUN_STATUSES = ["completed", "failed", "stopped"];
49
+ function isTerminalRunStatus(status) {
50
+ return TERMINAL_RUN_STATUSES.includes(status);
51
+ }
52
+ function canTransitionRunStatus(from, to) {
53
+ if (from === null)
54
+ return true;
55
+ if (from === to)
56
+ return true;
57
+ return RUN_STATUS_TRANSITIONS[from].includes(to);
58
+ }
59
+ function assertRunStatusTransition(from, to) {
60
+ if (!canTransitionRunStatus(from, to)) {
61
+ throw new Error(`Illegal run status transition: ${from ?? "(none)"} -> ${to}. ` + `Allowed from ${from ?? "(none)"}: ${from ? RUN_STATUS_TRANSITIONS[from].join(", ") : "(any)"}.`);
62
+ }
63
+ }
64
+ function reduceRunJournal(events, runId = null) {
65
+ let record = {};
66
+ let status = null;
67
+ const statusHistory = [];
68
+ const pendingApprovals = new Map;
69
+ const resolvedApprovals = [];
70
+ const pendingUserInputs = new Map;
71
+ const resolvedUserInputs = [];
72
+ const closeoutPhases = [];
73
+ let resolvedPipeline = null;
74
+ const stageOutcomes = [];
75
+ const anomalies = [];
76
+ let steeringCount = 0;
77
+ let stallCount = 0;
78
+ let lastSeq = 0;
79
+ let lastEventAt = null;
80
+ const projectedRunId = runId ?? events[0]?.runId ?? null;
81
+ for (const event of events) {
82
+ lastSeq = event.seq;
83
+ lastEventAt = event.at;
84
+ switch (event.type) {
85
+ case "status-changed": {
86
+ if (!canTransitionRunStatus(status, event.to)) {
87
+ anomalies.push({ seq: event.seq, kind: "illegal-transition", detail: `${status ?? "(none)"} -> ${event.to}` });
88
+ }
89
+ statusHistory.push({ seq: event.seq, at: event.at, from: status, to: event.to, reason: event.reason ?? null });
90
+ const wasTerminal = status !== null && isTerminalRunStatus(status);
91
+ status = event.to;
92
+ record = { ...record, updatedAt: event.at };
93
+ if (isTerminalRunStatus(event.to) && !record.completedAt)
94
+ record = { ...record, completedAt: event.at };
95
+ if (!isTerminalRunStatus(event.to) && wasTerminal)
96
+ record = { ...record, completedAt: null };
97
+ if (event.to === "running" && !record.startedAt)
98
+ record = { ...record, startedAt: event.at };
99
+ break;
100
+ }
101
+ case "record-patch": {
102
+ const next = { ...record };
103
+ for (const [key, value] of Object.entries(event.patch)) {
104
+ if (value !== undefined)
105
+ next[key] = value;
106
+ }
107
+ next.updatedAt = event.patch.updatedAt ?? event.at;
108
+ record = next;
109
+ break;
110
+ }
111
+ case "approval-requested": {
112
+ pendingApprovals.set(event.requestId, {
113
+ requestId: event.requestId,
114
+ requestKind: event.requestKind,
115
+ actionId: event.actionId ?? null,
116
+ payload: event.payload,
117
+ requestedAt: event.at
118
+ });
119
+ break;
120
+ }
121
+ case "approval-resolved": {
122
+ const pending = pendingApprovals.get(event.requestId);
123
+ if (!pending) {
124
+ const alreadyResolved = resolvedApprovals.some((entry) => entry.requestId === event.requestId);
125
+ anomalies.push({ seq: event.seq, kind: alreadyResolved ? "duplicate-resolution" : "unknown-request", detail: `approval ${event.requestId}` });
126
+ break;
127
+ }
128
+ pendingApprovals.delete(event.requestId);
129
+ resolvedApprovals.push({ ...pending, decision: event.decision, note: event.note ?? null, actor: event.actor, resolvedAt: event.at });
130
+ break;
131
+ }
132
+ case "input-requested": {
133
+ pendingUserInputs.set(event.requestId, {
134
+ requestId: event.requestId,
135
+ requestKind: "user-input",
136
+ actionId: null,
137
+ payload: event.payload,
138
+ requestedAt: event.at
139
+ });
140
+ break;
141
+ }
142
+ case "input-resolved": {
143
+ const pending = pendingUserInputs.get(event.requestId);
144
+ if (!pending) {
145
+ const alreadyResolved = resolvedUserInputs.some((entry) => entry.requestId === event.requestId);
146
+ anomalies.push({ seq: event.seq, kind: alreadyResolved ? "duplicate-resolution" : "unknown-request", detail: `user-input ${event.requestId}` });
147
+ break;
148
+ }
149
+ pendingUserInputs.delete(event.requestId);
150
+ resolvedUserInputs.push({ ...pending, answers: event.answers, actor: event.actor, resolvedAt: event.at });
151
+ break;
152
+ }
153
+ case "steering":
154
+ steeringCount += 1;
155
+ break;
156
+ case "adopted":
157
+ record = { ...record, pid: event.pid, updatedAt: event.at };
158
+ break;
159
+ case "stall-detected":
160
+ stallCount += 1;
161
+ break;
162
+ case "closeout-phase":
163
+ closeoutPhases.push({ seq: event.seq, at: event.at, phase: event.phase, outcome: event.outcome, detail: event.detail ?? null });
164
+ break;
165
+ case "pipeline-resolved":
166
+ resolvedPipeline = event.pipeline;
167
+ break;
168
+ case "stage-outcome":
169
+ stageOutcomes.push({ seq: event.seq, at: event.at, outcome: event.outcome });
170
+ break;
171
+ case "timeline-entry":
172
+ case "log-entry":
173
+ break;
174
+ }
175
+ }
176
+ return {
177
+ runId: projectedRunId,
178
+ record,
179
+ status,
180
+ statusHistory,
181
+ pendingApprovals: [...pendingApprovals.values()],
182
+ resolvedApprovals,
183
+ pendingUserInputs: [...pendingUserInputs.values()],
184
+ resolvedUserInputs,
185
+ steeringCount,
186
+ stallCount,
187
+ closeoutPhases,
188
+ resolvedPipeline,
189
+ stageOutcomes,
190
+ lastSeq,
191
+ lastEventAt,
192
+ anomalies
193
+ };
194
+ }
195
+ function isRunSessionCustomType(customType) {
196
+ return customType !== undefined && Object.hasOwn(TYPE_FOR_CUSTOM, customType);
197
+ }
198
+ function foldRunSessionEntries(entries, runId) {
199
+ const events = [];
200
+ entries.forEach((entry, index) => {
201
+ if (entry.type !== "custom" || !isRunSessionCustomType(entry.customType))
202
+ return;
203
+ const data = entry.data !== null && typeof entry.data === "object" ? entry.data : {};
204
+ const stamped = {
205
+ v: 1,
206
+ seq: index + 1,
207
+ at: typeof data.at === "string" ? data.at : new Date(0).toISOString(),
208
+ runId,
209
+ ...data,
210
+ type: TYPE_FOR_CUSTOM[entry.customType]
211
+ };
212
+ try {
213
+ events.push(decodeRunJournalEvent(stamped));
214
+ } catch {}
215
+ });
216
+ return reduceRunJournal(events, runId);
217
+ }
218
+ function asCustomEntries(entries) {
219
+ return entries.filter((entry) => entry.type === "custom");
220
+ }
221
+
222
+ class RunSessionJournal {
223
+ sm;
224
+ runId;
225
+ constructor(sm, runId) {
226
+ this.sm = sm;
227
+ this.runId = runId;
228
+ }
229
+ #append(init) {
230
+ this.sm.appendCustomEntry(CUSTOM_TYPE_FOR[init.type], { ...init, at: new Date().toISOString() });
231
+ }
232
+ appendStatus(to, opts = {}) {
233
+ const from = foldRunSessionEntries(asCustomEntries(this.sm.getEntries()), this.runId).status;
234
+ if (!opts.force)
235
+ assertRunStatusTransition(from, to);
236
+ if (opts.errorText !== undefined)
237
+ this.#append({ type: "record-patch", patch: { errorText: opts.errorText } });
238
+ this.#append({
239
+ type: "status-changed",
240
+ from,
241
+ to,
242
+ ...opts.reason !== undefined ? { reason: opts.reason } : {},
243
+ ...opts.actor !== undefined ? { actor: opts.actor } : {}
244
+ });
245
+ }
246
+ appendTimeline(payload) {
247
+ this.#append({ type: "timeline-entry", payload });
248
+ }
249
+ appendCloseoutPhase(input) {
250
+ this.#append({
251
+ type: "closeout-phase",
252
+ phase: input.phase,
253
+ outcome: input.outcome,
254
+ ...input.detail !== undefined ? { detail: input.detail } : {}
255
+ });
256
+ }
257
+ appendApprovalResolved(input) {
258
+ this.#append({
259
+ type: "approval-resolved",
260
+ requestId: input.requestId,
261
+ decision: input.decision,
262
+ actor: input.actor,
263
+ ...input.note !== undefined ? { note: input.note } : {}
264
+ });
265
+ }
266
+ appendInputResolved(input) {
267
+ this.#append({ type: "input-resolved", requestId: input.requestId, answers: input.answers, actor: input.actor });
268
+ }
269
+ appendStall(input) {
270
+ this.#append({ type: "stall-detected", detail: input.detail });
271
+ }
272
+ }
273
+ function createWorkflowStatusChanged(input) {
274
+ return {
275
+ schemaVersion: 1,
276
+ status: input.status,
277
+ ...input.detail ? { detail: input.detail } : {},
278
+ changedAt: input.changedAt ?? new Date().toISOString()
279
+ };
280
+ }
281
+
282
+ // packages/run-worker/src/utils.ts
283
+ import { resolveRegistryBaseUrl, resolveRelayUrl } from "@rig/core/remote-config";
5
284
  function isRecord(value) {
6
285
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
7
286
  }
@@ -14,7 +293,7 @@ function customEntries(entries) {
14
293
  return customs;
15
294
  }
16
295
  function appendStatus(api, status, detail) {
17
- api.appendEntry(RIG_WORKFLOW_STATUS_CHANGED, createWorkflowStatusChanged({
296
+ api.appendEntry(RIG_WORKFLOW_STATUS_CHANGED2, createWorkflowStatusChanged({
18
297
  status,
19
298
  ...detail ? { detail } : {}
20
299
  }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@h-rig/run-worker",
3
- "version": "0.0.6-alpha.156",
3
+ "version": "0.0.6-alpha.158",
4
4
  "type": "module",
5
5
  "description": "Rig package",
6
6
  "license": "UNLICENSED",
@@ -13,9 +13,9 @@
13
13
  "types": "./dist/src/index.d.ts",
14
14
  "import": "./dist/src/index.js"
15
15
  },
16
- "./runs": {
17
- "types": "./dist/src/runs/index.d.ts",
18
- "import": "./dist/src/runs/index.js"
16
+ "./host": {
17
+ "types": "./dist/src/host.d.ts",
18
+ "import": "./dist/src/host.js"
19
19
  }
20
20
  },
21
21
  "engines": {
@@ -30,15 +30,12 @@
30
30
  ]
31
31
  },
32
32
  "dependencies": {
33
+ "@oh-my-pi/omp-stats": "16.0.4",
33
34
  "@oh-my-pi/pi-coding-agent": "16.0.4",
34
- "@rig/bundle-default-lifecycle": "npm:@h-rig/bundle-default-lifecycle@0.0.6-alpha.156",
35
- "@rig/contracts": "npm:@h-rig/contracts@0.0.6-alpha.156",
36
- "@rig/core": "npm:@h-rig/core@0.0.6-alpha.156",
37
- "@rig/github-provider-plugin": "npm:@h-rig/github-provider-plugin@0.0.6-alpha.156",
38
- "@rig/kernel": "npm:@h-rig/kernel@0.0.6-alpha.156",
39
- "@rig/notifications-plugin": "npm:@h-rig/notifications-plugin@0.0.6-alpha.156",
40
- "@rig/relay-registry": "npm:@h-rig/relay-registry@0.0.6-alpha.156",
41
- "@rig/runtime": "npm:@h-rig/runtime@0.0.6-alpha.156",
35
+ "@oh-my-pi/pi-utils": "16.0.4",
36
+ "@rig/contracts": "npm:@h-rig/contracts@0.0.6-alpha.158",
37
+ "@rig/core": "npm:@h-rig/core@0.0.6-alpha.158",
38
+ "@rig/kernel-seed": "npm:@h-rig/kernel-seed@0.0.6-alpha.158",
42
39
  "effect": "4.0.0-beta.90"
43
40
  }
44
41
  }
@@ -1,33 +0,0 @@
1
- import type { ExtensionContext } from "@oh-my-pi/pi-coding-agent";
2
- import type { ApprovalDecision, RunActor, RunCloseoutPhase, RunCloseoutPhaseOutcome, RunStatus } from "@rig/contracts";
3
- import { type JournalSessionProvider } from "@rig/kernel/journal-session-provider";
4
- export type RunJournal = {
5
- readonly kernel: JournalSessionProvider;
6
- appendStatus(to: RunStatus, opts?: {
7
- reason?: string | null;
8
- actor?: RunActor;
9
- errorText?: string | null;
10
- force?: boolean;
11
- }): void;
12
- appendTimeline(payload: unknown): void;
13
- appendCloseoutPhase(input: {
14
- phase: RunCloseoutPhase;
15
- outcome: RunCloseoutPhaseOutcome;
16
- detail?: string | null;
17
- }): void;
18
- appendApprovalResolved(input: {
19
- requestId: string;
20
- decision: ApprovalDecision;
21
- note?: string | null;
22
- actor: RunActor;
23
- }): void;
24
- appendInputResolved(input: {
25
- requestId: string;
26
- answers: Record<string, string>;
27
- actor: RunActor;
28
- }): void;
29
- appendStall(input: {
30
- detail: string;
31
- }): void;
32
- };
33
- export declare function createRunJournal(sessionManager: ExtensionContext["sessionManager"], runId: string): Promise<RunJournal | null>;
@@ -1,31 +0,0 @@
1
- // @bun
2
- // packages/run-worker/src/journal.ts
3
- import { createJournalSessionProvider } from "@rig/kernel/journal-session-provider";
4
- import { RunSessionJournal } from "@rig/runtime/control-plane/run-session-writer";
5
- async function createRunJournal(sessionManager, runId) {
6
- try {
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
- };
24
- } catch (error) {
25
- console.warn(`[rig-run] RunSessionJournal unavailable; run-state arming deferred: ${error instanceof Error ? error.message : String(error)}`);
26
- return null;
27
- }
28
- }
29
- export {
30
- createRunJournal
31
- };