@exaudeus/workrail 3.3.0 → 3.5.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 (78) hide show
  1. package/dist/application/services/compiler/binding-registry.d.ts +3 -0
  2. package/dist/application/services/compiler/binding-registry.js +71 -0
  3. package/dist/application/services/compiler/resolve-bindings.d.ts +18 -0
  4. package/dist/application/services/compiler/resolve-bindings.js +162 -0
  5. package/dist/application/services/compiler/sentinel-scan.d.ts +9 -0
  6. package/dist/application/services/compiler/sentinel-scan.js +37 -0
  7. package/dist/application/services/validation-engine.js +104 -0
  8. package/dist/application/services/workflow-compiler.d.ts +10 -2
  9. package/dist/application/services/workflow-compiler.js +25 -6
  10. package/dist/application/services/workflow-validation-pipeline.js +8 -1
  11. package/dist/cli.js +2 -2
  12. package/dist/engine/engine-factory.js +1 -1
  13. package/dist/index.d.ts +2 -1
  14. package/dist/index.js +4 -2
  15. package/dist/manifest.json +149 -101
  16. package/dist/mcp/handler-factory.d.ts +1 -1
  17. package/dist/mcp/handler-factory.js +2 -2
  18. package/dist/mcp/handlers/v2-checkpoint.js +5 -5
  19. package/dist/mcp/handlers/v2-error-mapping.js +4 -4
  20. package/dist/mcp/handlers/v2-execution/continue-advance.js +2 -2
  21. package/dist/mcp/handlers/v2-execution/continue-rehydrate.d.ts +1 -0
  22. package/dist/mcp/handlers/v2-execution/continue-rehydrate.js +76 -60
  23. package/dist/mcp/handlers/v2-execution/index.js +86 -44
  24. package/dist/mcp/handlers/v2-execution-helpers.js +1 -1
  25. package/dist/mcp/handlers/v2-resume.js +10 -5
  26. package/dist/mcp/handlers/v2-token-ops.d.ts +1 -1
  27. package/dist/mcp/handlers/v2-token-ops.js +5 -5
  28. package/dist/mcp/handlers/v2-workspace-resolution.d.ts +1 -0
  29. package/dist/mcp/handlers/v2-workspace-resolution.js +12 -0
  30. package/dist/mcp/index.d.ts +4 -1
  31. package/dist/mcp/index.js +6 -2
  32. package/dist/mcp/output-schemas.d.ts +148 -8
  33. package/dist/mcp/output-schemas.js +22 -4
  34. package/dist/mcp/server.d.ts +6 -4
  35. package/dist/mcp/server.js +2 -57
  36. package/dist/mcp/tool-descriptions.js +9 -158
  37. package/dist/mcp/transports/http-entry.js +6 -25
  38. package/dist/mcp/transports/shutdown-hooks.d.ts +5 -0
  39. package/dist/mcp/transports/shutdown-hooks.js +38 -0
  40. package/dist/mcp/transports/stdio-entry.js +6 -28
  41. package/dist/mcp/v2/tool-registry.js +2 -1
  42. package/dist/mcp/v2/tools.d.ts +28 -11
  43. package/dist/mcp/v2/tools.js +28 -4
  44. package/dist/mcp/v2-response-formatter.js +28 -1
  45. package/dist/mcp/validation/suggestion-generator.d.ts +1 -1
  46. package/dist/mcp/validation/suggestion-generator.js +13 -3
  47. package/dist/mcp/workflow-protocol-contracts.d.ts +31 -0
  48. package/dist/mcp/workflow-protocol-contracts.js +207 -0
  49. package/dist/mcp-server.d.ts +3 -1
  50. package/dist/mcp-server.js +6 -2
  51. package/dist/types/workflow-definition.d.ts +7 -0
  52. package/dist/types/workflow-definition.js +1 -0
  53. package/dist/v2/durable-core/domain/binding-drift.d.ts +8 -0
  54. package/dist/v2/durable-core/domain/binding-drift.js +29 -0
  55. package/dist/v2/durable-core/domain/reason-model.js +2 -2
  56. package/dist/v2/durable-core/schemas/compiled-workflow/index.d.ts +12 -0
  57. package/dist/v2/durable-core/schemas/compiled-workflow/index.js +2 -0
  58. package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +56 -56
  59. package/dist/v2/durable-core/schemas/session/events.d.ts +16 -16
  60. package/dist/v2/durable-core/schemas/session/gaps.d.ts +6 -6
  61. package/dist/v2/projections/resume-ranking.d.ts +1 -0
  62. package/dist/v2/projections/resume-ranking.js +1 -0
  63. package/dist/v2/read-only/v1-to-v2-shim.js +27 -10
  64. package/dist/v2/usecases/resume-session.d.ts +5 -1
  65. package/dist/v2/usecases/resume-session.js +4 -1
  66. package/package.json +1 -1
  67. package/spec/authoring-spec.json +1373 -0
  68. package/spec/workflow.schema.json +132 -2
  69. package/workflows/coding-task-workflow-agentic.json +15 -15
  70. package/workflows/coding-task-workflow-agentic.lean.v2.json +10 -10
  71. package/workflows/coding-task-workflow-agentic.v2.json +12 -12
  72. package/workflows/coding-task-workflow-with-loops.json +2 -2
  73. package/workflows/cross-platform-code-conversion.v2.json +199 -0
  74. package/workflows/document-creation-workflow.json +1 -1
  75. package/workflows/exploration-workflow.json +3 -3
  76. package/workflows/mr-review-workflow.agentic.v2.json +11 -11
  77. package/workflows/routines/parallel-work-partitioning.json +43 -0
  78. package/workflows/workflow-for-workflows.v2.json +186 -0
@@ -0,0 +1,5 @@
1
+ export interface ShutdownHookOptions {
2
+ readonly onBeforeTerminate: () => Promise<void>;
3
+ }
4
+ export declare function wireShutdownHooks(opts: ShutdownHookOptions): void;
5
+ export declare function wireStdinShutdown(): void;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.wireShutdownHooks = wireShutdownHooks;
4
+ exports.wireStdinShutdown = wireStdinShutdown;
5
+ const container_js_1 = require("../../di/container.js");
6
+ const tokens_js_1 = require("../../di/tokens.js");
7
+ function wireShutdownHooks(opts) {
8
+ const shutdownEvents = container_js_1.container.resolve(tokens_js_1.DI.Runtime.ShutdownEvents);
9
+ const processSignals = container_js_1.container.resolve(tokens_js_1.DI.Runtime.ProcessSignals);
10
+ const terminator = container_js_1.container.resolve(tokens_js_1.DI.Runtime.ProcessTerminator);
11
+ processSignals.on('SIGINT', () => shutdownEvents.emit({ kind: 'shutdown_requested', signal: 'SIGINT' }));
12
+ processSignals.on('SIGTERM', () => shutdownEvents.emit({ kind: 'shutdown_requested', signal: 'SIGTERM' }));
13
+ processSignals.on('SIGHUP', () => shutdownEvents.emit({ kind: 'shutdown_requested', signal: 'SIGHUP' }));
14
+ let shutdownStarted = false;
15
+ shutdownEvents.onShutdown((event) => {
16
+ if (shutdownStarted)
17
+ return;
18
+ shutdownStarted = true;
19
+ void (async () => {
20
+ try {
21
+ console.error(`[Shutdown] Requested by ${event.signal}. Stopping services...`);
22
+ await opts.onBeforeTerminate();
23
+ terminator.terminate({ kind: 'success' });
24
+ }
25
+ catch (err) {
26
+ console.error('[Shutdown] Error while stopping services:', err);
27
+ terminator.terminate({ kind: 'failure' });
28
+ }
29
+ })();
30
+ });
31
+ }
32
+ function wireStdinShutdown() {
33
+ const shutdownEvents = container_js_1.container.resolve(tokens_js_1.DI.Runtime.ShutdownEvents);
34
+ process.stdin.on('end', () => {
35
+ console.error('[MCP] stdin closed, initiating shutdown');
36
+ shutdownEvents.emit({ kind: 'shutdown_requested', signal: 'SIGHUP' });
37
+ });
38
+ }
@@ -35,8 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.startStdioServer = startStdioServer;
37
37
  const server_js_1 = require("../server.js");
38
- const container_js_1 = require("../../di/container.js");
39
- const tokens_js_1 = require("../../di/tokens.js");
38
+ const shutdown_hooks_js_1 = require("./shutdown-hooks.js");
40
39
  async function startStdioServer() {
41
40
  const { server, ctx, rootsManager } = await (0, server_js_1.composeServer)();
42
41
  const { StdioServerTransport } = await Promise.resolve().then(() => __importStar(require('@modelcontextprotocol/sdk/server/stdio.js')));
@@ -62,31 +61,10 @@ async function startStdioServer() {
62
61
  console.error('[Roots] Client does not support roots/list; workspace context will use server CWD fallback');
63
62
  }
64
63
  console.error('[Transport] WorkRail MCP Server running on stdio');
65
- const shutdownEvents = container_js_1.container.resolve(tokens_js_1.DI.Runtime.ShutdownEvents);
66
- const processSignals = container_js_1.container.resolve(tokens_js_1.DI.Runtime.ProcessSignals);
67
- const terminator = container_js_1.container.resolve(tokens_js_1.DI.Runtime.ProcessTerminator);
68
- processSignals.on('SIGINT', () => shutdownEvents.emit({ kind: 'shutdown_requested', signal: 'SIGINT' }));
69
- processSignals.on('SIGTERM', () => shutdownEvents.emit({ kind: 'shutdown_requested', signal: 'SIGTERM' }));
70
- processSignals.on('SIGHUP', () => shutdownEvents.emit({ kind: 'shutdown_requested', signal: 'SIGHUP' }));
71
- process.stdin.on('end', () => {
72
- console.error('[MCP] stdin closed, initiating shutdown');
73
- shutdownEvents.emit({ kind: 'shutdown_requested', signal: 'SIGHUP' });
74
- });
75
- let shutdownStarted = false;
76
- shutdownEvents.onShutdown((event) => {
77
- if (shutdownStarted)
78
- return;
79
- shutdownStarted = true;
80
- void (async () => {
81
- try {
82
- console.error(`[Shutdown] Requested by ${event.signal}. Stopping services...`);
83
- await ctx.httpServer?.stop();
84
- terminator.terminate({ kind: 'success' });
85
- }
86
- catch (err) {
87
- console.error('[Shutdown] Error while stopping services:', err);
88
- terminator.terminate({ kind: 'failure' });
89
- }
90
- })();
64
+ (0, shutdown_hooks_js_1.wireShutdownHooks)({
65
+ onBeforeTerminate: async () => {
66
+ await ctx.httpServer?.stop();
67
+ },
91
68
  });
69
+ (0, shutdown_hooks_js_1.wireStdinShutdown)();
92
70
  }
@@ -7,6 +7,7 @@ const v2_execution_js_1 = require("../handlers/v2-execution.js");
7
7
  const v2_workflow_js_1 = require("../handlers/v2-workflow.js");
8
8
  const v2_checkpoint_js_1 = require("../handlers/v2-checkpoint.js");
9
9
  const v2_resume_js_1 = require("../handlers/v2-resume.js");
10
+ const workflow_protocol_contracts_js_1 = require("../workflow-protocol-contracts.js");
10
11
  function buildV2ToolRegistry(buildTool) {
11
12
  const tools = [
12
13
  buildTool({
@@ -50,7 +51,7 @@ function buildV2ToolRegistry(buildTool) {
50
51
  list_workflows: (0, handler_factory_js_1.createHandler)(tools_js_1.V2ListWorkflowsInput, v2_workflow_js_1.handleV2ListWorkflows),
51
52
  inspect_workflow: (0, handler_factory_js_1.createHandler)(tools_js_1.V2InspectWorkflowInput, v2_workflow_js_1.handleV2InspectWorkflow),
52
53
  start_workflow: (0, handler_factory_js_1.createHandler)(tools_js_1.V2StartWorkflowInput, v2_execution_js_1.handleV2StartWorkflow),
53
- continue_workflow: (0, handler_factory_js_1.createHandler)(tools_js_1.V2ContinueWorkflowInput, v2_execution_js_1.handleV2ContinueWorkflow, tools_js_1.V2ContinueWorkflowInputShape),
54
+ continue_workflow: (0, handler_factory_js_1.createHandler)(tools_js_1.V2ContinueWorkflowInput, v2_execution_js_1.handleV2ContinueWorkflow, tools_js_1.V2ContinueWorkflowInputShape, workflow_protocol_contracts_js_1.CONTINUE_WORKFLOW_PROTOCOL.aliasMap),
54
55
  checkpoint_workflow: (0, handler_factory_js_1.createHandler)(tools_js_1.V2CheckpointWorkflowInput, v2_checkpoint_js_1.handleV2CheckpointWorkflow),
55
56
  resume_session: (0, handler_factory_js_1.createHandler)(tools_js_1.V2ResumeSessionInput, v2_resume_js_1.handleV2ResumeSession),
56
57
  };
@@ -18,8 +18,8 @@ export declare const V2InspectWorkflowInput: z.ZodObject<{
18
18
  workspacePath?: string | undefined;
19
19
  }, {
20
20
  workflowId: string;
21
- mode?: "metadata" | "preview" | undefined;
22
21
  workspacePath?: string | undefined;
22
+ mode?: "metadata" | "preview" | undefined;
23
23
  }>;
24
24
  export type V2InspectWorkflowInput = z.infer<typeof V2InspectWorkflowInput>;
25
25
  export declare const V2StartWorkflowInput: z.ZodObject<{
@@ -34,6 +34,7 @@ export declare const V2StartWorkflowInput: z.ZodObject<{
34
34
  }>;
35
35
  export type V2StartWorkflowInput = z.infer<typeof V2StartWorkflowInput>;
36
36
  export declare const V2ContinueWorkflowInputShape: z.ZodObject<{
37
+ workspacePath: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
37
38
  continueToken: z.ZodString;
38
39
  intent: z.ZodOptional<z.ZodEnum<["advance", "rehydrate"]>>;
39
40
  context: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
@@ -50,21 +51,24 @@ export declare const V2ContinueWorkflowInputShape: z.ZodObject<{
50
51
  }, "strict", z.ZodTypeAny, {
51
52
  continueToken: string;
52
53
  context?: Record<string, unknown> | undefined;
54
+ workspacePath?: string | undefined;
55
+ intent?: "advance" | "rehydrate" | undefined;
53
56
  output?: {
54
57
  notesMarkdown?: string | undefined;
55
58
  artifacts?: unknown[] | undefined;
56
59
  } | undefined;
57
- intent?: "advance" | "rehydrate" | undefined;
58
60
  }, {
59
61
  continueToken: string;
60
62
  context?: Record<string, unknown> | undefined;
63
+ workspacePath?: string | undefined;
64
+ intent?: "advance" | "rehydrate" | undefined;
61
65
  output?: {
62
66
  notesMarkdown?: string | undefined;
63
67
  artifacts?: unknown[] | undefined;
64
68
  } | undefined;
65
- intent?: "advance" | "rehydrate" | undefined;
66
69
  }>;
67
70
  export declare const V2ContinueWorkflowInput: z.ZodEffects<z.ZodEffects<z.ZodObject<{
71
+ workspacePath: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
68
72
  continueToken: z.ZodString;
69
73
  intent: z.ZodOptional<z.ZodEnum<["advance", "rehydrate"]>>;
70
74
  context: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
@@ -78,54 +82,67 @@ export declare const V2ContinueWorkflowInput: z.ZodEffects<z.ZodEffects<z.ZodObj
78
82
  notesMarkdown?: string | undefined;
79
83
  artifacts?: unknown[] | undefined;
80
84
  }>>;
85
+ } & {
86
+ contextVariables: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
81
87
  }, "strict", z.ZodTypeAny, {
82
88
  continueToken: string;
83
89
  context?: Record<string, unknown> | undefined;
90
+ workspacePath?: string | undefined;
91
+ intent?: "advance" | "rehydrate" | undefined;
84
92
  output?: {
85
93
  notesMarkdown?: string | undefined;
86
94
  artifacts?: unknown[] | undefined;
87
95
  } | undefined;
88
- intent?: "advance" | "rehydrate" | undefined;
96
+ contextVariables?: Record<string, unknown> | undefined;
89
97
  }, {
90
98
  continueToken: string;
91
99
  context?: Record<string, unknown> | undefined;
100
+ workspacePath?: string | undefined;
101
+ intent?: "advance" | "rehydrate" | undefined;
92
102
  output?: {
93
103
  notesMarkdown?: string | undefined;
94
104
  artifacts?: unknown[] | undefined;
95
105
  } | undefined;
96
- intent?: "advance" | "rehydrate" | undefined;
106
+ contextVariables?: Record<string, unknown> | undefined;
97
107
  }>, {
98
108
  continueToken: string;
99
109
  context?: Record<string, unknown> | undefined;
110
+ workspacePath?: string | undefined;
111
+ intent?: "advance" | "rehydrate" | undefined;
100
112
  output?: {
101
113
  notesMarkdown?: string | undefined;
102
114
  artifacts?: unknown[] | undefined;
103
115
  } | undefined;
104
- intent?: "advance" | "rehydrate" | undefined;
116
+ contextVariables?: Record<string, unknown> | undefined;
105
117
  }, {
106
118
  continueToken: string;
107
119
  context?: Record<string, unknown> | undefined;
120
+ workspacePath?: string | undefined;
121
+ intent?: "advance" | "rehydrate" | undefined;
108
122
  output?: {
109
123
  notesMarkdown?: string | undefined;
110
124
  artifacts?: unknown[] | undefined;
111
125
  } | undefined;
112
- intent?: "advance" | "rehydrate" | undefined;
126
+ contextVariables?: Record<string, unknown> | undefined;
113
127
  }>, {
128
+ workspacePath?: string | undefined;
114
129
  output?: {
115
130
  notesMarkdown?: string | undefined;
116
131
  artifacts?: unknown[] | undefined;
117
132
  } | undefined;
118
- context?: Record<string, unknown> | undefined;
133
+ context?: {} | undefined;
119
134
  intent: "advance" | "rehydrate";
120
135
  continueToken: string;
121
136
  }, {
122
137
  continueToken: string;
123
138
  context?: Record<string, unknown> | undefined;
139
+ workspacePath?: string | undefined;
140
+ intent?: "advance" | "rehydrate" | undefined;
124
141
  output?: {
125
142
  notesMarkdown?: string | undefined;
126
143
  artifacts?: unknown[] | undefined;
127
144
  } | undefined;
128
- intent?: "advance" | "rehydrate" | undefined;
145
+ contextVariables?: Record<string, unknown> | undefined;
129
146
  }>;
130
147
  export type V2ContinueWorkflowInput = z.infer<typeof V2ContinueWorkflowInput>;
131
148
  export declare const V2ResumeSessionInput: z.ZodObject<{
@@ -134,13 +151,13 @@ export declare const V2ResumeSessionInput: z.ZodObject<{
134
151
  gitHeadSha: z.ZodOptional<z.ZodString>;
135
152
  workspacePath: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
136
153
  }, "strict", z.ZodTypeAny, {
137
- query?: string | undefined;
138
154
  workspacePath?: string | undefined;
155
+ query?: string | undefined;
139
156
  gitBranch?: string | undefined;
140
157
  gitHeadSha?: string | undefined;
141
158
  }, {
142
- query?: string | undefined;
143
159
  workspacePath?: string | undefined;
160
+ query?: string | undefined;
144
161
  gitBranch?: string | undefined;
145
162
  gitHeadSha?: string | undefined;
146
163
  }>;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.V2_TOOL_ANNOTATIONS = exports.V2_TOOL_TITLES = exports.V2CheckpointWorkflowInput = exports.V2ResumeSessionInput = exports.V2ContinueWorkflowInput = exports.V2ContinueWorkflowInputShape = exports.V2StartWorkflowInput = exports.V2InspectWorkflowInput = exports.V2ListWorkflowsInput = void 0;
4
4
  const zod_1 = require("zod");
5
+ const workflow_protocol_contracts_js_1 = require("../workflow-protocol-contracts.js");
5
6
  const workspacePathField = zod_1.z.string()
6
7
  .refine((p) => p.startsWith('/'), 'workspacePath must be an absolute path (starting with /)')
7
8
  .optional()
@@ -19,8 +20,11 @@ exports.V2StartWorkflowInput = zod_1.z.object({
19
20
  workspacePath: workspacePathField.describe('Absolute path to your current workspace directory (e.g. the "Workspace:" value from your system parameters). Used to resolve the correct project-scoped workflow variant and to anchor this session to your workspace for future resume_session discovery. Pass this on every start_workflow call. If omitted, WorkRail uses MCP roots when available, then falls back to the server process directory.'),
20
21
  });
21
22
  exports.V2ContinueWorkflowInputShape = zod_1.z.object({
22
- continueToken: zod_1.z.string().min(1).describe('The single token for your next continue_workflow call. Carries session identity AND advance authority. ' +
23
- 'Round-trip exactly as received from start_workflow or previous continue_workflow never decode, inspect, or modify it.'),
23
+ workspacePath: workspacePathField,
24
+ continueToken: zod_1.z.string().min(1).describe('The token for your next continue_workflow call. Two valid token kinds: ' +
25
+ '(1) A continueToken (ct_...) from start_workflow or a previous continue_workflow — carries session identity AND advance authority. ' +
26
+ '(2) A resumeToken (st_...) from resume_session or checkpoint_workflow — carries session identity only; valid for intent: "rehydrate", not "advance". ' +
27
+ 'Round-trip exactly as received — never decode, inspect, or modify it.'),
24
28
  intent: zod_1.z.enum(['advance', 'rehydrate']).optional().describe('What you want to do. Auto-inferred if omitted: ' +
25
29
  'output present → "advance", output absent → "rehydrate". ' +
26
30
  '"advance": I completed the current step. ' +
@@ -40,8 +44,23 @@ exports.V2ContinueWorkflowInputShape = zod_1.z.object({
40
44
  .optional()
41
45
  .describe('Durable output to attach to the current node. Only valid when intent is "advance".'),
42
46
  }).strict();
47
+ const continueWorkflowContextAliasField = zod_1.z.record(zod_1.z.unknown()).optional().describe('Compatibility alias for context. Canonical field name: "context".');
43
48
  exports.V2ContinueWorkflowInput = exports.V2ContinueWorkflowInputShape
49
+ .extend({
50
+ contextVariables: continueWorkflowContextAliasField,
51
+ })
44
52
  .superRefine((data, ctx) => {
53
+ const aliasMap = workflow_protocol_contracts_js_1.CONTINUE_WORKFLOW_PROTOCOL.aliasMap;
54
+ const conflicts = aliasMap
55
+ ? (0, workflow_protocol_contracts_js_1.findAliasFieldConflicts)(data, aliasMap)
56
+ : [];
57
+ for (const { alias, canonical } of conflicts) {
58
+ ctx.addIssue({
59
+ code: zod_1.z.ZodIssueCode.custom,
60
+ path: [alias],
61
+ message: `Provide either "${canonical}" or "${alias}", not both. Canonical field: "${canonical}".`,
62
+ });
63
+ }
45
64
  if (data.intent === 'rehydrate' && data.output) {
46
65
  ctx.addIssue({
47
66
  code: zod_1.z.ZodIssueCode.custom,
@@ -52,16 +71,21 @@ exports.V2ContinueWorkflowInput = exports.V2ContinueWorkflowInputShape
52
71
  }
53
72
  })
54
73
  .transform((data) => {
74
+ const normalized = workflow_protocol_contracts_js_1.CONTINUE_WORKFLOW_PROTOCOL.aliasMap
75
+ ? (0, workflow_protocol_contracts_js_1.normalizeAliasedFields)(data, workflow_protocol_contracts_js_1.CONTINUE_WORKFLOW_PROTOCOL.aliasMap)
76
+ : data;
55
77
  const intent = data.intent ?? (data.output ? 'advance' : 'rehydrate');
56
78
  return {
57
79
  intent,
58
80
  continueToken: data.continueToken,
59
- ...(data.context ? { context: data.context } : {}),
81
+ ...(normalized.context ? { context: normalized.context } : {}),
60
82
  ...(data.output ? { output: data.output } : {}),
83
+ ...(data.workspacePath !== undefined ? { workspacePath: data.workspacePath } : {}),
61
84
  };
62
85
  });
63
86
  exports.V2ResumeSessionInput = zod_1.z.object({
64
- query: zod_1.z.string().max(256).optional().describe('Free text search to find a relevant session. Matches against recap notes and workflow IDs.'),
87
+ query: zod_1.z.string().min(1).max(256).optional().describe('Free text search to find a relevant session. Matches against recap notes and workflow IDs. ' +
88
+ 'Without query, only git-context matching runs — the semantic (notes) tier is skipped.'),
65
89
  gitBranch: zod_1.z.string().max(256).optional().describe('Git branch name to match against session observations. Overrides auto-detected branch.'),
66
90
  gitHeadSha: zod_1.z.string().regex(/^[0-9a-f]{40}$/).optional().describe('Git HEAD SHA to match against session observations. Overrides auto-detected HEAD.'),
67
91
  workspacePath: zod_1.z.string()
@@ -59,13 +59,30 @@ function formatTokenBlock(data) {
59
59
  lines.push('```');
60
60
  return lines.join('\n');
61
61
  }
62
- function formatComplete(_data) {
62
+ function formatBindingDriftWarnings(data) {
63
+ if (!data.warnings || data.warnings.length === 0)
64
+ return '';
65
+ const lines = [
66
+ '',
67
+ '> **⚠ Binding Drift Detected**',
68
+ '> Your `.workrail/bindings.json` has changed since this session was started.',
69
+ '> The session continues with the original compiled bindings. Start a new session to pick up the changes.',
70
+ '>',
71
+ ];
72
+ for (const w of data.warnings) {
73
+ lines.push(`> - \`${w.slotId}\`: was \`${w.pinnedValue}\`, now \`${w.currentValue}\``);
74
+ }
75
+ return lines.join('\n');
76
+ }
77
+ function formatComplete(data) {
78
+ const driftBlock = formatBindingDriftWarnings(data);
63
79
  return [
64
80
  PERSONA_SYSTEM,
65
81
  '',
66
82
  '# Workflow Complete',
67
83
  '',
68
84
  'The workflow has finished. No further steps to execute.',
85
+ ...(driftBlock ? [driftBlock] : []),
69
86
  ].join('\n');
70
87
  }
71
88
  function formatBlocked(data) {
@@ -155,6 +172,11 @@ function formatRehydrate(data) {
155
172
  lines.push('No pending step. The workflow may be complete or waiting for external input.');
156
173
  lines.push('');
157
174
  }
175
+ const driftBlock = formatBindingDriftWarnings(data);
176
+ if (driftBlock) {
177
+ lines.push(driftBlock);
178
+ lines.push('');
179
+ }
158
180
  lines.push('Continue working on this step. When done, call `continue_workflow` to advance.');
159
181
  return lines.join('\n');
160
182
  }
@@ -178,6 +200,11 @@ function formatSuccess(data) {
178
200
  lines.push('Include `output.notesMarkdown` documenting your work — what you did, key decisions, what you produced, and anything notable.');
179
201
  lines.push('');
180
202
  lines.push(formatPreferences(data.preferences));
203
+ const driftBlock = formatBindingDriftWarnings(data);
204
+ if (driftBlock) {
205
+ lines.push('');
206
+ lines.push(driftBlock);
207
+ }
181
208
  return lines.join('\n');
182
209
  }
183
210
  function formatV2ExecutionResponse(data) {
@@ -2,7 +2,7 @@ import { z } from 'zod';
2
2
  import type { SuggestionConfig } from './suggestion-config.js';
3
3
  import type { SuggestionResult } from './suggestion-types.js';
4
4
  export type { ZodIssue } from 'zod';
5
- export declare function generateSuggestions(args: unknown, schema: z.ZodType, config: SuggestionConfig): SuggestionResult;
5
+ export declare function generateSuggestions(args: unknown, schema: z.ZodType, config: SuggestionConfig, aliasMap?: Readonly<Record<string, string>>): SuggestionResult;
6
6
  export declare function formatSuggestionDetails(result: SuggestionResult): Record<string, unknown>;
7
7
  export declare function hasSuggestions(result: SuggestionResult): boolean;
8
8
  export declare function patchTemplateForFailedOptionals(correctTemplate: Readonly<Record<string, unknown>> | null, args: unknown, zodErrors: readonly z.ZodIssue[], schema: z.ZodType, maxDepth: number): Readonly<Record<string, unknown>> | null;
@@ -8,9 +8,19 @@ const zod_1 = require("zod");
8
8
  const suggestion_types_js_1 = require("./suggestion-types.js");
9
9
  const string_similarity_js_1 = require("./string-similarity.js");
10
10
  const schema_introspection_js_1 = require("./schema-introspection.js");
11
- function generateUnknownKeySuggestions(unknownKeys, expectedKeys, config) {
11
+ function generateUnknownKeySuggestions(unknownKeys, expectedKeys, config, aliasMap) {
12
12
  const suggestions = [];
13
13
  for (const unknownKey of unknownKeys) {
14
+ const aliasTarget = aliasMap?.[unknownKey];
15
+ if (aliasTarget) {
16
+ suggestions.push({
17
+ kind: 'unknown_key',
18
+ provided: unknownKey,
19
+ didYouMean: aliasTarget,
20
+ similarity: (0, suggestion_types_js_1.similarity)(1),
21
+ });
22
+ continue;
23
+ }
14
24
  const match = (0, string_similarity_js_1.findClosestMatch)(unknownKey, expectedKeys, config.similarityThreshold);
15
25
  if (match) {
16
26
  suggestions.push({
@@ -43,11 +53,11 @@ function generateMissingRequiredSuggestions(missingKeys, schema, config) {
43
53
  suggestions.sort((a, b) => a.param.localeCompare(b.param));
44
54
  return suggestions.slice(0, config.maxSuggestions);
45
55
  }
46
- function generateSuggestions(args, schema, config) {
56
+ function generateSuggestions(args, schema, config, aliasMap) {
47
57
  const suggestions = [];
48
58
  const expectedKeys = (0, schema_introspection_js_1.extractExpectedKeys)(schema);
49
59
  const unknownKeys = (0, schema_introspection_js_1.findUnknownKeys)(args, schema);
50
- const unknownKeySuggestions = generateUnknownKeySuggestions(unknownKeys, expectedKeys, config);
60
+ const unknownKeySuggestions = generateUnknownKeySuggestions(unknownKeys, expectedKeys, config, aliasMap);
51
61
  suggestions.push(...unknownKeySuggestions);
52
62
  const missingKeys = (0, schema_introspection_js_1.findMissingRequiredKeys)(args, schema);
53
63
  const missingRequiredSuggestions = generateMissingRequiredSuggestions(missingKeys, schema, config);
@@ -0,0 +1,31 @@
1
+ import type { DescriptionMode } from './types/tool-description-types.js';
2
+ export type ProtocolAliasMap = Readonly<Record<string, string>>;
3
+ export interface ProtocolParams {
4
+ readonly required: readonly string[];
5
+ readonly optional?: readonly string[];
6
+ }
7
+ export interface CompactDescriptionSpec {
8
+ readonly purpose: string;
9
+ readonly whenToUse?: string;
10
+ readonly rules?: readonly string[];
11
+ readonly examplePayload?: Readonly<Record<string, unknown>>;
12
+ readonly returns?: string;
13
+ }
14
+ export interface WorkflowProtocolContract {
15
+ readonly canonicalParams: ProtocolParams;
16
+ readonly aliasMap?: ProtocolAliasMap;
17
+ readonly descriptions: Readonly<Record<DescriptionMode, CompactDescriptionSpec>>;
18
+ }
19
+ export declare const CONTINUE_WORKFLOW_CONTEXT_OBJECT_GUIDANCE = "Set these keys in the next `continue_workflow` call's `context` object:";
20
+ export declare const CONTINUE_WORKFLOW_SINGLE_CONTEXT_OBJECT_GUIDANCE = "Set this key in the next `continue_workflow` call's `context` object:";
21
+ export declare function renderCompactDescription(spec: CompactDescriptionSpec, canonicalParams: ProtocolParams): string;
22
+ export declare function normalizeAliasedFields(value: Readonly<Record<string, unknown>>, aliasMap: ProtocolAliasMap): Record<string, unknown>;
23
+ export declare function findAliasFieldConflicts(value: Readonly<Record<string, unknown>>, aliasMap: ProtocolAliasMap): readonly {
24
+ alias: string;
25
+ canonical: string;
26
+ }[];
27
+ export declare const START_WORKFLOW_PROTOCOL: WorkflowProtocolContract;
28
+ export declare const CONTINUE_WORKFLOW_PROTOCOL: WorkflowProtocolContract;
29
+ export declare const CHECKPOINT_WORKFLOW_PROTOCOL: WorkflowProtocolContract;
30
+ export declare const RESUME_SESSION_PROTOCOL: WorkflowProtocolContract;
31
+ export declare function renderProtocolDescription(contract: WorkflowProtocolContract, mode: DescriptionMode): string;