@exaudeus/workrail 3.39.0 → 3.41.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 (97) hide show
  1. package/dist/cli/commands/init.js +0 -3
  2. package/dist/cli-worktrain.js +58 -26
  3. package/dist/cli.js +0 -18
  4. package/dist/config/app-config.d.ts +0 -16
  5. package/dist/config/app-config.js +0 -14
  6. package/dist/config/config-file.js +0 -3
  7. package/dist/console-ui/assets/index-CQt4UhPB.js +28 -0
  8. package/dist/console-ui/assets/index-DGj8EsFR.css +1 -0
  9. package/dist/console-ui/index.html +2 -2
  10. package/dist/coordinators/pr-review.d.ts +23 -1
  11. package/dist/coordinators/pr-review.js +224 -5
  12. package/dist/daemon/daemon-events.d.ts +9 -1
  13. package/dist/daemon/soul-template.d.ts +2 -2
  14. package/dist/daemon/soul-template.js +11 -1
  15. package/dist/daemon/workflow-runner.d.ts +17 -3
  16. package/dist/daemon/workflow-runner.js +401 -28
  17. package/dist/di/container.js +1 -25
  18. package/dist/di/tokens.d.ts +0 -3
  19. package/dist/di/tokens.js +0 -3
  20. package/dist/engine/engine-factory.js +0 -1
  21. package/dist/infrastructure/console-defaults.d.ts +1 -0
  22. package/dist/infrastructure/console-defaults.js +4 -0
  23. package/dist/infrastructure/session/index.d.ts +0 -1
  24. package/dist/infrastructure/session/index.js +1 -3
  25. package/dist/manifest.json +124 -124
  26. package/dist/mcp/handlers/session.d.ts +1 -0
  27. package/dist/mcp/handlers/session.js +61 -13
  28. package/dist/mcp/output-schemas.d.ts +10 -10
  29. package/dist/mcp/server.js +1 -18
  30. package/dist/mcp/tools.d.ts +12 -12
  31. package/dist/mcp/transports/http-entry.js +0 -2
  32. package/dist/mcp/transports/stdio-entry.js +1 -2
  33. package/dist/mcp/types.d.ts +0 -2
  34. package/dist/trigger/daemon-console.d.ts +2 -0
  35. package/dist/trigger/daemon-console.js +1 -1
  36. package/dist/trigger/trigger-listener.d.ts +2 -0
  37. package/dist/trigger/trigger-listener.js +3 -1
  38. package/dist/trigger/trigger-router.d.ts +4 -3
  39. package/dist/trigger/trigger-router.js +13 -5
  40. package/dist/trigger/trigger-store.js +17 -4
  41. package/dist/types/workflow-source.d.ts +0 -1
  42. package/dist/types/workflow-source.js +3 -6
  43. package/dist/types/workflow.d.ts +1 -1
  44. package/dist/types/workflow.js +1 -2
  45. package/dist/v2/durable-core/domain/artifact-contract-validator.js +66 -0
  46. package/dist/v2/durable-core/schemas/artifacts/coordinator-signal.d.ts +25 -0
  47. package/dist/v2/durable-core/schemas/artifacts/coordinator-signal.js +31 -0
  48. package/dist/v2/durable-core/schemas/artifacts/index.d.ts +3 -1
  49. package/dist/v2/durable-core/schemas/artifacts/index.js +14 -1
  50. package/dist/v2/durable-core/schemas/artifacts/review-verdict.d.ts +41 -0
  51. package/dist/v2/durable-core/schemas/artifacts/review-verdict.js +30 -0
  52. package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +236 -236
  53. package/dist/v2/durable-core/schemas/session/events.d.ts +50 -50
  54. package/dist/v2/durable-core/schemas/session/gaps.d.ts +2 -2
  55. package/dist/v2/durable-core/schemas/session/manifest.d.ts +4 -4
  56. package/dist/v2/durable-core/schemas/session/outputs.d.ts +8 -8
  57. package/dist/v2/usecases/console-routes.d.ts +2 -1
  58. package/dist/v2/usecases/console-routes.js +207 -5
  59. package/dist/v2/usecases/console-service.js +14 -0
  60. package/dist/v2/usecases/console-types.d.ts +1 -0
  61. package/docs/authoring.md +16 -16
  62. package/docs/design/coordinator-artifact-protocol-design-candidates.md +155 -0
  63. package/docs/design/coordinator-artifact-protocol-design-review.md +103 -0
  64. package/docs/design/coordinator-artifact-protocol-implementation-plan.md +259 -0
  65. package/docs/design/coordinator-message-queue-drain-plan.md +241 -0
  66. package/docs/design/coordinator-message-queue-drain-review.md +120 -0
  67. package/docs/design/coordinator-message-queue-drain.md +289 -0
  68. package/docs/design/shaping-workflow-external-research.md +119 -0
  69. package/docs/discovery/late-bound-goals-impl-plan.md +147 -0
  70. package/docs/discovery/late-bound-goals-review.md +82 -0
  71. package/docs/discovery/late-bound-goals.md +118 -0
  72. package/docs/discovery/steer-endpoint-design-candidates.md +288 -0
  73. package/docs/discovery/steer-endpoint-design-review-findings.md +104 -0
  74. package/docs/discovery/steer-endpoint-implementation-plan.md +284 -0
  75. package/docs/ideas/backlog.md +447 -97
  76. package/docs/ideas/design-candidates-console-session-tree-impl.md +64 -0
  77. package/docs/ideas/design-candidates-session-tree-view.md +196 -0
  78. package/docs/ideas/design-review-findings-console-session-tree-impl.md +75 -0
  79. package/docs/ideas/design-review-findings-session-tree-view.md +88 -0
  80. package/docs/ideas/implementation_plan_session_tree_view.md +238 -0
  81. package/package.json +2 -1
  82. package/spec/authoring-spec.json +16 -16
  83. package/spec/shape.schema.json +178 -0
  84. package/spec/workflow-tags.json +232 -47
  85. package/workflows/coding-task-workflow-agentic.json +491 -480
  86. package/workflows/mr-review-workflow.agentic.v2.json +5 -1
  87. package/workflows/wr.shaping.json +182 -0
  88. package/dist/console-ui/assets/index-3oXZ_A9m.js +0 -28
  89. package/dist/console-ui/assets/index-8dh0Psu-.css +0 -1
  90. package/dist/infrastructure/session/DashboardHeartbeat.d.ts +0 -8
  91. package/dist/infrastructure/session/DashboardHeartbeat.js +0 -39
  92. package/dist/infrastructure/session/DashboardLockRelease.d.ts +0 -2
  93. package/dist/infrastructure/session/DashboardLockRelease.js +0 -29
  94. package/dist/infrastructure/session/HttpServer.d.ts +0 -60
  95. package/dist/infrastructure/session/HttpServer.js +0 -912
  96. package/workflows/coding-task-workflow-agentic.lean.v2.json +0 -648
  97. package/workflows/coding-task-workflow-agentic.v2.json +0 -324
@@ -1,10 +1,47 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.handleCreateSession = handleCreateSession;
4
37
  exports.handleUpdateSession = handleUpdateSession;
5
38
  exports.handleReadSession = handleReadSession;
6
39
  exports.handleOpenDashboard = handleOpenDashboard;
40
+ const fs = __importStar(require("fs/promises"));
41
+ const path = __importStar(require("path"));
42
+ const os = __importStar(require("os"));
7
43
  const types_js_1 = require("../types.js");
44
+ const console_defaults_js_1 = require("../../infrastructure/console-defaults.js");
8
45
  const SESSION_SCHEMA_OVERVIEW = {
9
46
  description: 'Bug Investigation Session Data Structure',
10
47
  mainSections: {
@@ -39,7 +76,7 @@ const SESSION_SCHEMA_OVERVIEW = {
39
76
  fullSchemaDoc: 'See docs/dashboard-architecture/bug-investigation-session-schema.md for complete details',
40
77
  };
41
78
  function requireSessionTools(ctx) {
42
- if (!ctx.sessionManager || !ctx.httpServer) {
79
+ if (!ctx.sessionManager) {
43
80
  return (0, types_js_1.errNotRetryable)('PRECONDITION_FAILED', 'Session tools are not enabled', { suggestion: 'Set WORKRAIL_ENABLE_SESSION_TOOLS=true to enable session tools' });
44
81
  }
45
82
  return null;
@@ -49,14 +86,12 @@ async function handleCreateSession(input, ctx) {
49
86
  if (guardError)
50
87
  return guardError;
51
88
  const sessionManager = ctx.sessionManager;
52
- const httpServer = ctx.httpServer;
53
89
  const res = await sessionManager.createSession(input.workflowId, input.sessionId, input.initialData);
54
90
  if (res.isErr()) {
55
91
  return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', res.error.message);
56
92
  }
57
93
  const session = res.value;
58
- const baseUrl = httpServer.getBaseUrl();
59
- const dashboardUrl = baseUrl ? `${baseUrl}?session=${input.sessionId}` : null;
94
+ const dashboardUrl = `http://localhost:${console_defaults_js_1.DEFAULT_CONSOLE_PORT}?session=${input.sessionId}`;
60
95
  const payload = {
61
96
  sessionId: session.id,
62
97
  workflowId: session.workflowId,
@@ -110,17 +145,30 @@ async function handleReadSession(input, ctx) {
110
145
  };
111
146
  return (0, types_js_1.success)(payload);
112
147
  }
148
+ async function readConsoleLockPort() {
149
+ const lockPath = path.join(os.homedir(), '.workrail', 'daemon-console.lock');
150
+ try {
151
+ const raw = await fs.readFile(lockPath, 'utf-8');
152
+ const data = JSON.parse(raw);
153
+ if (data !== null && typeof data === 'object' && 'port' in data && typeof data.port === 'number') {
154
+ return data.port;
155
+ }
156
+ return console_defaults_js_1.DEFAULT_CONSOLE_PORT;
157
+ }
158
+ catch {
159
+ return console_defaults_js_1.DEFAULT_CONSOLE_PORT;
160
+ }
161
+ }
113
162
  async function handleOpenDashboard(input, ctx) {
114
163
  const guardError = requireSessionTools(ctx);
115
164
  if (guardError)
116
165
  return guardError;
117
- const httpServer = ctx.httpServer;
118
- try {
119
- const url = await httpServer.openDashboard(input.sessionId);
120
- const payload = { url };
121
- return (0, types_js_1.success)(payload);
122
- }
123
- catch (err) {
124
- return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', err instanceof Error ? err.message : 'Failed to open dashboard');
125
- }
166
+ const port = await readConsoleLockPort();
167
+ const sessionQuery = input.sessionId ? `?session=${input.sessionId}` : '';
168
+ const url = `http://localhost:${port}${sessionQuery}`;
169
+ const payload = {
170
+ url,
171
+ guidance: "Run 'worktrain console' to start the dashboard UI if it's not already running.",
172
+ };
173
+ return (0, types_js_1.success)(payload);
126
174
  }
@@ -2257,9 +2257,9 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
2257
2257
  tool: "continue_workflow";
2258
2258
  }>;
2259
2259
  }, "strip", z.ZodTypeAny, {
2260
- confidence: "strong" | "weak" | "medium";
2261
- workflowId: string;
2260
+ confidence: "medium" | "strong" | "weak";
2262
2261
  sessionId: string;
2262
+ workflowId: string;
2263
2263
  runId: string;
2264
2264
  isComplete: boolean;
2265
2265
  sessionTitle: string | null;
@@ -2278,9 +2278,9 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
2278
2278
  pendingStepId: string | null;
2279
2279
  whyMatched: ("matched_exact_id" | "matched_notes" | "matched_notes_partial" | "matched_workflow_id" | "matched_head_sha" | "matched_branch" | "matched_repo_root" | "recency_fallback")[];
2280
2280
  }, {
2281
- confidence: "strong" | "weak" | "medium";
2282
- workflowId: string;
2281
+ confidence: "medium" | "strong" | "weak";
2283
2282
  sessionId: string;
2283
+ workflowId: string;
2284
2284
  runId: string;
2285
2285
  isComplete: boolean;
2286
2286
  sessionTitle: string | null;
@@ -2302,9 +2302,9 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
2302
2302
  totalEligible: z.ZodNumber;
2303
2303
  }, "strip", z.ZodTypeAny, {
2304
2304
  candidates: {
2305
- confidence: "strong" | "weak" | "medium";
2306
- workflowId: string;
2305
+ confidence: "medium" | "strong" | "weak";
2307
2306
  sessionId: string;
2307
+ workflowId: string;
2308
2308
  runId: string;
2309
2309
  isComplete: boolean;
2310
2310
  sessionTitle: string | null;
@@ -2326,9 +2326,9 @@ export declare const V2ResumeSessionOutputSchema: z.ZodObject<{
2326
2326
  totalEligible: number;
2327
2327
  }, {
2328
2328
  candidates: {
2329
- confidence: "strong" | "weak" | "medium";
2330
- workflowId: string;
2329
+ confidence: "medium" | "strong" | "weak";
2331
2330
  sessionId: string;
2331
+ workflowId: string;
2332
2332
  runId: string;
2333
2333
  isComplete: boolean;
2334
2334
  sessionTitle: string | null;
@@ -2545,14 +2545,14 @@ export declare const CreateSessionOutputSchema: z.ZodObject<{
2545
2545
  createdAt: z.ZodString;
2546
2546
  }, "strip", z.ZodTypeAny, {
2547
2547
  path: string;
2548
- workflowId: string;
2549
2548
  sessionId: string;
2549
+ workflowId: string;
2550
2550
  dashboardUrl: string | null;
2551
2551
  createdAt: string;
2552
2552
  }, {
2553
2553
  path: string;
2554
- workflowId: string;
2555
2554
  sessionId: string;
2555
+ workflowId: string;
2556
2556
  dashboardUrl: string | null;
2557
2557
  createdAt: string;
2558
2558
  }>;
@@ -59,11 +59,9 @@ async function createToolContext() {
59
59
  const workflowService = container_js_1.container.resolve(tokens_js_1.DI.Services.Workflow);
60
60
  const featureFlags = container_js_1.container.resolve(tokens_js_1.DI.Infra.FeatureFlags);
61
61
  let sessionManager = null;
62
- let httpServer = null;
63
62
  if (featureFlags.isEnabled('sessionTools')) {
64
63
  sessionManager = container_js_1.container.resolve(tokens_js_1.DI.Infra.SessionManager);
65
- httpServer = container_js_1.container.resolve(tokens_js_1.DI.Infra.HttpServer);
66
- console.error('[FeatureFlags] Session tools enabled');
64
+ console.error('[FeatureFlags] Session tools enabled (use \'worktrain console\' for the dashboard UI)');
67
65
  }
68
66
  else {
69
67
  console.error('[FeatureFlags] Session tools disabled (enable with WORKRAIL_ENABLE_SESSION_TOOLS=true)');
@@ -150,7 +148,6 @@ async function createToolContext() {
150
148
  workflowService,
151
149
  featureFlags,
152
150
  sessionManager,
153
- httpServer,
154
151
  v2,
155
152
  };
156
153
  }
@@ -178,20 +175,6 @@ async function composeServer() {
178
175
  const toolCallsPerfFile = ctx.v2?.dataDir
179
176
  ? path.join(ctx.v2.dataDir.perfDir(), 'tool-calls.jsonl')
180
177
  : null;
181
- if (ctx.v2 && ctx.httpServer && ctx.v2.dataDir && ctx.v2.directoryListing) {
182
- const { ConsoleService } = await Promise.resolve().then(() => __importStar(require('../v2/usecases/console-service.js')));
183
- const { mountConsoleRoutes } = await Promise.resolve().then(() => __importStar(require('../v2/usecases/console-routes.js')));
184
- const consoleService = new ConsoleService({
185
- directoryListing: ctx.v2.directoryListing,
186
- dataDir: ctx.v2.dataDir,
187
- sessionStore: ctx.v2.sessionStore,
188
- snapshotStore: ctx.v2.snapshotStore,
189
- pinnedWorkflowStore: ctx.v2.pinnedStore,
190
- });
191
- ctx.httpServer.mountRoutes((app) => mountConsoleRoutes(app, consoleService, ctx.workflowService, timingRingBuffer, toolCallsPerfFile ?? undefined, serverVersion, ctx.v2 ? ctx : undefined));
192
- console.error('[Console] v2 Console API routes mounted at /api/v2/');
193
- }
194
- ctx.httpServer?.finalize();
195
178
  const descriptionProvider = container_js_1.container.resolve(tokens_js_1.DI.Mcp.DescriptionProvider);
196
179
  const buildTool = (0, tool_factory_js_1.createToolFactory)(descriptionProvider);
197
180
  const workflowEdition = (0, workflow_tool_edition_selector_js_1.selectWorkflowToolEdition)(ctx.featureFlags, buildTool);
@@ -61,12 +61,12 @@ export declare const CreateSessionInput: z.ZodObject<{
61
61
  sessionId: z.ZodString;
62
62
  initialData: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
63
63
  }, "strip", z.ZodTypeAny, {
64
- workflowId: string;
65
64
  sessionId: string;
65
+ workflowId: string;
66
66
  initialData: Record<string, unknown>;
67
67
  }, {
68
- workflowId: string;
69
68
  sessionId: string;
69
+ workflowId: string;
70
70
  initialData?: Record<string, unknown> | undefined;
71
71
  }>;
72
72
  export type CreateSessionInput = z.infer<typeof CreateSessionInput>;
@@ -75,12 +75,12 @@ export declare const UpdateSessionInput: z.ZodObject<{
75
75
  sessionId: z.ZodString;
76
76
  updates: z.ZodRecord<z.ZodString, z.ZodUnknown>;
77
77
  }, "strip", z.ZodTypeAny, {
78
- workflowId: string;
79
78
  sessionId: string;
79
+ workflowId: string;
80
80
  updates: Record<string, unknown>;
81
81
  }, {
82
- workflowId: string;
83
82
  sessionId: string;
83
+ workflowId: string;
84
84
  updates: Record<string, unknown>;
85
85
  }>;
86
86
  export type UpdateSessionInput = z.infer<typeof UpdateSessionInput>;
@@ -89,12 +89,12 @@ export declare const ReadSessionInput: z.ZodObject<{
89
89
  sessionId: z.ZodString;
90
90
  path: z.ZodOptional<z.ZodString>;
91
91
  }, "strip", z.ZodTypeAny, {
92
- workflowId: string;
93
92
  sessionId: string;
93
+ workflowId: string;
94
94
  path?: string | undefined;
95
95
  }, {
96
- workflowId: string;
97
96
  sessionId: string;
97
+ workflowId: string;
98
98
  path?: string | undefined;
99
99
  }>;
100
100
  export type ReadSessionInput = z.infer<typeof ReadSessionInput>;
@@ -116,36 +116,36 @@ export declare const sessionTools: readonly [ToolDefinition<z.ZodObject<{
116
116
  sessionId: z.ZodString;
117
117
  initialData: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
118
118
  }, "strip", z.ZodTypeAny, {
119
- workflowId: string;
120
119
  sessionId: string;
120
+ workflowId: string;
121
121
  initialData: Record<string, unknown>;
122
122
  }, {
123
- workflowId: string;
124
123
  sessionId: string;
124
+ workflowId: string;
125
125
  initialData?: Record<string, unknown> | undefined;
126
126
  }>>, ToolDefinition<z.ZodObject<{
127
127
  workflowId: z.ZodString;
128
128
  sessionId: z.ZodString;
129
129
  updates: z.ZodRecord<z.ZodString, z.ZodUnknown>;
130
130
  }, "strip", z.ZodTypeAny, {
131
- workflowId: string;
132
131
  sessionId: string;
132
+ workflowId: string;
133
133
  updates: Record<string, unknown>;
134
134
  }, {
135
- workflowId: string;
136
135
  sessionId: string;
136
+ workflowId: string;
137
137
  updates: Record<string, unknown>;
138
138
  }>>, ToolDefinition<z.ZodObject<{
139
139
  workflowId: z.ZodString;
140
140
  sessionId: z.ZodString;
141
141
  path: z.ZodOptional<z.ZodString>;
142
142
  }, "strip", z.ZodTypeAny, {
143
- workflowId: string;
144
143
  sessionId: string;
144
+ workflowId: string;
145
145
  path?: string | undefined;
146
146
  }, {
147
- workflowId: string;
148
147
  sessionId: string;
148
+ workflowId: string;
149
149
  path?: string | undefined;
150
150
  }>>, ToolDefinition<z.ZodObject<{
151
151
  sessionId: z.ZodOptional<z.ZodString>;
@@ -52,7 +52,6 @@ async function startHttpServer(port) {
52
52
  const listener = await (0, http_listener_js_1.bindWithPortFallback)(port, scanEnd);
53
53
  (0, fatal_exit_js_1.registerGracefulShutdown)(async () => {
54
54
  await listener.stop();
55
- await ctx.httpServer?.stop();
56
55
  });
57
56
  const { StreamableHTTPServerTransport } = await Promise.resolve().then(() => __importStar(require('@modelcontextprotocol/sdk/server/streamableHttp.js')));
58
57
  const transport = new StreamableHTTPServerTransport({
@@ -73,7 +72,6 @@ async function startHttpServer(port) {
73
72
  (0, shutdown_hooks_js_1.wireShutdownHooks)({
74
73
  onBeforeTerminate: async () => {
75
74
  await listener.stop();
76
- await ctx.httpServer?.stop();
77
75
  },
78
76
  });
79
77
  }
@@ -50,7 +50,7 @@ async function startStdioServer() {
50
50
  (0, fatal_exit_js_1.registerFatalHandlers)('stdio');
51
51
  (0, fatal_exit_js_1.logStartup)('stdio');
52
52
  const { server, ctx, rootsManager } = await (0, server_js_1.composeServer)();
53
- (0, fatal_exit_js_1.registerGracefulShutdown)(async () => { await ctx.httpServer?.stop(); });
53
+ (0, fatal_exit_js_1.registerGracefulShutdown)(async () => { });
54
54
  const { StdioServerTransport } = await Promise.resolve().then(() => __importStar(require('@modelcontextprotocol/sdk/server/stdio.js')));
55
55
  const { RootsListChangedNotificationSchema, } = await Promise.resolve().then(() => __importStar(require('@modelcontextprotocol/sdk/types.js')));
56
56
  server.setNotificationHandler(RootsListChangedNotificationSchema, async () => {
@@ -100,7 +100,6 @@ async function startStdioServer() {
100
100
  (0, shutdown_hooks_js_1.wireStdinShutdown)();
101
101
  (0, shutdown_hooks_js_1.wireShutdownHooks)({
102
102
  onBeforeTerminate: async () => {
103
- await ctx.httpServer?.stop();
104
103
  },
105
104
  });
106
105
  }
@@ -1,7 +1,6 @@
1
1
  import type { WorkflowService } from '../application/services/workflow-service.js';
2
2
  import type { IFeatureFlagProvider } from '../config/feature-flags.js';
3
3
  import type { SessionManager } from '../infrastructure/session/SessionManager.js';
4
- import type { HttpServer } from '../infrastructure/session/HttpServer.js';
5
4
  import type { SessionHealthV2 } from '../v2/durable-core/schemas/session/session-health.js';
6
5
  import type { ExecutionSessionGateV2 } from '../v2/usecases/execution-session-gate.js';
7
6
  import type { SessionEventLogAppendStorePortV2, SessionEventLogReadonlyStorePortV2 } from '../v2/ports/session-event-log-store.port.js';
@@ -75,7 +74,6 @@ export interface ToolContext {
75
74
  readonly workflowService: WorkflowService;
76
75
  readonly featureFlags: IFeatureFlagProvider;
77
76
  readonly sessionManager: SessionManager | null;
78
- readonly httpServer: HttpServer | null;
79
77
  readonly v2: V2Dependencies | null;
80
78
  }
81
79
  export interface V2ToolContext extends ToolContext {
@@ -2,6 +2,7 @@ import 'reflect-metadata';
2
2
  import type { V2ToolContext } from '../mcp/types.js';
3
3
  import type { TriggerRouter } from './trigger-router.js';
4
4
  import type { WorkflowService } from '../application/services/workflow-service.js';
5
+ import type { SteerRegistry } from '../daemon/workflow-runner.js';
5
6
  import type { Result } from '../runtime/result.js';
6
7
  export interface DaemonConsoleHandle {
7
8
  readonly port: number;
@@ -20,5 +21,6 @@ export interface StartDaemonConsoleOptions {
20
21
  readonly serverVersion?: string;
21
22
  readonly workflowService?: WorkflowService;
22
23
  readonly lockFilePath?: string;
24
+ readonly steerRegistry?: SteerRegistry;
23
25
  }
24
26
  export declare function startDaemonConsole(ctx: V2ToolContext, options?: StartDaemonConsoleOptions): Promise<Result<DaemonConsoleHandle, DaemonConsoleError>>;
@@ -68,7 +68,7 @@ async function startDaemonConsole(ctx, options = {}) {
68
68
  snapshotStore: ctx.v2.snapshotStore,
69
69
  pinnedWorkflowStore: ctx.v2.pinnedStore,
70
70
  });
71
- const stopWatcher = mountConsoleRoutes(app, consoleService, options.workflowService, undefined, undefined, options.serverVersion, ctx, options.triggerRouter);
71
+ const stopWatcher = mountConsoleRoutes(app, consoleService, options.workflowService, undefined, undefined, options.serverVersion, ctx, options.triggerRouter, options.steerRegistry);
72
72
  app.use((req, res) => {
73
73
  res.status(404).json({ success: false, error: 'Not found', path: req.path });
74
74
  });
@@ -3,6 +3,7 @@ import express from 'express';
3
3
  import type { V2ToolContext } from '../mcp/types.js';
4
4
  import type { TriggerStoreError } from './trigger-store.js';
5
5
  import { TriggerRouter, type RunWorkflowFn } from './trigger-router.js';
6
+ import type { SteerRegistry } from '../daemon/workflow-runner.js';
6
7
  import type { WorkspaceConfig } from './types.js';
7
8
  import type { DaemonEventEmitter } from '../daemon/daemon-events.js';
8
9
  import type { FetchFn } from './adapters/gitlab-poller.js';
@@ -17,6 +18,7 @@ export type TriggerListenerError = TriggerStoreError | {
17
18
  export interface TriggerListenerHandle {
18
19
  readonly port: number;
19
20
  readonly router: TriggerRouter;
21
+ readonly steerRegistry: SteerRegistry;
20
22
  stop(): Promise<void>;
21
23
  }
22
24
  export interface StartTriggerListenerOptions {
@@ -183,8 +183,9 @@ async function startTriggerListener(ctx, options) {
183
183
  const notificationService = (notifyMacOs || (notifyWebhook !== undefined && notifyWebhook !== ''))
184
184
  ? new notification_service_js_1.NotificationService({ macOs: notifyMacOs, webhookUrl: notifyWebhook })
185
185
  : undefined;
186
+ const steerRegistry = new Map();
186
187
  const runWorkflowFn = options.runWorkflowFn ?? workflow_runner_js_1.runWorkflow;
187
- const router = new trigger_router_js_1.TriggerRouter(triggerIndex, ctx, apiKey, runWorkflowFn, undefined, maxConcurrentSessions, options.emitter, notificationService);
188
+ const router = new trigger_router_js_1.TriggerRouter(triggerIndex, ctx, apiKey, runWorkflowFn, undefined, maxConcurrentSessions, options.emitter, notificationService, steerRegistry);
188
189
  const app = createTriggerApp(router);
189
190
  const allTriggers = [...triggerIndex.values()];
190
191
  const polledEventStore = new polled_event_store_js_1.PolledEventStore(env);
@@ -219,6 +220,7 @@ async function startTriggerListener(ctx, options) {
219
220
  resolve({
220
221
  port: actualPort,
221
222
  router,
223
+ steerRegistry,
222
224
  stop: async () => {
223
225
  pollingScheduler.stop();
224
226
  return new Promise((res, rej) => {
@@ -1,4 +1,4 @@
1
- import type { WorkflowTrigger, WorkflowRunResult } from '../daemon/workflow-runner.js';
1
+ import type { WorkflowTrigger, WorkflowRunResult, SteerRegistry } from '../daemon/workflow-runner.js';
2
2
  import type { V2ToolContext } from '../mcp/types.js';
3
3
  import type { TriggerDefinition, WebhookEvent } from './types.js';
4
4
  import type { ExecFn } from './delivery-action.js';
@@ -20,7 +20,7 @@ export type RouteResult = {
20
20
  readonly _tag: 'error';
21
21
  readonly error: RouteError;
22
22
  };
23
- export type RunWorkflowFn = (trigger: WorkflowTrigger, ctx: V2ToolContext, apiKey: string, daemonRegistry?: import('../v2/infra/in-memory/daemon-registry/index.js').DaemonRegistry, emitter?: DaemonEventEmitter) => Promise<WorkflowRunResult>;
23
+ export type RunWorkflowFn = (trigger: WorkflowTrigger, ctx: V2ToolContext, apiKey: string, daemonRegistry?: import('../v2/infra/in-memory/daemon-registry/index.js').DaemonRegistry, emitter?: DaemonEventEmitter, steerRegistry?: SteerRegistry) => Promise<WorkflowRunResult>;
24
24
  export declare function interpolateGoalTemplate(template: string, staticGoal: string, payload: Readonly<Record<string, unknown>>, triggerId: string): string;
25
25
  export declare class TriggerRouter {
26
26
  private readonly index;
@@ -33,7 +33,8 @@ export declare class TriggerRouter {
33
33
  private readonly _maxConcurrentSessions;
34
34
  private readonly emitter;
35
35
  private readonly notificationService;
36
- constructor(index: ReadonlyMap<string, TriggerDefinition>, ctx: V2ToolContext, apiKey: string, runWorkflowFn: RunWorkflowFn, execFn?: ExecFn, maxConcurrentSessions?: number, emitter?: DaemonEventEmitter, notificationService?: NotificationService);
36
+ private readonly steerRegistry;
37
+ constructor(index: ReadonlyMap<string, TriggerDefinition>, ctx: V2ToolContext, apiKey: string, runWorkflowFn: RunWorkflowFn, execFn?: ExecFn, maxConcurrentSessions?: number, emitter?: DaemonEventEmitter, notificationService?: NotificationService, steerRegistry?: SteerRegistry);
37
38
  get activeSessions(): number;
38
39
  get maxConcurrentSessions(): number;
39
40
  route(event: WebhookEvent): RouteResult;
@@ -38,6 +38,7 @@ exports.interpolateGoalTemplate = interpolateGoalTemplate;
38
38
  const crypto = __importStar(require("node:crypto"));
39
39
  const node_child_process_1 = require("node:child_process");
40
40
  const node_util_1 = require("node:util");
41
+ const assert_never_js_1 = require("../runtime/assert-never.js");
41
42
  const index_js_1 = require("../v2/infra/in-memory/keyed-async-queue/index.js");
42
43
  const delivery_client_js_1 = require("./delivery-client.js");
43
44
  const delivery_action_js_1 = require("./delivery-action.js");
@@ -182,7 +183,7 @@ class Semaphore {
182
183
  }
183
184
  const DEFAULT_MAX_CONCURRENT_SESSIONS = 3;
184
185
  class TriggerRouter {
185
- constructor(index, ctx, apiKey, runWorkflowFn, execFn, maxConcurrentSessions, emitter, notificationService) {
186
+ constructor(index, ctx, apiKey, runWorkflowFn, execFn, maxConcurrentSessions, emitter, notificationService, steerRegistry) {
186
187
  this.index = index;
187
188
  this.ctx = ctx;
188
189
  this.apiKey = apiKey;
@@ -191,6 +192,7 @@ class TriggerRouter {
191
192
  this.execFn = execFn ?? execFileAsync;
192
193
  this.emitter = emitter;
193
194
  this.notificationService = notificationService;
195
+ this.steerRegistry = steerRegistry;
194
196
  const requested = maxConcurrentSessions ?? DEFAULT_MAX_CONCURRENT_SESSIONS;
195
197
  const cap = Number.isNaN(requested) ? DEFAULT_MAX_CONCURRENT_SESSIONS : requested;
196
198
  if (cap < 1) {
@@ -259,7 +261,7 @@ class TriggerRouter {
259
261
  await this.semaphore.acquire();
260
262
  let result;
261
263
  try {
262
- result = await this.runWorkflowFn(workflowTrigger, this.ctx, this.apiKey, undefined, this.emitter);
264
+ result = await this.runWorkflowFn(workflowTrigger, this.ctx, this.apiKey, undefined, this.emitter, this.steerRegistry);
263
265
  }
264
266
  finally {
265
267
  this.semaphore.release();
@@ -298,10 +300,13 @@ class TriggerRouter {
298
300
  console.log(`[TriggerRouter] Workflow timed out: triggerId=${trigger.id} ` +
299
301
  `workflowId=${trigger.workflowId} reason=${result.reason} message=${result.message}`);
300
302
  }
301
- else {
303
+ else if (result._tag === 'error') {
302
304
  console.log(`[TriggerRouter] Workflow failed: triggerId=${trigger.id} ` +
303
305
  `workflowId=${trigger.workflowId} error=${result.message} stopReason=${result.stopReason}`);
304
306
  }
307
+ else {
308
+ (0, assert_never_js_1.assertNever)(result);
309
+ }
305
310
  this.notificationService?.notify(result, workflowTrigger.goal);
306
311
  await maybeRunDelivery(trigger.id, trigger, originalResult, this.execFn);
307
312
  });
@@ -317,7 +322,7 @@ class TriggerRouter {
317
322
  await this.semaphore.acquire();
318
323
  let result;
319
324
  try {
320
- result = await this.runWorkflowFn(workflowTrigger, this.ctx, this.apiKey, undefined, this.emitter);
325
+ result = await this.runWorkflowFn(workflowTrigger, this.ctx, this.apiKey, undefined, this.emitter, this.steerRegistry);
321
326
  }
322
327
  finally {
323
328
  this.semaphore.release();
@@ -334,10 +339,13 @@ class TriggerRouter {
334
339
  console.log(`[TriggerRouter] Dispatch timed out: workflowId=${workflowTrigger.workflowId} ` +
335
340
  `reason=${result.reason} message=${result.message}`);
336
341
  }
337
- else {
342
+ else if (result._tag === 'error') {
338
343
  console.log(`[TriggerRouter] Dispatch failed: workflowId=${workflowTrigger.workflowId} ` +
339
344
  `error=${result.message} stopReason=${result.stopReason}`);
340
345
  }
346
+ else {
347
+ (0, assert_never_js_1.assertNever)(result);
348
+ }
341
349
  this.notificationService?.notify(result, workflowTrigger.goal);
342
350
  });
343
351
  return workflowTrigger.workflowId;
@@ -426,7 +426,6 @@ function validateAndResolveTrigger(raw, env, workspaces = {}) {
426
426
  const requiredStringFields = [
427
427
  'provider',
428
428
  'workflowId',
429
- 'goal',
430
429
  ];
431
430
  for (const field of requiredStringFields) {
432
431
  const v = raw[field];
@@ -491,7 +490,21 @@ function validateAndResolveTrigger(raw, env, workspaces = {}) {
491
490
  return secretResult;
492
491
  hmacSecret = secretResult.value;
493
492
  }
494
- const goalTemplate = raw.goalTemplate?.trim();
493
+ const LATE_BOUND_GOAL_SENTINEL = 'Autonomous task';
494
+ let resolvedGoal;
495
+ let resolvedGoalTemplate = raw.goalTemplate?.trim();
496
+ if (!raw.goal?.trim()) {
497
+ resolvedGoal = LATE_BOUND_GOAL_SENTINEL;
498
+ if (!resolvedGoalTemplate) {
499
+ resolvedGoalTemplate = '{{$.goal}}';
500
+ console.log(`[TriggerStore] Trigger "${rawId}" has no static goal or goalTemplate -- ` +
501
+ `defaulting to goalTemplate: "{{$.goal}}" (goal taken from webhook payload). ` +
502
+ `Fallback goal if payload has no goal field: "${LATE_BOUND_GOAL_SENTINEL}".`);
503
+ }
504
+ }
505
+ else {
506
+ resolvedGoal = raw.goal.trim();
507
+ }
495
508
  const referenceUrlsRaw = raw.referenceUrls?.trim();
496
509
  const referenceUrls = referenceUrlsRaw
497
510
  ? referenceUrlsRaw.split(/\s+/).filter(Boolean)
@@ -712,13 +725,13 @@ function validateAndResolveTrigger(raw, env, workspaces = {}) {
712
725
  provider,
713
726
  workflowId: raw.workflowId.trim(),
714
727
  workspacePath: resolvedWorkspacePath,
715
- goal: raw.goal.trim(),
728
+ goal: resolvedGoal,
716
729
  concurrencyMode,
717
730
  ...(hmacSecret !== undefined ? { hmacSecret } : {}),
718
731
  ...(raw.contextMapping !== undefined
719
732
  ? { contextMapping: assembleContextMapping(raw.contextMapping) }
720
733
  : {}),
721
- ...(goalTemplate ? { goalTemplate } : {}),
734
+ ...(resolvedGoalTemplate ? { goalTemplate: resolvedGoalTemplate } : {}),
722
735
  ...(referenceUrls !== undefined && referenceUrls.length > 0 ? { referenceUrls } : {}),
723
736
  ...(agentConfig !== undefined ? { agentConfig } : {}),
724
737
  ...(callbackUrl !== undefined ? { callbackUrl } : {}),
@@ -46,6 +46,5 @@ export declare function createCustomDirectorySource(directoryPath: string, label
46
46
  export declare function createGitRepositorySource(repositoryUrl: string, branch: string, localCachePath: string): GitRepositorySource;
47
47
  export declare function createRemoteRegistrySource(registryUrl: string): RemoteRegistrySource;
48
48
  export declare function createPluginSource(pluginName: string, pluginVersion: string): PluginSource;
49
- export declare function assertNever(x: never): never;
50
49
  export declare function getSourceDisplayName(source: WorkflowSource): string;
51
50
  export declare function getSourcePath(source: WorkflowSource): string | undefined;
@@ -15,9 +15,9 @@ exports.createCustomDirectorySource = createCustomDirectorySource;
15
15
  exports.createGitRepositorySource = createGitRepositorySource;
16
16
  exports.createRemoteRegistrySource = createRemoteRegistrySource;
17
17
  exports.createPluginSource = createPluginSource;
18
- exports.assertNever = assertNever;
19
18
  exports.getSourceDisplayName = getSourceDisplayName;
20
19
  exports.getSourcePath = getSourcePath;
20
+ const assert_never_js_1 = require("../runtime/assert-never.js");
21
21
  exports.WORKFLOW_SOURCE_KINDS = [
22
22
  'bundled',
23
23
  'user',
@@ -69,9 +69,6 @@ function createRemoteRegistrySource(registryUrl) {
69
69
  function createPluginSource(pluginName, pluginVersion) {
70
70
  return Object.freeze({ kind: 'plugin', pluginName, pluginVersion });
71
71
  }
72
- function assertNever(x) {
73
- throw new Error(`Unexpected source kind: ${JSON.stringify(x)}`);
74
- }
75
72
  function getSourceDisplayName(source) {
76
73
  switch (source.kind) {
77
74
  case 'bundled':
@@ -89,7 +86,7 @@ function getSourceDisplayName(source) {
89
86
  case 'plugin':
90
87
  return source.pluginName;
91
88
  default:
92
- return assertNever(source);
89
+ return (0, assert_never_js_1.assertNever)(source);
93
90
  }
94
91
  }
95
92
  function getSourcePath(source) {
@@ -105,7 +102,7 @@ function getSourcePath(source) {
105
102
  case 'plugin':
106
103
  return undefined;
107
104
  default:
108
- return assertNever(source);
105
+ return (0, assert_never_js_1.assertNever)(source);
109
106
  }
110
107
  }
111
108
  function extractRepoName(url) {
@@ -28,4 +28,4 @@ export declare function isWorkflowDefinition(obj: unknown): obj is WorkflowDefin
28
28
  export type { WorkflowDefinition, WorkflowStepDefinition, LoopStepDefinition, LoopConfigDefinition, FunctionDefinition, FunctionParameter, FunctionCall } from './workflow-definition';
29
29
  export { isLoopStepDefinition, isWorkflowStepDefinition, hasWorkflowDefinitionShape } from './workflow-definition';
30
30
  export type { WorkflowSource, WorkflowSourceKind, BundledSource, UserDirectorySource, ProjectDirectorySource, CustomDirectorySource, GitRepositorySource, RemoteRegistrySource, PluginSource } from './workflow-source';
31
- export { WORKFLOW_SOURCE_KINDS, createBundledSource, createUserDirectorySource, createProjectDirectorySource, createCustomDirectorySource, createGitRepositorySource, createRemoteRegistrySource, createPluginSource, getSourceDisplayName, getSourcePath, assertNever } from './workflow-source';
31
+ export { WORKFLOW_SOURCE_KINDS, createBundledSource, createUserDirectorySource, createProjectDirectorySource, createCustomDirectorySource, createGitRepositorySource, createRemoteRegistrySource, createPluginSource, getSourceDisplayName, getSourcePath, } from './workflow-source';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.assertNever = exports.getSourcePath = exports.getSourceDisplayName = exports.createPluginSource = exports.createRemoteRegistrySource = exports.createGitRepositorySource = exports.createCustomDirectorySource = exports.createProjectDirectorySource = exports.createUserDirectorySource = exports.createBundledSource = exports.WORKFLOW_SOURCE_KINDS = exports.hasWorkflowDefinitionShape = exports.isWorkflowStepDefinition = exports.isLoopStepDefinition = void 0;
3
+ exports.getSourcePath = exports.getSourceDisplayName = exports.createPluginSource = exports.createRemoteRegistrySource = exports.createGitRepositorySource = exports.createCustomDirectorySource = exports.createProjectDirectorySource = exports.createUserDirectorySource = exports.createBundledSource = exports.WORKFLOW_SOURCE_KINDS = exports.hasWorkflowDefinitionShape = exports.isWorkflowStepDefinition = exports.isLoopStepDefinition = void 0;
4
4
  exports.createWorkflow = createWorkflow;
5
5
  exports.toWorkflowSummary = toWorkflowSummary;
6
6
  exports.toWorkflowSourceInfo = toWorkflowSourceInfo;
@@ -102,4 +102,3 @@ Object.defineProperty(exports, "createRemoteRegistrySource", { enumerable: true,
102
102
  Object.defineProperty(exports, "createPluginSource", { enumerable: true, get: function () { return workflow_source_2.createPluginSource; } });
103
103
  Object.defineProperty(exports, "getSourceDisplayName", { enumerable: true, get: function () { return workflow_source_2.getSourceDisplayName; } });
104
104
  Object.defineProperty(exports, "getSourcePath", { enumerable: true, get: function () { return workflow_source_2.getSourcePath; } });
105
- Object.defineProperty(exports, "assertNever", { enumerable: true, get: function () { return workflow_source_2.assertNever; } });