@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
package/dist/index.js CHANGED
@@ -1,27 +1,33 @@
1
1
  #!/usr/bin/env node
2
2
  import { execFile as execFileCallback } from "node:child_process";
3
3
  import { readFile, realpath } from "node:fs/promises";
4
+ import { tmpdir } from "node:os";
4
5
  import { fileURLToPath } from "node:url";
5
6
  import { createInterface } from "node:readline/promises";
6
7
  import { stdin, stdout as processStdout } from "node:process";
7
8
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
8
- import { ArtifactStore, defaultArtifactRoot } from "./artifact-store.js";
9
+ import { ArtifactStore, selectArtifactRoot, } from "./artifact-store.js";
10
+ import { CliUsageError, parseCliArguments } from "./cli/arguments.js";
9
11
  import { runClean } from "./cli/clean.js";
10
- import { runDoctor } from "./cli/doctor.js";
12
+ import { renderDoctor, runDoctor } from "./cli/doctor.js";
11
13
  import { runSetup } from "./cli/setup.js";
14
+ import { runUninstall } from "./cli/uninstall.js";
12
15
  import { CubeGrantClient } from "./cube-client.js";
13
16
  import { IiisClient } from "./iiis-client.js";
17
+ import { createLocalParseOperationManager } from "./operation-manager.js";
14
18
  import { OperationJournal } from "./operation-journal.js";
15
19
  import { splitAllowedRoots } from "./path-security.js";
20
+ import { HttpRemoteOmniClient } from "./remote-client.js";
16
21
  import { createOmniMcpServer } from "./server.js";
17
22
  function helpText() {
18
23
  return [
19
- "Usage: omni-reader-mcp [setup|doctor|clean|--help|--version]",
24
+ "Usage: omni-reader-mcp [setup|doctor|clean|uninstall|--help|--version]",
20
25
  "",
21
26
  "No arguments start the stdio MCP server.",
22
27
  "setup Configure a supported user-scope Agent",
23
28
  "doctor Check local configuration and protocol health",
24
29
  "clean Delete Bridge-created local artifacts and expired records",
30
+ "uninstall Restore a trusted URL-only Agent entry without deleting artifacts",
25
31
  "",
26
32
  ].join("\n");
27
33
  }
@@ -60,16 +66,26 @@ async function installedNpmVersion(env) {
60
66
  });
61
67
  });
62
68
  }
69
+ async function artifactSelectionFor(options, env, homeDirectory, cwd, platform) {
70
+ if (options.artifactRoot !== undefined) {
71
+ return { mode: "default", rootDirectory: options.artifactRoot };
72
+ }
73
+ return await selectArtifactRoot({
74
+ platform,
75
+ homeDirectory,
76
+ env,
77
+ projectDirectory: cwd,
78
+ temporaryDirectory: options.temporaryDirectory ?? tmpdir(),
79
+ });
80
+ }
63
81
  export async function startStdioServer(options = {}) {
64
82
  const env = options.env ?? process.env;
83
+ const homeDirectory = options.homeDirectory ?? (await import("node:os")).homedir();
65
84
  const cwd = options.cwd ?? process.cwd();
66
- const artifactRoot = options.artifactRoot ?? defaultArtifactRoot({
67
- platform: options.platform,
68
- homeDirectory: options.homeDirectory,
69
- env,
70
- });
85
+ const platform = options.platform ?? process.platform;
86
+ const artifactSelection = await artifactSelectionFor(options, env, homeDirectory, cwd, platform);
71
87
  const artifactStore = await ArtifactStore.open({
72
- rootDirectory: artifactRoot,
88
+ rootDirectory: artifactSelection.rootDirectory,
73
89
  projectDirectory: cwd,
74
90
  now: options.now,
75
91
  });
@@ -79,12 +95,33 @@ export async function startStdioServer(options = {}) {
79
95
  environment: { CUE_API_KEY: env.CUE_API_KEY },
80
96
  fetchImpl: options.fetchImpl,
81
97
  });
98
+ const iiisClient = new IiisClient({
99
+ fetchImpl: options.fetchImpl,
100
+ operationBaseUrl: options.iiisOperationBaseUrl,
101
+ });
102
+ const extraRoots = splitAllowedRoots(env.OMNI_ALLOWED_ROOTS);
103
+ const remoteClient = new HttpRemoteOmniClient({
104
+ apiKey: env.CUE_API_KEY,
105
+ fetchImpl: options.fetchImpl,
106
+ });
107
+ const operationManager = createLocalParseOperationManager({
108
+ journal,
109
+ workspace: cwd,
110
+ extraRoots,
111
+ cubeClient,
112
+ iiisClient,
113
+ artifactStore,
114
+ remoteClient,
115
+ now: options.now,
116
+ });
82
117
  const server = createOmniMcpServer({
83
118
  workspace: cwd,
84
- extraRoots: splitAllowedRoots(env.OMNI_ALLOWED_ROOTS),
119
+ extraRoots,
85
120
  cubeClient,
86
- iiisClient: new IiisClient({ fetchImpl: options.fetchImpl }),
121
+ iiisClient,
87
122
  artifactStore,
123
+ operationManager,
124
+ remoteClient,
88
125
  });
89
126
  const close = async () => {
90
127
  await server.close().catch(() => undefined);
@@ -99,7 +136,6 @@ export async function runCli(args, options = {}) {
99
136
  const homeDirectory = options.homeDirectory ?? (await import("node:os")).homedir();
100
137
  const cwd = options.cwd ?? process.cwd();
101
138
  const platform = options.platform ?? process.platform;
102
- const artifactRoot = options.artifactRoot ?? defaultArtifactRoot({ platform, homeDirectory, env });
103
139
  const fetchImpl = options.fetchImpl ?? fetch;
104
140
  const output = options.stdout ?? process.stdout;
105
141
  const errorOutput = options.stderr ?? process.stderr;
@@ -107,57 +143,82 @@ export async function runCli(args, options = {}) {
107
143
  const write = (text) => { output.write(text); };
108
144
  const packageVersion = options.packageVersion ?? await installedPackageVersion();
109
145
  try {
110
- if (args.length === 0) {
146
+ const parsed = parseCliArguments(args, platform);
147
+ if (parsed.command === "server") {
111
148
  await (options.startServer ?? (() => startStdioServer({
112
149
  ...options,
113
150
  env,
114
151
  homeDirectory,
115
152
  cwd,
116
153
  platform,
117
- artifactRoot,
118
154
  fetchImpl,
119
155
  })))();
120
156
  return 0;
121
157
  }
122
- const command = args[0];
123
- if (command === "--help" || command === "-h" || command === "help") {
158
+ if (parsed.command === "help") {
124
159
  write(helpText());
125
160
  return 0;
126
161
  }
127
- if (command === "--version" || command === "-v") {
162
+ if (parsed.command === "version") {
128
163
  write(`${packageVersion}\n`);
129
164
  return 0;
130
165
  }
131
- if (command === "setup") {
132
- await runSetup({ env, homeDirectory, platform, fetchImpl, ask, write });
166
+ if (parsed.command === "setup") {
167
+ await runSetup({
168
+ env,
169
+ homeDirectory,
170
+ platform,
171
+ fetchImpl,
172
+ ask,
173
+ write,
174
+ stdinIsTTY: options.stdinIsTTY ?? stdin.isTTY === true,
175
+ arguments: parsed.arguments,
176
+ });
177
+ return 0;
178
+ }
179
+ if (parsed.command === "uninstall") {
180
+ await runUninstall({
181
+ args: [
182
+ ...(parsed.yes ? ["--yes"] : []),
183
+ ...(parsed.json ? ["--json"] : []),
184
+ ],
185
+ env,
186
+ homeDirectory,
187
+ platform,
188
+ write,
189
+ });
133
190
  return 0;
134
191
  }
135
- if (command === "doctor") {
136
- const lines = await runDoctor({
192
+ if (parsed.command === "doctor") {
193
+ const artifactSelection = await artifactSelectionFor(options, env, homeDirectory, cwd, platform);
194
+ const report = await runDoctor({
137
195
  env,
138
196
  homeDirectory,
139
197
  platform,
140
- artifactRoot,
198
+ artifactRoot: artifactSelection.rootDirectory,
199
+ cacheMode: artifactSelection.mode,
141
200
  fetchImpl,
142
201
  npmVersion: options.npmVersion ?? await installedNpmVersion(env),
143
202
  packageVersion,
144
203
  });
145
- write(`${lines.join("\n")}\n`);
146
- return 0;
147
- }
148
- if (command === "clean") {
149
- const result = await runClean({ artifactRoot, projectDirectory: cwd, now: options.now });
150
- write(`Removed ${result.removed} Bridge cache item(s).\n`);
204
+ write(parsed.json
205
+ ? `${JSON.stringify(report)}\n`
206
+ : `${renderDoctor(report).join("\n")}\n`);
151
207
  return 0;
152
208
  }
153
- errorOutput.write(`Unknown command: ${command}\n`);
154
- errorOutput.write(helpText());
155
- return 1;
209
+ const artifactSelection = await artifactSelectionFor(options, env, homeDirectory, cwd, platform);
210
+ const result = await runClean({
211
+ artifactRoot: artifactSelection.rootDirectory,
212
+ projectDirectory: cwd,
213
+ now: options.now,
214
+ });
215
+ write(`Removed ${result.removed} Bridge cache item(s).\n`);
216
+ return 0;
156
217
  }
157
218
  catch (error) {
158
219
  const message = error instanceof Error ? error.message : "The Bridge command failed.";
159
220
  errorOutput.write(`Error: ${message}\n`);
160
- return 1;
221
+ return error instanceof CliUsageError ? error.exitCode : 1;
161
222
  }
162
223
  }
163
224
  async function main() {
@@ -4,7 +4,9 @@ function bridgeError(code, message, retryable) {
4
4
  return new OmniBridgeError({
5
5
  code,
6
6
  message,
7
+ operationCreated: true,
7
8
  fileUploaded: false,
9
+ parserStarted: false,
8
10
  billed: false,
9
11
  contentReleased: false,
10
12
  retryable,
@@ -0,0 +1,10 @@
1
+ export declare const ONBOARDING_POLICY_URL = "https://cuecue.cn/api/v1/billing/public/onboarding-policy";
2
+ export declare const API_KEY_URL = "https://cuecue.cn/api-key";
3
+ export interface OnboardingPolicy {
4
+ readonly apiKeyUrl: typeof API_KEY_URL;
5
+ readonly firstRegistrationCredits: number;
6
+ readonly freeDailyCredits: number;
7
+ }
8
+ export declare function getOnboardingPolicy(fetchImpl: typeof fetch, signal: AbortSignal): Promise<OnboardingPolicy | undefined>;
9
+ export declare function onboardingGuidance(policy: OnboardingPolicy | undefined): string;
10
+ export declare function getOnboardingPolicyWithTimeout(fetchImpl: typeof fetch, timeoutMs?: number): Promise<OnboardingPolicy | undefined>;
@@ -0,0 +1,58 @@
1
+ export const ONBOARDING_POLICY_URL = "https://cuecue.cn/api/v1/billing/public/onboarding-policy";
2
+ export const API_KEY_URL = "https://cuecue.cn/api-key";
3
+ function isRecord(value) {
4
+ return value !== null && typeof value === "object" && !Array.isArray(value);
5
+ }
6
+ function boundedCredits(value) {
7
+ return Number.isInteger(value) && Number(value) > 0 && Number(value) <= 1_000_000;
8
+ }
9
+ function normalizeOnboardingPolicy(value) {
10
+ if (!isRecord(value))
11
+ return undefined;
12
+ if (value.api_key_url !== API_KEY_URL ||
13
+ !boundedCredits(value.first_registration) ||
14
+ !boundedCredits(value.free_daily))
15
+ return undefined;
16
+ return {
17
+ apiKeyUrl: API_KEY_URL,
18
+ firstRegistrationCredits: value.first_registration,
19
+ freeDailyCredits: value.free_daily,
20
+ };
21
+ }
22
+ export async function getOnboardingPolicy(fetchImpl, signal) {
23
+ try {
24
+ const response = await fetchImpl(ONBOARDING_POLICY_URL, {
25
+ method: "GET",
26
+ headers: { accept: "application/json" },
27
+ signal,
28
+ });
29
+ if (!response.ok)
30
+ return undefined;
31
+ return normalizeOnboardingPolicy(await response.json());
32
+ }
33
+ catch {
34
+ return undefined;
35
+ }
36
+ }
37
+ export function onboardingGuidance(policy) {
38
+ const creditLine = policy === undefined
39
+ ? `新账号有免费积分可体验,请前往 ${API_KEY_URL} 注册并创建 API Key。`
40
+ : `新账号首次注册赠送 ${policy.firstRegistrationCredits} 积分,免费账号每日有 ${policy.freeDailyCredits} 积分免费额度,可先体验 Omni,无需预先充值。`;
41
+ return [
42
+ "使用 Omni 需要配置 Cue API Key。",
43
+ `获取 API Key:${API_KEY_URL}`,
44
+ creditLine,
45
+ "创建后,请在 Agent 的安全密钥或环境设置中配置 CUE_API_KEY。请勿把 API Key 粘贴到对话中。",
46
+ ].join("\n");
47
+ }
48
+ export async function getOnboardingPolicyWithTimeout(fetchImpl, timeoutMs = 3_000) {
49
+ const controller = new AbortController();
50
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
51
+ timer.unref?.();
52
+ try {
53
+ return await getOnboardingPolicy(fetchImpl, controller.signal);
54
+ }
55
+ finally {
56
+ clearTimeout(timer);
57
+ }
58
+ }
@@ -1,13 +1,55 @@
1
- export type JournalState = "GRANT_PENDING" | "GRANT_ISSUED";
1
+ export type JournalState = "CREATED" | "GRANT_PENDING" | "GRANT_ISSUED" | "UPLOADING" | "PROCESSING" | "RESULT_READY" | "ACK_PENDING" | "CLEANUP_PENDING" | "COMPLETED" | "FAILED" | "CANCELED" | "EXPIRED";
2
+ export type JournalProgressUnit = "page" | "sheet" | "slide" | "frame" | "segment";
3
+ export type JournalCleanupState = "not_created" | "in_use" | "pending" | "deleted";
4
+ export type JournalDeliveryState = "not_created" | "pending" | "deleted_after_ack";
5
+ export interface JournalProgress {
6
+ readonly unit: JournalProgressUnit;
7
+ readonly completed: number;
8
+ readonly total: number;
9
+ }
2
10
  export interface JournalRecord {
3
11
  readonly clientRequestId: string;
4
12
  readonly requestHash: string;
13
+ readonly sourceLocatorHash: string | null;
14
+ readonly sourceKind: "local" | "url";
5
15
  readonly operationId: string | null;
6
16
  readonly operationToken: string | null;
7
17
  readonly uploadUrl: string | null;
8
18
  readonly state: JournalState;
9
19
  readonly createdAt: string;
20
+ readonly updatedAt: string;
10
21
  readonly expiresAt: string | null;
22
+ readonly stage: string | null;
23
+ readonly progressPercent: number;
24
+ readonly progress: JournalProgress | null;
25
+ readonly fileUploaded: boolean;
26
+ readonly parserStarted: boolean;
27
+ readonly billed: boolean;
28
+ readonly contentReleased: boolean;
29
+ readonly processingCopy: JournalCleanupState;
30
+ readonly temporaryData: JournalCleanupState;
31
+ readonly deliveryResult: JournalDeliveryState;
32
+ readonly resultId: string | null;
33
+ readonly resultExpiresAt: string | null;
34
+ readonly errorCode: string | null;
35
+ }
36
+ export interface JournalPatch {
37
+ readonly operationId?: string | null;
38
+ readonly operationToken?: string | null;
39
+ readonly expiresAt?: string | null;
40
+ readonly stage?: string | null;
41
+ readonly progressPercent?: number;
42
+ readonly progress?: JournalProgress | null;
43
+ readonly fileUploaded?: boolean;
44
+ readonly parserStarted?: boolean;
45
+ readonly billed?: boolean;
46
+ readonly contentReleased?: boolean;
47
+ readonly processingCopy?: JournalCleanupState;
48
+ readonly temporaryData?: JournalCleanupState;
49
+ readonly deliveryResult?: JournalDeliveryState;
50
+ readonly resultId?: string | null;
51
+ readonly resultExpiresAt?: string | null;
52
+ readonly errorCode?: string | null;
11
53
  }
12
54
  export interface IssuedGrantJournalFields {
13
55
  readonly operationId: string;
@@ -22,6 +64,13 @@ export interface OperationJournalOptions {
22
64
  export declare class OperationJournal {
23
65
  #private;
24
66
  constructor(options?: OperationJournalOptions);
67
+ beginIntent(clientRequestId: string, requestHash: string, sourceKind?: "local" | "url", sourceLocatorHash?: string | null): Promise<JournalRecord>;
68
+ transition(clientRequestId: string, expectedState: JournalState, nextState: JournalState, patch: JournalPatch): Promise<JournalRecord>;
69
+ loadByRequestId(clientRequestId: string): Promise<JournalRecord | null>;
70
+ loadByOperationId(operationId: string): Promise<JournalRecord | null>;
71
+ loadLatestByRequestHash(requestHash: string): Promise<JournalRecord | null>;
72
+ loadLatestBySourceLocatorHash(sourceLocatorHash: string): Promise<JournalRecord | null>;
73
+ listRecoverable(): Promise<JournalRecord[]>;
25
74
  begin(clientRequestId: string, requestHash: string): Promise<JournalRecord>;
26
75
  markGrantIssued(clientRequestId: string, fields: IssuedGrantJournalFields): Promise<JournalRecord>;
27
76
  load(clientRequestId: string): Promise<JournalRecord | null>;