@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
@@ -1,6 +1,40 @@
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.LocalPinnedWorkflowStoreV2 = void 0;
37
+ const nodePath = __importStar(require("node:path"));
4
38
  const neverthrow_1 = require("neverthrow");
5
39
  const index_js_1 = require("../../../durable-core/schemas/compiled-workflow/index.js");
6
40
  const jcs_js_1 = require("../../../durable-core/canonical/jcs.js");
@@ -43,6 +77,21 @@ class LocalPinnedWorkflowStoreV2 {
43
77
  return (0, neverthrow_1.okAsync)(validated.data);
44
78
  });
45
79
  }
80
+ list() {
81
+ const dir = this.dataDir.pinnedWorkflowsDir();
82
+ return this.fs.readdir(dir)
83
+ .orElse((e) => {
84
+ if (e.code === 'FS_NOT_FOUND')
85
+ return (0, neverthrow_1.okAsync)([]);
86
+ return (0, neverthrow_1.errAsync)(mapFsToStoreError(e));
87
+ })
88
+ .map((entries) => entries
89
+ .filter((name) => name.endsWith('.json') && !name.endsWith('.tmp'))
90
+ .map((name) => nodePath.basename(name, '.json')));
91
+ }
92
+ prune(_olderThanMs) {
93
+ return (0, neverthrow_1.okAsync)(0);
94
+ }
46
95
  put(workflowHash, compiled) {
47
96
  const dir = this.dataDir.pinnedWorkflowsDir();
48
97
  const filePath = this.dataDir.pinnedWorkflowPath(workflowHash);
@@ -1,11 +1,13 @@
1
1
  import type { ResultAsync } from 'neverthrow';
2
2
  import type { DataDirPortV2 } from '../../../ports/data-dir.port.js';
3
3
  import type { FileSystemPortV2 } from '../../../ports/fs.port.js';
4
+ import type { TimeClockPortV2 } from '../../../ports/time-clock.port.js';
4
5
  import type { RememberedRootRecordV2, RememberedRootsStoreError, RememberedRootsStorePortV2 } from '../../../ports/remembered-roots-store.port.js';
5
6
  export declare class LocalRememberedRootsStoreV2 implements RememberedRootsStorePortV2 {
6
7
  private readonly dataDir;
7
8
  private readonly fs;
8
- constructor(dataDir: DataDirPortV2, fs: FileSystemPortV2);
9
+ private readonly clock;
10
+ constructor(dataDir: DataDirPortV2, fs: FileSystemPortV2, clock: TimeClockPortV2);
9
11
  listRoots(): ResultAsync<readonly string[], RememberedRootsStoreError>;
10
12
  listRootRecords(): ResultAsync<readonly RememberedRootRecordV2[], RememberedRootsStoreError>;
11
13
  rememberRoot(rootPath: string): ResultAsync<void, RememberedRootsStoreError>;
@@ -9,6 +9,7 @@ const zod_1 = require("zod");
9
9
  const neverthrow_1 = require("neverthrow");
10
10
  const jcs_js_1 = require("../../../durable-core/canonical/jcs.js");
11
11
  const REMEMBERED_ROOTS_LOCK_RETRY_MS = 250;
12
+ const TTL_30_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
12
13
  const RememberedRootRecordSchema = zod_1.z.object({
13
14
  path: zod_1.z.string(),
14
15
  addedAtMs: zod_1.z.number().int().nonnegative(),
@@ -48,9 +49,10 @@ function normalizeRootRecords(roots) {
48
49
  return normalized;
49
50
  }
50
51
  class LocalRememberedRootsStoreV2 {
51
- constructor(dataDir, fs) {
52
+ constructor(dataDir, fs, clock) {
52
53
  this.dataDir = dataDir;
53
54
  this.fs = fs;
55
+ this.clock = clock;
54
56
  }
55
57
  listRoots() {
56
58
  return this.listRootRecords().map((roots) => roots.map((root) => root.path));
@@ -88,7 +90,7 @@ class LocalRememberedRootsStoreV2 {
88
90
  }
89
91
  rememberRoot(rootPath) {
90
92
  const normalizedRoot = path_1.default.resolve(rootPath);
91
- const nowMs = Date.now();
93
+ const nowMs = this.clock.nowMs();
92
94
  return this.withLock(() => this.listRootRecords().andThen((roots) => {
93
95
  const existing = roots.find((root) => root.path === normalizedRoot);
94
96
  const nextRoots = existing
@@ -104,7 +106,8 @@ class LocalRememberedRootsStoreV2 {
104
106
  source: 'explicit_workspace_path',
105
107
  },
106
108
  ];
107
- return this.persist(nextRoots);
109
+ const withEviction = nextRoots.filter((r) => r.lastSeenAtMs >= nowMs - TTL_30_DAYS_MS);
110
+ return this.persist(withEviction);
108
111
  }));
109
112
  }
110
113
  persist(roots) {
@@ -44,11 +44,13 @@ class LocalWorkspaceAnchorV2 {
44
44
  anchors.push({ key: 'repo_root_hash', value: repoRootHash });
45
45
  }
46
46
  anchors.push({ key: 'repo_root', value: repoRoot });
47
- const branch = await this.gitCommand('git rev-parse --abbrev-ref HEAD', cwd);
47
+ const [branch, sha] = await Promise.all([
48
+ this.gitCommand('git rev-parse --abbrev-ref HEAD', cwd),
49
+ this.gitCommand('git rev-parse HEAD', cwd),
50
+ ]);
48
51
  if (branch && branch !== 'HEAD') {
49
52
  anchors.push({ key: 'git_branch', value: branch });
50
53
  }
51
- const sha = await this.gitCommand('git rev-parse HEAD', cwd);
52
54
  if (sha && /^[0-9a-f]{40}$/.test(sha)) {
53
55
  anchors.push({ key: 'git_head_sha', value: sha });
54
56
  }
@@ -8,4 +8,6 @@ export type PinnedWorkflowStoreError = {
8
8
  export interface PinnedWorkflowStorePortV2 {
9
9
  get(workflowHash: WorkflowHash): ResultAsync<CompiledWorkflowSnapshot | null, PinnedWorkflowStoreError>;
10
10
  put(workflowHash: WorkflowHash, compiled: CompiledWorkflowSnapshot): ResultAsync<void, PinnedWorkflowStoreError>;
11
+ list(): ResultAsync<readonly WorkflowHash[], PinnedWorkflowStoreError>;
12
+ prune(olderThanMs: number): ResultAsync<number, PinnedWorkflowStoreError>;
11
13
  }
@@ -82,13 +82,14 @@ function mountConsoleRoutes(app, consoleService, workflowService, timingRingBuff
82
82
  req.on('close', () => { sseClients.delete(res); });
83
83
  res.on('close', () => { sseClients.delete(res); });
84
84
  });
85
- if (dev_mode_js_1.DEV_MODE) {
85
+ const devMode = (0, dev_mode_js_1.isDevMode)();
86
+ if (devMode) {
86
87
  app.get('/api/v2/perf/tool-calls', (req, res) => {
87
88
  const rawLimit = req.query['limit'];
88
89
  const limit = typeof rawLimit === 'string' ? parseInt(rawLimit, 10) : undefined;
89
90
  const safeLimit = (limit !== undefined && Number.isFinite(limit) && limit > 0) ? limit : undefined;
90
91
  const observations = timingRingBuffer ? timingRingBuffer.recent(safeLimit) : [];
91
- res.json({ success: true, data: { observations, total: timingRingBuffer?.size ?? 0, devMode: dev_mode_js_1.DEV_MODE } });
92
+ res.json({ success: true, data: { observations, total: timingRingBuffer?.size ?? 0, devMode } });
92
93
  });
93
94
  }
94
95
  app.get('/api/v2/sessions', async (_req, res) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exaudeus/workrail",
3
- "version": "3.16.0",
3
+ "version": "3.18.0",
4
4
  "description": "Step-by-step workflow enforcement for AI agents via MCP",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -998,11 +998,11 @@
998
998
  "step.assessmentRefs",
999
999
  "step.assessmentConsequences"
1000
1000
  ],
1001
- "rule": "V1 supports exactly one assessmentRef per step and at most one assessmentConsequences entry per step. Use anyEqualsLevel as the trigger -- the engine checks all submitted dimensions and fires if any equals that level.",
1002
- "why": "anyEqualsLevel is the only trigger form. It works for both single-dimension and multi-dimension assessments without requiring the author to choose between two forms.",
1001
+ "rule": "A step may declare one or more assessmentRefs and at most one assessmentConsequences entry. When assessmentConsequences is present, at least one ref is required. Use anyEqualsLevel as the trigger -- the engine checks all submitted dimensions across all referenced assessments and fires if any equals that level.",
1002
+ "why": "Multiple refs allow composing separate orthogonal assessment definitions (e.g. quality-gate + coverage-gate) behind a single blocking consequence, without forcing unrelated dimensions into one monolithic definition.",
1003
1003
  "enforcement": ["schema"],
1004
1004
  "checks": [
1005
- "No more than one assessmentRefs entry per step.",
1005
+ "At least one assessmentRefs entry when assessmentConsequences is present.",
1006
1006
  "No more than one assessmentConsequences entry per step.",
1007
1007
  "The consequence uses anyEqualsLevel to declare which level blocks -- not a named dimension."
1008
1008
  ],
@@ -456,14 +456,13 @@
456
456
  },
457
457
  "assessmentRefs": {
458
458
  "type": "array",
459
- "description": "References to workflow-level assessment definitions expected for this step. V1 supports exactly one assessmentRef per step.",
459
+ "description": "References to workflow-level assessment definitions expected for this step. When assessmentConsequences is present, at least one ref is required; multiple refs are supported and the consequence fires if any dimension across any referenced assessment equals the trigger level.",
460
460
  "items": {
461
461
  "type": "string",
462
462
  "minLength": 1,
463
463
  "maxLength": 64
464
464
  },
465
465
  "minItems": 1,
466
- "maxItems": 1,
467
466
  "uniqueItems": true
468
467
  },
469
468
  "assessmentConsequences": {