@exaudeus/workrail 2.0.0 → 3.0.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 (72) hide show
  1. package/dist/application/services/compiler/template-registry.d.ts +4 -2
  2. package/dist/application/services/compiler/template-registry.js +97 -5
  3. package/dist/application/services/workflow-compiler.d.ts +5 -1
  4. package/dist/application/services/workflow-compiler.js +20 -7
  5. package/dist/application/use-cases/raw-workflow-file-scanner.d.ts +1 -1
  6. package/dist/application/use-cases/raw-workflow-file-scanner.js +2 -0
  7. package/dist/application/use-cases/validate-workflow-registry.js +2 -1
  8. package/dist/config/feature-flags.js +8 -0
  9. package/dist/di/container.js +10 -1
  10. package/dist/di/tokens.d.ts +1 -0
  11. package/dist/di/tokens.js +1 -0
  12. package/dist/engine/engine-factory.d.ts +3 -0
  13. package/dist/engine/engine-factory.js +295 -0
  14. package/dist/engine/index.d.ts +3 -0
  15. package/dist/engine/index.js +12 -0
  16. package/dist/engine/types.d.ts +130 -0
  17. package/dist/engine/types.js +18 -0
  18. package/dist/infrastructure/storage/file-workflow-storage.d.ts +1 -0
  19. package/dist/infrastructure/storage/file-workflow-storage.js +18 -3
  20. package/dist/infrastructure/storage/workflow-resolution.d.ts +9 -6
  21. package/dist/infrastructure/storage/workflow-resolution.js +14 -1
  22. package/dist/manifest.json +166 -94
  23. package/dist/mcp/handlers/shared/request-workflow-reader.d.ts +19 -0
  24. package/dist/mcp/handlers/shared/request-workflow-reader.js +50 -0
  25. package/dist/mcp/handlers/v2-checkpoint.d.ts +31 -1
  26. package/dist/mcp/handlers/v2-checkpoint.js +76 -64
  27. package/dist/mcp/handlers/v2-execution/continue-advance.d.ts +2 -0
  28. package/dist/mcp/handlers/v2-execution/continue-advance.js +5 -5
  29. package/dist/mcp/handlers/v2-execution/continue-rehydrate.d.ts +2 -0
  30. package/dist/mcp/handlers/v2-execution/continue-rehydrate.js +17 -22
  31. package/dist/mcp/handlers/v2-execution/index.d.ts +10 -17
  32. package/dist/mcp/handlers/v2-execution/index.js +44 -54
  33. package/dist/mcp/handlers/v2-execution/replay.d.ts +4 -15
  34. package/dist/mcp/handlers/v2-execution/replay.js +52 -128
  35. package/dist/mcp/handlers/v2-execution/start.d.ts +4 -3
  36. package/dist/mcp/handlers/v2-execution/start.js +32 -49
  37. package/dist/mcp/handlers/v2-token-ops.d.ts +45 -24
  38. package/dist/mcp/handlers/v2-token-ops.js +372 -32
  39. package/dist/mcp/handlers/v2-workflow.d.ts +1 -1
  40. package/dist/mcp/handlers/v2-workflow.js +25 -4
  41. package/dist/mcp/output-schemas.d.ts +104 -283
  42. package/dist/mcp/output-schemas.js +24 -22
  43. package/dist/mcp/server.js +8 -0
  44. package/dist/mcp/tool-descriptions.js +9 -2
  45. package/dist/mcp/types.d.ts +4 -0
  46. package/dist/mcp/v2/tools.d.ts +32 -53
  47. package/dist/mcp/v2/tools.js +27 -37
  48. package/dist/mcp/v2-response-formatter.js +12 -16
  49. package/dist/runtime/runtime-mode.d.ts +2 -0
  50. package/dist/v2/durable-core/domain/prompt-renderer.d.ts +1 -0
  51. package/dist/v2/durable-core/domain/prompt-renderer.js +5 -3
  52. package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +14 -14
  53. package/dist/v2/durable-core/schemas/session/events.d.ts +4 -4
  54. package/dist/v2/durable-core/schemas/session/validation-event.d.ts +2 -2
  55. package/dist/v2/durable-core/tokens/payloads.d.ts +32 -32
  56. package/dist/v2/durable-core/tokens/short-token.d.ts +38 -0
  57. package/dist/v2/durable-core/tokens/short-token.js +126 -0
  58. package/dist/v2/durable-core/tokens/token-patterns.d.ts +4 -0
  59. package/dist/v2/durable-core/tokens/token-patterns.js +9 -0
  60. package/dist/v2/infra/in-memory/token-alias-store/index.d.ts +11 -0
  61. package/dist/v2/infra/in-memory/token-alias-store/index.js +38 -0
  62. package/dist/v2/infra/local/data-dir/index.d.ts +1 -0
  63. package/dist/v2/infra/local/data-dir/index.js +3 -0
  64. package/dist/v2/infra/local/token-alias-store/index.d.ts +16 -0
  65. package/dist/v2/infra/local/token-alias-store/index.js +117 -0
  66. package/dist/v2/ports/data-dir.port.d.ts +1 -0
  67. package/dist/v2/ports/token-alias-store.port.d.ts +33 -0
  68. package/dist/v2/ports/token-alias-store.port.js +2 -0
  69. package/package.json +8 -1
  70. package/workflows/coding-task-workflow-agentic.lean.v2.json +224 -0
  71. package/workflows/routines/philosophy-alignment.json +12 -12
  72. package/workflows/routines/tension-driven-design.json +63 -0
@@ -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
  }
@@ -1,4 +1,4 @@
1
1
  import type { ToolContext, ToolResult } from '../types.js';
2
2
  import type { V2InspectWorkflowInput, V2ListWorkflowsInput } from '../v2/tools.js';
3
- export declare function handleV2ListWorkflows(_input: V2ListWorkflowsInput, ctx: ToolContext): Promise<ToolResult<unknown>>;
3
+ export declare function handleV2ListWorkflows(input: V2ListWorkflowsInput, ctx: ToolContext): Promise<ToolResult<unknown>>;
4
4
  export declare function handleV2InspectWorkflow(input: V2InspectWorkflowInput, ctx: ToolContext): Promise<ToolResult<unknown>>;
@@ -11,13 +11,24 @@ const v1_to_v2_shim_js_1 = require("../../v2/read-only/v1-to-v2-shim.js");
11
11
  const hashing_js_1 = require("../../v2/durable-core/canonical/hashing.js");
12
12
  const TIMEOUT_MS = 30000;
13
13
  const with_timeout_js_1 = require("./shared/with-timeout.js");
14
- async function handleV2ListWorkflows(_input, ctx) {
14
+ const request_workflow_reader_js_1 = require("./shared/request-workflow-reader.js");
15
+ async function handleV2ListWorkflows(input, ctx) {
15
16
  const guard = (0, types_js_1.requireV2Context)(ctx);
16
17
  if (!guard.ok)
17
18
  return guard.error;
18
19
  const { crypto, pinnedStore } = guard.ctx.v2;
19
- return neverthrow_1.ResultAsync.fromPromise((0, with_timeout_js_1.withTimeout)(ctx.workflowService.listWorkflowSummaries(), TIMEOUT_MS, 'list_workflows'), (err) => (0, error_mapper_js_1.mapUnknownErrorToToolError)(err))
20
- .andThen((summaries) => neverthrow_1.ResultAsync.combine(summaries.map((s) => neverthrow_1.ResultAsync.fromPromise(ctx.workflowService.getWorkflowById(s.id), (err) => (0, error_mapper_js_1.mapUnknownErrorToToolError)(err)).andThen((wf) => {
20
+ const workflowReader = (0, request_workflow_reader_js_1.hasRequestWorkspaceSignal)({
21
+ workspacePath: input.workspacePath,
22
+ resolvedRootUris: guard.ctx.v2.resolvedRootUris,
23
+ })
24
+ ? (0, request_workflow_reader_js_1.createWorkflowReaderForRequest)({
25
+ featureFlags: ctx.featureFlags,
26
+ workspacePath: input.workspacePath,
27
+ resolvedRootUris: guard.ctx.v2.resolvedRootUris,
28
+ })
29
+ : ctx.workflowService;
30
+ return neverthrow_1.ResultAsync.fromPromise((0, with_timeout_js_1.withTimeout)(workflowReader.listWorkflowSummaries(), TIMEOUT_MS, 'list_workflows'), (err) => (0, error_mapper_js_1.mapUnknownErrorToToolError)(err))
31
+ .andThen((summaries) => neverthrow_1.ResultAsync.combine(summaries.map((s) => neverthrow_1.ResultAsync.fromPromise(workflowReader.getWorkflowById(s.id), (err) => (0, error_mapper_js_1.mapUnknownErrorToToolError)(err)).andThen((wf) => {
21
32
  if (!wf) {
22
33
  return (0, neverthrow_1.okAsync)({
23
34
  workflowId: s.id,
@@ -79,7 +90,17 @@ async function handleV2InspectWorkflow(input, ctx) {
79
90
  if (!guard.ok)
80
91
  return guard.error;
81
92
  const { crypto, pinnedStore } = guard.ctx.v2;
82
- return neverthrow_1.ResultAsync.fromPromise((0, with_timeout_js_1.withTimeout)(ctx.workflowService.getWorkflowById(input.workflowId), TIMEOUT_MS, 'inspect_workflow'), (err) => (0, error_mapper_js_1.mapUnknownErrorToToolError)(err))
93
+ const workflowReader = (0, request_workflow_reader_js_1.hasRequestWorkspaceSignal)({
94
+ workspacePath: input.workspacePath,
95
+ resolvedRootUris: guard.ctx.v2.resolvedRootUris,
96
+ })
97
+ ? (0, request_workflow_reader_js_1.createWorkflowReaderForRequest)({
98
+ featureFlags: ctx.featureFlags,
99
+ workspacePath: input.workspacePath,
100
+ resolvedRootUris: guard.ctx.v2.resolvedRootUris,
101
+ })
102
+ : ctx.workflowService;
103
+ return neverthrow_1.ResultAsync.fromPromise((0, with_timeout_js_1.withTimeout)(workflowReader.getWorkflowById(input.workflowId), TIMEOUT_MS, 'inspect_workflow'), (err) => (0, error_mapper_js_1.mapUnknownErrorToToolError)(err))
83
104
  .andThen((workflow) => {
84
105
  if (!workflow) {
85
106
  return (0, neverthrow_1.errAsync)((0, types_js_1.errNotRetryable)('NOT_FOUND', `Workflow not found: ${input.workflowId}`));