konsul-ai 0.2.4

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.
@@ -0,0 +1,13 @@
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>Konsul</title>
7
+ <link rel="stylesheet" href="/style.css">
8
+ </head>
9
+ <body>
10
+ <div class="container" id="app"></div>
11
+ <script type="module" src="/app.js"></script>
12
+ </body>
13
+ </html>
@@ -0,0 +1,554 @@
1
+ :root {
2
+ --bg: #f9fafb;
3
+ --bg-chat: #ffffff;
4
+ --surface: #f3f4f6;
5
+ --surface-hover: #e5e7eb;
6
+ --border: #e5e7eb;
7
+ --border-input: #d1d5db;
8
+ --text: #111827;
9
+ --text-secondary: #6b7280;
10
+ --text-dim: #9ca3af;
11
+ --accent: #111827;
12
+ --accent-text: #ffffff;
13
+ --green: #16a34a;
14
+ --yellow: #ca8a04;
15
+ --red: #dc2626;
16
+ --radius: 12px;
17
+ --radius-lg: 24px;
18
+ --radius-full: 9999px;
19
+ --shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
20
+ --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.07), 0 2px 4px -2px rgba(0,0,0,0.05);
21
+ --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.08), 0 4px 6px -4px rgba(0,0,0,0.04);
22
+ }
23
+
24
+ * { margin: 0; padding: 0; box-sizing: border-box; }
25
+
26
+ html, body {
27
+ height: 100%;
28
+ overflow: hidden;
29
+ }
30
+
31
+ body {
32
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
33
+ background: var(--bg);
34
+ color: var(--text);
35
+ line-height: 1.6;
36
+ }
37
+
38
+ /* ── Layout container ────────────────── */
39
+ .container {
40
+ max-width: 820px;
41
+ margin: 0 auto;
42
+ padding: 0 1.25rem;
43
+ display: flex;
44
+ flex-direction: column;
45
+ height: 100vh;
46
+ height: 100dvh;
47
+ }
48
+
49
+ /* ── Header ──────────────────────────── */
50
+ header {
51
+ display: flex;
52
+ align-items: center;
53
+ gap: 0.75rem;
54
+ padding: 0.75rem 0;
55
+ flex-shrink: 0;
56
+ border-bottom: 1px solid var(--border);
57
+ }
58
+
59
+ .logo {
60
+ display: flex;
61
+ align-items: center;
62
+ gap: 0.5rem;
63
+ }
64
+
65
+ .logo span {
66
+ font-size: 1.15rem;
67
+ font-weight: 700;
68
+ letter-spacing: -0.02em;
69
+ color: var(--text);
70
+ }
71
+
72
+ .logo svg {
73
+ flex-shrink: 0;
74
+ }
75
+
76
+ header .controls {
77
+ display: flex;
78
+ align-items: center;
79
+ gap: 0.5rem;
80
+ margin-left: auto;
81
+ }
82
+
83
+ select, button {
84
+ font-family: inherit;
85
+ font-size: 0.78rem;
86
+ background: var(--surface);
87
+ color: var(--text);
88
+ border: 1px solid var(--border);
89
+ border-radius: 8px;
90
+ padding: 0.35rem 0.7rem;
91
+ cursor: pointer;
92
+ transition: background 0.15s, border-color 0.15s, box-shadow 0.15s;
93
+ }
94
+
95
+ select:hover, button:hover {
96
+ background: var(--surface-hover);
97
+ border-color: var(--border-input);
98
+ }
99
+
100
+ select:focus, button:focus {
101
+ outline: none;
102
+ border-color: var(--text-dim);
103
+ box-shadow: 0 0 0 2px rgba(17,24,39,0.08);
104
+ }
105
+
106
+ button:disabled { opacity: 0.35; cursor: not-allowed; }
107
+
108
+ .toggle {
109
+ display: flex;
110
+ align-items: center;
111
+ gap: 0.3rem;
112
+ font-size: 0.78rem;
113
+ color: var(--text-secondary);
114
+ cursor: pointer;
115
+ user-select: none;
116
+ }
117
+
118
+ .toggle input { accent-color: var(--accent); }
119
+
120
+ /* ── Messages scroll area ────────────── */
121
+ .messages {
122
+ flex: 1 1 0;
123
+ overflow-y: auto;
124
+ min-height: 0;
125
+ padding: 1.5rem 0;
126
+ scroll-behavior: smooth;
127
+ }
128
+
129
+ .messages::-webkit-scrollbar { width: 6px; }
130
+ .messages::-webkit-scrollbar-track { background: transparent; }
131
+ .messages::-webkit-scrollbar-thumb {
132
+ background: var(--border);
133
+ border-radius: 3px;
134
+ }
135
+ .messages::-webkit-scrollbar-thumb:hover { background: var(--text-dim); }
136
+
137
+ /* ── Welcome / empty state ───────────── */
138
+ .welcome {
139
+ display: flex;
140
+ flex-direction: column;
141
+ align-items: center;
142
+ justify-content: center;
143
+ height: 100%;
144
+ gap: 1rem;
145
+ color: var(--text-dim);
146
+ user-select: none;
147
+ }
148
+
149
+ .welcome svg {
150
+ opacity: 0.6;
151
+ }
152
+
153
+ .welcome .welcome-title {
154
+ font-size: 1.5rem;
155
+ font-weight: 700;
156
+ color: var(--text);
157
+ letter-spacing: -0.02em;
158
+ }
159
+
160
+ .welcome .welcome-subtitle {
161
+ font-size: 0.9rem;
162
+ color: var(--text-secondary);
163
+ text-align: center;
164
+ max-width: 340px;
165
+ line-height: 1.5;
166
+ }
167
+
168
+ /* ── Team info (below header) ────────── */
169
+ .team-info {
170
+ font-size: 0.72rem;
171
+ color: var(--text-dim);
172
+ padding: 0.5rem 0 0;
173
+ flex-shrink: 0;
174
+ }
175
+
176
+ /* ── Query input ─────────────────────── */
177
+ .query-box {
178
+ position: relative;
179
+ padding: 0.75rem 0 1rem;
180
+ flex-shrink: 0;
181
+ }
182
+
183
+ .query-box .input-wrapper {
184
+ position: relative;
185
+ background: var(--bg-chat);
186
+ border: 1px solid var(--border-input);
187
+ border-radius: var(--radius-lg);
188
+ box-shadow: var(--shadow-sm);
189
+ transition: border-color 0.15s, box-shadow 0.2s;
190
+ }
191
+
192
+ .query-box .input-wrapper:focus-within {
193
+ border-color: var(--text-dim);
194
+ box-shadow: var(--shadow-md);
195
+ }
196
+
197
+ .query-box textarea {
198
+ width: 100%;
199
+ min-height: 48px;
200
+ max-height: 200px;
201
+ padding: 0.75rem 3.25rem 0.75rem 1.15rem;
202
+ background: transparent;
203
+ color: var(--text);
204
+ border: none;
205
+ border-radius: var(--radius-lg);
206
+ font-family: inherit;
207
+ font-size: 0.92rem;
208
+ line-height: 1.5;
209
+ resize: none;
210
+ }
211
+
212
+ .query-box textarea:focus {
213
+ outline: none;
214
+ }
215
+
216
+ .query-box textarea::placeholder { color: var(--text-dim); }
217
+
218
+ .query-box .send-btn {
219
+ position: absolute;
220
+ right: 0.5rem;
221
+ bottom: 0.5rem;
222
+ width: 32px;
223
+ height: 32px;
224
+ padding: 0;
225
+ display: flex;
226
+ align-items: center;
227
+ justify-content: center;
228
+ background: var(--accent);
229
+ color: var(--accent-text);
230
+ border: none;
231
+ border-radius: 50%;
232
+ font-size: 1rem;
233
+ line-height: 1;
234
+ box-shadow: var(--shadow-sm);
235
+ transition: opacity 0.15s, transform 0.1s;
236
+ }
237
+
238
+ .query-box .send-btn:hover {
239
+ opacity: 0.85;
240
+ background: var(--accent);
241
+ transform: scale(1.05);
242
+ }
243
+
244
+ .query-box .send-btn:disabled {
245
+ background: var(--text-dim);
246
+ opacity: 0.4;
247
+ transform: none;
248
+ }
249
+
250
+ /* ── User query bubble ───────────────── */
251
+ .user-query {
252
+ font-size: 0.9rem;
253
+ color: var(--text);
254
+ font-weight: 500;
255
+ padding: 0.75rem 1rem;
256
+ background: var(--surface);
257
+ border-radius: var(--radius);
258
+ margin-bottom: 1rem;
259
+ max-width: 85%;
260
+ margin-left: auto;
261
+ word-wrap: break-word;
262
+ }
263
+
264
+ /* ── Stage progress ──────────────────── */
265
+ .stages {
266
+ display: flex;
267
+ gap: 0.4rem;
268
+ margin-bottom: 1rem;
269
+ }
270
+
271
+ .stage {
272
+ flex: 1;
273
+ padding: 0.55rem 0.7rem;
274
+ background: var(--surface);
275
+ border: 1.5px solid transparent;
276
+ border-radius: 10px;
277
+ font-size: 0.76rem;
278
+ color: var(--text-dim);
279
+ transition: border-color 0.3s, color 0.3s;
280
+ }
281
+
282
+ .stage.active {
283
+ border-color: var(--accent);
284
+ color: var(--text);
285
+ }
286
+
287
+ .stage.done {
288
+ border-color: var(--green);
289
+ color: var(--green);
290
+ }
291
+
292
+ .stage .title { font-weight: 600; margin-bottom: 0.2rem; }
293
+
294
+ .stage .models {
295
+ font-size: 0.68rem;
296
+ line-height: 1.5;
297
+ }
298
+
299
+ .stage .models .model-status {
300
+ display: inline-block;
301
+ margin-right: 0.4rem;
302
+ }
303
+
304
+ .model-status .dot {
305
+ display: inline-block;
306
+ width: 6px;
307
+ height: 6px;
308
+ border-radius: 50%;
309
+ background: var(--text-dim);
310
+ margin-right: 3px;
311
+ vertical-align: middle;
312
+ }
313
+
314
+ .model-status .dot.ok { background: var(--green); }
315
+ .model-status .dot.fail { background: var(--red); }
316
+ .model-status .dot.pending { animation: pulse 1.2s ease-in-out infinite; }
317
+
318
+ @keyframes pulse {
319
+ 0%, 100% { opacity: 0.3; }
320
+ 50% { opacity: 1; }
321
+ }
322
+
323
+ /* ── Synthesis output ────────────────── */
324
+ .synthesis {
325
+ background: var(--bg-chat);
326
+ border: 1px solid var(--border);
327
+ border-radius: var(--radius);
328
+ padding: 1.25rem 1.5rem;
329
+ margin-bottom: 1rem;
330
+ font-size: 0.9rem;
331
+ line-height: 1.75;
332
+ word-wrap: break-word;
333
+ min-height: 3rem;
334
+ box-shadow: var(--shadow-sm);
335
+ animation: fadeIn 0.25s ease;
336
+ }
337
+
338
+ /* ── Markdown content styles ─────────── */
339
+ .md-content h1, .md-content h2, .md-content h3,
340
+ .md-content h4, .md-content h5, .md-content h6 {
341
+ color: var(--text);
342
+ margin: 1.25em 0 0.5em;
343
+ line-height: 1.3;
344
+ }
345
+
346
+ .md-content h1 { font-size: 1.3em; }
347
+ .md-content h2 { font-size: 1.12em; }
348
+ .md-content h3 { font-size: 1em; }
349
+ .md-content h1:first-child, .md-content h2:first-child,
350
+ .md-content h3:first-child { margin-top: 0; }
351
+
352
+ .md-content p { margin: 0.6em 0; }
353
+ .md-content p:first-child { margin-top: 0; }
354
+ .md-content p:last-child { margin-bottom: 0; }
355
+
356
+ .md-content strong { color: var(--text); font-weight: 600; }
357
+
358
+ .md-content ul, .md-content ol {
359
+ padding-left: 1.5em;
360
+ margin: 0.5em 0;
361
+ }
362
+
363
+ .md-content li { margin: 0.25em 0; }
364
+ .md-content li::marker { color: var(--text-secondary); }
365
+
366
+ .md-content code {
367
+ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
368
+ background: var(--surface);
369
+ padding: 0.15em 0.4em;
370
+ border-radius: 5px;
371
+ font-size: 0.86em;
372
+ }
373
+
374
+ .md-content pre {
375
+ background: #1e1e1e;
376
+ color: #d4d4d4;
377
+ border-radius: 10px;
378
+ padding: 0.85rem 1.1rem;
379
+ margin: 0.75em 0;
380
+ overflow-x: auto;
381
+ }
382
+
383
+ .md-content pre code {
384
+ background: none;
385
+ padding: 0;
386
+ border-radius: 0;
387
+ font-size: 0.84em;
388
+ line-height: 1.55;
389
+ color: inherit;
390
+ }
391
+
392
+ .md-content table {
393
+ border-collapse: collapse;
394
+ width: 100%;
395
+ margin: 0.75em 0;
396
+ font-size: 0.86em;
397
+ }
398
+
399
+ .md-content th, .md-content td {
400
+ border: 1px solid var(--border);
401
+ padding: 0.45rem 0.7rem;
402
+ text-align: left;
403
+ }
404
+
405
+ .md-content th {
406
+ background: var(--surface);
407
+ font-weight: 600;
408
+ color: var(--text);
409
+ }
410
+
411
+ .md-content blockquote {
412
+ border-left: 3px solid var(--border);
413
+ padding-left: 0.85rem;
414
+ margin: 0.5em 0;
415
+ color: var(--text-secondary);
416
+ }
417
+
418
+ .md-content hr {
419
+ border: none;
420
+ border-top: 1px solid var(--border);
421
+ margin: 1em 0;
422
+ }
423
+
424
+ .md-content a {
425
+ color: #2563eb;
426
+ text-decoration: underline;
427
+ text-underline-offset: 2px;
428
+ }
429
+
430
+ .md-content a:hover { color: #1d4ed8; }
431
+
432
+ .synthesis .cursor {
433
+ display: inline-block;
434
+ width: 2px;
435
+ height: 1em;
436
+ background: var(--accent);
437
+ margin-left: 1px;
438
+ vertical-align: text-bottom;
439
+ animation: blink 0.8s step-end infinite;
440
+ }
441
+
442
+ @keyframes blink {
443
+ 0%, 100% { opacity: 1; }
444
+ 50% { opacity: 0; }
445
+ }
446
+
447
+ @keyframes fadeIn {
448
+ from { opacity: 0; transform: translateY(6px); }
449
+ to { opacity: 1; transform: translateY(0); }
450
+ }
451
+
452
+ /* ── Results footer ──────────────────── */
453
+ .result-meta {
454
+ display: flex;
455
+ flex-wrap: wrap;
456
+ gap: 0.75rem;
457
+ font-size: 0.75rem;
458
+ color: var(--text-secondary);
459
+ margin-bottom: 1.5rem;
460
+ padding: 0.25rem 0;
461
+ }
462
+
463
+ .result-meta .rankings { flex: 1; }
464
+
465
+ .result-meta .rank-item {
466
+ display: inline-block;
467
+ margin-right: 0.75rem;
468
+ }
469
+
470
+ .result-meta .rank-num {
471
+ color: var(--text);
472
+ font-weight: 600;
473
+ }
474
+
475
+ /* ── Opinions drawer ─────────────────── */
476
+ .opinions-toggle {
477
+ font-size: 0.78rem;
478
+ color: var(--text-secondary);
479
+ background: none;
480
+ border: none;
481
+ cursor: pointer;
482
+ padding: 0;
483
+ margin-bottom: 0.75rem;
484
+ text-decoration: underline;
485
+ text-underline-offset: 2px;
486
+ }
487
+
488
+ .opinions-toggle:hover { color: var(--text); }
489
+
490
+ .opinion {
491
+ background: var(--bg-chat);
492
+ border: 1px solid var(--border);
493
+ border-radius: var(--radius);
494
+ padding: 1rem 1.25rem;
495
+ margin-bottom: 0.5rem;
496
+ animation: fadeIn 0.2s ease;
497
+ }
498
+
499
+ .opinion .opinion-header {
500
+ font-size: 0.75rem;
501
+ font-weight: 600;
502
+ color: var(--text);
503
+ margin-bottom: 0.5rem;
504
+ text-transform: uppercase;
505
+ letter-spacing: 0.03em;
506
+ }
507
+
508
+ .opinion .opinion-body {
509
+ font-size: 0.84rem;
510
+ line-height: 1.65;
511
+ word-wrap: break-word;
512
+ color: var(--text-secondary);
513
+ }
514
+
515
+ /* ── Conversation history ────────────── */
516
+ .history-entry {
517
+ margin-bottom: 2rem;
518
+ }
519
+
520
+ .history-entry .user-query {
521
+ margin-bottom: 0.75rem;
522
+ }
523
+
524
+ /* ── Error ────────────────────────────── */
525
+ .error-msg {
526
+ background: #fef2f2;
527
+ border: 1px solid #fecaca;
528
+ border-radius: var(--radius);
529
+ padding: 0.75rem 1rem;
530
+ color: var(--red);
531
+ font-size: 0.84rem;
532
+ margin-bottom: 1rem;
533
+ animation: fadeIn 0.2s ease;
534
+ }
535
+
536
+ /* ── Responsive ──────────────────────── */
537
+ @media (max-width: 640px) {
538
+ .container { padding: 0 0.75rem; }
539
+
540
+ header .controls { gap: 0.3rem; }
541
+
542
+ .toggle { font-size: 0.72rem; }
543
+
544
+ select, button {
545
+ font-size: 0.72rem;
546
+ padding: 0.3rem 0.55rem;
547
+ }
548
+
549
+ .stages { flex-direction: column; }
550
+
551
+ .welcome .welcome-title { font-size: 1.2rem; }
552
+
553
+ .user-query { max-width: 95%; }
554
+ }
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "konsul-ai",
3
+ "version": "0.2.4",
4
+ "description": "Multi-LLM council that debates and synthesizes answers",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "files": [
8
+ "dist",
9
+ "README.md"
10
+ ],
11
+ "bin": {
12
+ "konsul": "dist/index.js"
13
+ },
14
+ "scripts": {
15
+ "build": "tsc && node scripts/sync-web-assets.mjs",
16
+ "start": "node dist/index.js",
17
+ "dev": "tsx src/index.ts",
18
+ "test": "npm run build && node --test test/cli.test.mjs && node --test test/council.test.mjs && node --test test/router.test.mjs && node --test test/server.test.mjs && node --test test/web.test.mjs"
19
+ },
20
+ "engines": {
21
+ "node": ">=20"
22
+ },
23
+ "keywords": [
24
+ "llm",
25
+ "ai",
26
+ "multi-model",
27
+ "openrouter",
28
+ "cli",
29
+ "council",
30
+ "debate",
31
+ "consensus",
32
+ "blind-review",
33
+ "model-evaluation",
34
+ "synthesis",
35
+ "ai-agents",
36
+ "typescript"
37
+ ],
38
+ "license": "MIT",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "https://github.com/yigityargili991/konsul.git"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^22.0.0",
45
+ "tsx": "^4.19.0",
46
+ "typescript": "^5.6.0"
47
+ }
48
+ }