@oisincoveney/pipeline 2.1.0 → 2.2.0

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 (39) hide show
  1. package/defaults/pipeline.yaml +111 -0
  2. package/defaults/profiles.yaml +212 -0
  3. package/defaults/runners.yaml +24 -0
  4. package/dist/argo-graph.js +59 -27
  5. package/dist/argo-submit.js +28 -4
  6. package/dist/claude-settings-config.js +44 -0
  7. package/dist/cli/program.js +1 -1
  8. package/dist/config/defaults.js +7 -353
  9. package/dist/git-remote-url.js +30 -0
  10. package/dist/hooks.d.ts +1 -1
  11. package/dist/install-commands/claude-code.js +153 -17
  12. package/dist/install-commands/opencode.js +37 -33
  13. package/dist/install-commands/shared.js +27 -6
  14. package/dist/install-commands.js +26 -22
  15. package/dist/json-config-merge.js +47 -0
  16. package/dist/mcp/gateway.js +9 -1
  17. package/dist/moka-submit.d.ts +6 -6
  18. package/dist/moka-submit.js +4 -3
  19. package/dist/opencode-project-config.js +2 -45
  20. package/dist/pipeline-runtime.js +50 -8
  21. package/dist/runner-event-schema.d.ts +349 -0
  22. package/dist/runner-event-schema.js +185 -0
  23. package/dist/runner-output.js +2 -2
  24. package/dist/runner.d.ts +2 -0
  25. package/dist/runtime/agent-node/agent-node.js +1 -0
  26. package/dist/runtime/contracts/contracts.d.ts +2 -0
  27. package/dist/runtime/node-state-store.js +7 -0
  28. package/dist/runtime/opencode-adapter.js +28 -8
  29. package/dist/runtime/opencode-agent-name.js +18 -0
  30. package/dist/runtime/opencode-runtime.js +62 -0
  31. package/dist/runtime/opencode-server.js +67 -0
  32. package/dist/runtime/opencode-session-executor.js +206 -0
  33. package/docs/adr-opencode-first-goal-loop-runtime.md +1 -1
  34. package/docs/config-architecture.md +11 -6
  35. package/docs/mcp-gateway.md +4 -4
  36. package/docs/operator-guide.md +7 -5
  37. package/docs/slash-command-adapter-contract.md +1 -0
  38. package/package.json +6 -1
  39. package/.agents/skills/claude-code-opencode-execute/SKILL.md +0 -116
@@ -0,0 +1,349 @@
1
+ import { RunnerEventRecord } from "./runner-command-contract.js";
2
+ import { z } from "zod";
3
+
4
+ //#region src/runner-event-schema.d.ts
5
+ /**
6
+ * Zod schema for a single runner event record — one item in the events array
7
+ * that the runner POSTs to /api/pipeline/runner-events.
8
+ */
9
+ declare const runnerEventRecordSchema: z.ZodUnion<readonly [z.ZodObject<{
10
+ at: z.ZodOptional<z.ZodString>;
11
+ sequence: z.ZodNumber;
12
+ type: z.ZodEnum<{
13
+ "workflow.planned": "workflow.planned";
14
+ "workflow.start": "workflow.start";
15
+ }>;
16
+ workflowPlan: z.ZodObject<{
17
+ edges: z.ZodOptional<z.ZodArray<z.ZodObject<{
18
+ source: z.ZodString;
19
+ target: z.ZodString;
20
+ }, z.core.$strip>>>;
21
+ nodeIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
22
+ nodes: z.ZodOptional<z.ZodArray<z.ZodObject<{
23
+ id: z.ZodString;
24
+ kind: z.ZodString;
25
+ needs: z.ZodArray<z.ZodString>;
26
+ profile: z.ZodOptional<z.ZodString>;
27
+ runnerId: z.ZodOptional<z.ZodString>;
28
+ }, z.core.$strip>>>;
29
+ workflowId: z.ZodString;
30
+ }, z.core.$strip>;
31
+ }, z.core.$strip>, z.ZodObject<{
32
+ at: z.ZodOptional<z.ZodString>;
33
+ sequence: z.ZodNumber;
34
+ edge: z.ZodObject<{
35
+ id: z.ZodString;
36
+ source: z.ZodString;
37
+ target: z.ZodString;
38
+ }, z.core.$strip>;
39
+ type: z.ZodLiteral<"workflow.edge">;
40
+ }, z.core.$strip>, z.ZodObject<{
41
+ at: z.ZodOptional<z.ZodString>;
42
+ sequence: z.ZodNumber;
43
+ node: z.ZodObject<{
44
+ attempt: z.ZodNumber;
45
+ exitCode: z.ZodOptional<z.ZodNumber>;
46
+ nodeId: z.ZodString;
47
+ profile: z.ZodOptional<z.ZodString>;
48
+ runnerId: z.ZodOptional<z.ZodString>;
49
+ status: z.ZodEnum<{
50
+ "agent-finished": "agent-finished";
51
+ "agent-running": "agent-running";
52
+ failed: "failed";
53
+ passed: "passed";
54
+ running: "running";
55
+ }>;
56
+ }, z.core.$strip>;
57
+ type: z.ZodEnum<{
58
+ "agent.finish": "agent.finish";
59
+ "agent.start": "agent.start";
60
+ "node.finish": "node.finish";
61
+ "node.start": "node.start";
62
+ }>;
63
+ }, z.core.$strip>, z.ZodObject<{
64
+ at: z.ZodOptional<z.ZodString>;
65
+ sequence: z.ZodNumber;
66
+ gate: z.ZodObject<{
67
+ event: z.ZodOptional<z.ZodString>;
68
+ evidence: z.ZodOptional<z.ZodArray<z.ZodString>>;
69
+ gateId: z.ZodOptional<z.ZodString>;
70
+ hookId: z.ZodOptional<z.ZodString>;
71
+ kind: z.ZodOptional<z.ZodString>;
72
+ label: z.ZodOptional<z.ZodString>;
73
+ nodeId: z.ZodOptional<z.ZodString>;
74
+ passed: z.ZodOptional<z.ZodBoolean>;
75
+ reason: z.ZodOptional<z.ZodString>;
76
+ required: z.ZodOptional<z.ZodBoolean>;
77
+ status: z.ZodEnum<{
78
+ failed: "failed";
79
+ passed: "passed";
80
+ running: "running";
81
+ }>;
82
+ workflowId: z.ZodOptional<z.ZodString>;
83
+ }, z.core.$strip>;
84
+ type: z.ZodEnum<{
85
+ "gate.finish": "gate.finish";
86
+ "gate.start": "gate.start";
87
+ "hook.finish": "hook.finish";
88
+ "hook.start": "hook.start";
89
+ }>;
90
+ }, z.core.$strip>, z.ZodObject<{
91
+ at: z.ZodOptional<z.ZodString>;
92
+ sequence: z.ZodNumber;
93
+ hookResult: z.ZodObject<{
94
+ artifacts: z.ZodOptional<z.ZodArray<z.ZodObject<{
95
+ contentType: z.ZodOptional<z.ZodString>;
96
+ name: z.ZodString;
97
+ path: z.ZodString;
98
+ }, z.core.$strip>>>;
99
+ event: z.ZodString;
100
+ functionId: z.ZodString;
101
+ gateId: z.ZodOptional<z.ZodString>;
102
+ hookId: z.ZodString;
103
+ nodeId: z.ZodOptional<z.ZodString>;
104
+ outputs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
105
+ status: z.ZodEnum<{
106
+ fail: "fail";
107
+ pass: "pass";
108
+ skip: "skip";
109
+ }>;
110
+ summary: z.ZodOptional<z.ZodString>;
111
+ workflowId: z.ZodString;
112
+ }, z.core.$strip>;
113
+ type: z.ZodLiteral<"hook.result">;
114
+ }, z.core.$strip>, z.ZodObject<{
115
+ at: z.ZodOptional<z.ZodString>;
116
+ sequence: z.ZodNumber;
117
+ artifact: z.ZodObject<{
118
+ kind: z.ZodLiteral<"artifact">;
119
+ label: z.ZodString;
120
+ nodeId: z.ZodString;
121
+ passed: z.ZodOptional<z.ZodBoolean>;
122
+ path: z.ZodString;
123
+ reason: z.ZodOptional<z.ZodString>;
124
+ required: z.ZodBoolean;
125
+ status: z.ZodEnum<{
126
+ failed: "failed";
127
+ passed: "passed";
128
+ running: "running";
129
+ }>;
130
+ uri: z.ZodString;
131
+ }, z.core.$strip>;
132
+ type: z.ZodEnum<{
133
+ "artifact.check.finish": "artifact.check.finish";
134
+ "artifact.check.start": "artifact.check.start";
135
+ }>;
136
+ }, z.core.$strip>, z.ZodObject<{
137
+ at: z.ZodOptional<z.ZodString>;
138
+ sequence: z.ZodNumber;
139
+ log: z.ZodObject<{
140
+ attempt: z.ZodOptional<z.ZodNumber>;
141
+ format: z.ZodOptional<z.ZodString>;
142
+ level: z.ZodEnum<{
143
+ info: "info";
144
+ warn: "warn";
145
+ }>;
146
+ message: z.ZodString;
147
+ nodeId: z.ZodOptional<z.ZodString>;
148
+ output: z.ZodOptional<z.ZodUnknown>;
149
+ passed: z.ZodOptional<z.ZodBoolean>;
150
+ reason: z.ZodOptional<z.ZodString>;
151
+ workflowId: z.ZodOptional<z.ZodString>;
152
+ }, z.core.$strip>;
153
+ type: z.ZodEnum<{
154
+ "node.output.recorded": "node.output.recorded";
155
+ "output.repair": "output.repair";
156
+ "run.cancelled": "run.cancelled";
157
+ "runner.command.phase": "runner.command.phase";
158
+ "runner.schema.validation": "runner.schema.validation";
159
+ "runtime.observability": "runtime.observability";
160
+ }>;
161
+ }, z.core.$strip>, z.ZodObject<{
162
+ at: z.ZodOptional<z.ZodString>;
163
+ sequence: z.ZodNumber;
164
+ finalResult: z.ZodObject<{
165
+ outcome: z.ZodEnum<{
166
+ CANCELLED: "CANCELLED";
167
+ FAIL: "FAIL";
168
+ PASS: "PASS";
169
+ }>;
170
+ workflowId: z.ZodString;
171
+ }, z.core.$strip>;
172
+ type: z.ZodLiteral<"workflow.finish">;
173
+ }, z.core.$strip>]>;
174
+ /**
175
+ * Zod schema for the POST body of /api/pipeline/runner-events.
176
+ * The runner sends { events: RunnerEventRecord[] }.
177
+ */
178
+ declare const runnerEventBatchSchema: z.ZodObject<{
179
+ events: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
180
+ at: z.ZodOptional<z.ZodString>;
181
+ sequence: z.ZodNumber;
182
+ type: z.ZodEnum<{
183
+ "workflow.planned": "workflow.planned";
184
+ "workflow.start": "workflow.start";
185
+ }>;
186
+ workflowPlan: z.ZodObject<{
187
+ edges: z.ZodOptional<z.ZodArray<z.ZodObject<{
188
+ source: z.ZodString;
189
+ target: z.ZodString;
190
+ }, z.core.$strip>>>;
191
+ nodeIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
192
+ nodes: z.ZodOptional<z.ZodArray<z.ZodObject<{
193
+ id: z.ZodString;
194
+ kind: z.ZodString;
195
+ needs: z.ZodArray<z.ZodString>;
196
+ profile: z.ZodOptional<z.ZodString>;
197
+ runnerId: z.ZodOptional<z.ZodString>;
198
+ }, z.core.$strip>>>;
199
+ workflowId: z.ZodString;
200
+ }, z.core.$strip>;
201
+ }, z.core.$strip>, z.ZodObject<{
202
+ at: z.ZodOptional<z.ZodString>;
203
+ sequence: z.ZodNumber;
204
+ edge: z.ZodObject<{
205
+ id: z.ZodString;
206
+ source: z.ZodString;
207
+ target: z.ZodString;
208
+ }, z.core.$strip>;
209
+ type: z.ZodLiteral<"workflow.edge">;
210
+ }, z.core.$strip>, z.ZodObject<{
211
+ at: z.ZodOptional<z.ZodString>;
212
+ sequence: z.ZodNumber;
213
+ node: z.ZodObject<{
214
+ attempt: z.ZodNumber;
215
+ exitCode: z.ZodOptional<z.ZodNumber>;
216
+ nodeId: z.ZodString;
217
+ profile: z.ZodOptional<z.ZodString>;
218
+ runnerId: z.ZodOptional<z.ZodString>;
219
+ status: z.ZodEnum<{
220
+ "agent-finished": "agent-finished";
221
+ "agent-running": "agent-running";
222
+ failed: "failed";
223
+ passed: "passed";
224
+ running: "running";
225
+ }>;
226
+ }, z.core.$strip>;
227
+ type: z.ZodEnum<{
228
+ "agent.finish": "agent.finish";
229
+ "agent.start": "agent.start";
230
+ "node.finish": "node.finish";
231
+ "node.start": "node.start";
232
+ }>;
233
+ }, z.core.$strip>, z.ZodObject<{
234
+ at: z.ZodOptional<z.ZodString>;
235
+ sequence: z.ZodNumber;
236
+ gate: z.ZodObject<{
237
+ event: z.ZodOptional<z.ZodString>;
238
+ evidence: z.ZodOptional<z.ZodArray<z.ZodString>>;
239
+ gateId: z.ZodOptional<z.ZodString>;
240
+ hookId: z.ZodOptional<z.ZodString>;
241
+ kind: z.ZodOptional<z.ZodString>;
242
+ label: z.ZodOptional<z.ZodString>;
243
+ nodeId: z.ZodOptional<z.ZodString>;
244
+ passed: z.ZodOptional<z.ZodBoolean>;
245
+ reason: z.ZodOptional<z.ZodString>;
246
+ required: z.ZodOptional<z.ZodBoolean>;
247
+ status: z.ZodEnum<{
248
+ failed: "failed";
249
+ passed: "passed";
250
+ running: "running";
251
+ }>;
252
+ workflowId: z.ZodOptional<z.ZodString>;
253
+ }, z.core.$strip>;
254
+ type: z.ZodEnum<{
255
+ "gate.finish": "gate.finish";
256
+ "gate.start": "gate.start";
257
+ "hook.finish": "hook.finish";
258
+ "hook.start": "hook.start";
259
+ }>;
260
+ }, z.core.$strip>, z.ZodObject<{
261
+ at: z.ZodOptional<z.ZodString>;
262
+ sequence: z.ZodNumber;
263
+ hookResult: z.ZodObject<{
264
+ artifacts: z.ZodOptional<z.ZodArray<z.ZodObject<{
265
+ contentType: z.ZodOptional<z.ZodString>;
266
+ name: z.ZodString;
267
+ path: z.ZodString;
268
+ }, z.core.$strip>>>;
269
+ event: z.ZodString;
270
+ functionId: z.ZodString;
271
+ gateId: z.ZodOptional<z.ZodString>;
272
+ hookId: z.ZodString;
273
+ nodeId: z.ZodOptional<z.ZodString>;
274
+ outputs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
275
+ status: z.ZodEnum<{
276
+ fail: "fail";
277
+ pass: "pass";
278
+ skip: "skip";
279
+ }>;
280
+ summary: z.ZodOptional<z.ZodString>;
281
+ workflowId: z.ZodString;
282
+ }, z.core.$strip>;
283
+ type: z.ZodLiteral<"hook.result">;
284
+ }, z.core.$strip>, z.ZodObject<{
285
+ at: z.ZodOptional<z.ZodString>;
286
+ sequence: z.ZodNumber;
287
+ artifact: z.ZodObject<{
288
+ kind: z.ZodLiteral<"artifact">;
289
+ label: z.ZodString;
290
+ nodeId: z.ZodString;
291
+ passed: z.ZodOptional<z.ZodBoolean>;
292
+ path: z.ZodString;
293
+ reason: z.ZodOptional<z.ZodString>;
294
+ required: z.ZodBoolean;
295
+ status: z.ZodEnum<{
296
+ failed: "failed";
297
+ passed: "passed";
298
+ running: "running";
299
+ }>;
300
+ uri: z.ZodString;
301
+ }, z.core.$strip>;
302
+ type: z.ZodEnum<{
303
+ "artifact.check.finish": "artifact.check.finish";
304
+ "artifact.check.start": "artifact.check.start";
305
+ }>;
306
+ }, z.core.$strip>, z.ZodObject<{
307
+ at: z.ZodOptional<z.ZodString>;
308
+ sequence: z.ZodNumber;
309
+ log: z.ZodObject<{
310
+ attempt: z.ZodOptional<z.ZodNumber>;
311
+ format: z.ZodOptional<z.ZodString>;
312
+ level: z.ZodEnum<{
313
+ info: "info";
314
+ warn: "warn";
315
+ }>;
316
+ message: z.ZodString;
317
+ nodeId: z.ZodOptional<z.ZodString>;
318
+ output: z.ZodOptional<z.ZodUnknown>;
319
+ passed: z.ZodOptional<z.ZodBoolean>;
320
+ reason: z.ZodOptional<z.ZodString>;
321
+ workflowId: z.ZodOptional<z.ZodString>;
322
+ }, z.core.$strip>;
323
+ type: z.ZodEnum<{
324
+ "node.output.recorded": "node.output.recorded";
325
+ "output.repair": "output.repair";
326
+ "run.cancelled": "run.cancelled";
327
+ "runner.command.phase": "runner.command.phase";
328
+ "runner.schema.validation": "runner.schema.validation";
329
+ "runtime.observability": "runtime.observability";
330
+ }>;
331
+ }, z.core.$strip>, z.ZodObject<{
332
+ at: z.ZodOptional<z.ZodString>;
333
+ sequence: z.ZodNumber;
334
+ finalResult: z.ZodObject<{
335
+ outcome: z.ZodEnum<{
336
+ CANCELLED: "CANCELLED";
337
+ FAIL: "FAIL";
338
+ PASS: "PASS";
339
+ }>;
340
+ workflowId: z.ZodString;
341
+ }, z.core.$strip>;
342
+ type: z.ZodLiteral<"workflow.finish">;
343
+ }, z.core.$strip>]>>;
344
+ }, z.core.$strict>;
345
+ type RunnerEventRecordSchema = typeof runnerEventRecordSchema;
346
+ type RunnerEventBatchSchema = typeof runnerEventBatchSchema;
347
+ declare const _runnerEventRecordTypeCheck: z.ZodType<RunnerEventRecord>;
348
+ //#endregion
349
+ export { RunnerEventBatchSchema, type RunnerEventRecord, RunnerEventRecordSchema, _runnerEventRecordTypeCheck, runnerEventBatchSchema, runnerEventRecordSchema };
@@ -0,0 +1,185 @@
1
+ import { z } from "zod";
2
+ //#region src/runner-event-schema.ts
3
+ const runnerEventEnvelopeSchema = z.object({
4
+ at: z.string().optional(),
5
+ sequence: z.number().int().positive()
6
+ });
7
+ const runnerWorkflowNodeDetailsSchema = z.object({
8
+ id: z.string().min(1),
9
+ kind: z.string().min(1),
10
+ needs: z.array(z.string()),
11
+ profile: z.string().optional(),
12
+ runnerId: z.string().optional()
13
+ });
14
+ const runnerWorkflowEdgeDetailsSchema = z.object({
15
+ source: z.string().min(1),
16
+ target: z.string().min(1)
17
+ });
18
+ const runnerWorkflowPlanDetailsSchema = z.object({
19
+ edges: z.array(runnerWorkflowEdgeDetailsSchema).optional(),
20
+ nodeIds: z.array(z.string().min(1)).optional(),
21
+ nodes: z.array(runnerWorkflowNodeDetailsSchema).optional(),
22
+ workflowId: z.string().min(1)
23
+ });
24
+ const runnerWorkflowEdgeRecordDetailsSchema = z.object({
25
+ id: z.string().min(1),
26
+ source: z.string().min(1),
27
+ target: z.string().min(1)
28
+ });
29
+ const runnerNodeDetailsSchema = z.object({
30
+ attempt: z.number().int().nonnegative(),
31
+ exitCode: z.number().int().optional(),
32
+ nodeId: z.string().min(1),
33
+ profile: z.string().optional(),
34
+ runnerId: z.string().optional(),
35
+ status: z.enum([
36
+ "agent-finished",
37
+ "agent-running",
38
+ "failed",
39
+ "passed",
40
+ "running"
41
+ ])
42
+ });
43
+ const runnerGateDetailsSchema = z.object({
44
+ event: z.string().optional(),
45
+ evidence: z.array(z.string()).optional(),
46
+ gateId: z.string().optional(),
47
+ hookId: z.string().optional(),
48
+ kind: z.string().optional(),
49
+ label: z.string().optional(),
50
+ nodeId: z.string().optional(),
51
+ passed: z.boolean().optional(),
52
+ reason: z.string().optional(),
53
+ required: z.boolean().optional(),
54
+ status: z.enum([
55
+ "failed",
56
+ "passed",
57
+ "running"
58
+ ]),
59
+ workflowId: z.string().optional()
60
+ });
61
+ const runnerHookResultDetailsSchema = z.object({
62
+ artifacts: z.array(z.object({
63
+ contentType: z.string().optional(),
64
+ name: z.string().min(1),
65
+ path: z.string().min(1)
66
+ })).optional(),
67
+ event: z.string().min(1),
68
+ functionId: z.string().min(1),
69
+ gateId: z.string().optional(),
70
+ hookId: z.string().min(1),
71
+ nodeId: z.string().optional(),
72
+ outputs: z.record(z.string(), z.unknown()).optional(),
73
+ status: z.enum([
74
+ "fail",
75
+ "pass",
76
+ "skip"
77
+ ]),
78
+ summary: z.string().optional(),
79
+ workflowId: z.string().min(1)
80
+ });
81
+ const runnerArtifactDetailsSchema = z.object({
82
+ kind: z.literal("artifact"),
83
+ label: z.string().min(1),
84
+ nodeId: z.string().min(1),
85
+ passed: z.boolean().optional(),
86
+ path: z.string().min(1),
87
+ reason: z.string().optional(),
88
+ required: z.boolean(),
89
+ status: z.enum([
90
+ "failed",
91
+ "passed",
92
+ "running"
93
+ ]),
94
+ uri: z.string().min(1)
95
+ });
96
+ const runnerLogDetailsSchema = z.object({
97
+ attempt: z.number().int().nonnegative().optional(),
98
+ format: z.string().optional(),
99
+ level: z.enum(["info", "warn"]),
100
+ message: z.string(),
101
+ nodeId: z.string().optional(),
102
+ output: z.unknown().optional(),
103
+ passed: z.boolean().optional(),
104
+ reason: z.string().optional(),
105
+ workflowId: z.string().optional()
106
+ });
107
+ const runnerFinalResultDetailsSchema = z.object({
108
+ outcome: z.enum([
109
+ "CANCELLED",
110
+ "FAIL",
111
+ "PASS"
112
+ ]),
113
+ workflowId: z.string().min(1)
114
+ });
115
+ const workflowPlanEventSchema = runnerEventEnvelopeSchema.extend({
116
+ type: z.enum(["workflow.planned", "workflow.start"]),
117
+ workflowPlan: runnerWorkflowPlanDetailsSchema
118
+ });
119
+ const workflowEdgeEventSchema = runnerEventEnvelopeSchema.extend({
120
+ edge: runnerWorkflowEdgeRecordDetailsSchema,
121
+ type: z.literal("workflow.edge")
122
+ });
123
+ const nodeEventSchema = runnerEventEnvelopeSchema.extend({
124
+ node: runnerNodeDetailsSchema,
125
+ type: z.enum([
126
+ "agent.finish",
127
+ "agent.start",
128
+ "node.finish",
129
+ "node.start"
130
+ ])
131
+ });
132
+ const gateEventSchema = runnerEventEnvelopeSchema.extend({
133
+ gate: runnerGateDetailsSchema,
134
+ type: z.enum([
135
+ "gate.finish",
136
+ "gate.start",
137
+ "hook.finish",
138
+ "hook.start"
139
+ ])
140
+ });
141
+ const hookResultEventSchema = runnerEventEnvelopeSchema.extend({
142
+ hookResult: runnerHookResultDetailsSchema,
143
+ type: z.literal("hook.result")
144
+ });
145
+ const artifactEventSchema = runnerEventEnvelopeSchema.extend({
146
+ artifact: runnerArtifactDetailsSchema,
147
+ type: z.enum(["artifact.check.finish", "artifact.check.start"])
148
+ });
149
+ const logEventSchema = runnerEventEnvelopeSchema.extend({
150
+ log: runnerLogDetailsSchema,
151
+ type: z.enum([
152
+ "node.output.recorded",
153
+ "output.repair",
154
+ "run.cancelled",
155
+ "runner.command.phase",
156
+ "runner.schema.validation",
157
+ "runtime.observability"
158
+ ])
159
+ });
160
+ const finalResultEventSchema = runnerEventEnvelopeSchema.extend({
161
+ finalResult: runnerFinalResultDetailsSchema,
162
+ type: z.literal("workflow.finish")
163
+ });
164
+ /**
165
+ * Zod schema for a single runner event record — one item in the events array
166
+ * that the runner POSTs to /api/pipeline/runner-events.
167
+ */
168
+ const runnerEventRecordSchema = z.union([
169
+ workflowPlanEventSchema,
170
+ workflowEdgeEventSchema,
171
+ nodeEventSchema,
172
+ gateEventSchema,
173
+ hookResultEventSchema,
174
+ artifactEventSchema,
175
+ logEventSchema,
176
+ finalResultEventSchema
177
+ ]);
178
+ /**
179
+ * Zod schema for the POST body of /api/pipeline/runner-events.
180
+ * The runner sends { events: RunnerEventRecord[] }.
181
+ */
182
+ const runnerEventBatchSchema = z.object({ events: z.array(runnerEventRecordSchema).min(1) }).strict();
183
+ const _runnerEventRecordTypeCheck = runnerEventRecordSchema;
184
+ //#endregion
185
+ export { _runnerEventRecordTypeCheck, runnerEventBatchSchema, runnerEventRecordSchema };
@@ -1,4 +1,4 @@
1
- import { opencodeCliRuntimeAdapter } from "./runtime/opencode-adapter.js";
1
+ import { opencodeSdkRuntimeAdapter } from "./runtime/opencode-adapter.js";
2
2
  //#region src/runner-output.ts
3
3
  function normalizeRunnerOutput(plan, stdout) {
4
4
  const latest = runnerTextCandidates(plan, stdout).at(-1);
@@ -12,7 +12,7 @@ function normalizeRunnerOutput(plan, stdout) {
12
12
  };
13
13
  }
14
14
  function runnerTextCandidates(plan, stdout) {
15
- if (plan.type === "opencode") return opencodeCliRuntimeAdapter.outputCandidates(stdout);
15
+ if (plan.type === "opencode") return opencodeSdkRuntimeAdapter.outputCandidates(stdout);
16
16
  return [];
17
17
  }
18
18
  //#endregion
package/dist/runner.d.ts CHANGED
@@ -5,6 +5,8 @@ type AgentRole = "researcher" | "test-writer" | "code-writer" | "verifier";
5
5
  interface AgentResult {
6
6
  argv?: string[];
7
7
  exitCode: number;
8
+ /** opencode session id when driven through the SDK executor (PIPE-73). */
9
+ sessionId?: string;
8
10
  stderr?: string;
9
11
  stdout: string;
10
12
  timedOut?: boolean;
@@ -43,6 +43,7 @@ async function executeAgentNode(node, context, attempt) {
43
43
  signal: context.signal
44
44
  });
45
45
  emitAgentFinish(context, plan, attempt, result);
46
+ if (result.sessionId) context.nodeStateStore.recordSessionId(node.id, result.sessionId);
46
47
  const finalized = await finalizeAgentOutput({
47
48
  context,
48
49
  node,
@@ -79,6 +79,8 @@ interface NodeExecutionState {
79
79
  retryReason: string;
80
80
  scheduled: boolean;
81
81
  };
82
+ /** opencode session id when the node ran through the SDK executor (PIPE-73). */
83
+ sessionId?: string;
82
84
  startedAt?: string;
83
85
  status: NodeStatus;
84
86
  }
@@ -50,6 +50,13 @@ var NodeStateStore = class NodeStateStore {
50
50
  recordOutput(nodeId, output) {
51
51
  this.lastOutputByNode.set(nodeId, output);
52
52
  }
53
+ recordSessionId(nodeId, sessionId) {
54
+ const existing = this.nodeStates.get(nodeId);
55
+ if (existing) this.nodeStates.set(nodeId, {
56
+ ...existing,
57
+ sessionId
58
+ });
59
+ }
53
60
  recordStructuredOutput(output) {
54
61
  this.structuredOutputs.push(output);
55
62
  }
@@ -1,11 +1,31 @@
1
1
  import { isRecord } from "../safe-json.js";
2
2
  import { jsonLineValues } from "../json-line-values.js";
3
3
  //#region src/runtime/opencode-adapter.ts
4
- const opencodeCliRuntimeAdapter = {
5
- continuation() {
6
- return Promise.reject(/* @__PURE__ */ new Error("OpenCode CLI runtime adapter does not expose native continuation yet"));
4
+ /**
5
+ * Output-parsing seam for opencode runner output. The SDK executor
6
+ * (opencode-session-executor.ts) re-serializes assistant text parts into the
7
+ * same `{ part: { type: "text", text } }` JSONL the legacy CLI emitted, so this
8
+ * parser is transport-agnostic and the structured-output / repair passes work
9
+ * unchanged on top of SDK responses.
10
+ *
11
+ * The session lifecycle, event-stream forwarding, and per-message agent/model
12
+ * selection live in opencode-session-executor.ts + opencode-server.ts; this
13
+ * adapter only normalizes output and reports capabilities.
14
+ */
15
+ const opencodeSdkRuntimeAdapter = {
16
+ continuation(request) {
17
+ return Promise.resolve({ metadata: {
18
+ adapterId: "opencode-sdk",
19
+ continuationApi: "session-reuse",
20
+ nodeId: request.sessionId,
21
+ outputFormat: "text",
22
+ pluginEvents: "server-event-stream",
23
+ runnerId: "opencode",
24
+ sessionInspectionApi: "sdk",
25
+ worktreePath: ""
26
+ } });
7
27
  },
8
- id: "opencode-cli-subprocess",
28
+ id: "opencode-sdk",
9
29
  launch(plan) {
10
30
  assertOpenCodePlan(plan);
11
31
  return {
@@ -37,13 +57,13 @@ const opencodeCliRuntimeAdapter = {
37
57
  assertOpenCodePlan(plan);
38
58
  return {
39
59
  adapterId: this.id,
40
- continuationApi: "unavailable",
60
+ continuationApi: "session-reuse",
41
61
  nodeId: plan.nodeId,
42
62
  outputFormat: plan.outputFormat,
43
- pluginEvents: "project-local",
63
+ pluginEvents: "server-event-stream",
44
64
  profileId: plan.profileId,
45
65
  runnerId: plan.runnerId,
46
- sessionInspectionApi: "unavailable",
66
+ sessionInspectionApi: "sdk",
47
67
  worktreePath: plan.cwd
48
68
  };
49
69
  }
@@ -57,4 +77,4 @@ function opencodeTextPart(value) {
57
77
  if (isRecord(part) && part.type === "text") return typeof part.text === "string" ? part.text : void 0;
58
78
  }
59
79
  //#endregion
60
- export { opencodeCliRuntimeAdapter };
80
+ export { opencodeSdkRuntimeAdapter };
@@ -0,0 +1,18 @@
1
+ //#region src/runtime/opencode-agent-name.ts
2
+ const MOKA_PROFILE_PREFIX = "moka-";
3
+ /**
4
+ * Map a pipeline profile id to the opencode agent name a served instance
5
+ * exposes (e.g. `moka-code-writer` -> `MoKa Code Writer`). Shared by the slash
6
+ * command installer and the SDK runtime so per-message agent selection targets
7
+ * the same `.opencode/agent/*` definition the host projects.
8
+ */
9
+ function opencodeAgentName(profileId) {
10
+ if (!profileId.startsWith(MOKA_PROFILE_PREFIX)) return profileId;
11
+ return `MoKa ${profileId.slice(5).split("-").map(opencodeAgentNamePart).join(" ")}`;
12
+ }
13
+ function opencodeAgentNamePart(part) {
14
+ if (part === "opencode") return "OpenCode";
15
+ return `${part.charAt(0).toUpperCase()}${part.slice(1)}`;
16
+ }
17
+ //#endregion
18
+ export { opencodeAgentName };