@exaudeus/workrail 3.16.0 → 3.17.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 (55) hide show
  1. package/dist/application/use-cases/raw-workflow-file-scanner.js +10 -13
  2. package/dist/cli/commands/index.d.ts +1 -1
  3. package/dist/cli/commands/index.js +2 -1
  4. package/dist/cli/commands/init.d.ts +10 -0
  5. package/dist/cli/commands/init.js +72 -0
  6. package/dist/cli.js +13 -1
  7. package/dist/config/config-file.d.ts +8 -0
  8. package/dist/config/config-file.js +141 -0
  9. package/dist/config/feature-flags.js +8 -0
  10. package/dist/console/assets/index-BwJelCXK.js +28 -0
  11. package/dist/console/index.html +1 -1
  12. package/dist/di/container.d.ts +1 -0
  13. package/dist/di/container.js +24 -7
  14. package/dist/infrastructure/session/HttpServer.d.ts +0 -1
  15. package/dist/infrastructure/session/HttpServer.js +4 -46
  16. package/dist/manifest.json +101 -109
  17. package/dist/mcp/assert-output.js +2 -1
  18. package/dist/mcp/dev-mode.d.ts +1 -0
  19. package/dist/mcp/dev-mode.js +12 -0
  20. package/dist/mcp/handler-factory.d.ts +1 -1
  21. package/dist/mcp/handler-factory.js +8 -7
  22. package/dist/mcp/handlers/shared/request-workflow-reader.d.ts +1 -0
  23. package/dist/mcp/handlers/shared/request-workflow-reader.js +90 -20
  24. package/dist/mcp/handlers/v2-execution/continue-advance.d.ts +1 -0
  25. package/dist/mcp/handlers/v2-execution/continue-advance.js +3 -1
  26. package/dist/mcp/handlers/v2-execution/continue-rehydrate.d.ts +1 -0
  27. package/dist/mcp/handlers/v2-execution/continue-rehydrate.js +2 -1
  28. package/dist/mcp/handlers/v2-execution/index.js +2 -0
  29. package/dist/mcp/handlers/v2-execution/replay.d.ts +2 -0
  30. package/dist/mcp/handlers/v2-execution/replay.js +3 -0
  31. package/dist/mcp/handlers/v2-execution/start.js +48 -20
  32. package/dist/mcp/handlers/v2-workflow.js +4 -2
  33. package/dist/mcp/output-schemas.d.ts +5 -0
  34. package/dist/mcp/output-schemas.js +2 -0
  35. package/dist/mcp/server.js +3 -2
  36. package/dist/mcp/v2-response-formatter.d.ts +1 -1
  37. package/dist/mcp/v2-response-formatter.js +2 -3
  38. package/dist/types/workflow-definition.d.ts +3 -1
  39. package/dist/types/workflow-definition.js +2 -0
  40. package/dist/v2/durable-core/domain/prompt-renderer.d.ts +1 -0
  41. package/dist/v2/durable-core/domain/prompt-renderer.js +1 -2
  42. package/dist/v2/durable-core/schemas/compiled-workflow/index.js +4 -3
  43. package/dist/v2/infra/local/pinned-workflow-store/index.d.ts +2 -0
  44. package/dist/v2/infra/local/pinned-workflow-store/index.js +49 -0
  45. package/dist/v2/infra/local/remembered-roots-store/index.d.ts +3 -1
  46. package/dist/v2/infra/local/remembered-roots-store/index.js +6 -3
  47. package/dist/v2/infra/local/workspace-anchor/index.js +4 -2
  48. package/dist/v2/ports/pinned-workflow-store.port.d.ts +2 -0
  49. package/dist/v2/usecases/console-routes.js +3 -2
  50. package/package.json +1 -1
  51. package/dist/console/assets/index-BE5PAgPO.js +0 -28
  52. package/dist/env-flags.d.ts +0 -1
  53. package/dist/env-flags.js +0 -4
  54. package/dist/mcp/handlers/v2-resolve-refs-envelope.d.ts +0 -5
  55. package/dist/mcp/handlers/v2-resolve-refs-envelope.js +0 -17
@@ -110,13 +110,15 @@ export interface WorkflowRecommendedPreferences {
110
110
  readonly recommendedAutonomy?: 'guided' | 'full_auto_stop_on_user_deps' | 'full_auto_never_stop';
111
111
  readonly recommendedRiskPolicy?: 'conservative' | 'balanced' | 'aggressive';
112
112
  }
113
+ export declare const RESOLVE_FROM_VALUES: readonly ["workspace", "package"];
114
+ export type ResolveFrom = typeof RESOLVE_FROM_VALUES[number];
113
115
  export interface WorkflowReference {
114
116
  readonly id: string;
115
117
  readonly title: string;
116
118
  readonly source: string;
117
119
  readonly purpose: string;
118
120
  readonly authoritative: boolean;
119
- readonly resolveFrom?: 'workspace' | 'package';
121
+ readonly resolveFrom?: ResolveFrom;
120
122
  }
121
123
  export interface WorkflowDefinition {
122
124
  readonly id: string;
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RESOLVE_FROM_VALUES = void 0;
3
4
  exports.isLoopStepDefinition = isLoopStepDefinition;
4
5
  exports.isWorkflowStepDefinition = isWorkflowStepDefinition;
5
6
  exports.stepHasPromptSource = stepHasPromptSource;
6
7
  exports.hasWorkflowDefinitionShape = hasWorkflowDefinitionShape;
7
8
  exports.createWorkflowDefinition = createWorkflowDefinition;
9
+ exports.RESOLVE_FROM_VALUES = ['workspace', 'package'];
8
10
  function isLoopStepDefinition(step) {
9
11
  return 'type' in step && step.type === 'loop';
10
12
  }
@@ -25,4 +25,5 @@ export declare function renderPendingPrompt(args: {
25
25
  readonly nodeId: NodeId;
26
26
  readonly rehydrateOnly: boolean;
27
27
  readonly precomputedIndex?: import('../session-index.js').SessionIndex;
28
+ readonly cleanResponseFormat?: boolean;
28
29
  }): Result<StepMetadata, PromptRenderError>;
@@ -17,7 +17,6 @@ const sorted_event_log_js_1 = require("../sorted-event-log.js");
17
17
  const condition_evaluator_js_1 = require("../../../utils/condition-evaluator.js");
18
18
  const context_template_resolver_js_1 = require("./context-template-resolver.js");
19
19
  const retrieval_contract_js_1 = require("./retrieval-contract.js");
20
- const env_flags_js_1 = require("../../../env-flags.js");
21
20
  function buildNonTipSegments(args) {
22
21
  const segments = [];
23
22
  const childSummary = (0, recap_recovery_js_1.buildChildSummary)({ nodeId: args.nodeId, dag: args.run });
@@ -246,7 +245,7 @@ function renderPendingPrompt(args) {
246
245
  const renderContext = { ...sessionContext, ...loopRenderContext };
247
246
  const basePrompt = (0, context_template_resolver_js_1.resolveContextTemplates)(step.prompt ?? '', renderContext);
248
247
  const baseTitle = (0, context_template_resolver_js_1.resolveContextTemplates)(step.title, renderContext);
249
- const cleanResponseFormat = env_flags_js_1.CLEAN_RESPONSE_FORMAT;
248
+ const cleanResponseFormat = args.cleanResponseFormat ?? false;
250
249
  const loopBanner = buildLoopContextBanner({ loopPath: args.loopPath, isExitStep, maxIterations, cleanFormat: cleanResponseFormat });
251
250
  const validationCriteria = step.validationCriteria;
252
251
  const requirements = (0, validation_requirements_extractor_js_1.extractValidationRequirements)(validationCriteria);
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CompiledWorkflowSnapshotSchema = exports.CompiledWorkflowSnapshotV1Schema = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const json_zod_js_1 = require("../../canonical/json-zod.js");
6
+ const workflow_definition_js_1 = require("../../../../types/workflow-definition.js");
6
7
  const CompiledWorkflowSnapshotV1PreviewSchema = zod_1.z.object({
7
8
  schemaVersion: zod_1.z.literal(1),
8
9
  sourceKind: zod_1.z.literal('v1_preview'),
@@ -33,7 +34,7 @@ const CompiledWorkflowSnapshotV1PinnedSchema = zod_1.z.object({
33
34
  source: zod_1.z.string().min(1),
34
35
  purpose: zod_1.z.string().min(1),
35
36
  authoritative: zod_1.z.boolean(),
36
- resolveFrom: zod_1.z.enum(['workspace', 'package']),
37
+ resolveFrom: zod_1.z.enum(workflow_definition_js_1.RESOLVE_FROM_VALUES),
37
38
  status: zod_1.z.literal('resolved'),
38
39
  resolvedPath: zod_1.z.string().min(1),
39
40
  }),
@@ -43,7 +44,7 @@ const CompiledWorkflowSnapshotV1PinnedSchema = zod_1.z.object({
43
44
  source: zod_1.z.string().min(1),
44
45
  purpose: zod_1.z.string().min(1),
45
46
  authoritative: zod_1.z.boolean(),
46
- resolveFrom: zod_1.z.enum(['workspace', 'package']),
47
+ resolveFrom: zod_1.z.enum(workflow_definition_js_1.RESOLVE_FROM_VALUES),
47
48
  status: zod_1.z.literal('unresolved'),
48
49
  }),
49
50
  zod_1.z.object({
@@ -52,7 +53,7 @@ const CompiledWorkflowSnapshotV1PinnedSchema = zod_1.z.object({
52
53
  source: zod_1.z.string().min(1),
53
54
  purpose: zod_1.z.string().min(1),
54
55
  authoritative: zod_1.z.boolean(),
55
- resolveFrom: zod_1.z.enum(['workspace', 'package']),
56
+ resolveFrom: zod_1.z.enum(workflow_definition_js_1.RESOLVE_FROM_VALUES),
56
57
  status: zod_1.z.literal('pinned'),
57
58
  }),
58
59
  ])).optional(),
@@ -9,5 +9,7 @@ export declare class LocalPinnedWorkflowStoreV2 implements PinnedWorkflowStorePo
9
9
  private readonly fs;
10
10
  constructor(dataDir: DataDirPortV2, fs: FileSystemPortV2);
11
11
  get(workflowHash: WorkflowHash): ResultAsync<CompiledWorkflowSnapshot | null, PinnedWorkflowStoreError>;
12
+ list(): ResultAsync<readonly WorkflowHash[], PinnedWorkflowStoreError>;
13
+ prune(_olderThanMs: number): ResultAsync<number, PinnedWorkflowStoreError>;
12
14
  put(workflowHash: WorkflowHash, compiled: CompiledWorkflowSnapshot): ResultAsync<void, PinnedWorkflowStoreError>;
13
15
  }
@@ -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.17.0",
4
4
  "description": "Step-by-step workflow enforcement for AI agents via MCP",
5
5
  "license": "MIT",
6
6
  "repository": {