okrapdf 0.12.0 → 0.13.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.
- package/README.md +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/{chunk-XM4MS5WV.js → chunk-2VKGPLAA.js} +233 -5
- package/dist/chunk-2VKGPLAA.js.map +1 -0
- package/dist/{chunk-YY44NPDZ.js → chunk-F3LECDPP.js} +191 -12
- package/dist/chunk-F3LECDPP.js.map +1 -0
- package/dist/chunk-KJMV6TN2.js +155 -0
- package/dist/chunk-KJMV6TN2.js.map +1 -0
- package/dist/cli/bin.js +270 -10
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/index.d.ts +16 -4
- package/dist/cli/index.js +7 -1
- package/dist/{client-CdCU6Div.d.ts → client-DMEw0oK3.d.ts} +12 -1
- package/dist/index.d.ts +20 -4
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/react/index.d.ts +3 -3
- package/dist/react/index.js +2 -2
- package/dist/{types-58dvD4Yj.d.ts → types-D2JaySEg.d.ts} +140 -2
- package/dist/url.d.ts +1 -1
- package/package.json +3 -1
- package/dist/chunk-ADVWUO22.js +0 -84
- package/dist/chunk-ADVWUO22.js.map +0 -1
- package/dist/chunk-XM4MS5WV.js.map +0 -1
- package/dist/chunk-YY44NPDZ.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/workflows.ts","../src/providers.ts"],"sourcesContent":["import type { ProcessingCapabilities } from './types';\n\nexport type WorkflowPresetName =\n | 'default'\n | 'llamaparse_ocr'\n | 'parse_proxy_ocr'\n | 'docling_ocr';\n\nexport const DEFAULT_WORKFLOW_CAPABILITIES: ProcessingCapabilities = {\n vlm_qwen: false,\n structural_check: false,\n sandbox_verify: false,\n search: false,\n};\n\nexport const WORKFLOW_PRESETS: Record<WorkflowPresetName, ProcessingCapabilities> = {\n default: { ...DEFAULT_WORKFLOW_CAPABILITIES },\n llamaparse_ocr: {\n vlm_qwen: false,\n structural_check: false,\n sandbox_verify: false,\n search: false,\n phases: {\n ocr: { vendor: 'llamaparse', enabled: true },\n },\n },\n parse_proxy_ocr: {\n vlm_qwen: false,\n structural_check: false,\n sandbox_verify: false,\n search: false,\n phases: {\n ocr: { vendor: 'parse-proxy', enabled: true },\n },\n },\n // Alias for teams routing Docling through parse-proxy-compatible HTTP endpoints.\n docling_ocr: {\n vlm_qwen: false,\n structural_check: false,\n sandbox_verify: false,\n search: false,\n phases: {\n ocr: { vendor: 'parse-proxy', enabled: true },\n },\n },\n};\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction deepMerge(base: Record<string, unknown>, override: Record<string, unknown>): Record<string, unknown> {\n const merged: Record<string, unknown> = { ...base };\n for (const [key, value] of Object.entries(override)) {\n const existing = merged[key];\n if (isPlainObject(existing) && isPlainObject(value)) {\n merged[key] = deepMerge(existing, value);\n } else {\n merged[key] = value;\n }\n }\n return merged;\n}\n\n/**\n * Returns immutable capabilities for a named workflow preset.\n * Optional overrides are deep-merged on top for per-app tuning.\n */\nexport function workflowPreset(\n name: WorkflowPresetName,\n overrides?: ProcessingCapabilities,\n): ProcessingCapabilities {\n const base = WORKFLOW_PRESETS[name];\n if (!overrides) {\n return deepMerge({}, base as Record<string, unknown>) as ProcessingCapabilities;\n }\n return deepMerge(\n base as Record<string, unknown>,\n overrides as Record<string, unknown>,\n ) as ProcessingCapabilities;\n}\n","import type { OkraClientOptions, ProcessingCapabilities } from './types';\nimport { OkraClient } from './client';\nimport { workflowPreset, type WorkflowPresetName } from './workflows';\n\nexport type ExtractionPhase = 'ocr' | 'enhance' | 'metadata' | 'verify';\n\nexport interface OkraProvider {\n name: string;\n supportedPhases: ExtractionPhase[];\n}\n\nexport interface OkraMiddleware {\n name: string;\n config: Record<string, unknown>;\n}\n\nexport interface CreateOkraOptions extends OkraClientOptions {\n providers?: Record<string, OkraProvider>;\n extraction?: Partial<Record<ExtractionPhase, string>>;\n middleware?: OkraMiddleware[];\n /** Legacy default BYOK keys (prefer `workflow.vendorKeys`). */\n vendorKeys?: Record<string, string>;\n /** General workflow defaults for all uploads from this client. */\n workflow?: {\n preset?: WorkflowPresetName;\n capabilities?: ProcessingCapabilities;\n vendorKeys?: Record<string, string>;\n };\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction deepMerge(base: Record<string, unknown>, override: Record<string, unknown>): Record<string, unknown> {\n const merged: Record<string, unknown> = { ...base };\n for (const [key, value] of Object.entries(override)) {\n const existing = merged[key];\n if (isPlainObject(existing) && isPlainObject(value)) {\n merged[key] = deepMerge(existing, value);\n } else {\n merged[key] = value;\n }\n }\n return merged;\n}\n\n/**\n * Factory function — AI SDK-style provider abstraction.\n *\n * ```ts\n * import { createOkra } from 'okrapdf';\n *\n * const okra = createOkra({\n * apiKey: 'okra_...',\n * providers: { azureDocAI },\n * extraction: { ocr: 'azureDocAI' },\n * });\n * ```\n */\nexport function createOkra(options: CreateOkraOptions): OkraClient {\n if (options.extraction && options.providers) {\n for (const [phase, providerName] of Object.entries(options.extraction)) {\n if (!options.providers[providerName]) {\n throw new Error(\n `Extraction phase '${phase}' references provider '${providerName}' which is not registered. ` +\n `Available: ${Object.keys(options.providers).join(', ')}`,\n );\n }\n }\n }\n\n let capabilities: Record<string, unknown> = options.workflow?.preset\n ? (workflowPreset(options.workflow.preset) as Record<string, unknown>)\n : {};\n if (options.extraction) {\n const phases = (capabilities.phases && isPlainObject(capabilities.phases))\n ? { ...(capabilities.phases as Record<string, unknown>) }\n : {};\n for (const [phase, providerName] of Object.entries(options.extraction)) {\n phases[phase] = {\n vendor: providerName,\n enabled: true,\n };\n }\n capabilities.phases = phases;\n }\n\n if (options.middleware) {\n capabilities.middleware = options.middleware.map((m) => ({\n name: m.name,\n ...m.config,\n }));\n }\n if (options.workflow?.capabilities) {\n capabilities = deepMerge(capabilities, options.workflow.capabilities as Record<string, unknown>);\n }\n\n const client = new OkraClient({\n baseUrl: options.baseUrl,\n apiKey: options.apiKey,\n sharedSecret: options.sharedSecret,\n fetch: options.fetch,\n });\n\n const defaultVendorKeys = options.workflow?.vendorKeys ?? options.vendorKeys;\n const hasDefaults = Object.keys(capabilities).length > 0 || defaultVendorKeys;\n if (hasDefaults) {\n const upload = client.upload.bind(client);\n client.upload = ((input: Parameters<OkraClient['upload']>[0], uploadOptions: Parameters<OkraClient['upload']>[1] = {}) =>\n upload(input, {\n ...uploadOptions,\n capabilities: uploadOptions.capabilities\n ? deepMerge(capabilities, uploadOptions.capabilities)\n : Object.keys(capabilities).length > 0\n ? capabilities\n : uploadOptions.capabilities,\n vendorKeys: uploadOptions.vendorKeys\n ? { ...defaultVendorKeys, ...uploadOptions.vendorKeys }\n : defaultVendorKeys,\n })) as OkraClient['upload'];\n }\n\n return client;\n}\n\n// ─── Built-in middleware constructors ──────────────────────────────────────\n\nexport function withCache(opts: { by: 'pdf-hash' | 'content-hash' }): OkraMiddleware {\n return { name: 'cache', config: { strategy: opts.by } };\n}\n\nexport function withQualityScore(opts: { threshold: number }): OkraMiddleware {\n return { name: 'quality-score', config: { threshold: opts.threshold } };\n}\n\nexport function withSecret(namespace: string, opts?: { required?: boolean }): OkraMiddleware {\n return {\n name: 'secret',\n config: { namespace, required: opts?.required !== false },\n };\n}\n"],"mappings":"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","names":["isPlainObject","deepMerge"]}
|
package/dist/cli/bin.js
CHANGED
|
@@ -2,14 +2,24 @@
|
|
|
2
2
|
import {
|
|
3
3
|
authLogin,
|
|
4
4
|
authLogout,
|
|
5
|
+
authSetKey,
|
|
5
6
|
authStatus,
|
|
7
|
+
authToken,
|
|
8
|
+
authWhoAmI,
|
|
9
|
+
collectionExport,
|
|
6
10
|
collectionList,
|
|
7
11
|
collectionQueryRaw,
|
|
8
12
|
collectionSetVisibility,
|
|
13
|
+
deleteDocument,
|
|
9
14
|
find,
|
|
10
15
|
formatCollectionCsv,
|
|
16
|
+
formatCollectionExportFlat,
|
|
11
17
|
formatCollectionList,
|
|
12
18
|
formatCollectionTable,
|
|
19
|
+
formatDocumentList,
|
|
20
|
+
formatExtractCsv,
|
|
21
|
+
formatExtractJson,
|
|
22
|
+
formatExtractTable,
|
|
13
23
|
formatFindOutput,
|
|
14
24
|
formatHistoryOutput,
|
|
15
25
|
formatPageOutput,
|
|
@@ -24,27 +34,32 @@ import {
|
|
|
24
34
|
getBaseUrl,
|
|
25
35
|
handleError,
|
|
26
36
|
history,
|
|
37
|
+
listDocuments,
|
|
27
38
|
pageEdit,
|
|
28
39
|
pageGet,
|
|
29
40
|
pageResolve,
|
|
30
41
|
pageVersions,
|
|
31
42
|
progress,
|
|
43
|
+
readDocument,
|
|
32
44
|
search,
|
|
33
45
|
tables,
|
|
34
46
|
toc,
|
|
35
47
|
tree,
|
|
36
48
|
upload,
|
|
37
49
|
writeOutput
|
|
38
|
-
} from "../chunk-
|
|
50
|
+
} from "../chunk-F3LECDPP.js";
|
|
39
51
|
import {
|
|
40
52
|
OkraClient
|
|
41
|
-
} from "../chunk-
|
|
53
|
+
} from "../chunk-2VKGPLAA.js";
|
|
42
54
|
import "../chunk-NIZM2ETT.js";
|
|
43
55
|
|
|
44
56
|
// src/cli/bin.ts
|
|
45
57
|
import { Command } from "commander";
|
|
58
|
+
import { writeFileSync } from "fs";
|
|
46
59
|
var program = new Command();
|
|
47
|
-
program.
|
|
60
|
+
program.showHelpAfterError();
|
|
61
|
+
program.showSuggestionAfterError();
|
|
62
|
+
program.name("okra").description("OkraPDF CLI \u2014 upload PDFs, query collections, extract data").version("0.12.1").option("-j, --json", "Output JSON (structured, machine-readable)").option("-q, --quiet", "Suppress progress and human-readable frills").option("-o, --output <file>", "Write output to file instead of stdout");
|
|
48
63
|
function globals() {
|
|
49
64
|
return program.opts();
|
|
50
65
|
}
|
|
@@ -57,14 +72,14 @@ function getClient() {
|
|
|
57
72
|
process.stderr.write(JSON.stringify({ error: "No API key found", code: 401 }) + "\n");
|
|
58
73
|
} else {
|
|
59
74
|
process.stderr.write(
|
|
60
|
-
'No API key found.\n\n Get one: https://okrapdf.
|
|
75
|
+
'No API key found.\n\n Get one: https://docs.okrapdf.com/api-keys\n Then: export OKRA_API_KEY="okra_xxx"\n Or: npx okra auth login\n\n Docs: https://docs.okrapdf.com\n Discord: https://discord.gg/BHNmbZVs\n'
|
|
61
76
|
);
|
|
62
77
|
}
|
|
63
78
|
process.exit(1);
|
|
64
79
|
}
|
|
65
80
|
return new OkraClient({ apiKey, baseUrl });
|
|
66
81
|
}
|
|
67
|
-
|
|
82
|
+
async function runUploadCommand(source, options) {
|
|
68
83
|
const g = globals();
|
|
69
84
|
try {
|
|
70
85
|
const client = getClient();
|
|
@@ -89,16 +104,169 @@ program.command("upload <source>").description("Upload a PDF (file path or URL),
|
|
|
89
104
|
lines.push(" /v1/documents/{id}/d_shimmer/pg_{N}.png page image");
|
|
90
105
|
lines.push(" /v1/documents/{id}/full.md full document");
|
|
91
106
|
lines.push("");
|
|
92
|
-
lines.push(" Docs: https://okrapdf.
|
|
107
|
+
lines.push(" Docs: https://docs.okrapdf.com Discord: https://discord.gg/BHNmbZVs");
|
|
93
108
|
}
|
|
94
109
|
writeOutput(lines.join("\n"), g.output);
|
|
95
110
|
}
|
|
96
111
|
} catch (error) {
|
|
97
112
|
handleError(error, g.json);
|
|
98
113
|
}
|
|
114
|
+
}
|
|
115
|
+
function registerUploadCommand(commandName, description) {
|
|
116
|
+
program.command(`${commandName} <source>`).description(description).option("--no-wait", "Fire-and-forget (don't wait for processing)").action(async (source, options) => {
|
|
117
|
+
await runUploadCommand(source, options);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
registerUploadCommand("upload", "Upload a PDF (file path or URL), wait for processing");
|
|
121
|
+
program.command("extract <source>").description("Extract structured data from a document (doc ID, URL, or file path)").option("--no-wait", "Fire-and-forget (don't wait for processing)").option("--schema <file>", "JSON Schema file or inline JSON for structured extraction").option("--prompt <query>", 'Extraction prompt (default: "Extract all data according to the schema")').action(async (source, options) => {
|
|
122
|
+
const g = globals();
|
|
123
|
+
try {
|
|
124
|
+
const client = getClient();
|
|
125
|
+
const { readFileSync } = await import("fs");
|
|
126
|
+
const isExistingDoc = /^(?:ocr|doc)-[A-Za-z0-9_-]+$/.test(source);
|
|
127
|
+
let docId;
|
|
128
|
+
if (isExistingDoc) {
|
|
129
|
+
docId = source;
|
|
130
|
+
} else {
|
|
131
|
+
const result = await upload(client, source, {
|
|
132
|
+
...g,
|
|
133
|
+
noWait: options.wait === false
|
|
134
|
+
});
|
|
135
|
+
docId = result.id;
|
|
136
|
+
if (!options.schema || options.wait === false) {
|
|
137
|
+
if (g.json) {
|
|
138
|
+
writeOutput(JSON.stringify(result), g.output);
|
|
139
|
+
} else {
|
|
140
|
+
const lines = [`Done \u2014 ${result.pages ?? "?"} pages`, ""];
|
|
141
|
+
lines.push(` ${docId}`);
|
|
142
|
+
if (result.urls) {
|
|
143
|
+
const short = docId.slice(0, 11) + "...";
|
|
144
|
+
lines.push("");
|
|
145
|
+
lines.push(` Markdown: ${result.urls.full_md.replace(docId, short)}`);
|
|
146
|
+
lines.push(` Page 1: ${result.urls.page_png.replace(docId, short).replace("{N}", "1")}`);
|
|
147
|
+
lines.push(` Completion: ${result.urls.completion.replace(docId, short)}`);
|
|
148
|
+
}
|
|
149
|
+
writeOutput(lines.join("\n"), g.output);
|
|
150
|
+
}
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (!options.schema) {
|
|
155
|
+
if (isExistingDoc) {
|
|
156
|
+
writeOutput("Error: --schema is required when extracting from an existing document.", g.output);
|
|
157
|
+
process.exitCode = 1;
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
let schemaJson;
|
|
163
|
+
const schemaArg = options.schema;
|
|
164
|
+
if (schemaArg.startsWith("{")) {
|
|
165
|
+
schemaJson = JSON.parse(schemaArg);
|
|
166
|
+
} else {
|
|
167
|
+
schemaJson = JSON.parse(readFileSync(schemaArg, "utf8"));
|
|
168
|
+
}
|
|
169
|
+
const prompt = options.prompt || "Extract all data from this document according to the schema.";
|
|
170
|
+
progress(`Extracting from ${docId}\u2026`, g.quiet);
|
|
171
|
+
const extraction = await client.generate(docId, prompt, { schema: schemaJson });
|
|
172
|
+
if (g.json) {
|
|
173
|
+
writeOutput(JSON.stringify({
|
|
174
|
+
doc_id: docId,
|
|
175
|
+
data: extraction.data ?? extraction.answer
|
|
176
|
+
}), g.output);
|
|
177
|
+
} else if (g.output && g.output.endsWith(".csv")) {
|
|
178
|
+
const data = extraction.data ?? {};
|
|
179
|
+
const keys = Object.keys(data);
|
|
180
|
+
const header = ["doc_id", ...keys].join(",");
|
|
181
|
+
const values = keys.map((k) => {
|
|
182
|
+
const v = data[k];
|
|
183
|
+
if (v == null) return "";
|
|
184
|
+
if (typeof v === "string") return `"${String(v).replace(/"/g, '""')}"`;
|
|
185
|
+
return String(v);
|
|
186
|
+
});
|
|
187
|
+
writeOutput([header, [docId, ...values].join(",")].join("\n"), g.output);
|
|
188
|
+
} else {
|
|
189
|
+
writeOutput(JSON.stringify(extraction.data ?? extraction.answer, null, 2), g.output);
|
|
190
|
+
}
|
|
191
|
+
} catch (error) {
|
|
192
|
+
handleError(error, g.json);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
program.command("status <docId>").description("Get document processing status").action(async (docId) => {
|
|
196
|
+
const g = globals();
|
|
197
|
+
try {
|
|
198
|
+
const client = getClient();
|
|
199
|
+
const status = await client.status(docId);
|
|
200
|
+
if (g.json) {
|
|
201
|
+
writeOutput(JSON.stringify(status), g.output);
|
|
202
|
+
} else {
|
|
203
|
+
const lines = [
|
|
204
|
+
`Document: ${docId}`,
|
|
205
|
+
`Phase: ${status.phase}`
|
|
206
|
+
];
|
|
207
|
+
if (typeof status.pagesCompleted === "number" || typeof status.pagesTotal === "number") {
|
|
208
|
+
lines.push(`Pages: ${status.pagesCompleted ?? "?"} / ${status.pagesTotal ?? "?"}`);
|
|
209
|
+
}
|
|
210
|
+
writeOutput(lines.join("\n"), g.output);
|
|
211
|
+
}
|
|
212
|
+
} catch (error) {
|
|
213
|
+
handleError(error, g.json);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
program.command("chat <question>").description("Ask a question about a processed document").requiredOption("--doc <id>", "Document ID").option("--model <name>", "Override model").action(async (question, options) => {
|
|
217
|
+
const g = globals();
|
|
218
|
+
try {
|
|
219
|
+
const client = getClient();
|
|
220
|
+
const result = await client.generate(options.doc, question, options.model ? { model: options.model } : void 0);
|
|
221
|
+
if (g.json) {
|
|
222
|
+
writeOutput(JSON.stringify({ docId: options.doc, question, ...result }), g.output);
|
|
223
|
+
} else {
|
|
224
|
+
writeOutput(result.answer, g.output);
|
|
225
|
+
}
|
|
226
|
+
} catch (error) {
|
|
227
|
+
handleError(error, g.json);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
program.command("list").alias("ls").description("List all documents").action(async () => {
|
|
231
|
+
const g = globals();
|
|
232
|
+
try {
|
|
233
|
+
const client = getClient();
|
|
234
|
+
const { documents } = await listDocuments(client, g);
|
|
235
|
+
writeOutput(formatDocumentList(documents, g.json), g.output);
|
|
236
|
+
} catch (error) {
|
|
237
|
+
handleError(error, g.json);
|
|
238
|
+
}
|
|
99
239
|
});
|
|
100
|
-
|
|
101
|
-
|
|
240
|
+
program.command("delete <docId>").alias("rm").description("Delete a document").action(async (docId) => {
|
|
241
|
+
const g = globals();
|
|
242
|
+
try {
|
|
243
|
+
const client = getClient();
|
|
244
|
+
const result = await deleteDocument(client, docId, g);
|
|
245
|
+
if (g.json) {
|
|
246
|
+
writeOutput(JSON.stringify(result), g.output);
|
|
247
|
+
} else {
|
|
248
|
+
writeOutput(`Deleted ${docId}`, g.output);
|
|
249
|
+
}
|
|
250
|
+
} catch (error) {
|
|
251
|
+
handleError(error, g.json);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
program.command("read <docId>").description("Read document as markdown").option("-p, --pages <range>", "Page range (e.g., 1-5, 10-15)").action(async (docId, options) => {
|
|
255
|
+
const g = globals();
|
|
256
|
+
try {
|
|
257
|
+
const client = getClient();
|
|
258
|
+
const result = await readDocument(client, docId, { ...g, pages: options.pages });
|
|
259
|
+
if (g.json) {
|
|
260
|
+
writeOutput(JSON.stringify(result), g.output);
|
|
261
|
+
} else {
|
|
262
|
+
writeOutput(result.markdown, g.output);
|
|
263
|
+
}
|
|
264
|
+
} catch (error) {
|
|
265
|
+
handleError(error, g.json);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
var collectionCmd = program.command("collection").alias("collections").alias("col").description("Collection operations");
|
|
269
|
+
collectionCmd.command("list").alias("ls").description("List available collections").action(async () => {
|
|
102
270
|
const g = globals();
|
|
103
271
|
try {
|
|
104
272
|
const client = getClient();
|
|
@@ -135,6 +303,43 @@ collectionCmd.command("query <nameOrId> <question>").description("Fan-out query
|
|
|
135
303
|
handleError(error, g.json);
|
|
136
304
|
}
|
|
137
305
|
});
|
|
306
|
+
collectionCmd.command("extract <nameOrId>").description("Extract structured data from all documents in a collection").requiredOption("--schema <file>", "JSON Schema file or inline JSON for structured extraction").option("--prompt <query>", "Extraction prompt (default: auto-generated from schema)").action(async (nameOrId, options) => {
|
|
307
|
+
const g = globals();
|
|
308
|
+
try {
|
|
309
|
+
const client = getClient();
|
|
310
|
+
const { readFileSync } = await import("fs");
|
|
311
|
+
let schemaJson;
|
|
312
|
+
const schemaArg = options.schema;
|
|
313
|
+
if (schemaArg.startsWith("{")) {
|
|
314
|
+
schemaJson = JSON.parse(schemaArg);
|
|
315
|
+
} else {
|
|
316
|
+
schemaJson = JSON.parse(readFileSync(schemaArg, "utf8"));
|
|
317
|
+
}
|
|
318
|
+
const prompt = options.prompt || "Extract all data from this document according to the schema.";
|
|
319
|
+
const { results, summary } = await collectionQueryRaw(
|
|
320
|
+
client,
|
|
321
|
+
nameOrId,
|
|
322
|
+
prompt,
|
|
323
|
+
{ ...g, schema: schemaJson }
|
|
324
|
+
);
|
|
325
|
+
if (g.json) {
|
|
326
|
+
writeOutput(formatExtractJson(results), g.output);
|
|
327
|
+
} else if (g.output && g.output.endsWith(".csv")) {
|
|
328
|
+
writeOutput(formatExtractCsv(results), g.output);
|
|
329
|
+
} else if (g.output) {
|
|
330
|
+
writeOutput(formatExtractJson(results), g.output);
|
|
331
|
+
} else {
|
|
332
|
+
writeOutput(formatExtractTable(results));
|
|
333
|
+
}
|
|
334
|
+
progress(
|
|
335
|
+
`
|
|
336
|
+
${summary.completed} documents \u2014 $${summary.total_cost_usd.toFixed(4)} total`,
|
|
337
|
+
g.quiet
|
|
338
|
+
);
|
|
339
|
+
} catch (error) {
|
|
340
|
+
handleError(error, g.json);
|
|
341
|
+
}
|
|
342
|
+
});
|
|
138
343
|
collectionCmd.command("publish <nameOrId>").description("Make a collection publicly queryable").action(async (nameOrId) => {
|
|
139
344
|
const g = globals();
|
|
140
345
|
try {
|
|
@@ -167,10 +372,51 @@ collectionCmd.command("unpublish <nameOrId>").description("Make a collection pri
|
|
|
167
372
|
handleError(error, g.json);
|
|
168
373
|
}
|
|
169
374
|
});
|
|
375
|
+
collectionCmd.command("export <nameOrId>").description("Export pre-computed markdown for all documents in a collection").option("--flat", "Concatenated markdown with # headers + === separators").option("--zip", "One markdown file per document in a .zip archive").action(async (nameOrId, options) => {
|
|
376
|
+
const g = globals();
|
|
377
|
+
try {
|
|
378
|
+
const client = getClient();
|
|
379
|
+
if (options.flat && options.zip) {
|
|
380
|
+
throw new Error("Use either --flat or --zip, not both");
|
|
381
|
+
}
|
|
382
|
+
if (options.zip) {
|
|
383
|
+
const bytes = await collectionExport(client, nameOrId, { ...g, zip: true });
|
|
384
|
+
const safeBase = String(nameOrId).trim().replace(/[^A-Za-z0-9._-]+/g, "-").replace(/-{2,}/g, "-").replace(/^[-_.]+|[-_.]+$/g, "") || "collection-export";
|
|
385
|
+
const outputPath = g.output || `${safeBase}.zip`;
|
|
386
|
+
writeFileSync(outputPath, bytes);
|
|
387
|
+
progress(`Wrote \u2192 ${outputPath}`, g.quiet);
|
|
388
|
+
if (g.json) {
|
|
389
|
+
writeOutput(JSON.stringify({
|
|
390
|
+
format: "zip",
|
|
391
|
+
file: outputPath,
|
|
392
|
+
bytes: bytes.byteLength
|
|
393
|
+
}));
|
|
394
|
+
}
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
const result = await collectionExport(client, nameOrId, { ...g, flat: options.flat });
|
|
398
|
+
if (options.flat) {
|
|
399
|
+
writeOutput(formatCollectionExportFlat(result), g.output);
|
|
400
|
+
} else if (g.json) {
|
|
401
|
+
writeOutput(JSON.stringify(result), g.output);
|
|
402
|
+
} else {
|
|
403
|
+
writeOutput(JSON.stringify(result, null, 2), g.output);
|
|
404
|
+
}
|
|
405
|
+
} catch (error) {
|
|
406
|
+
handleError(error, g.json);
|
|
407
|
+
}
|
|
408
|
+
});
|
|
170
409
|
var authCmd = program.command("auth").description("Manage authentication");
|
|
171
|
-
authCmd.command("login").description("Save API key to global config").action(async () => {
|
|
410
|
+
authCmd.command("login").description("Save API key to global config").option("-k, --key <apiKey>", "Set API key non-interactively").action(async (options) => {
|
|
172
411
|
try {
|
|
173
|
-
await authLogin();
|
|
412
|
+
await authLogin(options.key);
|
|
413
|
+
} catch (error) {
|
|
414
|
+
handleError(error, globals().json);
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
authCmd.command("set-key <apiKey>").description("Save API key to global config (non-interactive)").action(async (apiKey) => {
|
|
418
|
+
try {
|
|
419
|
+
await authSetKey(apiKey);
|
|
174
420
|
} catch (error) {
|
|
175
421
|
handleError(error, globals().json);
|
|
176
422
|
}
|
|
@@ -182,6 +428,20 @@ authCmd.command("status").description("Show authentication status").action(async
|
|
|
182
428
|
handleError(error, globals().json);
|
|
183
429
|
}
|
|
184
430
|
});
|
|
431
|
+
authCmd.command("whoami").description("Show current auth identity (alias for status)").action(async () => {
|
|
432
|
+
try {
|
|
433
|
+
await authWhoAmI();
|
|
434
|
+
} catch (error) {
|
|
435
|
+
handleError(error, globals().json);
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
authCmd.command("token").description("Print active API key to stdout").action(async () => {
|
|
439
|
+
try {
|
|
440
|
+
await authToken();
|
|
441
|
+
} catch (error) {
|
|
442
|
+
handleError(error, globals().json);
|
|
443
|
+
}
|
|
444
|
+
});
|
|
185
445
|
authCmd.command("logout").description("Remove API key from global config").action(async () => {
|
|
186
446
|
try {
|
|
187
447
|
await authLogout();
|
package/dist/cli/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/bin.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * okra CLI — Agent-friendly PDF extraction and collection queries.\n *\n * Global flags:\n * -j, --json Structured JSON output\n * -q, --quiet Suppress progress (just data to stdout)\n * -o, --output Write output to file (CSV/JSON)\n *\n * Action commands (agent-grade):\n * okra upload <source> # Upload + wait\n * okra collection list # List collections\n * okra collection query <name> \"<question>\" # Fan-out → CSV\n *\n * Review commands (existing):\n * okra tree / find / page / search / tables / history / toc\n *\n * Exit codes: 0=success, 1=client error, 2=server error\n */\n\nimport { Command } from 'commander';\nimport { OkraClient } from '../client';\nimport {\n tree,\n formatTreeOutput,\n find,\n formatFindOutput,\n formatStats,\n pageGet,\n pageEdit,\n pageResolve,\n pageVersions,\n formatPageOutput,\n formatVersionsOutput,\n search,\n formatSearchOutput,\n tables,\n formatTablesOutput,\n history,\n formatHistoryOutput,\n toc,\n formatTocOutput,\n authLogin,\n authStatus,\n authLogout,\n upload,\n collectionList,\n collectionSetVisibility,\n collectionQueryRaw,\n formatCollectionList,\n formatCollectionCsv,\n formatCollectionTable,\n formatQueryJsonl,\n} from './commands';\nimport { getApiKey, getBaseUrl } from './config';\nimport { handleError, writeOutput, progress } from './output';\nimport type { GlobalFlags } from './output';\n\nconst program = new Command();\n\nprogram\n .name('okra')\n .description('OkraPDF CLI — upload PDFs, query collections, extract data')\n .version('0.9.0')\n .option('-j, --json', 'Output JSON (structured, machine-readable)')\n .option('-q, --quiet', 'Suppress progress and human-readable frills')\n .option('-o, --output <file>', 'Write output to file instead of stdout');\n\n/** Read global flags from program.opts(). */\nfunction globals(): GlobalFlags {\n return program.opts();\n}\n\n// Create client with proper config priority:\n// 1. Environment variable (OKRA_API_KEY)\n// 2. Project config (.okrarc, .okra.json)\n// 3. Global config (~/.okra/config.json)\nfunction getClient(): OkraClient {\n const apiKey = getApiKey();\n const baseUrl = getBaseUrl();\n\n if (!apiKey) {\n const g = globals();\n if (g.json) {\n process.stderr.write(JSON.stringify({ error: 'No API key found', code: 401 }) + '\\n');\n } else {\n process.stderr.write(\n 'No API key found.\\n\\n' +\n ' Get one: https://okrapdf.dev/api-keys\\n' +\n ' Then: export OKRA_API_KEY=\"okra_xxx\"\\n' +\n ' Or: npx okra auth login\\n\\n' +\n ' Docs: https://okrapdf.dev/docs\\n' +\n ' Discord: https://discord.gg/BHNmbZVs\\n',\n );\n }\n process.exit(1);\n }\n\n return new OkraClient({ apiKey, baseUrl });\n}\n\n// ============================================================================\n// upload command\n// ============================================================================\nprogram\n .command('upload <source>')\n .description('Upload a PDF (file path or URL), wait for processing')\n .option('--no-wait', 'Fire-and-forget (don\\'t wait for processing)')\n .action(async (source, options) => {\n const g = globals();\n try {\n const client = getClient();\n const result = await upload(client, source, {\n ...g,\n noWait: options.wait === false,\n });\n\n if (g.json) {\n writeOutput(JSON.stringify(result), g.output);\n } else {\n const lines = [`Done — ${result.pages ?? '?'} pages`, ''];\n lines.push(` ${result.id}`);\n if (result.urls) {\n const short = result.id.slice(0, 11) + '...';\n lines.push('');\n lines.push(` Markdown: ${result.urls.full_md.replace(result.id, short)}`);\n lines.push(` Page 1: ${result.urls.page_png.replace(result.id, short).replace('{N}', '1')}`);\n lines.push(` Completion: ${result.urls.completion.replace(result.id, short)}`);\n lines.push('');\n lines.push(' URL patterns:');\n lines.push(' /v1/documents/{id}/pg_{N}.md page markdown');\n lines.push(' /v1/documents/{id}/d_shimmer/pg_{N}.png page image');\n lines.push(' /v1/documents/{id}/full.md full document');\n lines.push('');\n lines.push(' Docs: https://okrapdf.dev/docs Discord: https://discord.gg/BHNmbZVs');\n }\n writeOutput(lines.join('\\n'), g.output);\n }\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// collection command\n// ============================================================================\nconst collectionCmd = program.command('collection').description('Collection operations');\n\ncollectionCmd\n .command('list')\n .description('List available collections')\n .action(async () => {\n const g = globals();\n try {\n const client = getClient();\n const rows = await collectionList(client, g);\n writeOutput(formatCollectionList(rows, g.json), g.output);\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\ncollectionCmd\n .command('query <nameOrId> <question>')\n .description('Fan-out query across collection documents')\n .option('--schema <file>', 'JSON Schema file for structured extraction')\n .action(async (nameOrId, question, options) => {\n const g = globals();\n try {\n const client = getClient();\n const { results, summary } = await collectionQueryRaw(\n client,\n nameOrId,\n question,\n { ...g, schema: options.schema },\n );\n\n // Determine output format based on flags\n if (g.json) {\n // --json: JSONL events to stdout\n writeOutput(formatQueryJsonl(results), g.output);\n } else if (g.output && g.output.endsWith('.csv')) {\n // -o file.csv → CSV\n writeOutput(formatCollectionCsv(results), g.output);\n } else if (g.output) {\n // -o file.json or other → JSON\n writeOutput(JSON.stringify({ results, summary }), g.output);\n } else {\n // Default: compact table to stdout\n writeOutput(formatCollectionTable(results));\n }\n\n progress(\n `${summary.completed} completed, ${summary.failed} failed — $${summary.total_cost_usd.toFixed(4)}`,\n g.quiet,\n );\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\ncollectionCmd\n .command('publish <nameOrId>')\n .description('Make a collection publicly queryable')\n .action(async (nameOrId) => {\n const g = globals();\n try {\n const client = getClient();\n await collectionSetVisibility(client, nameOrId, 'public');\n if (g.json) {\n writeOutput(JSON.stringify({ ok: true, visibility: 'public', collection: nameOrId }), g.output);\n } else {\n writeOutput(\n `Published \"${nameOrId}\"\\n` +\n `Share with: okra collection query ${nameOrId} \"your question\"`,\n g.output,\n );\n }\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\ncollectionCmd\n .command('unpublish <nameOrId>')\n .description('Make a collection private (owner-only)')\n .action(async (nameOrId) => {\n const g = globals();\n try {\n const client = getClient();\n await collectionSetVisibility(client, nameOrId, 'private');\n if (g.json) {\n writeOutput(JSON.stringify({ ok: true, visibility: 'private', collection: nameOrId }), g.output);\n } else {\n writeOutput(`Unpublished \"${nameOrId}\" — now private`, g.output);\n }\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// auth command - Authentication management\n// ============================================================================\nconst authCmd = program.command('auth').description('Manage authentication');\n\nauthCmd\n .command('login')\n .description('Save API key to global config')\n .action(async () => {\n try {\n await authLogin();\n } catch (error) {\n handleError(error, globals().json);\n }\n });\n\nauthCmd\n .command('status')\n .description('Show authentication status')\n .action(async () => {\n try {\n await authStatus();\n } catch (error) {\n handleError(error, globals().json);\n }\n });\n\nauthCmd\n .command('logout')\n .description('Remove API key from global config')\n .action(async () => {\n try {\n await authLogout();\n } catch (error) {\n handleError(error, globals().json);\n }\n });\n\n// ============================================================================\n// tree command - Document verification tree\n// ============================================================================\nprogram\n .command('tree <jobId>')\n .description('Show document verification tree')\n .option('-s, --status <status>', 'Filter by status (complete|partial|pending|flagged|empty|gap)')\n .option('-e, --entity <type>', 'Filter by entity type (table|figure|footnote)')\n .option('-f, --format <format>', 'Output format (text|json|markdown)', 'text')\n .action(async (jobId, options) => {\n const g = globals();\n try {\n const client = getClient();\n const fmt = g.json ? 'json' : options.format;\n const result = await tree(client, jobId, {\n status: options.status,\n entity: options.entity,\n });\n writeOutput(formatTreeOutput(result, fmt), g.output);\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// find command - jQuery-like entity search\n// ============================================================================\nprogram\n .command('find <jobId> <selector>')\n .description('Find entities using jQuery-like selectors')\n .option('-k, --top-k <n>', 'Limit results', parseInt)\n .option('-c, --min-confidence <n>', 'Minimum confidence (0-1)', parseFloat)\n .option('-p, --pages <range>', 'Page range (e.g., 1-10)')\n .option('--sort <by>', 'Sort by (confidence|page|type)')\n .option('--stats', 'Show aggregate statistics')\n .option('-f, --format <format>', 'Output format (text|json|entities|ids)', 'text')\n .action(async (jobId, selector, options) => {\n const g = globals();\n try {\n const client = getClient();\n const fmt = g.json ? 'json' : options.format;\n const pageRange = options.pages\n ? options.pages.split('-').map(Number) as [number, number]\n : undefined;\n\n const result = await find(client, jobId, selector, {\n topK: options.topK,\n minConfidence: options.minConfidence,\n pageRange,\n sortBy: options.sort,\n });\n\n if (options.stats && fmt === 'text') {\n writeOutput(formatStats(result.stats), g.output);\n } else {\n writeOutput(formatFindOutput(result, fmt, options.stats), g.output);\n }\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// page command - Page content operations\n// ============================================================================\nconst pageCmd = program.command('page').description('Page content operations');\n\npageCmd\n .command('get <jobId> <pageNum>')\n .description('Get page content')\n .option('-v, --version <n>', 'Specific version', parseInt)\n .option('-f, --format <format>', 'Output format (text|json|markdown)', 'markdown')\n .action(async (jobId, pageNum, options) => {\n const g = globals();\n try {\n const client = getClient();\n const fmt = g.json ? 'json' : options.format;\n const content = await pageGet(client, jobId, parseInt(pageNum), {\n version: options.version,\n });\n writeOutput(formatPageOutput(content, fmt), g.output);\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\npageCmd\n .command('edit <jobId> <pageNum>')\n .description('Edit page content (reads from stdin)')\n .action(async (jobId, pageNum) => {\n const g = globals();\n try {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk);\n }\n const content = Buffer.concat(chunks).toString('utf8');\n\n const client = getClient();\n const result = await pageEdit(client, jobId, parseInt(pageNum), content);\n if (g.json) {\n writeOutput(JSON.stringify({ version: result.version }), g.output);\n } else {\n writeOutput(`Saved as version ${result.version}`, g.output);\n }\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\npageCmd\n .command('resolve <jobId> <pageNum> <resolution>')\n .description('Resolve page verification status')\n .option('-c, --classification <class>', 'Classification')\n .option('-r, --reason <reason>', 'Reason')\n .action(async (jobId, pageNum, resolution, options) => {\n const g = globals();\n try {\n const client = getClient();\n const result = await pageResolve(client, jobId, parseInt(pageNum), {\n resolution,\n classification: options.classification,\n reason: options.reason,\n });\n if (g.json) {\n writeOutput(JSON.stringify({ success: result.success }), g.output);\n } else {\n writeOutput(result.success ? 'Resolved' : 'Failed', g.output);\n }\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\npageCmd\n .command('versions <jobId> <pageNum>')\n .description('List page versions')\n .option('-f, --format <format>', 'Output format (text|json)', 'text')\n .action(async (jobId, pageNum, options) => {\n const g = globals();\n try {\n const client = getClient();\n const fmt = g.json ? 'json' : options.format;\n const versions = await pageVersions(client, jobId, parseInt(pageNum));\n writeOutput(formatVersionsOutput(versions, fmt), g.output);\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// search command - Full-text search\n// ============================================================================\nprogram\n .command('search <jobId> <query>')\n .description('Search page content')\n .option('-f, --format <format>', 'Output format (text|json)', 'text')\n .action(async (jobId, query, options) => {\n const g = globals();\n try {\n const client = getClient();\n const fmt = g.json ? 'json' : options.format;\n const result = await search(client, jobId, query);\n writeOutput(formatSearchOutput(result, fmt), g.output);\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// tables command - List tables\n// ============================================================================\nprogram\n .command('tables <jobId>')\n .description('List extracted tables')\n .option('-p, --page <n>', 'Filter by page', parseInt)\n .option('-s, --status <status>', 'Filter by status (pending|verified|flagged|rejected)')\n .option('-f, --format <format>', 'Output format (text|json|markdown)', 'text')\n .action(async (jobId, options) => {\n const g = globals();\n try {\n const client = getClient();\n const fmt = g.json ? 'json' : options.format;\n const result = await tables(client, jobId, {\n page: options.page,\n status: options.status,\n });\n writeOutput(formatTablesOutput(result, fmt), g.output);\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// history command - Verification audit trail\n// ============================================================================\nprogram\n .command('history <jobId>')\n .description('Show verification history')\n .option('-l, --limit <n>', 'Limit entries', parseInt, 50)\n .option('-f, --format <format>', 'Output format (text|json)', 'text')\n .action(async (jobId, options) => {\n const g = globals();\n try {\n const client = getClient();\n const fmt = g.json ? 'json' : options.format;\n const result = await history(client, jobId, { limit: options.limit });\n writeOutput(formatHistoryOutput(result, fmt), g.output);\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// toc command - Table of contents extraction\n// ============================================================================\nprogram\n .command('toc <jobId>')\n .description('Extract table of contents from PDF')\n .option('--max-depth <n>', 'Maximum TOC depth', parseInt)\n .option('-f, --format <format>', 'Output format (text|json|markdown)', 'text')\n .option('--watch', 'Watch live extraction events via WebSocket')\n .action(async (jobId, options) => {\n const g = globals();\n try {\n const client = getClient();\n const fmt = g.json ? 'json' : options.format;\n const result = await toc(client, jobId, {\n maxDepth: options.maxDepth,\n watch: options.watch,\n });\n writeOutput(formatTocOutput(result, fmt), g.output);\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\nprogram.parse();\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/bin.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * okra CLI — Agent-friendly PDF extraction and collection queries.\n *\n * Global flags:\n * -j, --json Structured JSON output\n * -q, --quiet Suppress progress (just data to stdout)\n * -o, --output Write output to file (CSV/JSON/ZIP)\n *\n * Action commands (agent-grade):\n * okra upload <source> # Upload + wait\n * okra extract <source> --schema schema.json # Upload + structured extract\n * okra extract <docId> --schema schema.json # Extract from existing doc\n * okra list # List documents\n * okra read <id> [--pages 1-5] # Full markdown\n * okra delete <id> # Delete document\n * okra chat \"<question>\" --doc <id> # Ask a question\n * okra collection list # List collections\n * okra collection query <name> \"<question>\" # Fan-out → CSV\n * okra collection extract <name> --schema s.json # Structured extract → CSV\n *\n * Review commands:\n * okra tree / find / page / search / tables / history / toc\n *\n * Exit codes: 0=success, 1=client error, 2=server error\n */\n\nimport { Command } from 'commander';\nimport { writeFileSync } from 'fs';\nimport { OkraClient } from '../client';\nimport {\n tree,\n formatTreeOutput,\n find,\n formatFindOutput,\n formatStats,\n pageGet,\n pageEdit,\n pageResolve,\n pageVersions,\n formatPageOutput,\n formatVersionsOutput,\n search,\n formatSearchOutput,\n tables,\n formatTablesOutput,\n history,\n formatHistoryOutput,\n toc,\n formatTocOutput,\n authLogin,\n authSetKey,\n authStatus,\n authWhoAmI,\n authToken,\n authLogout,\n upload,\n listDocuments,\n formatDocumentList,\n deleteDocument,\n readDocument,\n collectionList,\n collectionSetVisibility,\n collectionQueryRaw,\n collectionExport,\n formatCollectionList,\n formatCollectionCsv,\n formatCollectionTable,\n formatQueryJsonl,\n formatCollectionExportFlat,\n formatExtractCsv,\n formatExtractTable,\n formatExtractJson,\n} from './commands';\nimport { getApiKey, getBaseUrl } from './config';\nimport { handleError, writeOutput, progress } from './output';\nimport type { GlobalFlags } from './output';\n\nconst program = new Command();\nprogram.showHelpAfterError();\nprogram.showSuggestionAfterError();\n\nprogram\n .name('okra')\n .description('OkraPDF CLI — upload PDFs, query collections, extract data')\n .version('0.12.1')\n .option('-j, --json', 'Output JSON (structured, machine-readable)')\n .option('-q, --quiet', 'Suppress progress and human-readable frills')\n .option('-o, --output <file>', 'Write output to file instead of stdout');\n\n/** Read global flags from program.opts(). */\nfunction globals(): GlobalFlags {\n return program.opts();\n}\n\n// Create client with proper config priority:\n// 1. Environment variable (OKRA_API_KEY)\n// 2. Project config (.okrarc, .okra.json)\n// 3. Global config (~/.okra/config.json)\nfunction getClient(): OkraClient {\n const apiKey = getApiKey();\n const baseUrl = getBaseUrl();\n\n if (!apiKey) {\n const g = globals();\n if (g.json) {\n process.stderr.write(JSON.stringify({ error: 'No API key found', code: 401 }) + '\\n');\n } else {\n process.stderr.write(\n 'No API key found.\\n\\n' +\n ' Get one: https://docs.okrapdf.com/api-keys\\n' +\n ' Then: export OKRA_API_KEY=\"okra_xxx\"\\n' +\n ' Or: npx okra auth login\\n\\n' +\n ' Docs: https://docs.okrapdf.com\\n' +\n ' Discord: https://discord.gg/BHNmbZVs\\n',\n );\n }\n process.exit(1);\n }\n\n return new OkraClient({ apiKey, baseUrl });\n}\n\n// ============================================================================\n// upload command\n// ============================================================================\nasync function runUploadCommand(source: string, options: { wait?: boolean }): Promise<void> {\n const g = globals();\n try {\n const client = getClient();\n const result = await upload(client, source, {\n ...g,\n noWait: options.wait === false,\n });\n\n if (g.json) {\n writeOutput(JSON.stringify(result), g.output);\n } else {\n const lines = [`Done — ${result.pages ?? '?'} pages`, ''];\n lines.push(` ${result.id}`);\n if (result.urls) {\n const short = result.id.slice(0, 11) + '...';\n lines.push('');\n lines.push(` Markdown: ${result.urls.full_md.replace(result.id, short)}`);\n lines.push(` Page 1: ${result.urls.page_png.replace(result.id, short).replace('{N}', '1')}`);\n lines.push(` Completion: ${result.urls.completion.replace(result.id, short)}`);\n lines.push('');\n lines.push(' URL patterns:');\n lines.push(' /v1/documents/{id}/pg_{N}.md page markdown');\n lines.push(' /v1/documents/{id}/d_shimmer/pg_{N}.png page image');\n lines.push(' /v1/documents/{id}/full.md full document');\n lines.push('');\n lines.push(' Docs: https://docs.okrapdf.com Discord: https://discord.gg/BHNmbZVs');\n }\n writeOutput(lines.join('\\n'), g.output);\n }\n } catch (error) {\n handleError(error, g.json);\n }\n}\n\nfunction registerUploadCommand(commandName: string, description: string): void {\n program\n .command(`${commandName} <source>`)\n .description(description)\n .option('--no-wait', 'Fire-and-forget (don\\'t wait for processing)')\n .action(async (source, options) => {\n await runUploadCommand(source, options);\n });\n}\n\nregisterUploadCommand('upload', 'Upload a PDF (file path or URL), wait for processing');\n\n// ============================================================================\n// extract command — structured extraction from existing doc or upload + extract\n// ============================================================================\nprogram\n .command('extract <source>')\n .description('Extract structured data from a document (doc ID, URL, or file path)')\n .option('--no-wait', \"Fire-and-forget (don't wait for processing)\")\n .option('--schema <file>', 'JSON Schema file or inline JSON for structured extraction')\n .option('--prompt <query>', 'Extraction prompt (default: \"Extract all data according to the schema\")')\n .action(async (source, options) => {\n const g = globals();\n try {\n const client = getClient();\n const { readFileSync } = await import('fs');\n\n // Resolve doc ID: if source looks like an existing doc, skip upload\n const isExistingDoc = /^(?:ocr|doc)-[A-Za-z0-9_-]+$/.test(source);\n let docId: string;\n\n if (isExistingDoc) {\n docId = source;\n } else {\n // Upload first\n const result = await upload(client, source, {\n ...g,\n noWait: options.wait === false,\n });\n docId = result.id;\n\n // If no schema and no-wait, just show upload result\n if (!options.schema || options.wait === false) {\n if (g.json) {\n writeOutput(JSON.stringify(result), g.output);\n } else {\n const lines = [`Done — ${result.pages ?? '?'} pages`, ''];\n lines.push(` ${docId}`);\n if (result.urls) {\n const short = docId.slice(0, 11) + '...';\n lines.push('');\n lines.push(` Markdown: ${result.urls.full_md.replace(docId, short)}`);\n lines.push(` Page 1: ${result.urls.page_png.replace(docId, short).replace('{N}', '1')}`);\n lines.push(` Completion: ${result.urls.completion.replace(docId, short)}`);\n }\n writeOutput(lines.join('\\n'), g.output);\n }\n return;\n }\n }\n\n // Schema is required for existing docs, optional for uploads\n if (!options.schema) {\n if (isExistingDoc) {\n writeOutput('Error: --schema is required when extracting from an existing document.', g.output);\n process.exitCode = 1;\n return;\n }\n return;\n }\n\n // Load schema — support file path or inline JSON\n let schemaJson: Record<string, unknown>;\n const schemaArg: string = options.schema;\n if (schemaArg.startsWith('{')) {\n schemaJson = JSON.parse(schemaArg);\n } else {\n schemaJson = JSON.parse(readFileSync(schemaArg, 'utf8'));\n }\n\n const prompt = options.prompt || 'Extract all data from this document according to the schema.';\n\n progress(`Extracting from ${docId}…`, g.quiet);\n const extraction = await client.generate(docId, prompt, { schema: schemaJson });\n\n if (g.json) {\n writeOutput(JSON.stringify({\n doc_id: docId,\n data: extraction.data ?? extraction.answer,\n }), g.output);\n } else if (g.output && g.output.endsWith('.csv')) {\n // CSV output for single doc — one header row + one data row\n const data = (extraction.data ?? {}) as Record<string, unknown>;\n const keys = Object.keys(data);\n const header = ['doc_id', ...keys].join(',');\n const values = keys.map((k) => {\n const v = data[k];\n if (v == null) return '';\n if (typeof v === 'string') return `\"${String(v).replace(/\"/g, '\"\"')}\"`;\n return String(v);\n });\n writeOutput([header, [docId, ...values].join(',')].join('\\n'), g.output);\n } else {\n writeOutput(JSON.stringify(extraction.data ?? extraction.answer, null, 2), g.output);\n }\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// status command\n// ============================================================================\nprogram\n .command('status <docId>')\n .description('Get document processing status')\n .action(async (docId) => {\n const g = globals();\n try {\n const client = getClient();\n const status = await client.status(docId);\n if (g.json) {\n writeOutput(JSON.stringify(status), g.output);\n } else {\n const lines = [\n `Document: ${docId}`,\n `Phase: ${status.phase}`,\n ];\n if (typeof status.pagesCompleted === 'number' || typeof status.pagesTotal === 'number') {\n lines.push(`Pages: ${status.pagesCompleted ?? '?'} / ${status.pagesTotal ?? '?'}`);\n }\n writeOutput(lines.join('\\n'), g.output);\n }\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// chat command\n// ============================================================================\nprogram\n .command('chat <question>')\n .description('Ask a question about a processed document')\n .requiredOption('--doc <id>', 'Document ID')\n .option('--model <name>', 'Override model')\n .action(async (question, options) => {\n const g = globals();\n try {\n const client = getClient();\n const result = await client.generate(options.doc, question, options.model ? { model: options.model } : undefined);\n\n if (g.json) {\n writeOutput(JSON.stringify({ docId: options.doc, question, ...result }), g.output);\n } else {\n writeOutput(result.answer, g.output);\n }\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// list command\n// ============================================================================\nprogram\n .command('list')\n .alias('ls')\n .description('List all documents')\n .action(async () => {\n const g = globals();\n try {\n const client = getClient();\n const { documents } = await listDocuments(client, g);\n writeOutput(formatDocumentList(documents, g.json), g.output);\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// delete command\n// ============================================================================\nprogram\n .command('delete <docId>')\n .alias('rm')\n .description('Delete a document')\n .action(async (docId) => {\n const g = globals();\n try {\n const client = getClient();\n const result = await deleteDocument(client, docId, g);\n if (g.json) {\n writeOutput(JSON.stringify(result), g.output);\n } else {\n writeOutput(`Deleted ${docId}`, g.output);\n }\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// read command\n// ============================================================================\nprogram\n .command('read <docId>')\n .description('Read document as markdown')\n .option('-p, --pages <range>', 'Page range (e.g., 1-5, 10-15)')\n .action(async (docId, options) => {\n const g = globals();\n try {\n const client = getClient();\n const result = await readDocument(client, docId, { ...g, pages: options.pages });\n if (g.json) {\n writeOutput(JSON.stringify(result), g.output);\n } else {\n writeOutput(result.markdown, g.output);\n }\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// collection command\n// ============================================================================\nconst collectionCmd = program\n .command('collection')\n .alias('collections')\n .alias('col')\n .description('Collection operations');\n\ncollectionCmd\n .command('list')\n .alias('ls')\n .description('List available collections')\n .action(async () => {\n const g = globals();\n try {\n const client = getClient();\n const rows = await collectionList(client, g);\n writeOutput(formatCollectionList(rows, g.json), g.output);\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\ncollectionCmd\n .command('query <nameOrId> <question>')\n .description('Fan-out query across collection documents')\n .option('--schema <file>', 'JSON Schema file for structured extraction')\n .action(async (nameOrId, question, options) => {\n const g = globals();\n try {\n const client = getClient();\n const { results, summary } = await collectionQueryRaw(\n client,\n nameOrId,\n question,\n { ...g, schema: options.schema },\n );\n\n // Determine output format based on flags\n if (g.json) {\n // --json: JSONL events to stdout\n writeOutput(formatQueryJsonl(results), g.output);\n } else if (g.output && g.output.endsWith('.csv')) {\n // -o file.csv → CSV\n writeOutput(formatCollectionCsv(results), g.output);\n } else if (g.output) {\n // -o file.json or other → JSON\n writeOutput(JSON.stringify({ results, summary }), g.output);\n } else {\n // Default: compact table to stdout\n writeOutput(formatCollectionTable(results));\n }\n\n progress(\n `${summary.completed} completed, ${summary.failed} failed — $${summary.total_cost_usd.toFixed(4)}`,\n g.quiet,\n );\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\ncollectionCmd\n .command('extract <nameOrId>')\n .description('Extract structured data from all documents in a collection')\n .requiredOption('--schema <file>', 'JSON Schema file or inline JSON for structured extraction')\n .option('--prompt <query>', 'Extraction prompt (default: auto-generated from schema)')\n .action(async (nameOrId, options) => {\n const g = globals();\n try {\n const client = getClient();\n const { readFileSync } = await import('fs');\n\n // Load schema — support file path or inline JSON\n let schemaJson: Record<string, unknown>;\n const schemaArg: string = options.schema;\n if (schemaArg.startsWith('{')) {\n schemaJson = JSON.parse(schemaArg);\n } else {\n schemaJson = JSON.parse(readFileSync(schemaArg, 'utf8'));\n }\n\n const prompt = options.prompt || 'Extract all data from this document according to the schema.';\n\n const { results, summary } = await collectionQueryRaw(\n client,\n nameOrId,\n prompt,\n { ...g, schema: schemaJson },\n );\n\n // Use structured formatters that flatten data keys into columns\n if (g.json) {\n writeOutput(formatExtractJson(results), g.output);\n } else if (g.output && g.output.endsWith('.csv')) {\n writeOutput(formatExtractCsv(results), g.output);\n } else if (g.output) {\n // Non-csv file output → JSON\n writeOutput(formatExtractJson(results), g.output);\n } else {\n // Default: table to stdout with flattened data columns\n writeOutput(formatExtractTable(results));\n }\n\n progress(\n `\\n${summary.completed} documents — $${summary.total_cost_usd.toFixed(4)} total`,\n g.quiet,\n );\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\ncollectionCmd\n .command('publish <nameOrId>')\n .description('Make a collection publicly queryable')\n .action(async (nameOrId) => {\n const g = globals();\n try {\n const client = getClient();\n await collectionSetVisibility(client, nameOrId, 'public');\n if (g.json) {\n writeOutput(JSON.stringify({ ok: true, visibility: 'public', collection: nameOrId }), g.output);\n } else {\n writeOutput(\n `Published \"${nameOrId}\"\\n` +\n `Share with: okra collection query ${nameOrId} \"your question\"`,\n g.output,\n );\n }\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\ncollectionCmd\n .command('unpublish <nameOrId>')\n .description('Make a collection private (owner-only)')\n .action(async (nameOrId) => {\n const g = globals();\n try {\n const client = getClient();\n await collectionSetVisibility(client, nameOrId, 'private');\n if (g.json) {\n writeOutput(JSON.stringify({ ok: true, visibility: 'private', collection: nameOrId }), g.output);\n } else {\n writeOutput(`Unpublished \"${nameOrId}\" — now private`, g.output);\n }\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\ncollectionCmd\n .command('export <nameOrId>')\n .description('Export pre-computed markdown for all documents in a collection')\n .option('--flat', 'Concatenated markdown with # headers + === separators')\n .option('--zip', 'One markdown file per document in a .zip archive')\n .action(async (nameOrId, options) => {\n const g = globals();\n try {\n const client = getClient();\n\n if (options.flat && options.zip) {\n throw new Error('Use either --flat or --zip, not both');\n }\n\n if (options.zip) {\n const bytes = await collectionExport(client, nameOrId, { ...g, zip: true });\n const safeBase = String(nameOrId)\n .trim()\n .replace(/[^A-Za-z0-9._-]+/g, '-')\n .replace(/-{2,}/g, '-')\n .replace(/^[-_.]+|[-_.]+$/g, '') || 'collection-export';\n const outputPath = g.output || `${safeBase}.zip`;\n writeFileSync(outputPath, bytes);\n progress(`Wrote → ${outputPath}`, g.quiet);\n\n if (g.json) {\n writeOutput(JSON.stringify({\n format: 'zip',\n file: outputPath,\n bytes: bytes.byteLength,\n }));\n }\n return;\n }\n\n const result = await collectionExport(client, nameOrId, { ...g, flat: options.flat });\n\n if (options.flat) {\n writeOutput(formatCollectionExportFlat(result), g.output);\n } else if (g.json) {\n writeOutput(JSON.stringify(result), g.output);\n } else {\n // Default: structured JSON\n writeOutput(JSON.stringify(result, null, 2), g.output);\n }\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// auth command - Authentication management\n// ============================================================================\nconst authCmd = program.command('auth').description('Manage authentication');\n\nauthCmd\n .command('login')\n .description('Save API key to global config')\n .option('-k, --key <apiKey>', 'Set API key non-interactively')\n .action(async (options) => {\n try {\n await authLogin(options.key);\n } catch (error) {\n handleError(error, globals().json);\n }\n });\n\nauthCmd\n .command('set-key <apiKey>')\n .description('Save API key to global config (non-interactive)')\n .action(async (apiKey) => {\n try {\n await authSetKey(apiKey);\n } catch (error) {\n handleError(error, globals().json);\n }\n });\n\nauthCmd\n .command('status')\n .description('Show authentication status')\n .action(async () => {\n try {\n await authStatus();\n } catch (error) {\n handleError(error, globals().json);\n }\n });\n\nauthCmd\n .command('whoami')\n .description('Show current auth identity (alias for status)')\n .action(async () => {\n try {\n await authWhoAmI();\n } catch (error) {\n handleError(error, globals().json);\n }\n });\n\nauthCmd\n .command('token')\n .description('Print active API key to stdout')\n .action(async () => {\n try {\n await authToken();\n } catch (error) {\n handleError(error, globals().json);\n }\n });\n\nauthCmd\n .command('logout')\n .description('Remove API key from global config')\n .action(async () => {\n try {\n await authLogout();\n } catch (error) {\n handleError(error, globals().json);\n }\n });\n\n// ============================================================================\n// tree command - Document verification tree\n// ============================================================================\nprogram\n .command('tree <jobId>')\n .description('Show document verification tree')\n .option('-s, --status <status>', 'Filter by status (complete|partial|pending|flagged|empty|gap)')\n .option('-e, --entity <type>', 'Filter by entity type (table|figure|footnote)')\n .option('-f, --format <format>', 'Output format (text|json|markdown)', 'text')\n .action(async (jobId, options) => {\n const g = globals();\n try {\n const client = getClient();\n const fmt = g.json ? 'json' : options.format;\n const result = await tree(client, jobId, {\n status: options.status,\n entity: options.entity,\n });\n writeOutput(formatTreeOutput(result, fmt), g.output);\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// find command - jQuery-like entity search\n// ============================================================================\nprogram\n .command('find <jobId> <selector>')\n .description('Find entities using jQuery-like selectors')\n .option('-k, --top-k <n>', 'Limit results', parseInt)\n .option('-c, --min-confidence <n>', 'Minimum confidence (0-1)', parseFloat)\n .option('-p, --pages <range>', 'Page range (e.g., 1-10)')\n .option('--sort <by>', 'Sort by (confidence|page|type)')\n .option('--stats', 'Show aggregate statistics')\n .option('-f, --format <format>', 'Output format (text|json|entities|ids)', 'text')\n .action(async (jobId, selector, options) => {\n const g = globals();\n try {\n const client = getClient();\n const fmt = g.json ? 'json' : options.format;\n const pageRange = options.pages\n ? options.pages.split('-').map(Number) as [number, number]\n : undefined;\n\n const result = await find(client, jobId, selector, {\n topK: options.topK,\n minConfidence: options.minConfidence,\n pageRange,\n sortBy: options.sort,\n });\n\n if (options.stats && fmt === 'text') {\n writeOutput(formatStats(result.stats), g.output);\n } else {\n writeOutput(formatFindOutput(result, fmt, options.stats), g.output);\n }\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// page command - Page content operations\n// ============================================================================\nconst pageCmd = program.command('page').description('Page content operations');\n\npageCmd\n .command('get <jobId> <pageNum>')\n .description('Get page content')\n .option('-v, --version <n>', 'Specific version', parseInt)\n .option('-f, --format <format>', 'Output format (text|json|markdown)', 'markdown')\n .action(async (jobId, pageNum, options) => {\n const g = globals();\n try {\n const client = getClient();\n const fmt = g.json ? 'json' : options.format;\n const content = await pageGet(client, jobId, parseInt(pageNum), {\n version: options.version,\n });\n writeOutput(formatPageOutput(content, fmt), g.output);\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\npageCmd\n .command('edit <jobId> <pageNum>')\n .description('Edit page content (reads from stdin)')\n .action(async (jobId, pageNum) => {\n const g = globals();\n try {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk);\n }\n const content = Buffer.concat(chunks).toString('utf8');\n\n const client = getClient();\n const result = await pageEdit(client, jobId, parseInt(pageNum), content);\n if (g.json) {\n writeOutput(JSON.stringify({ version: result.version }), g.output);\n } else {\n writeOutput(`Saved as version ${result.version}`, g.output);\n }\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\npageCmd\n .command('resolve <jobId> <pageNum> <resolution>')\n .description('Resolve page verification status')\n .option('-c, --classification <class>', 'Classification')\n .option('-r, --reason <reason>', 'Reason')\n .action(async (jobId, pageNum, resolution, options) => {\n const g = globals();\n try {\n const client = getClient();\n const result = await pageResolve(client, jobId, parseInt(pageNum), {\n resolution,\n classification: options.classification,\n reason: options.reason,\n });\n if (g.json) {\n writeOutput(JSON.stringify({ success: result.success }), g.output);\n } else {\n writeOutput(result.success ? 'Resolved' : 'Failed', g.output);\n }\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\npageCmd\n .command('versions <jobId> <pageNum>')\n .description('List page versions')\n .option('-f, --format <format>', 'Output format (text|json)', 'text')\n .action(async (jobId, pageNum, options) => {\n const g = globals();\n try {\n const client = getClient();\n const fmt = g.json ? 'json' : options.format;\n const versions = await pageVersions(client, jobId, parseInt(pageNum));\n writeOutput(formatVersionsOutput(versions, fmt), g.output);\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// search command - Full-text search\n// ============================================================================\nprogram\n .command('search <jobId> <query>')\n .description('Search page content')\n .option('-f, --format <format>', 'Output format (text|json)', 'text')\n .action(async (jobId, query, options) => {\n const g = globals();\n try {\n const client = getClient();\n const fmt = g.json ? 'json' : options.format;\n const result = await search(client, jobId, query);\n writeOutput(formatSearchOutput(result, fmt), g.output);\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// tables command - List tables\n// ============================================================================\nprogram\n .command('tables <jobId>')\n .description('List extracted tables')\n .option('-p, --page <n>', 'Filter by page', parseInt)\n .option('-s, --status <status>', 'Filter by status (pending|verified|flagged|rejected)')\n .option('-f, --format <format>', 'Output format (text|json|markdown)', 'text')\n .action(async (jobId, options) => {\n const g = globals();\n try {\n const client = getClient();\n const fmt = g.json ? 'json' : options.format;\n const result = await tables(client, jobId, {\n page: options.page,\n status: options.status,\n });\n writeOutput(formatTablesOutput(result, fmt), g.output);\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// history command - Verification audit trail\n// ============================================================================\nprogram\n .command('history <jobId>')\n .description('Show verification history')\n .option('-l, --limit <n>', 'Limit entries', parseInt, 50)\n .option('-f, --format <format>', 'Output format (text|json)', 'text')\n .action(async (jobId, options) => {\n const g = globals();\n try {\n const client = getClient();\n const fmt = g.json ? 'json' : options.format;\n const result = await history(client, jobId, { limit: options.limit });\n writeOutput(formatHistoryOutput(result, fmt), g.output);\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\n// ============================================================================\n// toc command - Table of contents extraction\n// ============================================================================\nprogram\n .command('toc <jobId>')\n .description('Extract table of contents from PDF')\n .option('--max-depth <n>', 'Maximum TOC depth', parseInt)\n .option('-f, --format <format>', 'Output format (text|json|markdown)', 'text')\n .option('--watch', 'Watch live extraction events via WebSocket')\n .action(async (jobId, options) => {\n const g = globals();\n try {\n const client = getClient();\n const fmt = g.json ? 'json' : options.format;\n const result = await toc(client, jobId, {\n maxDepth: options.maxDepth,\n watch: options.watch,\n });\n writeOutput(formatTocOutput(result, fmt), g.output);\n } catch (error) {\n handleError(error, g.json);\n }\n });\n\nprogram.parse();\n"],"mappings":"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","names":[]}
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { O as OkraClient } from '../client-
|
|
2
|
-
import '../types-
|
|
1
|
+
import { O as OkraClient } from '../client-DMEw0oK3.js';
|
|
2
|
+
import '../types-D2JaySEg.js';
|
|
3
3
|
import 'zod';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -471,11 +471,23 @@ declare function formatTocOutput(result: TocResult, format?: 'text' | 'json' | '
|
|
|
471
471
|
/**
|
|
472
472
|
* Login command - set API key in global config.
|
|
473
473
|
*/
|
|
474
|
-
declare function authLogin(): Promise<void>;
|
|
474
|
+
declare function authLogin(providedApiKey?: string): Promise<void>;
|
|
475
|
+
/**
|
|
476
|
+
* Set API key non-interactively.
|
|
477
|
+
*/
|
|
478
|
+
declare function authSetKey(apiKey: string): Promise<void>;
|
|
475
479
|
/**
|
|
476
480
|
* Status command - show current auth status.
|
|
477
481
|
*/
|
|
478
482
|
declare function authStatus(): Promise<void>;
|
|
483
|
+
/**
|
|
484
|
+
* Print active API key to stdout (for piping).
|
|
485
|
+
*/
|
|
486
|
+
declare function authToken(): Promise<void>;
|
|
487
|
+
/**
|
|
488
|
+
* WhoAmI command - currently aliases auth status.
|
|
489
|
+
*/
|
|
490
|
+
declare function authWhoAmI(): Promise<void>;
|
|
479
491
|
/**
|
|
480
492
|
* Logout command - remove API key from global config.
|
|
481
493
|
*/
|
|
@@ -533,4 +545,4 @@ declare function getBaseUrl(): string | undefined;
|
|
|
533
545
|
*/
|
|
534
546
|
declare function getApiKeySource(): string;
|
|
535
547
|
|
|
536
|
-
export { type EntitiesResponse, type Entity, type EntityBBox, type EntityType, type FindOptions, type HistoryEntry, type HistoryOptions, type HistoryResponse, type MatchSource, type OkraConfig, type OutputFormat, type PageContent, type PageDimension, type PageGetOptions, type PageResolveOptions, type PageVersionInfo, type PageVersionsResponse, type QueryConfig, type QueryOptions, type QueryResult, type QueryStats, type SearchOptions, type SearchResponse, type SearchResult, type SelectorParts, type Table, type TablesOptions, type TablesResponse, type TextBlock, type TocOptions, type TreeOptions, type TreeResult, type VerificationPageStatus, type VerificationTree, type VerificationTreePage, type VerificationTreeSummary, authLogin, authLogout, authStatus, calculateStats, executeQuery, filterEntities, find, formatFindOutput, formatHistoryOutput, formatPageOutput, formatSearchOutput, formatStats, formatTablesOutput, formatTocOutput, formatTreeOutput, formatVersionsOutput, getApiKey, getApiKeySource, getBaseUrl, getGlobalConfigDir, getGlobalConfigPath, history, pageEdit, pageGet, pageResolve, pageVersions, parseSelector, readGlobalConfig, readProjectConfig, search, tables, toc, tree, writeGlobalConfig };
|
|
548
|
+
export { type EntitiesResponse, type Entity, type EntityBBox, type EntityType, type FindOptions, type HistoryEntry, type HistoryOptions, type HistoryResponse, type MatchSource, type OkraConfig, type OutputFormat, type PageContent, type PageDimension, type PageGetOptions, type PageResolveOptions, type PageVersionInfo, type PageVersionsResponse, type QueryConfig, type QueryOptions, type QueryResult, type QueryStats, type SearchOptions, type SearchResponse, type SearchResult, type SelectorParts, type Table, type TablesOptions, type TablesResponse, type TextBlock, type TocOptions, type TreeOptions, type TreeResult, type VerificationPageStatus, type VerificationTree, type VerificationTreePage, type VerificationTreeSummary, authLogin, authLogout, authSetKey, authStatus, authToken, authWhoAmI, calculateStats, executeQuery, filterEntities, find, formatFindOutput, formatHistoryOutput, formatPageOutput, formatSearchOutput, formatStats, formatTablesOutput, formatTocOutput, formatTreeOutput, formatVersionsOutput, getApiKey, getApiKeySource, getBaseUrl, getGlobalConfigDir, getGlobalConfigPath, history, pageEdit, pageGet, pageResolve, pageVersions, parseSelector, readGlobalConfig, readProjectConfig, search, tables, toc, tree, writeGlobalConfig };
|
package/dist/cli/index.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
authLogin,
|
|
3
3
|
authLogout,
|
|
4
|
+
authSetKey,
|
|
4
5
|
authStatus,
|
|
6
|
+
authToken,
|
|
7
|
+
authWhoAmI,
|
|
5
8
|
calculateStats,
|
|
6
9
|
executeQuery,
|
|
7
10
|
filterEntities,
|
|
@@ -33,12 +36,15 @@ import {
|
|
|
33
36
|
toc,
|
|
34
37
|
tree,
|
|
35
38
|
writeGlobalConfig
|
|
36
|
-
} from "../chunk-
|
|
39
|
+
} from "../chunk-F3LECDPP.js";
|
|
37
40
|
import "../chunk-NIZM2ETT.js";
|
|
38
41
|
export {
|
|
39
42
|
authLogin,
|
|
40
43
|
authLogout,
|
|
44
|
+
authSetKey,
|
|
41
45
|
authStatus,
|
|
46
|
+
authToken,
|
|
47
|
+
authWhoAmI,
|
|
42
48
|
calculateStats,
|
|
43
49
|
executeQuery,
|
|
44
50
|
filterEntities,
|