@cueai/omni-reader-mcp 1.5.5 → 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.
@@ -0,0 +1,307 @@
1
+ import { constants } from "node:fs";
2
+ import { lstat as nodeLstat, open as nodeOpen, } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { PathNormalizationError, normalizePlatformPath, } from "../path-normalization.js";
5
+ const MAX_CONFIG_BYTES = 1_048_576;
6
+ const EXACT_PACKAGE_SPEC = /^@cueai\/omni-reader-mcp@(\d+\.\d+\.\d+)$/u;
7
+ const REFERENCE_VALUES = new Set([
8
+ "${CUE_API_KEY}",
9
+ "Bearer ${CUE_API_KEY}",
10
+ ]);
11
+ const NODE_FILE_SYSTEM = {
12
+ lstat: (candidate) => nodeLstat(candidate, { bigint: true }),
13
+ open: (candidate, flags) => nodeOpen(candidate, flags),
14
+ };
15
+ export class ConfigInspectionError extends Error {
16
+ code;
17
+ constraints;
18
+ constructor(code, message, constraints) {
19
+ super(message);
20
+ this.name = "ConfigInspectionError";
21
+ this.code = code;
22
+ if (constraints !== undefined)
23
+ this.constraints = constraints;
24
+ }
25
+ }
26
+ function pathsFor(platform) {
27
+ return platform === "win32" ? path.win32 : path.posix;
28
+ }
29
+ function inspectionError(code, message, constraints) {
30
+ return new ConfigInspectionError(code, message, constraints);
31
+ }
32
+ function normalizedAbsolutePath(value, platform) {
33
+ if (value.length === 0 || value.includes("\0")) {
34
+ throw inspectionError("INVALID_CONFIG_PATH", "Provide one absolute JSON configuration path.");
35
+ }
36
+ let normalized;
37
+ try {
38
+ normalized = normalizePlatformPath(value, platform);
39
+ }
40
+ catch (error) {
41
+ if (error instanceof PathNormalizationError) {
42
+ throw inspectionError(error.code, error.message);
43
+ }
44
+ throw error;
45
+ }
46
+ const paths = pathsFor(platform);
47
+ if (!paths.isAbsolute(normalized)) {
48
+ throw inspectionError("INVALID_CONFIG_PATH", "Provide one absolute JSON configuration path.");
49
+ }
50
+ return paths.normalize(normalized);
51
+ }
52
+ function validateServerName(value) {
53
+ if (value.length === 0 || value.includes("\0")) {
54
+ throw inspectionError("INVALID_SERVER_NAME", "Provide one exact MCP server entry name.");
55
+ }
56
+ }
57
+ function requireSafeRegularFile(details) {
58
+ if (details.isSymbolicLink() || !details.isFile()) {
59
+ throw inspectionError("CONFIG_FILE_UNSAFE", "The selected configuration must be one regular file, not a symlink.");
60
+ }
61
+ }
62
+ function requireAllowedSize(details) {
63
+ if (details.size > BigInt(MAX_CONFIG_BYTES)) {
64
+ throw inspectionError("CONFIG_FILE_TOO_LARGE", "The selected configuration exceeds the 1 MiB inspection limit.", { max_bytes: MAX_CONFIG_BYTES });
65
+ }
66
+ }
67
+ async function readBoundedConfig(handle) {
68
+ const buffer = Buffer.allocUnsafe(MAX_CONFIG_BYTES + 1);
69
+ let total = 0;
70
+ while (total < buffer.byteLength) {
71
+ const remaining = buffer.byteLength - total;
72
+ const { bytesRead } = await handle.read(buffer, total, remaining, total);
73
+ if (bytesRead === 0)
74
+ break;
75
+ if (!Number.isInteger(bytesRead) || bytesRead < 0 || bytesRead > remaining) {
76
+ throw inspectionError("CONFIG_FILE_UNREADABLE", "The selected configuration file could not be inspected.");
77
+ }
78
+ total += bytesRead;
79
+ }
80
+ if (total > MAX_CONFIG_BYTES) {
81
+ throw inspectionError("CONFIG_FILE_TOO_LARGE", "The selected configuration exceeds the 1 MiB inspection limit.", { max_bytes: MAX_CONFIG_BYTES });
82
+ }
83
+ return buffer.subarray(0, total);
84
+ }
85
+ function requireSameFile(before, after) {
86
+ if (before.dev !== after.dev ||
87
+ before.ino !== after.ino ||
88
+ before.size !== after.size ||
89
+ before.mtimeNs !== after.mtimeNs ||
90
+ before.ctimeNs !== after.ctimeNs) {
91
+ throw inspectionError("CONFIG_FILE_CHANGED", "The selected configuration changed during inspection. Retry after changes stop.");
92
+ }
93
+ }
94
+ function fileAccessError(error) {
95
+ if (error instanceof ConfigInspectionError)
96
+ return error;
97
+ const code = error?.code;
98
+ if (code === "ENOENT" || code === "ENOTDIR") {
99
+ return inspectionError("CONFIG_FILE_NOT_FOUND", "The selected configuration file does not exist.");
100
+ }
101
+ if (code === "ELOOP") {
102
+ return inspectionError("CONFIG_FILE_UNSAFE", "The selected configuration must be one regular file, not a symlink.");
103
+ }
104
+ return inspectionError("CONFIG_FILE_UNREADABLE", "The selected configuration file could not be inspected.");
105
+ }
106
+ function isRecord(value) {
107
+ return value !== null && typeof value === "object" && !Array.isArray(value);
108
+ }
109
+ function unknownInspection(status) {
110
+ return {
111
+ inspection_scope: "explicit_config",
112
+ entry: { status },
113
+ transport: { shape: "unknown" },
114
+ api_key: { status: "unknown" },
115
+ allowed_roots: { safety: "unknown" },
116
+ };
117
+ }
118
+ function commandBasename(command) {
119
+ const normalized = command.replaceAll("\\", "/");
120
+ const basename = normalized.slice(normalized.lastIndexOf("/") + 1).trim();
121
+ return basename.length === 0 ? undefined : basename;
122
+ }
123
+ function commandCategory(basename) {
124
+ const normalized = basename.toLowerCase().replace(/\.(?:cmd|exe)$/u, "");
125
+ if (["npx", "npm", "pnpm", "yarn", "bun"].includes(normalized)) {
126
+ return "package_runner";
127
+ }
128
+ if (["cmd", "powershell", "pwsh", "sh", "bash", "zsh"].includes(normalized)) {
129
+ return "shell";
130
+ }
131
+ if (["node", "deno", "python", "python3"].includes(normalized)) {
132
+ return "runtime";
133
+ }
134
+ return "executable";
135
+ }
136
+ function transportFacts(entry) {
137
+ const command = typeof entry.command === "string" && entry.command.length > 0
138
+ ? entry.command
139
+ : undefined;
140
+ const url = typeof entry.url === "string" && entry.url.length > 0
141
+ ? entry.url
142
+ : undefined;
143
+ if ((command === undefined) === (url === undefined)) {
144
+ return { shape: "unknown" };
145
+ }
146
+ if (url !== undefined)
147
+ return { shape: "remote_url" };
148
+ const basename = commandBasename(command);
149
+ return basename === undefined
150
+ ? { shape: "local_command" }
151
+ : {
152
+ shape: "local_command",
153
+ command: { basename, category: commandCategory(basename) },
154
+ };
155
+ }
156
+ function exactPackageVersion(entry) {
157
+ if (!Array.isArray(entry.args))
158
+ return undefined;
159
+ for (const argument of entry.args) {
160
+ if (typeof argument !== "string")
161
+ continue;
162
+ const match = EXACT_PACKAGE_SPEC.exec(argument);
163
+ if (match !== null)
164
+ return match[1];
165
+ }
166
+ return undefined;
167
+ }
168
+ function credentialCandidates(entry) {
169
+ const candidates = [];
170
+ let malformedContainer = false;
171
+ if (Object.hasOwn(entry, "env")) {
172
+ if (!isRecord(entry.env)) {
173
+ malformedContainer = true;
174
+ }
175
+ else {
176
+ for (const [key, value] of Object.entries(entry.env)) {
177
+ if (key.toUpperCase() === "CUE_API_KEY")
178
+ candidates.push(value);
179
+ }
180
+ }
181
+ }
182
+ if (Object.hasOwn(entry, "headers")) {
183
+ if (!isRecord(entry.headers)) {
184
+ malformedContainer = true;
185
+ }
186
+ else {
187
+ for (const [key, value] of Object.entries(entry.headers)) {
188
+ if (key.toLowerCase() === "authorization")
189
+ candidates.push(value);
190
+ }
191
+ }
192
+ }
193
+ return { candidates, malformedContainer };
194
+ }
195
+ function configuredApiKeyStatus(entry) {
196
+ const { candidates, malformedContainer } = credentialCandidates(entry);
197
+ if (candidates.length === 0)
198
+ return malformedContainer ? "unknown" : "absent";
199
+ let hasReference = false;
200
+ let hasUnknown = malformedContainer;
201
+ for (const candidate of candidates) {
202
+ if (typeof candidate !== "string" || candidate.length === 0) {
203
+ hasUnknown = true;
204
+ continue;
205
+ }
206
+ if (REFERENCE_VALUES.has(candidate)) {
207
+ hasReference = true;
208
+ continue;
209
+ }
210
+ if (/[$%{}]/u.test(candidate)) {
211
+ hasUnknown = true;
212
+ continue;
213
+ }
214
+ return "literal_present";
215
+ }
216
+ if (hasUnknown)
217
+ return "unknown";
218
+ return hasReference ? "reference_present" : "unknown";
219
+ }
220
+ function allowedRootFacts(entry, platform) {
221
+ if (!Object.hasOwn(entry, "env"))
222
+ return { count: 0, safety: "safe" };
223
+ if (!isRecord(entry.env))
224
+ return { safety: "unknown" };
225
+ const rootValue = entry.env.OMNI_ALLOWED_ROOTS;
226
+ if (rootValue === undefined)
227
+ return { count: 0, safety: "safe" };
228
+ if (typeof rootValue !== "string")
229
+ return { safety: "unknown" };
230
+ if (rootValue.length === 0)
231
+ return { count: 0, safety: "safe" };
232
+ const paths = pathsFor(platform);
233
+ const roots = rootValue
234
+ .split(paths.delimiter)
235
+ .filter((root) => root.length > 0);
236
+ if (roots.length === 0)
237
+ return { count: 0, safety: "safe" };
238
+ const safe = roots.every((root) => {
239
+ if (root.includes("\0"))
240
+ return false;
241
+ try {
242
+ return paths.isAbsolute(normalizePlatformPath(root, platform));
243
+ }
244
+ catch {
245
+ return false;
246
+ }
247
+ });
248
+ return { count: roots.length, safety: safe ? "safe" : "unsafe" };
249
+ }
250
+ function inspectParsedConfig(value, serverName, platform) {
251
+ if (!isRecord(value))
252
+ return unknownInspection("invalid");
253
+ if (!Object.hasOwn(value, "mcpServers"))
254
+ return unknownInspection("missing");
255
+ if (!isRecord(value.mcpServers))
256
+ return unknownInspection("invalid");
257
+ if (!Object.hasOwn(value.mcpServers, serverName))
258
+ return unknownInspection("missing");
259
+ const selected = value.mcpServers[serverName];
260
+ if (!isRecord(selected))
261
+ return unknownInspection("invalid");
262
+ const packageVersion = exactPackageVersion(selected);
263
+ return {
264
+ inspection_scope: "explicit_config",
265
+ entry: { status: "present" },
266
+ transport: transportFacts(selected),
267
+ ...(packageVersion === undefined ? {} : { package_version: packageVersion }),
268
+ api_key: { status: configuredApiKeyStatus(selected) },
269
+ allowed_roots: allowedRootFacts(selected, platform),
270
+ };
271
+ }
272
+ export async function inspectExplicitConfig(options) {
273
+ const platform = options.platform ?? process.platform;
274
+ validateServerName(options.serverName);
275
+ const configPath = normalizedAbsolutePath(options.configPath, platform);
276
+ const fileSystem = options.fileSystem ?? NODE_FILE_SYSTEM;
277
+ let handle;
278
+ try {
279
+ const before = await fileSystem.lstat(configPath);
280
+ requireSafeRegularFile(before);
281
+ requireAllowedSize(before);
282
+ handle = await fileSystem.open(configPath, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
283
+ const opened = await handle.stat({ bigint: true });
284
+ requireSafeRegularFile(opened);
285
+ requireSameFile(before, opened);
286
+ requireAllowedSize(opened);
287
+ const serialized = await readBoundedConfig(handle);
288
+ const after = await handle.stat({ bigint: true });
289
+ requireSafeRegularFile(after);
290
+ requireSameFile(opened, after);
291
+ requireAllowedSize(after);
292
+ let parsed;
293
+ try {
294
+ parsed = JSON.parse(serialized.toString("utf8"));
295
+ }
296
+ catch {
297
+ return unknownInspection("invalid");
298
+ }
299
+ return inspectParsedConfig(parsed, options.serverName, platform);
300
+ }
301
+ catch (error) {
302
+ throw fileAccessError(error);
303
+ }
304
+ finally {
305
+ await handle?.close().catch(() => undefined);
306
+ }
307
+ }
@@ -1,4 +1,5 @@
1
1
  import { type AgentConfigEnvironment } from "./agent-config.js";
2
+ import { type ExplicitConfigInspection } from "./config-inspection.js";
2
3
  export type VersionCheck = {
3
4
  readonly status: "current";
4
5
  readonly installed: string;
@@ -29,8 +30,14 @@ export interface DoctorOptions extends AgentConfigEnvironment {
29
30
  readonly nodeVersion?: string;
30
31
  readonly npmVersion?: string;
31
32
  readonly packageVersion?: string;
33
+ readonly explicitConfig?: {
34
+ readonly configPath: string;
35
+ readonly serverName: string;
36
+ };
32
37
  }
33
38
  export interface DoctorReport {
39
+ readonly inspection_scope: "current_process_env";
40
+ readonly explicit_config?: ExplicitConfigInspection;
34
41
  readonly package_version: string;
35
42
  readonly version_check: VersionCheck;
36
43
  readonly node_version: string;
@@ -3,7 +3,9 @@ import { lstat, open, readdir } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { DEFAULT_CUBE_BASE_URL, MAX_FILE_BYTES, CUBE_GRANT_PROTOCOL_VERSION, } from "../constants.js";
5
5
  import { API_KEY_URL, getOnboardingPolicyWithTimeout, onboardingGuidance, } from "../onboarding-policy.js";
6
+ import { normalizePlatformPath, PathNormalizationError, } from "../path-normalization.js";
6
7
  import { agentConfigPath, inspectAgentConfigDetails, } from "./agent-config.js";
8
+ import { inspectExplicitConfig, } from "./config-inspection.js";
7
9
  const CUBE_HEALTH_PATH = "/api/omni-reader/direct-upload/v1/health";
8
10
  const NPM_LATEST_URL = "https://registry.npmjs.org/@cueai/omni-reader-mcp/latest";
9
11
  // Local-file parsing reaches the data plane only through the controlled origin
@@ -188,7 +190,16 @@ function allowedRootFacts(options) {
188
190
  const roots = value.split(separator).filter((root) => root.length > 0);
189
191
  return {
190
192
  count: roots.length,
191
- safe: roots.length > 0 && roots.every((root) => paths.isAbsolute(root)),
193
+ safe: roots.length > 0 && roots.every((root) => {
194
+ try {
195
+ return paths.isAbsolute(normalizePlatformPath(root, options.platform));
196
+ }
197
+ catch (error) {
198
+ if (error instanceof PathNormalizationError)
199
+ return false;
200
+ throw error;
201
+ }
202
+ }),
192
203
  };
193
204
  }
194
205
  async function clientAdapterFacts(options) {
@@ -207,7 +218,7 @@ async function clientAdapterFacts(options) {
207
218
  }
208
219
  export async function runDoctor(options) {
209
220
  const packageVersion = options.packageVersion ?? "unknown";
210
- const [clientAdapters, artifacts, onboarding, latestPublishedVersion] = await Promise.all([
221
+ const [clientAdapters, artifacts, onboarding, latestPublishedVersion, explicitConfig,] = await Promise.all([
211
222
  clientAdapterFacts(options),
212
223
  artifactFacts(options.artifactRoot),
213
224
  getOnboardingPolicyWithTimeout(options.fetchImpl),
@@ -218,6 +229,12 @@ export async function runDoctor(options) {
218
229
  SEMVER_PATTERN.test(packageVersion)
219
230
  ? fetchLatestPublishedVersion(options.fetchImpl)
220
231
  : Promise.resolve(undefined),
232
+ options.explicitConfig === undefined
233
+ ? Promise.resolve(undefined)
234
+ : inspectExplicitConfig({
235
+ ...options.explicitConfig,
236
+ platform: options.platform,
237
+ }),
221
238
  ]);
222
239
  let urlControl = "skipped (Cue API Key absent)";
223
240
  if (options.env.CUE_API_KEY) {
@@ -235,6 +252,8 @@ export async function runDoctor(options) {
235
252
  // status stays "not probed" until the first real local-file parse validates it.
236
253
  const directUpload = RELAY_DATA_PLANE_STATUS;
237
254
  return {
255
+ inspection_scope: "current_process_env",
256
+ ...(explicitConfig === undefined ? {} : { explicit_config: explicitConfig }),
238
257
  package_version: packageVersion,
239
258
  version_check: SEMVER_PATTERN.test(packageVersion)
240
259
  ? versionCheckFacts(packageVersion, latestPublishedVersion)
@@ -278,6 +297,7 @@ function packageLine(versionCheck) {
278
297
  }
279
298
  export function renderDoctor(report) {
280
299
  const lines = [
300
+ `inspection_scope=${report.inspection_scope}`,
281
301
  `Node: ${report.node_version}`,
282
302
  `npm: ${report.npm_version}`,
283
303
  packageLine(report.version_check),
@@ -291,6 +311,21 @@ export function renderDoctor(report) {
291
311
  ]) {
292
312
  lines.push(`${label} config: ${report.client_adapters[key].status}`);
293
313
  }
314
+ if (report.explicit_config !== undefined) {
315
+ const explicit = report.explicit_config;
316
+ lines.push(`explicit_config.inspection_scope=${explicit.inspection_scope}`);
317
+ lines.push(`Explicit config entry: ${explicit.entry.status}`);
318
+ lines.push(`Explicit config transport: ${explicit.transport.shape}`);
319
+ if (explicit.transport.command !== undefined) {
320
+ lines.push(`Explicit config command: ${explicit.transport.command.category} `
321
+ + `(${explicit.transport.command.basename})`);
322
+ }
323
+ lines.push(`Explicit config package version: ${explicit.package_version ?? "unknown"}`);
324
+ lines.push(`Explicit config API key: ${explicit.api_key.status}`);
325
+ lines.push(`Explicit config allowed roots: ${"count" in explicit.allowed_roots
326
+ ? explicit.allowed_roots.count
327
+ : "unknown"} (${explicit.allowed_roots.safety})`);
328
+ }
294
329
  lines.push(`Omni control protocol: ${report.endpoints.url_control}`);
295
330
  if (report.endpoints.url_control === "unavailable or incompatible") {
296
331
  lines.push(" WARNING: URL parsing will fail until this is reachable.");
package/dist/cli/setup.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import path from "node:path";
2
2
  import { BRIDGE_RELEASE_VERSION } from "../constants.js";
3
+ import { PathNormalizationError, normalizePlatformPath, } from "../path-normalization.js";
3
4
  import { getOnboardingPolicyWithTimeout, onboardingGuidance, } from "../onboarding-policy.js";
4
5
  import { CliUsageError } from "./arguments.js";
5
6
  import { configuredAllowedRoots, detectAgentTargets, parseAgentTarget, prepareAgentConfig, rollbackPreparedAgentConfig, verifyPreparedAgentConfig, writePreparedAgentConfig, } from "./agent-config.js";
@@ -16,10 +17,20 @@ function parseExtraRoots(input, environment) {
16
17
  : value.startsWith(`~${paths.sep}`)
17
18
  ? paths.join(environment.homeDirectory, value.slice(2))
18
19
  : value;
19
- if (!paths.isAbsolute(expanded)) {
20
+ let normalizedInput;
21
+ try {
22
+ normalizedInput = normalizePlatformPath(expanded, environment.platform);
23
+ }
24
+ catch (error) {
25
+ if (error instanceof PathNormalizationError) {
26
+ throw new CliUsageError(error.message);
27
+ }
28
+ throw error;
29
+ }
30
+ if (!paths.isAbsolute(normalizedInput)) {
20
31
  throw new CliUsageError("Every additional allowed root must be an absolute path.");
21
32
  }
22
- return paths.normalize(expanded);
33
+ return paths.normalize(normalizedInput);
23
34
  });
24
35
  }
25
36
  async function interactiveArguments(options) {
@@ -6,7 +6,7 @@ export declare const CUBE_GRANT_PROTOCOL_VERSION = "omni.parse_grant.v1";
6
6
  export declare const GRANTED_STREAM_PROTOCOL_VERSION = "omni.granted_parse_stream.v1";
7
7
  export declare const DEFAULT_CUBE_BASE_URL = "https://mcp.cuecue.cn";
8
8
  export declare const DEFAULT_IIIS_GRANTED_BASE_URL = "https://omni-upload.cuecue.cn/omni/granted/";
9
- export declare const BRIDGE_RELEASE_VERSION = "1.5.5";
9
+ export declare const BRIDGE_RELEASE_VERSION = "1.6.0";
10
10
  export declare const REMOTE_OMNI_MCP_URL = "https://mcp.cuecue.cn/api/omni-reader/mcp/";
11
11
  export declare const FOREGROUND_BUDGET_MS = 15000;
12
12
  export declare const STATUS_LONG_POLL_MAX_MS = 20000;
@@ -14,6 +14,7 @@ export declare const STATUS_POLL_AFTER_SECONDS = 5;
14
14
  export declare const DELIVERY_TTL_SECONDS = 600;
15
15
  export declare const CUBE_CAPABILITIES_PATH = "/api/omni-reader/capabilities/v1";
16
16
  export declare const REMOTE_CAPABILITIES_CUSTOM_FIELD = "cue.omni-reader";
17
+ export declare const SERVER_NEGOTIATED_BRIDGE_PROTOCOL_VERSION = "omni.local_bridge_tools.v3";
17
18
  export declare const CAPABILITIES_PROTOCOL_VERSION = "omni.reader_capabilities.v1";
18
19
  export declare const CAPABILITIES_ENABLED_ENV = "OMNI_CAPABILITIES_ENABLED";
19
20
  export declare const CAPABILITIES_TTL_SECONDS_ENV = "OMNI_CAPABILITIES_TTL_SECONDS";
package/dist/constants.js CHANGED
@@ -6,7 +6,7 @@ export const CUBE_GRANT_PROTOCOL_VERSION = "omni.parse_grant.v1";
6
6
  export const GRANTED_STREAM_PROTOCOL_VERSION = "omni.granted_parse_stream.v1";
7
7
  export const DEFAULT_CUBE_BASE_URL = "https://mcp.cuecue.cn";
8
8
  export const DEFAULT_IIIS_GRANTED_BASE_URL = "https://omni-upload.cuecue.cn/omni/granted/";
9
- export const BRIDGE_RELEASE_VERSION = "1.5.5";
9
+ export const BRIDGE_RELEASE_VERSION = "1.6.0";
10
10
  export const REMOTE_OMNI_MCP_URL = "https://mcp.cuecue.cn/api/omni-reader/mcp/";
11
11
  export const FOREGROUND_BUDGET_MS = 15_000;
12
12
  export const STATUS_LONG_POLL_MAX_MS = 20_000;
@@ -14,6 +14,7 @@ export const STATUS_POLL_AFTER_SECONDS = 5;
14
14
  export const DELIVERY_TTL_SECONDS = 600;
15
15
  export const CUBE_CAPABILITIES_PATH = "/api/omni-reader/capabilities/v1";
16
16
  export const REMOTE_CAPABILITIES_CUSTOM_FIELD = "cue.omni-reader";
17
+ export const SERVER_NEGOTIATED_BRIDGE_PROTOCOL_VERSION = "omni.local_bridge_tools.v3";
17
18
  // ── omni.reader_capabilities.v1 advertisement (D2-D item 4) ────────────────────────────────
18
19
  // The direct profile's 14 exact literal fields mirror the pinned cube-mcp accepted set
19
20
  // (contracts/cube-mcp/omni-capabilities/v1); the URL profile's 9 fields belong to the
@@ -33,7 +34,7 @@ export const DIRECT_GROUNDING_PROFILE = {
33
34
  settlement_journal_protocol: "omni.direct_settlement_journal.v2",
34
35
  usage_protocol: "omni_parse_usage.v2",
35
36
  billing_protocol: "omni_billing.v2",
36
- bridge_protocol: "omni.local_bridge_tools.v3",
37
+ bridge_protocol: SERVER_NEGOTIATED_BRIDGE_PROTOCOL_VERSION,
37
38
  bundle_protocol: "omni.result_bundle.v1",
38
39
  grounding_schema: "omni.grounding.v1",
39
40
  details: ["grounded", "layout"],
@@ -44,7 +45,7 @@ export const URL_GROUNDING_PROFILE = {
44
45
  operation_protocol: "omni.url_operation.v3",
45
46
  usage_protocol: "omni_parse_usage.v2",
46
47
  billing_protocol: "omni_billing.v2",
47
- bridge_protocol: "omni.local_bridge_tools.v3",
48
+ bridge_protocol: SERVER_NEGOTIATED_BRIDGE_PROTOCOL_VERSION,
48
49
  bundle_protocol: "omni.result_bundle.v1",
49
50
  grounding_schema: "omni.grounding.v1",
50
51
  details: ["grounded", "layout"],
package/dist/cursor.d.ts CHANGED
@@ -16,6 +16,10 @@ export interface BundleCursorPayload {
16
16
  export interface CursorCodecOptions {
17
17
  readonly now?: () => Date;
18
18
  }
19
+ export declare class CursorCodecError extends Error {
20
+ readonly code: string;
21
+ constructor(code: string, message: string);
22
+ }
19
23
  export declare class CursorCodec {
20
24
  #private;
21
25
  constructor(key: Uint8Array, options?: CursorCodecOptions);
package/dist/cursor.js CHANGED
@@ -1,20 +1,18 @@
1
1
  import { createHmac, timingSafeEqual } from "node:crypto";
2
- import { OmniBridgeError } from "./errors.js";
3
2
  import { BUNDLE_CURSOR_VERSION, GROUNDING_SCHEMA_VERSION, RESULT_BUNDLE_PROTOCOL_VERSION, } from "./protocol.js";
4
3
  const CURSOR_VERSION = 1;
5
4
  const BASE64URL_PATTERN = /^[A-Za-z0-9_-]+$/;
6
5
  const RESULT_ID_PATTERN = /^result_[A-Za-z0-9_-]{16,64}$/;
6
+ export class CursorCodecError extends Error {
7
+ code;
8
+ constructor(code, message) {
9
+ super(message);
10
+ this.name = "CursorCodecError";
11
+ this.code = code;
12
+ }
13
+ }
7
14
  function cursorError(code, message) {
8
- return new OmniBridgeError({
9
- code,
10
- message,
11
- operationCreated: true,
12
- fileUploaded: true,
13
- parserStarted: true,
14
- billed: true,
15
- contentReleased: true,
16
- retryable: false,
17
- });
15
+ return new CursorCodecError(code, message);
18
16
  }
19
17
  function decodeBase64Url(value) {
20
18
  if (!BASE64URL_PATTERN.test(value)) {
@@ -55,7 +53,7 @@ export class CursorCodec {
55
53
  value = JSON.parse(decodeBase64Url(encoded).toString("utf8"));
56
54
  }
57
55
  catch (error) {
58
- if (error instanceof OmniBridgeError)
56
+ if (error instanceof CursorCodecError)
59
57
  throw error;
60
58
  throw cursorError("INVALID_RESULT_CURSOR", "The result cursor is invalid.");
61
59
  }
@@ -107,7 +105,7 @@ export class CursorCodec {
107
105
  value = JSON.parse(decodeBase64Url(encoded).toString("utf8"));
108
106
  }
109
107
  catch (error) {
110
- if (error instanceof OmniBridgeError)
108
+ if (error instanceof CursorCodecError)
111
109
  throw error;
112
110
  throw cursorError("INVALID_RESULT_CURSOR", "The result cursor is invalid.");
113
111
  }
package/dist/index.js CHANGED
@@ -26,6 +26,7 @@ function helpText() {
26
26
  "No arguments start the stdio MCP server.",
27
27
  "setup Configure a supported user-scope Agent",
28
28
  "doctor Check local configuration and protocol health",
29
+ " [--json] [--config-path <absolute-json-path> --server-name <entry>]",
29
30
  "clean Delete Bridge-created local artifacts and expired records",
30
31
  "uninstall Restore a trusted URL-only Agent entry without deleting artifacts",
31
32
  "",
@@ -99,7 +100,7 @@ export async function startStdioServer(options = {}) {
99
100
  fetchImpl: options.fetchImpl,
100
101
  operationBaseUrl: options.iiisOperationBaseUrl,
101
102
  });
102
- const extraRoots = splitAllowedRoots(env.OMNI_ALLOWED_ROOTS);
103
+ const extraRoots = splitAllowedRoots(env.OMNI_ALLOWED_ROOTS, platform);
103
104
  const remoteClient = new HttpRemoteOmniClient({
104
105
  apiKey: env.CUE_API_KEY,
105
106
  fetchImpl: options.fetchImpl,
@@ -200,6 +201,14 @@ export async function runCli(args, options = {}) {
200
201
  fetchImpl,
201
202
  npmVersion: options.npmVersion ?? await installedNpmVersion(env),
202
203
  packageVersion,
204
+ ...(parsed.configPath === undefined
205
+ ? {}
206
+ : {
207
+ explicitConfig: {
208
+ configPath: parsed.configPath,
209
+ serverName: parsed.serverName,
210
+ },
211
+ }),
203
212
  });
204
213
  write(parsed.json
205
214
  ? `${JSON.stringify(report)}\n`
@@ -3,6 +3,7 @@ export type JournalState = "CREATED" | "GRANT_PENDING" | "GRANT_ISSUED" | "UPLOA
3
3
  export type JournalProgressUnit = "page" | "sheet" | "slide" | "frame" | "segment";
4
4
  export type JournalCleanupState = "not_created" | "in_use" | "pending" | "deleted";
5
5
  export type JournalDeliveryState = "not_created" | "pending" | "deleted_after_ack";
6
+ export type JournalResultDelivery = "auto" | "artifact";
6
7
  export interface JournalProgress {
7
8
  readonly unit: JournalProgressUnit;
8
9
  readonly completed: number;
@@ -22,6 +23,7 @@ export interface JournalRecord {
22
23
  readonly detail: JournalDetail;
23
24
  readonly groundingSchemaVersion: JournalGroundingSchemaVersion;
24
25
  readonly bundleProtocolVersion: JournalBundleProtocolVersion;
26
+ readonly resultDeliveryEffective: JournalResultDelivery;
25
27
  readonly operationId: string | null;
26
28
  readonly operationToken: string | null;
27
29
  readonly uploadUrl: string | null;
@@ -85,9 +87,10 @@ export declare class OperationJournal {
85
87
  constructor(options?: OperationJournalOptions);
86
88
  requestIdentityHmac(canonicalIdentityJson: string): Promise<string>;
87
89
  sourceLocatorHmac(sourceLocator: string): Promise<string>;
88
- beginIntent(clientRequestId: string, canonicalIdentityJson: string, sourceKind?: JournalSourceKind, sourceLocator?: string | null, representation?: RepresentationIntent): Promise<JournalRecord>;
90
+ beginIntent(clientRequestId: string, canonicalIdentityJson: string, sourceKind?: JournalSourceKind, sourceLocator?: string | null, representation?: RepresentationIntent, resultDelivery?: JournalResultDelivery): Promise<JournalRecord>;
89
91
  migrateLegacyRecord(clientRequestId: string, canonicalIdentityJson: string, sourceLocator?: string | null): Promise<JournalRecord | null>;
90
92
  transition(clientRequestId: string, expectedState: JournalState, nextState: JournalState, patch: JournalPatch): Promise<JournalRecord>;
93
+ strengthenResultDelivery(clientRequestId: string, requested: JournalResultDelivery): Promise<JournalRecord>;
91
94
  loadByRequestId(clientRequestId: string): Promise<JournalRecord | null>;
92
95
  loadByOperationId(operationId: string): Promise<JournalRecord | null>;
93
96
  loadLatestByRequestIdentityHmac(requestIdentityHmac: string): Promise<JournalRecord | null>;