expressible 0.1.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.
Files changed (93) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +261 -0
  3. package/dist/commands/add.d.ts +9 -0
  4. package/dist/commands/add.d.ts.map +1 -0
  5. package/dist/commands/add.js +175 -0
  6. package/dist/commands/add.js.map +1 -0
  7. package/dist/commands/doctor.d.ts +2 -0
  8. package/dist/commands/doctor.d.ts.map +1 -0
  9. package/dist/commands/doctor.js +126 -0
  10. package/dist/commands/doctor.js.map +1 -0
  11. package/dist/commands/export.d.ts +2 -0
  12. package/dist/commands/export.d.ts.map +1 -0
  13. package/dist/commands/export.js +108 -0
  14. package/dist/commands/export.js.map +1 -0
  15. package/dist/commands/init.d.ts +2 -0
  16. package/dist/commands/init.d.ts.map +1 -0
  17. package/dist/commands/init.js +37 -0
  18. package/dist/commands/init.js.map +1 -0
  19. package/dist/commands/retrain.d.ts +2 -0
  20. package/dist/commands/retrain.d.ts.map +1 -0
  21. package/dist/commands/retrain.js +139 -0
  22. package/dist/commands/retrain.js.map +1 -0
  23. package/dist/commands/review.d.ts +2 -0
  24. package/dist/commands/review.d.ts.map +1 -0
  25. package/dist/commands/review.js +44 -0
  26. package/dist/commands/review.js.map +1 -0
  27. package/dist/commands/run.d.ts +2 -0
  28. package/dist/commands/run.d.ts.map +1 -0
  29. package/dist/commands/run.js +83 -0
  30. package/dist/commands/run.js.map +1 -0
  31. package/dist/commands/setup.d.ts +2 -0
  32. package/dist/commands/setup.d.ts.map +1 -0
  33. package/dist/commands/setup.js +15 -0
  34. package/dist/commands/setup.js.map +1 -0
  35. package/dist/commands/stats.d.ts +2 -0
  36. package/dist/commands/stats.d.ts.map +1 -0
  37. package/dist/commands/stats.js +52 -0
  38. package/dist/commands/stats.js.map +1 -0
  39. package/dist/commands/train.d.ts +2 -0
  40. package/dist/commands/train.d.ts.map +1 -0
  41. package/dist/commands/train.js +63 -0
  42. package/dist/commands/train.js.map +1 -0
  43. package/dist/core/classifier.d.ts +18 -0
  44. package/dist/core/classifier.d.ts.map +1 -0
  45. package/dist/core/classifier.js +220 -0
  46. package/dist/core/classifier.js.map +1 -0
  47. package/dist/core/config.d.ts +11 -0
  48. package/dist/core/config.d.ts.map +1 -0
  49. package/dist/core/config.js +15 -0
  50. package/dist/core/config.js.map +1 -0
  51. package/dist/core/data.d.ts +23 -0
  52. package/dist/core/data.d.ts.map +1 -0
  53. package/dist/core/data.js +66 -0
  54. package/dist/core/data.js.map +1 -0
  55. package/dist/core/embeddings.d.ts +4 -0
  56. package/dist/core/embeddings.d.ts.map +1 -0
  57. package/dist/core/embeddings.js +80 -0
  58. package/dist/core/embeddings.js.map +1 -0
  59. package/dist/core/model-io.d.ts +11 -0
  60. package/dist/core/model-io.d.ts.map +1 -0
  61. package/dist/core/model-io.js +76 -0
  62. package/dist/core/model-io.js.map +1 -0
  63. package/dist/core/tf.d.ts +4 -0
  64. package/dist/core/tf.d.ts.map +1 -0
  65. package/dist/core/tf.js +21 -0
  66. package/dist/core/tf.js.map +1 -0
  67. package/dist/index.d.ts +3 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +161 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/ui/server.d.ts +3 -0
  72. package/dist/ui/server.d.ts.map +1 -0
  73. package/dist/ui/server.js +107 -0
  74. package/dist/ui/server.js.map +1 -0
  75. package/dist/ui/static/index.html +486 -0
  76. package/dist/ui/static/static/index.html +486 -0
  77. package/dist/utils/display.d.ts +9 -0
  78. package/dist/utils/display.d.ts.map +1 -0
  79. package/dist/utils/display.js +34 -0
  80. package/dist/utils/display.js.map +1 -0
  81. package/dist/utils/fs.d.ts +3 -0
  82. package/dist/utils/fs.d.ts.map +1 -0
  83. package/dist/utils/fs.js +31 -0
  84. package/dist/utils/fs.js.map +1 -0
  85. package/dist/utils/paths.d.ts +13 -0
  86. package/dist/utils/paths.d.ts.map +1 -0
  87. package/dist/utils/paths.js +55 -0
  88. package/dist/utils/paths.js.map +1 -0
  89. package/dist/utils/similarity.d.ts +6 -0
  90. package/dist/utils/similarity.d.ts.map +1 -0
  91. package/dist/utils/similarity.js +23 -0
  92. package/dist/utils/similarity.js.map +1 -0
  93. package/package.json +45 -0
@@ -0,0 +1,486 @@
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>Distill — Review</title>
7
+ <style>
8
+ * { margin: 0; padding: 0; box-sizing: border-box; }
9
+
10
+ body {
11
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
12
+ background: #f5f5f5;
13
+ color: #333;
14
+ min-height: 100vh;
15
+ }
16
+
17
+ .header {
18
+ background: #fff;
19
+ border-bottom: 1px solid #e0e0e0;
20
+ padding: 16px 24px;
21
+ display: flex;
22
+ align-items: center;
23
+ justify-content: space-between;
24
+ flex-wrap: wrap;
25
+ gap: 12px;
26
+ }
27
+
28
+ .header h1 {
29
+ font-size: 20px;
30
+ font-weight: 600;
31
+ color: #111;
32
+ }
33
+
34
+ .header h1 span {
35
+ color: #6366f1;
36
+ }
37
+
38
+ .stats-bar {
39
+ display: flex;
40
+ gap: 20px;
41
+ font-size: 13px;
42
+ color: #666;
43
+ }
44
+
45
+ .stats-bar .stat-value {
46
+ font-weight: 600;
47
+ color: #333;
48
+ }
49
+
50
+ .progress-container {
51
+ background: #fff;
52
+ padding: 12px 24px;
53
+ border-bottom: 1px solid #e0e0e0;
54
+ }
55
+
56
+ .progress-bar {
57
+ width: 100%;
58
+ height: 6px;
59
+ background: #e5e7eb;
60
+ border-radius: 3px;
61
+ overflow: hidden;
62
+ }
63
+
64
+ .progress-fill {
65
+ height: 100%;
66
+ background: #6366f1;
67
+ border-radius: 3px;
68
+ transition: width 0.3s ease;
69
+ }
70
+
71
+ .progress-text {
72
+ font-size: 12px;
73
+ color: #999;
74
+ margin-top: 4px;
75
+ }
76
+
77
+ .main {
78
+ max-width: 1200px;
79
+ margin: 24px auto;
80
+ padding: 0 24px;
81
+ }
82
+
83
+ .panels {
84
+ display: grid;
85
+ grid-template-columns: 1fr 1fr;
86
+ gap: 16px;
87
+ margin-bottom: 20px;
88
+ }
89
+
90
+ @media (max-width: 768px) {
91
+ .panels { grid-template-columns: 1fr; }
92
+ }
93
+
94
+ .panel {
95
+ background: #fff;
96
+ border: 1px solid #e0e0e0;
97
+ border-radius: 8px;
98
+ overflow: hidden;
99
+ }
100
+
101
+ .panel-header {
102
+ padding: 12px 16px;
103
+ background: #fafafa;
104
+ border-bottom: 1px solid #e0e0e0;
105
+ font-size: 13px;
106
+ font-weight: 600;
107
+ text-transform: uppercase;
108
+ letter-spacing: 0.5px;
109
+ color: #888;
110
+ }
111
+
112
+ .panel-body {
113
+ padding: 16px;
114
+ font-size: 14px;
115
+ line-height: 1.6;
116
+ white-space: pre-wrap;
117
+ word-break: break-word;
118
+ min-height: 120px;
119
+ max-height: 400px;
120
+ overflow-y: auto;
121
+ }
122
+
123
+ .actions {
124
+ background: #fff;
125
+ border: 1px solid #e0e0e0;
126
+ border-radius: 8px;
127
+ padding: 20px;
128
+ }
129
+
130
+ .action-buttons {
131
+ display: flex;
132
+ gap: 12px;
133
+ justify-content: center;
134
+ margin-bottom: 16px;
135
+ }
136
+
137
+ .btn {
138
+ padding: 10px 32px;
139
+ border: 2px solid transparent;
140
+ border-radius: 8px;
141
+ font-size: 15px;
142
+ font-weight: 600;
143
+ cursor: pointer;
144
+ transition: all 0.15s ease;
145
+ display: flex;
146
+ align-items: center;
147
+ gap: 8px;
148
+ }
149
+
150
+ .btn:active { transform: scale(0.97); }
151
+
152
+ .btn-approve {
153
+ background: #ecfdf5;
154
+ color: #059669;
155
+ border-color: #a7f3d0;
156
+ }
157
+ .btn-approve:hover { background: #d1fae5; }
158
+ .btn-approve.active { background: #059669; color: #fff; }
159
+
160
+ .btn-reject {
161
+ background: #fef2f2;
162
+ color: #dc2626;
163
+ border-color: #fecaca;
164
+ }
165
+ .btn-reject:hover { background: #fee2e2; }
166
+ .btn-reject.active { background: #dc2626; color: #fff; }
167
+
168
+ .correction-area {
169
+ margin-top: 12px;
170
+ display: none;
171
+ }
172
+
173
+ .correction-area.visible {
174
+ display: block;
175
+ }
176
+
177
+ .correction-area label {
178
+ display: block;
179
+ font-size: 13px;
180
+ font-weight: 500;
181
+ color: #666;
182
+ margin-bottom: 6px;
183
+ }
184
+
185
+ .correction-area textarea {
186
+ width: 100%;
187
+ min-height: 80px;
188
+ padding: 10px 12px;
189
+ border: 1px solid #d1d5db;
190
+ border-radius: 6px;
191
+ font-family: 'SF Mono', Monaco, Consolas, monospace;
192
+ font-size: 13px;
193
+ resize: vertical;
194
+ }
195
+
196
+ .correction-area textarea:focus {
197
+ outline: none;
198
+ border-color: #6366f1;
199
+ box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
200
+ }
201
+
202
+ .nav {
203
+ display: flex;
204
+ justify-content: space-between;
205
+ align-items: center;
206
+ margin-top: 16px;
207
+ }
208
+
209
+ .nav-btn {
210
+ padding: 8px 20px;
211
+ border: 1px solid #d1d5db;
212
+ border-radius: 6px;
213
+ background: #fff;
214
+ font-size: 14px;
215
+ cursor: pointer;
216
+ color: #374151;
217
+ }
218
+ .nav-btn:hover { background: #f9fafb; }
219
+ .nav-btn:disabled { opacity: 0.4; cursor: not-allowed; }
220
+
221
+ .nav-info {
222
+ font-size: 14px;
223
+ color: #666;
224
+ }
225
+
226
+ .done-btn {
227
+ padding: 8px 20px;
228
+ border: 1px solid #6366f1;
229
+ border-radius: 6px;
230
+ background: #6366f1;
231
+ color: #fff;
232
+ font-size: 14px;
233
+ font-weight: 500;
234
+ cursor: pointer;
235
+ }
236
+ .done-btn:hover { background: #4f46e5; }
237
+
238
+ .empty-state {
239
+ text-align: center;
240
+ padding: 60px 20px;
241
+ color: #999;
242
+ }
243
+
244
+ .keyboard-hint {
245
+ text-align: center;
246
+ font-size: 12px;
247
+ color: #aaa;
248
+ margin-top: 10px;
249
+ }
250
+
251
+ kbd {
252
+ padding: 2px 6px;
253
+ background: #f3f4f6;
254
+ border: 1px solid #d1d5db;
255
+ border-radius: 3px;
256
+ font-size: 11px;
257
+ font-family: inherit;
258
+ }
259
+ </style>
260
+ </head>
261
+ <body>
262
+ <div class="header">
263
+ <h1><span>distill</span> — Review</h1>
264
+ <div class="stats-bar" id="stats-bar">
265
+ <div>Reviewed: <span class="stat-value" id="stat-reviewed">0</span></div>
266
+ <div>Approved: <span class="stat-value" id="stat-approved">0</span></div>
267
+ <div>Rejected: <span class="stat-value" id="stat-rejected">0</span></div>
268
+ <div>Approval rate: <span class="stat-value" id="stat-rate">—</span></div>
269
+ </div>
270
+ </div>
271
+
272
+ <div class="progress-container">
273
+ <div class="progress-bar">
274
+ <div class="progress-fill" id="progress-fill" style="width: 0%"></div>
275
+ </div>
276
+ <div class="progress-text" id="progress-text">Loading...</div>
277
+ </div>
278
+
279
+ <div class="main">
280
+ <div id="content">
281
+ <div class="panels">
282
+ <div class="panel">
283
+ <div class="panel-header">Input</div>
284
+ <div class="panel-body" id="input-display"></div>
285
+ </div>
286
+ <div class="panel">
287
+ <div class="panel-header">Predicted Output</div>
288
+ <div class="panel-body" id="output-display"></div>
289
+ </div>
290
+ </div>
291
+
292
+ <div class="actions">
293
+ <div class="action-buttons">
294
+ <button class="btn btn-approve" id="btn-approve" onclick="score(true)">
295
+ 👍 Approve
296
+ </button>
297
+ <button class="btn btn-reject" id="btn-reject" onclick="score(false)">
298
+ 👎 Reject
299
+ </button>
300
+ </div>
301
+
302
+ <div class="correction-area" id="correction-area">
303
+ <label for="correction">What should the correct output be?</label>
304
+ <textarea id="correction" placeholder="Enter the correct output..."></textarea>
305
+ </div>
306
+
307
+ <div class="nav">
308
+ <button class="nav-btn" id="btn-prev" onclick="navigate(-1)">← Previous</button>
309
+ <span class="nav-info" id="nav-info">— / —</span>
310
+ <button class="nav-btn" id="btn-next" onclick="navigate(1)">Next →</button>
311
+ <button class="done-btn" onclick="finish()">Done</button>
312
+ </div>
313
+
314
+ <div class="keyboard-hint">
315
+ <kbd>→</kbd> Approve &nbsp; <kbd>←</kbd> Reject &nbsp; <kbd>Enter</kbd> Next
316
+ </div>
317
+ </div>
318
+ </div>
319
+
320
+ <div class="empty-state" id="empty-state" style="display:none">
321
+ <h2>All items reviewed!</h2>
322
+ <p>You've reviewed all items. Close this tab or click Done.</p>
323
+ </div>
324
+ </div>
325
+
326
+ <script>
327
+ let items = [];
328
+ let currentIndex = 0;
329
+
330
+ async function init() {
331
+ const res = await fetch('/api/items');
332
+ items = await res.json();
333
+ if (items.length === 0) {
334
+ document.getElementById('content').style.display = 'none';
335
+ document.getElementById('empty-state').style.display = 'block';
336
+ return;
337
+ }
338
+ // Start at first unreviewed item
339
+ const firstUnreviewed = items.findIndex(i => !i.reviewedAt);
340
+ currentIndex = firstUnreviewed >= 0 ? firstUnreviewed : 0;
341
+ render();
342
+ updateStats();
343
+ }
344
+
345
+ function render() {
346
+ const item = items[currentIndex];
347
+ if (!item) return;
348
+
349
+ document.getElementById('input-display').textContent = item.input;
350
+ document.getElementById('output-display').textContent = item.predictedOutput;
351
+ document.getElementById('nav-info').textContent =
352
+ `${currentIndex + 1} / ${items.length}`;
353
+
354
+ document.getElementById('btn-prev').disabled = currentIndex === 0;
355
+ document.getElementById('btn-next').disabled = currentIndex === items.length - 1;
356
+
357
+ // Show current state
358
+ const approveBtn = document.getElementById('btn-approve');
359
+ const rejectBtn = document.getElementById('btn-reject');
360
+ const correctionArea = document.getElementById('correction-area');
361
+
362
+ approveBtn.classList.toggle('active', item.reviewedAt && item.approved === true);
363
+ rejectBtn.classList.toggle('active', item.reviewedAt && item.approved === false);
364
+
365
+ if (item.reviewedAt && item.approved === false) {
366
+ correctionArea.classList.add('visible');
367
+ document.getElementById('correction').value = item.correctedOutput || '';
368
+ } else {
369
+ correctionArea.classList.remove('visible');
370
+ document.getElementById('correction').value = '';
371
+ }
372
+ }
373
+
374
+ async function score(approved) {
375
+ const item = items[currentIndex];
376
+ const correctedOutput = !approved
377
+ ? document.getElementById('correction').value.trim() || undefined
378
+ : undefined;
379
+
380
+ await fetch('/api/score', {
381
+ method: 'POST',
382
+ headers: { 'Content-Type': 'application/json' },
383
+ body: JSON.stringify({
384
+ id: item.id,
385
+ approved,
386
+ correctedOutput,
387
+ }),
388
+ });
389
+
390
+ item.approved = approved;
391
+ item.reviewedAt = new Date().toISOString();
392
+ if (correctedOutput) item.correctedOutput = correctedOutput;
393
+
394
+ // Show/hide correction area
395
+ const correctionArea = document.getElementById('correction-area');
396
+ if (!approved) {
397
+ correctionArea.classList.add('visible');
398
+ document.getElementById('correction').focus();
399
+ } else {
400
+ correctionArea.classList.remove('visible');
401
+ }
402
+
403
+ render();
404
+ updateStats();
405
+
406
+ // Auto-advance on approve
407
+ if (approved && currentIndex < items.length - 1) {
408
+ setTimeout(() => navigate(1), 300);
409
+ }
410
+ }
411
+
412
+ function navigate(delta) {
413
+ const newIndex = currentIndex + delta;
414
+ if (newIndex >= 0 && newIndex < items.length) {
415
+ // Save any pending correction before navigating
416
+ const item = items[currentIndex];
417
+ if (item.reviewedAt && item.approved === false) {
418
+ const correction = document.getElementById('correction').value.trim();
419
+ if (correction && correction !== item.correctedOutput) {
420
+ fetch('/api/score', {
421
+ method: 'POST',
422
+ headers: { 'Content-Type': 'application/json' },
423
+ body: JSON.stringify({
424
+ id: item.id,
425
+ approved: false,
426
+ correctedOutput: correction,
427
+ }),
428
+ });
429
+ item.correctedOutput = correction;
430
+ }
431
+ }
432
+ currentIndex = newIndex;
433
+ render();
434
+ }
435
+ }
436
+
437
+ async function updateStats() {
438
+ const res = await fetch('/api/stats');
439
+ const stats = await res.json();
440
+
441
+ document.getElementById('stat-reviewed').textContent = stats.reviewed;
442
+ document.getElementById('stat-approved').textContent = stats.approved;
443
+ document.getElementById('stat-rejected').textContent = stats.rejected;
444
+ document.getElementById('stat-rate').textContent =
445
+ stats.reviewed > 0 ? stats.approvalRate + '%' : '—';
446
+
447
+ const pct = stats.total > 0 ? (stats.reviewed / stats.total) * 100 : 0;
448
+ document.getElementById('progress-fill').style.width = pct + '%';
449
+ document.getElementById('progress-text').textContent =
450
+ `${stats.reviewed} of ${stats.total} reviewed`;
451
+
452
+ if (stats.remaining === 0 && stats.total > 0) {
453
+ document.getElementById('content').style.display = 'none';
454
+ document.getElementById('empty-state').style.display = 'block';
455
+ }
456
+ }
457
+
458
+ async function finish() {
459
+ if (confirm('End review session?')) {
460
+ await fetch('/api/shutdown', { method: 'POST' });
461
+ document.body.innerHTML =
462
+ '<div style="display:flex;align-items:center;justify-content:center;height:100vh;color:#666;font-family:sans-serif">' +
463
+ '<div style="text-align:center"><h2>Review complete</h2><p>You can close this tab.</p></div></div>';
464
+ }
465
+ }
466
+
467
+ // Keyboard shortcuts
468
+ document.addEventListener('keydown', (e) => {
469
+ if (e.target.tagName === 'TEXTAREA') return;
470
+
471
+ if (e.key === 'ArrowRight') {
472
+ e.preventDefault();
473
+ score(true);
474
+ } else if (e.key === 'ArrowLeft') {
475
+ e.preventDefault();
476
+ score(false);
477
+ } else if (e.key === 'Enter') {
478
+ e.preventDefault();
479
+ navigate(1);
480
+ }
481
+ });
482
+
483
+ init();
484
+ </script>
485
+ </body>
486
+ </html>