@exaudeus/workrail 2.1.0 → 3.1.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 (61) hide show
  1. package/dist/application/services/compiler/resolve-templates.d.ts +5 -0
  2. package/dist/application/services/compiler/resolve-templates.js +35 -0
  3. package/dist/application/services/compiler/routine-loader.d.ts +11 -0
  4. package/dist/application/services/compiler/routine-loader.js +45 -0
  5. package/dist/application/services/compiler/template-registry.d.ts +4 -2
  6. package/dist/application/services/compiler/template-registry.js +105 -4
  7. package/dist/application/services/workflow-compiler.js +34 -3
  8. package/dist/di/container.js +10 -1
  9. package/dist/di/tokens.d.ts +1 -0
  10. package/dist/di/tokens.js +1 -0
  11. package/dist/engine/engine-factory.d.ts +3 -0
  12. package/dist/engine/engine-factory.js +295 -0
  13. package/dist/engine/index.d.ts +3 -0
  14. package/dist/engine/index.js +12 -0
  15. package/dist/engine/types.d.ts +130 -0
  16. package/dist/engine/types.js +18 -0
  17. package/dist/manifest.json +146 -74
  18. package/dist/mcp/handlers/v2-checkpoint.d.ts +31 -1
  19. package/dist/mcp/handlers/v2-checkpoint.js +76 -64
  20. package/dist/mcp/handlers/v2-execution/continue-advance.d.ts +2 -0
  21. package/dist/mcp/handlers/v2-execution/continue-advance.js +5 -5
  22. package/dist/mcp/handlers/v2-execution/continue-rehydrate.d.ts +2 -0
  23. package/dist/mcp/handlers/v2-execution/continue-rehydrate.js +17 -22
  24. package/dist/mcp/handlers/v2-execution/index.d.ts +10 -17
  25. package/dist/mcp/handlers/v2-execution/index.js +44 -54
  26. package/dist/mcp/handlers/v2-execution/replay.d.ts +4 -15
  27. package/dist/mcp/handlers/v2-execution/replay.js +52 -128
  28. package/dist/mcp/handlers/v2-execution/start.d.ts +3 -2
  29. package/dist/mcp/handlers/v2-execution/start.js +18 -46
  30. package/dist/mcp/handlers/v2-token-ops.d.ts +45 -24
  31. package/dist/mcp/handlers/v2-token-ops.js +372 -32
  32. package/dist/mcp/output-schemas.d.ts +104 -283
  33. package/dist/mcp/output-schemas.js +24 -22
  34. package/dist/mcp/server.js +8 -0
  35. package/dist/mcp/types.d.ts +4 -0
  36. package/dist/mcp/v2/tools.d.ts +22 -52
  37. package/dist/mcp/v2/tools.js +18 -32
  38. package/dist/mcp/v2-response-formatter.js +12 -16
  39. package/dist/runtime/runtime-mode.d.ts +2 -0
  40. package/dist/v2/durable-core/domain/prompt-renderer.d.ts +1 -0
  41. package/dist/v2/durable-core/domain/prompt-renderer.js +5 -3
  42. package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +14 -14
  43. package/dist/v2/durable-core/schemas/session/events.d.ts +4 -4
  44. package/dist/v2/durable-core/schemas/session/validation-event.d.ts +2 -2
  45. package/dist/v2/durable-core/tokens/payloads.d.ts +32 -32
  46. package/dist/v2/durable-core/tokens/short-token.d.ts +38 -0
  47. package/dist/v2/durable-core/tokens/short-token.js +126 -0
  48. package/dist/v2/durable-core/tokens/token-patterns.d.ts +4 -0
  49. package/dist/v2/durable-core/tokens/token-patterns.js +9 -0
  50. package/dist/v2/infra/in-memory/token-alias-store/index.d.ts +11 -0
  51. package/dist/v2/infra/in-memory/token-alias-store/index.js +38 -0
  52. package/dist/v2/infra/local/data-dir/index.d.ts +1 -0
  53. package/dist/v2/infra/local/data-dir/index.js +3 -0
  54. package/dist/v2/infra/local/token-alias-store/index.d.ts +16 -0
  55. package/dist/v2/infra/local/token-alias-store/index.js +117 -0
  56. package/dist/v2/ports/data-dir.port.d.ts +1 -0
  57. package/dist/v2/ports/token-alias-store.port.d.ts +33 -0
  58. package/dist/v2/ports/token-alias-store.port.js +2 -0
  59. package/package.json +8 -1
  60. package/workflows/coding-task-workflow-agentic.lean.v2.json +41 -3
  61. package/workflows/examples/routine-injection-example.json +28 -0
@@ -183,51 +183,22 @@ function buildInitialEvents(args) {
183
183
  return mutableEvents;
184
184
  }
185
185
  function mintStartTokens(args) {
186
- const { sessionId, runId, nodeId, attemptId, workflowHashRef, ports } = args;
187
- const statePayload = {
188
- tokenVersion: 1,
189
- tokenKind: 'state',
190
- sessionId,
191
- runId,
192
- nodeId,
193
- workflowHashRef,
186
+ const { sessionId, runId, nodeId, attemptId, workflowHashRef, ports, aliasStore, entropy } = args;
187
+ const entryBase = {
188
+ sessionId: String(sessionId),
189
+ runId: String(runId),
190
+ nodeId: String(nodeId),
191
+ attemptId: String(attemptId),
192
+ workflowHashRef: String(workflowHashRef),
194
193
  };
195
- const ackPayload = {
196
- tokenVersion: 1,
197
- tokenKind: 'ack',
198
- sessionId,
199
- runId,
200
- nodeId,
201
- attemptId,
202
- };
203
- const checkpointPayload = {
204
- tokenVersion: 1,
205
- tokenKind: 'checkpoint',
206
- sessionId,
207
- runId,
208
- nodeId,
209
- attemptId,
210
- };
211
- const stateTokenRes = (0, v2_token_ops_js_1.signTokenOrErr)({ payload: statePayload, ports });
212
- if (stateTokenRes.isErr()) {
213
- return (0, neverthrow_1.errAsync)({ kind: 'token_signing_failed', cause: stateTokenRes.error });
214
- }
215
- const ackTokenRes = (0, v2_token_ops_js_1.signTokenOrErr)({ payload: ackPayload, ports });
216
- if (ackTokenRes.isErr()) {
217
- return (0, neverthrow_1.errAsync)({ kind: 'token_signing_failed', cause: ackTokenRes.error });
218
- }
219
- const checkpointTokenRes = (0, v2_token_ops_js_1.signTokenOrErr)({ payload: checkpointPayload, ports });
220
- if (checkpointTokenRes.isErr()) {
221
- return (0, neverthrow_1.errAsync)({ kind: 'token_signing_failed', cause: checkpointTokenRes.error });
222
- }
223
- return (0, neverthrow_1.okAsync)({
224
- stateToken: stateTokenRes.value,
225
- ackToken: ackTokenRes.value,
226
- checkpointToken: checkpointTokenRes.value,
227
- });
194
+ return (0, v2_token_ops_js_1.mintContinueAndCheckpointTokens)({ entry: entryBase, ports, aliasStore, entropy })
195
+ .mapErr((failure) => ({
196
+ kind: 'token_signing_failed',
197
+ cause: failure,
198
+ }));
228
199
  }
229
200
  function executeStartWorkflow(input, ctx) {
230
- const { gate, sessionStore, snapshotStore, pinnedStore, crypto, tokenCodecPorts, idFactory, validationPipelineDeps } = ctx.v2;
201
+ const { gate, sessionStore, snapshotStore, pinnedStore, crypto, tokenCodecPorts, idFactory, validationPipelineDeps, tokenAliasStore, entropy } = ctx.v2;
231
202
  const workflowReader = (0, request_workflow_reader_js_1.hasRequestWorkspaceSignal)({
232
203
  workspacePath: input.workspacePath,
233
204
  resolvedRootUris: ctx.v2.resolvedRootUris,
@@ -315,6 +286,8 @@ function executeStartWorkflow(input, ctx) {
315
286
  attemptId,
316
287
  workflowHashRef: wfRefRes.value,
317
288
  ports: tokenCodecPorts,
289
+ aliasStore: tokenAliasStore,
290
+ entropy,
318
291
  }).andThen((tokens) => {
319
292
  const metaResult = (0, prompt_renderer_js_1.renderPendingPrompt)({
320
293
  workflow: pinnedWorkflow,
@@ -332,18 +305,17 @@ function executeStartWorkflow(input, ctx) {
332
305
  });
333
306
  }
334
307
  const meta = metaResult.value;
335
- const pending = { stepId: meta.stepId, title: meta.title, prompt: meta.prompt };
308
+ const pending = (0, output_schemas_js_1.toPendingStep)(meta);
336
309
  const preferences = v2_execution_helpers_js_1.defaultPreferences;
337
310
  const nextIntent = (0, v2_state_conversion_js_1.deriveNextIntent)({ rehydrateOnly: false, isComplete: false, pending: meta });
338
311
  return (0, neverthrow_1.okAsync)(output_schemas_js_1.V2StartWorkflowOutputSchema.parse({
339
- stateToken: tokens.stateToken,
340
- ackToken: tokens.ackToken,
312
+ continueToken: tokens.continueToken,
341
313
  checkpointToken: tokens.checkpointToken,
342
314
  isComplete: false,
343
315
  pending,
344
316
  preferences,
345
317
  nextIntent,
346
- nextCall: (0, index_js_2.buildNextCall)({ stateToken: tokens.stateToken, ackToken: tokens.ackToken, isComplete: false, pending }),
318
+ nextCall: (0, index_js_2.buildNextCall)({ continueToken: tokens.continueToken, isComplete: false, pending }),
347
319
  }));
348
320
  });
349
321
  });
@@ -1,38 +1,59 @@
1
+ import type { ResultAsync } from 'neverthrow';
1
2
  import type { Result } from 'neverthrow';
2
3
  import { type ParsedTokenV1Binary, type TokenDecodeErrorV2, type TokenVerifyErrorV2, type TokenSignErrorV2, type TokenPayloadV1, type AttemptId } from '../../v2/durable-core/tokens/index.js';
3
4
  import type { TokenCodecPorts } from '../../v2/durable-core/tokens/token-codec-ports.js';
4
5
  import type { Sha256PortV2 } from '../../v2/ports/sha256.port.js';
5
6
  import { type ToolFailure } from './v2-execution-helpers.js';
7
+ import type { TokenAliasStorePortV2, TokenAliasEntryV2 } from '../../v2/ports/token-alias-store.port.js';
8
+ import type { RandomEntropyPortV2 } from '../../v2/ports/random-entropy.port.js';
9
+ import type { StateTokenPayloadV1, AckTokenPayloadV1, CheckpointTokenPayloadV1 } from '../../v2/durable-core/tokens/payloads.js';
6
10
  export type StateTokenInput = ParsedTokenV1Binary & {
7
- readonly payload: import('../../v2/durable-core/tokens/payloads.js').StateTokenPayloadV1;
11
+ readonly payload: StateTokenPayloadV1;
8
12
  };
9
13
  export type AckTokenInput = ParsedTokenV1Binary & {
10
- readonly payload: import('../../v2/durable-core/tokens/payloads.js').AckTokenPayloadV1;
14
+ readonly payload: AckTokenPayloadV1;
11
15
  };
12
16
  export type CheckpointTokenInput = ParsedTokenV1Binary & {
13
- readonly payload: import('../../v2/durable-core/tokens/payloads.js').CheckpointTokenPayloadV1;
14
- };
15
- export declare function parseStateTokenOrFail(raw: string, ports: TokenCodecPorts): {
16
- ok: true;
17
- token: StateTokenInput;
18
- } | {
19
- ok: false;
20
- failure: ToolFailure;
21
- };
22
- export declare function parseAckTokenOrFail(raw: string, ports: TokenCodecPorts): {
23
- ok: true;
24
- token: AckTokenInput;
25
- } | {
26
- ok: false;
27
- failure: ToolFailure;
28
- };
29
- export declare function parseCheckpointTokenOrFail(raw: string, ports: TokenCodecPorts): {
30
- ok: true;
31
- token: CheckpointTokenInput;
32
- } | {
33
- ok: false;
34
- failure: ToolFailure;
17
+ readonly payload: CheckpointTokenPayloadV1;
35
18
  };
19
+ export interface ContinueTokenResolved {
20
+ readonly sessionId: string;
21
+ readonly runId: string;
22
+ readonly nodeId: string;
23
+ readonly attemptId: string;
24
+ readonly workflowHashRef: string;
25
+ }
26
+ export declare function parseStateTokenOrFail(raw: string, ports: TokenCodecPorts, aliasStore: TokenAliasStorePortV2): ResultAsync<StateTokenInput, ToolFailure>;
27
+ export declare function parseAckTokenOrFail(raw: string, ports: TokenCodecPorts, aliasStore: TokenAliasStorePortV2): ResultAsync<AckTokenInput, ToolFailure>;
28
+ export declare function parseCheckpointTokenOrFail(raw: string, ports: TokenCodecPorts, aliasStore: TokenAliasStorePortV2): ResultAsync<CheckpointTokenInput, ToolFailure>;
29
+ export declare function parseContinueTokenOrFail(raw: string, ports: TokenCodecPorts, aliasStore: TokenAliasStorePortV2): ResultAsync<ContinueTokenResolved, ToolFailure>;
30
+ export interface ContinueAndCheckpointTokens {
31
+ readonly continueToken: string;
32
+ readonly checkpointToken: string;
33
+ }
34
+ export declare function mintContinueAndCheckpointTokens(args: Omit<MintShortTokenTripleArgs, 'entry'> & {
35
+ readonly entry: Omit<TokenAliasEntryV2, 'nonceHex' | 'tokenKind'>;
36
+ }): ResultAsync<ContinueAndCheckpointTokens, ToolFailure>;
37
+ export interface ShortTokenTriple {
38
+ readonly stateToken: string;
39
+ readonly ackToken: string;
40
+ readonly checkpointToken: string;
41
+ }
42
+ export interface MintShortTokenTripleArgs {
43
+ readonly entry: Omit<TokenAliasEntryV2, 'nonceHex' | 'tokenKind'>;
44
+ readonly ports: TokenCodecPorts;
45
+ readonly aliasStore: TokenAliasStorePortV2;
46
+ readonly entropy: RandomEntropyPortV2;
47
+ }
48
+ export declare function mintShortTokenTriple(args: MintShortTokenTripleArgs): ResultAsync<ShortTokenTriple, ToolFailure>;
49
+ export interface MintSingleShortTokenArgs {
50
+ readonly kind: import('../../v2/durable-core/tokens/short-token.js').ShortTokenKind;
51
+ readonly entry: Omit<TokenAliasEntryV2, 'nonceHex' | 'tokenKind'>;
52
+ readonly ports: TokenCodecPorts;
53
+ readonly aliasStore: TokenAliasStorePortV2;
54
+ readonly entropy: RandomEntropyPortV2;
55
+ }
56
+ export declare function mintSingleShortToken(args: MintSingleShortTokenArgs): ResultAsync<string, ToolFailure>;
36
57
  export declare function newAttemptId(idFactory: {
37
58
  readonly mintAttemptId: () => AttemptId;
38
59
  }): AttemptId;
@@ -3,70 +3,410 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseStateTokenOrFail = parseStateTokenOrFail;
4
4
  exports.parseAckTokenOrFail = parseAckTokenOrFail;
5
5
  exports.parseCheckpointTokenOrFail = parseCheckpointTokenOrFail;
6
+ exports.parseContinueTokenOrFail = parseContinueTokenOrFail;
7
+ exports.mintContinueAndCheckpointTokens = mintContinueAndCheckpointTokens;
8
+ exports.mintShortTokenTriple = mintShortTokenTriple;
9
+ exports.mintSingleShortToken = mintSingleShortToken;
6
10
  exports.newAttemptId = newAttemptId;
7
11
  exports.attemptIdForNextNode = attemptIdForNextNode;
8
12
  exports.signTokenOrErr = signTokenOrErr;
9
13
  const neverthrow_1 = require("neverthrow");
14
+ const neverthrow_2 = require("neverthrow");
10
15
  const index_js_1 = require("../../v2/durable-core/tokens/index.js");
11
16
  const attempt_id_derivation_js_1 = require("../../v2/durable-core/ids/attempt-id-derivation.js");
12
17
  const types_js_1 = require("../types.js");
13
18
  const v2_execution_helpers_js_1 = require("./v2-execution-helpers.js");
14
- function parseStateTokenOrFail(raw, ports) {
19
+ const short_token_js_1 = require("../../v2/durable-core/tokens/short-token.js");
20
+ const index_js_2 = require("../../v2/durable-core/ids/index.js");
21
+ function resolveShortToken(raw, ports, aliasStore) {
22
+ const parsed = (0, short_token_js_1.parseShortToken)(raw, ports.base64url);
23
+ if (parsed.isErr()) {
24
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', `Short token format invalid: ${parsed.error.code}`, {
25
+ suggestion: 'Use the token returned by WorkRail (st_... / ak_... / ck_...).',
26
+ }));
27
+ }
28
+ const hmacResult = (0, short_token_js_1.verifyShortTokenHmac)(parsed.value, ports.keyring, ports.hmac, ports.base64url);
29
+ if (hmacResult.isErr()) {
30
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_BAD_SIGNATURE', 'Short token HMAC verification failed.', {
31
+ suggestion: 'Use the exact token returned by WorkRail — do not modify it.',
32
+ }));
33
+ }
34
+ const entry = aliasStore.lookup(parsed.value.nonceHex);
35
+ if (!entry) {
36
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', 'Short token not found in alias index (unknown nonce).', {
37
+ suggestion: 'Use the token returned by WorkRail in the current session.',
38
+ }));
39
+ }
40
+ let payload;
41
+ if (entry.tokenKind === 'state') {
42
+ if (!entry.workflowHashRef) {
43
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', 'Alias entry for state token is missing workflowHashRef.'));
44
+ }
45
+ const statePayload = {
46
+ tokenVersion: 1,
47
+ tokenKind: 'state',
48
+ sessionId: (0, index_js_2.asSessionId)(entry.sessionId),
49
+ runId: (0, index_js_2.asRunId)(entry.runId),
50
+ nodeId: (0, index_js_2.asNodeId)(entry.nodeId),
51
+ workflowHashRef: (0, index_js_2.asWorkflowHashRef)(entry.workflowHashRef),
52
+ };
53
+ payload = statePayload;
54
+ }
55
+ else if (entry.tokenKind === 'ack') {
56
+ if (!entry.attemptId) {
57
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', 'Alias entry for ack token is missing attemptId.'));
58
+ }
59
+ const ackPayload = {
60
+ tokenVersion: 1,
61
+ tokenKind: 'ack',
62
+ sessionId: (0, index_js_2.asSessionId)(entry.sessionId),
63
+ runId: (0, index_js_2.asRunId)(entry.runId),
64
+ nodeId: (0, index_js_2.asNodeId)(entry.nodeId),
65
+ attemptId: (0, index_js_2.asAttemptId)(entry.attemptId),
66
+ };
67
+ payload = ackPayload;
68
+ }
69
+ else {
70
+ if (!entry.attemptId) {
71
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', 'Alias entry for checkpoint token is missing attemptId.'));
72
+ }
73
+ const ckPayload = {
74
+ tokenVersion: 1,
75
+ tokenKind: 'checkpoint',
76
+ sessionId: (0, index_js_2.asSessionId)(entry.sessionId),
77
+ runId: (0, index_js_2.asRunId)(entry.runId),
78
+ nodeId: (0, index_js_2.asNodeId)(entry.nodeId),
79
+ attemptId: (0, index_js_2.asAttemptId)(entry.attemptId),
80
+ };
81
+ payload = ckPayload;
82
+ }
83
+ const synthetic = {
84
+ hrp: entry.tokenKind === 'state' ? 'st' : entry.tokenKind === 'ack' ? 'ack' : 'chk',
85
+ version: '1',
86
+ payloadBytes: new Uint8Array(66),
87
+ signatureBytes: new Uint8Array(32),
88
+ payload,
89
+ };
90
+ return (0, neverthrow_1.okAsync)(synthetic);
91
+ }
92
+ function parseStateTokenOrFail(raw, ports, aliasStore) {
93
+ if (raw.startsWith('st_')) {
94
+ return resolveShortToken(raw, ports, aliasStore).andThen((resolved) => {
95
+ if (resolved.payload.tokenKind !== 'state') {
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.',
98
+ }));
99
+ }
100
+ return (0, neverthrow_1.okAsync)(resolved);
101
+ });
102
+ }
15
103
  const parsedRes = (0, index_js_1.parseTokenV1Binary)(raw, ports);
16
104
  if (parsedRes.isErr()) {
17
- return { ok: false, failure: (0, v2_execution_helpers_js_1.mapTokenDecodeErrorToToolError)(parsedRes.error) };
105
+ return (0, neverthrow_1.errAsync)((0, v2_execution_helpers_js_1.mapTokenDecodeErrorToToolError)(parsedRes.error));
18
106
  }
19
107
  const verified = (0, index_js_1.verifyTokenSignatureV1Binary)(parsedRes.value, ports);
20
108
  if (verified.isErr()) {
21
- return { ok: false, failure: (0, v2_execution_helpers_js_1.mapTokenVerifyErrorToToolError)(verified.error) };
109
+ return (0, neverthrow_1.errAsync)((0, v2_execution_helpers_js_1.mapTokenVerifyErrorToToolError)(verified.error));
22
110
  }
23
111
  if (parsedRes.value.payload.tokenKind !== 'state') {
24
- return {
25
- ok: false,
26
- failure: (0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', 'Expected a state token (st1...).', {
27
- suggestion: 'Use the stateToken returned by WorkRail.',
28
- }),
29
- };
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.',
114
+ }));
30
115
  }
31
- return { ok: true, token: parsedRes.value };
116
+ return (0, neverthrow_1.okAsync)(parsedRes.value);
32
117
  }
33
- function parseAckTokenOrFail(raw, ports) {
118
+ function parseAckTokenOrFail(raw, ports, aliasStore) {
119
+ if (raw.startsWith('ak_')) {
120
+ return resolveShortToken(raw, ports, aliasStore).andThen((resolved) => {
121
+ if (resolved.payload.tokenKind !== 'ack') {
122
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', 'Expected an ack token (ak_... or ack1...).', {
123
+ suggestion: 'Use the ackToken returned by WorkRail.',
124
+ }));
125
+ }
126
+ return (0, neverthrow_1.okAsync)(resolved);
127
+ });
128
+ }
34
129
  const parsedRes = (0, index_js_1.parseTokenV1Binary)(raw, ports);
35
130
  if (parsedRes.isErr()) {
36
- return { ok: false, failure: (0, v2_execution_helpers_js_1.mapTokenDecodeErrorToToolError)(parsedRes.error) };
131
+ return (0, neverthrow_1.errAsync)((0, v2_execution_helpers_js_1.mapTokenDecodeErrorToToolError)(parsedRes.error));
37
132
  }
38
133
  const verified = (0, index_js_1.verifyTokenSignatureV1Binary)(parsedRes.value, ports);
39
134
  if (verified.isErr()) {
40
- return { ok: false, failure: (0, v2_execution_helpers_js_1.mapTokenVerifyErrorToToolError)(verified.error) };
135
+ return (0, neverthrow_1.errAsync)((0, v2_execution_helpers_js_1.mapTokenVerifyErrorToToolError)(verified.error));
41
136
  }
42
137
  if (parsedRes.value.payload.tokenKind !== 'ack') {
43
- return {
44
- ok: false,
45
- failure: (0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', 'Expected an ack token (ack1...).', {
46
- suggestion: 'Use the ackToken returned by WorkRail.',
47
- }),
48
- };
138
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', 'Expected an ack token (ack1...).', {
139
+ suggestion: 'Use the ackToken returned by WorkRail.',
140
+ }));
49
141
  }
50
- return { ok: true, token: parsedRes.value };
142
+ return (0, neverthrow_1.okAsync)(parsedRes.value);
51
143
  }
52
- function parseCheckpointTokenOrFail(raw, ports) {
144
+ function parseCheckpointTokenOrFail(raw, ports, aliasStore) {
145
+ if (raw.startsWith('ck_')) {
146
+ return resolveShortToken(raw, ports, aliasStore).andThen((resolved) => {
147
+ if (resolved.payload.tokenKind !== 'checkpoint') {
148
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', 'Expected a checkpoint token (ck_... or chk1...).', {
149
+ suggestion: 'Use the checkpointToken returned by WorkRail.',
150
+ }));
151
+ }
152
+ return (0, neverthrow_1.okAsync)(resolved);
153
+ });
154
+ }
53
155
  const parsedRes = (0, index_js_1.parseTokenV1Binary)(raw, ports);
54
156
  if (parsedRes.isErr()) {
55
- return { ok: false, failure: (0, v2_execution_helpers_js_1.mapTokenDecodeErrorToToolError)(parsedRes.error) };
157
+ return (0, neverthrow_1.errAsync)((0, v2_execution_helpers_js_1.mapTokenDecodeErrorToToolError)(parsedRes.error));
56
158
  }
57
159
  const verified = (0, index_js_1.verifyTokenSignatureV1Binary)(parsedRes.value, ports);
58
160
  if (verified.isErr()) {
59
- return { ok: false, failure: (0, v2_execution_helpers_js_1.mapTokenVerifyErrorToToolError)(verified.error) };
161
+ return (0, neverthrow_1.errAsync)((0, v2_execution_helpers_js_1.mapTokenVerifyErrorToToolError)(verified.error));
60
162
  }
61
163
  if (parsedRes.value.payload.tokenKind !== 'checkpoint') {
62
- return {
63
- ok: false,
64
- failure: (0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', 'Expected a checkpoint token (chk1...).', {
65
- suggestion: 'Use the checkpointToken returned by WorkRail.',
66
- }),
67
- };
164
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', 'Expected a checkpoint token (chk1...).', {
165
+ suggestion: 'Use the checkpointToken returned by WorkRail.',
166
+ }));
167
+ }
168
+ return (0, neverthrow_1.okAsync)(parsedRes.value);
169
+ }
170
+ function parseContinueTokenOrFail(raw, ports, aliasStore) {
171
+ if (!raw.startsWith('ct_')) {
172
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', 'Expected a continue token (ct_...).', {
173
+ suggestion: 'Use the continueToken returned by WorkRail.',
174
+ }));
175
+ }
176
+ const parsed = (0, short_token_js_1.parseShortToken)(raw, ports.base64url);
177
+ if (parsed.isErr()) {
178
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', `Continue token format invalid: ${parsed.error.code}`, {
179
+ suggestion: 'Use the continueToken returned by WorkRail.',
180
+ }));
181
+ }
182
+ const hmacResult = (0, short_token_js_1.verifyShortTokenHmac)(parsed.value, ports.keyring, ports.hmac, ports.base64url);
183
+ if (hmacResult.isErr()) {
184
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_BAD_SIGNATURE', 'Continue token HMAC verification failed.', {
185
+ suggestion: 'Use the exact continueToken returned by WorkRail -- do not modify it.',
186
+ }));
187
+ }
188
+ const entry = aliasStore.lookup(parsed.value.nonceHex);
189
+ if (!entry) {
190
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', 'Continue token not found in alias index (unknown nonce).', {
191
+ suggestion: 'Use the continueToken returned by WorkRail in the current session.',
192
+ }));
193
+ }
194
+ if (entry.tokenKind !== 'continue') {
195
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', 'Token alias is not a continue token.', {
196
+ suggestion: 'Use the continueToken returned by WorkRail.',
197
+ }));
198
+ }
199
+ if (!entry.attemptId || !entry.workflowHashRef) {
200
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('TOKEN_INVALID_FORMAT', 'Continue token alias entry is missing required fields.', {
201
+ suggestion: 'Use the continueToken returned by WorkRail.',
202
+ }));
203
+ }
204
+ return (0, neverthrow_1.okAsync)({
205
+ sessionId: entry.sessionId,
206
+ runId: entry.runId,
207
+ nodeId: entry.nodeId,
208
+ attemptId: entry.attemptId,
209
+ workflowHashRef: entry.workflowHashRef,
210
+ });
211
+ }
212
+ function mintContinueAndCheckpointTokens(args) {
213
+ const { entry, ports, aliasStore, entropy } = args;
214
+ const existingContinue = aliasStore.lookupByPosition('continue', entry.sessionId, entry.nodeId, entry.attemptId, entry.aliasSlot);
215
+ const existingCk = aliasStore.lookupByPosition('checkpoint', entry.sessionId, entry.nodeId, entry.attemptId, entry.aliasSlot);
216
+ if (existingContinue && existingCk) {
217
+ const replayContinue = reTokenFromNonceHex('continue', existingContinue.nonceHex, ports);
218
+ const replayCk = reTokenFromNonceHex('checkpoint', existingCk.nonceHex, ports);
219
+ if (replayContinue.isOk() && replayCk.isOk()) {
220
+ return (0, neverthrow_1.okAsync)({
221
+ continueToken: replayContinue.value,
222
+ checkpointToken: replayCk.value,
223
+ });
224
+ }
225
+ }
226
+ const continueNonce = entropy.generateBytes(short_token_js_1.SHORT_TOKEN_NONCE_BYTES);
227
+ const continueMinted = (0, short_token_js_1.mintShortToken)('continue', continueNonce, ports.keyring, ports.hmac, ports.base64url);
228
+ if (continueMinted.isErr()) {
229
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('INTERNAL_ERROR', `Token minting failed: ${continueMinted.error.code}`));
230
+ }
231
+ const continueNonceHex = bufToHex(continueNonce);
232
+ let ckTokenStr;
233
+ if (existingCk) {
234
+ const replayCk = reTokenFromNonceHex('checkpoint', existingCk.nonceHex, ports);
235
+ if (replayCk.isOk()) {
236
+ const continueEntry = {
237
+ nonceHex: continueNonceHex, tokenKind: 'continue', aliasSlot: entry.aliasSlot,
238
+ sessionId: entry.sessionId, runId: entry.runId, nodeId: entry.nodeId,
239
+ attemptId: entry.attemptId, workflowHashRef: entry.workflowHashRef,
240
+ };
241
+ return aliasStore.register(continueEntry)
242
+ .map(() => ({ continueToken: continueMinted.value, checkpointToken: replayCk.value }))
243
+ .mapErr((regErr) => (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', `Alias registration failed: ${regErr.code}`));
244
+ }
245
+ const ckNonce = entropy.generateBytes(short_token_js_1.SHORT_TOKEN_NONCE_BYTES);
246
+ const ckMinted = (0, short_token_js_1.mintShortToken)('checkpoint', ckNonce, ports.keyring, ports.hmac, ports.base64url);
247
+ if (ckMinted.isErr())
248
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('INTERNAL_ERROR', `Token minting failed: ${ckMinted.error.code}`));
249
+ ckTokenStr = ckMinted.value;
250
+ const ckEntry = { nonceHex: bufToHex(ckNonce), tokenKind: 'checkpoint', aliasSlot: entry.aliasSlot, sessionId: entry.sessionId, runId: entry.runId, nodeId: entry.nodeId, attemptId: entry.attemptId };
251
+ return aliasStore.register({ nonceHex: continueNonceHex, tokenKind: 'continue', aliasSlot: entry.aliasSlot, sessionId: entry.sessionId, runId: entry.runId, nodeId: entry.nodeId, attemptId: entry.attemptId, workflowHashRef: entry.workflowHashRef })
252
+ .andThen(() => aliasStore.register(ckEntry))
253
+ .map(() => ({ continueToken: continueMinted.value, checkpointToken: ckTokenStr }))
254
+ .mapErr((regErr) => (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', `Alias registration failed: ${regErr.code}`));
255
+ }
256
+ else {
257
+ const ckNonce = entropy.generateBytes(short_token_js_1.SHORT_TOKEN_NONCE_BYTES);
258
+ const ckMinted = (0, short_token_js_1.mintShortToken)('checkpoint', ckNonce, ports.keyring, ports.hmac, ports.base64url);
259
+ if (ckMinted.isErr())
260
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('INTERNAL_ERROR', `Token minting failed: ${ckMinted.error.code}`));
261
+ ckTokenStr = ckMinted.value;
262
+ const ckEntry = { nonceHex: bufToHex(ckNonce), tokenKind: 'checkpoint', aliasSlot: entry.aliasSlot, sessionId: entry.sessionId, runId: entry.runId, nodeId: entry.nodeId, attemptId: entry.attemptId };
263
+ return aliasStore.register({ nonceHex: continueNonceHex, tokenKind: 'continue', aliasSlot: entry.aliasSlot, sessionId: entry.sessionId, runId: entry.runId, nodeId: entry.nodeId, attemptId: entry.attemptId, workflowHashRef: entry.workflowHashRef })
264
+ .andThen(() => aliasStore.register(ckEntry))
265
+ .map(() => ({ continueToken: continueMinted.value, checkpointToken: ckTokenStr }))
266
+ .mapErr((regErr) => (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', `Alias registration failed: ${regErr.code}`));
267
+ }
268
+ }
269
+ function reTokenFromNonceHex(kind, nonceHex, ports) {
270
+ const nonceBytes = hexToBuf(nonceHex);
271
+ if (!nonceBytes) {
272
+ return (0, neverthrow_2.err)((0, types_js_1.errNotRetryable)('INTERNAL_ERROR', `Invalid stored nonce hex: ${nonceHex}`));
273
+ }
274
+ const result = (0, short_token_js_1.mintShortToken)(kind, nonceBytes, ports.keyring, ports.hmac, ports.base64url);
275
+ if (result.isErr()) {
276
+ return (0, neverthrow_2.err)((0, types_js_1.errNotRetryable)('INTERNAL_ERROR', `Failed to reconstruct token from nonce: ${result.error.code}`));
277
+ }
278
+ return (0, neverthrow_2.ok)(result.value);
279
+ }
280
+ function mintShortTokenTriple(args) {
281
+ const { entry, ports, aliasStore, entropy } = args;
282
+ const existingState = aliasStore.lookupByPosition('state', entry.sessionId, entry.nodeId, undefined, entry.aliasSlot);
283
+ const existingAck = aliasStore.lookupByPosition('ack', entry.sessionId, entry.nodeId, entry.attemptId, entry.aliasSlot);
284
+ const existingCk = aliasStore.lookupByPosition('checkpoint', entry.sessionId, entry.nodeId, entry.attemptId, entry.aliasSlot);
285
+ if (existingState && existingAck && existingCk) {
286
+ const replayState = reTokenFromNonceHex('state', existingState.nonceHex, ports);
287
+ const replayAck = reTokenFromNonceHex('ack', existingAck.nonceHex, ports);
288
+ const replayCk = reTokenFromNonceHex('checkpoint', existingCk.nonceHex, ports);
289
+ if (replayState.isOk() && replayAck.isOk() && replayCk.isOk()) {
290
+ return (0, neverthrow_1.okAsync)({
291
+ stateToken: replayState.value,
292
+ ackToken: replayAck.value,
293
+ checkpointToken: replayCk.value,
294
+ });
295
+ }
296
+ }
297
+ const stateNonce = entropy.generateBytes(short_token_js_1.SHORT_TOKEN_NONCE_BYTES);
298
+ const ackNonce = entropy.generateBytes(short_token_js_1.SHORT_TOKEN_NONCE_BYTES);
299
+ const ckNonce = entropy.generateBytes(short_token_js_1.SHORT_TOKEN_NONCE_BYTES);
300
+ const stateMinted = (0, short_token_js_1.mintShortToken)('state', stateNonce, ports.keyring, ports.hmac, ports.base64url);
301
+ const ackMinted = (0, short_token_js_1.mintShortToken)('ack', ackNonce, ports.keyring, ports.hmac, ports.base64url);
302
+ const ckMinted = (0, short_token_js_1.mintShortToken)('checkpoint', ckNonce, ports.keyring, ports.hmac, ports.base64url);
303
+ if (stateMinted.isErr() || ackMinted.isErr() || ckMinted.isErr()) {
304
+ const msg = stateMinted.isErr()
305
+ ? stateMinted.error.code
306
+ : ackMinted.isErr()
307
+ ? ackMinted.error.code
308
+ : ckMinted.isErr()
309
+ ? ckMinted.error.code
310
+ : 'UNKNOWN';
311
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('INTERNAL_ERROR', `Short token minting failed: ${msg}`));
312
+ }
313
+ const stateTokenStr = stateMinted.value;
314
+ const ackTokenStr = ackMinted.value;
315
+ const ckTokenStr = ckMinted.value;
316
+ const stateNonceHex = bufToHex(stateNonce);
317
+ const ackNonceHex = bufToHex(ackNonce);
318
+ const ckNonceHex = bufToHex(ckNonce);
319
+ const stateEntry = {
320
+ nonceHex: stateNonceHex,
321
+ tokenKind: 'state',
322
+ aliasSlot: entry.aliasSlot,
323
+ sessionId: entry.sessionId,
324
+ runId: entry.runId,
325
+ nodeId: entry.nodeId,
326
+ workflowHashRef: entry.workflowHashRef,
327
+ };
328
+ const ackEntry = {
329
+ nonceHex: ackNonceHex,
330
+ tokenKind: 'ack',
331
+ aliasSlot: entry.aliasSlot,
332
+ sessionId: entry.sessionId,
333
+ runId: entry.runId,
334
+ nodeId: entry.nodeId,
335
+ attemptId: entry.attemptId,
336
+ };
337
+ const ckEntry = {
338
+ nonceHex: ckNonceHex,
339
+ tokenKind: 'checkpoint',
340
+ aliasSlot: entry.aliasSlot,
341
+ sessionId: entry.sessionId,
342
+ runId: entry.runId,
343
+ nodeId: entry.nodeId,
344
+ attemptId: entry.attemptId,
345
+ };
346
+ return aliasStore.register(stateEntry)
347
+ .andThen(() => aliasStore.register(ackEntry))
348
+ .andThen(() => aliasStore.register(ckEntry))
349
+ .map(() => ({
350
+ stateToken: stateTokenStr,
351
+ ackToken: ackTokenStr,
352
+ checkpointToken: ckTokenStr,
353
+ }))
354
+ .mapErr((regErr) => {
355
+ const detail = regErr.code === 'ALIAS_DUPLICATE_NONCE'
356
+ ? `duplicate nonce: ${regErr.nonceHex}`
357
+ : regErr.message;
358
+ return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', `Token alias registration failed: ${detail}`);
359
+ });
360
+ }
361
+ function mintSingleShortToken(args) {
362
+ const { kind, entry, ports, aliasStore, entropy } = args;
363
+ const lookupAttemptId = kind === 'state' ? undefined : entry.attemptId;
364
+ const existing = aliasStore.lookupByPosition(kind, entry.sessionId, entry.nodeId, lookupAttemptId, entry.aliasSlot);
365
+ if (existing) {
366
+ const rebuilt = reTokenFromNonceHex(kind, existing.nonceHex, ports);
367
+ if (rebuilt.isOk())
368
+ return (0, neverthrow_1.okAsync)(rebuilt.value);
369
+ }
370
+ const nonce = entropy.generateBytes(short_token_js_1.SHORT_TOKEN_NONCE_BYTES);
371
+ const minted = (0, short_token_js_1.mintShortToken)(kind, nonce, ports.keyring, ports.hmac, ports.base64url);
372
+ if (minted.isErr()) {
373
+ return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('INTERNAL_ERROR', `Short token minting failed: ${minted.error.code}`));
374
+ }
375
+ const tokenStr = minted.value;
376
+ const nonceHex = bufToHex(nonce);
377
+ const aliasEntry = {
378
+ nonceHex,
379
+ tokenKind: kind,
380
+ aliasSlot: entry.aliasSlot,
381
+ sessionId: entry.sessionId,
382
+ runId: entry.runId,
383
+ nodeId: entry.nodeId,
384
+ attemptId: entry.attemptId,
385
+ workflowHashRef: entry.workflowHashRef,
386
+ };
387
+ return aliasStore.register(aliasEntry)
388
+ .map(() => tokenStr)
389
+ .mapErr((regErr) => {
390
+ const detail = regErr.code === 'ALIAS_DUPLICATE_NONCE'
391
+ ? `duplicate nonce: ${regErr.nonceHex}`
392
+ : regErr.message;
393
+ return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', `Token alias registration failed: ${detail}`);
394
+ });
395
+ }
396
+ function bufToHex(bytes) {
397
+ return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
398
+ }
399
+ function hexToBuf(hex) {
400
+ if (hex.length % 2 !== 0)
401
+ return null;
402
+ const bytes = new Uint8Array(hex.length / 2);
403
+ for (let i = 0; i < bytes.length; i++) {
404
+ const byte = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
405
+ if (isNaN(byte))
406
+ return null;
407
+ bytes[i] = byte;
68
408
  }
69
- return { ok: true, token: parsedRes.value };
409
+ return bytes;
70
410
  }
71
411
  function newAttemptId(idFactory) {
72
412
  return idFactory.mintAttemptId();
@@ -77,6 +417,6 @@ function attemptIdForNextNode(parentAttemptId, sha256) {
77
417
  function signTokenOrErr(args) {
78
418
  const token = (0, index_js_1.signTokenV1Binary)(args.payload, args.ports);
79
419
  if (token.isErr())
80
- return (0, neverthrow_1.err)(token.error);
81
- return (0, neverthrow_1.ok)(token.value);
420
+ return (0, neverthrow_2.err)(token.error);
421
+ return (0, neverthrow_2.ok)(token.value);
82
422
  }