opengauge 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 (79) hide show
  1. package/README.md +64 -0
  2. package/bin/opengauge.js +70 -0
  3. package/dist/core/optimizer/checkpoint.d.ts +37 -0
  4. package/dist/core/optimizer/checkpoint.d.ts.map +1 -0
  5. package/dist/core/optimizer/checkpoint.js +81 -0
  6. package/dist/core/optimizer/checkpoint.js.map +1 -0
  7. package/dist/core/optimizer/compressor.d.ts +41 -0
  8. package/dist/core/optimizer/compressor.d.ts.map +1 -0
  9. package/dist/core/optimizer/compressor.js +134 -0
  10. package/dist/core/optimizer/compressor.js.map +1 -0
  11. package/dist/core/optimizer/dedup.d.ts +48 -0
  12. package/dist/core/optimizer/dedup.d.ts.map +1 -0
  13. package/dist/core/optimizer/dedup.js +147 -0
  14. package/dist/core/optimizer/dedup.js.map +1 -0
  15. package/dist/core/providers/adapter.d.ts +48 -0
  16. package/dist/core/providers/adapter.d.ts.map +1 -0
  17. package/dist/core/providers/adapter.js +22 -0
  18. package/dist/core/providers/adapter.js.map +1 -0
  19. package/dist/core/providers/anthropic.d.ts +12 -0
  20. package/dist/core/providers/anthropic.d.ts.map +1 -0
  21. package/dist/core/providers/anthropic.js +155 -0
  22. package/dist/core/providers/anthropic.js.map +1 -0
  23. package/dist/core/providers/gemini.d.ts +13 -0
  24. package/dist/core/providers/gemini.d.ts.map +1 -0
  25. package/dist/core/providers/gemini.js +154 -0
  26. package/dist/core/providers/gemini.js.map +1 -0
  27. package/dist/core/providers/ollama.d.ts +11 -0
  28. package/dist/core/providers/ollama.d.ts.map +1 -0
  29. package/dist/core/providers/ollama.js +119 -0
  30. package/dist/core/providers/ollama.js.map +1 -0
  31. package/dist/core/providers/openai.d.ts +12 -0
  32. package/dist/core/providers/openai.d.ts.map +1 -0
  33. package/dist/core/providers/openai.js +169 -0
  34. package/dist/core/providers/openai.js.map +1 -0
  35. package/dist/core/rag/assembler.d.ts +47 -0
  36. package/dist/core/rag/assembler.d.ts.map +1 -0
  37. package/dist/core/rag/assembler.js +178 -0
  38. package/dist/core/rag/assembler.js.map +1 -0
  39. package/dist/core/rag/embedder.d.ts +16 -0
  40. package/dist/core/rag/embedder.d.ts.map +1 -0
  41. package/dist/core/rag/embedder.js +223 -0
  42. package/dist/core/rag/embedder.js.map +1 -0
  43. package/dist/core/rag/retriever.d.ts +20 -0
  44. package/dist/core/rag/retriever.d.ts.map +1 -0
  45. package/dist/core/rag/retriever.js +71 -0
  46. package/dist/core/rag/retriever.js.map +1 -0
  47. package/dist/db/index.d.ts +5 -0
  48. package/dist/db/index.d.ts.map +1 -0
  49. package/dist/db/index.js +48 -0
  50. package/dist/db/index.js.map +1 -0
  51. package/dist/db/queries.d.ts +72 -0
  52. package/dist/db/queries.d.ts.map +1 -0
  53. package/dist/db/queries.js +169 -0
  54. package/dist/db/queries.js.map +1 -0
  55. package/dist/db/schema.d.ts +3 -0
  56. package/dist/db/schema.d.ts.map +1 -0
  57. package/dist/db/schema.js +71 -0
  58. package/dist/db/schema.js.map +1 -0
  59. package/dist/server/config.d.ts +25 -0
  60. package/dist/server/config.d.ts.map +1 -0
  61. package/dist/server/config.js +69 -0
  62. package/dist/server/config.js.map +1 -0
  63. package/dist/server/index.d.ts +5 -0
  64. package/dist/server/index.d.ts.map +1 -0
  65. package/dist/server/index.js +61 -0
  66. package/dist/server/index.js.map +1 -0
  67. package/dist/server/routes/index.d.ts +6 -0
  68. package/dist/server/routes/index.d.ts.map +1 -0
  69. package/dist/server/routes/index.js +272 -0
  70. package/dist/server/routes/index.js.map +1 -0
  71. package/dist/server/sse.d.ts +21 -0
  72. package/dist/server/sse.d.ts.map +1 -0
  73. package/dist/server/sse.js +40 -0
  74. package/dist/server/sse.js.map +1 -0
  75. package/dist/ui/static/app.js +515 -0
  76. package/dist/ui/static/index.html +13 -0
  77. package/dist/ui/static/styles.css +506 -0
  78. package/dist/ui/static/vendor.js +26 -0
  79. package/package.json +49 -0
@@ -0,0 +1,506 @@
1
+ :root {
2
+ --bg-primary: #0d1117;
3
+ --bg-secondary: #161b22;
4
+ --bg-tertiary: #21262d;
5
+ --bg-hover: #30363d;
6
+ --border: #30363d;
7
+ --text-primary: #e6edf3;
8
+ --text-secondary: #8b949e;
9
+ --text-muted: #6e7681;
10
+ --accent: #58a6ff;
11
+ --accent-hover: #79c0ff;
12
+ --success: #3fb950;
13
+ --warning: #d29922;
14
+ --danger: #f85149;
15
+ --code-bg: #1a1f26;
16
+ --scrollbar: #30363d;
17
+ --sidebar-width: 280px;
18
+ --header-height: 56px;
19
+ }
20
+
21
+ * {
22
+ margin: 0;
23
+ padding: 0;
24
+ box-sizing: border-box;
25
+ }
26
+
27
+ body {
28
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
29
+ background: var(--bg-primary);
30
+ color: var(--text-primary);
31
+ height: 100vh;
32
+ overflow: hidden;
33
+ }
34
+
35
+ #app {
36
+ height: 100vh;
37
+ display: flex;
38
+ }
39
+
40
+ /* Scrollbar */
41
+ ::-webkit-scrollbar { width: 8px; }
42
+ ::-webkit-scrollbar-track { background: transparent; }
43
+ ::-webkit-scrollbar-thumb { background: var(--scrollbar); border-radius: 4px; }
44
+ ::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }
45
+
46
+ /* Layout */
47
+ .layout {
48
+ display: flex;
49
+ width: 100%;
50
+ height: 100vh;
51
+ }
52
+
53
+ /* Sidebar */
54
+ .sidebar {
55
+ width: var(--sidebar-width);
56
+ background: var(--bg-secondary);
57
+ border-right: 1px solid var(--border);
58
+ display: flex;
59
+ flex-direction: column;
60
+ flex-shrink: 0;
61
+ }
62
+
63
+ .sidebar-header {
64
+ padding: 16px;
65
+ border-bottom: 1px solid var(--border);
66
+ display: flex;
67
+ align-items: center;
68
+ justify-content: space-between;
69
+ }
70
+
71
+ .sidebar-header h1 {
72
+ font-size: 18px;
73
+ font-weight: 600;
74
+ color: var(--accent);
75
+ display: flex;
76
+ align-items: center;
77
+ gap: 8px;
78
+ }
79
+
80
+ .sidebar-header h1 span {
81
+ font-size: 20px;
82
+ }
83
+
84
+ .new-chat-btn {
85
+ background: var(--accent);
86
+ color: var(--bg-primary);
87
+ border: none;
88
+ padding: 6px 12px;
89
+ border-radius: 6px;
90
+ cursor: pointer;
91
+ font-size: 13px;
92
+ font-weight: 600;
93
+ transition: background 0.15s;
94
+ }
95
+
96
+ .new-chat-btn:hover {
97
+ background: var(--accent-hover);
98
+ }
99
+
100
+ .conversation-list {
101
+ flex: 1;
102
+ overflow-y: auto;
103
+ padding: 8px;
104
+ }
105
+
106
+ .conversation-item {
107
+ padding: 10px 12px;
108
+ border-radius: 6px;
109
+ cursor: pointer;
110
+ font-size: 13px;
111
+ color: var(--text-secondary);
112
+ display: flex;
113
+ align-items: center;
114
+ justify-content: space-between;
115
+ transition: background 0.15s;
116
+ margin-bottom: 2px;
117
+ }
118
+
119
+ .conversation-item:hover {
120
+ background: var(--bg-hover);
121
+ }
122
+
123
+ .conversation-item.active {
124
+ background: var(--bg-tertiary);
125
+ color: var(--text-primary);
126
+ }
127
+
128
+ .conversation-item .title {
129
+ flex: 1;
130
+ overflow: hidden;
131
+ text-overflow: ellipsis;
132
+ white-space: nowrap;
133
+ }
134
+
135
+ .conversation-item .delete-btn {
136
+ opacity: 0;
137
+ background: none;
138
+ border: none;
139
+ color: var(--danger);
140
+ cursor: pointer;
141
+ font-size: 14px;
142
+ padding: 2px 4px;
143
+ border-radius: 3px;
144
+ transition: opacity 0.15s;
145
+ }
146
+
147
+ .conversation-item:hover .delete-btn {
148
+ opacity: 1;
149
+ }
150
+
151
+ .conversation-item .delete-btn:hover {
152
+ background: rgba(248,81,73,0.15);
153
+ }
154
+
155
+ /* Main Content */
156
+ .main {
157
+ flex: 1;
158
+ display: flex;
159
+ flex-direction: column;
160
+ min-width: 0;
161
+ }
162
+
163
+ /* Header */
164
+ .header {
165
+ height: var(--header-height);
166
+ border-bottom: 1px solid var(--border);
167
+ display: flex;
168
+ align-items: center;
169
+ padding: 0 20px;
170
+ gap: 16px;
171
+ flex-shrink: 0;
172
+ }
173
+
174
+ .header .model-selector {
175
+ display: flex;
176
+ align-items: center;
177
+ gap: 8px;
178
+ }
179
+
180
+ .header select {
181
+ background: var(--bg-tertiary);
182
+ color: var(--text-primary);
183
+ border: 1px solid var(--border);
184
+ border-radius: 6px;
185
+ padding: 6px 10px;
186
+ font-size: 13px;
187
+ cursor: pointer;
188
+ outline: none;
189
+ }
190
+
191
+ .header select:focus {
192
+ border-color: var(--accent);
193
+ }
194
+
195
+ .token-meter {
196
+ margin-left: auto;
197
+ display: flex;
198
+ align-items: center;
199
+ gap: 12px;
200
+ font-size: 12px;
201
+ color: var(--text-secondary);
202
+ }
203
+
204
+ .token-stat {
205
+ display: flex;
206
+ align-items: center;
207
+ gap: 4px;
208
+ }
209
+
210
+ .token-stat .label { color: var(--text-muted); }
211
+ .token-stat .value { font-weight: 600; font-variant-numeric: tabular-nums; }
212
+ .token-stat.saved .value { color: var(--success); }
213
+ .token-stat.sent .value { color: var(--warning); }
214
+
215
+ .health-indicator {
216
+ width: 10px;
217
+ height: 10px;
218
+ border-radius: 50%;
219
+ background: var(--success);
220
+ flex-shrink: 0;
221
+ }
222
+
223
+ .health-indicator.warning { background: var(--warning); }
224
+ .health-indicator.danger { background: var(--danger); }
225
+
226
+ /* Chat Area */
227
+ .chat-area {
228
+ flex: 1;
229
+ overflow-y: auto;
230
+ padding: 20px;
231
+ display: flex;
232
+ flex-direction: column;
233
+ gap: 16px;
234
+ }
235
+
236
+ .message {
237
+ max-width: 800px;
238
+ width: 100%;
239
+ margin: 0 auto;
240
+ }
241
+
242
+ .message .role {
243
+ font-size: 12px;
244
+ font-weight: 600;
245
+ margin-bottom: 4px;
246
+ text-transform: uppercase;
247
+ letter-spacing: 0.5px;
248
+ }
249
+
250
+ .message.user .role { color: var(--accent); }
251
+ .message.assistant .role { color: var(--success); }
252
+
253
+ .message .content {
254
+ font-size: 14px;
255
+ line-height: 1.7;
256
+ color: var(--text-primary);
257
+ white-space: pre-wrap;
258
+ word-wrap: break-word;
259
+ }
260
+
261
+ .message .content code {
262
+ background: var(--code-bg);
263
+ padding: 2px 6px;
264
+ border-radius: 4px;
265
+ font-family: 'SF Mono', 'Fira Code', monospace;
266
+ font-size: 13px;
267
+ }
268
+
269
+ .message .content pre {
270
+ background: var(--code-bg);
271
+ padding: 12px;
272
+ border-radius: 6px;
273
+ overflow-x: auto;
274
+ margin: 8px 0;
275
+ }
276
+
277
+ .message .content pre code {
278
+ background: none;
279
+ padding: 0;
280
+ }
281
+
282
+ .message .meta {
283
+ font-size: 11px;
284
+ color: var(--text-muted);
285
+ margin-top: 4px;
286
+ }
287
+
288
+ /* Empty state */
289
+ .empty-state {
290
+ flex: 1;
291
+ display: flex;
292
+ flex-direction: column;
293
+ align-items: center;
294
+ justify-content: center;
295
+ color: var(--text-muted);
296
+ text-align: center;
297
+ gap: 12px;
298
+ }
299
+
300
+ .empty-state .logo {
301
+ font-size: 48px;
302
+ color: var(--accent);
303
+ opacity: 0.5;
304
+ }
305
+
306
+ .empty-state h2 {
307
+ font-size: 20px;
308
+ color: var(--text-secondary);
309
+ }
310
+
311
+ .empty-state p {
312
+ font-size: 14px;
313
+ max-width: 400px;
314
+ }
315
+
316
+ /* Input Area */
317
+ .input-area {
318
+ border-top: 1px solid var(--border);
319
+ padding: 16px 20px;
320
+ flex-shrink: 0;
321
+ }
322
+
323
+ .input-container {
324
+ max-width: 800px;
325
+ margin: 0 auto;
326
+ display: flex;
327
+ gap: 10px;
328
+ align-items: flex-end;
329
+ }
330
+
331
+ .input-container textarea {
332
+ flex: 1;
333
+ background: var(--bg-secondary);
334
+ color: var(--text-primary);
335
+ border: 1px solid var(--border);
336
+ border-radius: 8px;
337
+ padding: 12px 16px;
338
+ font-size: 14px;
339
+ font-family: inherit;
340
+ resize: none;
341
+ outline: none;
342
+ min-height: 44px;
343
+ max-height: 200px;
344
+ line-height: 1.5;
345
+ transition: border-color 0.15s;
346
+ }
347
+
348
+ .input-container textarea:focus {
349
+ border-color: var(--accent);
350
+ }
351
+
352
+ .input-container textarea::placeholder {
353
+ color: var(--text-muted);
354
+ }
355
+
356
+ .send-btn {
357
+ background: var(--accent);
358
+ color: var(--bg-primary);
359
+ border: none;
360
+ padding: 10px 16px;
361
+ border-radius: 8px;
362
+ cursor: pointer;
363
+ font-size: 14px;
364
+ font-weight: 600;
365
+ transition: background 0.15s;
366
+ white-space: nowrap;
367
+ height: 44px;
368
+ }
369
+
370
+ .send-btn:hover:not(:disabled) {
371
+ background: var(--accent-hover);
372
+ }
373
+
374
+ .send-btn:disabled {
375
+ opacity: 0.5;
376
+ cursor: not-allowed;
377
+ }
378
+
379
+ /* Setup Wizard */
380
+ .wizard-overlay {
381
+ position: fixed;
382
+ inset: 0;
383
+ background: rgba(0,0,0,0.7);
384
+ display: flex;
385
+ align-items: center;
386
+ justify-content: center;
387
+ z-index: 100;
388
+ }
389
+
390
+ .wizard {
391
+ background: var(--bg-secondary);
392
+ border: 1px solid var(--border);
393
+ border-radius: 12px;
394
+ padding: 32px;
395
+ max-width: 500px;
396
+ width: 90%;
397
+ }
398
+
399
+ .wizard h2 {
400
+ margin-bottom: 8px;
401
+ color: var(--accent);
402
+ }
403
+
404
+ .wizard p {
405
+ color: var(--text-secondary);
406
+ font-size: 14px;
407
+ margin-bottom: 20px;
408
+ }
409
+
410
+ .wizard .form-group {
411
+ margin-bottom: 16px;
412
+ }
413
+
414
+ .wizard label {
415
+ display: block;
416
+ font-size: 13px;
417
+ font-weight: 600;
418
+ margin-bottom: 6px;
419
+ color: var(--text-secondary);
420
+ }
421
+
422
+ .wizard input,
423
+ .wizard select {
424
+ width: 100%;
425
+ background: var(--bg-tertiary);
426
+ color: var(--text-primary);
427
+ border: 1px solid var(--border);
428
+ border-radius: 6px;
429
+ padding: 8px 12px;
430
+ font-size: 14px;
431
+ outline: none;
432
+ }
433
+
434
+ .wizard input:focus,
435
+ .wizard select:focus {
436
+ border-color: var(--accent);
437
+ }
438
+
439
+ .wizard .actions {
440
+ display: flex;
441
+ gap: 10px;
442
+ justify-content: flex-end;
443
+ margin-top: 24px;
444
+ }
445
+
446
+ .wizard .btn-primary {
447
+ background: var(--accent);
448
+ color: var(--bg-primary);
449
+ border: none;
450
+ padding: 8px 20px;
451
+ border-radius: 6px;
452
+ cursor: pointer;
453
+ font-weight: 600;
454
+ }
455
+
456
+ .wizard .btn-secondary {
457
+ background: var(--bg-tertiary);
458
+ color: var(--text-primary);
459
+ border: 1px solid var(--border);
460
+ padding: 8px 20px;
461
+ border-radius: 6px;
462
+ cursor: pointer;
463
+ }
464
+
465
+ /* Loading */
466
+ .loading-dots::after {
467
+ content: '';
468
+ animation: dots 1.5s steps(4, end) infinite;
469
+ }
470
+
471
+ @keyframes dots {
472
+ 0%, 20% { content: ''; }
473
+ 40% { content: '.'; }
474
+ 60% { content: '..'; }
475
+ 80%, 100% { content: '...'; }
476
+ }
477
+
478
+ /* Responsive */
479
+ @media (max-width: 768px) {
480
+ .sidebar {
481
+ display: none;
482
+ }
483
+ }
484
+
485
+ /* Settings button in sidebar */
486
+ .sidebar-footer {
487
+ padding: 12px 16px;
488
+ border-top: 1px solid var(--border);
489
+ }
490
+
491
+ .settings-btn {
492
+ width: 100%;
493
+ background: var(--bg-tertiary);
494
+ color: var(--text-secondary);
495
+ border: 1px solid var(--border);
496
+ padding: 8px;
497
+ border-radius: 6px;
498
+ cursor: pointer;
499
+ font-size: 13px;
500
+ transition: background 0.15s, color 0.15s;
501
+ }
502
+
503
+ .settings-btn:hover {
504
+ background: var(--bg-hover);
505
+ color: var(--text-primary);
506
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Vendor — re-exports Preact + HTM from CDN (ESM, no build step)
3
+ *
4
+ * The imports below are resolved at runtime by the browser.
5
+ * esm.sh serves minified ES modules with proper dependency resolution.
6
+ */
7
+
8
+ import { h, render as preactRender } from 'https://esm.sh/preact@10.24.3';
9
+ import { useState, useEffect, useRef, useCallback, useMemo } from 'https://esm.sh/preact@10.24.3/hooks';
10
+ import htm from 'https://esm.sh/htm@3.1.1';
11
+
12
+ const html = htm.bind(h);
13
+
14
+ function render(vnode, container) {
15
+ preactRender(vnode, container);
16
+ }
17
+
18
+ export {
19
+ html,
20
+ render,
21
+ useState,
22
+ useEffect,
23
+ useRef,
24
+ useCallback,
25
+ useMemo,
26
+ };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "opengauge",
3
+ "version": "0.1.0",
4
+ "description": "A local-first, token-efficient LLM chat interface",
5
+ "main": "dist/server/index.js",
6
+ "bin": {
7
+ "opengauge": "bin/opengauge.js"
8
+ },
9
+ "scripts": {
10
+ "build": "rm -rf dist && tsc && mkdir -p dist/ui && cp -r src/ui/static dist/ui/static",
11
+ "prepack": "npm run build",
12
+ "start": "node bin/opengauge.js",
13
+ "dev": "tsc --watch"
14
+ },
15
+ "files": [
16
+ "bin",
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "keywords": [
21
+ "llm",
22
+ "chat",
23
+ "token-optimization",
24
+ "rag",
25
+ "local-first"
26
+ ],
27
+ "license": "MIT",
28
+ "dependencies": {
29
+ "better-sqlite3": "^11.7.0",
30
+ "fastify": "^5.2.0",
31
+ "@fastify/static": "^8.1.0",
32
+ "@fastify/cors": "^10.0.2",
33
+ "onnxruntime-node": "^1.20.0",
34
+ "js-yaml": "^4.1.0",
35
+ "open": "^10.1.0",
36
+ "uuid": "^11.1.0",
37
+ "tiktoken": "^1.0.18"
38
+ },
39
+ "devDependencies": {
40
+ "@types/better-sqlite3": "^7.6.12",
41
+ "@types/js-yaml": "^4.0.9",
42
+ "@types/node": "^22.13.0",
43
+ "@types/uuid": "^10.0.0",
44
+ "typescript": "^5.7.0"
45
+ },
46
+ "engines": {
47
+ "node": ">=18"
48
+ }
49
+ }