@forgeax/engine-tool-runtime 0.1.29 → 0.1.30

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/index.mjs CHANGED
@@ -233,494 +233,186 @@ function validateArtifactRefs(value) {
233
233
  );
234
234
  }
235
235
 
236
- // src/capability.ts
237
- var capabilityIdPattern = /^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/;
238
- function defineToolCapability(id) {
239
- if (!capabilityIdPattern.test(id)) {
240
- throw new TypeError(`Tool capability id must use a stable lower-case path: ${id}`);
241
- }
242
- return Object.freeze({ id });
243
- }
244
- function createCapabilityResolver(resolve) {
245
- return (capability) => {
246
- const value = resolve(capability);
247
- return value === void 0 ? void 0 : { ok: true, value };
236
+ // src/lease.ts
237
+ function createLexicalLease(runId) {
238
+ const cleanups = [];
239
+ let state = "active";
240
+ let terminalId;
241
+ let termination;
242
+ const terminate = (reason) => {
243
+ if (termination !== void 0) return termination;
244
+ terminalId = `${runId}:terminal:${crypto.randomUUID()}`;
245
+ state = "terminating";
246
+ termination = (async () => {
247
+ const failures = [];
248
+ for (let index = cleanups.length - 1; index >= 0; index -= 1) {
249
+ const entry = cleanups[index];
250
+ if (entry === void 0) continue;
251
+ try {
252
+ await entry.cleanup();
253
+ } catch (cause) {
254
+ failures.push({
255
+ owner: entry.owner,
256
+ message: cause instanceof Error ? cause.message : String(cause)
257
+ });
258
+ }
259
+ }
260
+ state = "terminated";
261
+ return { terminalId, reason, failures };
262
+ })();
263
+ return termination;
248
264
  };
249
- }
250
- function admissionFailure(admission, expected) {
251
- if (admission === void 0) return "no workload-scoped admission report was supplied";
252
- if (admission.schema !== "forgeax.tool-service-admission-ref.v1" || !/^sha256:[0-9a-f]{64}$/.test(admission.reportDigest)) {
253
- return "admission report identity is invalid";
254
- }
255
- for (const key of [
256
- "toolId",
257
- "descriptorDigest",
258
- "recipeDigest",
259
- "workloadClass",
260
- "codeDigest",
261
- "browserVersion",
262
- "backend"
263
- ]) {
264
- if (admission[key] !== expected[key]) return `admission ${key} does not match this run`;
265
- }
266
- if (admission.frameCount < 300) return "admission workload ran fewer than 300 frames";
267
- if (Object.values(admission.samples).some((count) => count < 30)) {
268
- return "admission sample set is incomplete";
269
- }
270
- if (!admission.correctness.terminalEquivalent || !admission.correctness.artifactIntegrity || !admission.correctness.freshReplay || !admission.correctness.hiddenParity || admission.correctness.drawCalls <= 0 || admission.correctness.nonBlackPixels <= 0) {
271
- return "admission correctness gate failed";
272
- }
273
- const performance2 = admission.performance;
274
- if (Object.values(performance2).some((value) => !Number.isFinite(value) || value <= 0) || performance2.serviceMedianMs > performance2.privateMedianMs * 0.8 || performance2.serviceP95Ms > performance2.privateP95Ms * 0.9 || performance2.serviceMaxMs > performance2.privateMaxMs * 1.1 || performance2.serviceRssBytes > performance2.privateRssBytes * 1.25) {
275
- return "admission performance threshold failed";
276
- }
277
- if (!admission.cleanupPassed) return "admission cleanup gate failed";
278
- if (!admission.evictionPassed) return "admission eviction gate failed";
279
- return void 0;
280
- }
281
- function createServiceCapability(admission, expected) {
282
- const reason = admissionFailure(admission, expected);
283
- if (reason === void 0 && admission !== void 0) {
284
- return { available: true, reportDigest: admission.reportDigest };
285
- }
286
265
  return {
287
- available: false,
288
- code: "tool-service-capability-absent",
289
- expected: "an admitted acceleration service",
290
- hint: "Use the private executor and rerun benchmark admission before enabling service.",
291
- detail: { reason: reason ?? "benchmark admission did not pass" }
266
+ get state() {
267
+ return state;
268
+ },
269
+ register(owner, cleanup) {
270
+ if (state !== "active") return false;
271
+ cleanups.push({ owner, cleanup });
272
+ return true;
273
+ },
274
+ terminate
292
275
  };
293
276
  }
294
- function createRealmCapabilityMatrix(input) {
295
- const realms = ["build", "host", "engine"].reduce(
296
- (result, realm) => {
297
- const supported = input.supported[realm];
298
- result[realm] = supported ? { realm, supported: true } : { realm, supported: false, reason: "realm-capability-unavailable" };
299
- return result;
300
- },
301
- {}
277
+
278
+ // src/timing.ts
279
+ var PHASES = [
280
+ "lookup",
281
+ "lease",
282
+ "transport",
283
+ "execute",
284
+ "capture",
285
+ "finalize",
286
+ "analyze"
287
+ ];
288
+ function createExclusiveTiming(now = () => performance.now()) {
289
+ const phases = Object.fromEntries(
290
+ PHASES.map((phase) => [phase, { status: "not-applicable" }])
302
291
  );
303
- return { catalogDigest: input.catalogDigest, realms };
304
- }
305
- function bootstrapNotCloneSafeError(detail) {
292
+ const closed = /* @__PURE__ */ new Set();
293
+ let active;
294
+ let startedAtMs;
295
+ let endedAtMs;
306
296
  return {
307
- code: "tool-bootstrap-not-clone-safe",
308
- expected: "bootstrap input to contain structured-clone-safe data",
309
- hint: "Remove live handles, functions, ports, and realm-owned objects from bootstrap input.",
310
- detail
297
+ begin(phase) {
298
+ if (active !== void 0) throw new TypeError(`phase '${active.phase}' is still open`);
299
+ if (closed.has(phase)) throw new TypeError(`phase '${phase}' was already closed`);
300
+ const at = now();
301
+ startedAtMs ??= at;
302
+ active = { phase, startedAtMs: at };
303
+ },
304
+ end(phase) {
305
+ if (active?.phase !== phase) throw new TypeError(`phase '${phase}' is not the active phase`);
306
+ const at = now();
307
+ phases[phase] = { status: "observed", durationMs: Math.max(0, at - active.startedAtMs) };
308
+ closed.add(phase);
309
+ active = void 0;
310
+ endedAtMs = at;
311
+ },
312
+ record(phase, durationMs) {
313
+ if (!Number.isFinite(durationMs) || durationMs < 0)
314
+ throw new TypeError("phase duration must be finite and non-negative");
315
+ if (closed.has(phase)) throw new TypeError(`phase '${phase}' was already closed`);
316
+ const at = now();
317
+ startedAtMs ??= at - durationMs;
318
+ phases[phase] = { status: "observed", durationMs };
319
+ closed.add(phase);
320
+ endedAtMs = at;
321
+ },
322
+ finish() {
323
+ if (active !== void 0) throw new TypeError(`phase '${active.phase}' is still open`);
324
+ const start = startedAtMs ?? now();
325
+ const end = endedAtMs ?? start;
326
+ return {
327
+ startedAtMs: start,
328
+ endedAtMs: end,
329
+ totalMs: Math.max(0, end - start),
330
+ phases: { ...phases }
331
+ };
332
+ }
311
333
  };
312
334
  }
313
- function validateRealmBootstrapPayload(value) {
314
- try {
315
- structuredClone(value);
316
- return { ok: true };
317
- } catch (cause) {
318
- return {
319
- ok: false,
320
- error: bootstrapNotCloneSafeError({
321
- message: cause instanceof Error ? cause.message : String(cause)
322
- })
323
- };
324
- }
325
- }
326
-
327
- // src/carrier.ts
328
- function token() {
329
- return crypto.randomUUID().replaceAll("-", "");
330
- }
331
- function carrierError(code, expected, hint, detail) {
332
- return { code, expected, hint, detail };
335
+ function startToolTiming() {
336
+ return performance.now();
333
337
  }
334
- function containsLiveKey(value, seen = /* @__PURE__ */ new Set()) {
335
- if (typeof value !== "object" || value === null) return false;
336
- if (seen.has(value)) return false;
337
- seen.add(value);
338
- if (Array.isArray(value)) return value.some((entry) => containsLiveKey(entry, seen));
339
- return Object.entries(value).some(([key, nested]) => {
340
- if (["world", "renderer", "canvas", "ui", "profile", "liveHandle", "context", "fiber"].includes(
341
- key
342
- ))
343
- return true;
344
- return containsLiveKey(nested, seen);
345
- });
338
+ function finishToolTiming(startedAtMs, operationTiming) {
339
+ const endedAtMs = performance.now();
340
+ const result = operationTiming?.finish();
341
+ const durationMs = Math.max(0, endedAtMs - startedAtMs);
342
+ const attributedMs = result === void 0 ? 0 : Object.values(result.phases).reduce(
343
+ (sum, observation) => observation.status === "observed" ? sum + observation.durationMs : sum,
344
+ 0
345
+ );
346
+ return {
347
+ startedAtMs,
348
+ endedAtMs,
349
+ durationMs,
350
+ ...result === void 0 ? {} : { phases: result.phases, unattributedMs: Math.max(0, durationMs - attributedMs) }
351
+ };
346
352
  }
347
- function validateOptions(options) {
348
- if (options.projectId.length === 0 || options.consumerId.length === 0) {
349
- throw new TypeError("carrier projectId and consumerId must not be empty");
353
+
354
+ // src/runtime.ts
355
+ function defineTool(descriptor, execute) {
356
+ if (!/^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/.test(descriptor.id)) {
357
+ throw new TypeError(`Tool id must use a stable lower-case path: ${descriptor.id}`);
350
358
  }
351
- const endpoint = new URL(options.endpoint);
352
- if (endpoint.protocol !== "http:" || !["127.0.0.1", "localhost"].includes(endpoint.hostname)) {
353
- throw new TypeError("carrier endpoint must be loopback HTTP");
359
+ if (descriptor.title.trim().length === 0 || descriptor.summary.trim().length === 0) {
360
+ throw new TypeError("Tool title and summary must not be empty");
354
361
  }
355
- if (!Number.isFinite(options.now) || !Number.isFinite(options.ttlMs) || options.ttlMs <= 0) {
356
- throw new TypeError("carrier clock and ttl must be finite and positive");
362
+ if (!Array.isArray(descriptor.evidence)) throw new TypeError("Tool evidence must be an array");
363
+ if (descriptor.preview !== void 0 && descriptor.preview.realm !== descriptor.realm) {
364
+ throw new TypeError(
365
+ `Tool ${descriptor.id} preview contract declares ${descriptor.preview.realm} but descriptor declares ${descriptor.realm}`
366
+ );
357
367
  }
358
- if (containsLiveKey(options.payload)) throw new TypeError("carrier-payload-live-state");
359
- }
360
- function createCarrierStateMachine(options) {
361
- validateOptions(options);
362
- const offer = {
363
- schemaVersion: "1.0.0",
364
- projectId: options.projectId,
365
- consumerId: options.consumerId,
366
- offerId: `offer:${token()}`,
367
- endpoint: options.endpoint,
368
- bearerToken: token(),
369
- livenessToken: token(),
370
- expiresAt: options.now + options.ttlMs,
371
- ...options.descriptorDigest === void 0 ? {} : { descriptorDigest: options.descriptorDigest },
372
- ...options.recipeDigest === void 0 ? {} : { recipeDigest: options.recipeDigest },
373
- state: "offered"
368
+ const argsSchema = descriptor.argsSchema;
369
+ const resultSchema = descriptor.resultSchema;
370
+ return {
371
+ descriptor: { ...descriptor, argsSchema, resultSchema, evidence: [...descriptor.evidence] },
372
+ execute
374
373
  };
375
- let state = { state: "offered" };
376
- let lease;
377
- const leaseOffer = (requestOrId, maybeRequest) => {
378
- const request = typeof requestOrId === "string" ? maybeRequest : requestOrId;
379
- const requestedLeaseId = typeof requestOrId === "string" ? requestOrId : void 0;
380
- if (request === void 0) {
381
- return {
382
- ok: false,
383
- error: carrierError(
384
- "carrier-token-invalid",
385
- "a complete lease request",
386
- "Provide consumer identity, bearer token, and current time.",
387
- {}
388
- )
389
- };
390
- }
391
- if (state.state === "started") {
392
- return {
393
- ok: false,
394
- error: carrierError(
395
- "carrier-started",
396
- "a started carrier not to be retried",
397
- "Report one terminal failure and clean up the existing started lease.",
398
- {}
399
- )
400
- };
401
- }
402
- if (state.state === "exited") {
403
- return {
404
- ok: false,
405
- error: carrierError(
406
- "carrier-exited",
407
- "an exited carrier not to be retried",
408
- "Re-run the operation from a serialized snapshot instead of migrating live state.",
409
- {}
410
- )
411
- };
412
- }
413
- if (request.consumerId !== offer.consumerId) {
414
- return {
415
- ok: false,
416
- error: carrierError(
417
- "carrier-consumer-mismatch",
418
- "the offer consumer identity to match",
419
- "Use the consumer identity that was authenticated for this project offer.",
420
- { expected: offer.consumerId, actual: request.consumerId }
421
- )
422
- };
423
- }
424
- if (request.bearerToken !== offer.bearerToken) {
425
- return {
426
- ok: false,
427
- error: carrierError(
428
- "carrier-token-invalid",
429
- "the bearer token to match the ephemeral offer",
430
- "Request a fresh visible offer; never persist or guess bearer tokens.",
431
- {}
432
- )
433
- };
434
- }
435
- if (offer.descriptorDigest !== void 0 && request.descriptorDigest !== offer.descriptorDigest) {
436
- return {
437
- ok: false,
438
- error: carrierError(
439
- "carrier-descriptor-mismatch",
440
- "the descriptor digest to match the authenticated offer",
441
- "Refresh the descriptor and request a new visible offer before retrying.",
442
- { expected: offer.descriptorDigest, actual: request.descriptorDigest }
443
- )
444
- };
445
- }
446
- if (offer.recipeDigest !== void 0 && request.recipeDigest !== offer.recipeDigest) {
447
- return {
448
- ok: false,
449
- error: carrierError(
450
- "carrier-recipe-mismatch",
451
- "the recipe digest to match the authenticated offer",
452
- "Serialize the current snapshot and request a fresh visible offer before retrying.",
453
- { expected: offer.recipeDigest, actual: request.recipeDigest }
454
- )
455
- };
456
- }
457
- if (request.now >= offer.expiresAt) {
458
- state = { state: "expired" };
459
- return {
460
- ok: false,
461
- error: carrierError(
462
- "carrier-offer-expired",
463
- "the offer to be within its expiry window",
464
- "Fall back to the ordinary visible carrier before retrying.",
465
- { expiresAt: offer.expiresAt, now: request.now }
466
- )
467
- };
468
- }
469
- if (requestedLeaseId !== void 0 && requestedLeaseId !== lease?.leaseId) {
470
- return {
471
- ok: false,
472
- error: carrierError(
473
- "carrier-token-invalid",
474
- "the lease id to match the authenticated offer",
475
- "Use the lease id returned by the first successful lease.",
476
- {}
477
- )
478
- };
479
- }
480
- lease = {
481
- leaseId: `lease:${token()}`,
482
- offerId: offer.offerId,
483
- consumerId: request.consumerId,
484
- state: "leased"
485
- };
486
- state = { state: "leased", leaseId: lease.leaseId };
487
- return { ok: true, value: lease, state: "leased" };
488
- };
489
- const started = (leaseId) => {
490
- if (lease?.leaseId !== leaseId) {
491
- return {
492
- ok: false,
493
- error: carrierError(
494
- "carrier-lease-required",
495
- "a valid lease before started",
496
- "Lease the authenticated offer before reporting provider started.",
497
- {}
498
- )
499
- };
500
- }
501
- state = { state: "started", leaseId };
502
- return { ok: true, value: state, state: "started" };
374
+ }
375
+ function eventChannel() {
376
+ const queue = [];
377
+ const waiters = [];
378
+ let closed = false;
379
+ const emit = (event) => {
380
+ const waiter = waiters.shift();
381
+ if (waiter !== void 0) waiter({ done: false, value: event });
382
+ else queue.push(event);
503
383
  };
504
- const exit = (leaseId) => {
505
- if (lease?.leaseId !== leaseId || state.state !== "started") {
506
- return {
507
- ok: false,
508
- error: carrierError(
509
- "carrier-lease-required",
510
- "a started lease before provider exit",
511
- "Provider exit is terminal only after started has been acknowledged.",
512
- {}
513
- )
514
- };
515
- }
516
- state = { state: "exited", leaseId };
517
- return { ok: true, value: state, state: "exited" };
384
+ const close = () => {
385
+ closed = true;
386
+ while (waiters.length > 0) waiters.shift()?.({ done: true, value: void 0 });
518
387
  };
519
- const fallback = () => {
520
- if (state.state === "started" || state.state === "exited") {
388
+ const events = {
389
+ [Symbol.asyncIterator]() {
521
390
  return {
522
- ok: false,
523
- error: carrierError(
524
- "carrier-started",
525
- "fallback to happen before provider started",
526
- "Do not retry or migrate a carrier after started; return its terminal failure.",
527
- { state: state.state }
528
- )
391
+ next: async () => {
392
+ const event = queue.shift();
393
+ if (event !== void 0) return { done: false, value: event };
394
+ if (closed) return { done: true, value: void 0 };
395
+ return new Promise((resolve) => waiters.push(resolve));
396
+ }
529
397
  };
530
398
  }
531
- state = { state: "fallback" };
532
- return { ok: true, value: state, state: "fallback" };
533
- };
534
- return {
535
- offer,
536
- lease: leaseOffer,
537
- started,
538
- exit,
539
- fallback,
540
- snapshot: () => state
541
399
  };
400
+ return { emit, close, events };
542
401
  }
543
-
544
- // src/lease.ts
545
- function createLexicalLease(runId) {
546
- const cleanups = [];
547
- let state = "active";
548
- let terminalId;
549
- let termination;
550
- const terminate = (reason) => {
551
- if (termination !== void 0) return termination;
552
- terminalId = `${runId}:terminal:${crypto.randomUUID()}`;
553
- state = "terminating";
554
- termination = (async () => {
555
- const failures = [];
556
- for (let index = cleanups.length - 1; index >= 0; index -= 1) {
557
- const entry = cleanups[index];
558
- if (entry === void 0) continue;
559
- try {
560
- await entry.cleanup();
561
- } catch (cause) {
562
- failures.push({
563
- owner: entry.owner,
564
- message: cause instanceof Error ? cause.message : String(cause)
565
- });
566
- }
567
- }
568
- state = "terminated";
569
- return { terminalId, reason, failures };
570
- })();
571
- return termination;
572
- };
573
- return {
574
- get state() {
575
- return state;
576
- },
577
- register(owner, cleanup) {
578
- if (state !== "active") return false;
579
- cleanups.push({ owner, cleanup });
580
- return true;
581
- },
582
- terminate
583
- };
402
+ function isTerminal(value) {
403
+ if (typeof value !== "object" || value === null) return false;
404
+ const outcome = Reflect.get(value, "outcome");
405
+ return outcome === "succeeded" || outcome === "failed";
584
406
  }
585
-
586
- // src/timing.ts
587
- var PHASES = [
588
- "lookup",
589
- "lease",
590
- "transport",
591
- "execute",
592
- "capture",
593
- "finalize",
594
- "analyze"
595
- ];
596
- function createExclusiveTiming(now = () => performance.now()) {
597
- const phases = Object.fromEntries(
598
- PHASES.map((phase) => [phase, { status: "not-applicable" }])
599
- );
600
- const closed = /* @__PURE__ */ new Set();
601
- let active;
602
- let startedAtMs;
603
- let endedAtMs;
604
- return {
605
- begin(phase) {
606
- if (active !== void 0) throw new TypeError(`phase '${active.phase}' is still open`);
607
- if (closed.has(phase)) throw new TypeError(`phase '${phase}' was already closed`);
608
- const at = now();
609
- startedAtMs ??= at;
610
- active = { phase, startedAtMs: at };
611
- },
612
- end(phase) {
613
- if (active?.phase !== phase) throw new TypeError(`phase '${phase}' is not the active phase`);
614
- const at = now();
615
- phases[phase] = { status: "observed", durationMs: Math.max(0, at - active.startedAtMs) };
616
- closed.add(phase);
617
- active = void 0;
618
- endedAtMs = at;
619
- },
620
- record(phase, durationMs) {
621
- if (!Number.isFinite(durationMs) || durationMs < 0)
622
- throw new TypeError("phase duration must be finite and non-negative");
623
- if (closed.has(phase)) throw new TypeError(`phase '${phase}' was already closed`);
624
- const at = now();
625
- startedAtMs ??= at - durationMs;
626
- phases[phase] = { status: "observed", durationMs };
627
- closed.add(phase);
628
- endedAtMs = at;
629
- },
630
- finish() {
631
- if (active !== void 0) throw new TypeError(`phase '${active.phase}' is still open`);
632
- const start = startedAtMs ?? now();
633
- const end = endedAtMs ?? start;
634
- return {
635
- startedAtMs: start,
636
- endedAtMs: end,
637
- totalMs: Math.max(0, end - start),
638
- phases: { ...phases }
639
- };
640
- }
641
- };
642
- }
643
- function startToolTiming() {
644
- return performance.now();
645
- }
646
- function finishToolTiming(startedAtMs, operationTiming) {
647
- const endedAtMs = performance.now();
648
- const result = operationTiming?.finish();
649
- const durationMs = Math.max(0, endedAtMs - startedAtMs);
650
- const attributedMs = result === void 0 ? 0 : Object.values(result.phases).reduce(
651
- (sum, observation) => observation.status === "observed" ? sum + observation.durationMs : sum,
652
- 0
653
- );
654
- return {
655
- startedAtMs,
656
- endedAtMs,
657
- durationMs,
658
- ...result === void 0 ? {} : { phases: result.phases, unattributedMs: Math.max(0, durationMs - attributedMs) }
659
- };
660
- }
661
-
662
- // src/runtime.ts
663
- function defineTool(descriptor, execute) {
664
- if (!/^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/.test(descriptor.id)) {
665
- throw new TypeError(`Tool id must use a stable lower-case path: ${descriptor.id}`);
666
- }
667
- if (descriptor.title.trim().length === 0 || descriptor.summary.trim().length === 0) {
668
- throw new TypeError("Tool title and summary must not be empty");
669
- }
670
- if (!Array.isArray(descriptor.evidence)) throw new TypeError("Tool evidence must be an array");
671
- if (descriptor.preview !== void 0 && descriptor.preview.realm !== descriptor.realm) {
672
- throw new TypeError(
673
- `Tool ${descriptor.id} preview contract declares ${descriptor.preview.realm} but descriptor declares ${descriptor.realm}`
674
- );
675
- }
676
- const argsSchema = descriptor.argsSchema;
677
- const resultSchema = descriptor.resultSchema;
678
- return {
679
- descriptor: { ...descriptor, argsSchema, resultSchema, evidence: [...descriptor.evidence] },
680
- execute
681
- };
682
- }
683
- function eventChannel() {
684
- const queue = [];
685
- const waiters = [];
686
- let closed = false;
687
- const emit = (event) => {
688
- const waiter = waiters.shift();
689
- if (waiter !== void 0) waiter({ done: false, value: event });
690
- else queue.push(event);
691
- };
692
- const close = () => {
693
- closed = true;
694
- while (waiters.length > 0) waiters.shift()?.({ done: true, value: void 0 });
695
- };
696
- const events = {
697
- [Symbol.asyncIterator]() {
698
- return {
699
- next: async () => {
700
- const event = queue.shift();
701
- if (event !== void 0) return { done: false, value: event };
702
- if (closed) return { done: true, value: void 0 };
703
- return new Promise((resolve) => waiters.push(resolve));
704
- }
705
- };
706
- }
707
- };
708
- return { emit, close, events };
709
- }
710
- function isTerminal(value) {
711
- if (typeof value !== "object" || value === null) return false;
712
- const outcome = Reflect.get(value, "outcome");
713
- return outcome === "succeeded" || outcome === "failed";
714
- }
715
- function serializablePreview(value) {
716
- return isSerializableValue(value) ? value : null;
717
- }
718
- function domainError(error) {
719
- return domainFailureError(
720
- error.code,
721
- error.expected ?? "the producer operation to succeed",
722
- error.hint ?? "Inspect detail and repair the owning producer before retrying.",
723
- error.detail
407
+ function serializablePreview(value) {
408
+ return isSerializableValue(value) ? value : null;
409
+ }
410
+ function domainError(error) {
411
+ return domainFailureError(
412
+ error.code,
413
+ error.expected ?? "the producer operation to succeed",
414
+ error.hint ?? "Inspect detail and repair the owning producer before retrying.",
415
+ error.detail
724
416
  );
725
417
  }
726
418
  function hasOkField(value) {
@@ -765,6 +457,10 @@ function createToolRuntime(contributions) {
765
457
  const terminal = new Promise((resolve) => {
766
458
  resolveTerminal = resolve;
767
459
  });
460
+ let resolveExecutorExited;
461
+ const executorExited = new Promise((resolve) => {
462
+ resolveExecutorExited = resolve;
463
+ });
768
464
  const settle = async (candidate, reason = "terminal") => {
769
465
  if (terminalStarted) return;
770
466
  terminalStarted = true;
@@ -802,6 +498,8 @@ function createToolRuntime(contributions) {
802
498
  const context = {
803
499
  runId,
804
500
  signal: controller.signal,
501
+ ...options.owner === void 0 ? {} : { owner: options.owner },
502
+ ...options.caller === void 0 ? {} : { caller: options.caller },
805
503
  ...options.snapshot === void 0 ? {} : { snapshot: options.snapshot },
806
504
  emit: (event) => {
807
505
  if (!terminalStarted) channel.emit({ ...event, runId });
@@ -896,12 +594,25 @@ function createToolRuntime(contributions) {
896
594
  );
897
595
  channel.emit({ kind: "started", runId, atMs: performance.now() });
898
596
  void (async () => {
899
- const parsedArgs = contribution.descriptor.argsSchema.parse(args);
900
- if (!parsedArgs.ok) {
901
- fail(invalidArgsError(parsedArgs.error, serializablePreview(args)));
902
- return;
903
- }
904
597
  try {
598
+ let parsedArgs;
599
+ try {
600
+ parsedArgs = contribution.descriptor.argsSchema.parse(args);
601
+ } catch (cause) {
602
+ await settle({
603
+ outcome: "failed",
604
+ failure: invalidArgsError(
605
+ cause instanceof Error ? cause.message : String(cause),
606
+ serializablePreview(args)
607
+ ),
608
+ artifacts: []
609
+ });
610
+ return;
611
+ }
612
+ if (!parsedArgs.ok) {
613
+ fail(invalidArgsError(parsedArgs.error, serializablePreview(args)));
614
+ return;
615
+ }
905
616
  if (options.signal?.aborted) {
906
617
  cancelReason = "aborted by caller";
907
618
  fail(cancellationError(cancelReason));
@@ -1021,12 +732,14 @@ function createToolRuntime(contributions) {
1021
732
  });
1022
733
  } finally {
1023
734
  if (timeout !== void 0) clearTimeout(timeout);
735
+ resolveExecutorExited();
1024
736
  }
1025
737
  })();
1026
738
  const runtimeRun = {
1027
739
  id: runId,
1028
740
  events: channel.events,
1029
741
  terminal,
742
+ executorExited,
1030
743
  cancel,
1031
744
  disconnect,
1032
745
  providerExit
@@ -1042,6 +755,670 @@ function createToolRuntime(contributions) {
1042
755
  return runtime;
1043
756
  }
1044
757
 
758
+ // src/api.ts
759
+ function assertName(value, label) {
760
+ if (typeof value !== "string" || !/^[a-zA-Z0-9][a-zA-Z0-9._:/-]*$/.test(value)) {
761
+ throw new TypeError(`${label} must be a stable non-empty identity`);
762
+ }
763
+ }
764
+ function operationPath(descriptor) {
765
+ return (descriptor.path ?? descriptor.id.split(".")).join(" ");
766
+ }
767
+ function providerKey(sourceId, providerId) {
768
+ return `${sourceId}\0${providerId}`;
769
+ }
770
+ function apiFailure(code, expected, hint, detail) {
771
+ return domainFailureError(code, expected, hint, detail);
772
+ }
773
+ function failedRun(failure) {
774
+ const id = `api:${crypto.randomUUID()}`;
775
+ const terminal = Promise.resolve({
776
+ outcome: "failed",
777
+ failure,
778
+ artifacts: []
779
+ });
780
+ const events = {
781
+ async *[Symbol.asyncIterator]() {
782
+ yield { kind: "started", runId: id, atMs: performance.now() };
783
+ yield { kind: "terminal", runId: id, outcome: "failed", atMs: performance.now() };
784
+ }
785
+ };
786
+ return {
787
+ id,
788
+ events,
789
+ terminal,
790
+ executorExited: Promise.resolve(),
791
+ cancel() {
792
+ },
793
+ disconnect() {
794
+ },
795
+ providerExit() {
796
+ }
797
+ };
798
+ }
799
+ function validateProvider(input) {
800
+ assertName(input.providerId, "providerId");
801
+ assertName(input.sourceId, "sourceId");
802
+ if (!["build", "host", "engine"].includes(input.realm))
803
+ throw new TypeError(`unsupported Tool API realm ${String(input.realm)}`);
804
+ if (!Array.isArray(input.tools) || input.tools.length === 0)
805
+ throw new TypeError("Tool API providers must publish at least one contribution");
806
+ const ids = /* @__PURE__ */ new Set();
807
+ const paths = /* @__PURE__ */ new Set();
808
+ if (input.initialState !== void 0 && input.initialState !== "pending" && input.initialState !== "active")
809
+ throw new TypeError("Tool API provider initialState must be pending or active");
810
+ for (const contribution of input.tools) {
811
+ if (contribution === null || typeof contribution !== "object")
812
+ throw new TypeError("Tool API contributions must be objects");
813
+ if (typeof contribution.execute !== "function")
814
+ throw new TypeError(
815
+ `Tool API contribution ${String(contribution.descriptor?.id)} needs an executor`
816
+ );
817
+ const descriptor = contribution.descriptor;
818
+ if (descriptor.realm !== input.realm)
819
+ throw new TypeError(
820
+ `Tool API ${descriptor.id} declares ${descriptor.realm} but provider is ${input.realm}`
821
+ );
822
+ if (ids.has(descriptor.id))
823
+ throw new TypeError(`duplicate Tool API operation id ${descriptor.id}`);
824
+ ids.add(descriptor.id);
825
+ const path = operationPath(descriptor);
826
+ if (paths.has(path)) throw new TypeError(`duplicate Tool API command path ${path}`);
827
+ paths.add(path);
828
+ }
829
+ }
830
+ function createToolApi() {
831
+ const providers = /* @__PURE__ */ new Map();
832
+ const listeners = /* @__PURE__ */ new Set();
833
+ let providerGeneration = 0;
834
+ let disposed = false;
835
+ const notify = () => {
836
+ const value = api.snapshot();
837
+ for (const listener of listeners) {
838
+ try {
839
+ listener(value);
840
+ } catch {
841
+ }
842
+ }
843
+ };
844
+ const snapshot = () => {
845
+ const providerSnapshots = [];
846
+ const operations = [];
847
+ for (const record of providers.values()) {
848
+ providerSnapshots.push({
849
+ owner: record.owner,
850
+ state: record.state,
851
+ ...record.fiberState === void 0 ? {} : { fiberState: record.fiberState },
852
+ callable: record.state === "active",
853
+ operationIds: record.input.tools.map(({ descriptor }) => descriptor.id)
854
+ });
855
+ for (const contribution of record.input.tools) {
856
+ operations.push({
857
+ descriptor: contribution.descriptor,
858
+ owner: record.owner,
859
+ providerState: record.state,
860
+ declared: true,
861
+ callable: record.state === "active",
862
+ ...record.fiberState === void 0 ? {} : { fiberState: record.fiberState }
863
+ });
864
+ }
865
+ }
866
+ providerSnapshots.sort(
867
+ (left, right) => providerKey(left.owner.sourceId, left.owner.providerId).localeCompare(
868
+ providerKey(right.owner.sourceId, right.owner.providerId)
869
+ )
870
+ );
871
+ operations.sort((left, right) => {
872
+ const source = left.owner.sourceId.localeCompare(right.owner.sourceId);
873
+ return source !== 0 ? source : left.descriptor.id.localeCompare(right.descriptor.id);
874
+ });
875
+ return { providers: providerSnapshots, operations };
876
+ };
877
+ const registerProvider = (input) => {
878
+ if (disposed) throw new Error("Tool API is disposed");
879
+ validateProvider(input);
880
+ const key = providerKey(input.sourceId, input.providerId);
881
+ if (providers.get(key)?.state === "active" || providers.get(key)?.state === "revoking") {
882
+ throw new TypeError(
883
+ `Tool API provider ${input.sourceId}/${input.providerId} is already registered`
884
+ );
885
+ }
886
+ const operationKeys = /* @__PURE__ */ new Set();
887
+ for (const contribution of input.tools) {
888
+ const operationKey = `${input.sourceId}\0${contribution.descriptor.id}`;
889
+ const pathKey2 = `${input.sourceId}\0${operationPath(contribution.descriptor)}`;
890
+ if (operationKeys.has(operationKey) || operationKeys.has(pathKey2))
891
+ throw new TypeError(`Tool API contribution conflict for ${contribution.descriptor.id}`);
892
+ operationKeys.add(operationKey);
893
+ operationKeys.add(pathKey2);
894
+ for (const record2 of providers.values()) {
895
+ if (!["pending", "active", "revoking"].includes(record2.state) || record2.owner.sourceId !== input.sourceId)
896
+ continue;
897
+ if (record2.input.tools.some(({ descriptor }) => descriptor.id === contribution.descriptor.id)) {
898
+ throw new TypeError(
899
+ `Tool API operation ${contribution.descriptor.id} already exists for source ${input.sourceId}`
900
+ );
901
+ }
902
+ if (record2.input.tools.some(
903
+ ({ descriptor }) => operationPath(descriptor) === operationPath(contribution.descriptor)
904
+ )) {
905
+ throw new TypeError(
906
+ `Tool API command path ${operationPath(contribution.descriptor)} already exists for source ${input.sourceId}`
907
+ );
908
+ }
909
+ }
910
+ }
911
+ const generation = input.generation ?? ++providerGeneration;
912
+ if (!Number.isSafeInteger(generation) || generation <= 0)
913
+ throw new TypeError("Tool API provider generation must be a positive integer");
914
+ providerGeneration = Math.max(providerGeneration, generation);
915
+ const owner = {
916
+ providerId: input.providerId,
917
+ sourceId: input.sourceId,
918
+ generation,
919
+ realm: input.realm,
920
+ ...input.fiberId === void 0 ? {} : { fiberId: input.fiberId },
921
+ ...input.module === void 0 ? {} : { module: input.module }
922
+ };
923
+ const runtime = createToolRuntime(input.tools);
924
+ const record = {
925
+ input: { ...input, tools: [...input.tools] },
926
+ owner,
927
+ runtime,
928
+ runs: /* @__PURE__ */ new Set(),
929
+ state: input.initialState ?? "active",
930
+ ...input.fiberState === void 0 ? {} : { fiberState: input.fiberState }
931
+ };
932
+ providers.set(key, record);
933
+ notify();
934
+ const activate = (fiberState = "active") => {
935
+ if (record.state !== "pending") return;
936
+ record.state = "active";
937
+ record.fiberState = fiberState;
938
+ notify();
939
+ };
940
+ const fail = (reason = "provider failed", fiberState = "failed") => {
941
+ if (record.state !== "pending" && record.state !== "active") return;
942
+ record.state = "failed";
943
+ record.reason = reason;
944
+ record.fiberState = fiberState;
945
+ for (const run2 of record.runs) run2.cancel(reason);
946
+ notify();
947
+ };
948
+ const revoke = async (reason = "provider revoked") => {
949
+ if (record.state === "revoked") return;
950
+ if (record.state === "active" || record.state === "pending") {
951
+ record.state = "revoking";
952
+ record.reason = reason;
953
+ record.fiberState = "unloading";
954
+ notify();
955
+ for (const run2 of record.runs) run2.cancel(reason);
956
+ }
957
+ await Promise.all([...record.runs].map((run2) => run2.executorExited));
958
+ if (record.state !== "failed") {
959
+ record.state = "revoked";
960
+ record.fiberState = "disposed";
961
+ }
962
+ notify();
963
+ };
964
+ return Object.freeze({
965
+ owner,
966
+ activate,
967
+ fail,
968
+ snapshot: () => ({
969
+ owner,
970
+ state: record.state,
971
+ ...record.fiberState === void 0 ? {} : { fiberState: record.fiberState },
972
+ callable: record.state === "active",
973
+ operationIds: record.input.tools.map(({ descriptor }) => descriptor.id)
974
+ }),
975
+ revoke
976
+ });
977
+ };
978
+ const findRecords = (id, sourceId) => [...providers.values()].filter(
979
+ (record) => (sourceId === void 0 || record.owner.sourceId === sourceId) && record.input.tools.some(({ descriptor }) => descriptor.id === id)
980
+ );
981
+ const run = (id, args, options = {}) => {
982
+ if (disposed) {
983
+ return failedRun(
984
+ apiFailure(
985
+ "api-disposed",
986
+ "the Tool API owner to remain available",
987
+ "Create a fresh owner and retry the operation.",
988
+ { operation: id }
989
+ )
990
+ );
991
+ }
992
+ if (options.providerId !== void 0 && options.sourceId === void 0) {
993
+ return failedRun(
994
+ apiFailure(
995
+ "api-source-required",
996
+ `operation ${id} to include its explicit sourceId with providerId`,
997
+ "Refresh Tool API sources and pass both sourceId and providerId from one snapshot.",
998
+ { operation: id, providerId: options.providerId }
999
+ )
1000
+ );
1001
+ }
1002
+ const matches = findRecords(id, options.sourceId);
1003
+ const active = matches.filter((record) => record.state === "active");
1004
+ const selected = options.providerId === void 0 ? active.length === 1 ? active[0] : void 0 : active.find((record) => record.owner.providerId === options.providerId);
1005
+ if (selected === void 0) {
1006
+ const code = matches.length === 0 || active.length === 0 ? "api-operation-unavailable" : "api-provider-route-required";
1007
+ return failedRun(
1008
+ apiFailure(
1009
+ code,
1010
+ `operation ${id} to have one active, explicitly routable provider`,
1011
+ "Refresh Tool API sources and select the providerId/sourceId returned by discovery.",
1012
+ {
1013
+ operation: id,
1014
+ ...options.providerId === void 0 ? {} : { providerId: options.providerId },
1015
+ providers: matches.map((record) => record.owner.providerId)
1016
+ }
1017
+ )
1018
+ );
1019
+ }
1020
+ if (options.generation !== void 0 && options.generation !== selected.owner.generation) {
1021
+ return failedRun(
1022
+ apiFailure(
1023
+ "api-stale-generation",
1024
+ `provider ${selected.owner.providerId} generation ${options.generation} to match ${selected.owner.generation}`,
1025
+ "Refresh the source snapshot before retrying the operation.",
1026
+ {
1027
+ operation: id,
1028
+ providerId: selected.owner.providerId,
1029
+ expectedGeneration: selected.owner.generation,
1030
+ actualGeneration: options.generation
1031
+ }
1032
+ )
1033
+ );
1034
+ }
1035
+ const contribution = selected.input.tools.find(({ descriptor }) => descriptor.id === id);
1036
+ if (contribution === void 0) {
1037
+ return failedRun(
1038
+ apiFailure(
1039
+ "api-operation-unavailable",
1040
+ `operation ${id} to remain published by its provider`,
1041
+ "Refresh Tool API sources before retrying.",
1042
+ { operation: id }
1043
+ )
1044
+ );
1045
+ }
1046
+ if (selected.input.authorize?.(options.caller, contribution.descriptor) === false) {
1047
+ return failedRun(
1048
+ apiFailure(
1049
+ "api-unauthorized",
1050
+ `caller to be authorized for operation ${id}`,
1051
+ "Use the authenticated Host connection and the capability it was granted.",
1052
+ { operation: id, providerId: selected.owner.providerId }
1053
+ )
1054
+ );
1055
+ }
1056
+ const runOptions = {
1057
+ ...options,
1058
+ owner: selected.owner,
1059
+ ...options.caller === void 0 ? {} : { caller: options.caller }
1060
+ };
1061
+ const activeRun = selected.runtime.run(contribution, args, runOptions);
1062
+ selected.runs.add(activeRun);
1063
+ void activeRun.executorExited.finally(
1064
+ () => selected.runs.delete(activeRun)
1065
+ );
1066
+ return activeRun;
1067
+ };
1068
+ const api = {
1069
+ snapshot,
1070
+ list: () => snapshot().operations,
1071
+ describe: (id, sourceId) => findRecords(id, sourceId).flatMap((record) => {
1072
+ const contribution = record.input.tools.find(({ descriptor }) => descriptor.id === id);
1073
+ return contribution === void 0 ? [] : [
1074
+ {
1075
+ descriptor: contribution.descriptor,
1076
+ owner: record.owner,
1077
+ providerState: record.state,
1078
+ declared: true,
1079
+ callable: record.state === "active",
1080
+ ...record.fiberState === void 0 ? {} : { fiberState: record.fiberState }
1081
+ }
1082
+ ];
1083
+ }),
1084
+ registerProvider,
1085
+ run,
1086
+ subscribe(listener) {
1087
+ listeners.add(listener);
1088
+ return () => listeners.delete(listener);
1089
+ },
1090
+ async dispose() {
1091
+ if (disposed) return;
1092
+ disposed = true;
1093
+ const pending = [...providers.values()].map((record) => {
1094
+ if (record.state === "active" || record.state === "pending") {
1095
+ record.state = "revoking";
1096
+ record.fiberState = "unloading";
1097
+ for (const run2 of record.runs) run2.cancel("Tool API owner disposed");
1098
+ }
1099
+ return Promise.all([...record.runs].map((run2) => run2.executorExited)).then(() => {
1100
+ if (record.state !== "failed") {
1101
+ record.state = "revoked";
1102
+ record.fiberState = "disposed";
1103
+ }
1104
+ });
1105
+ });
1106
+ await Promise.all(pending);
1107
+ notify();
1108
+ listeners.clear();
1109
+ }
1110
+ };
1111
+ return api;
1112
+ }
1113
+
1114
+ // src/capability.ts
1115
+ var capabilityIdPattern = /^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/;
1116
+ function defineToolCapability(id) {
1117
+ if (!capabilityIdPattern.test(id)) {
1118
+ throw new TypeError(`Tool capability id must use a stable lower-case path: ${id}`);
1119
+ }
1120
+ return Object.freeze({ id });
1121
+ }
1122
+ function createCapabilityResolver(resolve) {
1123
+ return (capability) => {
1124
+ const value = resolve(capability);
1125
+ return value === void 0 ? void 0 : { ok: true, value };
1126
+ };
1127
+ }
1128
+ function admissionFailure(admission, expected) {
1129
+ if (admission === void 0) return "no workload-scoped admission report was supplied";
1130
+ if (admission.schema !== "forgeax.tool-service-admission-ref.v1" || !/^sha256:[0-9a-f]{64}$/.test(admission.reportDigest)) {
1131
+ return "admission report identity is invalid";
1132
+ }
1133
+ for (const key of [
1134
+ "toolId",
1135
+ "descriptorDigest",
1136
+ "recipeDigest",
1137
+ "workloadClass",
1138
+ "codeDigest",
1139
+ "browserVersion",
1140
+ "backend"
1141
+ ]) {
1142
+ if (admission[key] !== expected[key]) return `admission ${key} does not match this run`;
1143
+ }
1144
+ if (admission.frameCount < 300) return "admission workload ran fewer than 300 frames";
1145
+ if (Object.values(admission.samples).some((count) => count < 30)) {
1146
+ return "admission sample set is incomplete";
1147
+ }
1148
+ if (!admission.correctness.terminalEquivalent || !admission.correctness.artifactIntegrity || !admission.correctness.freshReplay || !admission.correctness.hiddenParity || admission.correctness.drawCalls <= 0 || admission.correctness.nonBlackPixels <= 0) {
1149
+ return "admission correctness gate failed";
1150
+ }
1151
+ const performance2 = admission.performance;
1152
+ if (Object.values(performance2).some((value) => !Number.isFinite(value) || value <= 0) || performance2.serviceMedianMs > performance2.privateMedianMs * 0.8 || performance2.serviceP95Ms > performance2.privateP95Ms * 0.9 || performance2.serviceMaxMs > performance2.privateMaxMs * 1.1 || performance2.serviceRssBytes > performance2.privateRssBytes * 1.25) {
1153
+ return "admission performance threshold failed";
1154
+ }
1155
+ if (!admission.cleanupPassed) return "admission cleanup gate failed";
1156
+ if (!admission.evictionPassed) return "admission eviction gate failed";
1157
+ return void 0;
1158
+ }
1159
+ function createServiceCapability(admission, expected) {
1160
+ const reason = admissionFailure(admission, expected);
1161
+ if (reason === void 0 && admission !== void 0) {
1162
+ return { available: true, reportDigest: admission.reportDigest };
1163
+ }
1164
+ return {
1165
+ available: false,
1166
+ code: "tool-service-capability-absent",
1167
+ expected: "an admitted acceleration service",
1168
+ hint: "Use the private executor and rerun benchmark admission before enabling service.",
1169
+ detail: { reason: reason ?? "benchmark admission did not pass" }
1170
+ };
1171
+ }
1172
+ function createRealmCapabilityMatrix(input) {
1173
+ const realms = ["build", "host", "engine"].reduce(
1174
+ (result, realm) => {
1175
+ const supported = input.supported[realm];
1176
+ result[realm] = supported ? { realm, supported: true } : { realm, supported: false, reason: "realm-capability-unavailable" };
1177
+ return result;
1178
+ },
1179
+ {}
1180
+ );
1181
+ return { catalogDigest: input.catalogDigest, realms };
1182
+ }
1183
+ function bootstrapNotCloneSafeError(detail) {
1184
+ return {
1185
+ code: "tool-bootstrap-not-clone-safe",
1186
+ expected: "bootstrap input to contain structured-clone-safe data",
1187
+ hint: "Remove live handles, functions, ports, and realm-owned objects from bootstrap input.",
1188
+ detail
1189
+ };
1190
+ }
1191
+ function validateRealmBootstrapPayload(value) {
1192
+ try {
1193
+ structuredClone(value);
1194
+ return { ok: true };
1195
+ } catch (cause) {
1196
+ return {
1197
+ ok: false,
1198
+ error: bootstrapNotCloneSafeError({
1199
+ message: cause instanceof Error ? cause.message : String(cause)
1200
+ })
1201
+ };
1202
+ }
1203
+ }
1204
+
1205
+ // src/carrier.ts
1206
+ function token() {
1207
+ return crypto.randomUUID().replaceAll("-", "");
1208
+ }
1209
+ function carrierError(code, expected, hint, detail) {
1210
+ return { code, expected, hint, detail };
1211
+ }
1212
+ function containsLiveKey(value, seen = /* @__PURE__ */ new Set()) {
1213
+ if (typeof value !== "object" || value === null) return false;
1214
+ if (seen.has(value)) return false;
1215
+ seen.add(value);
1216
+ if (Array.isArray(value)) return value.some((entry) => containsLiveKey(entry, seen));
1217
+ return Object.entries(value).some(([key, nested]) => {
1218
+ if (["world", "renderer", "canvas", "ui", "profile", "liveHandle", "context", "fiber"].includes(
1219
+ key
1220
+ ))
1221
+ return true;
1222
+ return containsLiveKey(nested, seen);
1223
+ });
1224
+ }
1225
+ function validateOptions(options) {
1226
+ if (options.projectId.length === 0 || options.consumerId.length === 0) {
1227
+ throw new TypeError("carrier projectId and consumerId must not be empty");
1228
+ }
1229
+ const endpoint = new URL(options.endpoint);
1230
+ if (endpoint.protocol !== "http:" || !["127.0.0.1", "localhost"].includes(endpoint.hostname)) {
1231
+ throw new TypeError("carrier endpoint must be loopback HTTP");
1232
+ }
1233
+ if (!Number.isFinite(options.now) || !Number.isFinite(options.ttlMs) || options.ttlMs <= 0) {
1234
+ throw new TypeError("carrier clock and ttl must be finite and positive");
1235
+ }
1236
+ if (containsLiveKey(options.payload)) throw new TypeError("carrier-payload-live-state");
1237
+ }
1238
+ function createCarrierStateMachine(options) {
1239
+ validateOptions(options);
1240
+ const offer = {
1241
+ schemaVersion: "1.0.0",
1242
+ projectId: options.projectId,
1243
+ consumerId: options.consumerId,
1244
+ offerId: `offer:${token()}`,
1245
+ endpoint: options.endpoint,
1246
+ bearerToken: token(),
1247
+ livenessToken: token(),
1248
+ expiresAt: options.now + options.ttlMs,
1249
+ ...options.descriptorDigest === void 0 ? {} : { descriptorDigest: options.descriptorDigest },
1250
+ ...options.recipeDigest === void 0 ? {} : { recipeDigest: options.recipeDigest },
1251
+ state: "offered"
1252
+ };
1253
+ let state = { state: "offered" };
1254
+ let lease;
1255
+ const leaseOffer = (requestOrId, maybeRequest) => {
1256
+ const request = typeof requestOrId === "string" ? maybeRequest : requestOrId;
1257
+ const requestedLeaseId = typeof requestOrId === "string" ? requestOrId : void 0;
1258
+ if (request === void 0) {
1259
+ return {
1260
+ ok: false,
1261
+ error: carrierError(
1262
+ "carrier-token-invalid",
1263
+ "a complete lease request",
1264
+ "Provide consumer identity, bearer token, and current time.",
1265
+ {}
1266
+ )
1267
+ };
1268
+ }
1269
+ if (state.state === "started") {
1270
+ return {
1271
+ ok: false,
1272
+ error: carrierError(
1273
+ "carrier-started",
1274
+ "a started carrier not to be retried",
1275
+ "Report one terminal failure and clean up the existing started lease.",
1276
+ {}
1277
+ )
1278
+ };
1279
+ }
1280
+ if (state.state === "exited") {
1281
+ return {
1282
+ ok: false,
1283
+ error: carrierError(
1284
+ "carrier-exited",
1285
+ "an exited carrier not to be retried",
1286
+ "Re-run the operation from a serialized snapshot instead of migrating live state.",
1287
+ {}
1288
+ )
1289
+ };
1290
+ }
1291
+ if (request.consumerId !== offer.consumerId) {
1292
+ return {
1293
+ ok: false,
1294
+ error: carrierError(
1295
+ "carrier-consumer-mismatch",
1296
+ "the offer consumer identity to match",
1297
+ "Use the consumer identity that was authenticated for this project offer.",
1298
+ { expected: offer.consumerId, actual: request.consumerId }
1299
+ )
1300
+ };
1301
+ }
1302
+ if (request.bearerToken !== offer.bearerToken) {
1303
+ return {
1304
+ ok: false,
1305
+ error: carrierError(
1306
+ "carrier-token-invalid",
1307
+ "the bearer token to match the ephemeral offer",
1308
+ "Request a fresh visible offer; never persist or guess bearer tokens.",
1309
+ {}
1310
+ )
1311
+ };
1312
+ }
1313
+ if (offer.descriptorDigest !== void 0 && request.descriptorDigest !== offer.descriptorDigest) {
1314
+ return {
1315
+ ok: false,
1316
+ error: carrierError(
1317
+ "carrier-descriptor-mismatch",
1318
+ "the descriptor digest to match the authenticated offer",
1319
+ "Refresh the descriptor and request a new visible offer before retrying.",
1320
+ { expected: offer.descriptorDigest, actual: request.descriptorDigest }
1321
+ )
1322
+ };
1323
+ }
1324
+ if (offer.recipeDigest !== void 0 && request.recipeDigest !== offer.recipeDigest) {
1325
+ return {
1326
+ ok: false,
1327
+ error: carrierError(
1328
+ "carrier-recipe-mismatch",
1329
+ "the recipe digest to match the authenticated offer",
1330
+ "Serialize the current snapshot and request a fresh visible offer before retrying.",
1331
+ { expected: offer.recipeDigest, actual: request.recipeDigest }
1332
+ )
1333
+ };
1334
+ }
1335
+ if (request.now >= offer.expiresAt) {
1336
+ state = { state: "expired" };
1337
+ return {
1338
+ ok: false,
1339
+ error: carrierError(
1340
+ "carrier-offer-expired",
1341
+ "the offer to be within its expiry window",
1342
+ "Fall back to the ordinary visible carrier before retrying.",
1343
+ { expiresAt: offer.expiresAt, now: request.now }
1344
+ )
1345
+ };
1346
+ }
1347
+ if (requestedLeaseId !== void 0 && requestedLeaseId !== lease?.leaseId) {
1348
+ return {
1349
+ ok: false,
1350
+ error: carrierError(
1351
+ "carrier-token-invalid",
1352
+ "the lease id to match the authenticated offer",
1353
+ "Use the lease id returned by the first successful lease.",
1354
+ {}
1355
+ )
1356
+ };
1357
+ }
1358
+ lease = {
1359
+ leaseId: `lease:${token()}`,
1360
+ offerId: offer.offerId,
1361
+ consumerId: request.consumerId,
1362
+ state: "leased"
1363
+ };
1364
+ state = { state: "leased", leaseId: lease.leaseId };
1365
+ return { ok: true, value: lease, state: "leased" };
1366
+ };
1367
+ const started = (leaseId) => {
1368
+ if (lease?.leaseId !== leaseId) {
1369
+ return {
1370
+ ok: false,
1371
+ error: carrierError(
1372
+ "carrier-lease-required",
1373
+ "a valid lease before started",
1374
+ "Lease the authenticated offer before reporting provider started.",
1375
+ {}
1376
+ )
1377
+ };
1378
+ }
1379
+ state = { state: "started", leaseId };
1380
+ return { ok: true, value: state, state: "started" };
1381
+ };
1382
+ const exit = (leaseId) => {
1383
+ if (lease?.leaseId !== leaseId || state.state !== "started") {
1384
+ return {
1385
+ ok: false,
1386
+ error: carrierError(
1387
+ "carrier-lease-required",
1388
+ "a started lease before provider exit",
1389
+ "Provider exit is terminal only after started has been acknowledged.",
1390
+ {}
1391
+ )
1392
+ };
1393
+ }
1394
+ state = { state: "exited", leaseId };
1395
+ return { ok: true, value: state, state: "exited" };
1396
+ };
1397
+ const fallback = () => {
1398
+ if (state.state === "started" || state.state === "exited") {
1399
+ return {
1400
+ ok: false,
1401
+ error: carrierError(
1402
+ "carrier-started",
1403
+ "fallback to happen before provider started",
1404
+ "Do not retry or migrate a carrier after started; return its terminal failure.",
1405
+ { state: state.state }
1406
+ )
1407
+ };
1408
+ }
1409
+ state = { state: "fallback" };
1410
+ return { ok: true, value: state, state: "fallback" };
1411
+ };
1412
+ return {
1413
+ offer,
1414
+ lease: leaseOffer,
1415
+ started,
1416
+ exit,
1417
+ fallback,
1418
+ snapshot: () => state
1419
+ };
1420
+ }
1421
+
1045
1422
  // src/command-tree.ts
1046
1423
  var ToolCommandError = class extends Error {
1047
1424
  code;
@@ -1543,6 +1920,6 @@ function createAuthenticatedLoopbackTransport(options) {
1543
1920
  };
1544
1921
  }
1545
1922
 
1546
- export { CarrierTransportError, ToolCommandError, artifactIncompleteError, cancellationError, capabilityUnavailableError, cleanupError, commandPath, createArtifactManifest, createArtifactRef, createAuthenticatedCarrierTransport, createAuthenticatedLoopbackTransport, createCapabilityResolver, createCapabilityToken, createCarrierStateMachine, createExclusiveTiming, createLexicalLease, createLoopbackTransport, createMigrationRecipe, createPreviewArtifactManifest, createRealmCapabilityMatrix, createServiceCapability, createSnapshotRef, createToolCommandRegistry, createToolRuntime, defineCommand, defineTool, defineToolCapability, disconnectedError, domainFailureError, finishToolTiming, invalidArgsError, isSerializableValue, isSnapshotRef, parseToolJsonSchema, probeMigrationTarget, snapshotStaleError, startToolTiming, terminalError, terminalSnapshot, timeoutError, toolJsonSchema, validateArtifactManifest, validateArtifactRefs, validateMigrationPayload, validatePreviewArtifactManifest, validateRealmBootstrapPayload };
1923
+ export { CarrierTransportError, ToolCommandError, artifactIncompleteError, cancellationError, capabilityUnavailableError, cleanupError, commandPath, createArtifactManifest, createArtifactRef, createAuthenticatedCarrierTransport, createAuthenticatedLoopbackTransport, createCapabilityResolver, createCapabilityToken, createCarrierStateMachine, createExclusiveTiming, createLexicalLease, createLoopbackTransport, createMigrationRecipe, createPreviewArtifactManifest, createRealmCapabilityMatrix, createServiceCapability, createSnapshotRef, createToolApi, createToolCommandRegistry, createToolRuntime, defineCommand, defineTool, defineToolCapability, disconnectedError, domainFailureError, finishToolTiming, invalidArgsError, isSerializableValue, isSnapshotRef, parseToolJsonSchema, probeMigrationTarget, snapshotStaleError, startToolTiming, terminalError, terminalSnapshot, timeoutError, toolJsonSchema, validateArtifactManifest, validateArtifactRefs, validateMigrationPayload, validatePreviewArtifactManifest, validateRealmBootstrapPayload };
1547
1924
  //# sourceMappingURL=index.mjs.map
1548
1925
  //# sourceMappingURL=index.mjs.map