@okrapdf/cli 0.1.0 → 0.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 (115) hide show
  1. package/README.md +163 -0
  2. package/dist/cli.d.ts +19 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +175 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/auth.d.ts +6 -0
  7. package/dist/commands/auth.d.ts.map +1 -0
  8. package/dist/commands/auth.js +154 -0
  9. package/dist/commands/auth.js.map +1 -0
  10. package/dist/commands/chat.d.ts +6 -0
  11. package/dist/commands/chat.d.ts.map +1 -0
  12. package/dist/commands/chat.js +218 -0
  13. package/dist/commands/chat.js.map +1 -0
  14. package/dist/commands/docs.d.ts +6 -0
  15. package/dist/commands/docs.d.ts.map +1 -0
  16. package/dist/commands/docs.js +181 -0
  17. package/dist/commands/docs.js.map +1 -0
  18. package/dist/commands/jobs.d.ts +6 -0
  19. package/dist/commands/jobs.d.ts.map +1 -0
  20. package/dist/commands/jobs.js +348 -0
  21. package/dist/commands/jobs.js.map +1 -0
  22. package/dist/commands/jobs.test.d.ts +5 -0
  23. package/dist/commands/jobs.test.d.ts.map +1 -0
  24. package/dist/commands/jobs.test.js +118 -0
  25. package/dist/commands/jobs.test.js.map +1 -0
  26. package/dist/commands/logs.d.ts +8 -0
  27. package/dist/commands/logs.d.ts.map +1 -0
  28. package/dist/commands/logs.js +186 -0
  29. package/dist/commands/logs.js.map +1 -0
  30. package/dist/commands/processors.d.ts +8 -0
  31. package/dist/commands/processors.d.ts.map +1 -0
  32. package/dist/commands/processors.js +91 -0
  33. package/dist/commands/processors.js.map +1 -0
  34. package/dist/commands/review.d.ts +3 -0
  35. package/dist/commands/review.d.ts.map +1 -0
  36. package/dist/commands/review.js +370 -0
  37. package/dist/commands/review.js.map +1 -0
  38. package/dist/commands/shortcuts.d.ts +20 -0
  39. package/dist/commands/shortcuts.d.ts.map +1 -0
  40. package/dist/commands/shortcuts.js +405 -0
  41. package/dist/commands/shortcuts.js.map +1 -0
  42. package/dist/commands/tables.d.ts +6 -0
  43. package/dist/commands/tables.d.ts.map +1 -0
  44. package/dist/commands/tables.js +189 -0
  45. package/dist/commands/tables.js.map +1 -0
  46. package/dist/commands/templates.d.ts +8 -0
  47. package/dist/commands/templates.d.ts.map +1 -0
  48. package/dist/commands/templates.js +202 -0
  49. package/dist/commands/templates.js.map +1 -0
  50. package/dist/index.d.ts +14 -412
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +23 -46
  53. package/dist/index.js.map +1 -1
  54. package/dist/lib/browser.d.ts +11 -0
  55. package/dist/lib/browser.d.ts.map +1 -0
  56. package/dist/lib/browser.js +33 -0
  57. package/dist/lib/browser.js.map +1 -0
  58. package/dist/lib/client.d.ts +57 -0
  59. package/dist/lib/client.d.ts.map +1 -0
  60. package/dist/lib/client.js +176 -0
  61. package/dist/lib/client.js.map +1 -0
  62. package/dist/lib/config.d.ts +56 -0
  63. package/dist/lib/config.d.ts.map +1 -0
  64. package/dist/lib/config.js +110 -0
  65. package/dist/lib/config.js.map +1 -0
  66. package/dist/lib/config.test.d.ts +5 -0
  67. package/dist/lib/config.test.d.ts.map +1 -0
  68. package/dist/lib/config.test.js +81 -0
  69. package/dist/lib/config.test.js.map +1 -0
  70. package/dist/lib/logs.d.ts +89 -0
  71. package/dist/lib/logs.d.ts.map +1 -0
  72. package/dist/lib/logs.js +196 -0
  73. package/dist/lib/logs.js.map +1 -0
  74. package/dist/lib/logs.test.d.ts +5 -0
  75. package/dist/lib/logs.test.d.ts.map +1 -0
  76. package/dist/lib/logs.test.js +183 -0
  77. package/dist/lib/logs.test.js.map +1 -0
  78. package/dist/lib/output.d.ts +73 -0
  79. package/dist/lib/output.d.ts.map +1 -0
  80. package/dist/lib/output.js +204 -0
  81. package/dist/lib/output.js.map +1 -0
  82. package/dist/lib/output.test.d.ts +5 -0
  83. package/dist/lib/output.test.d.ts.map +1 -0
  84. package/dist/lib/output.test.js +174 -0
  85. package/dist/lib/output.test.js.map +1 -0
  86. package/dist/lib/processors.d.ts +73 -0
  87. package/dist/lib/processors.d.ts.map +1 -0
  88. package/dist/lib/processors.js +94 -0
  89. package/dist/lib/processors.js.map +1 -0
  90. package/dist/lib/processors.test.d.ts +5 -0
  91. package/dist/lib/processors.test.d.ts.map +1 -0
  92. package/dist/lib/processors.test.js +83 -0
  93. package/dist/lib/processors.test.js.map +1 -0
  94. package/dist/lib/progress.d.ts +44 -0
  95. package/dist/lib/progress.d.ts.map +1 -0
  96. package/dist/lib/progress.js +102 -0
  97. package/dist/lib/progress.js.map +1 -0
  98. package/dist/lib/templates.d.ts +56 -0
  99. package/dist/lib/templates.d.ts.map +1 -0
  100. package/dist/lib/templates.js +204 -0
  101. package/dist/lib/templates.js.map +1 -0
  102. package/dist/lib/templates.test.d.ts +5 -0
  103. package/dist/lib/templates.test.d.ts.map +1 -0
  104. package/dist/lib/templates.test.js +101 -0
  105. package/dist/lib/templates.test.js.map +1 -0
  106. package/dist/types.d.ts +144 -0
  107. package/dist/types.d.ts.map +1 -0
  108. package/dist/types.js +5 -0
  109. package/dist/types.js.map +1 -0
  110. package/package.json +56 -25
  111. package/dist/bin.d.ts +0 -1
  112. package/dist/bin.js +0 -152
  113. package/dist/bin.js.map +0 -1
  114. package/dist/chunk-A6YTW4WL.js +0 -499
  115. package/dist/chunk-A6YTW4WL.js.map +0 -1
package/README.md ADDED
@@ -0,0 +1,163 @@
1
+ # @okrapdf/cli
2
+
3
+ Command-line interface for [OkraPDF](https://okrapdf.com) - extract tables from PDFs.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @okrapdf/cli
9
+ ```
10
+
11
+ Or use with npx:
12
+
13
+ ```bash
14
+ npx @okrapdf/cli jobs list
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ```bash
20
+ # Create a .env file with your API key
21
+ echo "OKRA_API_KEY=okra_xxxxxxxxxxxx" > .env
22
+
23
+ # Or create ~/.okra for global config
24
+ echo "OKRA_API_KEY=okra_xxxxxxxxxxxx" > ~/.okra
25
+
26
+ # List your documents
27
+ okra docs list
28
+
29
+ # List extraction jobs
30
+ okra jobs list
31
+
32
+ # Extract tables from a PDF
33
+ okra extract invoice.pdf -o json
34
+ ```
35
+
36
+ Get your API key from [okrapdf.com/settings/api-keys](https://okrapdf.com/settings/api-keys).
37
+
38
+ ## Configuration
39
+
40
+ The CLI looks for your API key in this order:
41
+
42
+ 1. `OKRA_API_KEY` environment variable
43
+ 2. `.env` file in current directory
44
+ 3. `.okra` file in current directory
45
+ 4. `~/.okra` file in home directory
46
+ 5. `~/.config/okrapdf/config.json`
47
+
48
+ Example `.env` or `.okra` file:
49
+
50
+ ```bash
51
+ OKRA_API_KEY=okra_xxxxxxxxxxxx
52
+ OKRA_BASE_URL=https://okrapdf.com
53
+ ```
54
+
55
+ ## Commands
56
+
57
+ ### Documents
58
+
59
+ ```bash
60
+ okra docs list # List all documents
61
+ okra docs upload <file> # Upload a PDF
62
+ okra docs get <uuid> # Get document details
63
+ okra docs delete <uuid> # Delete a document
64
+ ```
65
+
66
+ ### Jobs
67
+
68
+ ```bash
69
+ okra jobs list # List extraction jobs
70
+ okra jobs create <file> # Create extraction job
71
+ okra jobs get <job-id> # Get job status
72
+ okra jobs wait <job-id> # Wait for completion
73
+ okra jobs results <job-id> # Get extraction results
74
+ ```
75
+
76
+ ### Tables
77
+
78
+ ```bash
79
+ okra tables list <doc-uuid> # List extracted tables
80
+ okra tables get <table-id> # Get table content
81
+ okra tables export <id> # Export to CSV/JSON
82
+ ```
83
+
84
+ ### Shortcuts
85
+
86
+ ```bash
87
+ okra extract <file> # Upload + extract + wait (all-in-one)
88
+ ```
89
+
90
+ ## Output Formats
91
+
92
+ All commands support `-o, --output`:
93
+
94
+ - `table` (default) - Human-readable tables
95
+ - `json` - Machine-readable JSON
96
+ - `csv` - CSV format
97
+
98
+ ```bash
99
+ # JSON for scripting
100
+ okra jobs list -o json | jq '.[].id'
101
+
102
+ # Quiet mode for piping
103
+ okra extract doc.pdf -o json -q > results.json
104
+ ```
105
+
106
+ ## Environment Variables
107
+
108
+ | Variable | Description |
109
+ |----------|-------------|
110
+ | `OKRA_API_KEY` | API key (required) |
111
+ | `OKRA_BASE_URL` | Custom API URL (for self-hosted) |
112
+ | `OKRA_OUTPUT_FORMAT` | Default output format |
113
+
114
+ ## Examples
115
+
116
+ ### Batch Processing
117
+
118
+ ```bash
119
+ for pdf in *.pdf; do
120
+ okra extract "$pdf" -o json > "${pdf%.pdf}.json"
121
+ done
122
+ ```
123
+
124
+ ### CI/CD Integration
125
+
126
+ ```bash
127
+ # Extract and check for tables
128
+ RESULT=$(okra extract report.pdf -o json -q)
129
+ TABLE_COUNT=$(echo "$RESULT" | jq '.tables | length')
130
+ echo "Found $TABLE_COUNT tables"
131
+ ```
132
+
133
+ ## Exit Codes
134
+
135
+ | Code | Meaning |
136
+ |------|---------|
137
+ | 0 | Success |
138
+ | 1 | General error |
139
+ | 2 | Invalid arguments |
140
+ | 3 | Authentication error |
141
+ | 4 | Resource not found |
142
+ | 5 | Rate limited |
143
+
144
+ ## Development
145
+
146
+ ```bash
147
+ git clone https://github.com/steventsao/okrapdf
148
+ cd okrapdf/packages/cli
149
+ npm install
150
+ npm run build
151
+ npm link
152
+ okra --help
153
+ ```
154
+
155
+ ## License
156
+
157
+ MIT
158
+
159
+ ## Links
160
+
161
+ - [OkraPDF](https://okrapdf.com)
162
+ - [API Docs](https://docs.okrapdf.com/api)
163
+ - [GitHub](https://github.com/steventsao/okrapdf/tree/main/packages/cli)
package/dist/cli.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * CLI setup and configuration
3
+ *
4
+ * Designed for both human users and AI coding agents.
5
+ * - Predictable commands and flags
6
+ * - Machine-readable JSON output (-o json)
7
+ * - Composable with pipes (stdin/stdout)
8
+ * - Environment variable configuration
9
+ */
10
+ import { Command } from 'commander';
11
+ /**
12
+ * Create and configure the CLI program
13
+ */
14
+ export declare function createProgram(): Command;
15
+ /**
16
+ * Run the CLI with error handling
17
+ */
18
+ export declare function run(argv?: string[]): Promise<void>;
19
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBpC;;GAEG;AACH,wBAAgB,aAAa,IAAI,OAAO,CA6GvC;AAED;;GAEG;AACH,wBAAsB,GAAG,CAAC,IAAI,GAAE,MAAM,EAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQtE"}
package/dist/cli.js ADDED
@@ -0,0 +1,175 @@
1
+ /**
2
+ * CLI setup and configuration
3
+ *
4
+ * Designed for both human users and AI coding agents.
5
+ * - Predictable commands and flags
6
+ * - Machine-readable JSON output (-o json)
7
+ * - Composable with pipes (stdin/stdout)
8
+ * - Environment variable configuration
9
+ */
10
+ import { Command } from 'commander';
11
+ import chalk from 'chalk';
12
+ import { createAuthCommand } from './commands/auth.js';
13
+ import { createDocsCommand } from './commands/docs.js';
14
+ import { createJobsCommand } from './commands/jobs.js';
15
+ import { createTablesCommand } from './commands/tables.js';
16
+ import { createChatCommand } from './commands/chat.js';
17
+ import { createExtractCommand, createRunCommand } from './commands/shortcuts.js';
18
+ import { createProcessorsCommand } from './commands/processors.js';
19
+ import { createTemplatesCommand } from './commands/templates.js';
20
+ import { createLogsCommand } from './commands/logs.js';
21
+ import { createReviewCommand } from './commands/review.js';
22
+ import { OkraApiError, EXIT_CODES } from './lib/client.js';
23
+ import { error } from './lib/output.js';
24
+ // Package version
25
+ const VERSION = '0.1.0';
26
+ /**
27
+ * Create and configure the CLI program
28
+ */
29
+ export function createProgram() {
30
+ const program = new Command();
31
+ program
32
+ .name('okra')
33
+ .description('OkraPDF CLI - Extract tables and chat with PDF documents')
34
+ .version(VERSION, '-v, --version', 'Output the version number')
35
+ .option('-q, --quiet', 'Suppress non-essential output (ideal for piping)')
36
+ .option('--json', 'Shorthand for -o json (machine-readable output)')
37
+ .option('--no-color', 'Disable colored output');
38
+ // Core commands
39
+ program.addCommand(createAuthCommand());
40
+ program.addCommand(createDocsCommand());
41
+ program.addCommand(createJobsCommand());
42
+ program.addCommand(createTablesCommand());
43
+ program.addCommand(createReviewCommand());
44
+ program.addCommand(createChatCommand());
45
+ // Shortcut commands (most common workflows)
46
+ program.addCommand(createExtractCommand());
47
+ program.addCommand(createRunCommand());
48
+ // Introspection commands (vendor-agnostic architecture)
49
+ program.addCommand(createProcessorsCommand());
50
+ program.addCommand(createTemplatesCommand());
51
+ program.addCommand(createLogsCommand());
52
+ // Handle global --json flag
53
+ program.hook('preAction', (thisCommand) => {
54
+ const opts = thisCommand.opts();
55
+ if (opts.json) {
56
+ process.env.OKRA_OUTPUT_FORMAT = 'json';
57
+ }
58
+ if (opts.quiet) {
59
+ process.env.OKRA_QUIET = '1';
60
+ }
61
+ });
62
+ // Add examples to help
63
+ program.addHelpText('after', `
64
+ ${chalk.bold('Quick Start:')}
65
+
66
+ ${chalk.dim('# Set API key (or use OKRA_API_KEY env var)')}
67
+ $ export OKRA_API_KEY=okra_xxxx
68
+
69
+ ${chalk.dim('# Extract tables from a PDF')}
70
+ $ okra extract invoice.pdf
71
+
72
+ ${chalk.dim('# Ask a question about a document')}
73
+ $ okra run report.pdf "What is the total revenue?"
74
+
75
+ ${chalk.bold('For AI Agents (Machine-Readable Output):')}
76
+
77
+ ${chalk.dim('# Get tables as JSON (for building presentations, reports)')}
78
+ $ okra extract document.pdf --json --quiet
79
+
80
+ ${chalk.dim('# Get document list as JSON for processing')}
81
+ $ okra docs list -o json | jq '.[].uuid'
82
+
83
+ ${chalk.dim('# Extract with specific processor')}
84
+ $ okra jobs create document.pdf -p gemini --wait -o json
85
+
86
+ ${chalk.dim('# Pipe table data to other tools')}
87
+ $ okra tables get <table-id> -o csv | csvkit ...
88
+
89
+ ${chalk.bold('Common Workflows:')}
90
+
91
+ ${chalk.dim('# Upload + extract + get results')}
92
+ $ okra extract invoice.pdf -o json > results.json
93
+
94
+ ${chalk.dim('# Use a template for structured extraction')}
95
+ $ okra extract receipt.pdf --template receipt -o json
96
+
97
+ ${chalk.dim('# Interactive document chat')}
98
+ $ okra chat <document-uuid>
99
+
100
+ ${chalk.dim('# List available processors')}
101
+ $ okra processors list
102
+
103
+ ${chalk.dim('# View job history')}
104
+ $ okra logs
105
+
106
+ ${chalk.bold('Review & Verification:')}
107
+
108
+ ${chalk.dim('# List tables sorted by most tables')}
109
+ $ okra review docs --sort tables
110
+
111
+ ${chalk.dim('# List tables with filtering')}
112
+ $ okra review list <doc-uuid> --status pending --sort confidence
113
+
114
+ ${chalk.dim('# Open document in browser (like gh --web)')}
115
+ $ okra review list <doc-uuid> --web
116
+ $ okra review open <doc-uuid>
117
+
118
+ ${chalk.bold('Environment Variables:')}
119
+
120
+ OKRA_API_KEY API key (required)
121
+ OKRA_BASE_URL Base URL (default: https://okrapdf.com)
122
+ OKRA_OUTPUT_FORMAT Default output: table, json, csv (default: table)
123
+
124
+ ${chalk.bold('More Information:')}
125
+
126
+ Documentation: ${chalk.cyan('https://docs.okrapdf.com/cli')}
127
+ API Reference: ${chalk.cyan('https://docs.okrapdf.com/api')}
128
+ GitHub: ${chalk.cyan('https://github.com/steventsao/okrapdf')}
129
+ `);
130
+ return program;
131
+ }
132
+ /**
133
+ * Run the CLI with error handling
134
+ */
135
+ export async function run(argv = process.argv) {
136
+ const program = createProgram();
137
+ try {
138
+ await program.parseAsync(argv);
139
+ }
140
+ catch (err) {
141
+ handleError(err);
142
+ }
143
+ }
144
+ /**
145
+ * Global error handler
146
+ */
147
+ function handleError(err) {
148
+ if (err instanceof OkraApiError) {
149
+ error(err.message);
150
+ if (err.details) {
151
+ console.error(chalk.dim(JSON.stringify(err.details, null, 2)));
152
+ }
153
+ process.exit(err.exitCode);
154
+ }
155
+ if (err instanceof Error) {
156
+ // Check for common errors
157
+ if (err.message.includes('ENOTFOUND') || err.message.includes('ECONNREFUSED')) {
158
+ error('Unable to connect to OkraPDF. Check your internet connection.');
159
+ process.exit(EXIT_CODES.GENERAL_ERROR);
160
+ }
161
+ if (err.message.includes('ETIMEDOUT')) {
162
+ error('Request timed out. Try again later.');
163
+ process.exit(EXIT_CODES.GENERAL_ERROR);
164
+ }
165
+ error(err.message);
166
+ // Show stack trace in debug mode
167
+ if (process.env.DEBUG) {
168
+ console.error(err.stack);
169
+ }
170
+ process.exit(EXIT_CODES.GENERAL_ERROR);
171
+ }
172
+ error('An unexpected error occurred');
173
+ process.exit(EXIT_CODES.GENERAL_ERROR);
174
+ }
175
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Authentication commands
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare function createAuthCommand(): Command;
6
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAepC,wBAAgB,iBAAiB,IAAI,OAAO,CAwJ3C"}
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Authentication commands
3
+ */
4
+ import { Command } from 'commander';
5
+ import { prompt } from 'enquirer';
6
+ import chalk from 'chalk';
7
+ import { getApiKey, setApiKey, clearApiKey, getConfigPath, isAuthenticated, getBaseUrl, } from '../lib/config.js';
8
+ import { get, OkraApiError } from '../lib/client.js';
9
+ import { success, error, info } from '../lib/output.js';
10
+ export function createAuthCommand() {
11
+ const auth = new Command('auth')
12
+ .description('Manage authentication');
13
+ // auth login
14
+ auth
15
+ .command('login')
16
+ .description('Authenticate with OkraPDF')
17
+ .option('-k, --key <key>', 'API key (or set OKRA_API_KEY env var)')
18
+ .action(async (options) => {
19
+ try {
20
+ let apiKey = options.key;
21
+ if (!apiKey) {
22
+ // Interactive prompt
23
+ console.log(chalk.bold('\nOkraPDF CLI Authentication\n'));
24
+ console.log('Get your API key from: ' + chalk.cyan('https://okrapdf.com/settings/api-keys'));
25
+ console.log();
26
+ const response = await prompt({
27
+ type: 'password',
28
+ name: 'key',
29
+ message: 'Enter your API key:',
30
+ validate: (value) => {
31
+ if (!value)
32
+ return 'API key is required';
33
+ if (!value.startsWith('okra_'))
34
+ return 'API key should start with "okra_"';
35
+ return true;
36
+ },
37
+ });
38
+ apiKey = response.key;
39
+ }
40
+ // Validate the key by making a test request
41
+ const tempKey = getApiKey();
42
+ setApiKey(apiKey);
43
+ try {
44
+ const user = await get('api/auth/me');
45
+ success(`Authenticated as ${chalk.bold(user.email)}`);
46
+ info(`Config saved to: ${getConfigPath()}`);
47
+ }
48
+ catch (err) {
49
+ // Restore previous key if validation failed
50
+ if (tempKey) {
51
+ setApiKey(tempKey);
52
+ }
53
+ else {
54
+ clearApiKey();
55
+ }
56
+ if (err instanceof OkraApiError && err.statusCode === 401) {
57
+ error('Invalid API key');
58
+ process.exit(3);
59
+ }
60
+ throw err;
61
+ }
62
+ }
63
+ catch (err) {
64
+ if (err instanceof Error && err.message.includes('cancelled')) {
65
+ console.log('\nLogin cancelled');
66
+ process.exit(0);
67
+ }
68
+ throw err;
69
+ }
70
+ });
71
+ // auth logout
72
+ auth
73
+ .command('logout')
74
+ .description('Remove stored credentials')
75
+ .action(() => {
76
+ if (!isAuthenticated()) {
77
+ info('Not logged in');
78
+ return;
79
+ }
80
+ clearApiKey();
81
+ success('Logged out successfully');
82
+ });
83
+ // auth whoami
84
+ auth
85
+ .command('whoami')
86
+ .description('Show current authenticated user')
87
+ .action(async () => {
88
+ if (!isAuthenticated()) {
89
+ error('Not logged in. Run `okra auth login` first.');
90
+ process.exit(3);
91
+ }
92
+ try {
93
+ const user = await get('api/auth/me');
94
+ console.log(chalk.bold('Email:'), user.email);
95
+ if (user.name) {
96
+ console.log(chalk.bold('Name:'), user.name);
97
+ }
98
+ console.log(chalk.bold('User ID:'), user.id);
99
+ console.log(chalk.bold('API URL:'), getBaseUrl());
100
+ }
101
+ catch (err) {
102
+ if (err instanceof OkraApiError && err.statusCode === 401) {
103
+ error('Session expired. Run `okra auth login` again.');
104
+ process.exit(3);
105
+ }
106
+ throw err;
107
+ }
108
+ });
109
+ // auth token
110
+ auth
111
+ .command('token')
112
+ .description('Print current API token (for piping)')
113
+ .action(() => {
114
+ const key = getApiKey();
115
+ if (!key) {
116
+ process.stderr.write('Not logged in\n');
117
+ process.exit(3);
118
+ }
119
+ // Print only the token for easy piping
120
+ process.stdout.write(key);
121
+ });
122
+ // auth status
123
+ auth
124
+ .command('status')
125
+ .description('Check authentication status')
126
+ .action(async () => {
127
+ const key = getApiKey();
128
+ if (!key) {
129
+ console.log(chalk.yellow('Status:'), 'Not authenticated');
130
+ console.log(chalk.dim('Run `okra auth login` to authenticate'));
131
+ return;
132
+ }
133
+ const maskedKey = key.substring(0, 12) + '...' + key.substring(key.length - 4);
134
+ console.log(chalk.bold('API Key:'), maskedKey);
135
+ console.log(chalk.bold('API URL:'), getBaseUrl());
136
+ console.log(chalk.bold('Config:'), getConfigPath());
137
+ // Try to verify the key
138
+ try {
139
+ const user = await get('api/auth/me');
140
+ console.log(chalk.green('Status:'), 'Authenticated');
141
+ console.log(chalk.bold('User:'), user.email);
142
+ }
143
+ catch (err) {
144
+ if (err instanceof OkraApiError && err.statusCode === 401) {
145
+ console.log(chalk.red('Status:'), 'Invalid or expired key');
146
+ }
147
+ else {
148
+ console.log(chalk.yellow('Status:'), 'Unable to verify (network error)');
149
+ }
150
+ }
151
+ });
152
+ return auth;
153
+ }
154
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Chat commands for interactive document conversations
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare function createChatCommand(): Command;
6
+ //# sourceMappingURL=chat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/commands/chat.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,wBAAgB,iBAAiB,IAAI,OAAO,CAwC3C"}