@cueai/omni-reader-mcp 1.5.4 → 1.6.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.
@@ -4,7 +4,7 @@ import { homedir } from "node:os";
4
4
  import path from "node:path";
5
5
  import { OmniBridgeError } from "./errors.js";
6
6
  import { GROUNDING_SCHEMA_VERSION, RESULT_BUNDLE_PROTOCOL_VERSION, normalizeRepresentation, } from "./protocol.js";
7
- // D2-D item 4-6: v3 records persist keyed identities instead of unkeyed
7
+ // D2-D item 4-6: v3/v4 records persist keyed identities instead of unkeyed
8
8
  // request/source hashes. requestIdentityHmac and sourceLocatorHmac are
9
9
  // lowercase full hex of HMAC-SHA-256 over the journal secret with the exact
10
10
  // domain prefixes below; they are never returned in tool output and never
@@ -43,6 +43,10 @@ const PERSISTED_V3_KEYS = [
43
43
  "resultExpiresAt",
44
44
  "errorCode",
45
45
  ];
46
+ const PERSISTED_V4_KEYS = [
47
+ ...PERSISTED_V3_KEYS,
48
+ "result_delivery_effective",
49
+ ];
46
50
  const JOURNAL_STATES = new Set([
47
51
  "CREATED",
48
52
  "GRANT_PENDING",
@@ -81,6 +85,7 @@ const DELIVERY_STATES = new Set([
81
85
  "pending",
82
86
  "deleted_after_ack",
83
87
  ]);
88
+ const RESULT_DELIVERIES = new Set(["auto", "artifact"]);
84
89
  const RECORD_FILE_PATTERN = /^[0-9a-f]{64}(?:\.issued)?\.json$/u;
85
90
  const LOCK_STALE_MS = 30_000;
86
91
  const HEX_64_PATTERN = /^[0-9a-f]{64}$/u;
@@ -255,6 +260,26 @@ function parseVersionThreeRecord(value) {
255
260
  }
256
261
  return value;
257
262
  }
263
+ function parseVersionFourRecord(value) {
264
+ const keys = Object.keys(value);
265
+ if (keys.length !== PERSISTED_V4_KEYS.length ||
266
+ PERSISTED_V4_KEYS.some((key) => !(key in value)) ||
267
+ value.version !== 4 ||
268
+ typeof value.result_delivery_effective !== "string" ||
269
+ !RESULT_DELIVERIES.has(value.result_delivery_effective)) {
270
+ throw new Error("version-4 record fields are invalid");
271
+ }
272
+ const { result_delivery_effective, ...versionThreeFields } = value;
273
+ const validated = parseVersionThreeRecord({
274
+ ...versionThreeFields,
275
+ version: 3,
276
+ });
277
+ return {
278
+ ...validated,
279
+ version: 4,
280
+ result_delivery_effective: result_delivery_effective,
281
+ };
282
+ }
258
283
  function parsePersistedRecord(value) {
259
284
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
260
285
  throw new Error("record is not an object");
@@ -266,12 +291,14 @@ function parsePersistedRecord(value) {
266
291
  return parseVersionTwoRecord(record);
267
292
  if (record.version === 3)
268
293
  return parseVersionThreeRecord(record);
294
+ if (record.version === 4)
295
+ return parseVersionFourRecord(record);
269
296
  throw new Error("record version is invalid");
270
297
  }
271
298
  function migrateInMemory(stored) {
272
- if (stored.version === 3) {
299
+ if (stored.version === 3 || stored.version === 4) {
273
300
  return {
274
- version: 3,
301
+ version: 4,
275
302
  clientRequestId: stored.clientRequestId,
276
303
  requestIdentityHmac: stored.requestIdentityHmac,
277
304
  sourceLocatorHmac: stored.sourceLocatorHmac,
@@ -282,6 +309,9 @@ function migrateInMemory(stored) {
282
309
  detail: stored.detail,
283
310
  groundingSchemaVersion: stored.groundingSchemaVersion,
284
311
  bundleProtocolVersion: stored.bundleProtocolVersion,
312
+ resultDeliveryEffective: stored.version === 4
313
+ ? stored.result_delivery_effective
314
+ : "auto",
285
315
  operationId: stored.operationId,
286
316
  operationToken: stored.operationToken,
287
317
  state: stored.state,
@@ -308,7 +338,7 @@ function migrateInMemory(stored) {
308
338
  // are recomputed only when safe canonical source facts reconstruct the
309
339
  // stored unkeyed requestHash (see #reconstructLegacy).
310
340
  return {
311
- version: 3,
341
+ version: 4,
312
342
  clientRequestId: stored.clientRequestId,
313
343
  requestIdentityHmac: null,
314
344
  sourceLocatorHmac: null,
@@ -319,6 +349,7 @@ function migrateInMemory(stored) {
319
349
  detail: "text",
320
350
  groundingSchemaVersion: "none",
321
351
  bundleProtocolVersion: "none",
352
+ resultDeliveryEffective: "auto",
322
353
  operationId: stored.operationId,
323
354
  operationToken: stored.operationToken,
324
355
  state: stored.state,
@@ -341,7 +372,7 @@ function migrateInMemory(stored) {
341
372
  };
342
373
  }
343
374
  return {
344
- version: 3,
375
+ version: 4,
345
376
  clientRequestId: stored.clientRequestId,
346
377
  requestIdentityHmac: null,
347
378
  sourceLocatorHmac: null,
@@ -352,6 +383,7 @@ function migrateInMemory(stored) {
352
383
  detail: "text",
353
384
  groundingSchemaVersion: "none",
354
385
  bundleProtocolVersion: "none",
386
+ resultDeliveryEffective: "auto",
355
387
  operationId: stored.operationId,
356
388
  operationToken: stored.operationToken,
357
389
  state: stored.state,
@@ -428,6 +460,10 @@ function assertStableTransition(current, updated) {
428
460
  throw bridgeError("JOURNAL_FACT_REGRESSION", "A confirmed local operation fact cannot be reverted.", false);
429
461
  }
430
462
  }
463
+ if (current.resultDeliveryEffective === "artifact" &&
464
+ updated.resultDeliveryEffective !== "artifact") {
465
+ throw bridgeError("JOURNAL_RESULT_DELIVERY_REGRESSION", "Artifact result delivery cannot be weakened to automatic delivery.", false);
466
+ }
431
467
  }
432
468
  function hmacEqual(left, right) {
433
469
  if (left.length !== right.length)
@@ -451,19 +487,22 @@ export class OperationJournal {
451
487
  async sourceLocatorHmac(sourceLocator) {
452
488
  return this.#hmac(SOURCE_LOCATOR_DOMAIN, sourceLocator);
453
489
  }
454
- // v3 intent creation. canonicalIdentityJson is the exact canonical
490
+ // v4 intent creation. canonicalIdentityJson is the exact canonical
455
491
  // serialization of {source_kind, source_facts} (which includes the
456
492
  // normalized representation tuple); the journal derives the keyed identity
457
493
  // from it and persists only the HMAC, never the payload or any unkeyed hash.
458
- async beginIntent(clientRequestId, canonicalIdentityJson, sourceKind = "local", sourceLocator = null, representation = TEXT_REPRESENTATION) {
494
+ async beginIntent(clientRequestId, canonicalIdentityJson, sourceKind = "local", sourceLocator = null, representation = TEXT_REPRESENTATION, resultDelivery = "auto") {
459
495
  validateClientRequestId(clientRequestId);
496
+ if (!RESULT_DELIVERIES.has(resultDelivery)) {
497
+ throw bridgeError("INVALID_RESULT_DELIVERY", "The result delivery mode is invalid.", false);
498
+ }
460
499
  const existing = await this.#readRecord(clientRequestId);
461
500
  if (existing !== null) {
462
501
  return this.#requireMatchingRequest(clientRequestId, canonicalIdentityJson, sourceLocator, existing);
463
502
  }
464
503
  const createdAt = this.#now().toISOString();
465
504
  const created = {
466
- version: 3,
505
+ version: 4,
467
506
  clientRequestId,
468
507
  requestIdentityHmac: await this.#hmac(REQUEST_IDENTITY_DOMAIN, canonicalIdentityJson),
469
508
  sourceLocatorHmac: sourceLocator === null
@@ -476,6 +515,7 @@ export class OperationJournal {
476
515
  detail: representation.detail,
477
516
  groundingSchemaVersion: representation.groundingSchemaVersion,
478
517
  bundleProtocolVersion: representation.bundleProtocolVersion,
518
+ resultDeliveryEffective: resultDelivery,
479
519
  operationId: null,
480
520
  operationToken: null,
481
521
  state: "CREATED",
@@ -507,7 +547,7 @@ export class OperationJournal {
507
547
  }
508
548
  // Migrate a legacy v1/v2 record using the caller's safe canonical source
509
549
  // facts. When the facts reconstruct the stored unkeyed requestHash, the
510
- // record migrates to v3 (durably) with domain-separated HMACs and keeps its
550
+ // record migrates to v4 (durably) with domain-separated HMACs and keeps its
511
551
  // state; otherwise it becomes a terminal source-free recovery failure and
512
552
  // never copies the unkeyed hashes. Returns null when no record exists.
513
553
  async migrateLegacyRecord(clientRequestId, canonicalIdentityJson, sourceLocator = null) {
@@ -515,8 +555,9 @@ export class OperationJournal {
515
555
  const stored = await this.#readRecord(clientRequestId);
516
556
  if (stored === null)
517
557
  return null;
518
- if (stored.version === 3)
558
+ if (stored.version === 3 || stored.version === 4) {
519
559
  return this.#recordToPublic(clientRequestId, stored);
560
+ }
520
561
  const expected = `sha256:${createHash("sha256").update(canonicalIdentityJson, "utf8").digest("hex")}`;
521
562
  if (stored.requestHash === expected) {
522
563
  const migrated = await this.#reconstructLegacy(stored, canonicalIdentityJson, sourceLocator);
@@ -559,6 +600,31 @@ export class OperationJournal {
559
600
  return updated;
560
601
  });
561
602
  }
603
+ async strengthenResultDelivery(clientRequestId, requested) {
604
+ validateClientRequestId(clientRequestId);
605
+ if (!RESULT_DELIVERIES.has(requested)) {
606
+ throw bridgeError("INVALID_RESULT_DELIVERY", "The result delivery mode is invalid.", false);
607
+ }
608
+ return this.#withRecordLock(clientRequestId, async () => {
609
+ const stored = await this.#readRecord(clientRequestId);
610
+ if (stored === null) {
611
+ throw bridgeError("JOURNAL_RECORD_NOT_FOUND", "The local operation journal record is missing.", true);
612
+ }
613
+ const current = await this.#recordToPublic(clientRequestId, stored);
614
+ if (requested === "auto" || current.resultDeliveryEffective === "artifact") {
615
+ return current;
616
+ }
617
+ const updated = {
618
+ ...current,
619
+ resultDeliveryEffective: "artifact",
620
+ updatedAt: this.#now().toISOString(),
621
+ };
622
+ assertStableTransition(current, updated);
623
+ await this.#replaceRecord(await this.#persistedRecord(updated), this.#recordPath(clientRequestId));
624
+ await unlink(this.#legacyIssuedRecordPath(clientRequestId)).catch(() => undefined);
625
+ return updated;
626
+ });
627
+ }
562
628
  async loadByRequestId(clientRequestId) {
563
629
  validateClientRequestId(clientRequestId);
564
630
  const persisted = await this.#readRecord(clientRequestId);
@@ -592,7 +658,7 @@ export class OperationJournal {
592
658
  // the journal receives, so the keyed handle is derived over that value.
593
659
  const createdAt = this.#now().toISOString();
594
660
  const created = {
595
- version: 3,
661
+ version: 4,
596
662
  clientRequestId,
597
663
  requestIdentityHmac: await this.#hmac(REQUEST_IDENTITY_DOMAIN, requestHash),
598
664
  sourceLocatorHmac: null,
@@ -603,6 +669,7 @@ export class OperationJournal {
603
669
  detail: "text",
604
670
  groundingSchemaVersion: "none",
605
671
  bundleProtocolVersion: "none",
672
+ resultDeliveryEffective: "auto",
606
673
  operationId: null,
607
674
  operationToken: null,
608
675
  state: "CREATED",
@@ -698,7 +765,7 @@ export class OperationJournal {
698
765
  }
699
766
  async #persistedRecord(record) {
700
767
  return {
701
- version: 3,
768
+ version: 4,
702
769
  clientRequestId: record.clientRequestId,
703
770
  // A legacy record persisted before reconstruction (for example a
704
771
  // source-free recovery failure) gets the deterministic keyed handle of
@@ -711,6 +778,7 @@ export class OperationJournal {
711
778
  detail: record.detail,
712
779
  groundingSchemaVersion: record.groundingSchemaVersion,
713
780
  bundleProtocolVersion: record.bundleProtocolVersion,
781
+ result_delivery_effective: record.resultDeliveryEffective,
714
782
  operationId: record.operationId,
715
783
  operationToken: record.operationToken === null
716
784
  ? null
@@ -736,7 +804,7 @@ export class OperationJournal {
736
804
  }
737
805
  async #persistedFromInMemory(record) {
738
806
  return {
739
- version: 3,
807
+ version: 4,
740
808
  clientRequestId: record.clientRequestId,
741
809
  requestIdentityHmac: record.requestIdentityHmac === null
742
810
  ? await this.#hmac(REQUEST_IDENTITY_DOMAIN, "")
@@ -746,6 +814,7 @@ export class OperationJournal {
746
814
  detail: record.detail,
747
815
  groundingSchemaVersion: record.groundingSchemaVersion,
748
816
  bundleProtocolVersion: record.bundleProtocolVersion,
817
+ result_delivery_effective: record.resultDeliveryEffective,
749
818
  operationId: record.operationId,
750
819
  operationToken: record.operationToken,
751
820
  state: record.state,
@@ -784,6 +853,7 @@ export class OperationJournal {
784
853
  detail: migrated.detail,
785
854
  groundingSchemaVersion: migrated.groundingSchemaVersion,
786
855
  bundleProtocolVersion: migrated.bundleProtocolVersion,
856
+ resultDeliveryEffective: migrated.resultDeliveryEffective,
787
857
  operationId: migrated.operationId,
788
858
  operationToken,
789
859
  uploadUrl: migrated.uploadUrl,
@@ -819,7 +889,7 @@ export class OperationJournal {
819
889
  return migrated;
820
890
  }
821
891
  async #requireMatchingRequest(clientRequestId, canonicalIdentityJson, sourceLocator, persisted) {
822
- if (persisted.version === 3) {
892
+ if (persisted.version === 3 || persisted.version === 4) {
823
893
  const expected = await this.#hmacExisting(REQUEST_IDENTITY_DOMAIN, canonicalIdentityJson);
824
894
  if (!hmacEqual(persisted.requestIdentityHmac, expected)) {
825
895
  throw bridgeError("IDEMPOTENCY_COLLISION", "This local operation request identifier is already bound to different metadata.", false);
@@ -833,7 +903,7 @@ export class OperationJournal {
833
903
  throw bridgeError("IDEMPOTENCY_COLLISION", "This local operation request identifier is already bound to different metadata.", false);
834
904
  }
835
905
  async #requireMatchingCubeRequest(clientRequestId, requestHash, persisted) {
836
- if (persisted.version === 3) {
906
+ if (persisted.version === 3 || persisted.version === 4) {
837
907
  const expected = await this.#hmacExisting(REQUEST_IDENTITY_DOMAIN, requestHash);
838
908
  if (!hmacEqual(persisted.requestIdentityHmac, expected)) {
839
909
  throw bridgeError("IDEMPOTENCY_COLLISION", "This local operation request identifier is already bound to different metadata.", false);
@@ -3,7 +3,7 @@ import type { CubeGrantClient } from "./cube-client.js";
3
3
  import type { IiisClient, ResultRetentionSink } from "./iiis-client.js";
4
4
  import type { JournalPatch, JournalRecord, JournalState, OperationJournal } from "./operation-journal.js";
5
5
  import { type OpenAllowedFileOptions, type OpenedAllowedFile } from "./path-security.js";
6
- import { type RepresentationIntent } from "./protocol.js";
6
+ import { type RepresentationIntent, type ResultDelivery } from "./protocol.js";
7
7
  import type { RemoteOmniClient } from "./remote-client.js";
8
8
  import { type ParseResult } from "./result-contract.js";
9
9
  export interface SubmitOperationInput {
@@ -12,6 +12,7 @@ export interface SubmitOperationInput {
12
12
  readonly clientRequestId: string;
13
13
  readonly signal?: AbortSignal;
14
14
  readonly context?: unknown;
15
+ readonly resultDelivery?: ResultDelivery;
15
16
  readonly representation?: RepresentationIntent;
16
17
  }
17
18
  export interface OperationDriverUpdate {
@@ -38,8 +39,9 @@ export interface OperationManagerDriver {
38
39
  result?(record: JournalRecord, signal: AbortSignal): Promise<ParseResult | void>;
39
40
  }
40
41
  export interface OperationManagerOptions {
41
- readonly journal: Pick<OperationJournal, "beginIntent" | "migrateLegacyRecord" | "requestIdentityHmac" | "sourceLocatorHmac" | "transition" | "loadByRequestId" | "loadByOperationId" | "loadLatestByRequestIdentityHmac" | "loadLatestBySourceLocatorHmac" | "listRecoverable">;
42
+ readonly journal: Pick<OperationJournal, "beginIntent" | "migrateLegacyRecord" | "requestIdentityHmac" | "sourceLocatorHmac" | "transition" | "loadByRequestId" | "loadByOperationId" | "loadLatestByRequestIdentityHmac" | "loadLatestBySourceLocatorHmac" | "listRecoverable" | "strengthenResultDelivery">;
42
43
  readonly driver: OperationManagerDriver;
44
+ readonly presentResult?: (record: JournalRecord, canonicalResult: ParseResult) => Promise<ParseResult>;
43
45
  readonly now?: () => number;
44
46
  readonly sleep?: (milliseconds: number) => Promise<void>;
45
47
  }
@@ -61,6 +63,8 @@ export interface LocalRetention extends ResultRetentionSink {
61
63
  }
62
64
  export interface LocalArtifactStore {
63
65
  createRetention(): LocalRetention;
66
+ preflightWrite?(): Promise<void>;
67
+ mintReadCursor?(resultId: string, byteOffset: number): Promise<string>;
64
68
  read(resultId: string, cursor?: string, maxBytes?: number): Promise<ArtifactReadResult>;
65
69
  readBundleDescriptor?(resultId: string): Promise<BundleLocalResult | null>;
66
70
  }