pi-mega-compact 0.8.12 → 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/dist/assets/AchievementTiles-BH26e95w.js +2 -0
- package/extensions/dashboard-client/dist/assets/AchievementTiles-BH26e95w.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/AchievementsTab-B94wvRV_.js +2 -0
- package/extensions/dashboard-client/dist/assets/AchievementsTab-B94wvRV_.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-DPmw3NHR.js +2 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-DPmw3NHR.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/ConfigTab-C3g3smRL.js +2 -0
- package/extensions/dashboard-client/dist/assets/ConfigTab-C3g3smRL.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/EventsTab-B5PicfFw.js +2 -0
- package/extensions/dashboard-client/dist/assets/EventsTab-B5PicfFw.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/GameTab-CsVwp78a.js +2 -0
- package/extensions/dashboard-client/dist/assets/GameTab-CsVwp78a.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/MetricsTab-Cf72UewX.js +2 -0
- package/extensions/dashboard-client/dist/assets/MetricsTab-Cf72UewX.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/OverviewTab-Dh6aG3gy.js +2 -0
- package/extensions/dashboard-client/dist/assets/OverviewTab-Dh6aG3gy.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/ReposTab-HXf2dorl.js +2 -0
- package/extensions/dashboard-client/dist/assets/ReposTab-HXf2dorl.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-kUnoospE.js +2 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-kUnoospE.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/index-Cfxniu2R.css +1 -0
- package/extensions/dashboard-client/dist/assets/{index-XAIN8km6.js → index-DMntLu-8.js} +11 -10
- package/extensions/dashboard-client/dist/assets/index-DMntLu-8.js.map +1 -0
- package/extensions/dashboard-client/dist/index.html +2 -2
- package/extensions/dashboard-client/src/App.tsx +18 -4
- package/extensions/dashboard-client/src/components/AchievementTiles.tsx +105 -0
- package/extensions/dashboard-client/src/components/ActiveReposTable.tsx +116 -0
- package/extensions/dashboard-client/src/components/CacheHitsCard.tsx +73 -0
- package/extensions/dashboard-client/src/components/CacheStatusPerModel.tsx +78 -35
- package/extensions/dashboard-client/src/components/ConfigSummaryCard.tsx +101 -0
- package/extensions/dashboard-client/src/components/ContextGauge.tsx +11 -15
- package/extensions/dashboard-client/src/components/DataSafetyCard.tsx +42 -33
- package/extensions/dashboard-client/src/components/EventCategoryFilter.tsx +46 -9
- package/extensions/dashboard-client/src/components/LegendCard.tsx +49 -0
- package/extensions/dashboard-client/src/components/ModelBadge.tsx +42 -11
- package/extensions/dashboard-client/src/components/PerfCards.tsx +91 -0
- package/extensions/dashboard-client/src/components/RepoAllSessionsCard.tsx +102 -0
- package/extensions/dashboard-client/src/components/RepoDetailModal.tsx +9 -2
- package/extensions/dashboard-client/src/components/RepoTable.tsx +30 -22
- package/extensions/dashboard-client/src/components/SavingsByModelTable.tsx +226 -0
- package/extensions/dashboard-client/src/components/SessionInfo.tsx +25 -50
- package/extensions/dashboard-client/src/components/SummaryTiles.tsx +20 -11
- package/extensions/dashboard-client/src/components/TimeSavedCard.tsx +61 -0
- package/extensions/dashboard-client/src/components/TriggerStatus.tsx +31 -19
- package/extensions/dashboard-client/src/components/VectorStoreCard.tsx +134 -0
- package/extensions/dashboard-client/src/main.tsx +5 -0
- package/extensions/dashboard-client/src/styles/base.css +77 -9
- package/extensions/dashboard-client/src/styles/config.css +149 -0
- package/extensions/dashboard-client/src/styles/game-achievements.css +265 -0
- package/extensions/dashboard-client/src/styles/metrics-extra.css +69 -0
- package/extensions/dashboard-client/src/styles/overview-extra.css +170 -0
- package/extensions/dashboard-client/src/styles/repos-extra.css +99 -0
- package/extensions/dashboard-client/src/styles/repos-metrics.css +14 -23
- package/extensions/dashboard-client/src/tabs/AchievementsTab.tsx +55 -0
- package/extensions/dashboard-client/src/tabs/CacheTab.tsx +50 -0
- package/extensions/dashboard-client/src/tabs/ConfigTab.tsx +240 -5
- package/extensions/dashboard-client/src/tabs/EventsTab.tsx +55 -3
- package/extensions/dashboard-client/src/tabs/GameTab.tsx +287 -0
- package/extensions/dashboard-client/src/tabs/MetricsTab.tsx +7 -1
- package/extensions/dashboard-client/src/tabs/OverviewTab.tsx +103 -17
- package/extensions/dashboard-client/src/tabs/ReposTab.tsx +57 -22
- package/extensions/dashboard-client/src/utils/format.ts +85 -0
- package/extensions/dashboard-client/src/utils/types.ts +27 -0
- 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
- package/extensions/dashboard-client/dist/assets/ConfigTab-RrjXWfvr.js +0 -2
- package/extensions/dashboard-client/dist/assets/ConfigTab-RrjXWfvr.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/EventsTab-BH_FxJ08.js +0 -2
- package/extensions/dashboard-client/dist/assets/EventsTab-BH_FxJ08.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MetricsTab-C-PoFV4p.js +0 -2
- package/extensions/dashboard-client/dist/assets/MetricsTab-C-PoFV4p.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/OverviewTab-Db-qBqFN.js +0 -2
- package/extensions/dashboard-client/dist/assets/OverviewTab-Db-qBqFN.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/ReposTab-DhCjJvuj.js +0 -2
- package/extensions/dashboard-client/dist/assets/ReposTab-DhCjJvuj.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-Buer5yxB.css +0 -1
- package/extensions/dashboard-client/dist/assets/index-XAIN8km6.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ReposTab-DhCjJvuj.js","sources":["../../src/components/SummaryTiles.tsx","../../src/components/RepoTable.tsx","../../src/components/RepoDetailModal.tsx","../../src/tabs/ReposTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/components/SummaryTiles.tsx — aggregate header tiles.\n *\n * Total repos, active repos (24h), total checkpoints, total tokens saved.\n */\n\nimport type React from \"react\";\n\nexport interface SummaryTilesProps {\n\t/** Total repos in the registry. */\n\ttotalRepos: number;\n\t/** Repos active within the last 24 hours. */\n\tactiveRepos: number;\n\t/** Total checkpoints across all repos. */\n\ttotalCheckpoints: number;\n\t/** Total tokens saved across all repos. */\n\ttotalTokensSaved: number;\n}\n\nfunction fmt(n: number): string {\n\tif (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n\tif (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n\treturn String(n);\n}\n\nexport function SummaryTiles({\n\ttotalRepos,\n\tactiveRepos,\n\ttotalCheckpoints,\n\ttotalTokensSaved,\n}: SummaryTilesProps): React.ReactElement {\n\treturn (\n\t\t<div className=\"summary-tiles\">\n\t\t\t<div className=\"tile\">\n\t\t\t\t<span className=\"tile-label\">Total repos</span>\n\t\t\t\t<span className=\"tile-value\">{totalRepos.toLocaleString()}</span>\n\t\t\t</div>\n\t\t\t<div className=\"tile\">\n\t\t\t\t<span className=\"tile-label\">Active (24h)</span>\n\t\t\t\t<span className=\"tile-value\">{activeRepos.toLocaleString()}</span>\n\t\t\t</div>\n\t\t\t<div className=\"tile\">\n\t\t\t\t<span className=\"tile-label\">Checkpoints</span>\n\t\t\t\t<span className=\"tile-value\">{totalCheckpoints.toLocaleString()}</span>\n\t\t\t</div>\n\t\t\t<div className=\"tile tile-highlight\">\n\t\t\t\t<span className=\"tile-label\">Tokens saved</span>\n\t\t\t\t<span className=\"tile-value\">{fmt(totalTokensSaved)}</span>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/components/RepoTable.tsx — sortable, searchable repo table.\n *\n * Columns: name, model, checkpoints, tokens saved, last compacted, sessions.\n * Client-side sort (click header to toggle asc/desc). Search by displayName\n * (case-insensitive substring). Default sort: lastSeen DESC.\n */\n\nimport type React from \"react\";\nimport { useState, useMemo } from \"react\";\nimport type { IndexesIndexRow } from \"@contracts\";\n\nexport interface RepoTableProps {\n\trepos: IndexesIndexRow[];\n\t/** Called when a row is clicked — opens the detail modal. */\n\tonSelect: (repo: IndexesIndexRow) => void;\n}\n\ntype SortKey =\n\t| \"displayName\"\n\t| \"modelName\"\n\t| \"checkpointCount\"\n\t| \"tokensSaved\"\n\t| \"lastCompactedAt\"\n\t| \"sessions\";\n\ntype SortDir = \"asc\" | \"desc\";\n\nconst COLUMNS: Array<{ key: SortKey; label: string }> = [\n\t{ key: \"displayName\", label: \"Name\" },\n\t{ key: \"modelName\", label: \"Model\" },\n\t{ key: \"checkpointCount\", label: \"Checkpoints\" },\n\t{ key: \"tokensSaved\", label: \"Saved\" },\n\t{ key: \"lastCompactedAt\", label: \"Last compacted\" },\n\t{ key: \"sessions\", label: \"Sessions\" },\n];\n\nfunction fmt(n: number): string {\n\tif (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n\tif (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n\treturn String(n);\n}\n\nfunction formatTs(ts: number | null): string {\n\tif (ts === null || ts === undefined) return \"never\";\n\ttry {\n\t\treturn new Date(ts).toLocaleDateString();\n\t} catch {\n\t\treturn String(ts);\n\t}\n}\n\nexport function RepoTable({\n\trepos,\n\tonSelect,\n}: RepoTableProps): React.ReactElement {\n\tconst [search, setSearch] = useState(\"\");\n\tconst [sortKey, setSortKey] = useState<SortKey>(\"lastCompactedAt\");\n\tconst [sortDir, setSortDir] = useState<SortDir>(\"desc\");\n\n\tconst filtered = useMemo(() => {\n\t\tconst q = search.trim().toLowerCase();\n\t\tconst list = q\n\t\t\t? repos.filter((r) => r.displayName.toLowerCase().includes(q))\n\t\t\t: repos.slice();\n\t\tlist.sort((a, b) => {\n\t\t\tconst av = a[sortKey];\n\t\t\tconst bv = b[sortKey];\n\t\t\t// nulls last on desc, first on asc (consistent UX)\n\t\t\tconst aNull = av === null || av === undefined;\n\t\t\tconst bNull = bv === null || bv === undefined;\n\t\t\tif (aNull && bNull) return 0;\n\t\t\tif (aNull) return sortDir === \"desc\" ? 1 : -1;\n\t\t\tif (bNull) return sortDir === \"desc\" ? -1 : 1;\n\t\t\tconst cmp =\n\t\t\t\ttypeof av === \"number\" && typeof bv === \"number\"\n\t\t\t\t\t? av - bv\n\t\t\t\t\t: String(av).localeCompare(String(bv));\n\t\t\treturn sortDir === \"desc\" ? -cmp : cmp;\n\t\t});\n\t\treturn list;\n\t}, [repos, search, sortKey, sortDir]);\n\n\tconst handleSort = (key: SortKey): void => {\n\t\tif (sortKey === key) {\n\t\t\tsetSortDir((d) => (d === \"asc\" ? \"desc\" : \"asc\"));\n\t\t} else {\n\t\t\tsetSortKey(key);\n\t\t\tsetSortDir(\n\t\t\t\tkey === \"lastCompactedAt\" || key === \"tokensSaved\" ? \"desc\" : \"asc\",\n\t\t\t);\n\t\t}\n\t};\n\n\treturn (\n\t\t<div className=\"repo-table-wrap\">\n\t\t\t<input\n\t\t\t\ttype=\"search\"\n\t\t\t\tclassName=\"repo-search\"\n\t\t\t\tplaceholder=\"Search repos…\"\n\t\t\t\tvalue={search}\n\t\t\t\tonChange={(e) => setSearch(e.target.value)}\n\t\t\t\taria-label=\"Search repos\"\n\t\t\t/>\n\t\t\t<table className=\"repo-table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t{COLUMNS.map((col) => (\n\t\t\t\t\t\t\t<th key={col.key}>\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclassName={`sort-header ${sortKey === col.key ? `active-${sortDir}` : \"\"}`}\n\t\t\t\t\t\t\t\t\tonClick={() => handleSort(col.key)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{col.label}\n\t\t\t\t\t\t\t\t\t{sortKey === col.key && (\n\t\t\t\t\t\t\t\t\t\t<span className=\"sort-arrow\">\n\t\t\t\t\t\t\t\t\t\t\t{sortDir === \"asc\" ? \" ▲\" : \" ▼\"}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t{filtered.length === 0 && (\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td colSpan={COLUMNS.length} className=\"repo-empty\">\n\t\t\t\t\t\t\t\t{repos.length === 0\n\t\t\t\t\t\t\t\t\t? \"No repos yet.\"\n\t\t\t\t\t\t\t\t\t: \"No repos match your search.\"}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t)}\n\t\t\t\t\t{filtered.map((repo) => (\n\t\t\t\t\t\t<tr key={repo.stateDir} onClick={() => onSelect(repo)}>\n\t\t\t\t\t\t\t<td className=\"repo-name\">{repo.displayName}</td>\n\t\t\t\t\t\t\t<td className=\"repo-model\">{repo.modelName ?? \"—\"}</td>\n\t\t\t\t\t\t\t<td>{repo.checkpointCount.toLocaleString()}</td>\n\t\t\t\t\t\t\t<td>{fmt(repo.tokensSaved)}</td>\n\t\t\t\t\t\t\t<td>{formatTs(repo.lastCompactedAt)}</td>\n\t\t\t\t\t\t\t<td>{repo.sessions.toLocaleString()}</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t))}\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/components/RepoDetailModal.tsx — repo drill-down.\n *\n * Full detail from an /api/index row: token breakdown (kept/dropped), model\n * info, context window, dedup rate, reasoning flag. Click backdrop to close.\n */\n\nimport type React from \"react\";\nimport { useEffect } from \"react\";\nimport type { IndexesIndexRow } from \"@contracts\";\n\nexport interface RepoDetailModalProps {\n\trepo: IndexesIndexRow;\n\tonClose: () => void;\n}\n\nfunction fmt(n: number): string {\n\tif (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n\tif (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n\treturn String(n);\n}\n\nfunction formatTs(ts: number | null): string {\n\tif (ts === null || ts === undefined) return \"never\";\n\ttry {\n\t\treturn new Date(ts).toLocaleString();\n\t} catch {\n\t\treturn String(ts);\n\t}\n}\n\nexport function RepoDetailModal({\n\trepo,\n\tonClose,\n}: RepoDetailModalProps): React.ReactElement {\n\t// Close on Escape key.\n\tuseEffect(() => {\n\t\tconst handler = (e: KeyboardEvent): void => {\n\t\t\tif (e.key === \"Escape\") onClose();\n\t\t};\n\t\twindow.addEventListener(\"keydown\", handler);\n\t\treturn () => window.removeEventListener(\"keydown\", handler);\n\t}, [onClose]);\n\n\treturn (\n\t\t<div\n\t\t\tclassName=\"modal-backdrop\"\n\t\t\tonClick={onClose}\n\t\t\trole=\"dialog\"\n\t\t\taria-modal=\"true\"\n\t\t>\n\t\t\t<div className=\"modal-card\" onClick={(e) => e.stopPropagation()}>\n\t\t\t\t<header className=\"modal-header\">\n\t\t\t\t\t<h2>{repo.displayName}</h2>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName=\"modal-close\"\n\t\t\t\t\t\tonClick={onClose}\n\t\t\t\t\t\taria-label=\"Close\"\n\t\t\t\t\t>\n\t\t\t\t\t\t×\n\t\t\t\t\t</button>\n\t\t\t\t</header>\n\t\t\t\t<p className=\"modal-path\">{repo.repoRoot}</p>\n\t\t\t\t<div className=\"modal-grid\">\n\t\t\t\t\t<div className=\"modal-stat\">\n\t\t\t\t\t\t<span className=\"modal-label\">Checkpoints</span>\n\t\t\t\t\t\t<span className=\"modal-value\">\n\t\t\t\t\t\t\t{repo.checkpointCount.toLocaleString()}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"modal-stat\">\n\t\t\t\t\t\t<span className=\"modal-label\">Sessions</span>\n\t\t\t\t\t\t<span className=\"modal-value\">\n\t\t\t\t\t\t\t{repo.sessions.toLocaleString()}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"modal-stat modal-highlight\">\n\t\t\t\t\t\t<span className=\"modal-label\">Tokens saved</span>\n\t\t\t\t\t\t<span className=\"modal-value\">{fmt(repo.tokensSaved)}</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"modal-stat\">\n\t\t\t\t\t\t<span className=\"modal-label\">Tokens kept</span>\n\t\t\t\t\t\t<span className=\"modal-value\">{fmt(repo.tokensKept)}</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"modal-stat\">\n\t\t\t\t\t\t<span className=\"modal-label\">Tokens dropped</span>\n\t\t\t\t\t\t<span className=\"modal-value\">{fmt(repo.tokensDropped)}</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"modal-stat\">\n\t\t\t\t\t\t<span className=\"modal-label\">Dedup rate</span>\n\t\t\t\t\t\t<span className=\"modal-value\">—</span>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<h3>Model</h3>\n\t\t\t\t<dl className=\"modal-dl\">\n\t\t\t\t\t<dt>Provider</dt>\n\t\t\t\t\t<dd>{repo.providerName ?? \"—\"}</dd>\n\t\t\t\t\t<dt>Model</dt>\n\t\t\t\t\t<dd>{repo.modelName ?? \"—\"}</dd>\n\t\t\t\t\t<dt>Input rate</dt>\n\t\t\t\t\t<dd>{repo.inputRate !== null ? `${repo.inputRate} tok/s` : \"—\"}</dd>\n\t\t\t\t\t<dt>Output rate</dt>\n\t\t\t\t\t<dd>{repo.outputRate !== null ? `${repo.outputRate} tok/s` : \"—\"}</dd>\n\t\t\t\t\t<dt>Context window</dt>\n\t\t\t\t\t<dd>{repo.contextWindow !== null ? fmt(repo.contextWindow) : \"—\"}</dd>\n\t\t\t\t\t<dt>Max tokens</dt>\n\t\t\t\t\t<dd>{repo.maxTokens !== null ? fmt(repo.maxTokens) : \"—\"}</dd>\n\t\t\t\t\t<dt>Reasoning</dt>\n\t\t\t\t\t<dd>\n\t\t\t\t\t\t{repo.reasoning === null ? \"—\" : repo.reasoning ? \"on\" : \"off\"}\n\t\t\t\t\t</dd>\n\t\t\t\t</dl>\n\t\t\t\t<h3>Activity</h3>\n\t\t\t\t<dl className=\"modal-dl\">\n\t\t\t\t\t<dt>Last compacted</dt>\n\t\t\t\t\t<dd>{formatTs(repo.lastCompactedAt)}</dd>\n\t\t\t\t\t<dt>Last seen</dt>\n\t\t\t\t\t<dd>{formatTs(repo.lastSeen)}</dd>\n\t\t\t\t\t<dt>Compressed bytes</dt>\n\t\t\t\t\t<dd>{fmt(repo.compressedOriginalBytes)}</dd>\n\t\t\t\t</dl>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/ReposTab.tsx — Repos tab (C2).\n *\n * Fetches /api/repos + /api/summary. Renders SummaryTiles + RepoTable.\n * Row click opens RepoDetailModal. Polls every 10s.\n */\n\nimport type React from \"react\";\nimport { useCallback, useState } from \"react\";\nimport { useApi } from \"../hooks/useApi\";\nimport { fetchRepos, fetchSummary } from \"../api/client\";\nimport type {\n\tReposResponse,\n\tSummaryResponse,\n\tIndexesIndexRow,\n} from \"@contracts\";\nimport { SummaryTiles } from \"../components/SummaryTiles\";\nimport { RepoTable } from \"../components/RepoTable\";\nimport { RepoDetailModal } from \"../components/RepoDetailModal\";\n\nexport default function ReposTab(): React.ReactElement {\n\tconst [selected, setSelected] = useState<IndexesIndexRow | null>(null);\n\n\tconst { data: reposResp, error: reposErr } = useApi<ReposResponse>(\n\t\tuseCallback(() => fetchRepos(), []),\n\t\t{ pollInterval: 10_000 },\n\t);\n\tconst { data: summaryResp } = useApi<SummaryResponse>(\n\t\tuseCallback(() => fetchSummary(), []),\n\t\t{ pollInterval: 10_000 },\n\t);\n\n\tif (reposErr && !reposResp) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">Error loading repos: {reposErr.message}</div>\n\t\t);\n\t}\n\tif (!reposResp) {\n\t\treturn <div className=\"tab-stub\">Loading repos…</div>;\n\t}\n\n\tconst repos = reposResp.repos;\n\tconst summary = summaryResp?.summary;\n\n\treturn (\n\t\t<div className=\"repos-tab\">\n\t\t\t<SummaryTiles\n\t\t\t\ttotalRepos={summaryResp?.totalRepos ?? 0}\n\t\t\t\tactiveRepos={summaryResp?.activeRepos ?? 0}\n\t\t\t\ttotalCheckpoints={summary?.totalCheckpoints ?? 0}\n\t\t\t\ttotalTokensSaved={summary?.totalTokensSaved ?? 0}\n\t\t\t/>\n\t\t\t<RepoTable repos={repos} onSelect={setSelected} />\n\t\t\t{selected && (\n\t\t\t\t<RepoDetailModal repo={selected} onClose={() => setSelected(null)} />\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"],"names":["fmt","n","SummaryTiles","totalRepos","activeRepos","totalCheckpoints","totalTokensSaved","jsxs","jsx","COLUMNS","formatTs","ts","RepoTable","repos","onSelect","search","setSearch","useState","sortKey","setSortKey","sortDir","setSortDir","filtered","useMemo","q","list","r","a","b","av","bv","aNull","bNull","cmp","handleSort","key","d","e","col","repo","RepoDetailModal","onClose","useEffect","handler","ReposTab","selected","setSelected","reposResp","reposErr","useApi","useCallback","fetchRepos","summaryResp","fetchSummary","summary"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
:root{--bg: #0d1117;--panel: #161b22;--border: #30363d;--text: #e6edf3;--muted: #8b949e;--accent: #58a6ff;--ok: #3fb950;--warn: #d29922;--err: #f85149;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text);font-size:14px}.dashboard-app{max-width:1200px;margin:0 auto;padding:16px}.dashboard-header h1{font-size:18px;font-weight:600;margin:0 0 12px}.dashboard-header .tier,.dashboard-header .version-pill{display:inline-block;margin-left:8px;padding:2px 8px;font-size:12px;border-radius:10px;background:var(--panel);border:1px solid var(--border);color:var(--muted)}.dashboard-header .tier{color:var(--accent)}.tab-bar{display:flex;gap:4px;border-bottom:1px solid var(--border);margin-bottom:16px}.tab-bar button{background:none;border:none;color:var(--muted);padding:8px 14px;cursor:pointer;font-size:13px;border-bottom:2px solid transparent}.tab-bar button.active{color:var(--text);border-bottom-color:var(--accent)}.tab-bar button:hover{color:var(--text)}.dashboard-content{min-height:400px}.loading-spinner{display:flex;align-items:center;justify-content:center;padding:48px;color:var(--muted)}.error-fallback{padding:24px;border:1px solid var(--err);border-radius:8px;background:#f8514914}.error-fallback button{margin-top:12px;padding:6px 14px;background:var(--panel);border:1px solid var(--border);color:var(--text);border-radius:6px;cursor:pointer}.tab-stub{padding:32px;color:var(--muted);border:1px dashed var(--border);border-radius:8px;text-align:center}.overview-tab{display:flex;flex-direction:column;gap:12px}.overview-header{display:flex;align-items:center;gap:12px}.tier-pill{padding:2px 10px;font-size:12px;border-radius:10px;background:var(--panel);border:1px solid var(--border);color:var(--accent)}.updated{color:var(--muted);font-size:12px}.card-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:12px}.card{padding:14px 16px;background:var(--panel);border:1px solid var(--border);border-radius:8px}.card h3{margin:0 0 10px;font-size:13px;color:var(--muted);font-weight:600}.gauge-bar{height:10px;background:var(--bg);border-radius:5px;overflow:hidden;border:1px solid var(--border)}.gauge-fill{height:100%;transition:width .4s ease}.gauge-green .gauge-fill{background:var(--ok)}.gauge-yellow .gauge-fill{background:var(--warn)}.gauge-red .gauge-fill{background:var(--err)}.gauge-label{margin:8px 0 0;font-size:12px;color:var(--muted)}.stat-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.stat{display:flex;flex-direction:column;gap:2px}.stat-label{font-size:11px;color:var(--muted);text-transform:uppercase}.stat-value{font-size:16px;font-weight:600}.stat-highlight .stat-value{color:var(--ok)}.bullet-row{display:flex;gap:14px;margin-bottom:8px}.bullet{display:flex;align-items:center;gap:6px;font-size:13px}.bullet-dot{width:8px;height:8px;border-radius:50%;background:var(--muted)}.bullet-on .bullet-dot{background:var(--ok);box-shadow:0 0 6px var(--ok)}.bullet-off .bullet-dot{background:var(--border)}.bullet-on .bullet-label{color:var(--text)}.bullet-off .bullet-label{color:var(--muted)}.trigger-detail{margin:4px 0;font-size:12px;color:var(--muted)}.state-badge{display:inline-block;padding:2px 10px;font-size:12px;border-radius:10px;background:var(--bg);border:1px solid var(--border)}.state-idle,.state-none{color:var(--muted)}.state-compacting{color:var(--warn);border-color:var(--warn)}.persisted-tag{margin-left:8px;font-size:11px;color:var(--ok)}.events-tab{display:flex;flex-direction:column;gap:10px}.events-header{display:flex;align-items:center;gap:14px}.sse-status{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--muted)}.sse-dot{width:8px;height:8px;border-radius:50%;background:var(--muted)}.sse-connected .sse-dot{background:var(--ok);box-shadow:0 0 6px var(--ok)}.sse-connecting .sse-dot{background:var(--warn)}.sse-disconnected .sse-dot,.sse-error .sse-dot{background:var(--err)}.event-count{color:var(--muted);font-size:12px}.event-filters{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin-bottom:8px}.filter-chip{padding:3px 10px;font-size:11px;border:1px solid var(--border);background:var(--bg);color:var(--muted);border-radius:12px;cursor:pointer}.filter-chip.active{color:var(--text);border-color:var(--accent);background:var(--panel)}.event-list{list-style:none;margin:0;padding:0;max-height:60vh;overflow-y:auto}.event-row{display:grid;grid-template-columns:70px 150px 1fr;gap:8px;padding:6px 10px;border-bottom:1px solid var(--border);font-size:12px;cursor:pointer}.event-row:hover{background:var(--panel)}.ev-time{color:var(--muted)}.ev-type{font-size:11px;padding:1px 6px;border-radius:8px;background:var(--bg);border:1px solid var(--border);color:var(--muted);text-align:center}.ev-compact .ev-type{color:var(--accent);border-color:var(--accent)}.ev-trigger .ev-type{color:var(--warn);border-color:var(--warn)}.ev-tier .ev-type{color:var(--muted)}.ev-checkpoint .ev-type{color:var(--ok);border-color:var(--ok)}.ev-recall .ev-type{color:#d2a8ff;border-color:#d2a8ff}.ev-config .ev-type{color:var(--text)}.ev-crew .ev-type{color:#79c0ff;border-color:#79c0ff}.ev-game .ev-type{color:var(--warn)}.ev-summary{color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ev-detail{grid-column:1 / -1;margin:6px 0 0;padding:8px;background:var(--bg);border-radius:4px;font-size:11px;color:var(--muted);white-space:pre-wrap}.event-empty{padding:24px;color:var(--muted);text-align:center}@media (max-width: 768px){.card-grid{grid-template-columns:1fr}.event-row{grid-template-columns:60px 110px 1fr;font-size:11px}}.summary-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:10px;margin-bottom:16px}.tile{display:flex;flex-direction:column;gap:4px;padding:12px 14px;background:var(--panel);border:1px solid var(--border);border-radius:8px}.tile-label{font-size:11px;color:var(--muted);text-transform:uppercase}.tile-value{font-size:20px;font-weight:600}.tile-highlight .tile-value{color:var(--ok)}.repo-table-wrap{overflow-x:auto}.repo-search{width:100%;padding:8px 10px;margin-bottom:10px;background:var(--panel);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px}.repo-table{width:100%;border-collapse:collapse;font-size:13px}.repo-table th{text-align:left;padding:6px 10px;border-bottom:1px solid var(--border)}.repo-table td{padding:8px 10px;border-bottom:1px solid var(--border)}.repo-table tr{cursor:pointer}.repo-table tbody tr:hover{background:var(--panel)}.sort-header{background:none;border:none;color:var(--muted);font-size:12px;font-weight:600;cursor:pointer;padding:0}.sort-header.active-asc,.sort-header.active-desc{color:var(--text)}.sort-arrow{color:var(--accent)}.repo-name{font-weight:600}.repo-model{color:var(--muted)}.repo-empty{text-align:center;color:var(--muted);padding:24px}.modal-backdrop{position:fixed;inset:0;background:#0009;display:flex;align-items:center;justify-content:center;z-index:100}.modal-card{background:var(--panel);border:1px solid var(--border);border-radius:10px;padding:20px 24px;max-width:560px;width:90%;max-height:80vh;overflow-y:auto}.modal-header{display:flex;justify-content:space-between;align-items:center}.modal-header h2{margin:0;font-size:18px}.modal-close{background:none;border:none;color:var(--muted);font-size:22px;cursor:pointer;padding:0 4px}.modal-close:hover{color:var(--text)}.modal-path{font-size:11px;color:var(--muted);margin:4px 0 12px;word-break:break-all}.modal-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:16px}.modal-stat{display:flex;flex-direction:column;gap:2px}.modal-label{font-size:11px;color:var(--muted);text-transform:uppercase}.modal-value{font-size:16px;font-weight:600}.modal-highlight .modal-value{color:var(--ok)}.modal-card h3{font-size:13px;color:var(--muted);margin:16px 0 6px}.modal-dl{display:grid;grid-template-columns:130px 1fr;gap:4px 12px;margin:0}.modal-dl dt{color:var(--muted);font-size:12px}.modal-dl dd{margin:0;font-size:13px}.model-badge{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:12px 14px;background:var(--panel);border:1px solid var(--border);border-radius:8px;margin-bottom:12px}.model-name{font-size:15px;font-weight:600}.model-provider{color:var(--accent);font-size:13px}.model-provider-id{color:var(--muted);font-size:11px}.model-rates{margin-left:auto;display:flex;gap:12px}.model-rates .rate{font-size:12px;color:var(--muted)}.perf-chart{display:flex;flex-direction:column;gap:12px}.perf-header{display:flex;justify-content:space-between;align-items:center}.perf-header h3{margin:0;font-size:13px;color:var(--muted)}.perf-window{font-size:11px;color:var(--muted)}.perf-grid,.perf-resources{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px}.perf-resources{padding-top:10px;border-top:1px solid var(--border)}.perf-metric{display:flex;flex-direction:column;gap:4px;padding:10px 12px;background:var(--panel);border:1px solid var(--border);border-radius:6px}.perf-label{font-size:11px;color:var(--muted)}.perf-value{font-size:15px;font-weight:600}.perf-bar-track{height:6px;background:var(--bg);border-radius:3px;overflow:hidden}.perf-bar-fill{height:100%;transition:width .4s ease}.perf-blue .perf-bar-fill{background:var(--accent)}.perf-purple .perf-bar-fill{background:#d2a8ff}.perf-green .perf-bar-fill{background:var(--ok)}.perf-yellow .perf-bar-fill{background:var(--warn)}.perf-diag{display:flex;flex-wrap:wrap;gap:14px;padding-top:10px;border-top:1px solid var(--border)}@media (max-width: 768px){.modal-grid{grid-template-columns:1fr 1fr}.model-rates{margin-left:0;width:100%}}
|