@exaudeus/workrail 3.73.1 → 3.74.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 (41) hide show
  1. package/dist/cli-worktrain.js +126 -1
  2. package/dist/console-ui/assets/{index-txIYXGHx.js → index-CfU3va8H.js} +1 -1
  3. package/dist/console-ui/index.html +1 -1
  4. package/dist/coordinators/pr-review.d.ts +11 -1
  5. package/dist/coordinators/types.d.ts +15 -0
  6. package/dist/coordinators/types.js +2 -0
  7. package/dist/manifest.json +81 -57
  8. package/dist/mcp/handlers/v2-advance-core/index.d.ts +1 -0
  9. package/dist/mcp/handlers/v2-advance-core/index.js +3 -3
  10. package/dist/mcp/handlers/v2-advance-core/outcome-success.js +4 -18
  11. package/dist/mcp/handlers/v2-advance-events.d.ts +1 -1
  12. package/dist/mcp/handlers/v2-advance-events.js +1 -1
  13. package/dist/mcp/handlers/v2-execution/advance.d.ts +1 -0
  14. package/dist/mcp/handlers/v2-execution/advance.js +3 -3
  15. package/dist/mcp/handlers/v2-execution/continue-advance.d.ts +1 -0
  16. package/dist/mcp/handlers/v2-execution/continue-advance.js +2 -1
  17. package/dist/mcp/handlers/v2-execution/index.js +3 -1
  18. package/dist/mcp/server.js +6 -4
  19. package/dist/mcp/types.d.ts +2 -0
  20. package/dist/trigger/coordinator-deps.js +203 -36
  21. package/dist/trigger/delivery-action.d.ts +1 -0
  22. package/dist/trigger/delivery-action.js +1 -1
  23. package/dist/trigger/delivery-pipeline.d.ts +13 -2
  24. package/dist/trigger/delivery-pipeline.js +58 -3
  25. package/dist/trigger/trigger-router.js +6 -3
  26. package/dist/v2/durable-core/constants.d.ts +1 -0
  27. package/dist/v2/durable-core/constants.js +1 -0
  28. package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +202 -0
  29. package/dist/v2/durable-core/schemas/session/events.d.ts +56 -0
  30. package/dist/v2/durable-core/schemas/session/events.js +8 -0
  31. package/dist/v2/infra/local/git-snapshot/index.d.ts +6 -0
  32. package/dist/v2/infra/local/git-snapshot/index.js +39 -0
  33. package/dist/v2/ports/git-snapshot.port.d.ts +10 -0
  34. package/dist/v2/ports/git-snapshot.port.js +9 -0
  35. package/dist/v2/projections/session-metrics.js +17 -2
  36. package/docs/authoring.md +23 -0
  37. package/docs/design/engine-boundary-discovery.md +123 -0
  38. package/docs/design/engine-boundary-review-findings.md +72 -0
  39. package/docs/ideas/backlog.md +129 -48
  40. package/package.json +1 -1
  41. package/spec/authoring-spec.json +36 -1
@@ -45,6 +45,102 @@ const infra_js_1 = require("../context-assembly/infra.js");
45
45
  function createCoordinatorDeps(deps) {
46
46
  const { ctx, execFileAsync, consoleService } = deps;
47
47
  let dispatch = null;
48
+ async function fetchAgentResult(sessionHandle) {
49
+ const emptyResult = { recapMarkdown: null, artifacts: [] };
50
+ if (consoleService === null) {
51
+ return emptyResult;
52
+ }
53
+ try {
54
+ const detailResult = await consoleService.getSessionDetail(sessionHandle);
55
+ if (detailResult.isErr())
56
+ return emptyResult;
57
+ const run = detailResult.value.runs[0];
58
+ if (!run)
59
+ return emptyResult;
60
+ const tipNodeId = run.preferredTipNodeId;
61
+ if (!tipNodeId)
62
+ return emptyResult;
63
+ const allNodeIds = run.nodes
64
+ .map((n) => n.nodeId)
65
+ .filter((id) => typeof id === 'string' && id !== '');
66
+ const nodeIdsToFetch = allNodeIds.length > 0 ? allNodeIds : [tipNodeId];
67
+ let recap = null;
68
+ const collectedArtifacts = [];
69
+ for (const nodeId of nodeIdsToFetch) {
70
+ try {
71
+ const nodeResult = await consoleService.getNodeDetail(sessionHandle, nodeId);
72
+ if (nodeResult.isErr())
73
+ continue;
74
+ if (nodeId === tipNodeId)
75
+ recap = nodeResult.value.recapMarkdown;
76
+ if (nodeResult.value.artifacts.length > 0)
77
+ collectedArtifacts.push(...nodeResult.value.artifacts);
78
+ }
79
+ catch {
80
+ continue;
81
+ }
82
+ }
83
+ return { recapMarkdown: recap, artifacts: collectedArtifacts };
84
+ }
85
+ catch (e) {
86
+ const msg = e instanceof Error ? e.message : String(e);
87
+ process.stderr.write(`[WARN coord:reason=exception handle=${sessionHandle.slice(0, 16)}] fetchAgentResult: ${msg}\n`);
88
+ return emptyResult;
89
+ }
90
+ }
91
+ async function fetchChildSessionResult(handle, coordinatorSessionId) {
92
+ if (consoleService === null) {
93
+ process.stderr.write(`[WARN coord:reason=await_degraded handle=${handle.slice(0, 16)}${coordinatorSessionId ? ' parent=' + coordinatorSessionId.slice(0, 16) : ''}] fetchChildSessionResult: ConsoleService unavailable\n`);
94
+ return {
95
+ kind: 'await_degraded',
96
+ message: 'ConsoleService unavailable -- cannot read child session outcome',
97
+ };
98
+ }
99
+ let runStatus = null;
100
+ try {
101
+ const detailResult = await consoleService.getSessionDetail(handle);
102
+ if (detailResult.isErr()) {
103
+ process.stderr.write(`[WARN coord:reason=getSessionDetail_failed handle=${handle.slice(0, 16)}] fetchChildSessionResult: ${String(detailResult.error)}\n`);
104
+ return {
105
+ kind: 'failed',
106
+ reason: 'error',
107
+ message: `Could not read session detail: ${String(detailResult.error)}`,
108
+ };
109
+ }
110
+ const run = detailResult.value.runs[0];
111
+ runStatus = run?.status ?? null;
112
+ }
113
+ catch (e) {
114
+ const msg = e instanceof Error ? e.message : String(e);
115
+ process.stderr.write(`[WARN coord:reason=exception handle=${handle.slice(0, 16)}] fetchChildSessionResult getSessionDetail: ${msg}\n`);
116
+ return { kind: 'failed', reason: 'error', message: `Exception reading session detail: ${msg}` };
117
+ }
118
+ if (runStatus === 'complete' || runStatus === 'complete_with_gaps') {
119
+ const agentResult = await fetchAgentResult(handle);
120
+ return {
121
+ kind: 'success',
122
+ notes: agentResult.recapMarkdown,
123
+ artifacts: agentResult.artifacts,
124
+ };
125
+ }
126
+ if (runStatus === 'blocked') {
127
+ return {
128
+ kind: 'failed',
129
+ reason: 'stuck',
130
+ message: `Child session ${handle.slice(0, 16)} reached blocked state`,
131
+ };
132
+ }
133
+ if (runStatus === null) {
134
+ return {
135
+ kind: 'timed_out',
136
+ message: `Child session ${handle.slice(0, 16)} has no terminal run status (likely timed out)`,
137
+ };
138
+ }
139
+ return {
140
+ kind: 'timed_out',
141
+ message: `Child session ${handle.slice(0, 16)} is still in state '${runStatus}' -- awaitSessions may not have been called`,
142
+ };
143
+ }
48
144
  return {
49
145
  setDispatch(fn) {
50
146
  if (dispatch !== null) {
@@ -53,11 +149,16 @@ function createCoordinatorDeps(deps) {
53
149
  }
54
150
  dispatch = fn;
55
151
  },
56
- spawnSession: async (workflowId, goal, workspace, context, agentConfig) => {
152
+ spawnSession: async (workflowId, goal, workspace, context, agentConfig, parentSessionId) => {
57
153
  if (dispatch === null) {
58
154
  return { kind: 'err', error: 'in-process router not initialized -- coordinator deps not ready' };
59
155
  }
60
- const startResult = await (0, start_js_1.executeStartWorkflow)({ workflowId, workspacePath: workspace, goal }, ctx, { is_autonomous: 'true', workspacePath: workspace, triggerSource: 'daemon' });
156
+ const startResult = await (0, start_js_1.executeStartWorkflow)({ workflowId, workspacePath: workspace, goal }, ctx, {
157
+ is_autonomous: 'true',
158
+ workspacePath: workspace,
159
+ triggerSource: 'daemon',
160
+ ...(parentSessionId !== undefined ? { parentSessionId } : {}),
161
+ });
61
162
  if (startResult.isErr()) {
62
163
  const detail = `${startResult.error.kind}${'message' in startResult.error ? ': ' + startResult.error.message : ''}`;
63
164
  return { kind: 'err', error: `Session creation failed: ${detail}` };
@@ -173,47 +274,113 @@ function createCoordinatorDeps(deps) {
173
274
  };
174
275
  },
175
276
  getAgentResult: async (sessionHandle) => {
176
- const emptyResult = { recapMarkdown: null, artifacts: [] };
177
- if (consoleService === null) {
178
- return emptyResult;
277
+ return fetchAgentResult(sessionHandle);
278
+ },
279
+ getChildSessionResult: async (handle, coordinatorSessionId) => {
280
+ return fetchChildSessionResult(handle, coordinatorSessionId);
281
+ },
282
+ spawnAndAwait: async (workflowId, goal, workspace, opts) => {
283
+ const DEFAULT_TIMEOUT_MS = 15 * 60 * 1000;
284
+ const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
285
+ const coordinatorSessionId = opts?.coordinatorSessionId;
286
+ const agentConfig = opts?.agentConfig;
287
+ if (dispatch === null) {
288
+ return {
289
+ kind: 'failed',
290
+ reason: 'error',
291
+ message: 'spawnAndAwait: in-process router not initialized (setDispatch not called)',
292
+ };
179
293
  }
180
- try {
181
- const detailResult = await consoleService.getSessionDetail(sessionHandle);
182
- if (detailResult.isErr())
183
- return emptyResult;
184
- const run = detailResult.value.runs[0];
185
- if (!run)
186
- return emptyResult;
187
- const tipNodeId = run.preferredTipNodeId;
188
- if (!tipNodeId)
189
- return emptyResult;
190
- const allNodeIds = run.nodes.map((n) => n.nodeId).filter((id) => typeof id === 'string' && id !== '');
191
- const nodeIdsToFetch = allNodeIds.length > 0 ? allNodeIds : [tipNodeId];
192
- let recap = null;
193
- const collectedArtifacts = [];
194
- for (const nodeId of nodeIdsToFetch) {
195
- try {
196
- const nodeResult = await consoleService.getNodeDetail(sessionHandle, nodeId);
197
- if (nodeResult.isErr())
198
- continue;
199
- if (nodeId === tipNodeId) {
200
- recap = nodeResult.value.recapMarkdown;
294
+ const startResult = await (0, start_js_1.executeStartWorkflow)({ workflowId, workspacePath: workspace, goal }, ctx, {
295
+ is_autonomous: 'true',
296
+ workspacePath: workspace,
297
+ triggerSource: 'daemon',
298
+ ...(coordinatorSessionId !== undefined ? { parentSessionId: coordinatorSessionId } : {}),
299
+ });
300
+ if (startResult.isErr()) {
301
+ const detail = `${startResult.error.kind}${'message' in startResult.error ? ': ' + startResult.error.message : ''}`;
302
+ return { kind: 'failed', reason: 'error', message: `Session creation failed: ${detail}` };
303
+ }
304
+ const startContinueToken = startResult.value.response.continueToken;
305
+ let handle;
306
+ if (!startContinueToken) {
307
+ handle = workflowId;
308
+ }
309
+ else {
310
+ const tokenResult = await (0, v2_token_ops_js_1.parseContinueTokenOrFail)(startContinueToken, ctx.v2.tokenCodecPorts, ctx.v2.tokenAliasStore);
311
+ if (tokenResult.isErr()) {
312
+ return {
313
+ kind: 'failed',
314
+ reason: 'error',
315
+ message: `Internal error: could not extract session handle from new session: ${tokenResult.error.message}`,
316
+ };
317
+ }
318
+ handle = tokenResult.value.sessionId;
319
+ const trigger = {
320
+ workflowId,
321
+ goal,
322
+ workspacePath: workspace,
323
+ ...(agentConfig !== undefined ? { agentConfig } : {}),
324
+ };
325
+ const r = startResult.value.response;
326
+ const allocatedSession = {
327
+ continueToken: r.continueToken ?? '',
328
+ checkpointToken: r.checkpointToken,
329
+ firstStepPrompt: r.pending?.prompt ?? '',
330
+ isComplete: r.isComplete,
331
+ triggerSource: 'daemon',
332
+ };
333
+ const source = {
334
+ kind: 'pre_allocated',
335
+ trigger,
336
+ session: allocatedSession,
337
+ };
338
+ dispatch(trigger, source);
339
+ }
340
+ const awaitResult = await (async () => {
341
+ const POLL_INTERVAL_MS = 3000;
342
+ if (consoleService === null) {
343
+ return null;
344
+ }
345
+ const startMs = Date.now();
346
+ const pending = new Set([handle]);
347
+ while (pending.size > 0) {
348
+ const elapsed = Date.now() - startMs;
349
+ if (elapsed >= timeoutMs)
350
+ break;
351
+ for (const h of [...pending]) {
352
+ try {
353
+ const detail = await consoleService.getSessionDetail(h);
354
+ if (detail.isErr())
355
+ continue;
356
+ const run = detail.value.runs[0];
357
+ if (!run)
358
+ continue;
359
+ const status = run.status;
360
+ if (status === 'complete' || status === 'complete_with_gaps') {
361
+ pending.delete(h);
362
+ }
363
+ else if (status === 'blocked') {
364
+ pending.delete(h);
365
+ }
201
366
  }
202
- if (nodeResult.value.artifacts.length > 0) {
203
- collectedArtifacts.push(...nodeResult.value.artifacts);
367
+ catch {
368
+ pending.delete(h);
204
369
  }
205
370
  }
206
- catch {
207
- continue;
371
+ if (pending.size > 0) {
372
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
208
373
  }
209
374
  }
210
- return { recapMarkdown: recap, artifacts: collectedArtifacts };
211
- }
212
- catch (e) {
213
- const msg = e instanceof Error ? e.message : String(e);
214
- process.stderr.write(`[WARN coord:reason=exception handle=${sessionHandle.slice(0, 16)}] getAgentResult: ${msg}\n`);
215
- return emptyResult;
375
+ return handle;
376
+ })();
377
+ if (awaitResult === null) {
378
+ return {
379
+ kind: 'await_degraded',
380
+ message: 'ConsoleService unavailable -- cannot await child session outcome',
381
+ };
216
382
  }
383
+ return fetchChildSessionResult(handle, coordinatorSessionId);
217
384
  },
218
385
  listOpenPRs: async (workspace) => {
219
386
  try {
@@ -27,6 +27,7 @@ export type DeliveryResult = {
27
27
  } | {
28
28
  readonly _tag: 'pr_opened';
29
29
  readonly url: string;
30
+ readonly sha: string;
30
31
  } | {
31
32
  readonly _tag: 'skipped';
32
33
  readonly reason: string;
@@ -342,7 +342,7 @@ async function runDelivery(artifact, workspacePath, flags, execFn) {
342
342
  });
343
343
  }
344
344
  const prUrl = prStdout.trim().split('\n').at(-1)?.trim() ?? '';
345
- return { _tag: 'pr_opened', url: prUrl };
345
+ return { _tag: 'pr_opened', url: prUrl, sha };
346
346
  }
347
347
  function formatExecError(e) {
348
348
  if (e instanceof Error) {
@@ -1,6 +1,8 @@
1
1
  import type { WorkflowRunSuccess } from '../daemon/workflow-runner.js';
2
2
  import type { TriggerDefinition } from './types.js';
3
3
  import type { ExecFn, HandoffArtifact } from './delivery-action.js';
4
+ import type { ExecutionSessionGateV2 } from '../v2/usecases/execution-session-gate.js';
5
+ import type { SessionEventLogAppendStorePortV2 } from '../v2/ports/session-event-log-store.port.js';
4
6
  export type DeliveryStageOutcome = {
5
7
  readonly kind: 'continue';
6
8
  } | {
@@ -9,10 +11,19 @@ export type DeliveryStageOutcome = {
9
11
  };
10
12
  export interface DeliveryStage {
11
13
  readonly name: string;
12
- run(result: WorkflowRunSuccess, trigger: TriggerDefinition, execFn: ExecFn, ctx: PipelineContext): Promise<DeliveryStageOutcome>;
14
+ run(result: WorkflowRunSuccess, trigger: TriggerDefinition, execFn: ExecFn, ctx: PipelineContext, deps?: DeliveryPipelineDeps): Promise<DeliveryStageOutcome>;
13
15
  }
14
16
  export interface PipelineContext {
15
17
  handoffArtifact?: HandoffArtifact;
18
+ commitSha?: string;
19
+ prUrl?: string;
16
20
  }
17
- export declare function runDeliveryPipeline(stages: readonly DeliveryStage[], result: WorkflowRunSuccess, trigger: TriggerDefinition, execFn: ExecFn, triggerId: string): Promise<void>;
21
+ export interface DeliveryPipelineDeps {
22
+ readonly gate: ExecutionSessionGateV2;
23
+ readonly sessionStore: SessionEventLogAppendStorePortV2 & import('../v2/ports/session-event-log-store.port.js').SessionEventLogReadonlyStorePortV2;
24
+ readonly idFactory: {
25
+ readonly mintEventId: () => string;
26
+ };
27
+ }
28
+ export declare function runDeliveryPipeline(stages: readonly DeliveryStage[], result: WorkflowRunSuccess, trigger: TriggerDefinition, execFn: ExecFn, triggerId: string, deps?: DeliveryPipelineDeps): Promise<void>;
18
29
  export declare const DEFAULT_DELIVERY_PIPELINE: readonly DeliveryStage[];
@@ -39,11 +39,16 @@ const fs = __importStar(require("node:fs/promises"));
39
39
  const path = __importStar(require("node:path"));
40
40
  const workflow_runner_js_1 = require("../daemon/workflow-runner.js");
41
41
  const delivery_action_js_1 = require("./delivery-action.js");
42
- async function runDeliveryPipeline(stages, result, trigger, execFn, triggerId) {
42
+ const constants_js_1 = require("../v2/durable-core/constants.js");
43
+ const index_js_1 = require("../v2/durable-core/ids/index.js");
44
+ const session_index_js_1 = require("../v2/durable-core/session-index.js");
45
+ const sorted_event_log_js_1 = require("../v2/durable-core/sorted-event-log.js");
46
+ const neverthrow_1 = require("neverthrow");
47
+ async function runDeliveryPipeline(stages, result, trigger, execFn, triggerId, deps) {
43
48
  const ctx = {};
44
49
  try {
45
50
  for (const stage of stages) {
46
- const outcome = await stage.run(result, trigger, execFn, ctx);
51
+ const outcome = await stage.run(result, trigger, execFn, ctx, deps);
47
52
  if (outcome.kind === 'stop') {
48
53
  console.log(`[DeliveryPipeline] Stage "${stage.name}" stopped pipeline: triggerId=${triggerId} reason=${outcome.reason}`);
49
54
  return;
@@ -96,9 +101,12 @@ const gitDeliveryStage = {
96
101
  switch (deliveryResult._tag) {
97
102
  case 'committed':
98
103
  console.log(`[DeliveryPipeline] Delivery committed: triggerId=${trigger.id} sha=${deliveryResult.sha}`);
104
+ ctx.commitSha = deliveryResult.sha;
99
105
  break;
100
106
  case 'pr_opened':
101
- console.log(`[DeliveryPipeline] Delivery PR opened: triggerId=${trigger.id} url=${deliveryResult.url}`);
107
+ console.log(`[DeliveryPipeline] Delivery PR opened: triggerId=${trigger.id} url=${deliveryResult.url} sha=${deliveryResult.sha}`);
108
+ ctx.commitSha = deliveryResult.sha;
109
+ ctx.prUrl = deliveryResult.url;
102
110
  break;
103
111
  case 'skipped':
104
112
  console.log(`[DeliveryPipeline] Delivery skipped: triggerId=${trigger.id} reason=${deliveryResult.reason}`);
@@ -111,6 +119,52 @@ const gitDeliveryStage = {
111
119
  return { kind: 'continue' };
112
120
  },
113
121
  };
122
+ const recordCommitShasStage = {
123
+ name: 'recordCommitShas',
124
+ async run(result, _trigger, _execFn, ctx, deps) {
125
+ const { sessionId } = result;
126
+ if (!sessionId || !ctx.commitSha || !deps) {
127
+ return { kind: 'continue' };
128
+ }
129
+ try {
130
+ const sid = (0, index_js_1.asSessionId)(sessionId);
131
+ const shas = [ctx.commitSha];
132
+ const prUrl = ctx.prUrl;
133
+ await deps.gate.withHealthySessionLock(sid, (lock) => deps.sessionStore.load(sid).andThen((truth) => {
134
+ const sortedResult = (0, sorted_event_log_js_1.asSortedEventLog)(truth.events);
135
+ if (sortedResult.isErr()) {
136
+ return (0, neverthrow_1.okAsync)(undefined);
137
+ }
138
+ const index = (0, session_index_js_1.buildSessionIndex)(sortedResult.value);
139
+ const runCompleted = truth.events.find(e => e.kind === 'run_completed');
140
+ const runId = runCompleted?.scope.runId;
141
+ if (!runId) {
142
+ return (0, neverthrow_1.okAsync)(undefined);
143
+ }
144
+ const event = {
145
+ v: 1,
146
+ eventId: deps.idFactory.mintEventId(),
147
+ eventIndex: index.nextEventIndex,
148
+ sessionId,
149
+ kind: constants_js_1.EVENT_KIND.DELIVERY_RECORDED,
150
+ dedupeKey: `delivery-recorded:${sessionId}:${runId}`,
151
+ scope: { runId },
152
+ data: { shas, ...(prUrl ? { prUrl } : {}) },
153
+ timestampMs: Date.now(),
154
+ };
155
+ return deps.sessionStore.append(lock, { events: [event], snapshotPins: [] });
156
+ })).match(() => {
157
+ console.log(`[DeliveryPipeline] Commit SHAs recorded: sessionId=${sessionId} shas=${shas.join(',')}`);
158
+ }, (err) => {
159
+ console.warn(`[DeliveryPipeline] Could not record commit SHAs: sessionId=${sessionId} err=${JSON.stringify(err)}`);
160
+ });
161
+ }
162
+ catch (err) {
163
+ console.warn(`[DeliveryPipeline] Unexpected error in recordCommitShasStage: ${err instanceof Error ? err.message : String(err)}`);
164
+ }
165
+ return { kind: 'continue' };
166
+ },
167
+ };
114
168
  const cleanupWorktreeStage = {
115
169
  name: 'cleanupWorktree',
116
170
  async run(result, trigger, execFn, _ctx) {
@@ -143,6 +197,7 @@ const deleteSidecarStage = {
143
197
  exports.DEFAULT_DELIVERY_PIPELINE = [
144
198
  parseHandoffStage,
145
199
  gitDeliveryStage,
200
+ recordCommitShasStage,
146
201
  cleanupWorktreeStage,
147
202
  deleteSidecarStage,
148
203
  ];
@@ -118,7 +118,7 @@ function validateHmac(rawBody, secret, headerValue) {
118
118
  }
119
119
  return crypto.timingSafeEqual(Buffer.from(expected, 'utf8'), Buffer.from(received, 'utf8'));
120
120
  }
121
- async function maybeRunDelivery(triggerId, trigger, result, execFn) {
121
+ async function maybeRunDelivery(triggerId, trigger, result, execFn, deps) {
122
122
  if (result._tag !== 'success')
123
123
  return;
124
124
  if (result.lastStepNotes === undefined) {
@@ -131,7 +131,7 @@ async function maybeRunDelivery(triggerId, trigger, result, execFn) {
131
131
  }
132
132
  if (trigger.autoCommit !== true)
133
133
  return;
134
- await (0, delivery_pipeline_js_1.runDeliveryPipeline)(delivery_pipeline_js_1.DEFAULT_DELIVERY_PIPELINE, result, trigger, execFn, triggerId);
134
+ await (0, delivery_pipeline_js_1.runDeliveryPipeline)(delivery_pipeline_js_1.DEFAULT_DELIVERY_PIPELINE, result, trigger, execFn, triggerId, deps);
135
135
  }
136
136
  class Semaphore {
137
137
  constructor(max) {
@@ -340,7 +340,10 @@ class TriggerRouter {
340
340
  (0, assert_never_js_1.assertNever)(result);
341
341
  }
342
342
  this.notificationService?.notify(result, workflowTrigger.goal);
343
- await maybeRunDelivery(trigger.id, trigger, originalResult, this.execFn);
343
+ const deliveryDeps = this.ctx.v2
344
+ ? { gate: this.ctx.v2.gate, sessionStore: this.ctx.v2.sessionStore, idFactory: this.ctx.v2.idFactory }
345
+ : undefined;
346
+ await maybeRunDelivery(trigger.id, trigger, originalResult, this.execFn, deliveryDeps);
344
347
  });
345
348
  return { _tag: 'enqueued', triggerId: trigger.id };
346
349
  }
@@ -38,6 +38,7 @@ export declare const EVENT_KIND: {
38
38
  readonly DIVERGENCE_RECORDED: "divergence_recorded";
39
39
  readonly DECISION_TRACE_APPENDED: "decision_trace_appended";
40
40
  readonly RUN_COMPLETED: "run_completed";
41
+ readonly DELIVERY_RECORDED: "delivery_recorded";
41
42
  };
42
43
  export type EventKindV1 = typeof EVENT_KIND[keyof typeof EVENT_KIND];
43
44
  export declare const OUTPUT_CHANNEL: {
@@ -41,6 +41,7 @@ exports.EVENT_KIND = {
41
41
  DIVERGENCE_RECORDED: 'divergence_recorded',
42
42
  DECISION_TRACE_APPENDED: 'decision_trace_appended',
43
43
  RUN_COMPLETED: 'run_completed',
44
+ DELIVERY_RECORDED: 'delivery_recorded',
44
45
  };
45
46
  exports.OUTPUT_CHANNEL = {
46
47
  RECAP: 'recap',