@exaudeus/workrail 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/di/container.js +7 -0
- package/dist/di/tokens.d.ts +1 -0
- package/dist/di/tokens.js +1 -0
- package/dist/manifest.json +38 -14
- package/dist/mcp/handlers/v2-execution.js +40 -23
- package/dist/mcp/server.js +4 -0
- package/dist/mcp/types.d.ts +4 -0
- package/dist/v2/durable-core/encoding/base32-lower.d.ts +4 -0
- package/dist/v2/durable-core/encoding/base32-lower.js +30 -0
- package/dist/v2/durable-core/ids/attempt-id-derivation.d.ts +3 -0
- package/dist/v2/durable-core/ids/attempt-id-derivation.js +32 -0
- package/dist/v2/durable-core/tokens/payloads.js +5 -4
- package/dist/v2/infra/local/id-factory/index.d.ts +11 -0
- package/dist/v2/infra/local/id-factory/index.js +32 -0
- package/package.json +1 -1
package/dist/di/container.js
CHANGED
|
@@ -181,6 +181,7 @@ async function registerV2Services() {
|
|
|
181
181
|
const { NodeBase64UrlV2 } = await Promise.resolve().then(() => __importStar(require('../v2/infra/local/base64url/index.js')));
|
|
182
182
|
const { NodeRandomEntropyV2 } = await Promise.resolve().then(() => __importStar(require('../v2/infra/local/random-entropy/index.js')));
|
|
183
183
|
const { NodeTimeClockV2 } = await Promise.resolve().then(() => __importStar(require('../v2/infra/local/time-clock/index.js')));
|
|
184
|
+
const { IdFactoryV2 } = await Promise.resolve().then(() => __importStar(require('../v2/infra/local/id-factory/index.js')));
|
|
184
185
|
tsyringe_1.container.register(tokens_js_1.DI.V2.DataDir, {
|
|
185
186
|
useFactory: (0, tsyringe_1.instanceCachingFactory)(() => new LocalDataDirV2(process.env)),
|
|
186
187
|
});
|
|
@@ -205,6 +206,12 @@ async function registerV2Services() {
|
|
|
205
206
|
tsyringe_1.container.register(tokens_js_1.DI.V2.TimeClock, {
|
|
206
207
|
useFactory: (0, tsyringe_1.instanceCachingFactory)(() => new NodeTimeClockV2()),
|
|
207
208
|
});
|
|
209
|
+
tsyringe_1.container.register(tokens_js_1.DI.V2.IdFactory, {
|
|
210
|
+
useFactory: (0, tsyringe_1.instanceCachingFactory)((c) => {
|
|
211
|
+
const entropy = c.resolve(tokens_js_1.DI.V2.RandomEntropy);
|
|
212
|
+
return new IdFactoryV2(entropy);
|
|
213
|
+
}),
|
|
214
|
+
});
|
|
208
215
|
const { LocalKeyringV2 } = await Promise.resolve().then(() => __importStar(require('../v2/infra/local/keyring/index.js')));
|
|
209
216
|
const { LocalSessionEventLogStoreV2 } = await Promise.resolve().then(() => __importStar(require('../v2/infra/local/session-store/index.js')));
|
|
210
217
|
const { LocalSnapshotStoreV2 } = await Promise.resolve().then(() => __importStar(require('../v2/infra/local/snapshot-store/index.js')));
|
package/dist/di/tokens.d.ts
CHANGED
package/dist/di/tokens.js
CHANGED
|
@@ -33,6 +33,7 @@ exports.DI = {
|
|
|
33
33
|
Base64Url: Symbol('V2.Base64Url'),
|
|
34
34
|
RandomEntropy: Symbol('V2.RandomEntropy'),
|
|
35
35
|
TimeClock: Symbol('V2.TimeClock'),
|
|
36
|
+
IdFactory: Symbol('V2.IdFactory'),
|
|
36
37
|
Keyring: Symbol('V2.Keyring'),
|
|
37
38
|
SessionStore: Symbol('V2.SessionStore'),
|
|
38
39
|
SnapshotStore: Symbol('V2.SnapshotStore'),
|
package/dist/manifest.json
CHANGED
|
@@ -254,16 +254,16 @@
|
|
|
254
254
|
"bytes": 565
|
|
255
255
|
},
|
|
256
256
|
"di/container.js": {
|
|
257
|
-
"sha256": "
|
|
258
|
-
"bytes":
|
|
257
|
+
"sha256": "200c41528c64e4e8cf0e04046bfd254cdbe0900c157be2dfd8c302a4a096d193",
|
|
258
|
+
"bytes": 18890
|
|
259
259
|
},
|
|
260
260
|
"di/tokens.d.ts": {
|
|
261
|
-
"sha256": "
|
|
262
|
-
"bytes":
|
|
261
|
+
"sha256": "3b9e46e178107ad65575350da5d99c238e7a4389d3537e67ff516a04df1191fe",
|
|
262
|
+
"bytes": 1882
|
|
263
263
|
},
|
|
264
264
|
"di/tokens.js": {
|
|
265
|
-
"sha256": "
|
|
266
|
-
"bytes":
|
|
265
|
+
"sha256": "aa90a1af7eba9941663beeeb13a25e2f3ba877ba37cb786bac46b468cc840f1b",
|
|
266
|
+
"bytes": 2327
|
|
267
267
|
},
|
|
268
268
|
"domain/execution/error.d.ts": {
|
|
269
269
|
"sha256": "2eac85c42ec399a23724f868641eeadd0d196b4d324ee4caaff82a6b46155bd9",
|
|
@@ -534,8 +534,8 @@
|
|
|
534
534
|
"bytes": 399
|
|
535
535
|
},
|
|
536
536
|
"mcp/handlers/v2-execution.js": {
|
|
537
|
-
"sha256": "
|
|
538
|
-
"bytes":
|
|
537
|
+
"sha256": "4f3f7d9009007a6795e2dfe998165722f660354323f7e856b26f1a7f62a136be",
|
|
538
|
+
"bytes": 53400
|
|
539
539
|
},
|
|
540
540
|
"mcp/handlers/v2-workflow.d.ts": {
|
|
541
541
|
"sha256": "9fbd4d44854e2060c54982b21e72c608970bb2bd107bb15a8388b26c6b492e55",
|
|
@@ -574,8 +574,8 @@
|
|
|
574
574
|
"bytes": 168
|
|
575
575
|
},
|
|
576
576
|
"mcp/server.js": {
|
|
577
|
-
"sha256": "
|
|
578
|
-
"bytes":
|
|
577
|
+
"sha256": "f6bc4b1f3416d03add7b715a5bdae7955a877eae8008c0d2f8b8490dd8ae5708",
|
|
578
|
+
"bytes": 14097
|
|
579
579
|
},
|
|
580
580
|
"mcp/tool-description-provider.d.ts": {
|
|
581
581
|
"sha256": "1d46abc3112e11b68e57197e846f5708293ec9b2281fa71a9124ee2aad71e41b",
|
|
@@ -610,8 +610,8 @@
|
|
|
610
610
|
"bytes": 8020
|
|
611
611
|
},
|
|
612
612
|
"mcp/types.d.ts": {
|
|
613
|
-
"sha256": "
|
|
614
|
-
"bytes":
|
|
613
|
+
"sha256": "3b7d7d7d30d65cd22b47bc9d559820b3f51984476fce11d4f3b6d820e2ce1eb8",
|
|
614
|
+
"bytes": 3683
|
|
615
615
|
},
|
|
616
616
|
"mcp/types.js": {
|
|
617
617
|
"sha256": "0c12576fd0053115ff096fe26b38f77f1e830b7ec4781aaf94564827c4c9e81a",
|
|
@@ -993,6 +993,22 @@
|
|
|
993
993
|
"sha256": "ae16a0df03c3dec30e9ffca0066b6148568966f6660a3c660f82853e077a0cbd",
|
|
994
994
|
"bytes": 817
|
|
995
995
|
},
|
|
996
|
+
"v2/durable-core/encoding/base32-lower.d.ts": {
|
|
997
|
+
"sha256": "849ef1984db20984f1fce7f40b15d3680c888e01411932d30af6fae4d2132a67",
|
|
998
|
+
"bytes": 175
|
|
999
|
+
},
|
|
1000
|
+
"v2/durable-core/encoding/base32-lower.js": {
|
|
1001
|
+
"sha256": "9065da38936496a34c2808388b5fb68d8aaac6bd3f0f05de184abc101e07c419",
|
|
1002
|
+
"bytes": 934
|
|
1003
|
+
},
|
|
1004
|
+
"v2/durable-core/ids/attempt-id-derivation.d.ts": {
|
|
1005
|
+
"sha256": "baee295f114d8d4a74e9fa529e7c72d458a7c7244f50fad9ebbaea06c57dfe92",
|
|
1006
|
+
"bytes": 207
|
|
1007
|
+
},
|
|
1008
|
+
"v2/durable-core/ids/attempt-id-derivation.js": {
|
|
1009
|
+
"sha256": "c13da44f23890d85edfb64a471f4f4817e973a63b41287d79144a3c9c6a5dcea",
|
|
1010
|
+
"bytes": 1309
|
|
1011
|
+
},
|
|
996
1012
|
"v2/durable-core/ids/index.d.ts": {
|
|
997
1013
|
"sha256": "5525efc423ad30635996907f7560f53559e49e33a64411a684370ebd1ae56410",
|
|
998
1014
|
"bytes": 1792
|
|
@@ -1134,8 +1150,8 @@
|
|
|
1134
1150
|
"bytes": 6756
|
|
1135
1151
|
},
|
|
1136
1152
|
"v2/durable-core/tokens/payloads.js": {
|
|
1137
|
-
"sha256": "
|
|
1138
|
-
"bytes":
|
|
1153
|
+
"sha256": "24978999201e0413cb193e1fee2b9977335ecaa9e2170b901358c9119fac6c3a",
|
|
1154
|
+
"bytes": 2479
|
|
1139
1155
|
},
|
|
1140
1156
|
"v2/durable-core/tokens/token-codec.d.ts": {
|
|
1141
1157
|
"sha256": "44bd65c6102b3aa5fcd82d2854f5466263a20c0b9cbd31aa25f169dfeed8e045",
|
|
@@ -1193,6 +1209,14 @@
|
|
|
1193
1209
|
"sha256": "11917c1d29f34efcd7139f5573067ad20a4093a1c5190e6069ccdc25acf53f24",
|
|
1194
1210
|
"bytes": 578
|
|
1195
1211
|
},
|
|
1212
|
+
"v2/infra/local/id-factory/index.d.ts": {
|
|
1213
|
+
"sha256": "ffcbdcce6a9c6a93c2703e0d844f84fef59e6ef8a3f657d50750e885b88e879b",
|
|
1214
|
+
"bytes": 432
|
|
1215
|
+
},
|
|
1216
|
+
"v2/infra/local/id-factory/index.js": {
|
|
1217
|
+
"sha256": "bd7d8cde4fb63b299f11ff51721c9b468c887856d581e95867bbbee6547642e4",
|
|
1218
|
+
"bytes": 1044
|
|
1219
|
+
},
|
|
1196
1220
|
"v2/infra/local/keyring/index.d.ts": {
|
|
1197
1221
|
"sha256": "e8698dab64327f994bf78e1a6c30131062d8418847417610e6b071ce7e873763",
|
|
1198
1222
|
"bytes": 932
|
|
@@ -36,7 +36,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.handleV2StartWorkflow = handleV2StartWorkflow;
|
|
37
37
|
exports.handleV2ContinueWorkflow = handleV2ContinueWorkflow;
|
|
38
38
|
const os = __importStar(require("os"));
|
|
39
|
-
const crypto_1 = require("crypto");
|
|
40
39
|
const types_js_1 = require("../types.js");
|
|
41
40
|
const output_schemas_js_1 = require("../output-schemas.js");
|
|
42
41
|
const snapshot_state_js_1 = require("../../v2/durable-core/projections/snapshot-state.js");
|
|
@@ -45,6 +44,7 @@ const index_js_1 = require("../../v2/durable-core/tokens/index.js");
|
|
|
45
44
|
const index_js_2 = require("../../v2/durable-core/tokens/index.js");
|
|
46
45
|
const workflow_js_1 = require("../../types/workflow.js");
|
|
47
46
|
const index_js_3 = require("../../v2/durable-core/ids/index.js");
|
|
47
|
+
const attempt_id_derivation_js_1 = require("../../v2/durable-core/ids/attempt-id-derivation.js");
|
|
48
48
|
const neverthrow_1 = require("neverthrow");
|
|
49
49
|
const v1_to_v2_shim_js_1 = require("../../v2/read-only/v1-to-v2-shim.js");
|
|
50
50
|
const hashing_js_1 = require("../../v2/durable-core/canonical/hashing.js");
|
|
@@ -238,7 +238,7 @@ function mapInternalErrorToToolError(e) {
|
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
function replayFromRecordedAdvance(args) {
|
|
241
|
-
const { recordedEvent, truth, sessionId, runId, nodeId, workflowHash, attemptId, inputStateToken, inputAckToken, pinnedWorkflow, snapshotStore, keyring, hmac, base64url, } = args;
|
|
241
|
+
const { recordedEvent, truth, sessionId, runId, nodeId, workflowHash, attemptId, inputStateToken, inputAckToken, pinnedWorkflow, snapshotStore, keyring, sha256, hmac, base64url, } = args;
|
|
242
242
|
const checkpointTokenRes = signTokenOrErr({
|
|
243
243
|
unsignedPrefix: 'chk.v1.',
|
|
244
244
|
payload: { tokenVersion: 1, tokenKind: 'checkpoint', sessionId, runId, nodeId, attemptId },
|
|
@@ -295,7 +295,7 @@ function replayFromRecordedAdvance(args) {
|
|
|
295
295
|
}
|
|
296
296
|
const pending = (0, snapshot_state_js_1.derivePendingStep)(snap.enginePayload.engineState);
|
|
297
297
|
const isComplete = (0, snapshot_state_js_1.deriveIsComplete)(snap.enginePayload.engineState);
|
|
298
|
-
const nextAttemptId = attemptIdForNextNode(attemptId);
|
|
298
|
+
const nextAttemptId = attemptIdForNextNode(attemptId, sha256);
|
|
299
299
|
const nextAckTokenRes = signTokenOrErr({
|
|
300
300
|
unsignedPrefix: 'ack.v1.',
|
|
301
301
|
payload: { tokenVersion: 1, tokenKind: 'ack', sessionId, runId, nodeId: toNodeIdBranded, attemptId: nextAttemptId },
|
|
@@ -338,7 +338,7 @@ function replayFromRecordedAdvance(args) {
|
|
|
338
338
|
});
|
|
339
339
|
}
|
|
340
340
|
function advanceAndRecord(args) {
|
|
341
|
-
const { truth, sessionId, runId, nodeId, attemptId, workflowHash, dedupeKey, inputContext, inputOutput, lock, pinnedWorkflow, snapshotStore, sessionStore } = args;
|
|
341
|
+
const { truth, sessionId, runId, nodeId, attemptId, workflowHash, dedupeKey, inputContext, inputOutput, lock, pinnedWorkflow, snapshotStore, sessionStore, idFactory } = args;
|
|
342
342
|
const hasRun = truth.events.some((e) => e.kind === 'run_started' && e.scope?.runId === String(runId));
|
|
343
343
|
const hasNode = truth.events.some((e) => e.kind === 'node_created' && e.scope?.runId === String(runId) && e.scope?.nodeId === String(nodeId));
|
|
344
344
|
if (!hasRun || !hasNode) {
|
|
@@ -385,11 +385,11 @@ function advanceAndRecord(args) {
|
|
|
385
385
|
enginePayload: { v: 1, engineState: newEngineState },
|
|
386
386
|
};
|
|
387
387
|
return snapshotStore.putExecutionSnapshotV1(snapshotFile).andThen((newSnapshotRef) => {
|
|
388
|
-
const toNodeId =
|
|
388
|
+
const toNodeId = String(idFactory.mintNodeId());
|
|
389
389
|
const nextEventIndex = truth.events.length === 0 ? 0 : truth.events[truth.events.length - 1].eventIndex + 1;
|
|
390
|
-
const evtAdvanceRecorded =
|
|
391
|
-
const evtNodeCreated =
|
|
392
|
-
const evtEdgeCreated =
|
|
390
|
+
const evtAdvanceRecorded = idFactory.mintEventId();
|
|
391
|
+
const evtNodeCreated = idFactory.mintEventId();
|
|
392
|
+
const evtEdgeCreated = idFactory.mintEventId();
|
|
393
393
|
const hasChildren = truth.events.some((e) => e.kind === 'edge_created' && e.data.fromNodeId === String(nodeId));
|
|
394
394
|
const causeKind = hasChildren ? 'non_tip_advance' : 'intentional_fork';
|
|
395
395
|
const outputId = (0, index_js_1.asOutputId)(`out_recap_${String(attemptId)}`);
|
|
@@ -406,7 +406,7 @@ function advanceAndRecord(args) {
|
|
|
406
406
|
]
|
|
407
407
|
: [];
|
|
408
408
|
const normalizedOutputs = (0, outputs_js_1.normalizeOutputsForAppend)(outputsToAppend);
|
|
409
|
-
const outputEventIds = normalizedOutputs.map(() =>
|
|
409
|
+
const outputEventIds = normalizedOutputs.map(() => idFactory.mintEventId());
|
|
410
410
|
const planRes = (0, ack_advance_append_plan_js_1.buildAckAdvanceAppendPlanV1)({
|
|
411
411
|
sessionId: String(sessionId),
|
|
412
412
|
runId: String(runId),
|
|
@@ -534,11 +534,11 @@ function parseAckTokenOrFail(raw, keyring, hmac, base64url) {
|
|
|
534
534
|
}
|
|
535
535
|
return { ok: true, token: parsedRes.value };
|
|
536
536
|
}
|
|
537
|
-
function newAttemptId() {
|
|
538
|
-
return
|
|
537
|
+
function newAttemptId(idFactory) {
|
|
538
|
+
return idFactory.mintAttemptId();
|
|
539
539
|
}
|
|
540
|
-
function attemptIdForNextNode(parentAttemptId) {
|
|
541
|
-
return (0,
|
|
540
|
+
function attemptIdForNextNode(parentAttemptId, sha256) {
|
|
541
|
+
return (0, attempt_id_derivation_js_1.deriveChildAttemptId)(parentAttemptId, sha256);
|
|
542
542
|
}
|
|
543
543
|
function signTokenOrErr(args) {
|
|
544
544
|
const bytes = (0, index_js_2.encodeTokenPayloadV1)(args.payload);
|
|
@@ -630,7 +630,14 @@ function executeStartWorkflow(input, ctx) {
|
|
|
630
630
|
if (!ctx.v2) {
|
|
631
631
|
return (0, neverthrow_1.errAsync)({ kind: 'precondition_failed', message: 'v2 tools disabled', suggestion: 'Enable v2Tools flag' });
|
|
632
632
|
}
|
|
633
|
-
const { gate, sessionStore, snapshotStore, pinnedStore, keyring, crypto, hmac, base64url } = ctx.v2;
|
|
633
|
+
const { gate, sessionStore, snapshotStore, pinnedStore, keyring, crypto, hmac, base64url, idFactory } = ctx.v2;
|
|
634
|
+
if (!idFactory) {
|
|
635
|
+
return (0, neverthrow_1.errAsync)({
|
|
636
|
+
kind: 'precondition_failed',
|
|
637
|
+
message: 'v2 context missing idFactory',
|
|
638
|
+
suggestion: 'Reinitialize v2 tool context (idFactory must be provided when v2Tools are enabled).',
|
|
639
|
+
});
|
|
640
|
+
}
|
|
634
641
|
const ctxCheck = checkContextBudget({ tool: 'start_workflow', context: input.context });
|
|
635
642
|
if (!ctxCheck.ok)
|
|
636
643
|
return (0, neverthrow_1.errAsync)({ kind: 'validation_failed', failure: ctxCheck.error });
|
|
@@ -678,9 +685,9 @@ function executeStartWorkflow(input, ctx) {
|
|
|
678
685
|
});
|
|
679
686
|
})
|
|
680
687
|
.andThen(({ workflow, firstStep, workflowHash, pinnedWorkflow }) => {
|
|
681
|
-
const sessionId =
|
|
682
|
-
const runId =
|
|
683
|
-
const nodeId =
|
|
688
|
+
const sessionId = idFactory.mintSessionId();
|
|
689
|
+
const runId = idFactory.mintRunId();
|
|
690
|
+
const nodeId = idFactory.mintNodeId();
|
|
684
691
|
const snapshot = {
|
|
685
692
|
v: 1,
|
|
686
693
|
kind: 'execution_snapshot',
|
|
@@ -697,9 +704,9 @@ function executeStartWorkflow(input, ctx) {
|
|
|
697
704
|
return snapshotStore.putExecutionSnapshotV1(snapshot)
|
|
698
705
|
.mapErr((cause) => ({ kind: 'snapshot_creation_failed', cause }))
|
|
699
706
|
.andThen((snapshotRef) => {
|
|
700
|
-
const evtSessionCreated =
|
|
701
|
-
const evtRunStarted =
|
|
702
|
-
const evtNodeCreated =
|
|
707
|
+
const evtSessionCreated = idFactory.mintEventId();
|
|
708
|
+
const evtRunStarted = idFactory.mintEventId();
|
|
709
|
+
const evtNodeCreated = idFactory.mintEventId();
|
|
703
710
|
return gate.withHealthySessionLock(sessionId, (lock) => {
|
|
704
711
|
const eventsArray = [
|
|
705
712
|
{
|
|
@@ -768,7 +775,7 @@ function executeStartWorkflow(input, ctx) {
|
|
|
768
775
|
nodeId,
|
|
769
776
|
workflowHash,
|
|
770
777
|
};
|
|
771
|
-
const attemptId = newAttemptId();
|
|
778
|
+
const attemptId = newAttemptId(idFactory);
|
|
772
779
|
const ackPayload = {
|
|
773
780
|
tokenVersion: 1,
|
|
774
781
|
tokenKind: 'ack',
|
|
@@ -812,7 +819,14 @@ function executeContinueWorkflow(input, ctx) {
|
|
|
812
819
|
if (!ctx.v2) {
|
|
813
820
|
return (0, neverthrow_1.errAsync)({ kind: 'precondition_failed', message: 'v2 tools disabled', suggestion: 'Enable v2Tools flag' });
|
|
814
821
|
}
|
|
815
|
-
const { gate, sessionStore, snapshotStore, pinnedStore, keyring, crypto, hmac, base64url } = ctx.v2;
|
|
822
|
+
const { gate, sessionStore, snapshotStore, pinnedStore, keyring, sha256, crypto, hmac, base64url, idFactory } = ctx.v2;
|
|
823
|
+
if (!sha256 || !idFactory) {
|
|
824
|
+
return (0, neverthrow_1.errAsync)({
|
|
825
|
+
kind: 'precondition_failed',
|
|
826
|
+
message: 'v2 context missing required dependencies',
|
|
827
|
+
suggestion: 'Reinitialize v2 tool context (sha256 and idFactory must be provided when v2Tools are enabled).',
|
|
828
|
+
});
|
|
829
|
+
}
|
|
816
830
|
const stateRes = parseStateTokenOrFail(input.stateToken, keyring, hmac, base64url);
|
|
817
831
|
if (!stateRes.ok)
|
|
818
832
|
return (0, neverthrow_1.errAsync)({ kind: 'validation_failed', failure: stateRes.failure });
|
|
@@ -864,7 +878,7 @@ function executeContinueWorkflow(input, ctx) {
|
|
|
864
878
|
const engineState = snapshot.enginePayload.engineState;
|
|
865
879
|
const pending = (0, snapshot_state_js_1.derivePendingStep)(engineState);
|
|
866
880
|
const isComplete = (0, snapshot_state_js_1.deriveIsComplete)(engineState);
|
|
867
|
-
const attemptId = newAttemptId();
|
|
881
|
+
const attemptId = newAttemptId(idFactory);
|
|
868
882
|
const ackTokenRes = signTokenOrErr({
|
|
869
883
|
unsignedPrefix: 'ack.v1.',
|
|
870
884
|
payload: { tokenVersion: 1, tokenKind: 'ack', sessionId, runId, nodeId, attemptId },
|
|
@@ -963,6 +977,7 @@ function executeContinueWorkflow(input, ctx) {
|
|
|
963
977
|
pinnedWorkflow,
|
|
964
978
|
snapshotStore,
|
|
965
979
|
keyring,
|
|
980
|
+
sha256,
|
|
966
981
|
hmac,
|
|
967
982
|
base64url,
|
|
968
983
|
});
|
|
@@ -986,6 +1001,7 @@ function executeContinueWorkflow(input, ctx) {
|
|
|
986
1001
|
pinnedWorkflow,
|
|
987
1002
|
snapshotStore,
|
|
988
1003
|
sessionStore,
|
|
1004
|
+
idFactory,
|
|
989
1005
|
}).andThen(() => sessionStore
|
|
990
1006
|
.load(sessionId)
|
|
991
1007
|
.map((truthAfter) => ({ kind: 'replay', truth: truthAfter, recordedEvent: null })));
|
|
@@ -1035,6 +1051,7 @@ function executeContinueWorkflow(input, ctx) {
|
|
|
1035
1051
|
pinnedWorkflow,
|
|
1036
1052
|
snapshotStore,
|
|
1037
1053
|
keyring,
|
|
1054
|
+
sha256,
|
|
1038
1055
|
hmac,
|
|
1039
1056
|
base64url,
|
|
1040
1057
|
});
|
package/dist/mcp/server.js
CHANGED
|
@@ -95,18 +95,22 @@ async function createToolContext() {
|
|
|
95
95
|
console.error('[FeatureFlags] v2 tools disabled due to keyring initialization failure');
|
|
96
96
|
}
|
|
97
97
|
else {
|
|
98
|
+
const sha256 = container_js_1.container.resolve(tokens_js_1.DI.V2.Sha256);
|
|
98
99
|
const crypto = container_js_1.container.resolve(tokens_js_1.DI.V2.Crypto);
|
|
99
100
|
const hmac = container_js_1.container.resolve(tokens_js_1.DI.V2.HmacSha256);
|
|
100
101
|
const base64url = container_js_1.container.resolve(tokens_js_1.DI.V2.Base64Url);
|
|
102
|
+
const idFactory = container_js_1.container.resolve(tokens_js_1.DI.V2.IdFactory);
|
|
101
103
|
v2 = {
|
|
102
104
|
gate,
|
|
103
105
|
sessionStore,
|
|
104
106
|
snapshotStore,
|
|
105
107
|
pinnedStore,
|
|
106
108
|
keyring: keyringResult.value,
|
|
109
|
+
sha256,
|
|
107
110
|
crypto,
|
|
108
111
|
hmac,
|
|
109
112
|
base64url,
|
|
113
|
+
idFactory,
|
|
110
114
|
};
|
|
111
115
|
console.error('[FeatureFlags] v2 tools enabled');
|
|
112
116
|
}
|
package/dist/mcp/types.d.ts
CHANGED
|
@@ -8,9 +8,11 @@ import type { SessionEventLogAppendStorePortV2, SessionEventLogReadonlyStorePort
|
|
|
8
8
|
import type { SnapshotStorePortV2 } from '../v2/ports/snapshot-store.port.js';
|
|
9
9
|
import type { PinnedWorkflowStorePortV2 } from '../v2/ports/pinned-workflow-store.port.js';
|
|
10
10
|
import type { KeyringV1 } from '../v2/ports/keyring.port.js';
|
|
11
|
+
import type { Sha256PortV2 } from '../v2/ports/sha256.port.js';
|
|
11
12
|
import type { CryptoPortV2 } from '../v2/durable-core/canonical/hashing.js';
|
|
12
13
|
import type { HmacSha256PortV2 } from '../v2/ports/hmac-sha256.port.js';
|
|
13
14
|
import type { Base64UrlPortV2 } from '../v2/ports/base64url.port.js';
|
|
15
|
+
import type { IdFactoryV2 } from '../v2/infra/local/id-factory/index.js';
|
|
14
16
|
import type { JsonValue } from './output-schemas.js';
|
|
15
17
|
export interface SessionHealthDetails {
|
|
16
18
|
readonly health: SessionHealthV2;
|
|
@@ -48,9 +50,11 @@ export interface V2Dependencies {
|
|
|
48
50
|
readonly snapshotStore: SnapshotStorePortV2;
|
|
49
51
|
readonly pinnedStore: PinnedWorkflowStorePortV2;
|
|
50
52
|
readonly keyring: KeyringV1;
|
|
53
|
+
readonly sha256: Sha256PortV2;
|
|
51
54
|
readonly crypto: CryptoPortV2;
|
|
52
55
|
readonly hmac: HmacSha256PortV2;
|
|
53
56
|
readonly base64url: Base64UrlPortV2;
|
|
57
|
+
readonly idFactory: IdFactoryV2;
|
|
54
58
|
}
|
|
55
59
|
export interface ToolContext {
|
|
56
60
|
readonly workflowService: WorkflowService;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.encodeBase32LowerNoPad = encodeBase32LowerNoPad;
|
|
4
|
+
const BASE32_LOWER_ALPHABET = 'abcdefghijklmnopqrstuvwxyz234567';
|
|
5
|
+
function encodeBase32LowerNoPad(bytes) {
|
|
6
|
+
let out = '';
|
|
7
|
+
let buffer = 0n;
|
|
8
|
+
let bits = 0;
|
|
9
|
+
for (const b of bytes) {
|
|
10
|
+
buffer = (buffer << 8n) | BigInt(b);
|
|
11
|
+
bits += 8;
|
|
12
|
+
while (bits >= 5) {
|
|
13
|
+
const shift = BigInt(bits - 5);
|
|
14
|
+
const index = Number((buffer >> shift) & 31n);
|
|
15
|
+
out += BASE32_LOWER_ALPHABET[index];
|
|
16
|
+
bits -= 5;
|
|
17
|
+
if (bits === 0) {
|
|
18
|
+
buffer = 0n;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
buffer = buffer & ((1n << BigInt(bits)) - 1n);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (bits > 0) {
|
|
26
|
+
const index = Number((buffer << BigInt(5 - bits)) & 31n);
|
|
27
|
+
out += BASE32_LOWER_ALPHABET[index];
|
|
28
|
+
}
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deriveChildAttemptId = deriveChildAttemptId;
|
|
4
|
+
const index_js_1 = require("./index.js");
|
|
5
|
+
const base32_lower_js_1 = require("../encoding/base32-lower.js");
|
|
6
|
+
const PREFIX = 'wr_attempt_next_v1:';
|
|
7
|
+
function hexToBytes(hex) {
|
|
8
|
+
if (hex.length % 2 !== 0) {
|
|
9
|
+
throw new Error('hex string must have even length');
|
|
10
|
+
}
|
|
11
|
+
const out = new Uint8Array(hex.length / 2);
|
|
12
|
+
for (let i = 0; i < out.length; i++) {
|
|
13
|
+
const byteHex = hex.slice(i * 2, i * 2 + 2);
|
|
14
|
+
const n = Number.parseInt(byteHex, 16);
|
|
15
|
+
if (Number.isNaN(n)) {
|
|
16
|
+
throw new Error(`invalid hex byte: ${byteHex}`);
|
|
17
|
+
}
|
|
18
|
+
out[i] = n;
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
const SHA256_DIGEST_RE = /^sha256:[0-9a-f]{64}$/;
|
|
23
|
+
function deriveChildAttemptId(parent, sha256) {
|
|
24
|
+
const bytes = new TextEncoder().encode(`${PREFIX}${String(parent)}`);
|
|
25
|
+
const digest = String(sha256.sha256(bytes));
|
|
26
|
+
if (!SHA256_DIGEST_RE.test(digest)) {
|
|
27
|
+
throw new Error(`expected sha256:<64hex> digest, got: ${digest}`);
|
|
28
|
+
}
|
|
29
|
+
const first16 = hexToBytes(digest.slice('sha256:'.length, 'sha256:'.length + 32));
|
|
30
|
+
const suffix = (0, base32_lower_js_1.encodeBase32LowerNoPad)(first16);
|
|
31
|
+
return (0, index_js_1.asAttemptId)(`attempt_${suffix}`);
|
|
32
|
+
}
|
|
@@ -8,10 +8,11 @@ const index_js_1 = require("../ids/index.js");
|
|
|
8
8
|
const sha256DigestSchema = zod_1.z.string().regex(/^sha256:[0-9a-f]{64}$/, 'Expected sha256:<64 hex chars>');
|
|
9
9
|
const workflowHashSchema = sha256DigestSchema.transform((v) => (0, index_js_1.asWorkflowHash)((0, index_js_1.asSha256Digest)(v)));
|
|
10
10
|
const nonEmpty = zod_1.z.string().min(1);
|
|
11
|
-
|
|
12
|
-
exports.
|
|
13
|
-
exports.
|
|
14
|
-
exports.
|
|
11
|
+
const delimiterSafeId = nonEmpty.regex(/^[^:\s]+$/, 'Expected a delimiter-safe ID (no ":" or whitespace)');
|
|
12
|
+
exports.AttemptIdSchema = delimiterSafeId.transform(index_js_1.asAttemptId);
|
|
13
|
+
exports.SessionIdSchema = delimiterSafeId.transform(index_js_1.asSessionId);
|
|
14
|
+
exports.RunIdSchema = delimiterSafeId.transform(index_js_1.asRunId);
|
|
15
|
+
exports.NodeIdSchema = delimiterSafeId.transform(index_js_1.asNodeId);
|
|
15
16
|
exports.StateTokenPayloadV1Schema = zod_1.z.object({
|
|
16
17
|
tokenVersion: zod_1.z.literal(1),
|
|
17
18
|
tokenKind: zod_1.z.literal('state'),
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { RandomEntropyPortV2 } from '../../../ports/random-entropy.port.js';
|
|
2
|
+
import type { AttemptId, NodeId, RunId, SessionId } from '../../../durable-core/ids/index.js';
|
|
3
|
+
export declare class IdFactoryV2 {
|
|
4
|
+
private readonly entropy;
|
|
5
|
+
constructor(entropy: RandomEntropyPortV2);
|
|
6
|
+
mintSessionId(): SessionId;
|
|
7
|
+
mintRunId(): RunId;
|
|
8
|
+
mintNodeId(): NodeId;
|
|
9
|
+
mintAttemptId(): AttemptId;
|
|
10
|
+
mintEventId(): string;
|
|
11
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IdFactoryV2 = void 0;
|
|
4
|
+
const index_js_1 = require("../../../durable-core/ids/index.js");
|
|
5
|
+
const base32_lower_js_1 = require("../../../durable-core/encoding/base32-lower.js");
|
|
6
|
+
const BYTES = 16;
|
|
7
|
+
function mint(prefix, entropy) {
|
|
8
|
+
const bytes = entropy.generateBytes(BYTES);
|
|
9
|
+
const suffix = (0, base32_lower_js_1.encodeBase32LowerNoPad)(bytes);
|
|
10
|
+
return `${prefix}_${suffix}`;
|
|
11
|
+
}
|
|
12
|
+
class IdFactoryV2 {
|
|
13
|
+
constructor(entropy) {
|
|
14
|
+
this.entropy = entropy;
|
|
15
|
+
}
|
|
16
|
+
mintSessionId() {
|
|
17
|
+
return (0, index_js_1.asSessionId)(mint('sess', this.entropy));
|
|
18
|
+
}
|
|
19
|
+
mintRunId() {
|
|
20
|
+
return (0, index_js_1.asRunId)(mint('run', this.entropy));
|
|
21
|
+
}
|
|
22
|
+
mintNodeId() {
|
|
23
|
+
return (0, index_js_1.asNodeId)(mint('node', this.entropy));
|
|
24
|
+
}
|
|
25
|
+
mintAttemptId() {
|
|
26
|
+
return (0, index_js_1.asAttemptId)(mint('attempt', this.entropy));
|
|
27
|
+
}
|
|
28
|
+
mintEventId() {
|
|
29
|
+
return mint('evt', this.entropy);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.IdFactoryV2 = IdFactoryV2;
|