pi-mega-compact 0.8.14 → 0.8.15
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 +44 -21
- package/dist/extensions/mega-cache-replay.test.js +4 -2
- package/dist/extensions/mega-compact-s38.test.js +317 -0
- package/dist/extensions/mega-compact.js +14 -0
- package/dist/extensions/mega-compact.test.js +37 -8
- package/dist/extensions/mega-config.js +5 -0
- package/dist/extensions/mega-events/agent-handlers.js +184 -4
- package/dist/extensions/mega-events/context-handler.js +35 -2
- package/dist/extensions/mega-events/error-classifier.js +118 -0
- package/dist/extensions/mega-events.js +1 -0
- package/dist/extensions/mega-runtime/state.js +16 -0
- package/dist/extensions/mega-teamrun.test.js +14 -1
- package/extensions/dashboard-client/src/styles/base.css +2 -1
- package/extensions/mega-cache-replay.test.ts +3 -3
- package/extensions/mega-compact-s38.test.ts +330 -0
- package/extensions/mega-compact.test.ts +41 -13
- package/extensions/mega-compact.ts +14 -0
- package/extensions/mega-config.ts +24 -0
- package/extensions/mega-dashboard.ts +7 -0
- package/extensions/mega-events/agent-handlers.ts +179 -5
- package/extensions/mega-events/context-handler.ts +31 -2
- package/extensions/mega-events/error-classifier.ts +109 -0
- package/extensions/mega-events.ts +1 -0
- package/extensions/mega-runtime/helpers.ts +5 -0
- package/extensions/mega-runtime/state.ts +17 -1
- package/extensions/mega-teamrun.test.ts +13 -1
- package/package.json +4 -1
- package/dist/extensions/dashboard-server/helpers.js +0 -37
- package/dist/extensions/dashboard-server/html/all-repos-tab.js +0 -26
- package/dist/extensions/dashboard-server/html/body-open.js +0 -23
- package/dist/extensions/dashboard-server/html/current-repo-tab.js +0 -130
- package/dist/extensions/dashboard-server/html/head-open.js +0 -16
- package/dist/extensions/dashboard-server/html/high-score-tab.js +0 -25
- package/dist/extensions/dashboard-server/html/repo-detail-modal.js +0 -26
- package/dist/extensions/dashboard-server/html/script.js +0 -259
- package/dist/extensions/dashboard-server/html/styles.js +0 -103
- package/dist/extensions/dashboard-server/html/summary-tab.js +0 -19
- package/dist/extensions/dashboard-server/html-template.js +0 -41
- package/dist/src/store/sqlite/connection.js +0 -35
- package/dist/src/store/sqlite/index-store.js +0 -167
- package/dist/src/store/sqlite/memory.js +0 -54
- package/dist/src/store/sqlite/minhash-lsh.js +0 -47
- package/dist/src/store/sqlite/sessions.js +0 -39
- package/dist/src/store/sqlite/transaction.js +0 -19
- package/dist/src/vectorStore/add.js +0 -260
- package/dist/src/vectorStore/dedup.js +0 -52
- package/dist/src/vectorStore/index.js +0 -10
- package/dist/src/vectorStore/queries.js +0 -83
- package/dist/src/vectorStore/search.js +0 -95
- package/dist/src/vectorStore/session.js +0 -19
- package/dist/src/vectorStore/store.js +0 -105
- package/dist/src/vectorStore/types.js +0 -6
- package/dist/src/vectorStore/utils.js +0 -23
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* "Current repo" tab panel — the per-repo dashboard view.
|
|
3
|
-
*
|
|
4
|
-
* Contains: context-window meter, trigger status, vector-store stats,
|
|
5
|
-
* repo-wide stats, data-safety card, configuration, model & cost savings,
|
|
6
|
-
* crew/agents, a legend, the live event stream, and the in-panel all-repos
|
|
7
|
-
* table (shared rows with the All-repos tab via the index poller).
|
|
8
|
-
*
|
|
9
|
-
* `tierName` is interpolated into the Configuration card.
|
|
10
|
-
*/
|
|
11
|
-
export function currentRepoTab(tierName) {
|
|
12
|
-
return `<!-- Current repo (existing single-repo view) -->
|
|
13
|
-
<div class="tab-panel" id="panel-current">
|
|
14
|
-
<div class="grid">
|
|
15
|
-
<div class="card">
|
|
16
|
-
<h2>Context Window</h2>
|
|
17
|
-
<div class="meter-label" id="ctx-pct">—</div>
|
|
18
|
-
<div class="meter-track"><div class="meter-fill" id="ctx-bar" style="width:0%"></div></div>
|
|
19
|
-
<div class="meter-sub" id="ctx-sub">waiting for data</div>
|
|
20
|
-
</div>
|
|
21
|
-
<div class="card">
|
|
22
|
-
<h2>Trigger Status</h2>
|
|
23
|
-
<div class="status-row"><div class="bullet" id="tr-armed"></div><span>Armed (context ≥ fast gate)</span></div>
|
|
24
|
-
<div class="status-row"><div class="bullet" id="tr-ready"></div><span>Ready (tokens ≥ threshold)</span></div>
|
|
25
|
-
<div class="state-text" id="tr-state">waiting</div>
|
|
26
|
-
</div>
|
|
27
|
-
<div class="card">
|
|
28
|
-
<h2>Vector Store</h2>
|
|
29
|
-
<div class="stat-grid">
|
|
30
|
-
<span class="label" title="A saved summary of a chunk of your conversation that was compacted to free up space.">Checkpoints</span><span class="value" id="st-count">0</span>
|
|
31
|
-
<span class="label" title="How much conversation we are currently holding as compact summaries (the 'memory' this extension keeps). Smaller is better.">Tokens Stored</span><span class="value" id="st-tokens">0</span>
|
|
32
|
-
<span class="label" title="Total size of the original conversation text before it was compacted.">Original Tokens</span><span class="value" id="st-orig">0</span>
|
|
33
|
-
<span class="label" title="How much conversation space we have freed up for you (original size minus the compact summary we kept).">Tokens Saved</span><span class="value" id="st-saved">0</span>
|
|
34
|
-
<span class="label" title="How many times old context was automatically brought back into the conversation because it was relevant to what you were doing.">Injected</span><span class="value" id="st-injected">0</span>
|
|
35
|
-
<span class="label" title="Of the times we recalled old context, how often it was actually on-topic.">Recall Relevance</span><span class="value" id="st-dedup">0%</span>
|
|
36
|
-
<span class="label" title="How often new content matched something we already had, so we skipped storing a duplicate copy. Higher = less wasted space.">Storage Dedup</span><span class="value" id="st-sdedup">0%</span>
|
|
37
|
-
<span class="label" title="How many duplicate chunks we collapsed into one instead of storing separately.">Collapsed</span><span class="value" id="st-collapsed">0</span>
|
|
38
|
-
<span class="label" title="The ID of the most recent saved checkpoint.">Last ID</span><span class="value" id="st-lastid">—</span>
|
|
39
|
-
</div>
|
|
40
|
-
</div>
|
|
41
|
-
<div class="card">
|
|
42
|
-
<h2>Repo (all sessions)</h2>
|
|
43
|
-
<div class="stat-grid">
|
|
44
|
-
<span class="label">Checkpoints</span><span class="value" id="rp-count">0</span>
|
|
45
|
-
<span class="label">Tokens Stored</span><span class="value" id="rp-tokens">0</span>
|
|
46
|
-
<span class="label">Original Tokens</span><span class="value" id="rp-orig">0</span>
|
|
47
|
-
<span class="label">Tokens Saved</span><span class="value" id="rp-saved">0</span>
|
|
48
|
-
<span class="label">Sessions</span><span class="value" id="rp-sessions">0</span>
|
|
49
|
-
<span class="label">Collapsed</span><span class="value" id="rp-collapsed">0</span>
|
|
50
|
-
<span class="label">Storage Dedup</span><span class="value" id="rp-sdedup">0%</span>
|
|
51
|
-
</div>
|
|
52
|
-
</div>
|
|
53
|
-
<div class="card safe">
|
|
54
|
-
<h2>🛡 Data Safety</h2>
|
|
55
|
-
<div class="stat-grid">
|
|
56
|
-
<span class="label">Regions Retained</span><span class="value" id="ig-retained">0</span>
|
|
57
|
-
<span class="label">Compressed-Original</span><span class="value" id="ig-bytes">0 B</span>
|
|
58
|
-
<span class="label">Dedup Duplicates</span><span class="value" id="ig-dupes">0</span>
|
|
59
|
-
<span class="label">Permanently Deleted</span><span class="value ok" id="ig-deleted">0 B</span>
|
|
60
|
-
</div>
|
|
61
|
-
<p class="safe-note">Every compacted region is kept verbatim (compressed). "Drop" = removed from the live window only. We never delete your data.</p>
|
|
62
|
-
</div>
|
|
63
|
-
<div class="card">
|
|
64
|
-
<h2>Configuration</h2>
|
|
65
|
-
<div class="conf-grid">
|
|
66
|
-
<span class="label">Tier</span><span class="value" id="cf-tier">${tierName}</span>
|
|
67
|
-
<span class="label">Threshold</span><span class="value" id="cf-threshold">—</span>
|
|
68
|
-
<span class="label">Fast Gate</span><span class="value" id="cf-gate">—</span>
|
|
69
|
-
<span class="label">Auto</span><span class="value" id="cf-auto">—</span>
|
|
70
|
-
<span class="label">Anchor</span><span class="value" id="cf-anchor">—</span>
|
|
71
|
-
</div>
|
|
72
|
-
</div>
|
|
73
|
-
<div class="card cost">
|
|
74
|
-
<h2>💰 Model & Cost Savings</h2>
|
|
75
|
-
<div class="cost-usd" id="cost-usd">≈ $0.00 saved</div>
|
|
76
|
-
<div class="cost-sub" id="cost-windows">0 context-windows extended</div>
|
|
77
|
-
<div class="stat-grid" style="margin-top:12px">
|
|
78
|
-
<span class="label" title="The model pi is currently using — its pricing drives the cost figure.">Model</span><span class="value" id="md-name">—</span>
|
|
79
|
-
<span class="label" title="The provider serving the model.">Provider</span><span class="value" id="md-provider">—</span>
|
|
80
|
-
<span class="label" title="USD per input token, from the model's pricing.">Input Rate</span><span class="value" id="md-input">—</span>
|
|
81
|
-
<span class="label" title="USD per output token, from the model's pricing.">Output Rate</span><span class="value" id="md-output">—</span>
|
|
82
|
-
</div>
|
|
83
|
-
</div>
|
|
84
|
-
<div class="card">
|
|
85
|
-
<h2>Crew / Agents</h2>
|
|
86
|
-
<div class="stat-grid">
|
|
87
|
-
<span class="label">Active Agents</span><span class="value" id="cr-agents">0</span>
|
|
88
|
-
<span class="label">Current Turn</span><span class="value" id="cr-turn">0</span>
|
|
89
|
-
<span class="label">Status</span><span class="value" id="cr-status">idle</span>
|
|
90
|
-
</div>
|
|
91
|
-
</div>
|
|
92
|
-
<div class="card legend">
|
|
93
|
-
<h2>What these numbers mean</h2>
|
|
94
|
-
<ul class="legend-list">
|
|
95
|
-
<li><b>Tokens saved</b> — conversation space this extension has freed up for you (it compacted old text into short summaries).</li>
|
|
96
|
-
<li><b>Tokens stored</b> — how much "memory" (compact summaries) the extension is currently holding for this repo.</li>
|
|
97
|
-
<li><b>Injected</b> — times old context was automatically pasted back in because it was relevant to your current task.</li>
|
|
98
|
-
<li><b>Recall relevance</b> — of those, how often the recalled context was actually on-topic.</li>
|
|
99
|
-
<li><b>Storage dedup</b> — how often new content matched something already saved, so a duplicate copy was skipped (saves space).</li>
|
|
100
|
-
<li><b>Data safety</b> — every compacted region is kept verbatim (compressed). Nothing is permanently deleted; you can restore any of it.</li>
|
|
101
|
-
</ul>
|
|
102
|
-
<p class="legend-note">Hover any label above for a quick explanation.</p>
|
|
103
|
-
</div>
|
|
104
|
-
</div>
|
|
105
|
-
|
|
106
|
-
<div class="events">
|
|
107
|
-
<h2>Event Stream</h2>
|
|
108
|
-
<div class="events-wrap" id="events"><div class="empty">connecting…</div></div>
|
|
109
|
-
</div>
|
|
110
|
-
|
|
111
|
-
<h2 style="margin-top:24px;font-size:13px;color:#8b949e;text-transform:uppercase;letter-spacing:.5px">All Repositories</h2>
|
|
112
|
-
<table class="repos">
|
|
113
|
-
<thead>
|
|
114
|
-
<tr>
|
|
115
|
-
<th>Repo</th><th>Model</th>
|
|
116
|
-
<th style="text-align:right">Checkpoints</th>
|
|
117
|
-
<th style="text-align:right">Tokens Saved</th>
|
|
118
|
-
<th style="text-align:right">Retained</th>
|
|
119
|
-
<th style="text-align:right">Last Compacted</th>
|
|
120
|
-
</tr>
|
|
121
|
-
</thead>
|
|
122
|
-
<tbody id="cur-rows"><tr><td colspan="6" class="repo-none">loading…</td></tr></tbody>
|
|
123
|
-
</table>
|
|
124
|
-
<div class="updated" id="cur-updated"></div>
|
|
125
|
-
|
|
126
|
-
<div class="updated" id="updated"></div>
|
|
127
|
-
</div><!-- /panel-current -->
|
|
128
|
-
|
|
129
|
-
`;
|
|
130
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Document opening: DOCTYPE, <html>, <head> opening + meta/title.
|
|
3
|
-
*
|
|
4
|
-
* Styles are injected between this fragment and `bodyOpen()` by the
|
|
5
|
-
* `dashboardHtml` composer in `../html-template.ts`.
|
|
6
|
-
*/
|
|
7
|
-
export function headOpen() {
|
|
8
|
-
return `<!DOCTYPE html>
|
|
9
|
-
<html lang="en">
|
|
10
|
-
<head>
|
|
11
|
-
<meta charset="utf-8">
|
|
12
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
13
|
-
<title>mega-compact dashboard</title>
|
|
14
|
-
`;
|
|
15
|
-
// trailing \n preserves the original blank-line separation to <style> in the composer
|
|
16
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* "High Score" tab — FUTURE / PLACEHOLDER.
|
|
3
|
-
*
|
|
4
|
-
* Reserved for the next project milestone: a per-repo + global
|
|
5
|
-
* compaction-savings leaderboard ("high score" — most tokens saved, best
|
|
6
|
-
* recall relevance, longest context-window extension streak, etc.).
|
|
7
|
-
*
|
|
8
|
-
* Ships as a visible-but-inert stub so the tab nav, routing, and styles are
|
|
9
|
-
* in place; the data model + scoring logic land in a follow-up. The composer
|
|
10
|
-
* in `../html-template.ts` includes this panel; `script.ts` wires
|
|
11
|
-
* `highscore` into the tab-switch `panels` map so clicking the tab reveals
|
|
12
|
-
* this placeholder.
|
|
13
|
-
*/
|
|
14
|
-
export function highScoreTab() {
|
|
15
|
-
return `<!-- High Score (FUTURE / placeholder for the next project milestone) -->
|
|
16
|
-
<div class="tab-panel" id="panel-highscore">
|
|
17
|
-
<div class="placeholder">
|
|
18
|
-
<div class="em">🏆</div>
|
|
19
|
-
<h2>High Score</h2>
|
|
20
|
-
<p>A compaction-savings leaderboard is coming in the next project milestone — per-repo and global rankings for tokens saved, recall relevance, and context-window extension streaks. Stay tuned.</p>
|
|
21
|
-
</div>
|
|
22
|
-
</div>
|
|
23
|
-
|
|
24
|
-
`;
|
|
25
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Per-repo detail modal — fixed overlay opened when a repo row is clicked.
|
|
3
|
-
*
|
|
4
|
-
* Position-independent in the DOM; the modal is toggled via the `.open`
|
|
5
|
-
* class by `script.ts`. Sits between the tab panels and the script so it
|
|
6
|
-
* overlays whichever panel is active.
|
|
7
|
-
*/
|
|
8
|
-
export function repoDetailModal() {
|
|
9
|
-
return `<!-- Per-repo detail modal -->
|
|
10
|
-
<div class="repo-detail" id="repo-detail">
|
|
11
|
-
<div class="repo-detail-box">
|
|
12
|
-
<h2><span id="rd-name">Repo</span><button class="repo-close" id="rd-close" title="Close">×</button></h2>
|
|
13
|
-
<div class="repo-path" id="rd-path"></div>
|
|
14
|
-
<div class="stat-grid">
|
|
15
|
-
<span class="label">Model</span><span class="value" id="rd-model">—</span>
|
|
16
|
-
<span class="label">Checkpoints</span><span class="value" id="rd-cp">0</span>
|
|
17
|
-
<span class="label">Tokens Saved</span><span class="value" id="rd-saved">0</span>
|
|
18
|
-
<span class="label">Compressed-Original</span><span class="value" id="rd-bytes">0 B</span>
|
|
19
|
-
<span class="label">Last Compacted</span><span class="value" id="rd-when">—</span>
|
|
20
|
-
<span class="label">Provider</span><span class="value" id="rd-provider">—</span>
|
|
21
|
-
</div>
|
|
22
|
-
</div>
|
|
23
|
-
</div>
|
|
24
|
-
|
|
25
|
-
`;
|
|
26
|
-
}
|
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Client-side script: snapshot polling, SSE event stream, multi-repo index
|
|
3
|
-
* polling, per-repo detail modal, and tab switching.
|
|
4
|
-
*
|
|
5
|
-
* One IIFE — the logic is cross-tab (the index poller writes to both the
|
|
6
|
-
* Current-repo table and the All-repos tab) so it stays cohesive rather than
|
|
7
|
-
* being split per-tab. `</body></html>` closes the document.
|
|
8
|
-
*
|
|
9
|
-
* PREVENT-PI-004: the two `fetch(...)` calls below are the dashboard's
|
|
10
|
-
* browser-side localhost probes and carry inline `// guardrails-allow
|
|
11
|
-
* PREVENT-PI-004: <reason>` annotations (scanner-enforced).
|
|
12
|
-
*/
|
|
13
|
-
export function script() {
|
|
14
|
-
return `<script>
|
|
15
|
-
(function() {
|
|
16
|
-
var evBox = document.getElementById('events');
|
|
17
|
-
var evBuffer = [];
|
|
18
|
-
var MAX_EV = 50;
|
|
19
|
-
var offlineBanner = document.getElementById('offline-banner');
|
|
20
|
-
|
|
21
|
-
function bullet(el, on, na) {
|
|
22
|
-
el.className = 'bullet ' + (na ? 'bullet-na' : on ? 'bullet-on' : 'bullet-off');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function renderSnapshot(d) {
|
|
26
|
-
if (!d || !d.updatedAt) { offlineBanner.style.display = 'block'; return; }
|
|
27
|
-
offlineBanner.style.display = 'none';
|
|
28
|
-
|
|
29
|
-
var pct = d.context.percent || 0;
|
|
30
|
-
document.getElementById('ctx-pct').textContent = pct + '%';
|
|
31
|
-
var bar = document.getElementById('ctx-bar');
|
|
32
|
-
bar.style.width = Math.max(pct, 1) + '%';
|
|
33
|
-
bar.className = 'meter-fill ' + (pct >= 90 ? 'meter-red' : pct >= 70 ? 'meter-yellow' : 'meter-green');
|
|
34
|
-
var tok = d.context.tokens != null ? d.context.tokens.toLocaleString() : '?';
|
|
35
|
-
var win = d.context.contextWindow ? d.context.contextWindow.toLocaleString() : '?';
|
|
36
|
-
document.getElementById('ctx-sub').textContent = tok + ' / ' + win + ' tokens';
|
|
37
|
-
|
|
38
|
-
bullet(document.getElementById('tr-armed'), d.trigger.armed, false);
|
|
39
|
-
bullet(document.getElementById('tr-ready'), d.trigger.ready, !d.trigger.armed);
|
|
40
|
-
var state = d.trigger.ready ? 'THRESHOLD EXCEEDED — compacting next event' :
|
|
41
|
-
d.trigger.armed ? 'past fast gate — monitoring token count' : 'idle — below fast gate';
|
|
42
|
-
document.getElementById('tr-state').textContent = state;
|
|
43
|
-
|
|
44
|
-
document.getElementById('st-count').textContent = d.store.checkpointCount;
|
|
45
|
-
document.getElementById('st-tokens').textContent = d.store.totalTokenEstimate.toLocaleString();
|
|
46
|
-
document.getElementById('st-orig').textContent = (d.store.originalTokens || 0).toLocaleString();
|
|
47
|
-
document.getElementById('st-saved').textContent = (d.store.tokensSaved || 0).toLocaleString();
|
|
48
|
-
document.getElementById('st-injected').textContent = d.store.injectedCount;
|
|
49
|
-
document.getElementById('st-dedup').textContent = Math.round(d.store.dedupHitRate * 100) + '%';
|
|
50
|
-
var sdr = d.store.storageDedupRate || 0;
|
|
51
|
-
document.getElementById('st-sdedup').textContent = (sdr * 100 >= 10 ? Math.round(sdr * 100) : (sdr * 100).toFixed(1)) + '%';
|
|
52
|
-
document.getElementById('st-collapsed').textContent = d.store.dedupCollapsed || 0;
|
|
53
|
-
document.getElementById('st-lastid').textContent = d.session.lastCheckpointId || '—';
|
|
54
|
-
|
|
55
|
-
// Repo-wide (all sessions in this repo's SQLite store).
|
|
56
|
-
var repo = d.repo || { checkpointCount: 0, totalTokenEstimate: 0, originalTokens: 0, tokensSaved: 0, sessionCount: 0, dedupCollapsed: 0, storageDedupRate: 0 };
|
|
57
|
-
document.getElementById('rp-count').textContent = repo.checkpointCount;
|
|
58
|
-
document.getElementById('rp-tokens').textContent = repo.totalTokenEstimate.toLocaleString();
|
|
59
|
-
document.getElementById('rp-orig').textContent = (repo.originalTokens || 0).toLocaleString();
|
|
60
|
-
document.getElementById('rp-saved').textContent = (repo.tokensSaved || 0).toLocaleString();
|
|
61
|
-
document.getElementById('rp-sessions').textContent = repo.sessionCount || 0;
|
|
62
|
-
document.getElementById('rp-collapsed').textContent = repo.dedupCollapsed || 0;
|
|
63
|
-
var rsdr = repo.storageDedupRate || 0;
|
|
64
|
-
document.getElementById('rp-sdedup').textContent = (rsdr * 100 >= 10 ? Math.round(rsdr * 100) : (rsdr * 100).toFixed(1)) + '%';
|
|
65
|
-
|
|
66
|
-
// Data-safety invariant (Phase 0 — trust foundation).
|
|
67
|
-
var ig = d.integrity || { regionsRetained: 0, compressedOriginalBytes: 0, duplicatesCollapsed: 0, bytesPermanentlyDeleted: 0 };
|
|
68
|
-
function fmtBytes(b) {
|
|
69
|
-
b = b || 0;
|
|
70
|
-
if (b >= 1048576) return (b / 1048576).toFixed(1) + ' MiB';
|
|
71
|
-
if (b >= 1024) return (b / 1024).toFixed(1) + ' KiB';
|
|
72
|
-
return b + ' B';
|
|
73
|
-
}
|
|
74
|
-
document.getElementById('ig-retained').textContent = (ig.regionsRetained || 0).toLocaleString();
|
|
75
|
-
document.getElementById('ig-bytes').textContent = fmtBytes(ig.compressedOriginalBytes);
|
|
76
|
-
document.getElementById('ig-dupes').textContent = (ig.duplicatesCollapsed || 0).toLocaleString();
|
|
77
|
-
document.getElementById('ig-deleted').textContent = fmtBytes(ig.bytesPermanentlyDeleted);
|
|
78
|
-
|
|
79
|
-
// Crew / agents (live sub-agent activity + turn).
|
|
80
|
-
var crew = d.crew || { activeAgents: 0, currentTurn: 0 };
|
|
81
|
-
document.getElementById('cr-agents').textContent = crew.activeAgents || 0;
|
|
82
|
-
document.getElementById('cr-turn').textContent = crew.currentTurn || 0;
|
|
83
|
-
document.getElementById('cr-status').textContent = (crew.activeAgents > 0)
|
|
84
|
-
? ('▶ ' + crew.activeAgents + ' running') : 'idle';
|
|
85
|
-
|
|
86
|
-
document.getElementById('cf-tier').textContent = d.tier;
|
|
87
|
-
document.getElementById('cf-threshold').textContent = d.config.thresholdTokens.toLocaleString();
|
|
88
|
-
document.getElementById('cf-gate').textContent = d.config.fastGatePct + '%';
|
|
89
|
-
document.getElementById('cf-auto').textContent = d.config.auto ? 'enabled' : 'disabled';
|
|
90
|
-
document.getElementById('cf-anchor').textContent = d.config.anchorUserMessages;
|
|
91
|
-
|
|
92
|
-
// --- Active model + cost savings (same calc as /mega-status) ---------------
|
|
93
|
-
var model = d.model;
|
|
94
|
-
document.getElementById('hdr-model').textContent = model && model.name ? model.name : '—';
|
|
95
|
-
document.getElementById('md-name').textContent = model && model.name ? model.name : '—';
|
|
96
|
-
document.getElementById('md-provider').textContent = model && model.providerName ? model.providerName : (model && model.provider ? model.provider : '—');
|
|
97
|
-
document.getElementById('md-input').textContent = model && model.inputRate ? '$' + (model.inputRate).toFixed(6) : '—';
|
|
98
|
-
document.getElementById('md-output').textContent = model && model.outputRate ? '$' + (model.outputRate).toFixed(6) : '—';
|
|
99
|
-
if (model && model.inputRate && repo.tokensSaved > 0) {
|
|
100
|
-
var usd = (repo.tokensSaved * model.inputRate);
|
|
101
|
-
var win = d.context.contextWindow || 0;
|
|
102
|
-
var windows = win > 0 ? (repo.tokensSaved / win).toFixed(1) : '0';
|
|
103
|
-
document.getElementById('cost-usd').textContent = '≈ $' + usd.toFixed(4) + ' saved';
|
|
104
|
-
document.getElementById('cost-windows').textContent = windows + ' context-windows extended';
|
|
105
|
-
} else {
|
|
106
|
-
document.getElementById('cost-usd').textContent = '≈ $0.00 saved';
|
|
107
|
-
document.getElementById('cost-windows').textContent = '0 context-windows extended';
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
document.getElementById('updated').textContent = 'Updated ' + new Date(d.updatedAt).toLocaleTimeString();
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function sanitize(s) {
|
|
114
|
-
return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function renderEvent(ev) {
|
|
118
|
-
evBuffer.unshift(ev);
|
|
119
|
-
if (evBuffer.length > MAX_EV) evBuffer.length = MAX_EV;
|
|
120
|
-
evBox.innerHTML = evBuffer.map(function(e) {
|
|
121
|
-
var t = e.ts ? new Date(e.ts).toLocaleTimeString() : '';
|
|
122
|
-
var detail = '';
|
|
123
|
-
if (e.data) {
|
|
124
|
-
if (e.data.checkpointId) detail = sanitize(e.data.checkpointId);
|
|
125
|
-
else if (e.data.query) detail = sanitize(e.data.query.slice(0, 80));
|
|
126
|
-
if (e.data.tokenEstimate != null) detail += ' ' + e.data.tokenEstimate + ' tok';
|
|
127
|
-
if (e.data.deduped) detail += ' (deduped)';
|
|
128
|
-
if (e.data.injected != null) detail = 'injected: ' + e.data.injected + (e.data.empty ? ' (empty)' : '');
|
|
129
|
-
}
|
|
130
|
-
return '<div class="ev">' +
|
|
131
|
-
'<span class="ev-time">' + t + '</span>' +
|
|
132
|
-
'<span class="ev-type ev-type-' + sanitize(e.type) + '">' + sanitize(e.type) + '</span>' +
|
|
133
|
-
'<span class="ev-detail">' + detail + '</span></div>';
|
|
134
|
-
}).join('');
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Poll snapshot every 2s
|
|
138
|
-
function pollSnapshot() {
|
|
139
|
-
fetch('/api/snapshot').then(function(r) { return r.json(); }).then(renderSnapshot).catch(function() {}); // guardrails-allow PREVENT-PI-004: dashboard browser-side fetch (localhost)
|
|
140
|
-
}
|
|
141
|
-
pollSnapshot();
|
|
142
|
-
setInterval(pollSnapshot, 2000);
|
|
143
|
-
|
|
144
|
-
// SSE for events
|
|
145
|
-
function connectSSE() {
|
|
146
|
-
var es = new EventSource('/api/events');
|
|
147
|
-
es.onmessage = function(msg) {
|
|
148
|
-
try { renderEvent(JSON.parse(msg.data)); } catch(e) {}
|
|
149
|
-
};
|
|
150
|
-
es.onerror = function() {
|
|
151
|
-
es.close();
|
|
152
|
-
setTimeout(connectSSE, 3000);
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
connectSSE();
|
|
156
|
-
|
|
157
|
-
// --- Multi-repo (index.sqlite via /api/index) ---------------------------
|
|
158
|
-
function fmtBytesTop(b) {
|
|
159
|
-
b = b || 0;
|
|
160
|
-
if (b >= 1048576) return (b / 1048576).toFixed(1) + ' MiB';
|
|
161
|
-
if (b >= 1024) return (b / 1024).toFixed(1) + ' KiB';
|
|
162
|
-
return b + ' B';
|
|
163
|
-
}
|
|
164
|
-
function renderIndex(d) {
|
|
165
|
-
d = d || { updatedAt: null, summary: null, repos: [] };
|
|
166
|
-
var repos = d.repos || [];
|
|
167
|
-
var s = d.summary || { totalRepos: 0, totalCheckpoints: 0, totalTokensSaved: 0, totalCompressedOriginalBytes: 0 };
|
|
168
|
-
document.getElementById('sm-repos').textContent = (s.totalRepos || 0).toLocaleString();
|
|
169
|
-
document.getElementById('sm-checkpoints').textContent = (s.totalCheckpoints || 0).toLocaleString();
|
|
170
|
-
document.getElementById('sm-saved').textContent = (s.totalTokensSaved || 0).toLocaleString();
|
|
171
|
-
document.getElementById('sm-bytes').textContent = fmtBytesTop(s.totalCompressedOriginalBytes);
|
|
172
|
-
|
|
173
|
-
// Shared clickable-row renderer for both the in-current table and the
|
|
174
|
-
// All-repos tab — each row opens the per-repo detail modal.
|
|
175
|
-
function rowsHtml() {
|
|
176
|
-
if (!repos.length) return '<tr><td colspan="6" class="repo-none">No repositories registered yet.</td></tr>';
|
|
177
|
-
return repos.map(function(r) {
|
|
178
|
-
var model = r.modelName
|
|
179
|
-
? '<span class="repo-model">' + sanitize(r.modelName) + '</span>'
|
|
180
|
-
: '<span class="repo-none">—</span>';
|
|
181
|
-
var when = r.lastCompactedAt ? new Date(r.lastCompactedAt).toLocaleString() : '—';
|
|
182
|
-
return '<tr class="repo-link" data-repo="' + sanitize(r.repoRoot) + '">' +
|
|
183
|
-
'<td title="' + sanitize(r.repoRoot) + '">' + sanitize(r.displayName || r.repoRoot) + '</td>' +
|
|
184
|
-
'<td>' + model + '</td>' +
|
|
185
|
-
'<td class="num">' + (r.checkpointCount || 0).toLocaleString() + '</td>' +
|
|
186
|
-
'<td class="num">' + (r.tokensSaved || 0).toLocaleString() + '</td>' +
|
|
187
|
-
'<td class="num">' + fmtBytesTop(r.compressedOriginalBytes) + '</td>' +
|
|
188
|
-
'<td class="num">' + sanitize(when) + '</td>' +
|
|
189
|
-
'</tr>';
|
|
190
|
-
}).join('');
|
|
191
|
-
}
|
|
192
|
-
document.getElementById('cur-rows').innerHTML = rowsHtml();
|
|
193
|
-
document.getElementById('all-rows').innerHTML = rowsHtml();
|
|
194
|
-
bindRepoRows();
|
|
195
|
-
|
|
196
|
-
var stamp = d.updatedAt ? 'Updated ' + new Date(d.updatedAt).toLocaleTimeString() : '';
|
|
197
|
-
document.getElementById('cur-updated').textContent = stamp;
|
|
198
|
-
document.getElementById('all-updated').textContent = stamp;
|
|
199
|
-
document.getElementById('sm-updated').textContent = stamp;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Per-repo detail modal ---------------------------------------------------
|
|
203
|
-
var detailEl = document.getElementById('repo-detail');
|
|
204
|
-
var indexCache = { repos: [] };
|
|
205
|
-
function openRepoDetail(root) {
|
|
206
|
-
var r = null;
|
|
207
|
-
for (var i = 0; i < indexCache.repos.length; i++) {
|
|
208
|
-
if (indexCache.repos[i].repoRoot === root) { r = indexCache.repos[i]; break; }
|
|
209
|
-
}
|
|
210
|
-
if (!r) return;
|
|
211
|
-
document.getElementById('rd-name').textContent = r.displayName || r.repoRoot;
|
|
212
|
-
document.getElementById('rd-path').textContent = r.repoRoot;
|
|
213
|
-
document.getElementById('rd-model').textContent = r.modelName || '—';
|
|
214
|
-
document.getElementById('rd-provider').textContent = r.providerName || (r.provider || '—');
|
|
215
|
-
document.getElementById('rd-cp').textContent = (r.checkpointCount || 0).toLocaleString();
|
|
216
|
-
document.getElementById('rd-saved').textContent = (r.tokensSaved || 0).toLocaleString();
|
|
217
|
-
document.getElementById('rd-bytes').textContent = fmtBytesTop(r.compressedOriginalBytes);
|
|
218
|
-
document.getElementById('rd-when').textContent = r.lastCompactedAt ? new Date(r.lastCompactedAt).toLocaleString() : '—';
|
|
219
|
-
detailEl.classList.add('open');
|
|
220
|
-
}
|
|
221
|
-
document.getElementById('rd-close').addEventListener('click', function() { detailEl.classList.remove('open'); });
|
|
222
|
-
detailEl.addEventListener('click', function(e) { if (e.target === detailEl) detailEl.classList.remove('open'); });
|
|
223
|
-
function bindRepoRows() {
|
|
224
|
-
var rows = document.querySelectorAll('.repo-link');
|
|
225
|
-
for (var i = 0; i < rows.length; i++) {
|
|
226
|
-
rows[i].addEventListener('click', function() { openRepoDetail(this.getAttribute('data-repo')); });
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
function pollIndex() {
|
|
230
|
-
fetch('/api/index').then(function(r) { return r.json(); }).then(function(d) { // guardrails-allow PREVENT-PI-004: dashboard browser-side fetch (localhost)
|
|
231
|
-
indexCache = d && d.repos ? d : indexCache;
|
|
232
|
-
renderIndex(d);
|
|
233
|
-
}).catch(function() {});
|
|
234
|
-
}
|
|
235
|
-
pollIndex();
|
|
236
|
-
setInterval(pollIndex, 5000);
|
|
237
|
-
|
|
238
|
-
// --- Tab switching ------------------------------------------------------
|
|
239
|
-
var tabs = document.querySelectorAll('.tab');
|
|
240
|
-
var panels = { current: 'panel-current', all: 'panel-all', summary: 'panel-summary', highscore: 'panel-highscore' };
|
|
241
|
-
for (var i = 0; i < tabs.length; i++) {
|
|
242
|
-
tabs[i].addEventListener('click', function() {
|
|
243
|
-
var name = this.getAttribute('data-tab');
|
|
244
|
-
for (var j = 0; j < tabs.length; j++) tabs[j].classList.remove('active');
|
|
245
|
-
this.classList.add('active');
|
|
246
|
-
for (var k in panels) {
|
|
247
|
-
if (Object.prototype.hasOwnProperty.call(panels, k)) {
|
|
248
|
-
var el = document.getElementById(panels[k]);
|
|
249
|
-
if (el) el.classList.toggle('active', k === name);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
if (name === 'all' || name === 'summary') pollIndex();
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
})();
|
|
256
|
-
</script>
|
|
257
|
-
</body>
|
|
258
|
-
</html>`;
|
|
259
|
-
}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Inline CSS for the dashboard.
|
|
3
|
-
*
|
|
4
|
-
* Extracted verbatim from the original monolithic `html-template.ts`.
|
|
5
|
-
* Kept as a single cohesive stylesheet — splitting CSS into per-tab files
|
|
6
|
-
* would fragment the design system (shared tokens, e.g. `.card`, `.stat-grid`,
|
|
7
|
-
* `.meter-*` are reused across all tabs).
|
|
8
|
-
*/
|
|
9
|
-
export function styles() {
|
|
10
|
-
return `<style>
|
|
11
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
12
|
-
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; background: #0d1117; color: #c9d1d9; padding: 24px; line-height: 1.5; }
|
|
13
|
-
h1 { font-size: 20px; font-weight: 600; margin-bottom: 20px; display: flex; align-items: center; gap: 10px; color: #f0f6fc; }
|
|
14
|
-
h1 .tier { background: #1f6feb; color: #fff; font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 10px; text-transform: uppercase; letter-spacing: .5px; }
|
|
15
|
-
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 20px; }
|
|
16
|
-
.card { background: #161b22; border: 1px solid #30363d; border-radius: 8px; padding: 16px; }
|
|
17
|
-
.card.safe { border-color: #238636; }
|
|
18
|
-
.card.safe h2 { color: #3fb950; }
|
|
19
|
-
.safe-note { font-size: 12px; color: #8b949e; margin: 12px 0 0; line-height: 1.5; }
|
|
20
|
-
.value.ok { color: #3fb950; }
|
|
21
|
-
.label {
|
|
22
|
-
cursor: help;
|
|
23
|
-
border-bottom: 1px dotted #484f58;
|
|
24
|
-
}
|
|
25
|
-
.card.legend { grid-column: 1 / -1; }
|
|
26
|
-
.legend-list { margin: 0; padding-left: 18px; color: #c9d1d9; }
|
|
27
|
-
.legend-list li { margin-bottom: 8px; line-height: 1.5; }
|
|
28
|
-
.legend-list b { color: #f0f6fc; }
|
|
29
|
-
.legend-note { font-size: 12px; color: #8b949e; margin: 12px 0 0; font-style: italic; }
|
|
30
|
-
.card h2 { font-size: 12px; text-transform: uppercase; letter-spacing: .5px; color: #8b949e; margin-bottom: 12px; font-weight: 600; }
|
|
31
|
-
.meter-track { background: #21262d; border-radius: 4px; height: 20px; overflow: hidden; margin: 8px 0; }
|
|
32
|
-
.meter-fill { height: 100%; border-radius: 4px; transition: width .6s ease; min-width: 2px; }
|
|
33
|
-
.meter-green { background: #238636; }
|
|
34
|
-
.meter-yellow { background: #d29922; }
|
|
35
|
-
.meter-red { background: #f85149; }
|
|
36
|
-
.meter-label { font-size: 24px; font-weight: 700; color: #f0f6fc; }
|
|
37
|
-
.meter-sub { font-size: 12px; color: #8b949e; }
|
|
38
|
-
.status-row { display: flex; align-items: center; gap: 8px; margin: 6px 0; font-size: 14px; }
|
|
39
|
-
.status-row .bullet { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
|
|
40
|
-
.bullet-on { background: #3fb950; box-shadow: 0 0 6px #3fb95088; }
|
|
41
|
-
.bullet-off { background: #484f58; }
|
|
42
|
-
.bullet-na { background: #d29922; }
|
|
43
|
-
.state-text { font-size: 13px; color: #8b949e; margin-top: 8px; font-family: monospace; }
|
|
44
|
-
.stat-grid { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; font-size: 14px; }
|
|
45
|
-
.stat-grid .label { color: #8b949e; }
|
|
46
|
-
.stat-grid .value { color: #f0f6fc; font-weight: 600; font-family: monospace; }
|
|
47
|
-
.conf-grid { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; font-size: 14px; }
|
|
48
|
-
.conf-grid .label { color: #8b949e; }
|
|
49
|
-
.conf-grid .value { color: #f0f6fc; font-family: monospace; }
|
|
50
|
-
.events { background: #161b22; border: 1px solid #30363d; border-radius: 8px; padding: 16px; }
|
|
51
|
-
.events h2 { font-size: 12px; text-transform: uppercase; letter-spacing: .5px; color: #8b949e; margin-bottom: 12px; font-weight: 600; }
|
|
52
|
-
.events-wrap { max-height: 240px; overflow-y: auto; font-family: monospace; font-size: 12px; }
|
|
53
|
-
.ev { padding: 3px 0; border-bottom: 1px solid #21262d; display: flex; gap: 8px; align-items: baseline; }
|
|
54
|
-
.ev:last-child { border-bottom: none; }
|
|
55
|
-
.ev-type { font-weight: 700; min-width: 70px; text-align: right; }
|
|
56
|
-
.ev-type-compact { color: #3fb950; }
|
|
57
|
-
.ev-type-recall { color: #a371f7; }
|
|
58
|
-
.ev-time { color: #484f58; font-size: 10px; min-width: 80px; }
|
|
59
|
-
.ev-detail { color: #8b949e; flex: 1; }
|
|
60
|
-
.updated { font-size: 11px; color: #484f58; margin-top: 16px; text-align: right; }
|
|
61
|
-
.empty { color: #484f58; font-style: italic; font-size: 13px; padding: 8px 0; }
|
|
62
|
-
.offline-banner { background: #f8514922; border: 1px solid #f85149; border-radius: 6px; padding: 10px 16px; margin-bottom: 16px; font-size: 13px; color: #f85149; display: none; }
|
|
63
|
-
.tabs { display: flex; gap: 8px; margin-bottom: 20px; }
|
|
64
|
-
.tab { background: #161b22; color: #8b949e; border: 1px solid #30363d; border-radius: 6px; padding: 8px 16px; font-size: 13px; font-weight: 600; cursor: pointer; transition: all .15s ease; }
|
|
65
|
-
.tab:hover { color: #c9d1d9; border-color: #484f58; }
|
|
66
|
-
.tab.active { background: #1f6feb; color: #fff; border-color: #1f6feb; }
|
|
67
|
-
.tab.future { opacity: .7; }
|
|
68
|
-
.tab .soon { font-size: 9px; font-weight: 700; background: #6e40c9; color: #fff; padding: 1px 6px; border-radius: 8px; margin-left: 6px; text-transform: uppercase; letter-spacing: .5px; }
|
|
69
|
-
.tab-panel { display: none; }
|
|
70
|
-
.tab-panel.active { display: block; }
|
|
71
|
-
.summary-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 16px; margin-bottom: 20px; }
|
|
72
|
-
.summary-card { background: #161b22; border: 1px solid #30363d; border-radius: 8px; padding: 16px; }
|
|
73
|
-
.summary-card .num { font-size: 24px; font-weight: 700; color: #f0f6fc; }
|
|
74
|
-
.summary-card .lbl { font-size: 12px; color: #8b949e; text-transform: uppercase; letter-spacing: .5px; margin-top: 4px; }
|
|
75
|
-
table.repos { width: 100%; border-collapse: collapse; background: #161b22; border: 1px solid #30363d; border-radius: 8px; overflow: hidden; }
|
|
76
|
-
table.repos th, table.repos td { text-align: left; padding: 10px 14px; font-size: 13px; border-bottom: 1px solid #21262d; }
|
|
77
|
-
table.repos th { color: #8b949e; text-transform: uppercase; letter-spacing: .5px; font-size: 11px; background: #0d1117; }
|
|
78
|
-
table.repos td.num { font-family: monospace; color: #f0f6fc; text-align: right; }
|
|
79
|
-
table.repos tr:last-child td { border-bottom: none; }
|
|
80
|
-
table.repos tr:hover td { background: #1c2128; }
|
|
81
|
-
.repo-model { color: #a371f7; }
|
|
82
|
-
.repo-none { color: #484f58; font-style: italic; }
|
|
83
|
-
.updated { font-size: 11px; color: #484f58; margin-top: 16px; text-align: right; }
|
|
84
|
-
.model-pill { background: #6e40c9; color: #fff; font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 10px; text-transform: uppercase; letter-spacing: .5px; }
|
|
85
|
-
.card.cost h2 { color: #a371f7; }
|
|
86
|
-
.cost-usd { font-size: 22px; font-weight: 700; color: #3fb950; }
|
|
87
|
-
.cost-sub { font-size: 12px; color: #8b949e; margin-top: 4px; }
|
|
88
|
-
.repo-link { cursor: pointer; }
|
|
89
|
-
.repo-link:hover td { color: #58a6ff; }
|
|
90
|
-
.repo-detail { position: fixed; inset: 0; background: rgba(0,0,0,.6); display: none; align-items: center; justify-content: center; z-index: 50; }
|
|
91
|
-
.repo-detail.open { display: flex; }
|
|
92
|
-
.repo-detail-box { background: #161b22; border: 1px solid #30363d; border-radius: 10px; padding: 24px; width: 560px; max-width: 92vw; max-height: 86vh; overflow-y: auto; }
|
|
93
|
-
.repo-detail-box h2 { font-size: 14px; color: #f0f6fc; margin-bottom: 14px; display: flex; justify-content: space-between; align-items: center; }
|
|
94
|
-
.repo-close { cursor: pointer; color: #8b949e; font-size: 20px; line-height: 1; border: none; background: none; padding: 0 4px; }
|
|
95
|
-
.repo-close:hover { color: #f0f6fc; }
|
|
96
|
-
.repo-path { font-size: 11px; color: #484f58; word-break: break-all; margin: -8px 0 12px; }
|
|
97
|
-
.placeholder { text-align: center; padding: 48px 16px; color: #8b949e; }
|
|
98
|
-
.placeholder .em { font-size: 40px; margin-bottom: 12px; }
|
|
99
|
-
.placeholder h2 { font-size: 16px; color: #f0f6fc; margin-bottom: 8px; }
|
|
100
|
-
.placeholder p { font-size: 13px; line-height: 1.6; max-width: 420px; margin: 0 auto; }
|
|
101
|
-
</style>
|
|
102
|
-
`;
|
|
103
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* "Summary" tab panel — aggregate counts across all registered repos.
|
|
3
|
-
*
|
|
4
|
-
* Populated by the index poller in `script.ts`.
|
|
5
|
-
*/
|
|
6
|
-
export function summaryTab() {
|
|
7
|
-
return `<!-- Summary (aggregate across all repos) -->
|
|
8
|
-
<div class="tab-panel" id="panel-summary">
|
|
9
|
-
<div class="summary-grid">
|
|
10
|
-
<div class="summary-card"><div class="num" id="sm-repos">0</div><div class="lbl">Repositories</div></div>
|
|
11
|
-
<div class="summary-card"><div class="num" id="sm-checkpoints">0</div><div class="lbl">Total Checkpoints</div></div>
|
|
12
|
-
<div class="summary-card"><div class="num" id="sm-saved">0</div><div class="lbl">Total Tokens Saved</div></div>
|
|
13
|
-
<div class="summary-card"><div class="num" id="sm-bytes">0 B</div><div class="lbl">Compressed-Original</div></div>
|
|
14
|
-
</div>
|
|
15
|
-
<div class="updated" id="sm-updated"></div>
|
|
16
|
-
</div>
|
|
17
|
-
|
|
18
|
-
`;
|
|
19
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HTML template for the dashboard server — composer.
|
|
3
|
-
*
|
|
4
|
-
* Originally a single 518-line monolithic file returning one large HTML page
|
|
5
|
-
* template. Split into per-concern fragments under `./html/` (each tab is its
|
|
6
|
-
* own file; plus shared styles, header chrome, the repo-detail modal, and the
|
|
7
|
-
* client script). This file composes them back into the full document.
|
|
8
|
-
*
|
|
9
|
-
* `tierName` is threaded into the heading badge and the Configuration card.
|
|
10
|
-
*
|
|
11
|
-
* Fragment layout:
|
|
12
|
-
* headOpen() — <!DOCTYPE html>…<title>
|
|
13
|
-
* styles() — <style>…</style> (shared CSS, design-system level)
|
|
14
|
-
* bodyOpen(tier) — </head><body>…<h1>…</nav> (incl. High Score future tab)
|
|
15
|
-
* currentRepoTab(tier) — panel-current (cards + event stream + in-panel table)
|
|
16
|
-
* allReposTab() — panel-all (machine-wide repo table)
|
|
17
|
-
* summaryTab() — panel-summary (aggregate cards)
|
|
18
|
-
* highScoreTab() — panel-highscore (FUTURE placeholder, next milestone)
|
|
19
|
-
* repoDetailModal() — per-repo overlay (position-independent)
|
|
20
|
-
* script() — <script>…</script></body></html>
|
|
21
|
-
*/
|
|
22
|
-
import { headOpen } from "./html/head-open.js";
|
|
23
|
-
import { styles } from "./html/styles.js";
|
|
24
|
-
import { bodyOpen } from "./html/body-open.js";
|
|
25
|
-
import { currentRepoTab } from "./html/current-repo-tab.js";
|
|
26
|
-
import { allReposTab } from "./html/all-repos-tab.js";
|
|
27
|
-
import { summaryTab } from "./html/summary-tab.js";
|
|
28
|
-
import { highScoreTab } from "./html/high-score-tab.js";
|
|
29
|
-
import { repoDetailModal } from "./html/repo-detail-modal.js";
|
|
30
|
-
import { script } from "./html/script.js";
|
|
31
|
-
export function dashboardHtml(tierName) {
|
|
32
|
-
return (headOpen() +
|
|
33
|
-
styles() +
|
|
34
|
-
bodyOpen(tierName) +
|
|
35
|
-
currentRepoTab(tierName) +
|
|
36
|
-
repoDetailModal() +
|
|
37
|
-
allReposTab() +
|
|
38
|
-
summaryTab() +
|
|
39
|
-
highScoreTab() +
|
|
40
|
-
script());
|
|
41
|
-
}
|