@exaudeus/workrail 3.5.0 → 3.6.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 (44) hide show
  1. package/dist/application/services/validation-engine.js +50 -0
  2. package/dist/config/feature-flags.js +8 -0
  3. package/dist/engine/engine-factory.js +4 -2
  4. package/dist/manifest.json +100 -52
  5. package/dist/mcp/handler-factory.js +21 -4
  6. package/dist/mcp/handlers/v2-execution/continue-rehydrate.d.ts +6 -1
  7. package/dist/mcp/handlers/v2-execution/continue-rehydrate.js +22 -4
  8. package/dist/mcp/handlers/v2-execution/index.d.ts +6 -1
  9. package/dist/mcp/handlers/v2-execution/index.js +13 -3
  10. package/dist/mcp/handlers/v2-execution/start.d.ts +9 -1
  11. package/dist/mcp/handlers/v2-execution/start.js +74 -36
  12. package/dist/mcp/handlers/v2-execution-helpers.d.ts +2 -0
  13. package/dist/mcp/handlers/v2-execution-helpers.js +2 -0
  14. package/dist/mcp/handlers/v2-reference-resolver.d.ts +14 -0
  15. package/dist/mcp/handlers/v2-reference-resolver.js +112 -0
  16. package/dist/mcp/handlers/v2-resolve-refs-envelope.d.ts +5 -0
  17. package/dist/mcp/handlers/v2-resolve-refs-envelope.js +17 -0
  18. package/dist/mcp/handlers/v2-workflow.js +2 -0
  19. package/dist/mcp/output-schemas.d.ts +38 -0
  20. package/dist/mcp/output-schemas.js +8 -0
  21. package/dist/mcp/render-envelope.d.ts +21 -0
  22. package/dist/mcp/render-envelope.js +59 -0
  23. package/dist/mcp/response-supplements.d.ts +17 -0
  24. package/dist/mcp/response-supplements.js +58 -0
  25. package/dist/mcp/step-content-envelope.d.ts +32 -0
  26. package/dist/mcp/step-content-envelope.js +13 -0
  27. package/dist/mcp/v2-response-formatter.d.ts +11 -1
  28. package/dist/mcp/v2-response-formatter.js +168 -1
  29. package/dist/mcp/workflow-protocol-contracts.js +9 -7
  30. package/dist/types/workflow-definition.d.ts +16 -0
  31. package/dist/types/workflow-definition.js +1 -0
  32. package/dist/utils/condition-evaluator.d.ts +1 -0
  33. package/dist/utils/condition-evaluator.js +7 -0
  34. package/dist/v2/durable-core/domain/context-template-resolver.d.ts +2 -0
  35. package/dist/v2/durable-core/domain/context-template-resolver.js +26 -0
  36. package/dist/v2/durable-core/domain/prompt-renderer.d.ts +2 -0
  37. package/dist/v2/durable-core/domain/prompt-renderer.js +93 -15
  38. package/dist/v2/durable-core/schemas/compiled-workflow/index.d.ts +256 -0
  39. package/dist/v2/durable-core/schemas/compiled-workflow/index.js +30 -0
  40. package/package.json +4 -1
  41. package/spec/authoring-spec.provenance.json +77 -0
  42. package/spec/authoring-spec.schema.json +370 -0
  43. package/workflows/coding-task-workflow-agentic.lean.v2.json +132 -30
  44. package/workflows/workflow-for-workflows.json +27 -1
@@ -24,8 +24,11 @@ const constants_js_1 = require("../../../v2/durable-core/constants.js");
24
24
  const index_js_2 = require("./index.js");
25
25
  const start_construction_js_1 = require("../../../v2/durable-core/domain/start-construction.js");
26
26
  const request_workflow_reader_js_1 = require("../shared/request-workflow-reader.js");
27
+ const step_content_envelope_js_1 = require("../../step-content-envelope.js");
28
+ const v2_workspace_resolution_js_2 = require("../v2-workspace-resolution.js");
29
+ const v2_reference_resolver_js_1 = require("../v2-reference-resolver.js");
27
30
  function loadAndPinWorkflow(args) {
28
- const { workflowId, workflowReader, crypto, pinnedStore, validationPipelineDeps } = args;
31
+ const { workflowId, workflowReader, crypto, pinnedStore, validationPipelineDeps, workspacePath, resolvedRootUris } = args;
29
32
  return neverthrow_1.ResultAsync.fromPromise(workflowReader.getWorkflowById(workflowId), (e) => ({
30
33
  kind: 'precondition_failed',
31
34
  message: e instanceof Error ? e.message : String(e),
@@ -59,38 +62,48 @@ function loadAndPinWorkflow(args) {
59
62
  });
60
63
  }
61
64
  const compiled = pipelineOutcome.snapshot;
62
- const workflowHashRes = (0, hashing_js_1.workflowHashForCompiledSnapshot)(compiled, crypto);
63
- if (workflowHashRes.isErr()) {
64
- return (0, neverthrow_1.errAsync)({ kind: 'hash_computation_failed', message: workflowHashRes.error.message });
65
- }
66
- const workflowHash = workflowHashRes.value;
67
- return pinnedStore.get(workflowHash)
68
- .mapErr((cause) => ({ kind: 'pinned_workflow_store_failed', cause }))
69
- .andThen((existingPinned) => {
70
- if (!existingPinned) {
71
- return pinnedStore.put(workflowHash, compiled)
72
- .mapErr((cause) => ({ kind: 'pinned_workflow_store_failed', cause }));
65
+ const bindingBaseDir = (0, v2_workspace_resolution_js_2.resolveBindingBaseDir)(workspacePath, resolvedRootUris ?? []);
66
+ return enrichPinnedSnapshotWithResolvedReferences(compiled, workflow.definition.references ?? [], bindingBaseDir)
67
+ .andThen(({ snapshot: enrichedCompiled, resolvedReferences }) => {
68
+ const workflowHashRes = (0, hashing_js_1.workflowHashForCompiledSnapshot)(enrichedCompiled, crypto);
69
+ if (workflowHashRes.isErr()) {
70
+ return (0, neverthrow_1.errAsync)({ kind: 'hash_computation_failed', message: workflowHashRes.error.message });
73
71
  }
74
- return (0, neverthrow_1.okAsync)(undefined);
75
- })
76
- .andThen(() => pinnedStore.get(workflowHash).mapErr((cause) => ({ kind: 'pinned_workflow_store_failed', cause })))
77
- .andThen((pinned) => {
78
- if (!pinned || pinned.sourceKind !== 'v1_pinned' || !(0, workflow_definition_js_1.hasWorkflowDefinitionShape)(pinned.definition)) {
79
- return (0, neverthrow_1.errAsync)({
80
- kind: 'invariant_violation',
81
- message: 'Failed to pin executable workflow snapshot (missing or invalid pinned workflow).',
72
+ const workflowHash = workflowHashRes.value;
73
+ return pinnedStore.get(workflowHash)
74
+ .mapErr((cause) => ({ kind: 'pinned_workflow_store_failed', cause }))
75
+ .andThen((existingPinned) => {
76
+ if (!existingPinned) {
77
+ return pinnedStore.put(workflowHash, enrichedCompiled)
78
+ .mapErr((cause) => ({ kind: 'pinned_workflow_store_failed', cause }));
79
+ }
80
+ return (0, neverthrow_1.okAsync)(undefined);
81
+ })
82
+ .andThen(() => pinnedStore.get(workflowHash).mapErr((cause) => ({ kind: 'pinned_workflow_store_failed', cause })))
83
+ .andThen((pinned) => {
84
+ if (!pinned || pinned.sourceKind !== 'v1_pinned' || !(0, workflow_definition_js_1.hasWorkflowDefinitionShape)(pinned.definition)) {
85
+ return (0, neverthrow_1.errAsync)({
86
+ kind: 'invariant_violation',
87
+ message: 'Failed to pin executable workflow snapshot (missing or invalid pinned workflow).',
88
+ });
89
+ }
90
+ const pinnedWorkflow = (0, workflow_js_1.createWorkflow)(pinned.definition, (0, workflow_source_js_1.createBundledSource)());
91
+ const resolution = (0, start_construction_js_1.resolveFirstStep)(workflow, pinned);
92
+ if (resolution.isErr()) {
93
+ const error = resolution.error.reason === 'no_steps'
94
+ ? { kind: 'workflow_has_no_steps', workflowId: (0, index_js_1.asWorkflowId)(resolution.error.detail) }
95
+ : { kind: 'invariant_violation', message: resolution.error.detail };
96
+ return (0, neverthrow_1.errAsync)(error);
97
+ }
98
+ const firstStep = resolution.value;
99
+ return (0, neverthrow_1.okAsync)({
100
+ workflow,
101
+ firstStep,
102
+ workflowHash,
103
+ pinnedWorkflow,
104
+ resolvedReferences: pinned.resolvedReferences ?? resolvedReferences,
82
105
  });
83
- }
84
- const pinnedWorkflow = (0, workflow_js_1.createWorkflow)(pinned.definition, (0, workflow_source_js_1.createBundledSource)());
85
- const resolution = (0, start_construction_js_1.resolveFirstStep)(workflow, pinned);
86
- if (resolution.isErr()) {
87
- const error = resolution.error.reason === 'no_steps'
88
- ? { kind: 'workflow_has_no_steps', workflowId: (0, index_js_1.asWorkflowId)(resolution.error.detail) }
89
- : { kind: 'invariant_violation', message: resolution.error.detail };
90
- return (0, neverthrow_1.errAsync)(error);
91
- }
92
- const firstStep = resolution.value;
93
- return (0, neverthrow_1.okAsync)({ workflow, firstStep, workflowHash, pinnedWorkflow });
106
+ });
94
107
  });
95
108
  });
96
109
  }
@@ -215,8 +228,10 @@ function executeStartWorkflow(input, ctx) {
215
228
  crypto,
216
229
  pinnedStore,
217
230
  validationPipelineDeps,
231
+ workspacePath: input.workspacePath,
232
+ resolvedRootUris: ctx.v2.resolvedRootUris,
218
233
  })
219
- .andThen(({ workflow, firstStep, workflowHash, pinnedWorkflow }) => {
234
+ .andThen(({ workflow, firstStep, workflowHash, pinnedWorkflow, resolvedReferences }) => {
220
235
  const anchorsRA = (0, v2_workspace_resolution_js_1.resolveWorkspaceAnchors)(ctx.v2, input.workspacePath)
221
236
  .map((anchors) => (0, observation_builder_js_1.anchorsToObservations)(anchors));
222
237
  return anchorsRA.andThen((observations) => {
@@ -265,11 +280,11 @@ function executeStartWorkflow(input, ctx) {
265
280
  snapshotPins: [{ snapshotRef, eventIndex: 2, createdByEventId: events[2].eventId }],
266
281
  }))
267
282
  .mapErr((cause) => ({ kind: 'session_append_failed', cause }))
268
- .map(() => ({ workflow, firstStep, workflowHash, pinnedWorkflow, sessionId, runId, nodeId }));
283
+ .map(() => ({ workflow, firstStep, workflowHash, pinnedWorkflow, resolvedReferences, sessionId, runId, nodeId }));
269
284
  });
270
285
  });
271
286
  })
272
- .andThen(({ pinnedWorkflow, firstStep, workflowHash, sessionId, runId, nodeId }) => {
287
+ .andThen(({ pinnedWorkflow, firstStep, workflowHash, sessionId, runId, nodeId, resolvedReferences }) => {
273
288
  const wfRefRes = (0, workflow_hash_ref_js_1.deriveWorkflowHashRef)(workflowHash);
274
289
  if (wfRefRes.isErr()) {
275
290
  return (0, neverthrow_1.errAsync)({
@@ -308,7 +323,11 @@ function executeStartWorkflow(input, ctx) {
308
323
  const pending = (0, output_schemas_js_1.toPendingStep)(meta);
309
324
  const preferences = v2_execution_helpers_js_1.defaultPreferences;
310
325
  const nextIntent = (0, v2_state_conversion_js_1.deriveNextIntent)({ rehydrateOnly: false, isComplete: false, pending: meta });
311
- return (0, neverthrow_1.okAsync)(output_schemas_js_1.V2StartWorkflowOutputSchema.parse({
326
+ const contentEnvelope = (0, step_content_envelope_js_1.buildStepContentEnvelope)({
327
+ meta,
328
+ references: resolvedReferences,
329
+ });
330
+ const parsed = output_schemas_js_1.V2StartWorkflowOutputSchema.parse({
312
331
  continueToken: tokens.continueToken,
313
332
  checkpointToken: tokens.checkpointToken,
314
333
  isComplete: false,
@@ -316,7 +335,26 @@ function executeStartWorkflow(input, ctx) {
316
335
  preferences,
317
336
  nextIntent,
318
337
  nextCall: (0, index_js_2.buildNextCall)({ continueToken: tokens.continueToken, isComplete: false, pending }),
319
- }));
338
+ });
339
+ return (0, neverthrow_1.okAsync)({ response: parsed, contentEnvelope });
320
340
  });
321
341
  });
322
342
  }
343
+ function enrichPinnedSnapshotWithResolvedReferences(snapshot, references, workspacePath) {
344
+ if (references.length === 0) {
345
+ return (0, neverthrow_1.okAsync)({ snapshot, resolvedReferences: [] });
346
+ }
347
+ return neverthrow_1.ResultAsync.fromPromise((0, v2_reference_resolver_js_1.resolveWorkflowReferences)(references, workspacePath), () => ({ kind: 'reference_resolution_failed' })).map((result) => {
348
+ for (const warning of result.warnings) {
349
+ console.warn(`[workrail:reference-resolution] ${warning.message}`);
350
+ }
351
+ const pinnedResolvedReferences = [...result.resolved];
352
+ return {
353
+ snapshot: {
354
+ ...snapshot,
355
+ resolvedReferences: pinnedResolvedReferences,
356
+ },
357
+ resolvedReferences: result.resolved,
358
+ };
359
+ });
360
+ }
@@ -49,6 +49,8 @@ export type StartWorkflowError = {
49
49
  } | {
50
50
  readonly kind: 'prompt_render_failed';
51
51
  readonly message: string;
52
+ } | {
53
+ readonly kind: 'reference_resolution_failed';
52
54
  };
53
55
  export type ContinueWorkflowError = {
54
56
  readonly kind: 'precondition_failed';
@@ -52,6 +52,8 @@ function mapStartWorkflowErrorToToolError(e) {
52
52
  return mapTokenSigningErrorToToolError(e.cause);
53
53
  case 'prompt_render_failed':
54
54
  return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', `WorkRail could not render the pending step prompt: ${e.message}`, { suggestion: internalSuggestion('Retry start_workflow.', 'A step referenced by the workflow was not found in the executable definition.') });
55
+ case 'reference_resolution_failed':
56
+ return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', 'WorkRail could not resolve workflow references. This is not caused by your input.', { suggestion: internalSuggestion('Retry start_workflow.', 'Reference resolution encountered an unexpected error.') });
55
57
  default:
56
58
  const _exhaustive = e;
57
59
  return _exhaustive;
@@ -0,0 +1,14 @@
1
+ import type { WorkflowReference } from '../../types/workflow-definition.js';
2
+ import type { ResolvedReference } from '../step-content-envelope.js';
3
+ export interface ReferenceResolutionWarning {
4
+ readonly referenceId: string;
5
+ readonly source: string;
6
+ readonly message: string;
7
+ }
8
+ export interface ReferenceResolutionResult {
9
+ readonly resolved: readonly ResolvedReference[];
10
+ readonly warnings: readonly ReferenceResolutionWarning[];
11
+ }
12
+ export type FileExistsPort = (filePath: string) => Promise<boolean>;
13
+ export declare const defaultFileExists: FileExistsPort;
14
+ export declare function resolveWorkflowReferences(references: readonly WorkflowReference[], workspacePath: string, fileExists?: FileExistsPort): Promise<ReferenceResolutionResult>;
@@ -0,0 +1,112 @@
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
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.defaultFileExists = void 0;
37
+ exports.resolveWorkflowReferences = resolveWorkflowReferences;
38
+ const path = __importStar(require("node:path"));
39
+ const fs = __importStar(require("node:fs/promises"));
40
+ const defaultFileExists = async (filePath) => {
41
+ try {
42
+ const stat = await fs.stat(filePath);
43
+ return stat.isFile();
44
+ }
45
+ catch {
46
+ return false;
47
+ }
48
+ };
49
+ exports.defaultFileExists = defaultFileExists;
50
+ function getPackageRoot() {
51
+ const thisDir = __dirname;
52
+ return path.resolve(thisDir, '..', '..', '..');
53
+ }
54
+ async function resolveWorkflowReferences(references, workspacePath, fileExists = exports.defaultFileExists) {
55
+ const normalizedWorkspaceBase = path.resolve(workspacePath) + path.sep;
56
+ const packageRoot = getPackageRoot();
57
+ const normalizedPackageBase = path.resolve(packageRoot) + path.sep;
58
+ const entries = await Promise.all(references.map(async (ref) => {
59
+ const isPackageRef = ref.resolveFrom === 'package';
60
+ const resolveBase = isPackageRef ? packageRoot : workspacePath;
61
+ const normalizedBase = isPackageRef ? normalizedPackageBase : normalizedWorkspaceBase;
62
+ const resolvedPath = path.resolve(resolveBase, ref.source);
63
+ if (!resolvedPath.startsWith(normalizedBase) && resolvedPath !== path.resolve(resolveBase)) {
64
+ return { ref, resolvedPath, exists: false, escaped: true, ioError: null };
65
+ }
66
+ try {
67
+ const exists = await fileExists(resolvedPath);
68
+ return { ref, resolvedPath, exists, escaped: false, ioError: null };
69
+ }
70
+ catch (error) {
71
+ const message = error instanceof Error ? error.message : String(error);
72
+ return { ref, resolvedPath, exists: false, escaped: false, ioError: message };
73
+ }
74
+ }));
75
+ const resolved = [];
76
+ const warnings = [];
77
+ for (const { ref, resolvedPath, exists, escaped, ioError } of entries) {
78
+ if (escaped) {
79
+ warnings.push({
80
+ referenceId: ref.id,
81
+ source: ref.source,
82
+ message: `Reference '${ref.id}' source path escapes ${ref.resolveFrom === 'package' ? 'package' : 'workspace'} boundary: ${ref.source}`,
83
+ });
84
+ }
85
+ else if (ioError != null) {
86
+ warnings.push({
87
+ referenceId: ref.id,
88
+ source: ref.source,
89
+ message: `Reference '${ref.id}' source path could not be checked: ${ioError}`,
90
+ });
91
+ }
92
+ else if (!exists) {
93
+ warnings.push({
94
+ referenceId: ref.id,
95
+ source: ref.source,
96
+ message: `Reference '${ref.id}' source path does not exist: ${resolvedPath}`,
97
+ });
98
+ }
99
+ const base = {
100
+ id: ref.id,
101
+ title: ref.title,
102
+ source: ref.source,
103
+ purpose: ref.purpose,
104
+ authoritative: ref.authoritative,
105
+ resolveFrom: (ref.resolveFrom ?? 'workspace'),
106
+ };
107
+ resolved.push((!escaped && exists)
108
+ ? { ...base, status: 'resolved', resolvedPath }
109
+ : { ...base, status: 'unresolved' });
110
+ }
111
+ return { resolved, warnings };
112
+ }
@@ -0,0 +1,5 @@
1
+ import { ResultAsync as RA } from 'neverthrow';
2
+ import type { WorkflowReference } from '../../types/workflow-definition.js';
3
+ import type { StepMetadata } from '../../v2/durable-core/domain/prompt-renderer.js';
4
+ import { type StepContentEnvelope } from '../step-content-envelope.js';
5
+ export declare function resolveRefsAndBuildEnvelope<E>(meta: StepMetadata, workflowRefs: readonly WorkflowReference[], workspacePath: string, toError: () => E): RA<StepContentEnvelope, E>;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveRefsAndBuildEnvelope = resolveRefsAndBuildEnvelope;
4
+ const neverthrow_1 = require("neverthrow");
5
+ const v2_reference_resolver_js_1 = require("./v2-reference-resolver.js");
6
+ const step_content_envelope_js_1 = require("../step-content-envelope.js");
7
+ function resolveRefsAndBuildEnvelope(meta, workflowRefs, workspacePath, toError) {
8
+ return neverthrow_1.ResultAsync.fromPromise((0, v2_reference_resolver_js_1.resolveWorkflowReferences)(workflowRefs, workspacePath), toError).andThen((refResult) => {
9
+ for (const warning of refResult.warnings) {
10
+ console.warn(`[workrail:reference-resolution] ${warning.message}`);
11
+ }
12
+ return (0, neverthrow_1.okAsync)((0, step_content_envelope_js_1.buildStepContentEnvelope)({
13
+ meta,
14
+ references: refResult.resolved,
15
+ }));
16
+ });
17
+ }
@@ -127,11 +127,13 @@ async function handleV2InspectWorkflow(input, ctx) {
127
127
  const body = input.mode === 'metadata'
128
128
  ? { schemaVersion: compiled.schemaVersion, sourceKind: compiled.sourceKind, workflowId: compiled.workflowId }
129
129
  : compiled;
130
+ const references = workflow.definition.references;
130
131
  const payload = output_schemas_js_1.V2WorkflowInspectOutputSchema.parse({
131
132
  workflowId: input.workflowId,
132
133
  workflowHash,
133
134
  mode: input.mode,
134
135
  compiled: body,
136
+ ...(references != null && references.length > 0 ? { references } : {}),
135
137
  });
136
138
  return (0, neverthrow_1.okAsync)((0, types_js_1.success)(payload));
137
139
  });
@@ -221,16 +221,54 @@ export declare const V2WorkflowInspectOutputSchema: z.ZodObject<{
221
221
  workflowHash: z.ZodString;
222
222
  mode: z.ZodEnum<["metadata", "preview"]>;
223
223
  compiled: z.ZodType<JsonValue, z.ZodTypeDef, JsonValue>;
224
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
225
+ id: z.ZodString;
226
+ title: z.ZodString;
227
+ source: z.ZodString;
228
+ purpose: z.ZodString;
229
+ authoritative: z.ZodBoolean;
230
+ resolveFrom: z.ZodOptional<z.ZodEnum<["workspace", "package"]>>;
231
+ }, "strip", z.ZodTypeAny, {
232
+ id: string;
233
+ title: string;
234
+ source: string;
235
+ purpose: string;
236
+ authoritative: boolean;
237
+ resolveFrom?: "workspace" | "package" | undefined;
238
+ }, {
239
+ id: string;
240
+ title: string;
241
+ source: string;
242
+ purpose: string;
243
+ authoritative: boolean;
244
+ resolveFrom?: "workspace" | "package" | undefined;
245
+ }>, "many">>;
224
246
  }, "strip", z.ZodTypeAny, {
225
247
  workflowId: string;
226
248
  workflowHash: string;
227
249
  mode: "metadata" | "preview";
228
250
  compiled: JsonValue;
251
+ references?: {
252
+ id: string;
253
+ title: string;
254
+ source: string;
255
+ purpose: string;
256
+ authoritative: boolean;
257
+ resolveFrom?: "workspace" | "package" | undefined;
258
+ }[] | undefined;
229
259
  }, {
230
260
  workflowId: string;
231
261
  workflowHash: string;
232
262
  mode: "metadata" | "preview";
233
263
  compiled: JsonValue;
264
+ references?: {
265
+ id: string;
266
+ title: string;
267
+ source: string;
268
+ purpose: string;
269
+ authoritative: boolean;
270
+ resolveFrom?: "workspace" | "package" | undefined;
271
+ }[] | undefined;
234
272
  }>;
235
273
  export declare const V2PendingStepSchema: z.ZodObject<{
236
274
  stepId: z.ZodString;
@@ -63,6 +63,14 @@ exports.V2WorkflowInspectOutputSchema = zod_1.z.object({
63
63
  workflowHash: zod_1.z.string().min(1),
64
64
  mode: zod_1.z.enum(['metadata', 'preview']),
65
65
  compiled: exports.JsonValueSchema,
66
+ references: zod_1.z.array(zod_1.z.object({
67
+ id: zod_1.z.string().min(1),
68
+ title: zod_1.z.string().min(1),
69
+ source: zod_1.z.string().min(1),
70
+ purpose: zod_1.z.string().min(1),
71
+ authoritative: zod_1.z.boolean(),
72
+ resolveFrom: zod_1.z.enum(['workspace', 'package']).optional(),
73
+ })).optional(),
66
74
  });
67
75
  exports.V2PendingStepSchema = zod_1.z.object({
68
76
  stepId: zod_1.z.string().min(1),
@@ -0,0 +1,21 @@
1
+ import type { StepContentEnvelope } from './step-content-envelope.js';
2
+ export declare const V2_EXECUTION_LIFECYCLES: readonly ["start", "advance", "rehydrate"];
3
+ export type V2ExecutionResponseLifecycle = (typeof V2_EXECUTION_LIFECYCLES)[number];
4
+ export interface V2ExecutionRenderEnvelope<TResponse> {
5
+ readonly kind: 'v2_execution_render_envelope';
6
+ readonly response: TResponse;
7
+ readonly lifecycle: V2ExecutionResponseLifecycle;
8
+ readonly contentEnvelope?: StepContentEnvelope;
9
+ }
10
+ export declare function createV2ExecutionRenderEnvelope<TResponse>(args: {
11
+ readonly response: TResponse;
12
+ readonly lifecycle: V2ExecutionResponseLifecycle;
13
+ readonly contentEnvelope?: StepContentEnvelope;
14
+ }): V2ExecutionRenderEnvelope<TResponse>;
15
+ export declare function attachV2ExecutionRenderMetadata<TResponse extends object>(args: {
16
+ readonly response: TResponse;
17
+ readonly lifecycle: V2ExecutionResponseLifecycle;
18
+ readonly contentEnvelope?: StepContentEnvelope;
19
+ }): TResponse;
20
+ export declare function getV2ExecutionRenderEnvelope(value: unknown): V2ExecutionRenderEnvelope<unknown> | null;
21
+ export declare function isV2ExecutionRenderEnvelope(value: unknown): value is V2ExecutionRenderEnvelope<unknown>;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.V2_EXECUTION_LIFECYCLES = void 0;
4
+ exports.createV2ExecutionRenderEnvelope = createV2ExecutionRenderEnvelope;
5
+ exports.attachV2ExecutionRenderMetadata = attachV2ExecutionRenderMetadata;
6
+ exports.getV2ExecutionRenderEnvelope = getV2ExecutionRenderEnvelope;
7
+ exports.isV2ExecutionRenderEnvelope = isV2ExecutionRenderEnvelope;
8
+ exports.V2_EXECUTION_LIFECYCLES = ['start', 'advance', 'rehydrate'];
9
+ const V2_EXECUTION_RENDER_META = Symbol.for('workrail.v2ExecutionRenderMeta');
10
+ function createV2ExecutionRenderEnvelope(args) {
11
+ return Object.freeze({
12
+ kind: 'v2_execution_render_envelope',
13
+ response: args.response,
14
+ lifecycle: args.lifecycle,
15
+ ...(args.contentEnvelope != null ? { contentEnvelope: args.contentEnvelope } : {}),
16
+ });
17
+ }
18
+ const VALID_LIFECYCLES = new Set(exports.V2_EXECUTION_LIFECYCLES);
19
+ function attachV2ExecutionRenderMetadata(args) {
20
+ Object.defineProperty(args.response, V2_EXECUTION_RENDER_META, {
21
+ value: Object.freeze({
22
+ lifecycle: args.lifecycle,
23
+ ...(args.contentEnvelope != null ? { contentEnvelope: args.contentEnvelope } : {}),
24
+ }),
25
+ enumerable: false,
26
+ configurable: false,
27
+ writable: false,
28
+ });
29
+ return args.response;
30
+ }
31
+ function getV2ExecutionRenderEnvelope(value) {
32
+ if (typeof value !== 'object' || value === null)
33
+ return null;
34
+ const candidate = value;
35
+ if (candidate.kind === 'v2_execution_render_envelope' &&
36
+ 'response' in candidate &&
37
+ typeof candidate.lifecycle === 'string' &&
38
+ VALID_LIFECYCLES.has(candidate.lifecycle)) {
39
+ return candidate;
40
+ }
41
+ const metadata = Reflect.get(candidate, V2_EXECUTION_RENDER_META);
42
+ if (metadata == null || !VALID_LIFECYCLES.has(metadata.lifecycle)) {
43
+ return null;
44
+ }
45
+ return createV2ExecutionRenderEnvelope({
46
+ response: value,
47
+ lifecycle: metadata.lifecycle,
48
+ contentEnvelope: metadata.contentEnvelope,
49
+ });
50
+ }
51
+ function isV2ExecutionRenderEnvelope(value) {
52
+ if (typeof value !== 'object' || value === null)
53
+ return false;
54
+ const candidate = value;
55
+ return (candidate.kind === 'v2_execution_render_envelope' &&
56
+ 'response' in candidate &&
57
+ typeof candidate.lifecycle === 'string' &&
58
+ VALID_LIFECYCLES.has(candidate.lifecycle));
59
+ }
@@ -0,0 +1,17 @@
1
+ import type { V2ExecutionResponseLifecycle } from './render-envelope.js';
2
+ export type SupplementKind = 'authority_context' | 'notes_guidance';
3
+ export interface FormattedSupplement {
4
+ readonly kind: SupplementKind;
5
+ readonly order: number;
6
+ readonly text: string;
7
+ }
8
+ export type SupplementDelivery = {
9
+ readonly mode: 'per_lifecycle';
10
+ } | {
11
+ readonly mode: 'once_per_session';
12
+ readonly emitOn: V2ExecutionResponseLifecycle;
13
+ };
14
+ export declare function buildResponseSupplements(args: {
15
+ readonly lifecycle: V2ExecutionResponseLifecycle;
16
+ readonly cleanFormat: boolean;
17
+ }): readonly FormattedSupplement[];
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildResponseSupplements = buildResponseSupplements;
4
+ const AUTHORITY_CONTEXT = [
5
+ 'WorkRail is a separate live system the user is actively using to direct this task.',
6
+ 'Treat the main content item from WorkRail as the instruction to follow now.',
7
+ ].join('\n');
8
+ const NOTES_GUIDANCE = [
9
+ 'How to write good notes (output.notesMarkdown):',
10
+ '- Write for a human reader reviewing your work later.',
11
+ '- Include: what you did and key decisions, what you produced (files, functions, test results, specific numbers), anything notable (risks, open questions, things you deliberately chose NOT to do and why).',
12
+ '- Use markdown: headings, bullets, bold, code refs. Be specific — file paths, function names, counts.',
13
+ '- Scope: THIS step only. WorkRail concatenates notes across steps automatically.',
14
+ '- 10-30 lines is ideal. Too short is worse than too long.',
15
+ '- Omitting notes will block the step.',
16
+ ].join('\n');
17
+ function defineResponseSupplement(spec) {
18
+ if (spec.delivery.mode === 'once_per_session' &&
19
+ !spec.lifecycles.includes(spec.delivery.emitOn)) {
20
+ throw new Error(`Supplement "${spec.kind}" has once_per_session delivery on "${spec.delivery.emitOn}" but that lifecycle is not enabled.`);
21
+ }
22
+ return spec;
23
+ }
24
+ function shouldEmitSupplement(spec, lifecycle) {
25
+ if (!spec.lifecycles.includes(lifecycle))
26
+ return false;
27
+ if (spec.delivery.mode === 'per_lifecycle')
28
+ return true;
29
+ return spec.delivery.emitOn === lifecycle;
30
+ }
31
+ const CLEAN_RESPONSE_SUPPLEMENTS = [
32
+ defineResponseSupplement({
33
+ kind: 'authority_context',
34
+ order: 10,
35
+ lifecycles: ['start', 'rehydrate'],
36
+ delivery: { mode: 'per_lifecycle' },
37
+ renderText: () => AUTHORITY_CONTEXT,
38
+ }),
39
+ defineResponseSupplement({
40
+ kind: 'notes_guidance',
41
+ order: 20,
42
+ lifecycles: ['start', 'rehydrate'],
43
+ delivery: { mode: 'once_per_session', emitOn: 'start' },
44
+ renderText: () => NOTES_GUIDANCE,
45
+ }),
46
+ ];
47
+ function buildResponseSupplements(args) {
48
+ if (!args.cleanFormat)
49
+ return [];
50
+ return CLEAN_RESPONSE_SUPPLEMENTS
51
+ .filter((spec) => shouldEmitSupplement(spec, args.lifecycle))
52
+ .map((spec) => ({
53
+ kind: spec.kind,
54
+ order: spec.order,
55
+ text: spec.renderText(),
56
+ }))
57
+ .sort((left, right) => left.order - right.order);
58
+ }
@@ -0,0 +1,32 @@
1
+ import type { StepMetadata } from '../v2/durable-core/domain/prompt-renderer.js';
2
+ import type { FormattedSupplement } from './response-supplements.js';
3
+ interface ResolvedReferenceBase {
4
+ readonly id: string;
5
+ readonly title: string;
6
+ readonly source: string;
7
+ readonly purpose: string;
8
+ readonly authoritative: boolean;
9
+ readonly resolveFrom: 'workspace' | 'package';
10
+ }
11
+ export type ResolvedReference = (ResolvedReferenceBase & {
12
+ readonly status: 'resolved';
13
+ readonly resolvedPath: string;
14
+ }) | (ResolvedReferenceBase & {
15
+ readonly status: 'unresolved';
16
+ }) | (ResolvedReferenceBase & {
17
+ readonly status: 'pinned';
18
+ });
19
+ export interface StepContentEnvelope {
20
+ readonly stepId: string;
21
+ readonly title: string;
22
+ readonly authoredPrompt: string;
23
+ readonly agentRole?: string;
24
+ readonly references: readonly ResolvedReference[];
25
+ readonly supplements: readonly FormattedSupplement[];
26
+ }
27
+ export declare function buildStepContentEnvelope(args: {
28
+ readonly meta: StepMetadata;
29
+ readonly references?: readonly ResolvedReference[];
30
+ readonly supplements?: readonly FormattedSupplement[];
31
+ }): StepContentEnvelope;
32
+ export {};
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildStepContentEnvelope = buildStepContentEnvelope;
4
+ function buildStepContentEnvelope(args) {
5
+ return Object.freeze({
6
+ stepId: args.meta.stepId,
7
+ title: args.meta.title,
8
+ authoredPrompt: args.meta.prompt,
9
+ agentRole: args.meta.agentRole,
10
+ references: Object.freeze(args.references ?? []),
11
+ supplements: Object.freeze(args.supplements ?? []),
12
+ });
13
+ }
@@ -1 +1,11 @@
1
- export declare function formatV2ExecutionResponse(data: unknown): string | null;
1
+ import { type FormattedSupplement } from './response-supplements.js';
2
+ export interface FormattedReferences {
3
+ readonly kind: 'references';
4
+ readonly text: string;
5
+ }
6
+ export interface FormattedResponse {
7
+ readonly primary: string;
8
+ readonly references?: FormattedReferences;
9
+ readonly supplements?: readonly FormattedSupplement[];
10
+ }
11
+ export declare function formatV2ExecutionResponse(data: unknown): FormattedResponse | null;