@cueai/omni-reader-mcp 1.5.5 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +106 -46
  2. package/dist/artifact-store.d.ts +2 -0
  3. package/dist/artifact-store.js +45 -10
  4. package/dist/capabilities.d.ts +129 -2
  5. package/dist/capabilities.js +122 -19
  6. package/dist/cli/agent-config.js +2 -2
  7. package/dist/cli/arguments.d.ts +8 -4
  8. package/dist/cli/arguments.js +62 -7
  9. package/dist/cli/config-inspection.d.ts +59 -0
  10. package/dist/cli/config-inspection.js +307 -0
  11. package/dist/cli/doctor.d.ts +7 -0
  12. package/dist/cli/doctor.js +37 -2
  13. package/dist/cli/setup.js +13 -2
  14. package/dist/constants.d.ts +6 -1
  15. package/dist/constants.js +9 -4
  16. package/dist/cube-client.d.ts +4 -1
  17. package/dist/cube-client.js +286 -32
  18. package/dist/cursor.d.ts +4 -0
  19. package/dist/cursor.js +11 -13
  20. package/dist/errors.d.ts +1 -0
  21. package/dist/errors.js +15 -0
  22. package/dist/iiis-client.d.ts +33 -2
  23. package/dist/iiis-client.js +368 -40
  24. package/dist/index.js +10 -1
  25. package/dist/operation-journal.d.ts +17 -1
  26. package/dist/operation-journal.js +260 -15
  27. package/dist/operation-manager.d.ts +6 -2
  28. package/dist/operation-manager.js +448 -89
  29. package/dist/path-normalization.d.ts +5 -0
  30. package/dist/path-normalization.js +25 -0
  31. package/dist/path-security.d.ts +2 -1
  32. package/dist/path-security.js +49 -28
  33. package/dist/protocol.d.ts +10 -2
  34. package/dist/protocol.js +23 -7
  35. package/dist/remote-client.js +3 -13
  36. package/dist/result-contract.d.ts +76 -32
  37. package/dist/result-contract.js +121 -5
  38. package/dist/task-runtime.d.ts +3 -2
  39. package/dist/task-runtime.js +2 -2
  40. package/dist/tools.d.ts +4 -0
  41. package/dist/tools.js +41 -31
  42. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
- import { OmniBridgeError } from "./errors.js";
2
+ import { OmniBridgeError, unsupportedDetailError, } from "./errors.js";
3
3
  export const READER_CAPABILITIES_PROTOCOL = "omni.reader_capabilities.v1";
4
+ export const READER_CAPABILITIES_V2_PROTOCOL = "omni.reader_capabilities.v2";
4
5
  // Closed consumer-side schema for `omni.reader_capabilities.v1` (D2-D item 4).
5
6
  // Objects/arrays are closed: profile names and every tuple member are exact
6
7
  // literals, `details` is the exact ordered tuple ["grounded", "layout"], and a
@@ -40,6 +41,74 @@ const urlProfileSchema = z
40
41
  max_result_bytes: z.literal(16777216),
41
42
  })
42
43
  .strict();
44
+ export const DIRECT_TEXT_BILLING_PROFILE = {
45
+ profile: "omni.direct_text_billing.v1",
46
+ grant_protocol: "omni.parse_grant.v4",
47
+ stream_protocol: "omni.granted_parse_stream.v3",
48
+ operation_protocol: "omni.direct_operation.v3",
49
+ settlement_protocol: "omni.grant_settlement.v5",
50
+ release_protocol: "omni.release_decision.v3",
51
+ settlement_journal_protocol: "omni.direct_settlement_journal.v3",
52
+ usage_protocol: "omni_parse_usage.v2",
53
+ billing_protocol: "omni_billing.v2",
54
+ bridge_protocol: "omni.local_bridge_tools.v5",
55
+ details: ["text"],
56
+ max_result_bytes: 268435456,
57
+ };
58
+ export const DIRECT_GROUNDING_BILLING_PROFILE = {
59
+ profile: "omni.direct_grounding_billing.v1",
60
+ grant_protocol: "omni.parse_grant.v4",
61
+ stream_protocol: "omni.granted_parse_stream.v3",
62
+ operation_protocol: "omni.direct_operation.v3",
63
+ settlement_protocol: "omni.grant_settlement.v5",
64
+ release_protocol: "omni.release_decision.v3",
65
+ settlement_journal_protocol: "omni.direct_settlement_journal.v3",
66
+ usage_protocol: "omni_parse_usage.v2",
67
+ billing_protocol: "omni_billing.v2",
68
+ bridge_protocol: "omni.local_bridge_tools.v5",
69
+ bundle_protocol: "omni.result_bundle.v1",
70
+ grounding_schema: "omni.grounding.v1",
71
+ details: ["grounded", "layout"],
72
+ max_result_bytes: 67108864,
73
+ };
74
+ const directTextBillingProfileSchema = z
75
+ .object({
76
+ profile: z.literal(DIRECT_TEXT_BILLING_PROFILE.profile),
77
+ grant_protocol: z.literal(DIRECT_TEXT_BILLING_PROFILE.grant_protocol),
78
+ stream_protocol: z.literal(DIRECT_TEXT_BILLING_PROFILE.stream_protocol),
79
+ operation_protocol: z.literal(DIRECT_TEXT_BILLING_PROFILE.operation_protocol),
80
+ settlement_protocol: z.literal(DIRECT_TEXT_BILLING_PROFILE.settlement_protocol),
81
+ release_protocol: z.literal(DIRECT_TEXT_BILLING_PROFILE.release_protocol),
82
+ settlement_journal_protocol: z.literal(DIRECT_TEXT_BILLING_PROFILE.settlement_journal_protocol),
83
+ usage_protocol: z.literal(DIRECT_TEXT_BILLING_PROFILE.usage_protocol),
84
+ billing_protocol: z.literal(DIRECT_TEXT_BILLING_PROFILE.billing_protocol),
85
+ bridge_protocol: z.literal(DIRECT_TEXT_BILLING_PROFILE.bridge_protocol),
86
+ details: z.tuple([z.literal("text")]),
87
+ max_result_bytes: z.literal(DIRECT_TEXT_BILLING_PROFILE.max_result_bytes),
88
+ })
89
+ .strict();
90
+ const directGroundingBillingProfileSchema = z
91
+ .object({
92
+ profile: z.literal(DIRECT_GROUNDING_BILLING_PROFILE.profile),
93
+ grant_protocol: z.literal(DIRECT_GROUNDING_BILLING_PROFILE.grant_protocol),
94
+ stream_protocol: z.literal(DIRECT_GROUNDING_BILLING_PROFILE.stream_protocol),
95
+ operation_protocol: z.literal(DIRECT_GROUNDING_BILLING_PROFILE.operation_protocol),
96
+ settlement_protocol: z.literal(DIRECT_GROUNDING_BILLING_PROFILE.settlement_protocol),
97
+ release_protocol: z.literal(DIRECT_GROUNDING_BILLING_PROFILE.release_protocol),
98
+ settlement_journal_protocol: z.literal(DIRECT_GROUNDING_BILLING_PROFILE.settlement_journal_protocol),
99
+ usage_protocol: z.literal(DIRECT_GROUNDING_BILLING_PROFILE.usage_protocol),
100
+ billing_protocol: z.literal(DIRECT_GROUNDING_BILLING_PROFILE.billing_protocol),
101
+ bridge_protocol: z.literal(DIRECT_GROUNDING_BILLING_PROFILE.bridge_protocol),
102
+ bundle_protocol: z.literal(DIRECT_GROUNDING_BILLING_PROFILE.bundle_protocol),
103
+ grounding_schema: z.literal(DIRECT_GROUNDING_BILLING_PROFILE.grounding_schema),
104
+ details: z.tuple([z.literal("grounded"), z.literal("layout")]),
105
+ max_result_bytes: z.literal(DIRECT_GROUNDING_BILLING_PROFILE.max_result_bytes),
106
+ })
107
+ .strict();
108
+ const directProfileV2Schema = z.discriminatedUnion("profile", [
109
+ directTextBillingProfileSchema,
110
+ directGroundingBillingProfileSchema,
111
+ ]);
43
112
  const readerCapabilitiesSchema = z
44
113
  .object({
45
114
  protocol_version: z.literal(READER_CAPABILITIES_PROTOCOL),
@@ -48,6 +117,13 @@ const readerCapabilitiesSchema = z
48
117
  url_profiles: z.array(urlProfileSchema),
49
118
  })
50
119
  .strict();
120
+ const readerCapabilitiesV2Schema = z
121
+ .object({
122
+ protocol_version: z.literal(READER_CAPABILITIES_V2_PROTOCOL),
123
+ expires_at: z.string().datetime({ offset: true }),
124
+ direct_profiles: z.array(directProfileV2Schema).length(2),
125
+ })
126
+ .strict();
51
127
  function invalidCapabilities() {
52
128
  return new OmniBridgeError({
53
129
  code: "INVALID_READER_CAPABILITIES",
@@ -61,20 +137,6 @@ function invalidCapabilities() {
61
137
  retryable: false,
62
138
  });
63
139
  }
64
- function unsupportedDetail() {
65
- return new OmniBridgeError({
66
- code: "UNSUPPORTED_DETAIL",
67
- message: "This Omni service does not support the requested output detail.",
68
- failureScope: "service",
69
- userAction: "Use plain Markdown output for this source.",
70
- operationCreated: false,
71
- fileUploaded: false,
72
- parserStarted: false,
73
- billed: false,
74
- contentReleased: false,
75
- retryable: false,
76
- });
77
- }
78
140
  export function parseReaderCapabilities(value, now) {
79
141
  let parsed;
80
142
  try {
@@ -109,15 +171,56 @@ export function parseReaderCapabilities(value, now) {
109
171
  url_profiles: parsed.url_profiles,
110
172
  };
111
173
  }
112
- export function selectDirectProfile(value, detail) {
174
+ export function selectDirectProfile(value, detail, sourceKind) {
113
175
  const profile = value.direct_profiles.find((candidate) => candidate.details.includes(detail));
114
176
  if (profile === undefined)
115
- throw unsupportedDetail();
177
+ throw unsupportedDetailError(sourceKind);
116
178
  return profile;
117
179
  }
118
- export function selectUrlProfile(value, detail) {
180
+ export function selectUrlProfile(value, detail, sourceKind) {
119
181
  const profile = value.url_profiles.find((candidate) => candidate.details.includes(detail));
120
182
  if (profile === undefined)
121
- throw unsupportedDetail();
183
+ throw unsupportedDetailError(sourceKind);
184
+ return profile;
185
+ }
186
+ export function parseReaderCapabilitiesV2(value, now) {
187
+ let parsed;
188
+ try {
189
+ parsed = readerCapabilitiesV2Schema.parse(value);
190
+ }
191
+ catch {
192
+ throw invalidCapabilities();
193
+ }
194
+ const expiresAt = new Date(parsed.expires_at);
195
+ if (Number.isNaN(expiresAt.getTime()) ||
196
+ expiresAt.getTime() <= now.getTime()) {
197
+ throw invalidCapabilities();
198
+ }
199
+ const profileOrder = new Map([
200
+ [DIRECT_TEXT_BILLING_PROFILE.profile, 0],
201
+ [DIRECT_GROUNDING_BILLING_PROFILE.profile, 1],
202
+ ]);
203
+ const seen = new Set();
204
+ let previousOrder = -1;
205
+ for (const profile of parsed.direct_profiles) {
206
+ const order = profileOrder.get(profile.profile);
207
+ if (order === undefined ||
208
+ seen.has(profile.profile) ||
209
+ order <= previousOrder) {
210
+ throw invalidCapabilities();
211
+ }
212
+ seen.add(profile.profile);
213
+ previousOrder = order;
214
+ }
215
+ return {
216
+ protocol_version: parsed.protocol_version,
217
+ expires_at: expiresAt,
218
+ direct_profiles: parsed.direct_profiles,
219
+ };
220
+ }
221
+ export function selectDirectProfileV2(value, detail, sourceKind) {
222
+ const profile = value.direct_profiles.find((candidate) => candidate.details.includes(detail));
223
+ if (profile === undefined)
224
+ throw unsupportedDetailError(sourceKind);
122
225
  return profile;
123
226
  }
@@ -7,7 +7,7 @@ const PACKAGE_SPEC = `@cueai/omni-reader-mcp@${BRIDGE_RELEASE_VERSION}`;
7
7
  // The release that the current version is a trusted upgrade from: normal upgrade,
8
8
  // uninstall, and rollback recognize exactly {previous, current}. Bump this to the
9
9
  // version we just published when BRIDGE_RELEASE_VERSION advances.
10
- const PREVIOUS_RELEASE_VERSION = "1.5.4";
10
+ const PREVIOUS_RELEASE_VERSION = "1.6.0";
11
11
  const PREVIOUS_PACKAGE_SPEC = `@cueai/omni-reader-mcp@${PREVIOUS_RELEASE_VERSION}`;
12
12
  // Preserve the one evidenced two-release migration exception: 1.5.1 setup wrote a
13
13
  // bare `npx` launcher on Windows, so later setup/uninstall versions must still be able
@@ -641,7 +641,7 @@ export function expectedBridgeVersion(target, value, platform) {
641
641
  }
642
642
  function isLegacyBridgeEntry(target, value, platform) {
643
643
  // Defer the entire invocation-shape decision to the single platform policy:
644
- // exact pinned {1.5.4 previous, 1.5.5 current} plus the exact Windows 1.5.1
644
+ // exact pinned {1.6.0 previous, 1.7.0 current} plus the exact Windows 1.5.1
645
645
  // bare-npx migration source. The historical platform-agnostic acceptance of a
646
646
  // bare unpinned `npx -y @cueai/omni-reader-mcp` is removed: it widened the
647
647
  // frozen trust set to a floating latest on every OS, which expectedBridgeVersion
@@ -7,18 +7,22 @@ export interface SetupArguments {
7
7
  readonly headless: boolean;
8
8
  readonly json: boolean;
9
9
  }
10
+ export interface DoctorArguments {
11
+ readonly json: boolean;
12
+ readonly configPath?: string;
13
+ readonly serverName?: string;
14
+ }
10
15
  export type ParsedCommand = {
11
16
  readonly command: "server";
12
17
  } | {
13
18
  readonly command: "help";
14
19
  } | {
15
20
  readonly command: "version";
16
- } | {
21
+ } | ({
22
+ readonly command: "doctor";
23
+ } & DoctorArguments) | {
17
24
  readonly command: "setup";
18
25
  readonly arguments: SetupArguments;
19
- } | {
20
- readonly command: "doctor";
21
- readonly json: boolean;
22
26
  } | {
23
27
  readonly command: "clean";
24
28
  } | {
@@ -1,4 +1,5 @@
1
1
  import path from "node:path";
2
+ import { PathNormalizationError, normalizePlatformPath, } from "../path-normalization.js";
2
3
  import { parseAgentTarget } from "./agent-config.js";
3
4
  export class CliUsageError extends Error {
4
5
  exitCode = 2;
@@ -10,6 +11,26 @@ export class CliUsageError extends Error {
10
11
  function pathsFor(platform) {
11
12
  return platform === "win32" ? path.win32 : path.posix;
12
13
  }
14
+ function normalizeAbsoluteCliPath(raw, flag, platform) {
15
+ if (raw.length === 0 || raw.includes("\0")) {
16
+ throw new CliUsageError(`${flag} requires one valid absolute path.`);
17
+ }
18
+ let normalizedInput;
19
+ try {
20
+ normalizedInput = normalizePlatformPath(raw, platform);
21
+ }
22
+ catch (error) {
23
+ if (error instanceof PathNormalizationError) {
24
+ throw new CliUsageError(error.message);
25
+ }
26
+ throw error;
27
+ }
28
+ const paths = pathsFor(platform);
29
+ if (!paths.isAbsolute(normalizedInput)) {
30
+ throw new CliUsageError(`${flag} requires an absolute path.`);
31
+ }
32
+ return paths.normalize(normalizedInput);
33
+ }
13
34
  function requireNoArguments(command, values) {
14
35
  if (values.length > 0)
15
36
  throw new CliUsageError(`${command} does not accept arguments.`);
@@ -35,7 +56,6 @@ function parseSetupArguments(values, platform) {
35
56
  let headless = false;
36
57
  let json = false;
37
58
  const seen = new Set();
38
- const paths = pathsFor(platform);
39
59
  for (let index = 0; index < values.length; index += 1) {
40
60
  const flag = values[index];
41
61
  if (!["--client", "--allowed-root", "--add-root", "--yes", "--headless", "--non-interactive", "--json"].includes(flag)) {
@@ -71,10 +91,7 @@ function parseSetupArguments(values, platform) {
71
91
  client = parsed;
72
92
  continue;
73
93
  }
74
- if (!paths.isAbsolute(raw)) {
75
- throw new CliUsageError(`${flag} requires an absolute path.`);
76
- }
77
- const normalized = paths.normalize(raw);
94
+ const normalized = normalizeAbsoluteCliPath(raw, flag, platform);
78
95
  if (flag === "--allowed-root")
79
96
  allowedRoot = normalized;
80
97
  if (flag === "--add-root")
@@ -92,6 +109,45 @@ function parseSetupArguments(values, platform) {
92
109
  json,
93
110
  };
94
111
  }
112
+ function parseDoctorArguments(values, platform) {
113
+ let json = false;
114
+ let configPath;
115
+ let serverName;
116
+ const seen = new Set();
117
+ for (let index = 0; index < values.length; index += 1) {
118
+ const flag = values[index];
119
+ if (!["--json", "--config-path", "--server-name"].includes(flag)) {
120
+ throw new CliUsageError(`Unknown doctor flag: ${flag}`);
121
+ }
122
+ if (seen.has(flag))
123
+ throw new CliUsageError(`Duplicate doctor flag: ${flag}`);
124
+ seen.add(flag);
125
+ if (flag === "--json") {
126
+ json = true;
127
+ continue;
128
+ }
129
+ const raw = values[index + 1];
130
+ if (raw === undefined || raw.startsWith("--")) {
131
+ throw new CliUsageError(`${flag} requires a value.`);
132
+ }
133
+ index += 1;
134
+ if (flag === "--config-path") {
135
+ configPath = normalizeAbsoluteCliPath(raw, flag, platform);
136
+ continue;
137
+ }
138
+ if (raw.length === 0 || raw.includes("\0")) {
139
+ throw new CliUsageError("--server-name requires one valid entry name.");
140
+ }
141
+ serverName = raw;
142
+ }
143
+ if ((configPath === undefined) !== (serverName === undefined)) {
144
+ throw new CliUsageError("--config-path and --server-name must be provided together.");
145
+ }
146
+ return {
147
+ json,
148
+ ...(configPath === undefined ? {} : { configPath, serverName: serverName }),
149
+ };
150
+ }
95
151
  export function parseCliArguments(argv, platform = process.platform) {
96
152
  if (argv.length === 0)
97
153
  return { command: "server" };
@@ -108,8 +164,7 @@ export function parseCliArguments(argv, platform = process.platform) {
108
164
  return { command: "setup", arguments: parseSetupArguments(values, platform) };
109
165
  }
110
166
  if (command === "doctor") {
111
- const flags = parseBooleanFlags("doctor", values, new Set(["--json"]));
112
- return { command: "doctor", json: flags.has("--json") };
167
+ return { command: "doctor", ...parseDoctorArguments(values, platform) };
113
168
  }
114
169
  if (command === "clean") {
115
170
  requireNoArguments("clean", values);
@@ -0,0 +1,59 @@
1
+ import { type BigIntStats } from "node:fs";
2
+ export interface ConfigInspectionHandle {
3
+ stat(options: {
4
+ bigint: true;
5
+ }): Promise<BigIntStats>;
6
+ read(buffer: Buffer, offset: number, length: number, position: number): Promise<{
7
+ bytesRead: number;
8
+ buffer: Buffer;
9
+ }>;
10
+ close(): Promise<void>;
11
+ }
12
+ export interface ConfigInspectionFileSystem {
13
+ lstat(candidate: string): Promise<BigIntStats>;
14
+ open(candidate: string, flags: number): Promise<ConfigInspectionHandle>;
15
+ }
16
+ export declare class ConfigInspectionError extends Error {
17
+ readonly code: string;
18
+ readonly constraints?: {
19
+ readonly max_bytes: number;
20
+ };
21
+ constructor(code: string, message: string, constraints?: {
22
+ readonly max_bytes: number;
23
+ });
24
+ }
25
+ export type ConfigEntryStatus = "present" | "missing" | "invalid";
26
+ export type ConfigTransportShape = "local_command" | "remote_url" | "unknown";
27
+ export type ConfiguredApiKeyStatus = "literal_present" | "reference_present" | "absent" | "unknown";
28
+ export type AllowedRootSafety = "safe" | "unsafe" | "unknown";
29
+ export type CommandCategory = "package_runner" | "shell" | "runtime" | "executable";
30
+ export interface ExplicitConfigInspection {
31
+ readonly inspection_scope: "explicit_config";
32
+ readonly entry: {
33
+ readonly status: ConfigEntryStatus;
34
+ };
35
+ readonly transport: {
36
+ readonly shape: ConfigTransportShape;
37
+ readonly command?: {
38
+ readonly basename: string;
39
+ readonly category: CommandCategory;
40
+ };
41
+ };
42
+ readonly package_version?: string;
43
+ readonly api_key: {
44
+ readonly status: ConfiguredApiKeyStatus;
45
+ };
46
+ readonly allowed_roots: {
47
+ readonly count: number;
48
+ readonly safety: Exclude<AllowedRootSafety, "unknown">;
49
+ } | {
50
+ readonly safety: "unknown";
51
+ };
52
+ }
53
+ export interface InspectExplicitConfigOptions {
54
+ readonly configPath: string;
55
+ readonly serverName: string;
56
+ readonly platform?: NodeJS.Platform;
57
+ readonly fileSystem?: ConfigInspectionFileSystem;
58
+ }
59
+ export declare function inspectExplicitConfig(options: InspectExplicitConfigOptions): Promise<ExplicitConfigInspection>;