@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.
- package/dist/application/services/compiler/binding-registry.d.ts +3 -0
- package/dist/application/services/compiler/binding-registry.js +71 -0
- package/dist/application/services/compiler/resolve-bindings.d.ts +18 -0
- package/dist/application/services/compiler/resolve-bindings.js +162 -0
- package/dist/application/services/compiler/sentinel-scan.d.ts +9 -0
- package/dist/application/services/compiler/sentinel-scan.js +37 -0
- package/dist/application/services/validation-engine.js +104 -0
- package/dist/application/services/workflow-compiler.d.ts +10 -2
- package/dist/application/services/workflow-compiler.js +25 -6
- package/dist/application/services/workflow-validation-pipeline.js +8 -1
- package/dist/cli.js +2 -2
- package/dist/engine/engine-factory.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -2
- package/dist/manifest.json +149 -101
- package/dist/mcp/handler-factory.d.ts +1 -1
- package/dist/mcp/handler-factory.js +2 -2
- package/dist/mcp/handlers/v2-checkpoint.js +5 -5
- package/dist/mcp/handlers/v2-error-mapping.js +4 -4
- package/dist/mcp/handlers/v2-execution/continue-advance.js +2 -2
- package/dist/mcp/handlers/v2-execution/continue-rehydrate.d.ts +1 -0
- package/dist/mcp/handlers/v2-execution/continue-rehydrate.js +76 -60
- package/dist/mcp/handlers/v2-execution/index.js +86 -44
- package/dist/mcp/handlers/v2-execution-helpers.js +1 -1
- package/dist/mcp/handlers/v2-resume.js +10 -5
- package/dist/mcp/handlers/v2-token-ops.d.ts +1 -1
- package/dist/mcp/handlers/v2-token-ops.js +5 -5
- package/dist/mcp/handlers/v2-workspace-resolution.d.ts +1 -0
- package/dist/mcp/handlers/v2-workspace-resolution.js +12 -0
- package/dist/mcp/index.d.ts +4 -1
- package/dist/mcp/index.js +6 -2
- package/dist/mcp/output-schemas.d.ts +148 -8
- package/dist/mcp/output-schemas.js +22 -4
- package/dist/mcp/server.d.ts +6 -4
- package/dist/mcp/server.js +2 -57
- package/dist/mcp/tool-descriptions.js +9 -158
- package/dist/mcp/transports/http-entry.js +6 -25
- package/dist/mcp/transports/shutdown-hooks.d.ts +5 -0
- package/dist/mcp/transports/shutdown-hooks.js +38 -0
- package/dist/mcp/transports/stdio-entry.js +6 -28
- package/dist/mcp/v2/tool-registry.js +2 -1
- package/dist/mcp/v2/tools.d.ts +28 -11
- package/dist/mcp/v2/tools.js +28 -4
- package/dist/mcp/v2-response-formatter.js +28 -1
- package/dist/mcp/validation/suggestion-generator.d.ts +1 -1
- package/dist/mcp/validation/suggestion-generator.js +13 -3
- package/dist/mcp/workflow-protocol-contracts.d.ts +31 -0
- package/dist/mcp/workflow-protocol-contracts.js +207 -0
- package/dist/mcp-server.d.ts +3 -1
- package/dist/mcp-server.js +6 -2
- package/dist/types/workflow-definition.d.ts +7 -0
- package/dist/types/workflow-definition.js +1 -0
- package/dist/v2/durable-core/domain/binding-drift.d.ts +8 -0
- package/dist/v2/durable-core/domain/binding-drift.js +29 -0
- package/dist/v2/durable-core/domain/reason-model.js +2 -2
- package/dist/v2/durable-core/schemas/compiled-workflow/index.d.ts +12 -0
- package/dist/v2/durable-core/schemas/compiled-workflow/index.js +2 -0
- package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +56 -56
- package/dist/v2/durable-core/schemas/session/events.d.ts +16 -16
- package/dist/v2/durable-core/schemas/session/gaps.d.ts +6 -6
- package/dist/v2/projections/resume-ranking.d.ts +1 -0
- package/dist/v2/projections/resume-ranking.js +1 -0
- package/dist/v2/read-only/v1-to-v2-shim.js +27 -10
- package/dist/v2/usecases/resume-session.d.ts +5 -1
- package/dist/v2/usecases/resume-session.js +4 -1
- package/package.json +1 -1
- package/spec/authoring-spec.json +1373 -0
- package/spec/workflow.schema.json +132 -2
- package/workflows/coding-task-workflow-agentic.json +15 -15
- package/workflows/coding-task-workflow-agentic.lean.v2.json +10 -10
- package/workflows/coding-task-workflow-agentic.v2.json +12 -12
- package/workflows/coding-task-workflow-with-loops.json +2 -2
- package/workflows/cross-platform-code-conversion.v2.json +199 -0
- package/workflows/document-creation-workflow.json +1 -1
- package/workflows/exploration-workflow.json +3 -3
- package/workflows/mr-review-workflow.agentic.v2.json +11 -11
- package/workflows/routines/parallel-work-partitioning.json +43 -0
- package/workflows/workflow-for-workflows.v2.json +186 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RESUME_SESSION_PROTOCOL = exports.CHECKPOINT_WORKFLOW_PROTOCOL = exports.CONTINUE_WORKFLOW_PROTOCOL = exports.START_WORKFLOW_PROTOCOL = exports.CONTINUE_WORKFLOW_SINGLE_CONTEXT_OBJECT_GUIDANCE = exports.CONTINUE_WORKFLOW_CONTEXT_OBJECT_GUIDANCE = void 0;
|
|
4
|
+
exports.renderCompactDescription = renderCompactDescription;
|
|
5
|
+
exports.normalizeAliasedFields = normalizeAliasedFields;
|
|
6
|
+
exports.findAliasFieldConflicts = findAliasFieldConflicts;
|
|
7
|
+
exports.renderProtocolDescription = renderProtocolDescription;
|
|
8
|
+
exports.CONTINUE_WORKFLOW_CONTEXT_OBJECT_GUIDANCE = "Set these keys in the next `continue_workflow` call's `context` object:";
|
|
9
|
+
exports.CONTINUE_WORKFLOW_SINGLE_CONTEXT_OBJECT_GUIDANCE = "Set this key in the next `continue_workflow` call's `context` object:";
|
|
10
|
+
function renderCompactDescription(spec, canonicalParams) {
|
|
11
|
+
const sections = [spec.purpose];
|
|
12
|
+
if (spec.whenToUse) {
|
|
13
|
+
sections.push(spec.whenToUse);
|
|
14
|
+
}
|
|
15
|
+
const paramLines = [
|
|
16
|
+
...canonicalParams.required.map((param) => `- ${param} (required)`),
|
|
17
|
+
...(canonicalParams.optional ?? []).map((param) => `- ${param} (optional)`),
|
|
18
|
+
];
|
|
19
|
+
if (paramLines.length > 0) {
|
|
20
|
+
sections.push(['Parameters:', ...paramLines].join('\n'));
|
|
21
|
+
}
|
|
22
|
+
if ((spec.rules?.length ?? 0) > 0) {
|
|
23
|
+
sections.push(['Rules:', ...(spec.rules ?? []).map((rule) => `- ${rule}`)].join('\n'));
|
|
24
|
+
}
|
|
25
|
+
if (spec.examplePayload) {
|
|
26
|
+
sections.push(`Example: ${JSON.stringify(spec.examplePayload)}`);
|
|
27
|
+
}
|
|
28
|
+
if (spec.returns) {
|
|
29
|
+
sections.push(`Returns: ${spec.returns}`);
|
|
30
|
+
}
|
|
31
|
+
return sections.join('\n\n');
|
|
32
|
+
}
|
|
33
|
+
function normalizeAliasedFields(value, aliasMap) {
|
|
34
|
+
const normalized = { ...value };
|
|
35
|
+
for (const [alias, canonical] of Object.entries(aliasMap)) {
|
|
36
|
+
if (normalized[canonical] === undefined && normalized[alias] !== undefined) {
|
|
37
|
+
normalized[canonical] = normalized[alias];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return normalized;
|
|
41
|
+
}
|
|
42
|
+
function findAliasFieldConflicts(value, aliasMap) {
|
|
43
|
+
return Object.entries(aliasMap)
|
|
44
|
+
.filter(([alias, canonical]) => value[alias] !== undefined && value[canonical] !== undefined)
|
|
45
|
+
.map(([alias, canonical]) => ({ alias, canonical }));
|
|
46
|
+
}
|
|
47
|
+
exports.START_WORKFLOW_PROTOCOL = {
|
|
48
|
+
canonicalParams: {
|
|
49
|
+
required: ['workflowId'],
|
|
50
|
+
optional: ['workspacePath'],
|
|
51
|
+
},
|
|
52
|
+
descriptions: {
|
|
53
|
+
standard: {
|
|
54
|
+
purpose: 'Start a WorkRail v2 workflow and begin following its step-by-step instructions.',
|
|
55
|
+
whenToUse: 'Use this when you found the right workflow and are ready to execute it. The response body is the current step; the structured response includes the token(s) for your next call.',
|
|
56
|
+
rules: [
|
|
57
|
+
'Follow the returned step exactly; it represents the user\'s plan for the task.',
|
|
58
|
+
'When the step is done, call continue_workflow with the returned continueToken.',
|
|
59
|
+
'Only pass context on later continue_workflow calls if facts changed.',
|
|
60
|
+
],
|
|
61
|
+
examplePayload: {
|
|
62
|
+
workflowId: 'coding-task-workflow-agentic',
|
|
63
|
+
workspacePath: '/Users/you/git/my-project',
|
|
64
|
+
},
|
|
65
|
+
returns: 'Step instructions plus continueToken and checkpointToken in the structured response.',
|
|
66
|
+
},
|
|
67
|
+
authoritative: {
|
|
68
|
+
purpose: 'Begin executing the selected WorkRail v2 workflow.',
|
|
69
|
+
whenToUse: 'Call this once you have chosen the workflow you will follow. The returned step is a direct instruction from the user or workflow author.',
|
|
70
|
+
rules: [
|
|
71
|
+
'Execute the returned step exactly as written.',
|
|
72
|
+
'When the step is complete, call continue_workflow with the returned continueToken.',
|
|
73
|
+
'Pass workspacePath when available so WorkRail anchors the session to the correct workspace.',
|
|
74
|
+
],
|
|
75
|
+
examplePayload: {
|
|
76
|
+
workflowId: 'coding-task-workflow-agentic',
|
|
77
|
+
workspacePath: '/Users/you/git/my-project',
|
|
78
|
+
},
|
|
79
|
+
returns: 'Step instructions plus continueToken and checkpointToken in the structured response.',
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
exports.CONTINUE_WORKFLOW_PROTOCOL = {
|
|
84
|
+
canonicalParams: {
|
|
85
|
+
required: ['continueToken'],
|
|
86
|
+
optional: ['intent', 'context', 'output'],
|
|
87
|
+
},
|
|
88
|
+
aliasMap: {
|
|
89
|
+
contextVariables: 'context',
|
|
90
|
+
},
|
|
91
|
+
descriptions: {
|
|
92
|
+
standard: {
|
|
93
|
+
purpose: 'Advance or rehydrate the current WorkRail v2 step using the single-token protocol.',
|
|
94
|
+
whenToUse: 'Use this after completing a step, or to recover the current step after lost context.',
|
|
95
|
+
rules: [
|
|
96
|
+
'Advance by sending output (and intent: "advance" if you want to be explicit).',
|
|
97
|
+
'Rehydrate by omitting output (and intent: "rehydrate" if you want to be explicit).',
|
|
98
|
+
'Put changed facts under context only.',
|
|
99
|
+
'Round-trip continueToken exactly as returned by WorkRail; use the single-token API only.',
|
|
100
|
+
],
|
|
101
|
+
examplePayload: {
|
|
102
|
+
continueToken: 'ct_...',
|
|
103
|
+
output: {
|
|
104
|
+
notesMarkdown: 'Completed the step and verified the result.',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
returns: 'The next step, or the same current step when rehydrating.',
|
|
108
|
+
},
|
|
109
|
+
authoritative: {
|
|
110
|
+
purpose: 'Continue the active WorkRail v2 workflow with the canonical single-token API.',
|
|
111
|
+
whenToUse: 'Call this after you complete the current step, or call it in rehydrate mode to recover the current step without advancing.',
|
|
112
|
+
rules: [
|
|
113
|
+
'Use continueToken exactly as returned by WorkRail.',
|
|
114
|
+
'Use the single-token API only.',
|
|
115
|
+
'Advance by sending output; rehydrate by omitting output.',
|
|
116
|
+
'Put updated facts in context only.',
|
|
117
|
+
],
|
|
118
|
+
examplePayload: {
|
|
119
|
+
continueToken: 'ct_...',
|
|
120
|
+
intent: 'advance',
|
|
121
|
+
output: {
|
|
122
|
+
notesMarkdown: 'Completed the step and verified the result.',
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
returns: 'The next required step, or the same current step when rehydrating.',
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
exports.CHECKPOINT_WORKFLOW_PROTOCOL = {
|
|
130
|
+
canonicalParams: {
|
|
131
|
+
required: ['checkpointToken'],
|
|
132
|
+
},
|
|
133
|
+
descriptions: {
|
|
134
|
+
standard: {
|
|
135
|
+
purpose: 'Save a checkpoint on the current WorkRail v2 step without advancing.',
|
|
136
|
+
whenToUse: 'Use this on long-running steps when you want a durable save point before continuing later.',
|
|
137
|
+
rules: [
|
|
138
|
+
'Use the checkpointToken from the most recent start_workflow or continue_workflow response.',
|
|
139
|
+
'Checkpointing is idempotent: retrying with the same checkpointToken is safe.',
|
|
140
|
+
'After checkpointing, continue by calling continue_workflow with nextCall.params.continueToken.',
|
|
141
|
+
],
|
|
142
|
+
examplePayload: {
|
|
143
|
+
checkpointToken: 'cp_...',
|
|
144
|
+
},
|
|
145
|
+
returns: 'checkpointNodeId, a resumeToken (durable cross-chat bookmark — pass as continueToken with intent: "rehydrate" in a future chat to resume exactly here), and nextCall.params.continueToken (a continueToken to continue in the current chat).',
|
|
146
|
+
},
|
|
147
|
+
authoritative: {
|
|
148
|
+
purpose: 'Create a durable checkpoint on the current WorkRail v2 step without advancing.',
|
|
149
|
+
whenToUse: 'Call this when you need a save point for a long-running step and intend to continue later.',
|
|
150
|
+
rules: [
|
|
151
|
+
'Use the checkpointToken from the most recent WorkRail response.',
|
|
152
|
+
'Checkpointing is idempotent.',
|
|
153
|
+
'To continue in this chat: use nextCall.params.continueToken.',
|
|
154
|
+
'To resume in a future chat: pass the returned resumeToken as continueToken with intent: "rehydrate".',
|
|
155
|
+
],
|
|
156
|
+
examplePayload: {
|
|
157
|
+
checkpointToken: 'cp_...',
|
|
158
|
+
},
|
|
159
|
+
returns: 'checkpointNodeId, a resumeToken (durable cross-chat bookmark — pass as continueToken with intent: "rehydrate" in a future chat to resume exactly here), and nextCall.params.continueToken (a continueToken to continue in the current chat).',
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
exports.RESUME_SESSION_PROTOCOL = {
|
|
164
|
+
canonicalParams: {
|
|
165
|
+
required: [],
|
|
166
|
+
optional: ['query', 'gitBranch', 'gitHeadSha', 'workspacePath'],
|
|
167
|
+
},
|
|
168
|
+
descriptions: {
|
|
169
|
+
standard: {
|
|
170
|
+
purpose: 'Find and reconnect to an existing WorkRail v2 workflow session.',
|
|
171
|
+
whenToUse: 'Use this when you need to resume a previously started workflow but no longer have the latest continueToken in chat context.',
|
|
172
|
+
rules: [
|
|
173
|
+
'Always pass query with the user\'s stated topic or intent (e.g. "resume the ACEI-1234 workflow"). Without query, only git-context matching runs and the right session may not surface.',
|
|
174
|
+
'Pass workspacePath when available so WorkRail can match sessions to the correct workspace and git context.',
|
|
175
|
+
'Pick the best candidate, then call continue_workflow using its nextCall template — no manual parameter construction needed.',
|
|
176
|
+
'Do not call read_session to resume; use the nextCall from the chosen candidate.',
|
|
177
|
+
'If candidates is empty, no eligible session exists — call start_workflow to begin a new session instead.',
|
|
178
|
+
'If all candidates have whyMatched: ["recency_fallback"], the match had no strong signal (git or notes). Verify the snippet before resuming.',
|
|
179
|
+
],
|
|
180
|
+
examplePayload: {
|
|
181
|
+
workspacePath: '/Users/you/git/my-project',
|
|
182
|
+
query: 'resume the coding task workflow for protocol drift',
|
|
183
|
+
},
|
|
184
|
+
returns: 'Up to 5 ranked candidates, each with whyMatched explaining the match signal and a nextCall template for continue_workflow. If candidates is empty, call start_workflow.',
|
|
185
|
+
},
|
|
186
|
+
authoritative: {
|
|
187
|
+
purpose: 'Find an existing WorkRail v2 session and reconnect to it deterministically.',
|
|
188
|
+
whenToUse: 'Call this when resuming a workflow without the latest in-chat token block.',
|
|
189
|
+
rules: [
|
|
190
|
+
'Always pass query with the user\'s stated topic or intent. Semantic (notes) matching only runs when query is provided.',
|
|
191
|
+
'Pass workspacePath set to the current workspace whenever possible.',
|
|
192
|
+
'Pick the best candidate and call continue_workflow with its nextCall — the resumeToken is already embedded in nextCall.params.continueToken.',
|
|
193
|
+
'Do not invent token values or call read_session to resume execution.',
|
|
194
|
+
'If candidates is empty, no eligible session exists — call start_workflow instead.',
|
|
195
|
+
'whyMatched values: matched_head_sha / matched_branch / matched_notes = strong signal; recency_fallback = no signal, verify snippet before resuming.',
|
|
196
|
+
],
|
|
197
|
+
examplePayload: {
|
|
198
|
+
workspacePath: '/Users/you/git/my-project',
|
|
199
|
+
query: 'resume the coding task workflow for protocol drift',
|
|
200
|
+
},
|
|
201
|
+
returns: 'Up to 5 ranked candidates, each with whyMatched confidence signals and a pre-built nextCall. Empty candidates means no session found — call start_workflow.',
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
function renderProtocolDescription(contract, mode) {
|
|
206
|
+
return renderCompactDescription(contract.descriptions[mode], contract.canonicalParams);
|
|
207
|
+
}
|
package/dist/mcp-server.d.ts
CHANGED
package/dist/mcp-server.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.
|
|
4
|
+
exports.composeServer = exports.startHttpServer = exports.startStdioServer = void 0;
|
|
5
5
|
const transport_mode_js_1 = require("./mcp/transports/transport-mode.js");
|
|
6
6
|
const stdio_entry_js_1 = require("./mcp/transports/stdio-entry.js");
|
|
7
7
|
const http_entry_js_1 = require("./mcp/transports/http-entry.js");
|
|
8
8
|
const assert_never_js_1 = require("./runtime/assert-never.js");
|
|
9
|
+
var stdio_entry_js_2 = require("./mcp/transports/stdio-entry.js");
|
|
10
|
+
Object.defineProperty(exports, "startStdioServer", { enumerable: true, get: function () { return stdio_entry_js_2.startStdioServer; } });
|
|
11
|
+
var http_entry_js_2 = require("./mcp/transports/http-entry.js");
|
|
12
|
+
Object.defineProperty(exports, "startHttpServer", { enumerable: true, get: function () { return http_entry_js_2.startHttpServer; } });
|
|
9
13
|
var server_js_1 = require("./mcp/server.js");
|
|
10
|
-
Object.defineProperty(exports, "
|
|
14
|
+
Object.defineProperty(exports, "composeServer", { enumerable: true, get: function () { return server_js_1.composeServer; } });
|
|
11
15
|
const mode = (0, transport_mode_js_1.resolveTransportMode)(process.env);
|
|
12
16
|
switch (mode.kind) {
|
|
13
17
|
case 'stdio':
|
|
@@ -69,6 +69,12 @@ export interface FunctionCall {
|
|
|
69
69
|
readonly name: string;
|
|
70
70
|
readonly args: Readonly<Record<string, unknown>>;
|
|
71
71
|
}
|
|
72
|
+
export interface ExtensionPoint {
|
|
73
|
+
readonly slotId: string;
|
|
74
|
+
readonly purpose: string;
|
|
75
|
+
readonly default: string;
|
|
76
|
+
readonly acceptedKinds?: readonly ('routine' | 'workflow')[];
|
|
77
|
+
}
|
|
72
78
|
export interface WorkflowRecommendedPreferences {
|
|
73
79
|
readonly recommendedAutonomy?: 'guided' | 'full_auto_stop_on_user_deps' | 'full_auto_never_stop';
|
|
74
80
|
readonly recommendedRiskPolicy?: 'conservative' | 'balanced' | 'aggressive';
|
|
@@ -85,6 +91,7 @@ export interface WorkflowDefinition {
|
|
|
85
91
|
readonly functionDefinitions?: readonly FunctionDefinition[];
|
|
86
92
|
readonly recommendedPreferences?: WorkflowRecommendedPreferences;
|
|
87
93
|
readonly features?: readonly string[];
|
|
94
|
+
readonly extensionPoints?: readonly ExtensionPoint[];
|
|
88
95
|
}
|
|
89
96
|
export declare function isLoopStepDefinition(step: WorkflowStepDefinition | LoopStepDefinition): step is LoopStepDefinition;
|
|
90
97
|
export declare function isWorkflowStepDefinition(step: WorkflowStepDefinition | LoopStepDefinition): step is WorkflowStepDefinition;
|
|
@@ -33,5 +33,6 @@ function createWorkflowDefinition(definition) {
|
|
|
33
33
|
clarificationPrompts: definition.clarificationPrompts ? Object.freeze([...definition.clarificationPrompts]) : undefined,
|
|
34
34
|
metaGuidance: definition.metaGuidance ? Object.freeze([...definition.metaGuidance]) : undefined,
|
|
35
35
|
functionDefinitions: definition.functionDefinitions ? Object.freeze([...definition.functionDefinitions]) : undefined,
|
|
36
|
+
extensionPoints: definition.extensionPoints ? Object.freeze([...definition.extensionPoints]) : undefined,
|
|
36
37
|
});
|
|
37
38
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface BindingDriftWarning {
|
|
2
|
+
readonly code: 'BINDING_DRIFT';
|
|
3
|
+
readonly slotId: string;
|
|
4
|
+
readonly pinnedValue: string;
|
|
5
|
+
readonly currentValue: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function formatDriftWarning(w: BindingDriftWarning): string;
|
|
8
|
+
export declare function detectBindingDrift(pinnedOverrides: Readonly<Record<string, string>>, currentBindings: ReadonlyMap<string, string>): readonly BindingDriftWarning[];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatDriftWarning = formatDriftWarning;
|
|
4
|
+
exports.detectBindingDrift = detectBindingDrift;
|
|
5
|
+
function formatDriftWarning(w) {
|
|
6
|
+
if (w.currentValue === 'default') {
|
|
7
|
+
return (`Binding '${w.slotId}' was removed from .workrail/bindings.json since this session started. ` +
|
|
8
|
+
`Session uses '${w.pinnedValue}' (project override at start); ` +
|
|
9
|
+
`it now falls back to the workflow default. ` +
|
|
10
|
+
`Start a new session to pick up the change.`);
|
|
11
|
+
}
|
|
12
|
+
return (`Binding '${w.slotId}' changed since this session started. ` +
|
|
13
|
+
`Session uses '${w.pinnedValue}' (compiled at start); ` +
|
|
14
|
+
`current .workrail/bindings.json specifies '${w.currentValue}'. ` +
|
|
15
|
+
`Start a new session to pick up the updated binding.`);
|
|
16
|
+
}
|
|
17
|
+
function detectBindingDrift(pinnedOverrides, currentBindings) {
|
|
18
|
+
const warnings = [];
|
|
19
|
+
for (const [slotId, pinnedValue] of Object.entries(pinnedOverrides)) {
|
|
20
|
+
const currentValue = currentBindings.get(slotId);
|
|
21
|
+
if (currentValue === undefined) {
|
|
22
|
+
warnings.push({ code: 'BINDING_DRIFT', slotId, pinnedValue, currentValue: 'default' });
|
|
23
|
+
}
|
|
24
|
+
else if (currentValue !== pinnedValue) {
|
|
25
|
+
warnings.push({ code: 'BINDING_DRIFT', slotId, pinnedValue, currentValue });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return warnings;
|
|
29
|
+
}
|
|
@@ -162,7 +162,7 @@ function reasonToBlocker(reason) {
|
|
|
162
162
|
code: 'MISSING_REQUIRED_OUTPUT',
|
|
163
163
|
pointer: { kind: 'output_contract', contractRef },
|
|
164
164
|
message: `Missing required output (contractRef=${contractRef}).`,
|
|
165
|
-
suggestedFix: 'Call continue_workflow
|
|
165
|
+
suggestedFix: 'Call continue_workflow without output to rehydrate the current step, then retry with output.notesMarkdown that satisfies the step output requirements.',
|
|
166
166
|
}))
|
|
167
167
|
.andThen(ensureBlockerTextBudgets);
|
|
168
168
|
case 'invalid_required_output':
|
|
@@ -171,7 +171,7 @@ function reasonToBlocker(reason) {
|
|
|
171
171
|
code: 'INVALID_REQUIRED_OUTPUT',
|
|
172
172
|
pointer: { kind: 'output_contract', contractRef },
|
|
173
173
|
message: `Invalid output for contractRef=${contractRef}.`,
|
|
174
|
-
suggestedFix: 'Update output.notesMarkdown to satisfy validation. Then call continue_workflow
|
|
174
|
+
suggestedFix: 'Update output.notesMarkdown to satisfy validation. Then call continue_workflow without output to rehydrate the current step and retry advance with the corrected output. Replaying the same invalid advance will keep returning this blocked result.',
|
|
175
175
|
}))
|
|
176
176
|
.andThen(ensureBlockerTextBudgets);
|
|
177
177
|
case 'missing_notes':
|
|
@@ -51,6 +51,8 @@ export declare const CompiledWorkflowSnapshotV1Schema: z.ZodDiscriminatedUnion<"
|
|
|
51
51
|
description: z.ZodString;
|
|
52
52
|
version: z.ZodString;
|
|
53
53
|
definition: z.ZodType<unknown, z.ZodTypeDef, unknown>;
|
|
54
|
+
resolvedBindings: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
55
|
+
pinnedOverrides: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
54
56
|
}, "strip", z.ZodTypeAny, {
|
|
55
57
|
name: string;
|
|
56
58
|
description: string;
|
|
@@ -59,6 +61,8 @@ export declare const CompiledWorkflowSnapshotV1Schema: z.ZodDiscriminatedUnion<"
|
|
|
59
61
|
schemaVersion: 1;
|
|
60
62
|
sourceKind: "v1_pinned";
|
|
61
63
|
definition?: unknown;
|
|
64
|
+
resolvedBindings?: Record<string, string> | undefined;
|
|
65
|
+
pinnedOverrides?: Record<string, string> | undefined;
|
|
62
66
|
}, {
|
|
63
67
|
name: string;
|
|
64
68
|
description: string;
|
|
@@ -67,6 +71,8 @@ export declare const CompiledWorkflowSnapshotV1Schema: z.ZodDiscriminatedUnion<"
|
|
|
67
71
|
schemaVersion: 1;
|
|
68
72
|
sourceKind: "v1_pinned";
|
|
69
73
|
definition?: unknown;
|
|
74
|
+
resolvedBindings?: Record<string, string> | undefined;
|
|
75
|
+
pinnedOverrides?: Record<string, string> | undefined;
|
|
70
76
|
}>]>;
|
|
71
77
|
export type CompiledWorkflowSnapshotV1 = z.infer<typeof CompiledWorkflowSnapshotV1Schema>;
|
|
72
78
|
export declare const CompiledWorkflowSnapshotSchema: z.ZodDiscriminatedUnion<"sourceKind", [z.ZodObject<{
|
|
@@ -121,6 +127,8 @@ export declare const CompiledWorkflowSnapshotSchema: z.ZodDiscriminatedUnion<"so
|
|
|
121
127
|
description: z.ZodString;
|
|
122
128
|
version: z.ZodString;
|
|
123
129
|
definition: z.ZodType<unknown, z.ZodTypeDef, unknown>;
|
|
130
|
+
resolvedBindings: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
131
|
+
pinnedOverrides: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
124
132
|
}, "strip", z.ZodTypeAny, {
|
|
125
133
|
name: string;
|
|
126
134
|
description: string;
|
|
@@ -129,6 +137,8 @@ export declare const CompiledWorkflowSnapshotSchema: z.ZodDiscriminatedUnion<"so
|
|
|
129
137
|
schemaVersion: 1;
|
|
130
138
|
sourceKind: "v1_pinned";
|
|
131
139
|
definition?: unknown;
|
|
140
|
+
resolvedBindings?: Record<string, string> | undefined;
|
|
141
|
+
pinnedOverrides?: Record<string, string> | undefined;
|
|
132
142
|
}, {
|
|
133
143
|
name: string;
|
|
134
144
|
description: string;
|
|
@@ -137,5 +147,7 @@ export declare const CompiledWorkflowSnapshotSchema: z.ZodDiscriminatedUnion<"so
|
|
|
137
147
|
schemaVersion: 1;
|
|
138
148
|
sourceKind: "v1_pinned";
|
|
139
149
|
definition?: unknown;
|
|
150
|
+
resolvedBindings?: Record<string, string> | undefined;
|
|
151
|
+
pinnedOverrides?: Record<string, string> | undefined;
|
|
140
152
|
}>]>;
|
|
141
153
|
export type CompiledWorkflowSnapshot = CompiledWorkflowSnapshotV1;
|
|
@@ -24,6 +24,8 @@ const CompiledWorkflowSnapshotV1PinnedSchema = zod_1.z.object({
|
|
|
24
24
|
description: zod_1.z.string().min(1),
|
|
25
25
|
version: zod_1.z.string().min(1),
|
|
26
26
|
definition: json_zod_js_1.JsonValueSchema,
|
|
27
|
+
resolvedBindings: zod_1.z.record(zod_1.z.string()).optional(),
|
|
28
|
+
pinnedOverrides: zod_1.z.record(zod_1.z.string()).optional(),
|
|
27
29
|
});
|
|
28
30
|
exports.CompiledWorkflowSnapshotV1Schema = zod_1.z.discriminatedUnion('sourceKind', [
|
|
29
31
|
CompiledWorkflowSnapshotV1PreviewSchema,
|