@exaudeus/workrail 3.16.0 → 3.18.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 (68) hide show
  1. package/dist/application/services/validation-engine.js +7 -11
  2. package/dist/application/services/workflow-compiler.js +9 -11
  3. package/dist/application/use-cases/raw-workflow-file-scanner.js +10 -13
  4. package/dist/cli/commands/index.d.ts +1 -1
  5. package/dist/cli/commands/index.js +2 -1
  6. package/dist/cli/commands/init.d.ts +10 -0
  7. package/dist/cli/commands/init.js +72 -0
  8. package/dist/cli.js +13 -1
  9. package/dist/config/config-file.d.ts +8 -0
  10. package/dist/config/config-file.js +141 -0
  11. package/dist/config/feature-flags.js +8 -0
  12. package/dist/console/assets/index-BwJelCXK.js +28 -0
  13. package/dist/console/index.html +1 -1
  14. package/dist/di/container.d.ts +1 -0
  15. package/dist/di/container.js +24 -7
  16. package/dist/infrastructure/session/HttpServer.d.ts +0 -1
  17. package/dist/infrastructure/session/HttpServer.js +4 -46
  18. package/dist/manifest.json +120 -128
  19. package/dist/mcp/assert-output.js +2 -1
  20. package/dist/mcp/dev-mode.d.ts +1 -0
  21. package/dist/mcp/dev-mode.js +12 -0
  22. package/dist/mcp/handler-factory.d.ts +1 -1
  23. package/dist/mcp/handler-factory.js +8 -7
  24. package/dist/mcp/handlers/shared/request-workflow-reader.d.ts +1 -0
  25. package/dist/mcp/handlers/shared/request-workflow-reader.js +90 -20
  26. package/dist/mcp/handlers/v2-advance-core/assessment-consequences.d.ts +1 -1
  27. package/dist/mcp/handlers/v2-advance-core/assessment-consequences.js +14 -11
  28. package/dist/mcp/handlers/v2-advance-core/assessment-validation.d.ts +5 -3
  29. package/dist/mcp/handlers/v2-advance-core/assessment-validation.js +109 -87
  30. package/dist/mcp/handlers/v2-advance-core/input-validation.d.ts +0 -4
  31. package/dist/mcp/handlers/v2-advance-core/input-validation.js +1 -3
  32. package/dist/mcp/handlers/v2-advance-core/outcome-blocked.js +8 -3
  33. package/dist/mcp/handlers/v2-advance-core/outcome-success.js +8 -3
  34. package/dist/mcp/handlers/v2-execution/continue-advance.d.ts +1 -0
  35. package/dist/mcp/handlers/v2-execution/continue-advance.js +3 -1
  36. package/dist/mcp/handlers/v2-execution/continue-rehydrate.d.ts +1 -0
  37. package/dist/mcp/handlers/v2-execution/continue-rehydrate.js +2 -1
  38. package/dist/mcp/handlers/v2-execution/index.js +2 -0
  39. package/dist/mcp/handlers/v2-execution/replay.d.ts +2 -0
  40. package/dist/mcp/handlers/v2-execution/replay.js +7 -4
  41. package/dist/mcp/handlers/v2-execution/start.js +48 -20
  42. package/dist/mcp/handlers/v2-workflow.js +4 -2
  43. package/dist/mcp/output-schemas.d.ts +17 -12
  44. package/dist/mcp/output-schemas.js +12 -11
  45. package/dist/mcp/server.js +3 -2
  46. package/dist/mcp/v2-response-formatter.d.ts +1 -1
  47. package/dist/mcp/v2-response-formatter.js +2 -3
  48. package/dist/types/workflow-definition.d.ts +3 -1
  49. package/dist/types/workflow-definition.js +2 -0
  50. package/dist/v2/durable-core/domain/prompt-renderer.d.ts +1 -0
  51. package/dist/v2/durable-core/domain/prompt-renderer.js +5 -2
  52. package/dist/v2/durable-core/schemas/compiled-workflow/index.js +4 -3
  53. package/dist/v2/infra/local/pinned-workflow-store/index.d.ts +2 -0
  54. package/dist/v2/infra/local/pinned-workflow-store/index.js +49 -0
  55. package/dist/v2/infra/local/remembered-roots-store/index.d.ts +3 -1
  56. package/dist/v2/infra/local/remembered-roots-store/index.js +6 -3
  57. package/dist/v2/infra/local/workspace-anchor/index.js +4 -2
  58. package/dist/v2/ports/pinned-workflow-store.port.d.ts +2 -0
  59. package/dist/v2/usecases/console-routes.js +3 -2
  60. package/package.json +1 -1
  61. package/spec/authoring-spec.json +3 -3
  62. package/spec/workflow.schema.json +1 -2
  63. package/workflows/workflow-for-workflows.json +558 -448
  64. package/dist/console/assets/index-BE5PAgPO.js +0 -28
  65. package/dist/env-flags.d.ts +0 -1
  66. package/dist/env-flags.js +0 -4
  67. package/dist/mcp/handlers/v2-resolve-refs-envelope.d.ts +0 -5
  68. package/dist/mcp/handlers/v2-resolve-refs-envelope.js +0 -17
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>WorkRail Console</title>
7
- <script type="module" crossorigin src="/console/assets/index-BE5PAgPO.js"></script>
7
+ <script type="module" crossorigin src="/console/assets/index-BwJelCXK.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="/console/assets/index-BZNM03t1.css">
9
9
  </head>
10
10
  <body>
@@ -3,6 +3,7 @@ import { container } from 'tsyringe';
3
3
  import type { RuntimeMode } from '../runtime/runtime-mode.js';
4
4
  export interface ContainerInitOptions {
5
5
  readonly runtimeMode?: RuntimeMode;
6
+ readonly env?: Record<string, string | undefined>;
6
7
  }
7
8
  export declare function initializeContainer(options?: ContainerInitOptions): Promise<void>;
8
9
  export declare function startAsyncServices(): Promise<void>;
@@ -50,14 +50,28 @@ const in_memory_shutdown_events_js_1 = require("../runtime/adapters/in-memory-sh
50
50
  const node_process_terminator_js_1 = require("../runtime/adapters/node-process-terminator.js");
51
51
  const throwing_process_terminator_js_1 = require("../runtime/adapters/throwing-process-terminator.js");
52
52
  const app_config_js_1 = require("../config/app-config.js");
53
+ const config_file_js_1 = require("../config/config-file.js");
53
54
  const formatter_js_1 = require("../errors/formatter.js");
54
55
  let initialized = false;
55
56
  let asyncInitialized = false;
56
57
  let initializationPromise = null;
57
58
  let isInitializing = false;
58
- async function registerConfig() {
59
+ let mergedEnv = process.env;
60
+ async function registerConfig(env) {
61
+ (0, config_file_js_1.ensureWorkrailConfigFile)();
62
+ if (env !== undefined) {
63
+ mergedEnv = env;
64
+ }
65
+ else if (process.env['VITEST']) {
66
+ mergedEnv = { ...process.env };
67
+ }
68
+ else {
69
+ const configFileResult = (0, config_file_js_1.loadWorkrailConfigFile)();
70
+ const configFileValues = configFileResult.kind === 'ok' ? configFileResult.value : {};
71
+ mergedEnv = { ...configFileValues, ...process.env };
72
+ }
59
73
  if (!tsyringe_1.container.isRegistered(tokens_js_1.DI.Config.App)) {
60
- const configResult = (0, app_config_js_1.loadConfig)({ env: process.env, projectPath: process.cwd() });
74
+ const configResult = (0, app_config_js_1.loadConfig)({ env: mergedEnv, projectPath: process.cwd() });
61
75
  if (configResult.kind === 'err') {
62
76
  console.error((0, formatter_js_1.formatAppError)(configResult.error));
63
77
  process.exit(1);
@@ -71,9 +85,10 @@ async function registerConfig() {
71
85
  tsyringe_1.container.register(tokens_js_1.DI.Config.BrowserBehavior, { useValue: config.dashboard.browserBehavior });
72
86
  }
73
87
  if (!tsyringe_1.container.isRegistered(tokens_js_1.DI.Infra.FeatureFlags)) {
74
- const { EnvironmentFeatureFlagProvider } = await Promise.resolve().then(() => __importStar(require('../config/feature-flags.js')));
88
+ const { CustomEnvFeatureFlagProvider } = await Promise.resolve().then(() => __importStar(require('../config/feature-flags.js')));
89
+ const captured = mergedEnv;
75
90
  tsyringe_1.container.register(tokens_js_1.DI.Infra.FeatureFlags, {
76
- useFactory: (0, tsyringe_1.instanceCachingFactory)((c) => c.resolve(EnvironmentFeatureFlagProvider))
91
+ useFactory: (0, tsyringe_1.instanceCachingFactory)(() => new CustomEnvFeatureFlagProvider(captured))
77
92
  });
78
93
  }
79
94
  }
@@ -186,7 +201,7 @@ async function registerV2Services() {
186
201
  const { NodeTimeClockV2 } = await Promise.resolve().then(() => __importStar(require('../v2/infra/local/time-clock/index.js')));
187
202
  const { IdFactoryV2 } = await Promise.resolve().then(() => __importStar(require('../v2/infra/local/id-factory/index.js')));
188
203
  tsyringe_1.container.register(tokens_js_1.DI.V2.DataDir, {
189
- useFactory: (0, tsyringe_1.instanceCachingFactory)(() => new LocalDataDirV2(process.env)),
204
+ useFactory: (0, tsyringe_1.instanceCachingFactory)(() => new LocalDataDirV2(mergedEnv)),
190
205
  });
191
206
  tsyringe_1.container.register(tokens_js_1.DI.V2.FileSystem, {
192
207
  useFactory: (0, tsyringe_1.instanceCachingFactory)(() => new NodeFileSystemV2()),
@@ -249,7 +264,8 @@ async function registerV2Services() {
249
264
  useFactory: (0, tsyringe_1.instanceCachingFactory)((c) => {
250
265
  const dataDir = c.resolve(tokens_js_1.DI.V2.DataDir);
251
266
  const fs = c.resolve(tokens_js_1.DI.V2.FileSystem);
252
- return new LocalRememberedRootsStoreV2(dataDir, fs);
267
+ const clock = c.resolve(tokens_js_1.DI.V2.TimeClock);
268
+ return new LocalRememberedRootsStoreV2(dataDir, fs, clock);
253
269
  }),
254
270
  });
255
271
  tsyringe_1.container.register(tokens_js_1.DI.V2.ManagedSourceStore, {
@@ -321,7 +337,7 @@ async function initializeContainer(options = {}) {
321
337
  isInitializing = true;
322
338
  try {
323
339
  registerRuntime(options);
324
- await registerConfig();
340
+ await registerConfig(options.env);
325
341
  await registerStorageChain();
326
342
  await registerV2Services();
327
343
  await registerServices();
@@ -366,6 +382,7 @@ function resetContainer() {
366
382
  asyncInitialized = false;
367
383
  initializationPromise = null;
368
384
  isInitializing = false;
385
+ mergedEnv = process.env;
369
386
  }
370
387
  function isInitialized() {
371
388
  return initialized;
@@ -42,7 +42,6 @@ export declare class HttpServer {
42
42
  private tryBecomePrimary;
43
43
  private shouldReclaimLock;
44
44
  private reclaimStaleLock;
45
- private checkHealth;
46
45
  private setupPrimaryCleanup;
47
46
  private startAsPrimary;
48
47
  private startLegacyMode;
@@ -343,7 +343,8 @@ let HttpServer = class HttpServer {
343
343
  }
344
344
  catch (error) {
345
345
  if (error.code === 'EADDRINUSE') {
346
- console.error(`[Dashboard] Port ${this.port} busy despite lock, falling back to legacy mode`);
346
+ console.error(`[Dashboard] Port ${this.port} still held by previous instance -- ` +
347
+ `running on next available port. Restart the old instance to move to ${this.port}.`);
347
348
  await promises_1.default.unlink(this.lockFile).catch(() => { });
348
349
  return await this.startLegacyMode();
349
350
  }
@@ -411,37 +412,11 @@ let HttpServer = class HttpServer {
411
412
  const lockData = JSON.parse(lockContent);
412
413
  const { reclaim, reason } = this.shouldReclaimLock(lockData);
413
414
  if (!reclaim) {
414
- const isHealthy = await this.checkHealth(lockData.port);
415
- if (isHealthy) {
416
- return false;
417
- }
418
- console.error(`[Dashboard] Primary (PID ${lockData.pid}) not responding, attempting graceful shutdown`);
419
- try {
420
- process.kill(lockData.pid, 'SIGTERM');
421
- await new Promise(resolve => setTimeout(resolve, 2000));
422
- }
423
- catch { }
424
- const stillHealthy = await this.checkHealth(lockData.port);
425
- if (stillHealthy) {
426
- return false;
427
- }
415
+ console.error(`[Dashboard] Secondary mode: primary lock valid (PID ${lockData.pid}), yielding`);
416
+ return false;
428
417
  }
429
418
  else {
430
419
  console.error(`[Dashboard] Lock reclaim needed: ${reason}`);
431
- try {
432
- process.kill(lockData.pid, 0);
433
- const isWorkRailOnPort = await this.checkHealth(lockData.port);
434
- if (isWorkRailOnPort) {
435
- console.error(`[Dashboard] Sending SIGTERM to old process (PID ${lockData.pid})`);
436
- process.kill(lockData.pid, 'SIGTERM');
437
- await new Promise(resolve => setTimeout(resolve, 2000));
438
- }
439
- else {
440
- console.error(`[Dashboard] PID ${lockData.pid} alive but not WorkRail on port ${lockData.port} -- reclaiming without SIGTERM`);
441
- }
442
- }
443
- catch {
444
- }
445
420
  }
446
421
  const tempPath = `${this.lockFile}.${process.pid}.${Date.now()}`;
447
422
  const newLockData = {
@@ -496,23 +471,6 @@ let HttpServer = class HttpServer {
496
471
  return await this.tryBecomePrimary();
497
472
  }
498
473
  }
499
- async checkHealth(port) {
500
- try {
501
- const controller = new AbortController();
502
- const timeout = setTimeout(() => controller.abort(), 2000);
503
- const response = await fetch(`http://localhost:${port}/api/health`, {
504
- signal: controller.signal
505
- });
506
- clearTimeout(timeout);
507
- if (!response.ok)
508
- return false;
509
- const data = await response.json();
510
- return data.status === 'healthy' && data.isPrimary !== undefined;
511
- }
512
- catch {
513
- return false;
514
- }
515
- }
516
474
  setupPrimaryCleanup() {
517
475
  if (this.processLifecyclePolicy.kind === 'no_signal_handlers') {
518
476
  return;