@cueai/omni-reader-mcp 1.0.2 → 1.1.1

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 (48) hide show
  1. package/README.md +115 -26
  2. package/dist/artifact-store.d.ts +11 -0
  3. package/dist/artifact-store.js +94 -48
  4. package/dist/cli/agent-config.d.ts +29 -4
  5. package/dist/cli/agent-config.js +910 -107
  6. package/dist/cli/arguments.d.ts +32 -0
  7. package/dist/cli/arguments.js +120 -0
  8. package/dist/cli/doctor.d.ts +42 -1
  9. package/dist/cli/doctor.js +109 -36
  10. package/dist/cli/setup.d.ts +3 -0
  11. package/dist/cli/setup.js +103 -18
  12. package/dist/cli/uninstall.d.ts +6 -0
  13. package/dist/cli/uninstall.js +37 -0
  14. package/dist/constants.d.ts +7 -0
  15. package/dist/constants.js +7 -0
  16. package/dist/cube-client.d.ts +5 -3
  17. package/dist/cube-client.js +16 -11
  18. package/dist/cursor.js +2 -0
  19. package/dist/errors.d.ts +32 -1
  20. package/dist/errors.js +26 -1
  21. package/dist/iiis-client.d.ts +18 -4
  22. package/dist/iiis-client.js +194 -40
  23. package/dist/index.d.ts +3 -0
  24. package/dist/index.js +93 -32
  25. package/dist/multipart-body.js +2 -0
  26. package/dist/onboarding-policy.d.ts +10 -0
  27. package/dist/onboarding-policy.js +58 -0
  28. package/dist/operation-journal.d.ts +50 -1
  29. package/dist/operation-journal.js +473 -114
  30. package/dist/operation-manager.d.ts +75 -0
  31. package/dist/operation-manager.js +1324 -0
  32. package/dist/path-security.d.ts +1 -0
  33. package/dist/path-security.js +26 -6
  34. package/dist/progress.d.ts +6 -1
  35. package/dist/protocol.d.ts +26 -13
  36. package/dist/protocol.js +34 -10
  37. package/dist/remote-client.d.ts +17 -0
  38. package/dist/remote-client.js +233 -0
  39. package/dist/result-contract.d.ts +199 -0
  40. package/dist/result-contract.js +235 -0
  41. package/dist/server.js +21 -4
  42. package/dist/source.d.ts +8 -0
  43. package/dist/source.js +37 -0
  44. package/dist/task-runtime.d.ts +13 -0
  45. package/dist/task-runtime.js +94 -0
  46. package/dist/tools.d.ts +19 -1
  47. package/dist/tools.js +317 -112
  48. package/package.json +3 -3
@@ -0,0 +1,32 @@
1
+ import { type AgentTarget } from "./agent-config.js";
2
+ export interface SetupArguments {
3
+ readonly client?: AgentTarget;
4
+ readonly allowedRoots: readonly string[];
5
+ readonly addRoots: readonly string[];
6
+ readonly yes: boolean;
7
+ readonly json: boolean;
8
+ }
9
+ export type ParsedCommand = {
10
+ readonly command: "server";
11
+ } | {
12
+ readonly command: "help";
13
+ } | {
14
+ readonly command: "version";
15
+ } | {
16
+ readonly command: "setup";
17
+ readonly arguments: SetupArguments;
18
+ } | {
19
+ readonly command: "doctor";
20
+ readonly json: boolean;
21
+ } | {
22
+ readonly command: "clean";
23
+ } | {
24
+ readonly command: "uninstall";
25
+ readonly yes: boolean;
26
+ readonly json: boolean;
27
+ };
28
+ export declare class CliUsageError extends Error {
29
+ readonly exitCode = 2;
30
+ constructor(message: string);
31
+ }
32
+ export declare function parseCliArguments(argv: readonly string[], platform?: NodeJS.Platform): ParsedCommand;
@@ -0,0 +1,120 @@
1
+ import path from "node:path";
2
+ import { parseAgentTarget } from "./agent-config.js";
3
+ export class CliUsageError extends Error {
4
+ exitCode = 2;
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = "CliUsageError";
8
+ }
9
+ }
10
+ function pathsFor(platform) {
11
+ return platform === "win32" ? path.win32 : path.posix;
12
+ }
13
+ function requireNoArguments(command, values) {
14
+ if (values.length > 0)
15
+ throw new CliUsageError(`${command} does not accept arguments.`);
16
+ }
17
+ function parseBooleanFlags(command, values, supported) {
18
+ const seen = new Set();
19
+ for (const value of values) {
20
+ if (!supported.has(value)) {
21
+ throw new CliUsageError(`Unknown ${command} flag: ${value}`);
22
+ }
23
+ if (seen.has(value)) {
24
+ throw new CliUsageError(`Duplicate ${command} flag: ${value}`);
25
+ }
26
+ seen.add(value);
27
+ }
28
+ return seen;
29
+ }
30
+ function parseSetupArguments(values, platform) {
31
+ let client;
32
+ let allowedRoot;
33
+ let addRoot;
34
+ let yes = false;
35
+ let json = false;
36
+ const seen = new Set();
37
+ const paths = pathsFor(platform);
38
+ for (let index = 0; index < values.length; index += 1) {
39
+ const flag = values[index];
40
+ if (!["--client", "--allowed-root", "--add-root", "--yes", "--json"].includes(flag)) {
41
+ throw new CliUsageError(`Unknown setup flag: ${flag}`);
42
+ }
43
+ if (seen.has(flag))
44
+ throw new CliUsageError(`Duplicate setup flag: ${flag}`);
45
+ seen.add(flag);
46
+ if (flag === "--yes") {
47
+ yes = true;
48
+ continue;
49
+ }
50
+ if (flag === "--json") {
51
+ json = true;
52
+ continue;
53
+ }
54
+ const raw = values[index + 1];
55
+ if (raw === undefined || raw.startsWith("--")) {
56
+ throw new CliUsageError(`${flag} requires a value.`);
57
+ }
58
+ index += 1;
59
+ if (flag === "--client") {
60
+ const parsed = parseAgentTarget(raw);
61
+ const normalized = raw.trim().toLowerCase();
62
+ if (parsed === "generic" &&
63
+ normalized !== "generic" &&
64
+ normalized !== "other")
65
+ throw new CliUsageError(`Unsupported Agent client: ${raw}`);
66
+ client = parsed;
67
+ continue;
68
+ }
69
+ if (!paths.isAbsolute(raw)) {
70
+ throw new CliUsageError(`${flag} requires an absolute path.`);
71
+ }
72
+ const normalized = paths.normalize(raw);
73
+ if (flag === "--allowed-root")
74
+ allowedRoot = normalized;
75
+ if (flag === "--add-root")
76
+ addRoot = normalized;
77
+ }
78
+ if (allowedRoot !== undefined && addRoot !== undefined) {
79
+ throw new CliUsageError("--allowed-root and --add-root cannot be combined.");
80
+ }
81
+ return {
82
+ ...(client === undefined ? {} : { client }),
83
+ allowedRoots: allowedRoot === undefined ? [] : [allowedRoot],
84
+ addRoots: addRoot === undefined ? [] : [addRoot],
85
+ yes,
86
+ json,
87
+ };
88
+ }
89
+ export function parseCliArguments(argv, platform = process.platform) {
90
+ if (argv.length === 0)
91
+ return { command: "server" };
92
+ const [command, ...values] = argv;
93
+ if (command === "--help" || command === "-h" || command === "help") {
94
+ requireNoArguments("help", values);
95
+ return { command: "help" };
96
+ }
97
+ if (command === "--version" || command === "-v") {
98
+ requireNoArguments("version", values);
99
+ return { command: "version" };
100
+ }
101
+ if (command === "setup") {
102
+ return { command: "setup", arguments: parseSetupArguments(values, platform) };
103
+ }
104
+ if (command === "doctor") {
105
+ const flags = parseBooleanFlags("doctor", values, new Set(["--json"]));
106
+ return { command: "doctor", json: flags.has("--json") };
107
+ }
108
+ if (command === "clean") {
109
+ requireNoArguments("clean", values);
110
+ return { command: "clean" };
111
+ }
112
+ if (command === "uninstall") {
113
+ const flags = parseBooleanFlags("uninstall", values, new Set(["--yes", "--json"]));
114
+ if (!flags.has("--yes") || !flags.has("--json")) {
115
+ throw new CliUsageError("Uninstall requires: uninstall --yes --json");
116
+ }
117
+ return { command: "uninstall", yes: true, json: true };
118
+ }
119
+ throw new CliUsageError(`Unknown command: ${command}`);
120
+ }
@@ -6,12 +6,53 @@ export interface HealthResult {
6
6
  export interface DoctorOptions extends AgentConfigEnvironment {
7
7
  readonly env: NodeJS.ProcessEnv;
8
8
  readonly artifactRoot: string;
9
+ readonly cacheMode: "default" | "fallback";
9
10
  readonly fetchImpl: typeof fetch;
10
11
  readonly nodeVersion?: string;
11
12
  readonly npmVersion?: string;
12
13
  readonly packageVersion?: string;
13
14
  }
15
+ export interface DoctorReport {
16
+ readonly package_version: string;
17
+ readonly node_version: string;
18
+ readonly npm_version: string;
19
+ readonly client_adapters: Record<string, {
20
+ readonly status: AgentConfigStatusForReport;
21
+ readonly version?: string;
22
+ }>;
23
+ readonly api_key: {
24
+ readonly status: "present" | "absent";
25
+ };
26
+ readonly allowed_roots: {
27
+ readonly count: number;
28
+ readonly safe: boolean;
29
+ };
30
+ readonly endpoints: {
31
+ readonly url_control: string;
32
+ readonly direct_upload: string;
33
+ };
34
+ readonly artifacts: {
35
+ readonly count: number;
36
+ readonly bytes: number;
37
+ readonly earliest_expiry?: string;
38
+ };
39
+ readonly cache: {
40
+ readonly mode: "default" | "fallback";
41
+ readonly safe: true;
42
+ };
43
+ readonly onboarding: {
44
+ readonly status: "current";
45
+ readonly first_registration_credits: number;
46
+ readonly free_daily_credits: number;
47
+ } | {
48
+ readonly status: "unavailable";
49
+ };
50
+ readonly reload_required: boolean;
51
+ }
52
+ type AgentConfigStatusForReport = "configured" | "not configured" | "invalid or unreadable";
14
53
  export declare function checkCubeHealth(fetchImpl: typeof fetch, apiKey: string): Promise<string>;
15
54
  export declare function checkIiisHealth(fetchImpl: typeof fetch): Promise<string>;
16
55
  export declare function checkHealth(fetchImpl: typeof fetch, apiKey: string): Promise<HealthResult>;
17
- export declare function runDoctor(options: DoctorOptions): Promise<string[]>;
56
+ export declare function runDoctor(options: DoctorOptions): Promise<DoctorReport>;
57
+ export declare function renderDoctor(report: DoctorReport): string[];
58
+ export {};
@@ -1,10 +1,11 @@
1
1
  import { constants as fsConstants } from "node:fs";
2
2
  import { lstat, open, readdir } from "node:fs/promises";
3
3
  import path from "node:path";
4
- import { DEFAULT_CUBE_BASE_URL, GRANTED_STREAM_PROTOCOL_VERSION, MAX_FILE_BYTES, CUBE_GRANT_PROTOCOL_VERSION, } from "../constants.js";
4
+ import { BRIDGE_RELEASE_VERSION, DEFAULT_CUBE_BASE_URL, GRANTED_STREAM_PROTOCOL_VERSION, MAX_FILE_BYTES, CUBE_GRANT_PROTOCOL_VERSION, } from "../constants.js";
5
+ import { API_KEY_URL, getOnboardingPolicyWithTimeout, onboardingGuidance, } from "../onboarding-policy.js";
5
6
  import { agentConfigPath, inspectAgentConfig, } from "./agent-config.js";
6
7
  const CUBE_HEALTH_PATH = "/api/omni-reader/direct-upload/v1/health";
7
- const IIIS_HEALTH_URL = "https://cubefile.ai.iiis.co:9443/omni/granted/health";
8
+ const GRANTED_UPLOAD_HEALTH_URL = "https://cubefile.ai.iiis.co:9443/omni/granted/health";
8
9
  function isHealthBody(value) {
9
10
  if (value === null || typeof value !== "object" || Array.isArray(value))
10
11
  return false;
@@ -29,16 +30,16 @@ export async function checkCubeHealth(fetchImpl, apiKey) {
29
30
  const cubeUrl = new URL(CUBE_HEALTH_PATH, DEFAULT_CUBE_BASE_URL).toString();
30
31
  const cube = await fetchHealth(fetchImpl, cubeUrl, `Bearer ${apiKey}`);
31
32
  if (!cube.enabled || cube.protocol_version !== CUBE_GRANT_PROTOCOL_VERSION) {
32
- throw new Error("Cube direct upload is disabled or incompatible");
33
+ throw new Error("Omni URL control is disabled or incompatible");
33
34
  }
34
35
  return cube.protocol_version;
35
36
  }
36
37
  export async function checkIiisHealth(fetchImpl) {
37
- const iiis = await fetchHealth(fetchImpl, IIIS_HEALTH_URL);
38
- if (!iiis.enabled || iiis.protocol_version !== GRANTED_STREAM_PROTOCOL_VERSION) {
39
- throw new Error("IIIS granted upload is disabled or incompatible");
38
+ const granted = await fetchHealth(fetchImpl, GRANTED_UPLOAD_HEALTH_URL);
39
+ if (!granted.enabled || granted.protocol_version !== GRANTED_STREAM_PROTOCOL_VERSION) {
40
+ throw new Error("Omni direct upload is disabled or incompatible");
40
41
  }
41
- return iiis.protocol_version;
42
+ return granted.protocol_version;
42
43
  }
43
44
  export async function checkHealth(fetchImpl, apiKey) {
44
45
  const [cubeProtocol, iiisProtocol] = await Promise.all([
@@ -83,7 +84,7 @@ async function artifactFacts(artifactRoot) {
83
84
  }
84
85
  catch (error) {
85
86
  if (error.code === "ENOENT") {
86
- return { count: 0, bytes: 0, expiry: "none" };
87
+ return { count: 0, bytes: 0 };
87
88
  }
88
89
  throw error;
89
90
  }
@@ -108,50 +109,122 @@ async function artifactFacts(artifactRoot) {
108
109
  earliestExpiry = expiresAt;
109
110
  }
110
111
  }
111
- const expiry = count === 0
112
- ? "none"
113
- : unknownExpiry || earliestExpiry === undefined
114
- ? "unknown"
115
- : new Date(earliestExpiry).toISOString();
116
- return { count, bytes, expiry };
112
+ return {
113
+ count,
114
+ bytes,
115
+ ...(count > 0 && !unknownExpiry && earliestExpiry !== undefined
116
+ ? { expiry: new Date(earliestExpiry).toISOString() }
117
+ : {}),
118
+ };
117
119
  }
118
- export async function runDoctor(options) {
119
- const lines = [
120
- `Node: ${options.nodeVersion ?? process.version}`,
121
- `npm: ${options.npmVersion ?? "unavailable"}`,
122
- `Package: ${options.packageVersion ?? "unknown"}`,
123
- `Cue API Key: ${options.env.CUE_API_KEY ? "present" : "absent"}`,
124
- `Allowed roots: ${options.env.OMNI_ALLOWED_ROOTS || "none"}`,
125
- ];
120
+ function allowedRootFacts(options) {
121
+ const value = options.env.OMNI_ALLOWED_ROOTS?.trim() ?? "";
122
+ if (value === "")
123
+ return { count: 0, safe: true };
124
+ const paths = options.platform === "win32" ? path.win32 : path.posix;
125
+ const separator = options.platform === "win32" ? ";" : ":";
126
+ const roots = value.split(separator).filter((root) => root.length > 0);
127
+ return {
128
+ count: roots.length,
129
+ safe: roots.length > 0 && roots.every((root) => paths.isAbsolute(root)),
130
+ };
131
+ }
132
+ async function clientAdapterFacts(options) {
133
+ const result = {};
126
134
  for (const [label, target] of [
127
- ["Cursor", "cursor"],
128
- ["Claude Desktop", "claude-desktop"],
135
+ ["hermes", "hermes"],
136
+ ["cursor", "cursor"],
137
+ ["claude_desktop", "claude-desktop"],
129
138
  ]) {
130
139
  const configPath = agentConfigPath(target, options);
131
140
  const status = configPath === undefined
132
141
  ? "not configured"
133
- : await inspectAgentConfig(configPath, options);
134
- lines.push(`${label} config: ${status}`);
142
+ : await inspectAgentConfig(configPath, options, target);
143
+ result[label] = {
144
+ status,
145
+ ...(status === "configured" ? { version: BRIDGE_RELEASE_VERSION } : {}),
146
+ };
135
147
  }
148
+ return result;
149
+ }
150
+ export async function runDoctor(options) {
151
+ const [clientAdapters, artifacts, onboarding] = await Promise.all([
152
+ clientAdapterFacts(options),
153
+ artifactFacts(options.artifactRoot),
154
+ getOnboardingPolicyWithTimeout(options.fetchImpl),
155
+ ]);
156
+ let urlControl = "skipped (Cue API Key absent)";
136
157
  if (options.env.CUE_API_KEY) {
137
158
  try {
138
- lines.push(`Cube protocol: ${await checkCubeHealth(options.fetchImpl, options.env.CUE_API_KEY)}`);
159
+ urlControl = await checkCubeHealth(options.fetchImpl, options.env.CUE_API_KEY);
139
160
  }
140
161
  catch {
141
- lines.push("Cube health: unavailable or incompatible");
162
+ urlControl = "unavailable or incompatible";
142
163
  }
143
164
  }
144
- else {
145
- lines.push("Cube health: skipped (Cue API Key absent)");
146
- }
165
+ let directUpload;
147
166
  try {
148
- lines.push(`IIIS protocol: ${await checkIiisHealth(options.fetchImpl)}`);
167
+ directUpload = await checkIiisHealth(options.fetchImpl);
149
168
  }
150
169
  catch {
151
- lines.push("IIIS health: unavailable or incompatible");
170
+ directUpload = "unavailable or incompatible";
171
+ }
172
+ return {
173
+ package_version: options.packageVersion ?? "unknown",
174
+ node_version: options.nodeVersion ?? process.version,
175
+ npm_version: options.npmVersion ?? "unavailable",
176
+ client_adapters: clientAdapters,
177
+ api_key: { status: options.env.CUE_API_KEY ? "present" : "absent" },
178
+ allowed_roots: allowedRootFacts(options),
179
+ endpoints: {
180
+ url_control: urlControl,
181
+ direct_upload: directUpload,
182
+ },
183
+ artifacts: {
184
+ count: artifacts.count,
185
+ bytes: artifacts.bytes,
186
+ ...(artifacts.expiry === undefined ? {} : { earliest_expiry: artifacts.expiry }),
187
+ },
188
+ cache: { mode: options.cacheMode, safe: true },
189
+ onboarding: onboarding === undefined
190
+ ? { status: "unavailable" }
191
+ : {
192
+ status: "current",
193
+ first_registration_credits: onboarding.firstRegistrationCredits,
194
+ free_daily_credits: onboarding.freeDailyCredits,
195
+ },
196
+ reload_required: false,
197
+ };
198
+ }
199
+ export function renderDoctor(report) {
200
+ const lines = [
201
+ `Node: ${report.node_version}`,
202
+ `npm: ${report.npm_version}`,
203
+ `Package: ${report.package_version}`,
204
+ `Cue API Key: ${report.api_key.status}`,
205
+ `Allowed roots: ${report.allowed_roots.count} (${report.allowed_roots.safe ? "safe" : "invalid"})`,
206
+ ];
207
+ for (const [label, key] of [
208
+ ["Hermes", "hermes"],
209
+ ["Cursor", "cursor"],
210
+ ["Claude Desktop", "claude_desktop"],
211
+ ]) {
212
+ lines.push(`${label} config: ${report.client_adapters[key].status}`);
213
+ }
214
+ lines.push(`Omni control protocol: ${report.endpoints.url_control}`);
215
+ lines.push(`Omni direct upload protocol: ${report.endpoints.direct_upload}`);
216
+ lines.push(`Artifacts: ${report.artifacts.count} file(s), ${report.artifacts.bytes} byte(s)`);
217
+ lines.push(`Artifact expiry: ${report.artifacts.earliest_expiry ?? (report.artifacts.count === 0 ? "none" : "unknown")}`);
218
+ lines.push(`Cache: ${report.cache.mode}`);
219
+ if (report.api_key.status === "absent") {
220
+ const policy = report.onboarding.status === "current"
221
+ ? {
222
+ apiKeyUrl: API_KEY_URL,
223
+ firstRegistrationCredits: report.onboarding.first_registration_credits,
224
+ freeDailyCredits: report.onboarding.free_daily_credits,
225
+ }
226
+ : undefined;
227
+ lines.push(...onboardingGuidance(policy).split("\n"));
152
228
  }
153
- const artifacts = await artifactFacts(options.artifactRoot);
154
- lines.push(`Artifacts: ${artifacts.count} file(s), ${artifacts.bytes} byte(s)`);
155
- lines.push(`Artifact expiry: ${artifacts.expiry}`);
156
229
  return lines;
157
230
  }
@@ -1,8 +1,11 @@
1
+ import { type SetupArguments } from "./arguments.js";
1
2
  import { type AgentConfigEnvironment } from "./agent-config.js";
2
3
  export interface SetupOptions extends AgentConfigEnvironment {
3
4
  readonly env: NodeJS.ProcessEnv;
4
5
  readonly fetchImpl: typeof fetch;
5
6
  readonly ask: (question: string) => Promise<string>;
6
7
  readonly write: (text: string) => void;
8
+ readonly stdinIsTTY: boolean;
9
+ readonly arguments: SetupArguments;
7
10
  }
8
11
  export declare function runSetup(options: SetupOptions): Promise<void>;
package/dist/cli/setup.js CHANGED
@@ -1,5 +1,8 @@
1
1
  import path from "node:path";
2
- import { detectAgentTargets, parseAgentTarget, prepareAgentConfig, verifyPreparedAgentConfig, writePreparedAgentConfig, } from "./agent-config.js";
2
+ import { BRIDGE_RELEASE_VERSION } from "../constants.js";
3
+ import { getOnboardingPolicyWithTimeout, onboardingGuidance, } from "../onboarding-policy.js";
4
+ import { CliUsageError } from "./arguments.js";
5
+ import { configuredAllowedRoots, detectAgentTargets, parseAgentTarget, prepareAgentConfig, rollbackPreparedAgentConfig, verifyPreparedAgentConfig, writePreparedAgentConfig, } from "./agent-config.js";
3
6
  import { checkHealth } from "./doctor.js";
4
7
  function parseExtraRoots(input, environment) {
5
8
  const separator = environment.platform === "win32" ? ";" : ":";
@@ -14,46 +17,128 @@ function parseExtraRoots(input, environment) {
14
17
  ? paths.join(environment.homeDirectory, value.slice(2))
15
18
  : value;
16
19
  if (!paths.isAbsolute(expanded)) {
17
- throw new Error("Every additional allowed root must be an absolute path.");
20
+ throw new CliUsageError("Every additional allowed root must be an absolute path.");
18
21
  }
19
22
  return paths.normalize(expanded);
20
23
  });
21
24
  }
22
- export async function runSetup(options) {
23
- const labels = { cursor: "Cursor", "claude-desktop": "Claude Desktop" };
25
+ async function interactiveArguments(options) {
26
+ const labels = {
27
+ hermes: "Hermes",
28
+ cursor: "Cursor",
29
+ "claude-desktop": "Claude Desktop",
30
+ };
24
31
  const detected = await detectAgentTargets(options);
25
32
  const detectedLabel = detected.length === 0
26
33
  ? "none"
27
34
  : detected.map((target) => labels[target]).join(", ");
28
- const selected = await options.ask(`Agent (Cursor / Claude Desktop / Other; Detected: ${detectedLabel}): `);
35
+ const selected = await options.ask(`Agent (Hermes / Cursor / Claude Desktop / Other; Detected: ${detectedLabel}): `);
29
36
  const target = parseAgentTarget(selected);
30
- const extraRootInput = await options.ask("Additional allowed roots (optional): ");
31
- const extraRoots = parseExtraRoots(extraRootInput, options);
32
- const prepared = await prepareAgentConfig(target, extraRoots, options);
37
+ const rootInput = await options.ask("Additional allowed roots (optional): ");
38
+ return { target, roots: parseExtraRoots(rootInput, options) };
39
+ }
40
+ async function selectedTargetAndRoots(options) {
41
+ const requested = options.arguments;
42
+ if (requested.client === undefined) {
43
+ if (!options.stdinIsTTY) {
44
+ throw new CliUsageError("Non-interactive setup requires: setup --client hermes --allowed-root <absolute-path> --yes --json");
45
+ }
46
+ const selected = await interactiveArguments(options);
47
+ return { ...selected, interactive: true };
48
+ }
49
+ if (!options.stdinIsTTY && !requested.yes) {
50
+ throw new CliUsageError("Non-interactive setup requires --yes.");
51
+ }
52
+ const existing = await configuredAllowedRoots(requested.client, options);
53
+ const roots = requested.allowedRoots.length > 0
54
+ ? requested.allowedRoots
55
+ : requested.addRoots.length > 0
56
+ ? [...new Set([...existing, ...requested.addRoots])]
57
+ : existing;
58
+ return { target: requested.client, roots, interactive: !requested.yes };
59
+ }
60
+ function writePreview(options, prepared) {
33
61
  options.write(`Target: ${prepared.displayPath}\n`);
34
62
  options.write("Before:\n");
35
63
  options.write(`${JSON.stringify(prepared.before, null, 2)}\n`);
36
64
  options.write("After:\n");
37
65
  options.write(`${JSON.stringify(prepared.after, null, 2)}\n`);
66
+ }
67
+ async function confirmSetup(options, prepared, interactive) {
68
+ if (!interactive)
69
+ return true;
70
+ writePreview(options, prepared);
38
71
  const confirmation = (await options.ask("Apply this user-scope configuration? Type yes: ")).trim().toLowerCase();
39
- if (confirmation !== "yes") {
40
- options.write("No changes written.\n");
41
- return;
42
- }
43
- await verifyPreparedAgentConfig(prepared);
72
+ if (confirmation === "yes")
73
+ return true;
74
+ options.write("No changes written.\n");
75
+ return false;
76
+ }
77
+ async function requireApiKey(options) {
44
78
  const apiKey = options.env.CUE_API_KEY ?? "";
45
- if (apiKey.length === 0) {
46
- throw new Error("CUE_API_KEY is absent. Create one at https://cuecue.cn/hub/api-key and retry.");
79
+ if (apiKey.length > 0)
80
+ return apiKey;
81
+ const policy = await getOnboardingPolicyWithTimeout(options.fetchImpl);
82
+ throw new Error(onboardingGuidance(policy));
83
+ }
84
+ async function validateConfiguredEnvironment(options, prepared, apiKey) {
85
+ try {
86
+ await checkHealth(options.fetchImpl, apiKey);
87
+ }
88
+ catch {
89
+ try {
90
+ await rollbackPreparedAgentConfig(prepared);
91
+ }
92
+ catch {
93
+ throw new Error("Omni 安全解析环境验证失败,且无法确认 Agent 配置已自动恢复;请停止重试并检查 user-scope 配置。");
94
+ }
95
+ throw new Error("Omni 安全解析环境验证失败;原 Agent 配置已自动恢复。");
96
+ }
97
+ }
98
+ function writeSuccess(options, prepared, roots) {
99
+ if (options.arguments.json) {
100
+ options.write(`${JSON.stringify({
101
+ status: prepared.configPath === undefined ? "manual_configuration" : "configured",
102
+ target: prepared.target,
103
+ package: "@cueai/omni-reader-mcp",
104
+ version: BRIDGE_RELEASE_VERSION,
105
+ config_path: prepared.displayPath,
106
+ allowed_roots: roots.length,
107
+ reload: prepared.reload,
108
+ })}\n`);
109
+ return;
47
110
  }
48
111
  options.write("Cue API Key: present\n");
49
- await checkHealth(options.fetchImpl, apiKey);
50
112
  if (prepared.configPath === undefined) {
51
113
  options.write("Generic user-scope configuration:\n");
52
- options.write(`${JSON.stringify({ mcpServers: { "omni-reader": prepared.entry } }, null, 2)}\n`);
114
+ options.write(`${JSON.stringify({
115
+ mcpServers: { "omni-reader": prepared.entry },
116
+ }, null, 2)}\n`);
53
117
  }
54
118
  else {
55
- await writePreparedAgentConfig(prepared);
56
119
  options.write(`Wrote ${prepared.displayPath}\n`);
120
+ options.write(`${prepared.reload}\n`);
57
121
  }
58
122
  options.write("用 Omni 解析 ./report.pdf\n");
59
123
  }
124
+ export async function runSetup(options) {
125
+ const selected = await selectedTargetAndRoots(options);
126
+ const prepared = await prepareAgentConfig(selected.target, selected.roots, options);
127
+ if (!await confirmSetup(options, prepared, selected.interactive))
128
+ return;
129
+ await verifyPreparedAgentConfig(prepared);
130
+ const apiKey = await requireApiKey(options);
131
+ if (prepared.configPath === undefined) {
132
+ try {
133
+ await checkHealth(options.fetchImpl, apiKey);
134
+ }
135
+ catch {
136
+ throw new Error("Omni 安全解析环境验证失败;未写入 Agent 配置。");
137
+ }
138
+ }
139
+ else {
140
+ await writePreparedAgentConfig(prepared);
141
+ await validateConfiguredEnvironment(options, prepared, apiKey);
142
+ }
143
+ writeSuccess(options, prepared, selected.roots);
144
+ }
@@ -0,0 +1,6 @@
1
+ import { type AgentConfigEnvironment } from "./agent-config.js";
2
+ export interface UninstallOptions extends AgentConfigEnvironment {
3
+ readonly args: readonly string[];
4
+ readonly write: (text: string) => void;
5
+ }
6
+ export declare function runUninstall(options: UninstallOptions): Promise<void>;
@@ -0,0 +1,37 @@
1
+ import { uninstallAgentConfig, } from "./agent-config.js";
2
+ export async function runUninstall(options) {
3
+ const flags = [...options.args].sort();
4
+ if (flags.length !== 2 ||
5
+ flags[0] !== "--json" ||
6
+ flags[1] !== "--yes") {
7
+ throw new Error("Uninstall requires: uninstall --yes --json");
8
+ }
9
+ const results = [];
10
+ for (const target of ["hermes", "cursor", "claude-desktop"]) {
11
+ const result = await uninstallAgentConfig(target, options);
12
+ if (result !== undefined)
13
+ results.push(result);
14
+ }
15
+ if (results.length === 0) {
16
+ options.write(`${JSON.stringify({
17
+ status: "not_installed",
18
+ restored_remote: false,
19
+ artifacts_preserved: true,
20
+ source_files_unchanged: true,
21
+ })}\n`);
22
+ return;
23
+ }
24
+ const response = {
25
+ status: "uninstalled",
26
+ restored_remote: results.every((result) => result.restoredRemote),
27
+ artifacts_preserved: true,
28
+ source_files_unchanged: true,
29
+ };
30
+ if (results.length === 1) {
31
+ response.target = results[0].target;
32
+ }
33
+ else {
34
+ response.targets = results.map((result) => result.target);
35
+ }
36
+ options.write(`${JSON.stringify(response)}\n`);
37
+ }
@@ -5,3 +5,10 @@ export declare const RESULT_CHUNK_MAX_BYTES = 65536;
5
5
  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
+ export declare const DEFAULT_IIIS_GRANTED_BASE_URL = "https://cubefile.ai.iiis.co:9443/omni/granted/";
9
+ export declare const BRIDGE_RELEASE_VERSION = "1.1.1";
10
+ export declare const REMOTE_OMNI_MCP_URL = "https://mcp.cuecue.cn/api/omni-reader/mcp/";
11
+ export declare const FOREGROUND_BUDGET_MS = 15000;
12
+ export declare const STATUS_LONG_POLL_MAX_MS = 20000;
13
+ export declare const STATUS_POLL_AFTER_SECONDS = 5;
14
+ export declare const DELIVERY_TTL_SECONDS = 600;
package/dist/constants.js CHANGED
@@ -5,3 +5,10 @@ export const RESULT_CHUNK_MAX_BYTES = 65536;
5
5
  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
+ export const DEFAULT_IIIS_GRANTED_BASE_URL = "https://cubefile.ai.iiis.co:9443/omni/granted/";
9
+ export const BRIDGE_RELEASE_VERSION = "1.1.1";
10
+ export const REMOTE_OMNI_MCP_URL = "https://mcp.cuecue.cn/api/omni-reader/mcp/";
11
+ export const FOREGROUND_BUDGET_MS = 15_000;
12
+ export const STATUS_LONG_POLL_MAX_MS = 20_000;
13
+ export const STATUS_POLL_AFTER_SECONDS = 5;
14
+ export const DELIVERY_TTL_SECONDS = 600;
@@ -1,6 +1,6 @@
1
+ import { BRIDGE_RELEASE_VERSION } from "./constants.js";
1
2
  import { OperationJournal } from "./operation-journal.js";
2
3
  declare const BRIDGE_PACKAGE = "@cueai/omni-reader-mcp";
3
- declare const BRIDGE_VERSION = "1.0.2";
4
4
  export interface GrantRequestInput {
5
5
  readonly contentLength: number;
6
6
  readonly contentType: string;
@@ -35,7 +35,7 @@ interface GrantRequestBody {
35
35
  readonly output: "markdown";
36
36
  readonly bridge: {
37
37
  readonly package: typeof BRIDGE_PACKAGE;
38
- readonly version: typeof BRIDGE_VERSION;
38
+ readonly version: typeof BRIDGE_RELEASE_VERSION;
39
39
  };
40
40
  }
41
41
  export declare function grantRequestHash(body: GrantRequestBody): string;
@@ -43,6 +43,8 @@ export declare function createClientRequestId(): string;
43
43
  export declare class CubeGrantClient {
44
44
  #private;
45
45
  constructor(options: CubeGrantClientOptions);
46
- createGrant(input: GrantRequestInput, clientRequestId: string, signal?: AbortSignal): Promise<GrantedOperation>;
46
+ createGrant(input: GrantRequestInput, clientRequestId: string, signal?: AbortSignal, options?: {
47
+ journal?: boolean;
48
+ }): Promise<GrantedOperation>;
47
49
  }
48
50
  export {};