@okrapdf/cli 0.3.2 → 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.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 +8 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +13 -0
- package/dist/lib/config.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
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>OkraPDF Chat Replay — {{SESSION_ID}}</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
9
|
+
body {
|
|
10
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
11
|
+
background: #0a0a0a; color: #e5e5e5;
|
|
12
|
+
line-height: 1.6; padding: 0;
|
|
13
|
+
}
|
|
14
|
+
.header {
|
|
15
|
+
position: sticky; top: 0; z-index: 10;
|
|
16
|
+
background: #141414; border-bottom: 1px solid #262626;
|
|
17
|
+
padding: 12px 24px; display: flex; align-items: center; gap: 16px;
|
|
18
|
+
}
|
|
19
|
+
.header h1 { font-size: 14px; font-weight: 600; color: #a3a3a3; }
|
|
20
|
+
.header .meta { font-size: 12px; color: #525252; }
|
|
21
|
+
.header .meta span { margin-right: 12px; }
|
|
22
|
+
.container { max-width: 860px; margin: 0 auto; padding: 24px; }
|
|
23
|
+
.event {
|
|
24
|
+
margin-bottom: 16px; padding: 12px 16px;
|
|
25
|
+
border-radius: 8px; position: relative;
|
|
26
|
+
border: 1px solid transparent;
|
|
27
|
+
}
|
|
28
|
+
.event.active { border-color: #555; }
|
|
29
|
+
.event-user {
|
|
30
|
+
background: #1a1a1a; border-left: 3px solid #888;
|
|
31
|
+
}
|
|
32
|
+
.event-assistant { background: #171717; }
|
|
33
|
+
.event-result {
|
|
34
|
+
background: #0c0c0c; border-left: 3px solid #22c55e;
|
|
35
|
+
font-size: 13px; color: #737373; padding: 8px 16px;
|
|
36
|
+
}
|
|
37
|
+
.event-error {
|
|
38
|
+
background: #1a0a0a; border-left: 3px solid #ef4444;
|
|
39
|
+
}
|
|
40
|
+
.event-system {
|
|
41
|
+
background: transparent; color: #525252;
|
|
42
|
+
font-size: 12px; padding: 4px 16px; text-align: center;
|
|
43
|
+
}
|
|
44
|
+
.role {
|
|
45
|
+
font-size: 11px; font-weight: 600; text-transform: uppercase;
|
|
46
|
+
letter-spacing: 0.05em; margin-bottom: 6px;
|
|
47
|
+
}
|
|
48
|
+
.role-user { color: #ccc; }
|
|
49
|
+
.role-assistant { color: #a3a3a3; }
|
|
50
|
+
.role-error { color: #f87171; }
|
|
51
|
+
.timestamp {
|
|
52
|
+
position: absolute; top: 12px; right: 16px;
|
|
53
|
+
font-size: 11px; color: #404040;
|
|
54
|
+
}
|
|
55
|
+
.content { white-space: pre-wrap; word-break: break-word; }
|
|
56
|
+
.content code {
|
|
57
|
+
background: #262626; padding: 1px 5px; border-radius: 3px;
|
|
58
|
+
font-family: 'SF Mono', 'Fira Code', monospace; font-size: 13px;
|
|
59
|
+
}
|
|
60
|
+
.tool-use {
|
|
61
|
+
margin: 8px 0; padding: 8px 12px;
|
|
62
|
+
background: #1a1a1a; border-radius: 6px;
|
|
63
|
+
border: 1px solid #333; cursor: pointer;
|
|
64
|
+
}
|
|
65
|
+
.tool-use summary {
|
|
66
|
+
font-size: 13px; color: #999; font-weight: 500;
|
|
67
|
+
list-style: none; display: flex; align-items: center; gap: 6px;
|
|
68
|
+
}
|
|
69
|
+
.tool-use summary::before { content: '▶'; font-size: 10px; transition: transform 0.15s; }
|
|
70
|
+
.tool-use[open] summary::before { transform: rotate(90deg); }
|
|
71
|
+
.tool-input {
|
|
72
|
+
margin-top: 8px; padding: 8px;
|
|
73
|
+
background: #111; border-radius: 4px;
|
|
74
|
+
font-family: 'SF Mono', monospace; font-size: 12px;
|
|
75
|
+
color: #a3a3a3; overflow-x: auto; white-space: pre;
|
|
76
|
+
}
|
|
77
|
+
.tool-result {
|
|
78
|
+
margin: 4px 0; padding: 6px 12px;
|
|
79
|
+
background: #111; border-radius: 4px;
|
|
80
|
+
font-size: 12px; color: #737373;
|
|
81
|
+
max-height: 200px; overflow-y: auto;
|
|
82
|
+
font-family: 'SF Mono', monospace; white-space: pre-wrap;
|
|
83
|
+
}
|
|
84
|
+
.nav-hint {
|
|
85
|
+
position: fixed; bottom: 16px; right: 16px;
|
|
86
|
+
background: #262626; padding: 8px 12px; border-radius: 6px;
|
|
87
|
+
font-size: 11px; color: #525252;
|
|
88
|
+
}
|
|
89
|
+
.nav-hint kbd {
|
|
90
|
+
background: #404040; padding: 2px 6px; border-radius: 3px;
|
|
91
|
+
font-family: monospace; color: #a3a3a3;
|
|
92
|
+
}
|
|
93
|
+
.cost { color: #22c55e; }
|
|
94
|
+
.duration { color: #a3a3a3; }
|
|
95
|
+
</style>
|
|
96
|
+
</head>
|
|
97
|
+
<body>
|
|
98
|
+
<div class="header">
|
|
99
|
+
<h1>OkraPDF Chat Replay</h1>
|
|
100
|
+
<div class="meta">
|
|
101
|
+
<span id="session-id"></span>
|
|
102
|
+
<span id="event-count"></span>
|
|
103
|
+
<span id="time-range"></span>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
<div class="container" id="events"></div>
|
|
107
|
+
<div class="nav-hint">
|
|
108
|
+
<kbd>↑</kbd><kbd>↓</kbd> navigate
|
|
109
|
+
<kbd>Home</kbd><kbd>End</kbd> jump
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<script>
|
|
113
|
+
const DATA = {{REPLAY_DATA}};
|
|
114
|
+
const container = document.getElementById('events');
|
|
115
|
+
let activeIndex = -1;
|
|
116
|
+
const eventEls = [];
|
|
117
|
+
|
|
118
|
+
// Metadata
|
|
119
|
+
document.getElementById('session-id').textContent = '{{SESSION_ID}}';
|
|
120
|
+
document.getElementById('event-count').textContent = DATA.length + ' events';
|
|
121
|
+
if (DATA.length > 0) {
|
|
122
|
+
const first = DATA[0].timestamp;
|
|
123
|
+
const last = DATA[DATA.length - 1].timestamp;
|
|
124
|
+
if (first && last) {
|
|
125
|
+
document.getElementById('time-range').textContent =
|
|
126
|
+
new Date(first).toLocaleString() + ' → ' + new Date(last).toLocaleString();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function formatTs(ts) {
|
|
131
|
+
if (!ts) return '';
|
|
132
|
+
const d = new Date(ts);
|
|
133
|
+
return d.toLocaleTimeString();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function escapeHtml(s) {
|
|
137
|
+
if (typeof s !== 'string') return '';
|
|
138
|
+
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function renderContent(blocks) {
|
|
142
|
+
if (!Array.isArray(blocks)) return escapeHtml(String(blocks || ''));
|
|
143
|
+
let html = '';
|
|
144
|
+
for (const b of blocks) {
|
|
145
|
+
if (b.type === 'text') {
|
|
146
|
+
html += '<div class="content">' + escapeHtml(b.text) + '</div>';
|
|
147
|
+
} else if (b.type === 'tool_use') {
|
|
148
|
+
html += '<details class="tool-use"><summary>' + escapeHtml(b.name) + '</summary>';
|
|
149
|
+
html += '<div class="tool-input">' + escapeHtml(JSON.stringify(b.input, null, 2)) + '</div>';
|
|
150
|
+
html += '</details>';
|
|
151
|
+
} else if (b.type === 'tool_result') {
|
|
152
|
+
const text = typeof b.content === 'string' ? b.content : JSON.stringify(b.content);
|
|
153
|
+
const truncated = text && text.length > 500 ? text.slice(0, 500) + '...' : text;
|
|
154
|
+
html += '<div class="tool-result">' + escapeHtml(truncated || '') + '</div>';
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return html;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
for (let i = 0; i < DATA.length; i++) {
|
|
161
|
+
const evt = DATA[i];
|
|
162
|
+
const div = document.createElement('div');
|
|
163
|
+
|
|
164
|
+
switch (evt.type) {
|
|
165
|
+
case 'user':
|
|
166
|
+
div.className = 'event event-user';
|
|
167
|
+
div.innerHTML = '<div class="role role-user">User' +
|
|
168
|
+
(evt.author ? ' (' + escapeHtml(evt.author.name) + ')' : '') +
|
|
169
|
+
'</div>' +
|
|
170
|
+
'<span class="timestamp">' + formatTs(evt.timestamp) + '</span>' +
|
|
171
|
+
'<div class="content">' + escapeHtml(evt.message?.content || '') + '</div>';
|
|
172
|
+
break;
|
|
173
|
+
case 'assistant':
|
|
174
|
+
div.className = 'event event-assistant';
|
|
175
|
+
div.innerHTML = '<div class="role role-assistant">Assistant</div>' +
|
|
176
|
+
'<span class="timestamp">' + formatTs(evt.timestamp) + '</span>' +
|
|
177
|
+
renderContent(evt.message?.content || []);
|
|
178
|
+
break;
|
|
179
|
+
case 'result':
|
|
180
|
+
div.className = 'event event-result';
|
|
181
|
+
const parts = [];
|
|
182
|
+
if (evt.duration_ms != null) parts.push('<span class="duration">' + (evt.duration_ms / 1000).toFixed(1) + 's</span>');
|
|
183
|
+
if (evt.total_cost_usd != null) parts.push('<span class="cost">$' + evt.total_cost_usd.toFixed(4) + '</span>');
|
|
184
|
+
if (evt.exit_code != null) parts.push('exit ' + evt.exit_code);
|
|
185
|
+
div.innerHTML = parts.join(' · ') || 'done';
|
|
186
|
+
break;
|
|
187
|
+
case 'error':
|
|
188
|
+
div.className = 'event event-error';
|
|
189
|
+
div.innerHTML = '<div class="role role-error">Error</div>' +
|
|
190
|
+
'<div class="content">' + escapeHtml(evt.error) + '</div>';
|
|
191
|
+
break;
|
|
192
|
+
case 'system':
|
|
193
|
+
div.className = 'event event-system';
|
|
194
|
+
div.textContent = evt.message || '';
|
|
195
|
+
break;
|
|
196
|
+
default:
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
div.dataset.index = i;
|
|
201
|
+
container.appendChild(div);
|
|
202
|
+
eventEls.push(div);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function setActive(idx) {
|
|
206
|
+
if (idx < 0 || idx >= eventEls.length) return;
|
|
207
|
+
if (activeIndex >= 0) eventEls[activeIndex].classList.remove('active');
|
|
208
|
+
activeIndex = idx;
|
|
209
|
+
eventEls[activeIndex].classList.add('active');
|
|
210
|
+
eventEls[activeIndex].scrollIntoView({ block: 'nearest', behavior: 'smooth' });
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
document.addEventListener('keydown', (e) => {
|
|
214
|
+
if (e.key === 'ArrowDown' || e.key === 'j') {
|
|
215
|
+
e.preventDefault();
|
|
216
|
+
setActive(Math.min(activeIndex + 1, eventEls.length - 1));
|
|
217
|
+
} else if (e.key === 'ArrowUp' || e.key === 'k') {
|
|
218
|
+
e.preventDefault();
|
|
219
|
+
setActive(Math.max(activeIndex - 1, 0));
|
|
220
|
+
} else if (e.key === 'Home') {
|
|
221
|
+
e.preventDefault();
|
|
222
|
+
setActive(0);
|
|
223
|
+
} else if (e.key === 'End') {
|
|
224
|
+
e.preventDefault();
|
|
225
|
+
setActive(eventEls.length - 1);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
</script>
|
|
229
|
+
</body>
|
|
230
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@okrapdf/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "OkraPDF command-line interface for PDF extraction and document chat",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"access": "public"
|
|
13
13
|
},
|
|
14
14
|
"scripts": {
|
|
15
|
-
"build": "tsc",
|
|
15
|
+
"build": "tsc && cp -r src/templates dist/",
|
|
16
16
|
"dev": "tsc --watch",
|
|
17
17
|
"start": "node dist/index.js",
|
|
18
18
|
"test": "vitest run",
|
|
@@ -57,7 +57,8 @@
|
|
|
57
57
|
"got": "^14.4.2",
|
|
58
58
|
"ora": "^8.0.1",
|
|
59
59
|
"pdfquery": "^0.1.2",
|
|
60
|
-
"ws": "^8.18.0"
|
|
60
|
+
"ws": "^8.18.0",
|
|
61
|
+
"zod": "^4.3.6"
|
|
61
62
|
},
|
|
62
63
|
"optionalDependencies": {
|
|
63
64
|
"mupdf": "^0.3.0",
|