@okrapdf/cli 0.3.1 → 0.3.3
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/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +18 -4
- package/dist/cli.js.map +1 -1
- package/dist/cli.test.js +178 -11
- package/dist/cli.test.js.map +1 -1
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +246 -10
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/chat.test.js +178 -3
- package/dist/commands/chat.test.js.map +1 -1
- package/dist/commands/jobs.d.ts.map +1 -1
- package/dist/commands/jobs.js +4 -3
- package/dist/commands/jobs.js.map +1 -1
- package/dist/index.js +0 -0
- package/dist/lib/agent-renderer.d.ts +12 -0
- package/dist/lib/agent-renderer.d.ts.map +1 -1
- package/dist/lib/agent-renderer.js +28 -0
- package/dist/lib/agent-renderer.js.map +1 -1
- package/dist/lib/client.d.ts +1 -0
- package/dist/lib/client.d.ts.map +1 -1
- package/dist/lib/client.js +1 -0
- package/dist/lib/client.js.map +1 -1
- package/dist/lib/config.d.ts +16 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +28 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/output.d.ts +1 -1
- package/dist/lib/output.d.ts.map +1 -1
- package/dist/lib/output.js +53 -2
- package/dist/lib/output.js.map +1 -1
- package/dist/lib/runtime.d.ts.map +1 -1
- package/dist/lib/runtime.js +5 -0
- package/dist/lib/runtime.js.map +1 -1
- package/dist/lib/structured-output.d.ts +32 -0
- package/dist/lib/structured-output.d.ts.map +1 -0
- package/dist/lib/structured-output.js +156 -0
- package/dist/lib/structured-output.js.map +1 -0
- package/dist/lib/structured-output.test.d.ts +2 -0
- package/dist/lib/structured-output.test.d.ts.map +1 -0
- package/dist/lib/structured-output.test.js +148 -0
- package/dist/lib/structured-output.test.js.map +1 -0
- package/dist/lib/system-prompt.d.ts +4 -0
- package/dist/lib/system-prompt.d.ts.map +1 -1
- package/dist/lib/system-prompt.js +8 -0
- package/dist/lib/system-prompt.js.map +1 -1
- package/dist/templates/replay-viewer.html +230 -0
- package/package.json +4 -3
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +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;AAqCpC;;GAEG;AACH,wBAAgB,aAAa,IAAI,OAAO,
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqCpC;;GAEG;AACH,wBAAgB,aAAa,IAAI,OAAO,CA8JvC;AAED;;GAEG;AACH,wBAAsB,GAAG,CAAC,IAAI,GAAE,MAAM,EAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAStE"}
|
package/dist/cli.js
CHANGED
|
@@ -53,7 +53,8 @@ export function createProgram() {
|
|
|
53
53
|
.version(VERSION, '-v, --version', 'Output the version number')
|
|
54
54
|
.option('-q, --quiet', 'Suppress non-essential output (ideal for piping)')
|
|
55
55
|
.option('-V, --verbose', 'Enable verbose diagnostics (retries and debug logging)')
|
|
56
|
-
.option('--json', '
|
|
56
|
+
.option('--json [fields]', 'JSON output, optionally with comma-separated field names')
|
|
57
|
+
.option('--jq <expression>', 'Filter JSON output with a jq expression')
|
|
57
58
|
.option('--no-color', 'Disable colored output');
|
|
58
59
|
// Core commands
|
|
59
60
|
program.addCommand(createAuthCommand());
|
|
@@ -75,12 +76,22 @@ export function createProgram() {
|
|
|
75
76
|
program.addCommand(createLogsCommand());
|
|
76
77
|
program.addCommand(createProvidersCommand());
|
|
77
78
|
program.addCommand(createVlmCommand());
|
|
78
|
-
// Handle global --json
|
|
79
|
+
// Handle global --json / --jq flags
|
|
79
80
|
program.hook('preAction', (thisCommand, actionCommand) => {
|
|
80
81
|
const target = actionCommand || thisCommand;
|
|
81
82
|
const opts = target.optsWithGlobals();
|
|
83
|
+
// --jq implies JSON mode
|
|
84
|
+
if (opts.jq) {
|
|
85
|
+
process.env.OKRA_JQ = opts.jq;
|
|
86
|
+
if (!opts.json)
|
|
87
|
+
opts.json = true;
|
|
88
|
+
}
|
|
82
89
|
if (opts.json) {
|
|
83
90
|
process.env.OKRA_OUTPUT_FORMAT = 'json';
|
|
91
|
+
// --json field1,field2 → store fields for filtering
|
|
92
|
+
if (typeof opts.json === 'string') {
|
|
93
|
+
process.env.OKRA_JSON_FIELDS = opts.json;
|
|
94
|
+
}
|
|
84
95
|
const hasOutputOption = target.options.some((option) => option.attributeName() === 'output');
|
|
85
96
|
if (hasOutputOption && target.getOptionValueSource('output') !== 'cli') {
|
|
86
97
|
target.setOptionValueWithSource('output', 'json', 'env');
|
|
@@ -111,8 +122,11 @@ ${chalk.bold('For AI Agents (Machine-Readable Output):')}
|
|
|
111
122
|
${chalk.dim('# Get tables as JSON (for building presentations, reports)')}
|
|
112
123
|
$ okra extract document.pdf --json --quiet
|
|
113
124
|
|
|
114
|
-
${chalk.dim('# Get job list as JSON
|
|
115
|
-
$ okra jobs list
|
|
125
|
+
${chalk.dim('# Get job list as JSON, select fields')}
|
|
126
|
+
$ okra jobs list --json job_id,status
|
|
127
|
+
|
|
128
|
+
${chalk.dim('# Filter JSON output with jq')}
|
|
129
|
+
$ okra jobs list --jq '.[0].job_id'
|
|
116
130
|
|
|
117
131
|
${chalk.dim('# Extract with specific processor')}
|
|
118
132
|
$ okra jobs create document.pdf -p gemini --wait -o json
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;AAE9B,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;QACvD,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,IAAI,OAAO,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,MAAM,CAAC;SACZ,WAAW,CAAC,0DAA0D,CAAC;SACvE,OAAO,CAAC,OAAO,EAAE,eAAe,EAAE,2BAA2B,CAAC;SAC9D,MAAM,CAAC,aAAa,EAAE,kDAAkD,CAAC;SACzE,MAAM,CAAC,eAAe,EAAE,wDAAwD,CAAC;SACjF,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.test.js
CHANGED
|
@@ -1,35 +1,202 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
// Mock client module before importing anything that uses it
|
|
3
|
+
vi.mock('./lib/client.js', async (importOriginal) => {
|
|
4
|
+
const actual = await importOriginal();
|
|
5
|
+
return {
|
|
6
|
+
...actual,
|
|
7
|
+
get: vi.fn(),
|
|
8
|
+
};
|
|
9
|
+
});
|
|
2
10
|
import { createProgram } from './cli.js';
|
|
11
|
+
import { get } from './lib/client.js';
|
|
12
|
+
const mockedGet = vi.mocked(get);
|
|
3
13
|
const ORIGINAL_ENV = process.env;
|
|
4
|
-
|
|
14
|
+
const FAKE_JOBS_RESPONSE = {
|
|
15
|
+
items: [
|
|
16
|
+
{
|
|
17
|
+
job_id: 'ocr-abc123',
|
|
18
|
+
status: 'completed',
|
|
19
|
+
filename: 'invoice.pdf',
|
|
20
|
+
total_pages: 10,
|
|
21
|
+
pages_completed: 10,
|
|
22
|
+
error: null,
|
|
23
|
+
created_at: '2026-02-15T00:00:00Z',
|
|
24
|
+
updated_at: '2026-02-15T01:00:00Z',
|
|
25
|
+
viewer_url: 'https://app.okrapdf.com/ocr/ocr-abc123',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
job_id: 'ocr-xyz789',
|
|
29
|
+
status: 'running',
|
|
30
|
+
filename: 'report.pdf',
|
|
31
|
+
total_pages: 5,
|
|
32
|
+
pages_completed: 2,
|
|
33
|
+
error: null,
|
|
34
|
+
created_at: '2026-02-16T00:00:00Z',
|
|
35
|
+
updated_at: '2026-02-16T01:00:00Z',
|
|
36
|
+
viewer_url: 'https://app.okrapdf.com/ocr/ocr-xyz789',
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
pagination: { page: 1, totalPages: 1, total: 2 },
|
|
40
|
+
};
|
|
41
|
+
function cleanEnv() {
|
|
42
|
+
process.env = { ...ORIGINAL_ENV };
|
|
43
|
+
delete process.env.OKRA_OUTPUT_FORMAT;
|
|
44
|
+
delete process.env.OKRA_JSON_FIELDS;
|
|
45
|
+
delete process.env.OKRA_JQ;
|
|
46
|
+
delete process.env.OKRA_QUIET;
|
|
47
|
+
delete process.env.OKRA_VERBOSE;
|
|
48
|
+
}
|
|
49
|
+
describe('global --json flag', () => {
|
|
50
|
+
beforeEach(cleanEnv);
|
|
51
|
+
afterEach(() => {
|
|
52
|
+
process.env = ORIGINAL_ENV;
|
|
53
|
+
vi.restoreAllMocks();
|
|
54
|
+
});
|
|
55
|
+
it('--json exit_codes filters to only that field', async () => {
|
|
56
|
+
const out = [];
|
|
57
|
+
vi.spyOn(console, 'log').mockImplementation((...args) => {
|
|
58
|
+
out.push(args.join(' '));
|
|
59
|
+
});
|
|
60
|
+
const program = createProgram();
|
|
61
|
+
// --json takes 'exit_codes' as the field filter, 'exit-codes' is the subcommand
|
|
62
|
+
await program.parseAsync(['--json', 'exit_codes', 'exit-codes'], { from: 'user' });
|
|
63
|
+
const payload = JSON.parse(out.join('\n'));
|
|
64
|
+
expect(payload).toHaveProperty('exit_codes');
|
|
65
|
+
expect(Object.keys(payload)).toEqual(['exit_codes']);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
describe('--json field filtering with jobs list', () => {
|
|
5
69
|
beforeEach(() => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
delete process.env.OKRA_QUIET;
|
|
9
|
-
delete process.env.OKRA_VERBOSE;
|
|
70
|
+
cleanEnv();
|
|
71
|
+
process.env.OKRA_API_KEY = 'test-key';
|
|
10
72
|
});
|
|
11
73
|
afterEach(() => {
|
|
12
74
|
process.env = ORIGINAL_ENV;
|
|
13
75
|
vi.restoreAllMocks();
|
|
76
|
+
mockedGet.mockReset();
|
|
77
|
+
});
|
|
78
|
+
it('--json filename (before subcommand) returns only filename', async () => {
|
|
79
|
+
mockedGet.mockResolvedValueOnce(FAKE_JOBS_RESPONSE);
|
|
80
|
+
const out = [];
|
|
81
|
+
vi.spyOn(console, 'log').mockImplementation((...args) => {
|
|
82
|
+
out.push(args.join(' '));
|
|
83
|
+
});
|
|
84
|
+
const program = createProgram();
|
|
85
|
+
await program.parseAsync(['--json', 'filename', 'jobs', 'list'], { from: 'user' });
|
|
86
|
+
const payload = JSON.parse(out.join('\n'));
|
|
87
|
+
expect(Array.isArray(payload)).toBe(true);
|
|
88
|
+
expect(payload).toHaveLength(2);
|
|
89
|
+
for (const item of payload) {
|
|
90
|
+
expect(Object.keys(item)).toEqual(['filename']);
|
|
91
|
+
}
|
|
92
|
+
expect(payload[0].filename).toBe('invoice.pdf');
|
|
93
|
+
});
|
|
94
|
+
it('--json job_id,status returns only those two fields', async () => {
|
|
95
|
+
mockedGet.mockResolvedValueOnce(FAKE_JOBS_RESPONSE);
|
|
96
|
+
const out = [];
|
|
97
|
+
vi.spyOn(console, 'log').mockImplementation((...args) => {
|
|
98
|
+
out.push(args.join(' '));
|
|
99
|
+
});
|
|
100
|
+
const program = createProgram();
|
|
101
|
+
await program.parseAsync(['--json', 'job_id,status', 'jobs', 'list'], { from: 'user' });
|
|
102
|
+
const payload = JSON.parse(out.join('\n'));
|
|
103
|
+
expect(Array.isArray(payload)).toBe(true);
|
|
104
|
+
for (const item of payload) {
|
|
105
|
+
expect(Object.keys(item).sort()).toEqual(['job_id', 'status']);
|
|
106
|
+
}
|
|
14
107
|
});
|
|
15
|
-
it('
|
|
108
|
+
it('--json filename (after subcommand) also filters correctly', async () => {
|
|
109
|
+
mockedGet.mockResolvedValueOnce(FAKE_JOBS_RESPONSE);
|
|
16
110
|
const out = [];
|
|
17
111
|
vi.spyOn(console, 'log').mockImplementation((...args) => {
|
|
18
112
|
out.push(args.join(' '));
|
|
19
113
|
});
|
|
20
114
|
const program = createProgram();
|
|
21
|
-
await program.parseAsync(['--json', '
|
|
115
|
+
await program.parseAsync(['jobs', 'list', '--json', 'filename', '-l', '5'], { from: 'user' });
|
|
22
116
|
const payload = JSON.parse(out.join('\n'));
|
|
23
|
-
expect(payload
|
|
117
|
+
expect(Array.isArray(payload)).toBe(true);
|
|
118
|
+
for (const item of payload) {
|
|
119
|
+
expect(Object.keys(item)).toEqual(['filename']);
|
|
120
|
+
}
|
|
24
121
|
});
|
|
25
|
-
it('
|
|
122
|
+
it('full run() simulation with bootstrapGlobalEnv', async () => {
|
|
123
|
+
const { bootstrapGlobalEnv } = await import('./lib/runtime.js');
|
|
124
|
+
const argv = ['node', 'okra', 'jobs', 'list', '--json', 'filename', '-l', '5'];
|
|
125
|
+
bootstrapGlobalEnv(argv);
|
|
126
|
+
mockedGet.mockResolvedValueOnce(FAKE_JOBS_RESPONSE);
|
|
26
127
|
const out = [];
|
|
27
128
|
vi.spyOn(console, 'log').mockImplementation((...args) => {
|
|
28
129
|
out.push(args.join(' '));
|
|
29
130
|
});
|
|
30
131
|
const program = createProgram();
|
|
31
|
-
await program.parseAsync(
|
|
32
|
-
|
|
132
|
+
await program.parseAsync(argv);
|
|
133
|
+
const payload = JSON.parse(out.join('\n'));
|
|
134
|
+
expect(Array.isArray(payload)).toBe(true);
|
|
135
|
+
for (const item of payload) {
|
|
136
|
+
expect(Object.keys(item)).toEqual(['filename']);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
describe('JSON output cleanliness (gh CLI patterns)', () => {
|
|
141
|
+
beforeEach(() => {
|
|
142
|
+
cleanEnv();
|
|
143
|
+
process.env.OKRA_API_KEY = 'test-key';
|
|
144
|
+
});
|
|
145
|
+
afterEach(() => {
|
|
146
|
+
process.env = ORIGINAL_ENV;
|
|
147
|
+
vi.restoreAllMocks();
|
|
148
|
+
mockedGet.mockReset();
|
|
149
|
+
});
|
|
150
|
+
it('suppresses pagination footer in JSON mode', async () => {
|
|
151
|
+
const multiPageResponse = {
|
|
152
|
+
...FAKE_JOBS_RESPONSE,
|
|
153
|
+
pagination: { page: 1, totalPages: 35, total: 699 },
|
|
154
|
+
};
|
|
155
|
+
mockedGet.mockResolvedValueOnce(multiPageResponse);
|
|
156
|
+
const out = [];
|
|
157
|
+
vi.spyOn(console, 'log').mockImplementation((...args) => {
|
|
158
|
+
out.push(args.join(' '));
|
|
159
|
+
});
|
|
160
|
+
const program = createProgram();
|
|
161
|
+
await program.parseAsync(['--json', 'job_id', 'jobs', 'list'], { from: 'user' });
|
|
162
|
+
const raw = out.join('\n');
|
|
163
|
+
// Should be valid JSON with no trailing "Page X of Y" text
|
|
164
|
+
expect(() => JSON.parse(raw)).not.toThrow();
|
|
165
|
+
expect(raw).not.toContain('Page');
|
|
166
|
+
expect(raw).not.toContain('total');
|
|
167
|
+
});
|
|
168
|
+
it('shows pagination footer in table mode', async () => {
|
|
169
|
+
const multiPageResponse = {
|
|
170
|
+
...FAKE_JOBS_RESPONSE,
|
|
171
|
+
pagination: { page: 1, totalPages: 35, total: 699 },
|
|
172
|
+
};
|
|
173
|
+
mockedGet.mockResolvedValueOnce(multiPageResponse);
|
|
174
|
+
const out = [];
|
|
175
|
+
vi.spyOn(console, 'log').mockImplementation((...args) => {
|
|
176
|
+
out.push(args.join(' '));
|
|
177
|
+
});
|
|
178
|
+
const program = createProgram();
|
|
179
|
+
await program.parseAsync(['jobs', 'list'], { from: 'user' });
|
|
180
|
+
const raw = out.join('\n');
|
|
181
|
+
expect(raw).toContain('Page 1 of 35');
|
|
182
|
+
expect(raw).toContain('699 total');
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
describe('bootstrapGlobalEnv', () => {
|
|
186
|
+
beforeEach(cleanEnv);
|
|
187
|
+
afterEach(() => {
|
|
188
|
+
process.env = ORIGINAL_ENV;
|
|
189
|
+
});
|
|
190
|
+
it('--json sets OKRA_OUTPUT_FORMAT', async () => {
|
|
191
|
+
const { bootstrapGlobalEnv } = await import('./lib/runtime.js');
|
|
192
|
+
bootstrapGlobalEnv(['node', 'okra', 'jobs', 'list', '--json']);
|
|
193
|
+
expect(process.env.OKRA_OUTPUT_FORMAT).toBe('json');
|
|
194
|
+
});
|
|
195
|
+
it('--json=fields sets OKRA_JSON_FIELDS', async () => {
|
|
196
|
+
const { bootstrapGlobalEnv } = await import('./lib/runtime.js');
|
|
197
|
+
bootstrapGlobalEnv(['node', 'okra', 'jobs', 'list', '--json=filename,status']);
|
|
198
|
+
expect(process.env.OKRA_OUTPUT_FORMAT).toBe('json');
|
|
199
|
+
expect(process.env.OKRA_JSON_FIELDS).toBe('filename,status');
|
|
33
200
|
});
|
|
34
201
|
});
|
|
35
202
|
//# sourceMappingURL=cli.test.js.map
|
package/dist/cli.test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.test.js","sourceRoot":"","sources":["../src/cli.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.test.js","sourceRoot":"","sources":["../src/cli.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/commands/chat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,uBAAuB,CAAC;AAE/B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/commands/chat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,uBAAuB,CAAC;AAE/B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuBpC,wBAAgB,iBAAiB,IAAI,OAAO,CA6W3C"}
|
package/dist/commands/chat.js
CHANGED
|
@@ -22,22 +22,48 @@ import '../lib/ws-polyfill.js';
|
|
|
22
22
|
import { Command } from 'commander';
|
|
23
23
|
import { AgentSessionClient } from '@steventsao/agent-session';
|
|
24
24
|
import { fetchBootstrap } from '../lib/bootstrap.js';
|
|
25
|
-
import { AgentRenderer } from '../lib/agent-renderer.js';
|
|
26
|
-
import {
|
|
27
|
-
import { getApiKey } from '../lib/config.js';
|
|
25
|
+
import { AgentRenderer, SilentCollectorRenderer } from '../lib/agent-renderer.js';
|
|
26
|
+
import { buildSystemPrompt } from '../lib/system-prompt.js';
|
|
27
|
+
import { getApiKey, getAgentSessionUrl, getAgentSessionHttpUrl } from '../lib/config.js';
|
|
28
28
|
import { error, info } from '../lib/output.js';
|
|
29
29
|
import { createSpinner } from '../lib/progress.js';
|
|
30
30
|
import { OkraApiError, EXIT_CODES } from '../lib/client.js';
|
|
31
|
-
|
|
31
|
+
import { resolveSchema, extractJson, listBuiltinNames, } from '../lib/structured-output.js';
|
|
32
|
+
const WSS_URL = getAgentSessionUrl();
|
|
32
33
|
const SANDBOX_TEMPLATE = 'okra-claude-agent-sdk';
|
|
33
34
|
const SANDBOX_TIMEOUT_MS = 120_000;
|
|
34
35
|
export function createChatCommand() {
|
|
35
36
|
const chat = new Command('chat')
|
|
36
|
-
.description('Chat with a document via agent session')
|
|
37
|
+
.description('Chat with a document via agent session');
|
|
38
|
+
// Default subcommand: okra chat <jobId> -m "msg"
|
|
39
|
+
const send = new Command('send')
|
|
40
|
+
.description('Send a message to a document chat session')
|
|
37
41
|
.argument('<jobId>', 'OCR job ID (e.g. ocr-Bvx9ire6wFEHbsjecW3FM)')
|
|
38
42
|
.requiredOption('-m, --message <message>', 'Message to send')
|
|
39
43
|
.option('-o, --output <format>', 'Output format (text, json)', 'text')
|
|
44
|
+
.option('-s, --schema <schema>', 'Structured output: built-in name, inline JSON, or file path')
|
|
40
45
|
.action(async (jobId, options) => {
|
|
46
|
+
// Handle --schema help
|
|
47
|
+
if (options.schema === 'help') {
|
|
48
|
+
console.log('Built-in schemas:');
|
|
49
|
+
for (const name of listBuiltinNames()) {
|
|
50
|
+
console.log(` ${name}`);
|
|
51
|
+
}
|
|
52
|
+
console.log('\nYou can also pass inline JSON or a file path:');
|
|
53
|
+
console.log(' --schema \'{"type":"object","properties":{"name":{"type":"string"}}}\'');
|
|
54
|
+
console.log(' --schema ./my-schema.json');
|
|
55
|
+
process.exit(0);
|
|
56
|
+
}
|
|
57
|
+
// Resolve schema (built-in name, inline JSON, or file path)
|
|
58
|
+
let resolvedSchema;
|
|
59
|
+
if (options.schema) {
|
|
60
|
+
const result = resolveSchema(options.schema);
|
|
61
|
+
if ('error' in result) {
|
|
62
|
+
error(result.error);
|
|
63
|
+
process.exit(EXIT_CODES.INVALID_ARGS);
|
|
64
|
+
}
|
|
65
|
+
resolvedSchema = result.schema;
|
|
66
|
+
}
|
|
41
67
|
const apiKey = getApiKey();
|
|
42
68
|
if (!apiKey) {
|
|
43
69
|
error('Not authenticated. Run `okra auth login` first.');
|
|
@@ -68,7 +94,9 @@ export function createChatCommand() {
|
|
|
68
94
|
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
69
95
|
}
|
|
70
96
|
// 2. Connect WebSocket
|
|
71
|
-
const renderer =
|
|
97
|
+
const renderer = resolvedSchema
|
|
98
|
+
? new SilentCollectorRenderer()
|
|
99
|
+
: new AgentRenderer();
|
|
72
100
|
const client = new AgentSessionClient({
|
|
73
101
|
url: WSS_URL,
|
|
74
102
|
sessionId: jobId,
|
|
@@ -141,6 +169,8 @@ export function createChatCommand() {
|
|
|
141
169
|
return;
|
|
142
170
|
renderer.onAgentStarted();
|
|
143
171
|
});
|
|
172
|
+
// Capture structured_output from SDK result event
|
|
173
|
+
let structuredOutput = undefined;
|
|
144
174
|
client.on('AGENT_MESSAGE', (event) => {
|
|
145
175
|
if (!messageSent)
|
|
146
176
|
return;
|
|
@@ -151,6 +181,10 @@ export function createChatCommand() {
|
|
|
151
181
|
rejectAgent(new Error(String(errMsg)));
|
|
152
182
|
return;
|
|
153
183
|
}
|
|
184
|
+
// Capture SDK structured_output from result event
|
|
185
|
+
if (event.subtype === 'result' && event.structured_output != null) {
|
|
186
|
+
structuredOutput = event.structured_output;
|
|
187
|
+
}
|
|
154
188
|
renderer.onAgentMessage(event.message?.content);
|
|
155
189
|
});
|
|
156
190
|
client.on('AGENT_DONE', (event) => {
|
|
@@ -188,17 +222,27 @@ export function createChatCommand() {
|
|
|
188
222
|
await replayDone;
|
|
189
223
|
// 7. Send message — flip gate so subsequent events are rendered
|
|
190
224
|
messageSent = true;
|
|
191
|
-
|
|
225
|
+
if (!resolvedSchema)
|
|
226
|
+
info(`Sending: ${options.message}`);
|
|
227
|
+
const systemPrompt = buildSystemPrompt({ schema: resolvedSchema });
|
|
192
228
|
// Send raw AGENT_MESSAGE so author metadata is preserved across
|
|
193
229
|
// older @steventsao/agent-session client versions used by the CLI.
|
|
194
|
-
|
|
230
|
+
const wsMessage = {
|
|
195
231
|
type: 'AGENT_MESSAGE',
|
|
196
232
|
content: options.message,
|
|
197
233
|
model: { id: 'claude-sonnet-4-20250514', provider: 'anthropic' },
|
|
198
|
-
systemPrompt
|
|
234
|
+
systemPrompt,
|
|
199
235
|
agentType: 'claude-code',
|
|
200
236
|
author: { name: 'okra-cli', clientType: 'cli' },
|
|
201
|
-
}
|
|
237
|
+
};
|
|
238
|
+
// Send JSON Schema for SDK-native structured output
|
|
239
|
+
if (resolvedSchema) {
|
|
240
|
+
wsMessage.outputFormat = {
|
|
241
|
+
type: 'json_schema',
|
|
242
|
+
schema: resolvedSchema.jsonSchema,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
client.send(wsMessage);
|
|
202
246
|
// 8. Wait for agent completion
|
|
203
247
|
try {
|
|
204
248
|
await agentDone;
|
|
@@ -207,10 +251,202 @@ export function createChatCommand() {
|
|
|
207
251
|
error(err instanceof Error ? err.message : String(err));
|
|
208
252
|
process.exitCode = EXIT_CODES.GENERAL_ERROR;
|
|
209
253
|
}
|
|
254
|
+
// 8b. Structured output: prefer SDK structured_output, fall back to text extraction
|
|
255
|
+
if (resolvedSchema && !process.exitCode) {
|
|
256
|
+
let parsed = structuredOutput ?? null;
|
|
257
|
+
// Fallback: extract JSON from collected text if SDK didn't return structured_output
|
|
258
|
+
if (parsed === null) {
|
|
259
|
+
const raw = renderer.getCollectedText();
|
|
260
|
+
parsed = extractJson(raw);
|
|
261
|
+
if (parsed === null) {
|
|
262
|
+
console.error('Failed to extract JSON from agent response.');
|
|
263
|
+
console.error('Raw output:\n' + raw);
|
|
264
|
+
process.exitCode = EXIT_CODES.VALIDATION_ERROR;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (parsed !== null && !process.exitCode) {
|
|
268
|
+
// For built-in schemas, validate with Zod; for custom schemas, output as-is
|
|
269
|
+
if (resolvedSchema.zodSchema) {
|
|
270
|
+
const result = resolvedSchema.zodSchema.safeParse(parsed);
|
|
271
|
+
if (result.success) {
|
|
272
|
+
console.log(JSON.stringify(result.data, null, 2));
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
console.error('Schema validation failed:');
|
|
276
|
+
for (const issue of result.error.issues) {
|
|
277
|
+
console.error(` - ${issue.path.join('.')}: ${issue.message}`);
|
|
278
|
+
}
|
|
279
|
+
console.error('\nRaw JSON:\n' + JSON.stringify(parsed, null, 2));
|
|
280
|
+
process.exitCode = EXIT_CODES.VALIDATION_ERROR;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
// Custom schema — SDK already validated via constrained decoding
|
|
285
|
+
console.log(JSON.stringify(parsed, null, 2));
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
210
289
|
// 9. Disconnect and exit
|
|
211
290
|
client.disconnect();
|
|
212
291
|
process.exit(process.exitCode ?? 0);
|
|
213
292
|
});
|
|
293
|
+
// ── view subcommand ──────────────────────────────────────────────────
|
|
294
|
+
const view = new Command('view')
|
|
295
|
+
.description('View a past chat session (read-only replay)')
|
|
296
|
+
.argument('[sessionId]', 'Session ID to view')
|
|
297
|
+
.option('--file <path>', 'Read events from local JSONL file instead of server')
|
|
298
|
+
.option('--web', 'Open as static HTML in browser')
|
|
299
|
+
.option('--jsonl', 'Output raw JSONL to stdout')
|
|
300
|
+
.action(async (sessionId, opts) => {
|
|
301
|
+
const { readFileSync, writeFileSync } = await import('fs');
|
|
302
|
+
const { tmpdir } = await import('os');
|
|
303
|
+
const { join, dirname } = await import('path');
|
|
304
|
+
const { fileURLToPath } = await import('url');
|
|
305
|
+
const chalk = (await import('chalk')).default;
|
|
306
|
+
const got = (await import('got')).default;
|
|
307
|
+
const { openInBrowser } = await import('../lib/browser.js');
|
|
308
|
+
// Resolve events source
|
|
309
|
+
let events;
|
|
310
|
+
if (opts.file) {
|
|
311
|
+
try {
|
|
312
|
+
const raw = readFileSync(opts.file, 'utf8');
|
|
313
|
+
events = parseJsonl(raw);
|
|
314
|
+
}
|
|
315
|
+
catch (err) {
|
|
316
|
+
error(`Failed to read file: ${err instanceof Error ? err.message : err}`);
|
|
317
|
+
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
else if (sessionId) {
|
|
321
|
+
const apiKey = getApiKey();
|
|
322
|
+
if (!apiKey) {
|
|
323
|
+
error('Not authenticated. Run `okra auth login` first.');
|
|
324
|
+
process.exit(EXIT_CODES.AUTH_ERROR);
|
|
325
|
+
}
|
|
326
|
+
const spinner = createSpinner('Fetching session events...');
|
|
327
|
+
spinner.start();
|
|
328
|
+
try {
|
|
329
|
+
const url = `${getAgentSessionHttpUrl()}/session/${sessionId}/events`;
|
|
330
|
+
const response = await got(url, {
|
|
331
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
332
|
+
timeout: { request: 15_000 },
|
|
333
|
+
});
|
|
334
|
+
events = parseJsonl(response.body);
|
|
335
|
+
spinner.succeed(`${events.length} events loaded`);
|
|
336
|
+
}
|
|
337
|
+
catch (err) {
|
|
338
|
+
spinner.fail('Failed to fetch events');
|
|
339
|
+
error(err instanceof Error ? err.message : String(err));
|
|
340
|
+
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
error('Provide a session ID or --file path');
|
|
345
|
+
process.exit(EXIT_CODES.INVALID_ARGS);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
if (events.length === 0) {
|
|
349
|
+
info('No events found');
|
|
350
|
+
process.exit(0);
|
|
351
|
+
}
|
|
352
|
+
// Output modes
|
|
353
|
+
if (opts.jsonl) {
|
|
354
|
+
for (const evt of events) {
|
|
355
|
+
console.log(JSON.stringify(evt));
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
else if (opts.web) {
|
|
359
|
+
const label = sessionId || opts.file || 'local';
|
|
360
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
361
|
+
const templatePath = join(currentDir, '..', 'templates', 'replay-viewer.html');
|
|
362
|
+
let template = readFileSync(templatePath, 'utf8');
|
|
363
|
+
template = template.replace(/\{\{SESSION_ID\}\}/g, label);
|
|
364
|
+
template = template.replace('{{REPLAY_DATA}}', JSON.stringify(events));
|
|
365
|
+
const safeId = label.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
366
|
+
const outPath = join(tmpdir(), `okra-replay-${safeId}.html`);
|
|
367
|
+
writeFileSync(outPath, template, 'utf8');
|
|
368
|
+
info(`Opening ${outPath}`);
|
|
369
|
+
await openInBrowser(`file://${outPath}`);
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
renderTerminalTranscript(events, chalk);
|
|
373
|
+
}
|
|
374
|
+
process.exit(0);
|
|
375
|
+
});
|
|
376
|
+
chat.addCommand(send, { isDefault: true });
|
|
377
|
+
chat.addCommand(view);
|
|
214
378
|
return chat;
|
|
215
379
|
}
|
|
380
|
+
function parseJsonl(raw) {
|
|
381
|
+
return raw
|
|
382
|
+
.split('\n')
|
|
383
|
+
.filter(line => line.trim())
|
|
384
|
+
.map(line => {
|
|
385
|
+
try {
|
|
386
|
+
return JSON.parse(line);
|
|
387
|
+
}
|
|
388
|
+
catch {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
})
|
|
392
|
+
.filter((e) => e !== null);
|
|
393
|
+
}
|
|
394
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
395
|
+
function renderTerminalTranscript(events, chalk) {
|
|
396
|
+
for (const evt of events) {
|
|
397
|
+
const ts = evt.timestamp ? chalk.dim(new Date(evt.timestamp).toLocaleTimeString() + ' ') : '';
|
|
398
|
+
switch (evt.type) {
|
|
399
|
+
case 'user': {
|
|
400
|
+
const author = evt.author ? chalk.dim(` (${evt.author.name})`) : '';
|
|
401
|
+
console.log(`\n${ts}${chalk.blue.bold('User')}${author}`);
|
|
402
|
+
const content = typeof evt.message?.content === 'string'
|
|
403
|
+
? evt.message.content
|
|
404
|
+
: '';
|
|
405
|
+
if (content)
|
|
406
|
+
console.log(content);
|
|
407
|
+
break;
|
|
408
|
+
}
|
|
409
|
+
case 'assistant': {
|
|
410
|
+
console.log(`\n${ts}${chalk.bold('Assistant')}`);
|
|
411
|
+
const blocks = evt.message?.content;
|
|
412
|
+
if (Array.isArray(blocks)) {
|
|
413
|
+
for (const b of blocks) {
|
|
414
|
+
if (b.type === 'text' && b.text) {
|
|
415
|
+
console.log(b.text);
|
|
416
|
+
}
|
|
417
|
+
else if (b.type === 'tool_use') {
|
|
418
|
+
console.log(chalk.dim(` ▸ ${b.name}(${JSON.stringify(b.input).slice(0, 120)})`));
|
|
419
|
+
}
|
|
420
|
+
else if (b.type === 'tool_result') {
|
|
421
|
+
const text = typeof b.content === 'string' ? b.content : JSON.stringify(b.content);
|
|
422
|
+
if (text) {
|
|
423
|
+
const truncated = text.length > 200 ? text.slice(0, 200) + '...' : text;
|
|
424
|
+
console.log(chalk.dim(` ← ${truncated}`));
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
break;
|
|
430
|
+
}
|
|
431
|
+
case 'result': {
|
|
432
|
+
const parts = [];
|
|
433
|
+
if (evt.duration_ms != null)
|
|
434
|
+
parts.push(`${(evt.duration_ms / 1000).toFixed(1)}s`);
|
|
435
|
+
if (evt.total_cost_usd != null)
|
|
436
|
+
parts.push(`$${evt.total_cost_usd.toFixed(4)}`);
|
|
437
|
+
if (evt.exit_code != null)
|
|
438
|
+
parts.push(`exit ${evt.exit_code}`);
|
|
439
|
+
if (parts.length)
|
|
440
|
+
console.log(chalk.dim(`\n${parts.join(' · ')}`));
|
|
441
|
+
break;
|
|
442
|
+
}
|
|
443
|
+
case 'error':
|
|
444
|
+
console.log(`\n${ts}${chalk.red('Error:')} ${evt.error || ''}`);
|
|
445
|
+
break;
|
|
446
|
+
case 'system':
|
|
447
|
+
console.log(chalk.dim(` [system] ${evt.message || ''}`));
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
216
452
|
//# sourceMappingURL=chat.js.map
|