@exaudeus/workrail 3.3.0 → 3.4.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 (74) 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/workflow.schema.json +44 -0
  68. package/workflows/coding-task-workflow-agentic.json +15 -15
  69. package/workflows/coding-task-workflow-agentic.lean.v2.json +10 -10
  70. package/workflows/coding-task-workflow-agentic.v2.json +12 -12
  71. package/workflows/coding-task-workflow-with-loops.json +2 -2
  72. package/workflows/document-creation-workflow.json +1 -1
  73. package/workflows/exploration-workflow.json +3 -3
  74. package/workflows/mr-review-workflow.agentic.v2.json +11 -11
@@ -21,4 +21,5 @@ export declare function handleRehydrateIntent(args: {
21
21
  };
22
22
  readonly aliasStore: import('../../../v2/ports/token-alias-store.port.js').TokenAliasStorePortV2;
23
23
  readonly entropy: import('../../../v2/ports/random-entropy.port.js').RandomEntropyPortV2;
24
+ readonly resolvedRootUris?: readonly string[];
24
25
  }): RA<z.infer<typeof V2ContinueWorkflowOutputSchema>, ContinueWorkflowError>;
@@ -2,6 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.handleRehydrateIntent = handleRehydrateIntent;
4
4
  const output_schemas_js_1 = require("../../output-schemas.js");
5
+ const binding_drift_js_1 = require("../../../v2/durable-core/domain/binding-drift.js");
6
+ const binding_registry_js_1 = require("../../../application/services/compiler/binding-registry.js");
7
+ const v2_workspace_resolution_js_1 = require("../v2-workspace-resolution.js");
5
8
  const snapshot_state_js_1 = require("../../../v2/durable-core/projections/snapshot-state.js");
6
9
  const workflow_js_1 = require("../../../types/workflow.js");
7
10
  const index_js_1 = require("../../../v2/durable-core/ids/index.js");
@@ -16,14 +19,14 @@ const v2_state_conversion_js_1 = require("../v2-state-conversion.js");
16
19
  const constants_js_1 = require("../../../v2/durable-core/constants.js");
17
20
  const index_js_2 = require("./index.js");
18
21
  function handleRehydrateIntent(args) {
19
- const { input, sessionId, runId, nodeId, workflowHashRef, truth, tokenCodecPorts, pinnedStore, snapshotStore, idFactory, aliasStore, entropy } = args;
22
+ const { input, sessionId, runId, nodeId, workflowHashRef, truth, tokenCodecPorts, pinnedStore, snapshotStore, idFactory, aliasStore, entropy, resolvedRootUris } = args;
20
23
  const runStarted = truth.events.find((e) => e.kind === constants_js_1.EVENT_KIND.RUN_STARTED && e.scope.runId === String(runId));
21
24
  const workflowId = runStarted?.data.workflowId;
22
25
  if (!runStarted || typeof workflowId !== 'string' || workflowId.trim() === '') {
23
26
  return (0, neverthrow_1.errAsync)({
24
27
  kind: 'token_unknown_node',
25
- message: 'No durable run state was found for this stateToken (missing run_started).',
26
- suggestion: 'Use start_workflow to mint a new run, or use a stateToken returned by WorkRail for an existing run.',
28
+ message: 'No durable run state was found for this continueToken (missing run_started).',
29
+ suggestion: 'Use start_workflow to mint a new run, or use a continueToken returned by WorkRail for an existing run.',
27
30
  });
28
31
  }
29
32
  const workflowHash = runStarted.data.workflowHash;
@@ -36,14 +39,14 @@ function handleRehydrateIntent(args) {
36
39
  });
37
40
  }
38
41
  if (String(expectedRefRes.value) !== String(workflowHashRef)) {
39
- return (0, neverthrow_1.errAsync)({ kind: 'precondition_failed', message: 'workflowHash mismatch for this run.', suggestion: 'Use the stateToken returned by WorkRail for this run.' });
42
+ return (0, neverthrow_1.errAsync)({ kind: 'precondition_failed', message: 'workflowHash mismatch for this run.', suggestion: 'Use the continueToken returned by WorkRail for this run.' });
40
43
  }
41
44
  const nodeCreated = truth.events.find((e) => e.kind === constants_js_1.EVENT_KIND.NODE_CREATED && e.scope.nodeId === String(nodeId) && e.scope.runId === String(runId));
42
45
  if (!nodeCreated) {
43
46
  return (0, neverthrow_1.errAsync)({
44
47
  kind: 'token_unknown_node',
45
- message: 'No durable node state was found for this stateToken (missing node_created).',
46
- suggestion: 'Use a stateToken returned by WorkRail for an existing node.',
48
+ message: 'No durable node state was found for this continueToken (missing node_created).',
49
+ suggestion: 'Use a continueToken returned by WorkRail for an existing node.',
47
50
  });
48
51
  }
49
52
  const expectedNodeRefRes = (0, workflow_hash_ref_js_1.deriveWorkflowHashRef)(nodeCreated.data.workflowHash);
@@ -55,7 +58,7 @@ function handleRehydrateIntent(args) {
55
58
  });
56
59
  }
57
60
  if (String(expectedNodeRefRes.value) !== String(workflowHashRef)) {
58
- return (0, neverthrow_1.errAsync)({ kind: 'precondition_failed', message: 'workflowHash mismatch for this node.', suggestion: 'Use the stateToken returned by WorkRail for this node.' });
61
+ return (0, neverthrow_1.errAsync)({ kind: 'precondition_failed', message: 'workflowHash mismatch for this node.', suggestion: 'Use the continueToken returned by WorkRail for this node.' });
59
62
  }
60
63
  return snapshotStore.getExecutionSnapshotV1(nodeCreated.data.snapshotRef)
61
64
  .mapErr((cause) => ({ kind: 'snapshot_load_failed', cause }))
@@ -64,35 +67,13 @@ function handleRehydrateIntent(args) {
64
67
  return (0, neverthrow_1.errAsync)({
65
68
  kind: 'token_unknown_node',
66
69
  message: 'No execution snapshot was found for this node.',
67
- suggestion: 'Use a stateToken returned by WorkRail for an existing node.',
70
+ suggestion: 'Use a continueToken returned by WorkRail for an existing node.',
68
71
  });
69
72
  }
70
73
  const engineState = snapshot.enginePayload.engineState;
71
74
  const pending = (0, snapshot_state_js_1.derivePendingStep)(engineState);
72
75
  const isComplete = (0, snapshot_state_js_1.deriveIsComplete)(engineState);
73
- if (!pending) {
74
- const preferences = (0, v2_execution_helpers_js_1.derivePreferencesOrDefault)({ truth, runId, nodeId });
75
- const nextIntent = (0, v2_state_conversion_js_1.deriveNextIntent)({ rehydrateOnly: true, isComplete, pending: null });
76
- return (0, neverthrow_1.okAsync)(output_schemas_js_1.V2ContinueWorkflowOutputSchema.parse({
77
- kind: 'ok',
78
- isComplete,
79
- pending: null,
80
- preferences,
81
- nextIntent,
82
- nextCall: null,
83
- }));
84
- }
85
- const attemptId = (0, v2_token_ops_js_1.newAttemptId)(idFactory);
86
- const entryBase = {
87
- sessionId: String(sessionId),
88
- runId: String(runId),
89
- nodeId: String(nodeId),
90
- attemptId: String(attemptId),
91
- workflowHashRef: String(workflowHashRef),
92
- };
93
- return (0, v2_token_ops_js_1.mintContinueAndCheckpointTokens)({ entry: entryBase, ports: tokenCodecPorts, aliasStore, entropy })
94
- .mapErr((failure) => ({ kind: 'token_signing_failed', cause: failure }))
95
- .andThen(({ continueToken: continueTokenValue, checkpointToken: checkpointTokenValue }) => pinnedStore.get(workflowHash)
76
+ return pinnedStore.get(workflowHash)
96
77
  .mapErr((cause) => ({ kind: 'pinned_workflow_store_failed', cause }))
97
78
  .andThen((pinned) => {
98
79
  if (!pinned)
@@ -106,35 +87,70 @@ function handleRehydrateIntent(args) {
106
87
  suggestion: 'Re-pin the workflow via start_workflow.',
107
88
  });
108
89
  }
109
- const wf = (0, workflow_js_1.createWorkflow)(pinned.definition, (0, workflow_source_js_1.createBundledSource)());
110
- const metaRes = (0, prompt_renderer_js_1.renderPendingPrompt)({
111
- workflow: wf,
112
- stepId: String(pending.stepId),
113
- loopPath: pending.loopPath,
114
- truth,
115
- runId: (0, index_js_1.asRunId)(String(runId)),
116
- nodeId: (0, index_js_1.asNodeId)(String(nodeId)),
117
- rehydrateOnly: true,
118
- });
119
- if (metaRes.isErr()) {
120
- return (0, neverthrow_1.errAsync)({
121
- kind: 'invariant_violation',
122
- message: `Prompt rendering failed: ${metaRes.error.message}`,
123
- });
90
+ const bindingBaseDir = (0, v2_workspace_resolution_js_1.resolveBindingBaseDir)(input.workspacePath, resolvedRootUris ?? []);
91
+ const driftWarnings = detectBindingDriftForSnapshot(pinned, workflowId, bindingBaseDir);
92
+ if (!pending) {
93
+ const preferences = (0, v2_execution_helpers_js_1.derivePreferencesOrDefault)({ truth, runId, nodeId });
94
+ const nextIntent = (0, v2_state_conversion_js_1.deriveNextIntent)({ rehydrateOnly: true, isComplete, pending: null });
95
+ return (0, neverthrow_1.okAsync)(output_schemas_js_1.V2ContinueWorkflowOutputSchema.parse({
96
+ kind: 'ok',
97
+ isComplete,
98
+ pending: null,
99
+ preferences,
100
+ nextIntent,
101
+ nextCall: null,
102
+ ...(driftWarnings.length > 0 ? { warnings: driftWarnings } : {}),
103
+ }));
124
104
  }
125
- const meta = metaRes.value;
126
- const preferences = (0, v2_execution_helpers_js_1.derivePreferencesOrDefault)({ truth, runId, nodeId });
127
- const nextIntent = (0, v2_state_conversion_js_1.deriveNextIntent)({ rehydrateOnly: true, isComplete, pending: meta });
128
- return (0, neverthrow_1.okAsync)(output_schemas_js_1.V2ContinueWorkflowOutputSchema.parse({
129
- kind: 'ok',
130
- continueToken: continueTokenValue,
131
- checkpointToken: checkpointTokenValue,
132
- isComplete,
133
- pending: (0, output_schemas_js_1.toPendingStep)(meta),
134
- preferences,
135
- nextIntent,
136
- nextCall: (0, index_js_2.buildNextCall)({ continueToken: continueTokenValue, isComplete, pending: meta }),
137
- }));
138
- }));
105
+ const attemptId = (0, v2_token_ops_js_1.newAttemptId)(idFactory);
106
+ const entryBase = {
107
+ sessionId: String(sessionId),
108
+ runId: String(runId),
109
+ nodeId: String(nodeId),
110
+ attemptId: String(attemptId),
111
+ workflowHashRef: String(workflowHashRef),
112
+ };
113
+ return (0, v2_token_ops_js_1.mintContinueAndCheckpointTokens)({ entry: entryBase, ports: tokenCodecPorts, aliasStore, entropy })
114
+ .mapErr((failure) => ({ kind: 'token_signing_failed', cause: failure }))
115
+ .andThen(({ continueToken: continueTokenValue, checkpointToken: checkpointTokenValue }) => {
116
+ const wf = (0, workflow_js_1.createWorkflow)(pinned.definition, (0, workflow_source_js_1.createBundledSource)());
117
+ const metaRes = (0, prompt_renderer_js_1.renderPendingPrompt)({
118
+ workflow: wf,
119
+ stepId: String(pending.stepId),
120
+ loopPath: pending.loopPath,
121
+ truth,
122
+ runId: (0, index_js_1.asRunId)(String(runId)),
123
+ nodeId: (0, index_js_1.asNodeId)(String(nodeId)),
124
+ rehydrateOnly: true,
125
+ });
126
+ if (metaRes.isErr()) {
127
+ return (0, neverthrow_1.errAsync)({
128
+ kind: 'invariant_violation',
129
+ message: `Prompt rendering failed: ${metaRes.error.message}`,
130
+ });
131
+ }
132
+ const meta = metaRes.value;
133
+ const preferences = (0, v2_execution_helpers_js_1.derivePreferencesOrDefault)({ truth, runId, nodeId });
134
+ const nextIntent = (0, v2_state_conversion_js_1.deriveNextIntent)({ rehydrateOnly: true, isComplete, pending: meta });
135
+ return (0, neverthrow_1.okAsync)(output_schemas_js_1.V2ContinueWorkflowOutputSchema.parse({
136
+ kind: 'ok',
137
+ continueToken: continueTokenValue,
138
+ checkpointToken: checkpointTokenValue,
139
+ isComplete,
140
+ pending: (0, output_schemas_js_1.toPendingStep)(meta),
141
+ preferences,
142
+ nextIntent,
143
+ nextCall: (0, index_js_2.buildNextCall)({ continueToken: continueTokenValue, isComplete, pending: meta }),
144
+ ...(driftWarnings.length > 0 ? { warnings: driftWarnings } : {}),
145
+ }));
146
+ });
147
+ });
139
148
  });
140
149
  }
150
+ function detectBindingDriftForSnapshot(pinned, workflowId, baseDir) {
151
+ const pinnedOverrides = pinned.pinnedOverrides ?? pinned.resolvedBindings;
152
+ if (!pinnedOverrides || Object.keys(pinnedOverrides).length === 0)
153
+ return [];
154
+ const currentBindings = (0, binding_registry_js_1.loadProjectBindings)(workflowId, baseDir);
155
+ return (0, binding_drift_js_1.detectBindingDrift)(pinnedOverrides, currentBindings);
156
+ }
@@ -10,6 +10,7 @@ const index_js_2 = require("../../../v2/durable-core/ids/index.js");
10
10
  const neverthrow_1 = require("neverthrow");
11
11
  const v2_execution_helpers_js_1 = require("../v2-execution-helpers.js");
12
12
  const v2_token_ops_js_1 = require("../v2-token-ops.js");
13
+ const types_js_2 = require("../../types.js");
13
14
  const v2_context_budget_js_1 = require("../v2-context-budget.js");
14
15
  const start_js_1 = require("./start.js");
15
16
  const continue_rehydrate_js_1 = require("./continue-rehydrate.js");
@@ -37,56 +38,97 @@ async function handleV2ContinueWorkflow(input, ctx) {
37
38
  return guard.error;
38
39
  return executeContinueWorkflow(input, guard.ctx).match((payload) => (0, types_js_1.success)(payload), (e) => (0, v2_execution_helpers_js_1.mapContinueWorkflowErrorToToolError)(e));
39
40
  }
41
+ function classifyToken(raw) {
42
+ if (raw.startsWith('st_') || raw.startsWith('st1'))
43
+ return { kind: 'state', raw };
44
+ return { kind: 'continue', raw };
45
+ }
46
+ function loadAndRehydrate(args) {
47
+ const { sessionId, runId, nodeId, workflowHashRef, input } = args;
48
+ const { sessionStore, tokenCodecPorts, pinnedStore, snapshotStore, idFactory, tokenAliasStore, entropy } = args.ctx.v2;
49
+ return sessionStore.load(sessionId)
50
+ .mapErr((cause) => ({ kind: 'session_load_failed', cause }))
51
+ .andThen((truth) => (0, continue_rehydrate_js_1.handleRehydrateIntent)({
52
+ input,
53
+ sessionId,
54
+ runId,
55
+ nodeId,
56
+ workflowHashRef,
57
+ truth,
58
+ tokenCodecPorts,
59
+ pinnedStore,
60
+ snapshotStore,
61
+ idFactory,
62
+ aliasStore: tokenAliasStore,
63
+ entropy,
64
+ resolvedRootUris: args.ctx.v2.resolvedRootUris,
65
+ }));
66
+ }
40
67
  function executeContinueWorkflow(input, ctx) {
41
68
  const { gate, sessionStore, snapshotStore, pinnedStore, sha256, tokenCodecPorts, idFactory, tokenAliasStore, entropy } = ctx.v2;
42
69
  const ctxCheck = (0, v2_context_budget_js_1.checkContextBudget)({ tool: 'continue_workflow', context: input.context });
43
70
  if (!ctxCheck.ok)
44
71
  return (0, neverthrow_1.errAsync)({ kind: 'validation_failed', failure: ctxCheck.error });
45
- return (0, v2_token_ops_js_1.parseContinueTokenOrFail)(input.continueToken, tokenCodecPorts, tokenAliasStore)
46
- .mapErr((failure) => ({ kind: 'validation_failed', failure }))
47
- .andThen((resolved) => {
48
- const sessionId = (0, index_js_2.asSessionId)(resolved.sessionId);
49
- const runId = (0, index_js_2.asRunId)(resolved.runId);
50
- const nodeId = (0, index_js_2.asNodeId)(resolved.nodeId);
51
- const workflowHashRef = resolved.workflowHashRef;
52
- if (input.intent === 'rehydrate') {
53
- return sessionStore.load(sessionId)
54
- .mapErr((cause) => ({ kind: 'session_load_failed', cause }))
55
- .andThen((truth) => (0, continue_rehydrate_js_1.handleRehydrateIntent)({
72
+ const routing = classifyToken(input.continueToken);
73
+ switch (routing.kind) {
74
+ case 'state': {
75
+ if (input.intent === 'advance') {
76
+ const hasOutput = input.output != null;
77
+ const message = hasOutput
78
+ ? 'A resumeToken cannot carry output — resumeTokens are read-only. Remove the output field and call continue_workflow with just the resumeToken to rehydrate session context.'
79
+ : 'A resumeToken (st_... / st1...) carries no advance authority. Use intent: "rehydrate" to restore session context.';
80
+ const suggestion = hasOutput
81
+ ? 'Remove the output field. Pass just { continueToken: "<resumeToken>", intent: "rehydrate" } to rehydrate, then use the returned continueToken to advance.'
82
+ : 'Pass intent: "rehydrate" when using the resumeToken from resume_session or checkpoint_workflow.';
83
+ return (0, neverthrow_1.errAsync)({
84
+ kind: 'validation_failed',
85
+ failure: (0, types_js_2.errNotRetryable)('TOKEN_SCOPE_MISMATCH', message, { suggestion }),
86
+ });
87
+ }
88
+ return (0, v2_token_ops_js_1.parseStateTokenOrFail)(routing.raw, tokenCodecPorts, tokenAliasStore)
89
+ .mapErr((failure) => ({ kind: 'validation_failed', failure }))
90
+ .andThen((resolved) => loadAndRehydrate({
91
+ sessionId: (0, index_js_2.asSessionId)(resolved.payload.sessionId),
92
+ runId: (0, index_js_2.asRunId)(resolved.payload.runId),
93
+ nodeId: (0, index_js_2.asNodeId)(resolved.payload.nodeId),
94
+ workflowHashRef: resolved.payload.workflowHashRef,
56
95
  input,
57
- sessionId,
58
- runId,
59
- nodeId,
60
- workflowHashRef,
61
- truth,
62
- tokenCodecPorts,
63
- pinnedStore,
64
- snapshotStore,
65
- idFactory,
66
- aliasStore: tokenAliasStore,
67
- entropy,
96
+ ctx,
68
97
  }));
69
98
  }
70
- const attemptId = (0, index_js_1.asAttemptId)(resolved.attemptId);
71
- return sessionStore.load(sessionId)
72
- .mapErr((cause) => ({ kind: 'session_load_failed', cause }))
73
- .andThen((truth) => (0, continue_advance_js_1.handleAdvanceIntent)({
74
- input,
75
- sessionId,
76
- runId,
77
- nodeId,
78
- attemptId,
79
- workflowHashRef,
80
- truth,
81
- gate,
82
- sessionStore,
83
- snapshotStore,
84
- pinnedStore,
85
- tokenCodecPorts,
86
- idFactory,
87
- sha256,
88
- aliasStore: tokenAliasStore,
89
- entropy,
90
- }));
91
- });
99
+ case 'continue': {
100
+ return (0, v2_token_ops_js_1.parseContinueTokenOrFail)(routing.raw, tokenCodecPorts, tokenAliasStore)
101
+ .mapErr((failure) => ({ kind: 'validation_failed', failure }))
102
+ .andThen((resolved) => {
103
+ const sessionId = (0, index_js_2.asSessionId)(resolved.sessionId);
104
+ const runId = (0, index_js_2.asRunId)(resolved.runId);
105
+ const nodeId = (0, index_js_2.asNodeId)(resolved.nodeId);
106
+ const workflowHashRef = resolved.workflowHashRef;
107
+ if (input.intent === 'rehydrate') {
108
+ return loadAndRehydrate({ sessionId, runId, nodeId, workflowHashRef, input, ctx });
109
+ }
110
+ const attemptId = (0, index_js_1.asAttemptId)(resolved.attemptId);
111
+ return sessionStore.load(sessionId)
112
+ .mapErr((cause) => ({ kind: 'session_load_failed', cause }))
113
+ .andThen((truth) => (0, continue_advance_js_1.handleAdvanceIntent)({
114
+ input,
115
+ sessionId,
116
+ runId,
117
+ nodeId,
118
+ attemptId,
119
+ workflowHashRef,
120
+ truth,
121
+ gate,
122
+ sessionStore,
123
+ snapshotStore,
124
+ pinnedStore,
125
+ tokenCodecPorts,
126
+ idFactory,
127
+ sha256,
128
+ aliasStore: tokenAliasStore,
129
+ entropy,
130
+ }));
131
+ });
132
+ }
133
+ }
92
134
  }
@@ -107,7 +107,7 @@ function mapTokenDecodeErrorToToolError(e) {
107
107
  }
108
108
  if (bech32mErr.code === 'BECH32M_HRP_MISMATCH') {
109
109
  return (0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', `Wrong token type. ${e.message}`, {
110
- suggestion: 'Ensure you are using the correct token (stateToken vs ackToken) for this operation.',
110
+ suggestion: 'Ensure you are using the correct token type for this operation (continueToken, checkpointToken, or resumeToken).',
111
111
  details: {
112
112
  errorType: 'hrp_mismatch',
113
113
  },
@@ -30,14 +30,14 @@ async function handleV2ResumeSession(input, ctx) {
30
30
  if (resumeResult.isErr()) {
31
31
  return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', `Resume failed: ${resumeResult.error.message}`);
32
32
  }
33
- const candidates = resumeResult.value;
33
+ const { candidates, totalFound } = resumeResult.value;
34
34
  const { outputCandidates, skipped } = mintCandidateTokens(candidates, v2.tokenCodecPorts);
35
35
  if (skipped > 0) {
36
36
  console.error(`[workrail:resume] ${skipped}/${candidates.length} candidate(s) skipped: token minting failed (workflowHashRef derivation or signing error)`);
37
37
  }
38
38
  const output = output_schemas_js_1.V2ResumeSessionOutputSchema.parse({
39
39
  candidates: outputCandidates,
40
- totalEligible: candidates.length,
40
+ totalEligible: totalFound,
41
41
  });
42
42
  return {
43
43
  type: 'success',
@@ -53,7 +53,7 @@ function mintCandidateTokens(candidates, ports) {
53
53
  skipped++;
54
54
  continue;
55
55
  }
56
- const stateTokenRes = (0, v2_token_ops_js_1.signTokenOrErr)({
56
+ const resumeTokenRes = (0, v2_token_ops_js_1.signTokenOrErr)({
57
57
  payload: {
58
58
  tokenVersion: 1,
59
59
  tokenKind: 'state',
@@ -64,16 +64,21 @@ function mintCandidateTokens(candidates, ports) {
64
64
  },
65
65
  ports,
66
66
  });
67
- if (stateTokenRes.isErr()) {
67
+ if (resumeTokenRes.isErr()) {
68
68
  skipped++;
69
69
  continue;
70
70
  }
71
71
  outputCandidates.push({
72
72
  sessionId: candidate.sessionId,
73
73
  runId: candidate.runId,
74
- stateToken: stateTokenRes.value,
74
+ workflowId: candidate.workflowId,
75
+ resumeToken: resumeTokenRes.value,
75
76
  snippet: candidate.snippet,
76
77
  whyMatched: [...candidate.whyMatched],
78
+ nextCall: {
79
+ tool: 'continue_workflow',
80
+ params: { continueToken: resumeTokenRes.value, intent: 'rehydrate' },
81
+ },
77
82
  });
78
83
  }
79
84
  return { outputCandidates, skipped };
@@ -35,7 +35,7 @@ export declare function mintContinueAndCheckpointTokens(args: Omit<MintShortToke
35
35
  readonly entry: Omit<TokenAliasEntryV2, 'nonceHex' | 'tokenKind'>;
36
36
  }): ResultAsync<ContinueAndCheckpointTokens, ToolFailure>;
37
37
  export interface ShortTokenTriple {
38
- readonly stateToken: string;
38
+ readonly resumeToken: string;
39
39
  readonly ackToken: string;
40
40
  readonly checkpointToken: string;
41
41
  }
@@ -94,7 +94,7 @@ function parseStateTokenOrFail(raw, ports, aliasStore) {
94
94
  return resolveShortToken(raw, ports, aliasStore).andThen((resolved) => {
95
95
  if (resolved.payload.tokenKind !== 'state') {
96
96
  return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', 'Expected a state token (st_... or st1...).', {
97
- suggestion: 'Use the stateToken returned by WorkRail.',
97
+ suggestion: 'Use the resumeToken returned by WorkRail.',
98
98
  }));
99
99
  }
100
100
  return (0, neverthrow_1.okAsync)(resolved);
@@ -110,7 +110,7 @@ function parseStateTokenOrFail(raw, ports, aliasStore) {
110
110
  }
111
111
  if (parsedRes.value.payload.tokenKind !== 'state') {
112
112
  return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', 'Expected a state token (st1...).', {
113
- suggestion: 'Use the stateToken returned by WorkRail.',
113
+ suggestion: 'Use the resumeToken returned by WorkRail.',
114
114
  }));
115
115
  }
116
116
  return (0, neverthrow_1.okAsync)(parsedRes.value);
@@ -288,7 +288,7 @@ function mintShortTokenTriple(args) {
288
288
  const replayCk = reTokenFromNonceHex('checkpoint', existingCk.nonceHex, ports);
289
289
  if (replayState.isOk() && replayAck.isOk() && replayCk.isOk()) {
290
290
  return (0, neverthrow_1.okAsync)({
291
- stateToken: replayState.value,
291
+ resumeToken: replayState.value,
292
292
  ackToken: replayAck.value,
293
293
  checkpointToken: replayCk.value,
294
294
  });
@@ -310,7 +310,7 @@ function mintShortTokenTriple(args) {
310
310
  : 'UNKNOWN';
311
311
  return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('INTERNAL_ERROR', `Short token minting failed: ${msg}`));
312
312
  }
313
- const stateTokenStr = stateMinted.value;
313
+ const resumeTokenStr = stateMinted.value;
314
314
  const ackTokenStr = ackMinted.value;
315
315
  const ckTokenStr = ckMinted.value;
316
316
  const stateNonceHex = bufToHex(stateNonce);
@@ -347,7 +347,7 @@ function mintShortTokenTriple(args) {
347
347
  .andThen(() => aliasStore.register(ackEntry))
348
348
  .andThen(() => aliasStore.register(ckEntry))
349
349
  .map(() => ({
350
- stateToken: stateTokenStr,
350
+ resumeToken: resumeTokenStr,
351
351
  ackToken: ackTokenStr,
352
352
  checkpointToken: ckTokenStr,
353
353
  }))
@@ -1,5 +1,6 @@
1
1
  import type { ResultAsync } from 'neverthrow';
2
2
  import type { WorkspaceAnchor, WorkspaceSource } from '../../v2/ports/workspace-anchor.port.js';
3
3
  import type { V2Dependencies } from '../types.js';
4
+ export declare function resolveBindingBaseDir(workspacePath: string | undefined, resolvedRootUris: readonly string[]): string;
4
5
  export declare function selectWorkspaceSource(workspacePath: string | undefined, resolvedRootUris: readonly string[]): WorkspaceSource;
5
6
  export declare function resolveWorkspaceAnchors(v2: V2Dependencies, workspacePath: string | undefined): ResultAsync<readonly WorkspaceAnchor[], never>;
@@ -1,8 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveBindingBaseDir = resolveBindingBaseDir;
3
4
  exports.selectWorkspaceSource = selectWorkspaceSource;
4
5
  exports.resolveWorkspaceAnchors = resolveWorkspaceAnchors;
5
6
  const neverthrow_1 = require("neverthrow");
7
+ function resolveBindingBaseDir(workspacePath, resolvedRootUris) {
8
+ if (workspacePath !== undefined)
9
+ return workspacePath;
10
+ const primaryUri = resolvedRootUris[0];
11
+ if (primaryUri !== undefined) {
12
+ if (primaryUri.startsWith('file://')) {
13
+ return decodeURIComponent(primaryUri.replace(/^file:\/\//, ''));
14
+ }
15
+ }
16
+ return process.cwd();
17
+ }
6
18
  function selectWorkspaceSource(workspacePath, resolvedRootUris) {
7
19
  if (workspacePath !== undefined) {
8
20
  return { kind: 'explicit_path', path: workspacePath };
@@ -12,5 +12,8 @@ export { handleWorkflowList, handleWorkflowGet, handleWorkflowNext, handleWorkfl
12
12
  export type { WorkflowSummary, WorkflowListOutput, WorkflowGetOutput, WorkflowNextOutput, WorkflowValidateJsonOutput, WorkflowGetSchemaOutput, } from './handlers/workflow.js';
13
13
  export { handleCreateSession, handleUpdateSession, handleReadSession, handleOpenDashboard, } from './handlers/session.js';
14
14
  export type { CreateSessionOutput, UpdateSessionOutput, ReadSessionOutput, ReadSessionSchemaOutput, SchemaOverview, OpenDashboardOutput, } from './handlers/session.js';
15
- export { createToolContext, startServer, } from './server.js';
15
+ export { createToolContext, composeServer, } from './server.js';
16
+ export type { ComposedServer } from './server.js';
17
+ export { startStdioServer } from './transports/stdio-entry.js';
18
+ export { startHttpServer } from './transports/http-entry.js';
16
19
  export { zodToJsonSchema } from './zod-to-json-schema.js';
package/dist/mcp/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.zodToJsonSchema = exports.startServer = exports.createToolContext = exports.handleOpenDashboard = exports.handleReadSession = exports.handleUpdateSession = exports.handleCreateSession = exports.handleWorkflowGetSchema = exports.handleWorkflowValidateJson = exports.handleWorkflowNext = exports.handleWorkflowGet = exports.handleWorkflowList = exports.sessionTools = exports.openDashboardTool = exports.readSessionTool = exports.updateSessionTool = exports.createSessionTool = exports.OpenDashboardInput = exports.ReadSessionInput = exports.UpdateSessionInput = exports.CreateSessionInput = exports.WORKFLOW_TOOL_TITLES = exports.WORKFLOW_TOOL_ANNOTATIONS = exports.WorkflowGetSchemaInput = exports.WorkflowValidateJsonInput = exports.WorkflowNextInput = exports.WorkflowGetInput = exports.WorkflowListInput = exports.DESCRIPTIONS = exports.StaticToolDescriptionProvider = exports.ToolDescriptionProvider = exports.isWorkflowToolName = exports.isDescriptionMode = exports.WORKFLOW_TOOL_NAMES = exports.DESCRIPTION_MODES = exports.createToolFactory = exports.errRetryImmediate = exports.errRetryAfterMs = exports.errNotRetryable = exports.error = exports.success = void 0;
3
+ exports.zodToJsonSchema = exports.startHttpServer = exports.startStdioServer = exports.composeServer = exports.createToolContext = exports.handleOpenDashboard = exports.handleReadSession = exports.handleUpdateSession = exports.handleCreateSession = exports.handleWorkflowGetSchema = exports.handleWorkflowValidateJson = exports.handleWorkflowNext = exports.handleWorkflowGet = exports.handleWorkflowList = exports.sessionTools = exports.openDashboardTool = exports.readSessionTool = exports.updateSessionTool = exports.createSessionTool = exports.OpenDashboardInput = exports.ReadSessionInput = exports.UpdateSessionInput = exports.CreateSessionInput = exports.WORKFLOW_TOOL_TITLES = exports.WORKFLOW_TOOL_ANNOTATIONS = exports.WorkflowGetSchemaInput = exports.WorkflowValidateJsonInput = exports.WorkflowNextInput = exports.WorkflowGetInput = exports.WorkflowListInput = exports.DESCRIPTIONS = exports.StaticToolDescriptionProvider = exports.ToolDescriptionProvider = exports.isWorkflowToolName = exports.isDescriptionMode = exports.WORKFLOW_TOOL_NAMES = exports.DESCRIPTION_MODES = exports.createToolFactory = exports.errRetryImmediate = exports.errRetryAfterMs = exports.errNotRetryable = exports.error = exports.success = void 0;
4
4
  var types_js_1 = require("./types.js");
5
5
  Object.defineProperty(exports, "success", { enumerable: true, get: function () { return types_js_1.success; } });
6
6
  Object.defineProperty(exports, "error", { enumerable: true, get: function () { return types_js_1.error; } });
@@ -49,6 +49,10 @@ Object.defineProperty(exports, "handleReadSession", { enumerable: true, get: fun
49
49
  Object.defineProperty(exports, "handleOpenDashboard", { enumerable: true, get: function () { return session_js_1.handleOpenDashboard; } });
50
50
  var server_js_1 = require("./server.js");
51
51
  Object.defineProperty(exports, "createToolContext", { enumerable: true, get: function () { return server_js_1.createToolContext; } });
52
- Object.defineProperty(exports, "startServer", { enumerable: true, get: function () { return server_js_1.startServer; } });
52
+ Object.defineProperty(exports, "composeServer", { enumerable: true, get: function () { return server_js_1.composeServer; } });
53
+ var stdio_entry_js_1 = require("./transports/stdio-entry.js");
54
+ Object.defineProperty(exports, "startStdioServer", { enumerable: true, get: function () { return stdio_entry_js_1.startStdioServer; } });
55
+ var http_entry_js_1 = require("./transports/http-entry.js");
56
+ Object.defineProperty(exports, "startHttpServer", { enumerable: true, get: function () { return http_entry_js_1.startHttpServer; } });
53
57
  var zod_to_json_schema_js_1 = require("./zod-to-json-schema.js");
54
58
  Object.defineProperty(exports, "zodToJsonSchema", { enumerable: true, get: function () { return zod_to_json_schema_js_1.zodToJsonSchema; } });