@balpal4495/quorum 3.4.0 → 3.6.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.
- package/README.md +111 -1
- package/bin/__tests__/mcp-server.test.js +5 -4
- package/bin/__tests__/mcp-tools.test.js +13 -13
- package/bin/commands/llm.js +108 -0
- package/bin/commands/serve.js +23 -4
- package/bin/mcp/server.js +36 -2
- package/bin/mcp/tools.js +80 -15
- package/bin/quorum.js +8 -0
- package/bin/shared/llm.js +244 -9
- package/bin/ui/app.html +416 -3
- package/dist/oracle/adapters/lance-db.d.ts.map +1 -1
- package/dist/oracle/adapters/lance-db.js +2 -1
- package/dist/oracle/adapters/lance-db.js.map +1 -1
- package/package.json +1 -1
package/bin/ui/app.html
CHANGED
|
@@ -351,6 +351,179 @@
|
|
|
351
351
|
::-webkit-scrollbar { width: 6px; }
|
|
352
352
|
::-webkit-scrollbar-track { background: transparent; }
|
|
353
353
|
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
|
|
354
|
+
|
|
355
|
+
/* ── Growth ── */
|
|
356
|
+
.health-grid {
|
|
357
|
+
display: grid;
|
|
358
|
+
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
359
|
+
gap: 12px;
|
|
360
|
+
margin-bottom: 24px;
|
|
361
|
+
}
|
|
362
|
+
.health-stat {
|
|
363
|
+
background: var(--surface);
|
|
364
|
+
border: 1px solid var(--border);
|
|
365
|
+
border-radius: var(--radius);
|
|
366
|
+
padding: 14px 16px;
|
|
367
|
+
}
|
|
368
|
+
.health-stat-val {
|
|
369
|
+
font-size: 28px;
|
|
370
|
+
font-weight: 700;
|
|
371
|
+
color: var(--text);
|
|
372
|
+
line-height: 1;
|
|
373
|
+
}
|
|
374
|
+
.health-stat-lbl {
|
|
375
|
+
font-size: 11px;
|
|
376
|
+
color: var(--muted);
|
|
377
|
+
margin-top: 4px;
|
|
378
|
+
text-transform: uppercase;
|
|
379
|
+
letter-spacing: .06em;
|
|
380
|
+
}
|
|
381
|
+
.health-score-wrap {
|
|
382
|
+
display: flex;
|
|
383
|
+
align-items: center;
|
|
384
|
+
gap: 16px;
|
|
385
|
+
margin-bottom: 24px;
|
|
386
|
+
background: var(--surface);
|
|
387
|
+
border: 1px solid var(--border);
|
|
388
|
+
border-radius: var(--radius);
|
|
389
|
+
padding: 20px 24px;
|
|
390
|
+
}
|
|
391
|
+
.health-score-num {
|
|
392
|
+
font-size: 52px;
|
|
393
|
+
font-weight: 800;
|
|
394
|
+
line-height: 1;
|
|
395
|
+
}
|
|
396
|
+
.health-score-text { flex: 1; }
|
|
397
|
+
.health-score-label {
|
|
398
|
+
font-size: 13px;
|
|
399
|
+
font-weight: 700;
|
|
400
|
+
text-transform: uppercase;
|
|
401
|
+
letter-spacing: .08em;
|
|
402
|
+
margin-bottom: 4px;
|
|
403
|
+
}
|
|
404
|
+
.health-hint { font-size: 13px; color: var(--muted); }
|
|
405
|
+
.hint-thriving { color: var(--green); }
|
|
406
|
+
.hint-healthy { color: var(--accent); }
|
|
407
|
+
.hint-slow { color: var(--yellow); }
|
|
408
|
+
.hint-stalled { color: var(--red); }
|
|
409
|
+
|
|
410
|
+
/* ── Compass ── */
|
|
411
|
+
.compass-output {
|
|
412
|
+
background: var(--surface);
|
|
413
|
+
border: 1px solid var(--border);
|
|
414
|
+
border-radius: var(--radius);
|
|
415
|
+
padding: 16px;
|
|
416
|
+
font-family: var(--mono);
|
|
417
|
+
font-size: 12px;
|
|
418
|
+
white-space: pre-wrap;
|
|
419
|
+
color: var(--muted);
|
|
420
|
+
max-height: 500px;
|
|
421
|
+
overflow-y: auto;
|
|
422
|
+
line-height: 1.6;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/* ── Edit modal ── */
|
|
426
|
+
.modal-overlay {
|
|
427
|
+
display: none;
|
|
428
|
+
position: fixed;
|
|
429
|
+
inset: 0;
|
|
430
|
+
background: rgba(0,0,0,.65);
|
|
431
|
+
z-index: 200;
|
|
432
|
+
align-items: center;
|
|
433
|
+
justify-content: center;
|
|
434
|
+
}
|
|
435
|
+
.modal-overlay.open { display: flex; }
|
|
436
|
+
.modal {
|
|
437
|
+
background: var(--surface);
|
|
438
|
+
border: 1px solid var(--border);
|
|
439
|
+
border-radius: 10px;
|
|
440
|
+
padding: 24px;
|
|
441
|
+
width: min(560px, 94vw);
|
|
442
|
+
max-height: 90vh;
|
|
443
|
+
overflow-y: auto;
|
|
444
|
+
}
|
|
445
|
+
.modal h3 { font-size: 15px; font-weight: 700; margin-bottom: 16px; }
|
|
446
|
+
.field { margin-bottom: 14px; }
|
|
447
|
+
.field label { display: block; font-size: 12px; color: var(--muted); margin-bottom: 5px; }
|
|
448
|
+
.field input, .field textarea, .field select {
|
|
449
|
+
width: 100%;
|
|
450
|
+
padding: 8px 12px;
|
|
451
|
+
background: var(--bg);
|
|
452
|
+
border: 1px solid var(--border);
|
|
453
|
+
border-radius: var(--radius);
|
|
454
|
+
color: var(--text);
|
|
455
|
+
font: inherit;
|
|
456
|
+
font-size: 13px;
|
|
457
|
+
outline: none;
|
|
458
|
+
transition: border-color .15s;
|
|
459
|
+
resize: vertical;
|
|
460
|
+
}
|
|
461
|
+
.field input:focus, .field textarea:focus, .field select:focus { border-color: var(--accent); }
|
|
462
|
+
.modal-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 20px; }
|
|
463
|
+
|
|
464
|
+
/* ── Evidence/jury breakdown on proposals ── */
|
|
465
|
+
.evidence-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
|
|
466
|
+
.evidence-tag {
|
|
467
|
+
font-family: var(--mono);
|
|
468
|
+
font-size: 10px;
|
|
469
|
+
padding: 2px 6px;
|
|
470
|
+
border-radius: 4px;
|
|
471
|
+
background: rgba(124,110,255,.12);
|
|
472
|
+
color: var(--accent);
|
|
473
|
+
border: 1px solid rgba(124,110,255,.2);
|
|
474
|
+
}
|
|
475
|
+
.breakdown-row {
|
|
476
|
+
display: flex;
|
|
477
|
+
align-items: center;
|
|
478
|
+
gap: 8px;
|
|
479
|
+
font-size: 11px;
|
|
480
|
+
color: var(--muted);
|
|
481
|
+
margin-top: 3px;
|
|
482
|
+
}
|
|
483
|
+
.breakdown-label { width: 128px; flex-shrink: 0; }
|
|
484
|
+
.breakdown-bar {
|
|
485
|
+
flex: 1;
|
|
486
|
+
height: 3px;
|
|
487
|
+
border-radius: 2px;
|
|
488
|
+
background: var(--border);
|
|
489
|
+
overflow: hidden;
|
|
490
|
+
}
|
|
491
|
+
.breakdown-fill { height: 100%; border-radius: 2px; background: var(--accent); }
|
|
492
|
+
.breakdown-pct { width: 28px; text-align: right; color: var(--muted); }
|
|
493
|
+
.jury-section {
|
|
494
|
+
margin-top: 10px;
|
|
495
|
+
padding: 8px 10px;
|
|
496
|
+
background: rgba(124,110,255,.05);
|
|
497
|
+
border: 1px solid rgba(124,110,255,.12);
|
|
498
|
+
border-radius: 6px;
|
|
499
|
+
}
|
|
500
|
+
.jury-section-title {
|
|
501
|
+
font-size: 10px;
|
|
502
|
+
font-weight: 700;
|
|
503
|
+
text-transform: uppercase;
|
|
504
|
+
letter-spacing: .07em;
|
|
505
|
+
color: var(--muted);
|
|
506
|
+
margin-bottom: 6px;
|
|
507
|
+
}
|
|
508
|
+
.council-section {
|
|
509
|
+
margin-top: 8px;
|
|
510
|
+
padding: 8px 10px;
|
|
511
|
+
background: rgba(82,168,224,.05);
|
|
512
|
+
border: 1px solid rgba(82,168,224,.12);
|
|
513
|
+
border-radius: 6px;
|
|
514
|
+
font-size: 12px;
|
|
515
|
+
color: var(--blue);
|
|
516
|
+
}
|
|
517
|
+
.council-section-title {
|
|
518
|
+
font-size: 10px;
|
|
519
|
+
font-weight: 700;
|
|
520
|
+
text-transform: uppercase;
|
|
521
|
+
letter-spacing: .07em;
|
|
522
|
+
color: var(--muted);
|
|
523
|
+
margin-bottom: 6px;
|
|
524
|
+
}
|
|
525
|
+
.council-section ul { margin: 0 0 0 14px; }
|
|
526
|
+
.council-section li { margin-bottom: 2px; color: var(--blue); }
|
|
354
527
|
</style>
|
|
355
528
|
</head>
|
|
356
529
|
<body>
|
|
@@ -361,6 +534,8 @@
|
|
|
361
534
|
<button class="active" onclick="showTab('chronicle')">Chronicle</button>
|
|
362
535
|
<button onclick="showTab('proposals')">Proposals <span class="badge" id="proposalCount" style="display:none"></span></button>
|
|
363
536
|
<button onclick="showTab('coverage')">Coverage</button>
|
|
537
|
+
<button onclick="showTab('growth')">Growth</button>
|
|
538
|
+
<button onclick="showTab('compass')">Compass</button>
|
|
364
539
|
</nav>
|
|
365
540
|
</header>
|
|
366
541
|
|
|
@@ -386,8 +561,63 @@
|
|
|
386
561
|
<p class="section-sub">Source files with Chronicle entries referencing them.</p>
|
|
387
562
|
<div id="coverageView"><div class="loading">Loading…</div></div>
|
|
388
563
|
</div>
|
|
564
|
+
|
|
565
|
+
<!-- ── Growth tab ───────────────────────────────────────────────── -->
|
|
566
|
+
<div id="tab-growth" class="tab">
|
|
567
|
+
<h2 class="section-heading">Growth</h2>
|
|
568
|
+
<p class="section-sub">Chronicle memory health — how actively this codebase is learning.</p>
|
|
569
|
+
<div id="growthView"><div class="loading">Loading…</div></div>
|
|
570
|
+
</div>
|
|
571
|
+
|
|
572
|
+
<!-- ── Compass tab ──────────────────────────────────────────────── -->
|
|
573
|
+
<div id="tab-compass" class="tab">
|
|
574
|
+
<h2 class="section-heading">Compass</h2>
|
|
575
|
+
<p class="section-sub">Product-direction synthesis — behaviours, gaps, and opportunities.</p>
|
|
576
|
+
<div class="toolbar" style="margin-bottom:20px">
|
|
577
|
+
<select id="compassSubcmd" style="max-width:200px;flex:none;padding:8px 12px;background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);color:var(--text);font:inherit;font-size:13px;outline:none">
|
|
578
|
+
<option value="map">Behaviour map</option>
|
|
579
|
+
<option value="brief">Direction brief</option>
|
|
580
|
+
<option value="opportunities">Opportunities</option>
|
|
581
|
+
<option value="bets">Strategic bets</option>
|
|
582
|
+
</select>
|
|
583
|
+
<button class="btn" onclick="loadCompass()" style="flex:none">Run</button>
|
|
584
|
+
</div>
|
|
585
|
+
<div id="compassView"><div class="empty">Select a subcommand and click Run.<small>Requires an LLM provider configured for quorum serve.</small></div></div>
|
|
586
|
+
</div>
|
|
389
587
|
</main>
|
|
390
588
|
|
|
589
|
+
<!-- ── Edit proposal modal ───────────────────────────────────────────── -->
|
|
590
|
+
<div class="modal-overlay" id="editModal" onclick="closeEditModal(event)">
|
|
591
|
+
<div class="modal" onclick="event.stopPropagation()">
|
|
592
|
+
<h3>Edit proposal</h3>
|
|
593
|
+
<input type="hidden" id="editId">
|
|
594
|
+
<div class="field">
|
|
595
|
+
<label>Topic</label>
|
|
596
|
+
<input type="text" id="editTopic">
|
|
597
|
+
</div>
|
|
598
|
+
<div class="field">
|
|
599
|
+
<label>Decision / key insight</label>
|
|
600
|
+
<textarea id="editDecision" rows="5"></textarea>
|
|
601
|
+
</div>
|
|
602
|
+
<div class="field">
|
|
603
|
+
<label>Status</label>
|
|
604
|
+
<select id="editStatus">
|
|
605
|
+
<option value="open">open</option>
|
|
606
|
+
<option value="validated">validated</option>
|
|
607
|
+
<option value="refuted">refuted</option>
|
|
608
|
+
</select>
|
|
609
|
+
</div>
|
|
610
|
+
<div class="field">
|
|
611
|
+
<label>Confidence (0–1)</label>
|
|
612
|
+
<input type="number" id="editConfidence" min="0" max="1" step="0.05">
|
|
613
|
+
</div>
|
|
614
|
+
<div class="modal-actions">
|
|
615
|
+
<button class="btn" onclick="closeEditModal()">Cancel</button>
|
|
616
|
+
<button class="btn btn-approve" onclick="saveEdit()">Save changes</button>
|
|
617
|
+
</div>
|
|
618
|
+
</div>
|
|
619
|
+
</div>
|
|
620
|
+
|
|
391
621
|
<div id="toast"></div>
|
|
392
622
|
|
|
393
623
|
<script>
|
|
@@ -396,6 +626,7 @@
|
|
|
396
626
|
let allEntries = []
|
|
397
627
|
let allProposals = []
|
|
398
628
|
let coverageData = null
|
|
629
|
+
let growthData = null
|
|
399
630
|
let searchTimer = null
|
|
400
631
|
let activeTab = "chronicle"
|
|
401
632
|
|
|
@@ -404,19 +635,22 @@ let activeTab = "chronicle"
|
|
|
404
635
|
window.addEventListener("DOMContentLoaded", () => {
|
|
405
636
|
loadChronicle()
|
|
406
637
|
loadProposals()
|
|
407
|
-
//
|
|
638
|
+
// Other tabs loaded lazily on first open
|
|
408
639
|
})
|
|
409
640
|
|
|
410
641
|
// ── Tab switching ──────────────────────────────────────────────────────────
|
|
411
642
|
|
|
643
|
+
const TAB_NAMES = ["chronicle", "proposals", "coverage", "growth", "compass"]
|
|
644
|
+
|
|
412
645
|
function showTab(name) {
|
|
413
646
|
document.querySelectorAll(".tab").forEach(t => t.classList.remove("active"))
|
|
414
647
|
document.querySelectorAll("nav button").forEach((b, i) => {
|
|
415
|
-
b.classList.toggle("active", [
|
|
648
|
+
b.classList.toggle("active", TAB_NAMES[i] === name)
|
|
416
649
|
})
|
|
417
650
|
document.getElementById(`tab-${name}`).classList.add("active")
|
|
418
651
|
activeTab = name
|
|
419
652
|
if (name === "coverage" && !coverageData) loadCoverage()
|
|
653
|
+
if (name === "growth" && !growthData) loadGrowth()
|
|
420
654
|
}
|
|
421
655
|
|
|
422
656
|
// ── Toast ──────────────────────────────────────────────────────────────────
|
|
@@ -541,10 +775,49 @@ async function loadProposals() {
|
|
|
541
775
|
}
|
|
542
776
|
}
|
|
543
777
|
|
|
778
|
+
function juryBreakdown(jury) {
|
|
779
|
+
if (!jury?.breakdown) return ""
|
|
780
|
+
const dims = [
|
|
781
|
+
["Evidence support", jury.breakdown.evidence_support],
|
|
782
|
+
["Feasibility", jury.breakdown.feasibility],
|
|
783
|
+
["Risk", jury.breakdown.risk],
|
|
784
|
+
["Completeness", jury.breakdown.completeness],
|
|
785
|
+
]
|
|
786
|
+
const rows = dims.filter(([,v]) => v != null).map(([label, v]) => {
|
|
787
|
+
const pct = Math.round(v * 100)
|
|
788
|
+
return `<div class="breakdown-row">
|
|
789
|
+
<span class="breakdown-label">${esc(label)}</span>
|
|
790
|
+
<span class="breakdown-bar"><span class="breakdown-fill" style="width:${pct}%"></span></span>
|
|
791
|
+
<span class="breakdown-pct">${pct}%</span>
|
|
792
|
+
</div>`
|
|
793
|
+
}).join("")
|
|
794
|
+
if (!rows) return ""
|
|
795
|
+
return `<div class="jury-section">
|
|
796
|
+
<div class="jury-section-title">Jury · confidence ${Math.round((jury.confidence ?? 0) * 100)}% · ${esc(jury.recommendation ?? "")}</div>
|
|
797
|
+
${rows}
|
|
798
|
+
</div>`
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
function councilConditions(council) {
|
|
802
|
+
if (!council?.conditions?.length) return ""
|
|
803
|
+
const items = council.conditions.map(c => `<li>${esc(c)}</li>`).join("")
|
|
804
|
+
const sat = council.satisfied ? "✓ satisfied" : "✗ not satisfied"
|
|
805
|
+
return `<div class="council-section">
|
|
806
|
+
<div class="council-section-title">Council · ${esc(sat)} · ${esc(council.recommendation ?? "")}</div>
|
|
807
|
+
<ul>${items}</ul>
|
|
808
|
+
</div>`
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
function evidenceTags(ids) {
|
|
812
|
+
if (!ids?.length) return ""
|
|
813
|
+
const tags = ids.map(id => `<span class="evidence-tag">${esc(String(id).slice(0,8))}</span>`).join("")
|
|
814
|
+
return `<div class="evidence-tags">${tags}</div>`
|
|
815
|
+
}
|
|
816
|
+
|
|
544
817
|
function renderProposals(proposals) {
|
|
545
818
|
const el = document.getElementById("proposalList")
|
|
546
819
|
if (!proposals.length) {
|
|
547
|
-
el.innerHTML = `<div class="empty">No pending proposals<small>AI agents stage proposals via <code>
|
|
820
|
+
el.innerHTML = `<div class="empty">No pending proposals<small>AI agents stage proposals via <code>quorum_stage</code> MCP tool or <code>oracle.propose()</code></small></div>`
|
|
548
821
|
return
|
|
549
822
|
}
|
|
550
823
|
el.innerHTML = proposals.map(p => `
|
|
@@ -555,13 +828,18 @@ function renderProposals(proposals) {
|
|
|
555
828
|
</div>
|
|
556
829
|
<div class="card-body">${esc(p.decision ?? p.key_insight ?? "")}</div>
|
|
557
830
|
${areas(p.affected_areas)}
|
|
831
|
+
${evidenceTags(p.evidence_cited)}
|
|
832
|
+
${juryBreakdown(p.jury)}
|
|
833
|
+
${councilConditions(p.council)}
|
|
558
834
|
<div class="card-meta" style="margin-top:10px">
|
|
559
835
|
<span style="font-family:var(--mono);font-size:11px;color:var(--muted)">${esc(p.proposalId?.slice(0,8))}</span>
|
|
560
836
|
${confidenceBar(p.confidence)}
|
|
837
|
+
${p.source_module ? `<span style="font-size:11px;color:var(--muted)">${esc(p.source_module)}</span>` : ""}
|
|
561
838
|
</div>
|
|
562
839
|
<div class="actions">
|
|
563
840
|
<button class="btn btn-approve" onclick="approveProposal('${esc(p.proposalId)}', this)">✓ Approve</button>
|
|
564
841
|
<button class="btn btn-reject" onclick="rejectProposal('${esc(p.proposalId)}', this)">✕ Reject</button>
|
|
842
|
+
<button class="btn" onclick="openEditModal('${esc(p.proposalId)}')">Edit</button>
|
|
565
843
|
</div>
|
|
566
844
|
</div>
|
|
567
845
|
`).join("")
|
|
@@ -603,6 +881,48 @@ async function rejectProposal(id, btn) {
|
|
|
603
881
|
}
|
|
604
882
|
}
|
|
605
883
|
|
|
884
|
+
// ── Edit modal ────────────────────────────────────────────────────────────
|
|
885
|
+
|
|
886
|
+
function openEditModal(id) {
|
|
887
|
+
const p = allProposals.find(x => x.proposalId === id)
|
|
888
|
+
if (!p) return
|
|
889
|
+
document.getElementById("editId").value = id
|
|
890
|
+
document.getElementById("editTopic").value = p.topic ?? ""
|
|
891
|
+
document.getElementById("editDecision").value = p.decision ?? p.key_insight ?? ""
|
|
892
|
+
document.getElementById("editStatus").value = p.status ?? "open"
|
|
893
|
+
document.getElementById("editConfidence").value = p.confidence ?? 0.7
|
|
894
|
+
document.getElementById("editModal").classList.add("open")
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
function closeEditModal(e) {
|
|
898
|
+
if (e && e.target !== document.getElementById("editModal")) return
|
|
899
|
+
document.getElementById("editModal").classList.remove("open")
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
async function saveEdit() {
|
|
903
|
+
const id = document.getElementById("editId").value
|
|
904
|
+
const topic = document.getElementById("editTopic").value.trim()
|
|
905
|
+
const decision = document.getElementById("editDecision").value.trim()
|
|
906
|
+
const status = document.getElementById("editStatus").value
|
|
907
|
+
const confidence = parseFloat(document.getElementById("editConfidence").value)
|
|
908
|
+
|
|
909
|
+
if (!topic || !decision) { toast("Topic and decision are required", "err"); return }
|
|
910
|
+
|
|
911
|
+
try {
|
|
912
|
+
const res = await fetch(`/api/proposals/${encodeURIComponent(id)}`, {
|
|
913
|
+
method: "PATCH",
|
|
914
|
+
headers: { "content-type": "application/json" },
|
|
915
|
+
body: JSON.stringify({ topic, decision, key_insight: decision, status, confidence }),
|
|
916
|
+
})
|
|
917
|
+
if (!res.ok) throw new Error((await res.json()).error)
|
|
918
|
+
document.getElementById("editModal").classList.remove("open")
|
|
919
|
+
toast("Proposal updated")
|
|
920
|
+
loadProposals()
|
|
921
|
+
} catch (err) {
|
|
922
|
+
toast(err.message, "err")
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
606
926
|
// ── Coverage ──────────────────────────────────────────────────────────────
|
|
607
927
|
|
|
608
928
|
async function loadCoverage() {
|
|
@@ -671,6 +991,99 @@ function renderCoverage(data) {
|
|
|
671
991
|
${totalFiles === 0 ? `<div class="empty">No source files found</div>` : ""}
|
|
672
992
|
`
|
|
673
993
|
}
|
|
994
|
+
|
|
995
|
+
// ── Growth ────────────────────────────────────────────────────────────────
|
|
996
|
+
|
|
997
|
+
async function loadGrowth() {
|
|
998
|
+
document.getElementById("growthView").innerHTML = `<div class="loading">Loading…</div>`
|
|
999
|
+
try {
|
|
1000
|
+
const res = await fetch("/api/growth")
|
|
1001
|
+
growthData = await res.json()
|
|
1002
|
+
renderGrowth(growthData)
|
|
1003
|
+
} catch (err) {
|
|
1004
|
+
document.getElementById("growthView").innerHTML =
|
|
1005
|
+
`<div class="empty">Failed to load growth data<small>${esc(err.message)}</small></div>`
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
function renderGrowth(data) {
|
|
1010
|
+
const { health, entries, proposals, hint } = data
|
|
1011
|
+
const col = health >= 80 ? "var(--green)" : health >= 60 ? "var(--accent)" : health >= 40 ? "var(--yellow)" : "var(--red)"
|
|
1012
|
+
const label = health >= 80 ? "THRIVING" : health >= 60 ? "HEALTHY" : health >= 40 ? "SLOW" : "STALLED"
|
|
1013
|
+
|
|
1014
|
+
document.getElementById("growthView").innerHTML = `
|
|
1015
|
+
<div class="health-score-wrap">
|
|
1016
|
+
<div class="health-score-num" style="color:${col}">${health}</div>
|
|
1017
|
+
<div class="health-score-text">
|
|
1018
|
+
<div class="health-score-label" style="color:${col}">${label}</div>
|
|
1019
|
+
<div class="health-hint">${esc(hint ?? "")}</div>
|
|
1020
|
+
</div>
|
|
1021
|
+
</div>
|
|
1022
|
+
|
|
1023
|
+
<div class="health-grid">
|
|
1024
|
+
<div class="health-stat">
|
|
1025
|
+
<div class="health-stat-val">${entries.total}</div>
|
|
1026
|
+
<div class="health-stat-lbl">Total entries</div>
|
|
1027
|
+
</div>
|
|
1028
|
+
<div class="health-stat">
|
|
1029
|
+
<div class="health-stat-val" style="color:var(--green)">${entries.byStatus.validated ?? 0}</div>
|
|
1030
|
+
<div class="health-stat-lbl">Validated</div>
|
|
1031
|
+
</div>
|
|
1032
|
+
<div class="health-stat">
|
|
1033
|
+
<div class="health-stat-val" style="color:var(--blue)">${entries.byStatus.open ?? 0}</div>
|
|
1034
|
+
<div class="health-stat-lbl">Open</div>
|
|
1035
|
+
</div>
|
|
1036
|
+
<div class="health-stat">
|
|
1037
|
+
<div class="health-stat-val" style="color:var(--red)">${entries.byStatus.refuted ?? 0}</div>
|
|
1038
|
+
<div class="health-stat-lbl">Refuted</div>
|
|
1039
|
+
</div>
|
|
1040
|
+
<div class="health-stat">
|
|
1041
|
+
<div class="health-stat-val" style="color:var(--yellow)">${proposals.pending}</div>
|
|
1042
|
+
<div class="health-stat-lbl">Pending proposals</div>
|
|
1043
|
+
</div>
|
|
1044
|
+
<div class="health-stat">
|
|
1045
|
+
<div class="health-stat-val">${Math.round((entries.avgConfidence ?? 0) * 100)}%</div>
|
|
1046
|
+
<div class="health-stat-lbl">Avg confidence</div>
|
|
1047
|
+
</div>
|
|
1048
|
+
</div>
|
|
1049
|
+
|
|
1050
|
+
${proposals.pending > 0 ? `
|
|
1051
|
+
<div class="card" style="border-color:rgba(224,185,82,.3);background:rgba(224,185,82,.04)">
|
|
1052
|
+
<div class="card-body" style="color:var(--yellow)">
|
|
1053
|
+
${proposals.pending} proposal${proposals.pending === 1 ? "" : "s"} awaiting approval.
|
|
1054
|
+
<a href="#" onclick="showTab('proposals');return false" style="color:var(--accent);text-decoration:none;margin-left:6px">Review →</a>
|
|
1055
|
+
</div>
|
|
1056
|
+
</div>` : ""}
|
|
1057
|
+
`
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
// ── Compass ───────────────────────────────────────────────────────────────
|
|
1061
|
+
|
|
1062
|
+
async function loadCompass() {
|
|
1063
|
+
const subcommand = document.getElementById("compassSubcmd").value
|
|
1064
|
+
document.getElementById("compassView").innerHTML = `<div class="loading">Running compass ${esc(subcommand)}…</div>`
|
|
1065
|
+
try {
|
|
1066
|
+
const res = await fetch(`/api/compass?subcommand=${encodeURIComponent(subcommand)}`)
|
|
1067
|
+
const data = await res.json()
|
|
1068
|
+
renderCompass(data, subcommand)
|
|
1069
|
+
} catch (err) {
|
|
1070
|
+
document.getElementById("compassView").innerHTML =
|
|
1071
|
+
`<div class="empty">Failed to run compass<small>${esc(err.message)}</small></div>`
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
function renderCompass(data, subcommand) {
|
|
1076
|
+
const el = document.getElementById("compassView")
|
|
1077
|
+
if (data.status === "no-llm") {
|
|
1078
|
+
el.innerHTML = `<div class="empty">${esc(data.message)}<small>Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY and restart quorum serve.</small></div>`
|
|
1079
|
+
return
|
|
1080
|
+
}
|
|
1081
|
+
const output = data.output ?? JSON.stringify(data, null, 2)
|
|
1082
|
+
el.innerHTML = `
|
|
1083
|
+
<div style="font-size:12px;color:var(--muted);margin-bottom:10px">compass ${esc(subcommand)}</div>
|
|
1084
|
+
<div class="compass-output">${esc(output)}</div>
|
|
1085
|
+
`
|
|
1086
|
+
}
|
|
674
1087
|
</script>
|
|
675
1088
|
</body>
|
|
676
1089
|
</html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lance-db.d.ts","sourceRoot":"","sources":["../../../modules/oracle/adapters/lance-db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAa9C,wBAAsB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"lance-db.d.ts","sourceRoot":"","sources":["../../../modules/oracle/adapters/lance-db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAa9C,wBAAsB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA0DnF"}
|
|
@@ -64,7 +64,8 @@ export async function createLanceDBStore(chronicleDir) {
|
|
|
64
64
|
const t = await getOrCreateTable();
|
|
65
65
|
if (!t)
|
|
66
66
|
return [];
|
|
67
|
-
|
|
67
|
+
// vectordb v0.4.x has no t.query() — use filter with a tautology to fetch all rows
|
|
68
|
+
const rows = await t.filter("id IS NOT NULL").execute();
|
|
68
69
|
return rows.map(row => JSON.parse(row.payload));
|
|
69
70
|
},
|
|
70
71
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lance-db.js","sourceRoot":"","sources":["../../../modules/oracle/adapters/lance-db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,IAAI,MAAM,MAAM,CAAA;AAWvB,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,YAAoB;IAC3D,4EAA4E;IAC5E,sEAAsE;IACtE,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAA;IAC3C,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,IAAI,UAAU,CAAA;IAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,CAAA;IACnD,+EAA+E;IAC/E,mEAAmE;IACnE,8DAA8D;IAC9D,MAAM,EAAE,GAAQ,MAAM,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC/C,IAAI,KAAK,GAAQ,IAAI,CAAA;IAErB,KAAK,UAAU,gBAAgB,CAAC,QAAmB;QACjD,IAAI,KAAK;YAAE,OAAO,KAAK,CAAA;QACvB,MAAM,KAAK,GAAa,MAAM,EAAE,CAAC,UAAU,EAAE,CAAA;QAC7C,IAAI,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9B,KAAK,GAAG,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAA;QACvC,CAAC;aAAM,IAAI,QAAQ,EAAE,CAAC;YACpB,4EAA4E;YAC5E,wEAAwE;YACxE,+EAA+E;YAC/E,KAAK,GAAG,MAAM,EAAE,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAA;QACrD,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAED,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ;YAC/B,MAAM,GAAG,GAAa,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAA;YACvE,MAAM,CAAC,GAAG,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAAA;YACrC,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC;gBAChB,0DAA0D;gBAC1D,OAAM;YACR,CAAC;YACD,oEAAoE;YACpE,MAAM,CAAC,CAAC,MAAM,CAAC,SAAS,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;YAC1C,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QACpB,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK;YACxB,MAAM,CAAC,GAAG,MAAM,gBAAgB,EAAE,CAAA;YAClC,IAAI,CAAC,CAAC;gBAAE,OAAO,EAAE,CAAA;YACjB,MAAM,IAAI,GAAe,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAA;YACtE,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACtB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAmB;gBAChD,wEAAwE;gBACxE,KAAK,EAAE,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;aAC3D,CAAC,CAAC,CAAA;QACL,CAAC;QAED,KAAK,CAAC,MAAM;YACV,MAAM,CAAC,GAAG,MAAM,gBAAgB,EAAE,CAAA;YAClC,IAAI,CAAC,CAAC;gBAAE,OAAO,EAAE,CAAA;YACjB,MAAM,IAAI,GAAe,MAAM,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"lance-db.js","sourceRoot":"","sources":["../../../modules/oracle/adapters/lance-db.ts"],"names":[],"mappings":"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"}
|