@exaudeus/workrail 3.14.0 → 3.16.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 (156) hide show
  1. package/dist/application/services/validation-engine.js +4 -9
  2. package/dist/application/services/workflow-compiler.js +4 -6
  3. package/dist/application/services/workflow-service.d.ts +2 -0
  4. package/dist/application/services/workflow-service.js +3 -0
  5. package/dist/console/assets/index-BE5PAgPO.js +28 -0
  6. package/dist/console/assets/index-BZNM03t1.css +1 -0
  7. package/dist/console/index.html +2 -2
  8. package/dist/engine/engine-factory.js +2 -2
  9. package/dist/engine/types.d.ts +1 -1
  10. package/dist/env-flags.d.ts +1 -0
  11. package/dist/env-flags.js +4 -0
  12. package/dist/infrastructure/session/HttpServer.d.ts +3 -3
  13. package/dist/infrastructure/session/HttpServer.js +68 -74
  14. package/dist/infrastructure/storage/caching-workflow-storage.d.ts +2 -0
  15. package/dist/infrastructure/storage/caching-workflow-storage.js +15 -6
  16. package/dist/infrastructure/storage/file-workflow-storage.js +3 -4
  17. package/dist/infrastructure/storage/schema-validating-workflow-storage.js +9 -8
  18. package/dist/manifest.json +283 -219
  19. package/dist/mcp/assert-output.d.ts +37 -0
  20. package/dist/mcp/assert-output.js +52 -0
  21. package/dist/mcp/boundary-coercion.d.ts +1 -0
  22. package/dist/mcp/boundary-coercion.js +44 -0
  23. package/dist/mcp/dev-mode.d.ts +1 -0
  24. package/dist/mcp/dev-mode.js +4 -0
  25. package/dist/mcp/handler-factory.js +12 -9
  26. package/dist/mcp/handlers/session.js +8 -9
  27. package/dist/mcp/handlers/shared/request-workflow-reader.d.ts +5 -0
  28. package/dist/mcp/handlers/shared/request-workflow-reader.js +47 -2
  29. package/dist/mcp/handlers/v2-advance-core/assessment-consequences.d.ts +1 -1
  30. package/dist/mcp/handlers/v2-advance-core/assessment-consequences.js +4 -5
  31. package/dist/mcp/handlers/v2-advance-core/event-builders.d.ts +2 -0
  32. package/dist/mcp/handlers/v2-advance-core/event-builders.js +6 -6
  33. package/dist/mcp/handlers/v2-advance-core/index.d.ts +2 -0
  34. package/dist/mcp/handlers/v2-advance-core/index.js +5 -4
  35. package/dist/mcp/handlers/v2-advance-core/input-validation.d.ts +2 -0
  36. package/dist/mcp/handlers/v2-advance-core/input-validation.js +32 -9
  37. package/dist/mcp/handlers/v2-advance-core/outcome-blocked.d.ts +2 -0
  38. package/dist/mcp/handlers/v2-advance-core/outcome-blocked.js +2 -2
  39. package/dist/mcp/handlers/v2-advance-core/outcome-success.d.ts +2 -0
  40. package/dist/mcp/handlers/v2-advance-core/outcome-success.js +1 -1
  41. package/dist/mcp/handlers/v2-checkpoint.d.ts +1 -1
  42. package/dist/mcp/handlers/v2-checkpoint.js +5 -6
  43. package/dist/mcp/handlers/v2-execution/advance.d.ts +4 -2
  44. package/dist/mcp/handlers/v2-execution/advance.js +5 -7
  45. package/dist/mcp/handlers/v2-execution/continue-advance.js +56 -26
  46. package/dist/mcp/handlers/v2-execution/continue-rehydrate.d.ts +1 -1
  47. package/dist/mcp/handlers/v2-execution/continue-rehydrate.js +9 -9
  48. package/dist/mcp/handlers/v2-execution/replay.d.ts +6 -4
  49. package/dist/mcp/handlers/v2-execution/replay.js +47 -30
  50. package/dist/mcp/handlers/v2-execution/start.d.ts +3 -3
  51. package/dist/mcp/handlers/v2-execution/start.js +31 -12
  52. package/dist/mcp/handlers/v2-execution/workflow-object-cache.d.ts +5 -0
  53. package/dist/mcp/handlers/v2-execution/workflow-object-cache.js +19 -0
  54. package/dist/mcp/handlers/v2-execution-helpers.d.ts +1 -0
  55. package/dist/mcp/handlers/v2-execution-helpers.js +23 -7
  56. package/dist/mcp/handlers/v2-resume.d.ts +1 -1
  57. package/dist/mcp/handlers/v2-resume.js +3 -4
  58. package/dist/mcp/handlers/v2-state-conversion.js +5 -1
  59. package/dist/mcp/handlers/v2-workflow.d.ts +100 -0
  60. package/dist/mcp/handlers/v2-workflow.js +155 -31
  61. package/dist/mcp/handlers/workflow.d.ts +2 -5
  62. package/dist/mcp/handlers/workflow.js +15 -12
  63. package/dist/mcp/output-schemas.d.ts +123 -29
  64. package/dist/mcp/output-schemas.js +36 -18
  65. package/dist/mcp/server.js +70 -5
  66. package/dist/mcp/tool-call-timing.d.ts +24 -0
  67. package/dist/mcp/tool-call-timing.js +85 -0
  68. package/dist/mcp/tool-descriptions.js +17 -9
  69. package/dist/mcp/transports/http-entry.js +3 -2
  70. package/dist/mcp/transports/http-listener.d.ts +1 -0
  71. package/dist/mcp/transports/http-listener.js +25 -0
  72. package/dist/mcp/transports/shutdown-hooks.d.ts +4 -1
  73. package/dist/mcp/transports/shutdown-hooks.js +3 -2
  74. package/dist/mcp/transports/stdio-entry.js +6 -28
  75. package/dist/mcp/v2/tools.d.ts +6 -0
  76. package/dist/mcp/v2/tools.js +2 -0
  77. package/dist/mcp/v2-response-formatter.js +2 -4
  78. package/dist/mcp/validation/schema-introspection.d.ts +1 -0
  79. package/dist/mcp/validation/schema-introspection.js +15 -5
  80. package/dist/mcp/validation/suggestion-generator.js +2 -2
  81. package/dist/mcp/workflow-protocol-contracts.js +5 -1
  82. package/dist/runtime/adapters/node-process-signals.d.ts +1 -0
  83. package/dist/runtime/adapters/node-process-signals.js +5 -0
  84. package/dist/runtime/adapters/noop-process-signals.d.ts +1 -0
  85. package/dist/runtime/adapters/noop-process-signals.js +2 -0
  86. package/dist/runtime/ports/process-signals.d.ts +1 -0
  87. package/dist/types/workflow-definition.d.ts +3 -2
  88. package/dist/types/workflow.d.ts +3 -0
  89. package/dist/types/workflow.js +35 -26
  90. package/dist/v2/durable-core/domain/context-template-resolver.js +2 -2
  91. package/dist/v2/durable-core/domain/function-definition-expander.js +2 -17
  92. package/dist/v2/durable-core/domain/prompt-renderer.d.ts +1 -0
  93. package/dist/v2/durable-core/domain/prompt-renderer.js +23 -18
  94. package/dist/v2/durable-core/domain/recap-recovery.js +23 -16
  95. package/dist/v2/durable-core/domain/retrieval-contract.js +13 -7
  96. package/dist/v2/durable-core/session-index.d.ts +22 -0
  97. package/dist/v2/durable-core/session-index.js +58 -0
  98. package/dist/v2/durable-core/sorted-event-log.d.ts +6 -0
  99. package/dist/v2/durable-core/sorted-event-log.js +15 -0
  100. package/dist/v2/infra/local/fs/index.js +8 -8
  101. package/dist/v2/infra/local/session-store/index.d.ts +1 -1
  102. package/dist/v2/infra/local/session-store/index.js +71 -61
  103. package/dist/v2/infra/local/session-summary-provider/index.js +9 -4
  104. package/dist/v2/infra/local/snapshot-store/index.js +2 -1
  105. package/dist/v2/infra/local/workspace-anchor/index.js +4 -1
  106. package/dist/v2/ports/session-event-log-store.port.d.ts +1 -1
  107. package/dist/v2/projections/assessment-consequences.d.ts +2 -1
  108. package/dist/v2/projections/assessment-consequences.js +0 -5
  109. package/dist/v2/projections/assessments.d.ts +2 -1
  110. package/dist/v2/projections/assessments.js +2 -4
  111. package/dist/v2/projections/gaps.d.ts +2 -1
  112. package/dist/v2/projections/gaps.js +0 -5
  113. package/dist/v2/projections/preferences.d.ts +2 -1
  114. package/dist/v2/projections/preferences.js +0 -5
  115. package/dist/v2/projections/run-context.d.ts +2 -2
  116. package/dist/v2/projections/run-context.js +0 -5
  117. package/dist/v2/projections/run-dag.js +7 -1
  118. package/dist/v2/projections/run-execution-trace.d.ts +8 -0
  119. package/dist/v2/projections/run-execution-trace.js +124 -0
  120. package/dist/v2/projections/run-status-signals.d.ts +2 -2
  121. package/dist/v2/usecases/console-routes.d.ts +3 -1
  122. package/dist/v2/usecases/console-routes.js +149 -3
  123. package/dist/v2/usecases/console-service.d.ts +2 -0
  124. package/dist/v2/usecases/console-service.js +87 -26
  125. package/dist/v2/usecases/console-types.d.ts +65 -0
  126. package/dist/v2/usecases/worktree-service.js +87 -8
  127. package/package.json +7 -6
  128. package/spec/authoring-spec.json +82 -1
  129. package/spec/workflow-tags.json +132 -0
  130. package/spec/workflow.schema.json +21 -11
  131. package/workflows/adaptive-ticket-creation.json +33 -8
  132. package/workflows/architecture-scalability-audit.json +50 -9
  133. package/workflows/bug-investigation.agentic.v2.json +43 -14
  134. package/workflows/coding-task-workflow-agentic.json +57 -38
  135. package/workflows/coding-task-workflow-agentic.lean.v2.json +129 -34
  136. package/workflows/coding-task-workflow-agentic.v2.json +97 -30
  137. package/workflows/cross-platform-code-conversion.v2.json +175 -48
  138. package/workflows/document-creation-workflow.json +49 -12
  139. package/workflows/documentation-update-workflow.json +9 -2
  140. package/workflows/intelligent-test-case-generation.json +9 -2
  141. package/workflows/learner-centered-course-workflow.json +273 -266
  142. package/workflows/mr-review-workflow.agentic.v2.json +88 -14
  143. package/workflows/personal-learning-materials-creation-branched.json +181 -174
  144. package/workflows/presentation-creation.json +167 -160
  145. package/workflows/production-readiness-audit.json +61 -15
  146. package/workflows/relocation-workflow-us.json +21 -5
  147. package/workflows/routines/tension-driven-design.json +1 -1
  148. package/workflows/scoped-documentation-workflow.json +9 -2
  149. package/workflows/test-artifact-loop-control.json +1 -2
  150. package/workflows/ui-ux-design-workflow.json +334 -0
  151. package/workflows/workflow-diagnose-environment.json +7 -1
  152. package/workflows/workflow-for-workflows.json +514 -484
  153. package/workflows/workflow-for-workflows.v2.json +55 -11
  154. package/workflows/wr.discovery.json +118 -29
  155. package/dist/console/assets/index-DW78t31j.css +0 -1
  156. package/dist/console/assets/index-EsSXrC_a.js +0 -28
@@ -0,0 +1,37 @@
1
+ export declare function assertOutput<T>(data: T, check: (data: T) => void): T;
2
+ type BlockerPointer = {
3
+ readonly kind: 'context_key';
4
+ readonly key: string;
5
+ } | {
6
+ readonly kind: 'context_budget';
7
+ } | {
8
+ readonly kind: 'output_contract';
9
+ readonly contractRef: string;
10
+ } | {
11
+ readonly kind: 'capability';
12
+ readonly capability: string;
13
+ } | {
14
+ readonly kind: 'assessment_dimension';
15
+ readonly assessmentId: string;
16
+ readonly dimensionId: string;
17
+ } | {
18
+ readonly kind: 'workflow_step';
19
+ readonly stepId: string;
20
+ };
21
+ type BlockerLike = {
22
+ readonly code: string;
23
+ readonly pointer: BlockerPointer;
24
+ };
25
+ type BlockerReportLike = {
26
+ readonly blockers: readonly BlockerLike[];
27
+ };
28
+ export declare function assertBlockerReportInvariants(report: BlockerReportLike): void;
29
+ type PendingLike = {
30
+ readonly stepId: string;
31
+ } | null;
32
+ type ContinueTokenHolder = {
33
+ readonly continueToken?: string | null | undefined;
34
+ readonly pending: PendingLike;
35
+ };
36
+ export declare function assertContinueTokenPresence(data: ContinueTokenHolder): void;
37
+ export {};
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assertOutput = assertOutput;
4
+ exports.assertBlockerReportInvariants = assertBlockerReportInvariants;
5
+ exports.assertContinueTokenPresence = assertContinueTokenPresence;
6
+ function assertOutput(data, check) {
7
+ if (process.env['WORKRAIL_DEV'] === '1') {
8
+ check(data);
9
+ }
10
+ return data;
11
+ }
12
+ function assertBlockerReportInvariants(report) {
13
+ const keyFor = (b) => {
14
+ const p = b.pointer;
15
+ let ptrStable;
16
+ switch (p.kind) {
17
+ case 'context_key':
18
+ ptrStable = p.key;
19
+ break;
20
+ case 'output_contract':
21
+ ptrStable = p.contractRef;
22
+ break;
23
+ case 'capability':
24
+ ptrStable = p.capability;
25
+ break;
26
+ case 'assessment_dimension':
27
+ ptrStable = `${p.assessmentId}|${p.dimensionId}`;
28
+ break;
29
+ case 'workflow_step':
30
+ ptrStable = p.stepId;
31
+ break;
32
+ case 'context_budget':
33
+ ptrStable = '';
34
+ break;
35
+ default: {
36
+ const _exhaustive = p;
37
+ ptrStable = String(_exhaustive);
38
+ }
39
+ }
40
+ return `${b.code}|${p.kind}|${String(ptrStable)}`;
41
+ };
42
+ for (let i = 1; i < report.blockers.length; i++) {
43
+ if (keyFor(report.blockers[i - 1]) > keyFor(report.blockers[i])) {
44
+ throw new Error('assertOutput: blockers must be deterministically sorted by composite key');
45
+ }
46
+ }
47
+ }
48
+ function assertContinueTokenPresence(data) {
49
+ if (data.pending != null && data.continueToken == null) {
50
+ throw new Error('assertOutput: continueToken is required when a pending step exists');
51
+ }
52
+ }
@@ -1,2 +1,3 @@
1
1
  import { z } from 'zod';
2
+ export declare function buildCoercionFn(shapeSchema: z.ZodObject<z.ZodRawShape>, aliasMap?: Readonly<Record<string, string>>): (args: unknown) => unknown;
2
3
  export declare function coerceJsonStringObjectFields(args: unknown, shapeSchema: z.ZodObject<z.ZodRawShape>, aliasMap?: Readonly<Record<string, string>>): unknown;
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildCoercionFn = buildCoercionFn;
3
4
  exports.coerceJsonStringObjectFields = coerceJsonStringObjectFields;
4
5
  const zod_1 = require("zod");
6
+ const schema_introspection_js_1 = require("./validation/schema-introspection.js");
5
7
  function unwrapToBaseType(schema) {
6
8
  let current = schema;
7
9
  for (;;) {
@@ -32,6 +34,48 @@ function tryParseJsonObject(value) {
32
34
  return null;
33
35
  }
34
36
  }
37
+ function buildCoercionFn(shapeSchema, aliasMap) {
38
+ const shape = (0, schema_introspection_js_1.getCachedShape)(shapeSchema);
39
+ const objectFields = new Set();
40
+ for (const [key, fieldSchema] of Object.entries(shape)) {
41
+ if (expectsObjectValue(fieldSchema)) {
42
+ objectFields.add(key);
43
+ }
44
+ }
45
+ const aliasesToCoerce = new Set();
46
+ if (aliasMap) {
47
+ for (const [alias, canonical] of Object.entries(aliasMap)) {
48
+ if (objectFields.has(canonical)) {
49
+ aliasesToCoerce.add(alias);
50
+ }
51
+ }
52
+ }
53
+ const hasCoercibleFields = objectFields.size > 0 || aliasesToCoerce.size > 0;
54
+ return (args) => {
55
+ if (!hasCoercibleFields)
56
+ return args;
57
+ if (typeof args !== 'object' || args === null)
58
+ return args;
59
+ const input = args;
60
+ let result = null;
61
+ const coerceField = (key) => {
62
+ const value = input[key];
63
+ if (typeof value !== 'string')
64
+ return;
65
+ const parsed = tryParseJsonObject(value);
66
+ if (parsed === null)
67
+ return;
68
+ if (result === null)
69
+ result = { ...input };
70
+ result[key] = parsed;
71
+ };
72
+ for (const key of objectFields)
73
+ coerceField(key);
74
+ for (const alias of aliasesToCoerce)
75
+ coerceField(alias);
76
+ return result ?? args;
77
+ };
78
+ }
35
79
  function coerceJsonStringObjectFields(args, shapeSchema, aliasMap) {
36
80
  if (typeof args !== 'object' || args === null)
37
81
  return args;
@@ -0,0 +1 @@
1
+ export declare const DEV_MODE: boolean;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEV_MODE = void 0;
4
+ exports.DEV_MODE = process.env['WORKRAIL_DEV'] === '1';
@@ -36,7 +36,7 @@ function toMcpResult(result) {
36
36
  return {
37
37
  content: [{
38
38
  type: 'text',
39
- text: JSON.stringify(jsonPayload, null, 2),
39
+ text: JSON.stringify(jsonPayload),
40
40
  }],
41
41
  };
42
42
  }
@@ -49,17 +49,18 @@ function toMcpResult(result) {
49
49
  message: result.message,
50
50
  retry: result.retry,
51
51
  ...(result.details !== undefined ? { details: result.details } : {}),
52
- }, null, 2),
52
+ }),
53
53
  }],
54
54
  isError: true,
55
55
  };
56
56
  }
57
57
  }
58
58
  function createHandler(schema, handler, shapeSchema, aliasMap) {
59
+ const coerce = shapeSchema !== undefined
60
+ ? (0, boundary_coercion_js_1.buildCoercionFn)(shapeSchema, aliasMap)
61
+ : null;
59
62
  return async (args, ctx) => {
60
- const normalizedArgs = shapeSchema !== undefined
61
- ? (0, boundary_coercion_js_1.coerceJsonStringObjectFields)(args, shapeSchema, aliasMap)
62
- : args;
63
+ const normalizedArgs = coerce !== null ? coerce(args) : args;
63
64
  const parseResult = schema.safeParse(normalizedArgs);
64
65
  if (!parseResult.success) {
65
66
  const introspectionSchema = shapeSchema ?? schema;
@@ -87,10 +88,12 @@ function createHandler(schema, handler, shapeSchema, aliasMap) {
87
88
  };
88
89
  }
89
90
  function createValidatingHandler(schema, preValidate, handler, shapeSchema, aliasMap) {
91
+ const coerce = shapeSchema !== undefined
92
+ ? (0, boundary_coercion_js_1.buildCoercionFn)(shapeSchema, aliasMap)
93
+ : null;
94
+ const innerHandler = createHandler(schema, handler, shapeSchema);
90
95
  return async (args, ctx) => {
91
- const normalizedArgs = shapeSchema !== undefined
92
- ? (0, boundary_coercion_js_1.coerceJsonStringObjectFields)(args, shapeSchema, aliasMap)
93
- : args;
96
+ const normalizedArgs = coerce !== null ? coerce(args) : args;
94
97
  const pre = preValidate(normalizedArgs);
95
98
  if (!pre.ok) {
96
99
  const error = pre.error;
@@ -110,6 +113,6 @@ function createValidatingHandler(schema, preValidate, handler, shapeSchema, alia
110
113
  }
111
114
  return toMcpResult(error);
112
115
  }
113
- return createHandler(schema, handler, shapeSchema, aliasMap)(normalizedArgs, ctx);
116
+ return innerHandler(normalizedArgs, ctx);
114
117
  };
115
118
  }
@@ -5,7 +5,6 @@ exports.handleUpdateSession = handleUpdateSession;
5
5
  exports.handleReadSession = handleReadSession;
6
6
  exports.handleOpenDashboard = handleOpenDashboard;
7
7
  const types_js_1 = require("../types.js");
8
- const output_schemas_js_1 = require("../output-schemas.js");
9
8
  const SESSION_SCHEMA_OVERVIEW = {
10
9
  description: 'Bug Investigation Session Data Structure',
11
10
  mainSections: {
@@ -58,13 +57,13 @@ async function handleCreateSession(input, ctx) {
58
57
  const session = res.value;
59
58
  const baseUrl = httpServer.getBaseUrl();
60
59
  const dashboardUrl = baseUrl ? `${baseUrl}?session=${input.sessionId}` : null;
61
- const payload = output_schemas_js_1.CreateSessionOutputSchema.parse({
60
+ const payload = {
62
61
  sessionId: session.id,
63
62
  workflowId: session.workflowId,
64
63
  path: sessionManager.getSessionPath(input.workflowId, input.sessionId),
65
64
  dashboardUrl,
66
65
  createdAt: session.createdAt,
67
- });
66
+ };
68
67
  return (0, types_js_1.success)(payload);
69
68
  }
70
69
  async function handleUpdateSession(input, ctx) {
@@ -81,7 +80,7 @@ async function handleUpdateSession(input, ctx) {
81
80
  }
82
81
  return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', res.error.message);
83
82
  }
84
- const payload = output_schemas_js_1.UpdateSessionOutputSchema.parse({ updatedAt: new Date().toISOString() });
83
+ const payload = { updatedAt: new Date().toISOString() };
85
84
  return (0, types_js_1.success)(payload);
86
85
  }
87
86
  async function handleReadSession(input, ctx) {
@@ -90,10 +89,10 @@ async function handleReadSession(input, ctx) {
90
89
  return guardError;
91
90
  const sessionManager = ctx.sessionManager;
92
91
  if (input.path === '$schema') {
93
- const payload = output_schemas_js_1.ReadSessionSchemaOutputSchema.parse({
92
+ const payload = {
94
93
  query: '$schema',
95
94
  schema: SESSION_SCHEMA_OVERVIEW,
96
- });
95
+ };
97
96
  return (0, types_js_1.success)(payload);
98
97
  }
99
98
  const res = await sessionManager.readSession(input.workflowId, input.sessionId, input.path);
@@ -105,10 +104,10 @@ async function handleReadSession(input, ctx) {
105
104
  }
106
105
  return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', res.error.message);
107
106
  }
108
- const payload = output_schemas_js_1.ReadSessionOutputSchema.parse({
107
+ const payload = {
109
108
  query: input.path ?? '(full session)',
110
109
  data: res.value,
111
- });
110
+ };
112
111
  return (0, types_js_1.success)(payload);
113
112
  }
114
113
  async function handleOpenDashboard(input, ctx) {
@@ -118,7 +117,7 @@ async function handleOpenDashboard(input, ctx) {
118
117
  const httpServer = ctx.httpServer;
119
118
  try {
120
119
  const url = await httpServer.openDashboard(input.sessionId);
121
- const payload = output_schemas_js_1.OpenDashboardOutputSchema.parse({ url });
120
+ const payload = { url };
122
121
  return (0, types_js_1.success)(payload);
123
122
  }
124
123
  catch (err) {
@@ -1,12 +1,14 @@
1
1
  import type { IWorkflowReader } from '../../../types/storage.js';
2
2
  import type { IFeatureFlagProvider } from '../../../config/feature-flags.js';
3
3
  import type { RememberedRootsStorePortV2 } from '../../../v2/ports/remembered-roots-store.port.js';
4
+ import type { ManagedSourceRecordV2, ManagedSourceStorePortV2 } from '../../../v2/ports/managed-source-store.port.js';
4
5
  export interface RequestWorkflowReaderOptions {
5
6
  readonly featureFlags: IFeatureFlagProvider;
6
7
  readonly workspacePath?: string;
7
8
  readonly resolvedRootUris?: readonly string[];
8
9
  readonly serverCwd?: string;
9
10
  readonly rememberedRootsStore?: RememberedRootsStorePortV2;
11
+ readonly managedSourceStore?: ManagedSourceStorePortV2;
10
12
  }
11
13
  export declare function hasRequestWorkspaceSignal(options: {
12
14
  readonly workspacePath?: string;
@@ -26,5 +28,8 @@ export declare function discoverRootedWorkflowDirectories(roots: readonly string
26
28
  export interface WorkflowReaderForRequestResult {
27
29
  readonly reader: IWorkflowReader;
28
30
  readonly stalePaths: readonly string[];
31
+ readonly managedSourceRecords: readonly ManagedSourceRecordV2[];
32
+ readonly staleManagedRecords: readonly ManagedSourceRecordV2[];
33
+ readonly managedStoreError?: string;
29
34
  }
30
35
  export declare function createWorkflowReaderForRequest(options: RequestWorkflowReaderOptions): Promise<WorkflowReaderForRequestResult>;
@@ -60,13 +60,58 @@ async function createWorkflowReaderForRequest(options) {
60
60
  const projectWorkflowDirectory = toProjectWorkflowDirectory(workspaceDirectory);
61
61
  const rememberedRoots = await listRememberedRoots(options.rememberedRootsStore);
62
62
  const { discovered: rootedWorkflowDirectories, stale: stalePaths } = await discoverRootedWorkflowDirectories(rememberedRoots);
63
- const customPaths = rootedWorkflowDirectories.filter((directory) => directory !== projectWorkflowDirectory);
63
+ const rootedCustomPaths = rootedWorkflowDirectories.filter((directory) => directory !== projectWorkflowDirectory);
64
+ const { records: allManagedRecords, storeError: managedStoreError } = await listManagedSourceRecords(options.managedSourceStore);
65
+ const envCustomPaths = parseWorkflowStoragePathEnv();
66
+ const normalizedCustom = new Set([
67
+ ...rootedCustomPaths.map((p) => path_1.default.resolve(p)),
68
+ ...envCustomPaths.map((p) => path_1.default.resolve(p)),
69
+ ]);
70
+ const additionalManagedPaths = [];
71
+ const activeManagedRecords = [];
72
+ const staleManagedRecords = [];
73
+ for (const record of allManagedRecords) {
74
+ if (normalizedCustom.has(path_1.default.resolve(record.path))) {
75
+ activeManagedRecords.push(record);
76
+ continue;
77
+ }
78
+ if (await isDirectory(record.path)) {
79
+ additionalManagedPaths.push(record.path);
80
+ activeManagedRecords.push(record);
81
+ }
82
+ else {
83
+ staleManagedRecords.push(record);
84
+ }
85
+ }
86
+ const customPaths = [...rootedCustomPaths, ...additionalManagedPaths];
87
+ const allStalePaths = [...stalePaths, ...staleManagedRecords.map((r) => r.path)];
64
88
  const storage = (0, enhanced_multi_source_workflow_storage_js_1.createEnhancedMultiSourceWorkflowStorage)({
65
89
  customPaths,
66
90
  projectPath: projectWorkflowDirectory,
67
91
  }, options.featureFlags ?? undefined);
68
92
  const reader = new schema_validating_workflow_storage_js_1.SchemaValidatingCompositeWorkflowStorage(storage);
69
- return { reader, stalePaths };
93
+ return {
94
+ reader,
95
+ stalePaths: allStalePaths,
96
+ managedSourceRecords: activeManagedRecords,
97
+ staleManagedRecords,
98
+ ...(managedStoreError !== undefined ? { managedStoreError } : {}),
99
+ };
100
+ }
101
+ function parseWorkflowStoragePathEnv() {
102
+ const raw = process.env['WORKFLOW_STORAGE_PATH'];
103
+ if (!raw)
104
+ return [];
105
+ return raw.split(path_1.default.delimiter).map((p) => p.trim()).filter((p) => p.length > 0);
106
+ }
107
+ async function listManagedSourceRecords(managedSourceStore) {
108
+ if (!managedSourceStore)
109
+ return { records: [] };
110
+ const result = await managedSourceStore.list();
111
+ if (result.isErr()) {
112
+ return { records: [], storeError: `${result.error.code}: ${result.error.message}` };
113
+ }
114
+ return { records: result.value };
70
115
  }
71
116
  async function listRememberedRoots(rememberedRootsStore) {
72
117
  if (!rememberedRootsStore)
@@ -3,7 +3,7 @@ import type { RecordedAssessmentV1 } from '../../../v2/durable-core/domain/asses
3
3
  export interface TriggeredAssessmentConsequenceV1 {
4
4
  readonly kind: 'require_followup';
5
5
  readonly assessmentId: string;
6
- readonly triggerDimensionId: string;
6
+ readonly firstMatchedDimensionId: string;
7
7
  readonly triggerLevel: string;
8
8
  readonly guidance: string;
9
9
  }
@@ -10,15 +10,14 @@ function evaluateAssessmentConsequences(args) {
10
10
  const consequence = args.step.assessmentConsequences[0];
11
11
  if (!consequence)
12
12
  return undefined;
13
- const matchedDimension = args.recordedAssessment.dimensions.find(dimension => dimension.dimensionId === consequence.when.dimensionId &&
14
- dimension.level === consequence.when.equalsLevel);
15
- if (!matchedDimension)
13
+ const matched = args.recordedAssessment.dimensions.find(d => d.level === consequence.when.anyEqualsLevel);
14
+ if (!matched)
16
15
  return undefined;
17
16
  return {
18
17
  kind: 'require_followup',
19
18
  assessmentId: args.recordedAssessment.assessmentId,
20
- triggerDimensionId: consequence.when.dimensionId,
21
- triggerLevel: consequence.when.equalsLevel,
19
+ firstMatchedDimensionId: matched.dimensionId,
20
+ triggerLevel: consequence.when.anyEqualsLevel,
22
21
  guidance: consequence.effect.guidance,
23
22
  };
24
23
  }
@@ -10,8 +10,10 @@ import type { V2ContinueWorkflowInput } from '../../v2/tools.js';
10
10
  import { type OutputToAppend } from '../../../v2/durable-core/domain/outputs.js';
11
11
  import type { InternalError } from '../v2-error-mapping.js';
12
12
  import type { AdvanceCorePorts } from './index.js';
13
+ import type { SessionIndex } from '../../../v2/durable-core/session-index.js';
13
14
  type BuildAppendPlanArgs = {
14
15
  readonly truth: LoadedSessionTruthV2;
16
+ readonly lockedIndex: SessionIndex;
15
17
  readonly sessionId: SessionId;
16
18
  readonly runId: RunId;
17
19
  readonly currentNodeId: NodeId;
@@ -11,15 +11,15 @@ const outputs_js_1 = require("../../../v2/durable-core/domain/outputs.js");
11
11
  const ack_advance_append_plan_js_1 = require("../../../v2/durable-core/domain/ack-advance-append-plan.js");
12
12
  const constants_js_1 = require("../../../v2/durable-core/constants.js");
13
13
  function buildAndAppendPlan(args) {
14
- const { truth, sessionId, runId, currentNodeId, attemptId, workflowHash, extraEventsToAppend, sessionStore, idFactory, lock } = args;
15
- const nextEventIndex = truth.events.length === 0 ? 0 : truth.events[truth.events.length - 1].eventIndex + 1;
14
+ const { truth, lockedIndex, sessionId, runId, currentNodeId, attemptId, workflowHash, extraEventsToAppend, sessionStore, idFactory, lock } = args;
15
+ const nextEventIndex = lockedIndex.nextEventIndex;
16
16
  const evtAdvanceRecorded = idFactory.mintEventId();
17
17
  if (args.kind === 'blocked') {
18
18
  const toNodeId = String(idFactory.mintNodeId());
19
19
  const evtNodeCreated = idFactory.mintEventId();
20
20
  const evtEdgeCreated = idFactory.mintEventId();
21
21
  const outputEventIds = (args.outputsToAppend ?? []).map(() => idFactory.mintEventId());
22
- const hasChildren = truth.events.some((e) => e.kind === constants_js_1.EVENT_KIND.EDGE_CREATED && e.data.fromNodeId === String(currentNodeId));
22
+ const hasChildren = lockedIndex.hasChildEdgeByFromNodeId.has(String(currentNodeId));
23
23
  const causeKind = hasChildren ? constants_js_1.EDGE_CAUSE.NON_TIP_ADVANCE : constants_js_1.EDGE_CAUSE.INTENTIONAL_FORK;
24
24
  const planRes = (0, ack_advance_append_plan_js_1.buildAckAdvanceAppendPlanV1)({
25
25
  sessionId: String(sessionId),
@@ -44,12 +44,12 @@ function buildAndAppendPlan(args) {
44
44
  });
45
45
  if (planRes.isErr())
46
46
  return (0, neverthrow_1.errAsync)({ kind: 'invariant_violation', message: planRes.error.message });
47
- return sessionStore.append(lock, planRes.value);
47
+ return sessionStore.append(lock, planRes.value, truth);
48
48
  }
49
49
  const toNodeId = String(idFactory.mintNodeId());
50
50
  const evtNodeCreated = idFactory.mintEventId();
51
51
  const evtEdgeCreated = idFactory.mintEventId();
52
- const hasChildren = truth.events.some((e) => e.kind === constants_js_1.EVENT_KIND.EDGE_CREATED && e.data.fromNodeId === String(currentNodeId));
52
+ const hasChildren = lockedIndex.hasChildEdgeByFromNodeId.has(String(currentNodeId));
53
53
  const causeKind = hasChildren ? constants_js_1.EDGE_CAUSE.NON_TIP_ADVANCE : constants_js_1.EDGE_CAUSE.INTENTIONAL_FORK;
54
54
  const normalizedOutputs = (0, outputs_js_1.normalizeOutputsForAppend)(args.outputsToAppend);
55
55
  const outputEventIds = normalizedOutputs.map(() => idFactory.mintEventId());
@@ -76,7 +76,7 @@ function buildAndAppendPlan(args) {
76
76
  });
77
77
  if (planRes.isErr())
78
78
  return (0, neverthrow_1.errAsync)({ kind: 'invariant_violation', message: planRes.error.message });
79
- return sessionStore.append(lock, planRes.value);
79
+ return sessionStore.append(lock, planRes.value, truth);
80
80
  }
81
81
  function buildNotesOutputs(allowNotesAppend, attemptId, inputOutput) {
82
82
  if (!allowNotesAppend || !inputOutput?.notesMarkdown)
@@ -1,4 +1,5 @@
1
1
  import { ResultAsync as RA } from 'neverthrow';
2
+ import type { SessionIndex } from '../../../v2/durable-core/session-index.js';
2
3
  import type { ExecutionSnapshotFileV1, EngineStateV1 } from '../../../v2/durable-core/schemas/execution-snapshot/index.js';
3
4
  import type { SessionId, RunId, NodeId, WorkflowHash } from '../../../v2/durable-core/ids/index.js';
4
5
  import type { AttemptId } from '../../../v2/durable-core/tokens/index.js';
@@ -63,4 +64,5 @@ export declare function executeAdvanceCore(args: {
63
64
  readonly lock: WithHealthySessionLock;
64
65
  readonly pinnedWorkflow: ReturnType<typeof createWorkflow>;
65
66
  readonly ports: AdvanceCorePorts;
67
+ readonly lockedIndex: SessionIndex;
66
68
  }): RA<void, InternalError | SessionEventLogStoreError | SnapshotStoreError>;
@@ -39,6 +39,7 @@ function executeAdvanceCore(args) {
39
39
  }
40
40
  const validatedRes = (0, input_validation_js_1.validateAdvanceInputs)({
41
41
  truth, runId, currentNodeId, inputContext, inputOutput, pinnedWorkflow, pendingStep,
42
+ precomputedIndex: args.lockedIndex,
42
43
  });
43
44
  if (validatedRes.isErr())
44
45
  return errAsync(validatedRes.error);
@@ -71,7 +72,7 @@ function executeAdvanceCore(args) {
71
72
  const ctx = { truth, sessionId, runId, currentNodeId, attemptId, workflowHash, inputOutput, pinnedWorkflow, engineState, pendingStep };
72
73
  const computed = { reasons: effectiveReasons, outputRequirement, validation: evalValidation };
73
74
  const portsLocal = { snapshotStore, sessionStore, sha256, idFactory };
74
- return (0, outcome_blocked_js_1.buildBlockedOutcome)({ mode, snap, ctx, computed, v, lock, ports: portsLocal });
75
+ return (0, outcome_blocked_js_1.buildBlockedOutcome)({ mode, snap, ctx, computed, v, lock, ports: portsLocal, lockedIndex: args.lockedIndex });
75
76
  }
76
77
  const validation = phase.validation;
77
78
  const effectiveValidation = v.assessmentValidation && !v.assessmentValidation.validation.valid
@@ -94,7 +95,7 @@ function executeAdvanceCore(args) {
94
95
  assessmentFollowupRequired: v.triggeredAssessmentConsequence
95
96
  ? {
96
97
  assessmentId: v.triggeredAssessmentConsequence.assessmentId,
97
- dimensionId: v.triggeredAssessmentConsequence.triggerDimensionId,
98
+ dimensionId: v.triggeredAssessmentConsequence.firstMatchedDimensionId,
98
99
  level: v.triggeredAssessmentConsequence.triggerLevel,
99
100
  guidance: v.triggeredAssessmentConsequence.guidance,
100
101
  }
@@ -110,9 +111,9 @@ function executeAdvanceCore(args) {
110
111
  const computed = { reasons, outputRequirement, validation: effectiveValidation };
111
112
  const ports = { snapshotStore, sessionStore, sha256, idFactory };
112
113
  if (shouldBlockNow) {
113
- return (0, outcome_blocked_js_1.buildBlockedOutcome)({ mode, snap, ctx, computed, v, lock, ports });
114
+ return (0, outcome_blocked_js_1.buildBlockedOutcome)({ mode, snap, ctx, computed, v, lock, ports, lockedIndex: args.lockedIndex });
114
115
  }
115
- return (0, outcome_success_js_1.buildSuccessOutcome)({ mode, ctx, computed, v, lock, ports });
116
+ return (0, outcome_success_js_1.buildSuccessOutcome)({ mode, ctx, computed, v, lock, ports, lockedIndex: args.lockedIndex });
116
117
  });
117
118
  }
118
119
  function derivePendingStepForMode(mode, engineState) {
@@ -9,6 +9,7 @@ import type { AssessmentArtifactV1 } from '../../../v2/durable-core/schemas/arti
9
9
  import type { RecordedAssessmentV1 } from '../../../v2/durable-core/domain/assessment-record.js';
10
10
  import type { TriggeredAssessmentConsequenceV1 } from './assessment-consequences.js';
11
11
  import type { InternalError } from '../v2-error-mapping.js';
12
+ import type { SessionIndex } from '../../../v2/durable-core/session-index.js';
12
13
  export interface ValidatedAdvanceInputs {
13
14
  readonly pendingStep: {
14
15
  readonly stepId: string;
@@ -50,4 +51,5 @@ export declare function validateAdvanceInputs(args: {
50
51
  readonly iteration: number;
51
52
  }[];
52
53
  };
54
+ readonly precomputedIndex?: SessionIndex;
53
55
  }): Result<ValidatedAdvanceInputs, InternalError>;
@@ -5,14 +5,28 @@ const neverthrow_1 = require("neverthrow");
5
5
  const workflow_js_1 = require("../../../types/workflow.js");
6
6
  const run_context_js_1 = require("../../../v2/projections/run-context.js");
7
7
  const preferences_js_1 = require("../../../v2/projections/preferences.js");
8
+ const sorted_event_log_js_1 = require("../../../v2/durable-core/sorted-event-log.js");
8
9
  const context_merge_js_1 = require("../../../v2/durable-core/domain/context-merge.js");
9
10
  const constants_js_1 = require("../../../v2/durable-core/constants.js");
10
11
  const assessment_validation_js_1 = require("./assessment-validation.js");
11
12
  const assessment_consequences_js_1 = require("./assessment-consequences.js");
12
13
  function validateAdvanceInputs(args) {
13
14
  const { truth, runId, currentNodeId, inputContext, inputOutput, pinnedWorkflow, pendingStep } = args;
14
- const storedContextRes = (0, run_context_js_1.projectRunContextV2)(truth.events);
15
- const storedContext = storedContextRes.isOk() ? storedContextRes.value.byRunId[String(runId)]?.context : undefined;
15
+ let sortedEvents;
16
+ let storedContext;
17
+ if (args.precomputedIndex) {
18
+ sortedEvents = args.precomputedIndex.sortedEvents;
19
+ storedContext = args.precomputedIndex.runContextByRunId.get(String(runId));
20
+ }
21
+ else {
22
+ const sortedEventsRes = (0, sorted_event_log_js_1.asSortedEventLog)(truth.events);
23
+ if (sortedEventsRes.isErr()) {
24
+ return (0, neverthrow_1.err)({ kind: 'invariant_violation', message: sortedEventsRes.error.message });
25
+ }
26
+ sortedEvents = sortedEventsRes.value;
27
+ const storedContextRes = (0, run_context_js_1.projectRunContextV2)(sortedEvents);
28
+ storedContext = storedContextRes.isOk() ? storedContextRes.value.byRunId[String(runId)]?.context : undefined;
29
+ }
16
30
  const inputContextObj = inputContext && typeof inputContext === 'object' && inputContext !== null && !Array.isArray(inputContext)
17
31
  ? inputContext
18
32
  : undefined;
@@ -39,14 +53,23 @@ function validateAdvanceInputs(args) {
39
53
  const notesOptional = outputContract !== undefined ||
40
54
  (step !== null && step !== undefined && 'notesOptional' in step && step.notesOptional === true);
41
55
  const parentByNodeId = {};
42
- for (const e of truth.events) {
43
- if (e.kind !== constants_js_1.EVENT_KIND.NODE_CREATED)
44
- continue;
45
- if (e.scope?.runId !== String(runId))
46
- continue;
47
- parentByNodeId[String(e.scope.nodeId)] = e.data.parentNodeId;
56
+ if (args.precomputedIndex) {
57
+ for (const [nodeId, evt] of args.precomputedIndex.nodeCreatedByNodeId) {
58
+ if (evt.scope.runId === String(runId)) {
59
+ parentByNodeId[nodeId] = evt.data.parentNodeId ?? null;
60
+ }
61
+ }
62
+ }
63
+ else {
64
+ for (const e of truth.events) {
65
+ if (e.kind !== constants_js_1.EVENT_KIND.NODE_CREATED)
66
+ continue;
67
+ if (e.scope?.runId !== String(runId))
68
+ continue;
69
+ parentByNodeId[String(e.scope.nodeId)] = e.data.parentNodeId;
70
+ }
48
71
  }
49
- const prefs = (0, preferences_js_1.projectPreferencesV2)(truth.events, parentByNodeId);
72
+ const prefs = (0, preferences_js_1.projectPreferencesV2)(sortedEvents, parentByNodeId);
50
73
  const effectivePrefs = prefs.isOk() ? prefs.value.byNodeId[String(currentNodeId)]?.effective : undefined;
51
74
  const rawAutonomy = effectivePrefs?.autonomy ?? 'guided';
52
75
  const rawRiskPolicy = effectivePrefs?.riskPolicy ?? 'conservative';
@@ -1,4 +1,5 @@
1
1
  import { ResultAsync as RA } from 'neverthrow';
2
+ import type { SessionIndex } from '../../../v2/durable-core/session-index.js';
2
3
  import type { ExecutionSnapshotFileV1 } from '../../../v2/durable-core/schemas/execution-snapshot/index.js';
3
4
  import type { SessionEventLogStoreError } from '../../../v2/ports/session-event-log-store.port.js';
4
5
  import type { SnapshotStoreError } from '../../../v2/ports/snapshot-store.port.js';
@@ -15,4 +16,5 @@ export declare function buildBlockedOutcome(args: {
15
16
  readonly v: ValidatedAdvanceInputs;
16
17
  readonly lock: WithHealthySessionLock;
17
18
  readonly ports: AdvanceCorePorts;
19
+ readonly lockedIndex: SessionIndex;
18
20
  }): RA<void, InternalError | SessionEventLogStoreError | SnapshotStoreError>;
@@ -89,7 +89,7 @@ function buildBlockedOutcome(args) {
89
89
  attemptId: String(attemptId),
90
90
  scope: { runId: String(runId), nodeId: String(currentNodeId) },
91
91
  assessmentId: validated.triggeredAssessmentConsequence.assessmentId,
92
- dimensionId: validated.triggeredAssessmentConsequence.triggerDimensionId,
92
+ dimensionId: validated.triggeredAssessmentConsequence.firstMatchedDimensionId,
93
93
  level: validated.triggeredAssessmentConsequence.triggerLevel,
94
94
  guidance: validated.triggeredAssessmentConsequence.guidance,
95
95
  minted: { eventId: idFactory.mintEventId() },
@@ -102,7 +102,7 @@ function buildBlockedOutcome(args) {
102
102
  return snapshotStore.putExecutionSnapshotV1(blockedSnapshotRes.value).andThen((blockedSnapshotRef) => {
103
103
  return (0, event_builders_js_1.buildAndAppendPlan)({
104
104
  kind: 'blocked',
105
- truth, sessionId, runId, currentNodeId, attemptId, workflowHash,
105
+ truth, lockedIndex: args.lockedIndex, sessionId, runId, currentNodeId, attemptId, workflowHash,
106
106
  extraEventsToAppend, blockers: blockersRes.value, snapshotRef: blockedSnapshotRef,
107
107
  outputsToAppend,
108
108
  sessionStore, idFactory, lock,
@@ -1,4 +1,5 @@
1
1
  import { ResultAsync as RA } from 'neverthrow';
2
+ import type { SessionIndex } from '../../../v2/durable-core/session-index.js';
2
3
  import type { SessionEventLogStoreError } from '../../../v2/ports/session-event-log-store.port.js';
3
4
  import type { SnapshotStoreError } from '../../../v2/ports/snapshot-store.port.js';
4
5
  import type { WithHealthySessionLock } from '../../../v2/durable-core/ids/with-healthy-session-lock.js';
@@ -12,4 +13,5 @@ export declare function buildSuccessOutcome(args: {
12
13
  readonly v: ValidatedAdvanceInputs;
13
14
  readonly lock: WithHealthySessionLock;
14
15
  readonly ports: AdvanceCorePorts;
16
+ readonly lockedIndex: SessionIndex;
15
17
  }): RA<void, InternalError | SessionEventLogStoreError | SnapshotStoreError>;
@@ -149,7 +149,7 @@ function buildSuccessOutcome(args) {
149
149
  const outputsToAppend = [...notesOutputs, ...artifactOutputsRes.value];
150
150
  return (0, event_builders_js_1.buildAndAppendPlan)({
151
151
  kind: 'advanced',
152
- truth, sessionId, runId, currentNodeId, attemptId, workflowHash,
152
+ truth, lockedIndex: args.lockedIndex, sessionId, runId, currentNodeId, attemptId, workflowHash,
153
153
  extraEventsToAppend, toNodeKind: successNodeKind(mode),
154
154
  snapshotRef: newSnapshotRef, outputsToAppend,
155
155
  sessionStore, idFactory, lock,