pi-mega-compact 0.11.13 → 0.12.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/dist/extensions/dashboard-server/routes-health.js +81 -0
- package/dist/extensions/dashboard-server/routes.js +1 -0
- package/dist/extensions/dashboard-server/server.js +5 -1
- package/dist/extensions/mega-config.js +5 -0
- package/dist/extensions/mega-events/agent-handlers.js +5 -0
- package/dist/extensions/mega-events/health-handler.js +156 -0
- package/dist/extensions/mega-runtime/runtime.js +6 -0
- package/dist/src/contextHealth/cachePoison.js +183 -0
- package/dist/src/contextHealth/drift.js +89 -0
- package/dist/src/contextHealth/outputQuality.js +112 -0
- package/dist/src/contextHealth.js +110 -0
- package/dist/src/store/sqlite/context-health.js +193 -0
- package/dist/src/store/sqlite/schema.js +43 -1
- package/dist/src/store/sqlite.js +1 -0
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-9KQgKBEh.js → AchievementTiles-DeQ0qnBX.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-9KQgKBEh.js.map → AchievementTiles-DeQ0qnBX.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{AchievementsTab-B6xoQTEa.js → AchievementsTab-Dtk_RJfs.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AchievementsTab-B6xoQTEa.js.map → AchievementsTab-Dtk_RJfs.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{CacheTab-Dkm9rawo.js → CacheTab-kWcQt3PI.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-Dkm9rawo.js.map → CacheTab-kWcQt3PI.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ConfigTab-Bd_v_OUF.js → ConfigTab-UFlo73fR.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ConfigTab-Bd_v_OUF.js.map → ConfigTab-UFlo73fR.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-CYWoFOdI.js → EventsTab-BENO2N0y.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-CYWoFOdI.js.map → EventsTab-BENO2N0y.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{GameTab-CH7lecNL.js → GameTab-BCJavOML.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{GameTab-CH7lecNL.js.map → GameTab-BCJavOML.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/HealthTab-C7iw7rhx.js +2 -0
- package/extensions/dashboard-client/dist/assets/HealthTab-C7iw7rhx.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DNZ1IF4t.js → MaintenanceTab-C0rdAMWc.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DNZ1IF4t.js.map → MaintenanceTab-C0rdAMWc.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-tVRREYiG.js → MemoryMapTab-w5BZP3i-.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-tVRREYiG.js.map → MemoryMapTab-w5BZP3i-.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CHblYuTY.js → MetricsTab-BBCXa3xS.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CHblYuTY.js.map → MetricsTab-BBCXa3xS.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-Dj0TgFvU.js → OverviewTab-CzABMSAQ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-Dj0TgFvU.js.map → OverviewTab-CzABMSAQ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-BTJcfc1W.js → ReposTab-DFiM_Ubg.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-BTJcfc1W.js.map → ReposTab-DFiM_Ubg.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-C8tU8K5u.js → SessionsTab-BtW4bees.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-C8tU8K5u.js.map → SessionsTab-BtW4bees.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SetupTab-BdxGMo6O.js → SetupTab-Duy1LJhg.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SetupTab-BdxGMo6O.js.map → SetupTab-Duy1LJhg.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BWZSARzT.js → TimeSavedCard-CC13EXij.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BWZSARzT.js.map → TimeSavedCard-CC13EXij.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TopicsTab-BCJwPYl8.js → TopicsTab-BrTB8uEK.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TopicsTab-BCJwPYl8.js.map → TopicsTab-BrTB8uEK.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DQFTSDpz.js → TurnsTab-BJK7FIHu.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DQFTSDpz.js.map → TurnsTab-BJK7FIHu.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-DrrDswj-.js → index-B8k19B9g.js} +11 -11
- package/extensions/dashboard-client/dist/assets/{index-DrrDswj-.js.map → index-B8k19B9g.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-o4tteeTs.js → useSSE-CWBB4Me7.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-o4tteeTs.js.map → useSSE-CWBB4Me7.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/App.tsx +5 -1
- package/extensions/dashboard-client/src/api/health.ts +64 -0
- package/extensions/dashboard-client/src/tabs/HealthTab.tsx +165 -0
- package/extensions/dashboard-server/routes-health.ts +104 -0
- package/extensions/dashboard-server/routes.ts +1 -0
- package/extensions/dashboard-server/server.ts +4 -0
- package/extensions/mega-config.ts +15 -0
- package/extensions/mega-events/agent-handlers.ts +6 -0
- package/extensions/mega-events/health-handler.ts +190 -0
- package/extensions/mega-runtime/runtime.ts +7 -0
- package/package.json +1 -1
- package/src/contextHealth/cachePoison.ts +243 -0
- package/src/contextHealth/drift.ts +107 -0
- package/src/contextHealth/outputQuality.ts +139 -0
- package/src/contextHealth.ts +191 -0
- package/src/store/sqlite/context-health.ts +342 -0
- package/src/store/sqlite/schema.ts +43 -1
- package/src/store/sqlite.ts +1 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{u as N,r,B as p,C as v,j as e,D as f,E as C}from"./index-
|
|
2
|
-
//# sourceMappingURL=MaintenanceTab-
|
|
1
|
+
import{u as N,r,B as p,C as v,j as e,D as f,E as C}from"./index-B8k19B9g.js";const k=[{key:"integrity-check",label:"Integrity Check",desc:"Run PRAGMA integrity_check",dangerous:!1},{key:"reconcile-dedup",label:"Reconcile Dedup Mirror",desc:"Fix orphan dedup rows + backfill refs",dangerous:!1,confirm:"Reconcile dedup_mirror (safe read/write)?"},{key:"checkpoint",label:"WAL Checkpoint",desc:"Merge WAL into main DB (read-only)",dangerous:!1},{key:"vacuum",label:"VACUUM",desc:"Rebuild DB reclaiming free pages",dangerous:!0,confirm:"VACUUM rewrites the entire DB. Continue?"},{key:"reindex",label:"REINDEX",desc:"Rebuild all indexes",dangerous:!0,confirm:"REINDEX rebuilds indexes. Continue?"},{key:"fts5-rebuild",label:"FTS5 Rebuild",desc:"Rebuild full-text search index",dangerous:!0,confirm:"Rebuild FTS5 trigram index. Continue?"},{key:"prune",label:"Prune Old Rows",desc:"Delete transcripts + epochs older than N days",dangerous:!0,daysOld:!0,confirm:"Delete old raw_transcript rows. Continue?"}];function x(s){return s<1024?`${s} B`:s<1024*1024?`${(s/1024).toFixed(1)} KB`:`${(s/(1024*1024)).toFixed(1)} MB`}function w({files:s,pageSize:n,pageCount:t,freelistPages:l}){const c=s.dbBytes+s.walBytes+s.shmBytes;return e.jsxs("div",{className:"stat-section",children:[e.jsx("div",{className:"stat-label",children:"File Sizes"}),e.jsx("table",{className:"compact-table",children:e.jsxs("tbody",{children:[e.jsxs("tr",{children:[e.jsx("td",{children:"sqlite.db"}),e.jsx("td",{className:"num",children:x(s.dbBytes)})]}),s.walBytes>0&&e.jsxs("tr",{children:[e.jsx("td",{children:".wal"}),e.jsx("td",{className:"num",children:x(s.walBytes)})]}),s.shmBytes>0&&e.jsxs("tr",{children:[e.jsx("td",{children:".shm"}),e.jsx("td",{className:"num",children:x(s.shmBytes)})]}),e.jsxs("tr",{children:[e.jsx("td",{children:"Total"}),e.jsx("td",{className:"num",children:x(c)})]}),e.jsxs("tr",{children:[e.jsx("td",{children:"Page size"}),e.jsx("td",{className:"num",children:x(n)})]}),e.jsxs("tr",{children:[e.jsx("td",{children:"Pages"}),e.jsxs("td",{className:"num",children:[t.toLocaleString()," (",l.toLocaleString()," ","free)"]})]})]})})]})}function S({tables:s}){const n=s.reduce((t,l)=>t+Math.max(0,l.rowCount),0);return e.jsxs("div",{className:"stat-section",children:[e.jsxs("div",{className:"stat-label",children:["Table Row Counts (",n.toLocaleString()," total)"]}),e.jsxs("table",{className:"compact-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Table"}),e.jsx("th",{className:"num",children:"Rows"})]})}),e.jsx("tbody",{children:s.map(t=>e.jsxs("tr",{children:[e.jsx("td",{children:t.table}),e.jsx("td",{className:"num",children:t.rowCount>=0?t.rowCount.toLocaleString():"—"})]},t.table))})]})]})}function R({data:s,loading:n,error:t}){return e.jsxs("div",{className:"card",children:[e.jsx("div",{className:"card-header",children:"DB Stats"}),e.jsxs("div",{className:"card-body",children:[n&&!s&&e.jsx("span",{className:"text-muted",children:"Loading…"}),t&&!s&&e.jsx("span",{className:"text-error",children:t.message}),s&&e.jsxs(e.Fragment,{children:[e.jsx(w,{files:s.storage.files,pageSize:s.storage.pageSize,pageCount:s.storage.pageCount,freelistPages:s.storage.freelistPages}),e.jsx(S,{tables:s.tables})]})]})]})}function D({columns:s}){const n=s.filter(t=>!t.present);return e.jsxs("div",{className:"stat-section",children:[e.jsxs("div",{className:"stat-label",children:["Column Audit (",s.length," columns, ",n.length," missing)"]}),e.jsxs("table",{className:"compact-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Table"}),e.jsx("th",{children:"Column"}),e.jsx("th",{children:"Decl"}),e.jsx("th",{children:"Status"})]})}),e.jsx("tbody",{children:s.map(t=>e.jsxs("tr",{children:[e.jsx("td",{children:t.table}),e.jsx("td",{children:t.column}),e.jsx("td",{className:"text-mono",children:t.expectedDecl}),e.jsx("td",{className:t.present?"text-ok":"text-error",children:t.present?"✓":"MISSING"})]},`${t.table}.${t.column}`))})]})]})}function B({data:s,loading:n,error:t}){return e.jsxs("div",{className:"card",children:[e.jsxs("div",{className:"card-header",children:["Schema Health",s&&e.jsx("span",{className:`badge ${s.healthy?"badge-ok":"badge-bad"}`,children:s.healthy?"HEALTHY":"DEGRADED"})]}),e.jsxs("div",{className:"card-body",children:[n&&!s&&e.jsx("span",{className:"text-muted",children:"Loading…"}),t&&!s&&e.jsx("span",{className:"text-error",children:t.message}),s&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"stat-row",children:[e.jsx("span",{className:"stat-label",children:"Schema version"}),e.jsx("span",{className:"num",children:s.schemaVersion})]}),e.jsxs("div",{className:"stat-row",children:[e.jsx("span",{className:"stat-label",children:"Integrity"}),e.jsx("span",{className:s.integrity[0]==="ok"?"text-ok":"text-error",children:s.integrity.join("; ")})]}),e.jsx(D,{columns:s.columns}),s.fkCheck.length>0&&e.jsxs("div",{className:"stat-section",children:[e.jsxs("div",{className:"stat-label text-warn",children:["FK Check (",s.fkCheck.length,")"]}),s.fkCheck.map((l,c)=>e.jsx("div",{className:"text-warn text-mono",children:l},c))]})]})]})]})}function E(){const[s,n]=r.useState([]),[t,l]=r.useState(null),[c,h]=r.useState("30"),j=r.useCallback(async a=>{const m=a.daysOld?{action:"prune",daysOld:Number(c)}:{action:a.key};l(a.key);try{const i=await f(m);n(o=>[{...i,timestamp:Date.now()},...o].slice(0,20))}catch(i){n(o=>[{operation:a.key,success:!1,affected:0,reclaimedBytes:0,summary:i instanceof Error?i.message:String(i),timestamp:Date.now()},...o].slice(0,20))}finally{l(null)}},[c]);return e.jsxs("div",{className:"card",children:[e.jsx("div",{className:"card-header",children:"Actions"}),e.jsx("div",{className:"card-body",children:e.jsx("div",{className:"action-grid",children:k.map(a=>{const m=t===a.key,i=s.find(o=>o.operation===a.key);return e.jsxs("div",{className:"action-item",children:[e.jsxs("div",{className:"action-info",children:[e.jsxs("div",{className:"action-label",children:[a.label,a.dangerous&&e.jsx("span",{className:"badge badge-warn",children:"DESTRUCTIVE"})]}),e.jsx("div",{className:"action-desc",children:a.desc}),i&&e.jsx("div",{className:`action-result ${i.success?"text-ok":"text-error"}`,children:i.summary})]}),e.jsxs("div",{className:"action-controls",children:[a.daysOld&&e.jsx("input",{type:"number",min:1,max:365,value:c,onChange:o=>h(o.target.value),className:"days-input",disabled:m}),e.jsx("button",{className:`btn ${a.dangerous?"btn-danger":"btn-primary"}`,disabled:t!==null,onClick:()=>{a.confirm&&!window.confirm(a.confirm)||j(a)},children:m?"Running…":"Run"})]})]},a.key)})})})]})}function L(){const[s,n]=r.useState(null),[t,l]=r.useState(!1),[c,h]=r.useState(null),[j,a]=r.useState(!1),m=r.useCallback(async()=>{l(!0),h(null);try{const d=await C();n(d),a(!0)}catch(d){h(d instanceof Error?d.message:String(d))}finally{l(!1)}},[]),i=r.useCallback(()=>{if(!s)return;const d=JSON.stringify(s,null,2);navigator.clipboard.writeText(d).catch(()=>{})},[s]),o=r.useCallback(()=>{if(!s)return;const d=JSON.stringify(s,null,2),y=new Blob([d],{type:"application/json"}),b=URL.createObjectURL(y),g=document.createElement("a");g.href=b,g.download=`mega-compact-debug-bundle-${s.builtAt}.json`,g.click(),URL.revokeObjectURL(b)},[s]),u=s?.criticalEvents.length??0;return e.jsxs("div",{className:"card",children:[e.jsxs("div",{className:"card-header",children:["Debug Bundle",u>0&&e.jsxs("span",{className:"text-warn",style:{marginLeft:"1em"},children:[u," critical event",u!==1?"s":""," found"]})]}),e.jsxs("div",{className:"card-body",children:[e.jsx("p",{className:"text-muted",style:{marginBottom:"0.75em"},children:"Gather a diagnostic bundle (recent events, config flags, schema health, store stats) to attach to a bug report. Critical/compaction events are highlighted."}),e.jsx("button",{onClick:m,disabled:t,style:{marginRight:"0.5em"},children:t?"Gathering…":"Gather Debug Logs"}),c&&e.jsx("div",{className:"text-error",children:c}),s&&j&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:{marginTop:"0.75em",marginBottom:"0.5em"},children:[e.jsx("button",{onClick:i,style:{marginRight:"0.5em"},children:"Copy to clipboard"}),e.jsx("button",{onClick:o,children:"Download JSON"}),e.jsx("button",{onClick:()=>a(d=>!d),style:{marginLeft:"0.5em"},children:j?"Hide":"Show"})]}),u>0&&e.jsxs("div",{className:"stat-section",children:[e.jsxs("div",{className:"stat-label text-warn",children:["Critical events (",u,")"]}),e.jsx("pre",{className:"text-mono",style:{maxHeight:"12em",overflow:"auto"},children:JSON.stringify(s.criticalEvents,null,2)})]}),e.jsx("pre",{className:"text-mono",style:{maxHeight:"24em",overflow:"auto"},children:JSON.stringify(s,null,2)})]})]})]})}function T(){const{data:s,loading:n,error:t}=N(r.useCallback(()=>p(),[]),{pollInterval:15e3}),{data:l,loading:c,error:h}=N(r.useCallback(()=>v(),[]),{pollInterval:1e4});return e.jsxs("div",{className:"maintenance-tab",children:[e.jsxs("div",{className:"card-grid",children:[e.jsx(B,{data:l,loading:c,error:h}),e.jsx(R,{data:s,loading:n,error:t})]}),e.jsx(E,{}),e.jsx(L,{})]})}export{T as default};
|
|
2
|
+
//# sourceMappingURL=MaintenanceTab-C0rdAMWc.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MaintenanceTab-DNZ1IF4t.js","sources":["../../src/tabs/MaintenanceTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/tabs/MaintenanceTab.tsx — Maintenance tab (v0.11.2 S49B).\n *\n * Three cards:\n * 1. Schema Health (schema version + integrity + column audit)\n * 2. DB Stats (file sizes + table row counts)\n * 3. Actions (one-time maintenance operations with results history)\n *\n * All three fetch independently; failures in one do not block the others.\n */\n\nimport type React from \"react\";\nimport { useState, useCallback } from \"react\";\nimport type {\n\tDbStatsResponse,\n\tSchemaHealthResponse,\n\tMaintenanceAction,\n\tMaintenanceActionResult,\n\tDebugBundleResponse,\n} from \"@contracts\";\nimport { useApi } from \"../hooks/useApi\";\nimport {\n\tfetchDbStats,\n\tfetchSchemaHealth,\n\tpostMaintenanceAction,\n\tfetchDebugBundle,\n} from \"../api/client\";\n\n// ---------------------------------------------------------------------------\n// Action config\n// ---------------------------------------------------------------------------\n\ninterface ActionDef {\n\tkey: string;\n\tlabel: string;\n\tdesc: string;\n\tdangerous: boolean;\n\tconfirm?: string;\n\tdaysOld?: boolean;\n}\n\nconst ACTIONS: ActionDef[] = [\n\t{\n\t\tkey: \"integrity-check\",\n\t\tlabel: \"Integrity Check\",\n\t\tdesc: \"Run PRAGMA integrity_check\",\n\t\tdangerous: false,\n\t},\n\t{\n\t\tkey: \"reconcile-dedup\",\n\t\tlabel: \"Reconcile Dedup Mirror\",\n\t\tdesc: \"Fix orphan dedup rows + backfill refs\",\n\t\tdangerous: false,\n\t\tconfirm: \"Reconcile dedup_mirror (safe read/write)?\",\n\t},\n\t{\n\t\tkey: \"checkpoint\",\n\t\tlabel: \"WAL Checkpoint\",\n\t\tdesc: \"Merge WAL into main DB (read-only)\",\n\t\tdangerous: false,\n\t},\n\t{\n\t\tkey: \"vacuum\",\n\t\tlabel: \"VACUUM\",\n\t\tdesc: \"Rebuild DB reclaiming free pages\",\n\t\tdangerous: true,\n\t\tconfirm: \"VACUUM rewrites the entire DB. Continue?\",\n\t},\n\t{\n\t\tkey: \"reindex\",\n\t\tlabel: \"REINDEX\",\n\t\tdesc: \"Rebuild all indexes\",\n\t\tdangerous: true,\n\t\tconfirm: \"REINDEX rebuilds indexes. Continue?\",\n\t},\n\t{\n\t\tkey: \"fts5-rebuild\",\n\t\tlabel: \"FTS5 Rebuild\",\n\t\tdesc: \"Rebuild full-text search index\",\n\t\tdangerous: true,\n\t\tconfirm: \"Rebuild FTS5 trigram index. Continue?\",\n\t},\n\t{\n\t\tkey: \"prune\",\n\t\tlabel: \"Prune Old Rows\",\n\t\tdesc: \"Delete transcripts + epochs older than N days\",\n\t\tdangerous: true,\n\t\tdaysOld: true,\n\t\tconfirm: \"Delete old raw_transcript rows. Continue?\",\n\t},\n];\n\n// ---------------------------------------------------------------------------\n// Format helpers (local — matches html.ts fmtBytes)\n// ---------------------------------------------------------------------------\n\nfunction fmtBytes(b: number): string {\n\tif (b < 1024) return `${b} B`;\n\tif (b < 1024 * 1024) return `${(b / 1024).toFixed(1)} KB`;\n\treturn `${(b / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n// ---------------------------------------------------------------------------\n// DB Stats card\n// ---------------------------------------------------------------------------\n\nfunction FileSizesCard({\n\tfiles,\n\tpageSize,\n\tpageCount,\n\tfreelistPages,\n}: {\n\tfiles: DbStatsResponse[\"storage\"][\"files\"];\n\tpageSize: number;\n\tpageCount: number;\n\tfreelistPages: number;\n}): React.ReactElement {\n\tconst total = files.dbBytes + files.walBytes + files.shmBytes;\n\treturn (\n\t\t<div className=\"stat-section\">\n\t\t\t<div className=\"stat-label\">File Sizes</div>\n\t\t\t<table className=\"compact-table\">\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>sqlite.db</td>\n\t\t\t\t\t\t<td className=\"num\">{fmtBytes(files.dbBytes)}</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t{files.walBytes > 0 && (\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td>.wal</td>\n\t\t\t\t\t\t\t<td className=\"num\">{fmtBytes(files.walBytes)}</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t)}\n\t\t\t\t\t{files.shmBytes > 0 && (\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td>.shm</td>\n\t\t\t\t\t\t\t<td className=\"num\">{fmtBytes(files.shmBytes)}</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t)}\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>Total</td>\n\t\t\t\t\t\t<td className=\"num\">{fmtBytes(total)}</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>Page size</td>\n\t\t\t\t\t\t<td className=\"num\">{fmtBytes(pageSize)}</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>Pages</td>\n\t\t\t\t\t\t<td className=\"num\">\n\t\t\t\t\t\t\t{pageCount.toLocaleString()} ({freelistPages.toLocaleString()}{\" \"}\n\t\t\t\t\t\t\tfree)\n\t\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>\n\t);\n}\n\nfunction TableRowCountsCard({\n\ttables,\n}: {\n\ttables: DbStatsResponse[\"tables\"];\n}): React.ReactElement {\n\tconst totalRows = tables.reduce((s, t) => s + Math.max(0, t.rowCount), 0);\n\treturn (\n\t\t<div className=\"stat-section\">\n\t\t\t<div className=\"stat-label\">\n\t\t\t\tTable Row Counts ({totalRows.toLocaleString()} total)\n\t\t\t</div>\n\t\t\t<table className=\"compact-table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>Table</th>\n\t\t\t\t\t\t<th className=\"num\">Rows</th>\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{tables.map((t) => (\n\t\t\t\t\t\t<tr key={t.table}>\n\t\t\t\t\t\t\t<td>{t.table}</td>\n\t\t\t\t\t\t\t<td className=\"num\">\n\t\t\t\t\t\t\t\t{t.rowCount >= 0 ? t.rowCount.toLocaleString() : \"—\"}\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</tbody>\n\t\t\t</table>\n\t\t</div>\n\t);\n}\n\nfunction DbStatsCard({\n\tdata,\n\tloading,\n\terror,\n}: {\n\tdata: DbStatsResponse | null;\n\tloading: boolean;\n\terror: Error | null;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"card\">\n\t\t\t<div className=\"card-header\">DB Stats</div>\n\t\t\t<div className=\"card-body\">\n\t\t\t\t{loading && !data && <span className=\"text-muted\">Loading…</span>}\n\t\t\t\t{error && !data && <span className=\"text-error\">{error.message}</span>}\n\t\t\t\t{data && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<FileSizesCard\n\t\t\t\t\t\t\tfiles={data.storage.files}\n\t\t\t\t\t\t\tpageSize={data.storage.pageSize}\n\t\t\t\t\t\t\tpageCount={data.storage.pageCount}\n\t\t\t\t\t\t\tfreelistPages={data.storage.freelistPages}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<TableRowCountsCard tables={data.tables} />\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Schema Health card\n// ---------------------------------------------------------------------------\n\nfunction ColumnAuditCard({\n\tcolumns,\n}: {\n\tcolumns: SchemaHealthResponse[\"columns\"];\n}): React.ReactElement {\n\tconst missing = columns.filter((c) => !c.present);\n\treturn (\n\t\t<div className=\"stat-section\">\n\t\t\t<div className=\"stat-label\">\n\t\t\t\tColumn Audit ({columns.length} columns, {missing.length} missing)\n\t\t\t</div>\n\t\t\t<table className=\"compact-table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>Table</th>\n\t\t\t\t\t\t<th>Column</th>\n\t\t\t\t\t\t<th>Decl</th>\n\t\t\t\t\t\t<th>Status</th>\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{columns.map((c) => (\n\t\t\t\t\t\t<tr key={`${c.table}.${c.column}`}>\n\t\t\t\t\t\t\t<td>{c.table}</td>\n\t\t\t\t\t\t\t<td>{c.column}</td>\n\t\t\t\t\t\t\t<td className=\"text-mono\">{c.expectedDecl}</td>\n\t\t\t\t\t\t\t<td className={c.present ? \"text-ok\" : \"text-error\"}>\n\t\t\t\t\t\t\t\t{c.present ? \"✓\" : \"MISSING\"}\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</tbody>\n\t\t\t</table>\n\t\t</div>\n\t);\n}\n\nfunction SchemaHealthCard({\n\tdata,\n\tloading,\n\terror,\n}: {\n\tdata: SchemaHealthResponse | null;\n\tloading: boolean;\n\terror: Error | null;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"card\">\n\t\t\t<div className=\"card-header\">\n\t\t\t\tSchema Health\n\t\t\t\t{data && (\n\t\t\t\t\t<span className={`badge ${data.healthy ? \"badge-ok\" : \"badge-bad\"}`}>\n\t\t\t\t\t\t{data.healthy ? \"HEALTHY\" : \"DEGRADED\"}\n\t\t\t\t\t</span>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<div className=\"card-body\">\n\t\t\t\t{loading && !data && <span className=\"text-muted\">Loading…</span>}\n\t\t\t\t{error && !data && <span className=\"text-error\">{error.message}</span>}\n\t\t\t\t{data && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<div className=\"stat-row\">\n\t\t\t\t\t\t\t<span className=\"stat-label\">Schema version</span>\n\t\t\t\t\t\t\t<span className=\"num\">{data.schemaVersion}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"stat-row\">\n\t\t\t\t\t\t\t<span className=\"stat-label\">Integrity</span>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tclassName={\n\t\t\t\t\t\t\t\t\tdata.integrity[0] === \"ok\" ? \"text-ok\" : \"text-error\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{data.integrity.join(\"; \")}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<ColumnAuditCard columns={data.columns} />\n\t\t\t\t\t\t{data.fkCheck.length > 0 && (\n\t\t\t\t\t\t\t<div className=\"stat-section\">\n\t\t\t\t\t\t\t\t<div className=\"stat-label text-warn\">\n\t\t\t\t\t\t\t\t\tFK Check ({data.fkCheck.length})\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t{data.fkCheck.map((line, i) => (\n\t\t\t\t\t\t\t\t\t<div key={i} className=\"text-warn text-mono\">\n\t\t\t\t\t\t\t\t\t\t{line}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Actions card\n// ---------------------------------------------------------------------------\n\nfunction ActionsCard(): React.ReactElement {\n\tconst [results, setResults] = useState<MaintenanceActionResult[]>([]);\n\tconst [running, setRunning] = useState<string | null>(null);\n\tconst [days, setDays] = useState(\"30\");\n\n\tconst handleAction = useCallback(\n\t\tasync (def: ActionDef) => {\n\t\t\tconst action: MaintenanceAction = def.daysOld\n\t\t\t\t? { action: \"prune\", daysOld: Number(days) }\n\t\t\t\t: ({ action: def.key } as MaintenanceAction);\n\n\t\t\tsetRunning(def.key);\n\t\t\ttry {\n\t\t\t\tconst res = await postMaintenanceAction(action);\n\t\t\t\tsetResults((prev) =>\n\t\t\t\t\t[{ ...res, timestamp: Date.now() }, ...prev].slice(0, 20),\n\t\t\t\t);\n\t\t\t} catch (err) {\n\t\t\t\tsetResults((prev) =>\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toperation: def.key,\n\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\taffected: 0,\n\t\t\t\t\t\t\treclaimedBytes: 0,\n\t\t\t\t\t\t\tsummary: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...prev,\n\t\t\t\t\t].slice(0, 20),\n\t\t\t\t);\n\t\t\t} finally {\n\t\t\t\tsetRunning(null);\n\t\t\t}\n\t\t},\n\t\t[days],\n\t);\n\n\treturn (\n\t\t<div className=\"card\">\n\t\t\t<div className=\"card-header\">Actions</div>\n\t\t\t<div className=\"card-body\">\n\t\t\t\t<div className=\"action-grid\">\n\t\t\t\t\t{ACTIONS.map((def) => {\n\t\t\t\t\t\tconst isRunning = running === def.key;\n\t\t\t\t\t\tconst lastResult = results.find((r) => r.operation === def.key);\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<div key={def.key} className=\"action-item\">\n\t\t\t\t\t\t\t\t<div className=\"action-info\">\n\t\t\t\t\t\t\t\t\t<div className=\"action-label\">\n\t\t\t\t\t\t\t\t\t\t{def.label}\n\t\t\t\t\t\t\t\t\t\t{def.dangerous && (\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"badge badge-warn\">DESTRUCTIVE</span>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t<div className=\"action-desc\">{def.desc}</div>\n\t\t\t\t\t\t\t\t\t{lastResult && (\n\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\tclassName={`action-result ${lastResult.success ? \"text-ok\" : \"text-error\"}`}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{lastResult.summary}\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"action-controls\">\n\t\t\t\t\t\t\t\t\t{def.daysOld && (\n\t\t\t\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\t\t\t\t\tmin={1}\n\t\t\t\t\t\t\t\t\t\t\tmax={365}\n\t\t\t\t\t\t\t\t\t\t\tvalue={days}\n\t\t\t\t\t\t\t\t\t\t\tonChange={(e) => setDays(e.target.value)}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"days-input\"\n\t\t\t\t\t\t\t\t\t\t\tdisabled={isRunning}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\tclassName={`btn ${def.dangerous ? \"btn-danger\" : \"btn-primary\"}`}\n\t\t\t\t\t\t\t\t\t\tdisabled={running !== null}\n\t\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\t\tif (def.confirm && !window.confirm(def.confirm)) return;\n\t\t\t\t\t\t\t\t\t\t\thandleAction(def);\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{isRunning ? \"Running…\" : \"Run\"}\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t);\n\t\t\t\t\t})}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Debug bundle card — gather diagnostic info for bug reports\n// ---------------------------------------------------------------------------\n\nfunction DebugBundleCard(): React.ReactElement {\n\tconst [bundle, setBundle] = useState<DebugBundleResponse | null>(null);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<string | null>(null);\n\tconst [showJson, setShowJson] = useState(false);\n\n\tconst gather = useCallback(async () => {\n\t\tsetLoading(true);\n\t\tsetError(null);\n\t\ttry {\n\t\t\tconst res = await fetchDebugBundle();\n\t\t\tsetBundle(res);\n\t\t\tsetShowJson(true);\n\t\t} catch (err) {\n\t\t\tsetError(err instanceof Error ? err.message : String(err));\n\t\t} finally {\n\t\t\tsetLoading(false);\n\t\t}\n\t}, []);\n\n\tconst copyToClipboard = useCallback(() => {\n\t\tif (!bundle) return;\n\t\tconst text = JSON.stringify(bundle, null, 2);\n\t\tvoid navigator.clipboard.writeText(text).catch(() => {});\n\t}, [bundle]);\n\n\tconst downloadJson = useCallback(() => {\n\t\tif (!bundle) return;\n\t\tconst text = JSON.stringify(bundle, null, 2);\n\t\tconst blob = new Blob([text], { type: \"application/json\" });\n\t\tconst url = URL.createObjectURL(blob);\n\t\tconst a = document.createElement(\"a\");\n\t\ta.href = url;\n\t\ta.download = `mega-compact-debug-bundle-${bundle.builtAt}.json`;\n\t\ta.click();\n\t\tURL.revokeObjectURL(url);\n\t}, [bundle]);\n\n\tconst criticalCount = bundle?.criticalEvents.length ?? 0;\n\n\treturn (\n\t\t<div className=\"card\">\n\t\t\t<div className=\"card-header\">\n\t\t\t\tDebug Bundle\n\t\t\t\t{criticalCount > 0 && (\n\t\t\t\t\t<span className=\"text-warn\" style={{ marginLeft: \"1em\" }}>\n\t\t\t\t\t\t{criticalCount} critical event{criticalCount !== 1 ? \"s\" : \"\"} found\n\t\t\t\t\t</span>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<div className=\"card-body\">\n\t\t\t\t<p className=\"text-muted\" style={{ marginBottom: \"0.75em\" }}>\n\t\t\t\t\tGather a diagnostic bundle (recent events, config flags, schema health,\n\t\t\t\t\tstore stats) to attach to a bug report. Critical/compaction events are\n\t\t\t\t\thighlighted.\n\t\t\t\t</p>\n\t\t\t\t<button onClick={gather} disabled={loading} style={{ marginRight: \"0.5em\" }}>\n\t\t\t\t\t{loading ? \"Gathering…\" : \"Gather Debug Logs\"}\n\t\t\t\t</button>\n\t\t\t\t{error && <div className=\"text-error\">{error}</div>}\n\t\t\t\t{bundle && showJson && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<div style={{ marginTop: \"0.75em\", marginBottom: \"0.5em\" }}>\n\t\t\t\t\t\t\t<button onClick={copyToClipboard} style={{ marginRight: \"0.5em\" }}>\n\t\t\t\t\t\t\t\tCopy to clipboard\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t<button onClick={downloadJson}>Download JSON</button>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tonClick={() => setShowJson((v) => !v)}\n\t\t\t\t\t\t\t\tstyle={{ marginLeft: \"0.5em\" }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{showJson ? \"Hide\" : \"Show\"}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t{criticalCount > 0 && (\n\t\t\t\t\t\t\t<div className=\"stat-section\">\n\t\t\t\t\t\t\t\t<div className=\"stat-label text-warn\">\n\t\t\t\t\t\t\t\t\tCritical events ({criticalCount})\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<pre className=\"text-mono\" style={{ maxHeight: \"12em\", overflow: \"auto\" }}>\n\t\t\t\t\t\t\t\t\t{JSON.stringify(bundle.criticalEvents, null, 2)}\n\t\t\t\t\t\t\t\t</pre>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<pre className=\"text-mono\" style={{ maxHeight: \"24em\", overflow: \"auto\" }}>\n\t\t\t\t\t\t\t{JSON.stringify(bundle, null, 2)}\n\t\t\t\t\t\t</pre>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Main tab component\n// ---------------------------------------------------------------------------\n\nexport default function MaintenanceTab(): React.ReactElement {\n\tconst {\n\t\tdata: dbStats,\n\t\tloading: statsLoading,\n\t\terror: statsError,\n\t} = useApi<DbStatsResponse>(\n\t\tuseCallback(() => fetchDbStats(), []),\n\t\t{ pollInterval: 15000 },\n\t);\n\n\tconst {\n\t\tdata: schemaHealth,\n\t\tloading: healthLoading,\n\t\terror: healthError,\n\t} = useApi<SchemaHealthResponse>(\n\t\tuseCallback(() => fetchSchemaHealth(), []),\n\t\t{ pollInterval: 10000 },\n\t);\n\n\treturn (\n\t\t<div className=\"maintenance-tab\">\n\t\t\t<div className=\"card-grid\">\n\t\t\t\t<SchemaHealthCard\n\t\t\t\t\tdata={schemaHealth}\n\t\t\t\t\tloading={healthLoading}\n\t\t\t\t\terror={healthError}\n\t\t\t\t/>\n\t\t\t\t<DbStatsCard data={dbStats} loading={statsLoading} error={statsError} />\n\t\t\t</div>\n\t\t\t<ActionsCard />\n\t\t\t<DebugBundleCard />\n\t\t</div>\n\t);\n}\n"],"names":["ACTIONS","fmtBytes","b","FileSizesCard","files","pageSize","pageCount","freelistPages","total","jsxs","jsx","TableRowCountsCard","tables","totalRows","s","t","DbStatsCard","data","loading","error","Fragment","ColumnAuditCard","columns","missing","c","SchemaHealthCard","line","i","ActionsCard","results","setResults","useState","running","setRunning","days","setDays","handleAction","useCallback","def","action","res","postMaintenanceAction","prev","err","isRunning","lastResult","r","e","DebugBundleCard","bundle","setBundle","setLoading","setError","showJson","setShowJson","gather","fetchDebugBundle","copyToClipboard","text","downloadJson","blob","url","a","criticalCount","v","MaintenanceTab","dbStats","statsLoading","statsError","useApi","fetchDbStats","schemaHealth","healthLoading","healthError","fetchSchemaHealth"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MaintenanceTab-C0rdAMWc.js","sources":["../../src/tabs/MaintenanceTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/tabs/MaintenanceTab.tsx — Maintenance tab (v0.11.2 S49B).\n *\n * Three cards:\n * 1. Schema Health (schema version + integrity + column audit)\n * 2. DB Stats (file sizes + table row counts)\n * 3. Actions (one-time maintenance operations with results history)\n *\n * All three fetch independently; failures in one do not block the others.\n */\n\nimport type React from \"react\";\nimport { useState, useCallback } from \"react\";\nimport type {\n\tDbStatsResponse,\n\tSchemaHealthResponse,\n\tMaintenanceAction,\n\tMaintenanceActionResult,\n\tDebugBundleResponse,\n} from \"@contracts\";\nimport { useApi } from \"../hooks/useApi\";\nimport {\n\tfetchDbStats,\n\tfetchSchemaHealth,\n\tpostMaintenanceAction,\n\tfetchDebugBundle,\n} from \"../api/client\";\n\n// ---------------------------------------------------------------------------\n// Action config\n// ---------------------------------------------------------------------------\n\ninterface ActionDef {\n\tkey: string;\n\tlabel: string;\n\tdesc: string;\n\tdangerous: boolean;\n\tconfirm?: string;\n\tdaysOld?: boolean;\n}\n\nconst ACTIONS: ActionDef[] = [\n\t{\n\t\tkey: \"integrity-check\",\n\t\tlabel: \"Integrity Check\",\n\t\tdesc: \"Run PRAGMA integrity_check\",\n\t\tdangerous: false,\n\t},\n\t{\n\t\tkey: \"reconcile-dedup\",\n\t\tlabel: \"Reconcile Dedup Mirror\",\n\t\tdesc: \"Fix orphan dedup rows + backfill refs\",\n\t\tdangerous: false,\n\t\tconfirm: \"Reconcile dedup_mirror (safe read/write)?\",\n\t},\n\t{\n\t\tkey: \"checkpoint\",\n\t\tlabel: \"WAL Checkpoint\",\n\t\tdesc: \"Merge WAL into main DB (read-only)\",\n\t\tdangerous: false,\n\t},\n\t{\n\t\tkey: \"vacuum\",\n\t\tlabel: \"VACUUM\",\n\t\tdesc: \"Rebuild DB reclaiming free pages\",\n\t\tdangerous: true,\n\t\tconfirm: \"VACUUM rewrites the entire DB. Continue?\",\n\t},\n\t{\n\t\tkey: \"reindex\",\n\t\tlabel: \"REINDEX\",\n\t\tdesc: \"Rebuild all indexes\",\n\t\tdangerous: true,\n\t\tconfirm: \"REINDEX rebuilds indexes. Continue?\",\n\t},\n\t{\n\t\tkey: \"fts5-rebuild\",\n\t\tlabel: \"FTS5 Rebuild\",\n\t\tdesc: \"Rebuild full-text search index\",\n\t\tdangerous: true,\n\t\tconfirm: \"Rebuild FTS5 trigram index. Continue?\",\n\t},\n\t{\n\t\tkey: \"prune\",\n\t\tlabel: \"Prune Old Rows\",\n\t\tdesc: \"Delete transcripts + epochs older than N days\",\n\t\tdangerous: true,\n\t\tdaysOld: true,\n\t\tconfirm: \"Delete old raw_transcript rows. Continue?\",\n\t},\n];\n\n// ---------------------------------------------------------------------------\n// Format helpers (local — matches html.ts fmtBytes)\n// ---------------------------------------------------------------------------\n\nfunction fmtBytes(b: number): string {\n\tif (b < 1024) return `${b} B`;\n\tif (b < 1024 * 1024) return `${(b / 1024).toFixed(1)} KB`;\n\treturn `${(b / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n// ---------------------------------------------------------------------------\n// DB Stats card\n// ---------------------------------------------------------------------------\n\nfunction FileSizesCard({\n\tfiles,\n\tpageSize,\n\tpageCount,\n\tfreelistPages,\n}: {\n\tfiles: DbStatsResponse[\"storage\"][\"files\"];\n\tpageSize: number;\n\tpageCount: number;\n\tfreelistPages: number;\n}): React.ReactElement {\n\tconst total = files.dbBytes + files.walBytes + files.shmBytes;\n\treturn (\n\t\t<div className=\"stat-section\">\n\t\t\t<div className=\"stat-label\">File Sizes</div>\n\t\t\t<table className=\"compact-table\">\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>sqlite.db</td>\n\t\t\t\t\t\t<td className=\"num\">{fmtBytes(files.dbBytes)}</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t{files.walBytes > 0 && (\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td>.wal</td>\n\t\t\t\t\t\t\t<td className=\"num\">{fmtBytes(files.walBytes)}</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t)}\n\t\t\t\t\t{files.shmBytes > 0 && (\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td>.shm</td>\n\t\t\t\t\t\t\t<td className=\"num\">{fmtBytes(files.shmBytes)}</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t)}\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>Total</td>\n\t\t\t\t\t\t<td className=\"num\">{fmtBytes(total)}</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>Page size</td>\n\t\t\t\t\t\t<td className=\"num\">{fmtBytes(pageSize)}</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>Pages</td>\n\t\t\t\t\t\t<td className=\"num\">\n\t\t\t\t\t\t\t{pageCount.toLocaleString()} ({freelistPages.toLocaleString()}{\" \"}\n\t\t\t\t\t\t\tfree)\n\t\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>\n\t);\n}\n\nfunction TableRowCountsCard({\n\ttables,\n}: {\n\ttables: DbStatsResponse[\"tables\"];\n}): React.ReactElement {\n\tconst totalRows = tables.reduce((s, t) => s + Math.max(0, t.rowCount), 0);\n\treturn (\n\t\t<div className=\"stat-section\">\n\t\t\t<div className=\"stat-label\">\n\t\t\t\tTable Row Counts ({totalRows.toLocaleString()} total)\n\t\t\t</div>\n\t\t\t<table className=\"compact-table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>Table</th>\n\t\t\t\t\t\t<th className=\"num\">Rows</th>\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{tables.map((t) => (\n\t\t\t\t\t\t<tr key={t.table}>\n\t\t\t\t\t\t\t<td>{t.table}</td>\n\t\t\t\t\t\t\t<td className=\"num\">\n\t\t\t\t\t\t\t\t{t.rowCount >= 0 ? t.rowCount.toLocaleString() : \"—\"}\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</tbody>\n\t\t\t</table>\n\t\t</div>\n\t);\n}\n\nfunction DbStatsCard({\n\tdata,\n\tloading,\n\terror,\n}: {\n\tdata: DbStatsResponse | null;\n\tloading: boolean;\n\terror: Error | null;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"card\">\n\t\t\t<div className=\"card-header\">DB Stats</div>\n\t\t\t<div className=\"card-body\">\n\t\t\t\t{loading && !data && <span className=\"text-muted\">Loading…</span>}\n\t\t\t\t{error && !data && <span className=\"text-error\">{error.message}</span>}\n\t\t\t\t{data && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<FileSizesCard\n\t\t\t\t\t\t\tfiles={data.storage.files}\n\t\t\t\t\t\t\tpageSize={data.storage.pageSize}\n\t\t\t\t\t\t\tpageCount={data.storage.pageCount}\n\t\t\t\t\t\t\tfreelistPages={data.storage.freelistPages}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<TableRowCountsCard tables={data.tables} />\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Schema Health card\n// ---------------------------------------------------------------------------\n\nfunction ColumnAuditCard({\n\tcolumns,\n}: {\n\tcolumns: SchemaHealthResponse[\"columns\"];\n}): React.ReactElement {\n\tconst missing = columns.filter((c) => !c.present);\n\treturn (\n\t\t<div className=\"stat-section\">\n\t\t\t<div className=\"stat-label\">\n\t\t\t\tColumn Audit ({columns.length} columns, {missing.length} missing)\n\t\t\t</div>\n\t\t\t<table className=\"compact-table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>Table</th>\n\t\t\t\t\t\t<th>Column</th>\n\t\t\t\t\t\t<th>Decl</th>\n\t\t\t\t\t\t<th>Status</th>\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{columns.map((c) => (\n\t\t\t\t\t\t<tr key={`${c.table}.${c.column}`}>\n\t\t\t\t\t\t\t<td>{c.table}</td>\n\t\t\t\t\t\t\t<td>{c.column}</td>\n\t\t\t\t\t\t\t<td className=\"text-mono\">{c.expectedDecl}</td>\n\t\t\t\t\t\t\t<td className={c.present ? \"text-ok\" : \"text-error\"}>\n\t\t\t\t\t\t\t\t{c.present ? \"✓\" : \"MISSING\"}\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</tbody>\n\t\t\t</table>\n\t\t</div>\n\t);\n}\n\nfunction SchemaHealthCard({\n\tdata,\n\tloading,\n\terror,\n}: {\n\tdata: SchemaHealthResponse | null;\n\tloading: boolean;\n\terror: Error | null;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"card\">\n\t\t\t<div className=\"card-header\">\n\t\t\t\tSchema Health\n\t\t\t\t{data && (\n\t\t\t\t\t<span className={`badge ${data.healthy ? \"badge-ok\" : \"badge-bad\"}`}>\n\t\t\t\t\t\t{data.healthy ? \"HEALTHY\" : \"DEGRADED\"}\n\t\t\t\t\t</span>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<div className=\"card-body\">\n\t\t\t\t{loading && !data && <span className=\"text-muted\">Loading…</span>}\n\t\t\t\t{error && !data && <span className=\"text-error\">{error.message}</span>}\n\t\t\t\t{data && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<div className=\"stat-row\">\n\t\t\t\t\t\t\t<span className=\"stat-label\">Schema version</span>\n\t\t\t\t\t\t\t<span className=\"num\">{data.schemaVersion}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"stat-row\">\n\t\t\t\t\t\t\t<span className=\"stat-label\">Integrity</span>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tclassName={\n\t\t\t\t\t\t\t\t\tdata.integrity[0] === \"ok\" ? \"text-ok\" : \"text-error\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{data.integrity.join(\"; \")}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<ColumnAuditCard columns={data.columns} />\n\t\t\t\t\t\t{data.fkCheck.length > 0 && (\n\t\t\t\t\t\t\t<div className=\"stat-section\">\n\t\t\t\t\t\t\t\t<div className=\"stat-label text-warn\">\n\t\t\t\t\t\t\t\t\tFK Check ({data.fkCheck.length})\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t{data.fkCheck.map((line, i) => (\n\t\t\t\t\t\t\t\t\t<div key={i} className=\"text-warn text-mono\">\n\t\t\t\t\t\t\t\t\t\t{line}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Actions card\n// ---------------------------------------------------------------------------\n\nfunction ActionsCard(): React.ReactElement {\n\tconst [results, setResults] = useState<MaintenanceActionResult[]>([]);\n\tconst [running, setRunning] = useState<string | null>(null);\n\tconst [days, setDays] = useState(\"30\");\n\n\tconst handleAction = useCallback(\n\t\tasync (def: ActionDef) => {\n\t\t\tconst action: MaintenanceAction = def.daysOld\n\t\t\t\t? { action: \"prune\", daysOld: Number(days) }\n\t\t\t\t: ({ action: def.key } as MaintenanceAction);\n\n\t\t\tsetRunning(def.key);\n\t\t\ttry {\n\t\t\t\tconst res = await postMaintenanceAction(action);\n\t\t\t\tsetResults((prev) =>\n\t\t\t\t\t[{ ...res, timestamp: Date.now() }, ...prev].slice(0, 20),\n\t\t\t\t);\n\t\t\t} catch (err) {\n\t\t\t\tsetResults((prev) =>\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toperation: def.key,\n\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\taffected: 0,\n\t\t\t\t\t\t\treclaimedBytes: 0,\n\t\t\t\t\t\t\tsummary: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...prev,\n\t\t\t\t\t].slice(0, 20),\n\t\t\t\t);\n\t\t\t} finally {\n\t\t\t\tsetRunning(null);\n\t\t\t}\n\t\t},\n\t\t[days],\n\t);\n\n\treturn (\n\t\t<div className=\"card\">\n\t\t\t<div className=\"card-header\">Actions</div>\n\t\t\t<div className=\"card-body\">\n\t\t\t\t<div className=\"action-grid\">\n\t\t\t\t\t{ACTIONS.map((def) => {\n\t\t\t\t\t\tconst isRunning = running === def.key;\n\t\t\t\t\t\tconst lastResult = results.find((r) => r.operation === def.key);\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<div key={def.key} className=\"action-item\">\n\t\t\t\t\t\t\t\t<div className=\"action-info\">\n\t\t\t\t\t\t\t\t\t<div className=\"action-label\">\n\t\t\t\t\t\t\t\t\t\t{def.label}\n\t\t\t\t\t\t\t\t\t\t{def.dangerous && (\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"badge badge-warn\">DESTRUCTIVE</span>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t<div className=\"action-desc\">{def.desc}</div>\n\t\t\t\t\t\t\t\t\t{lastResult && (\n\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\tclassName={`action-result ${lastResult.success ? \"text-ok\" : \"text-error\"}`}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{lastResult.summary}\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"action-controls\">\n\t\t\t\t\t\t\t\t\t{def.daysOld && (\n\t\t\t\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\t\t\t\t\tmin={1}\n\t\t\t\t\t\t\t\t\t\t\tmax={365}\n\t\t\t\t\t\t\t\t\t\t\tvalue={days}\n\t\t\t\t\t\t\t\t\t\t\tonChange={(e) => setDays(e.target.value)}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"days-input\"\n\t\t\t\t\t\t\t\t\t\t\tdisabled={isRunning}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\tclassName={`btn ${def.dangerous ? \"btn-danger\" : \"btn-primary\"}`}\n\t\t\t\t\t\t\t\t\t\tdisabled={running !== null}\n\t\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\t\tif (def.confirm && !window.confirm(def.confirm)) return;\n\t\t\t\t\t\t\t\t\t\t\thandleAction(def);\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{isRunning ? \"Running…\" : \"Run\"}\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t);\n\t\t\t\t\t})}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Debug bundle card — gather diagnostic info for bug reports\n// ---------------------------------------------------------------------------\n\nfunction DebugBundleCard(): React.ReactElement {\n\tconst [bundle, setBundle] = useState<DebugBundleResponse | null>(null);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<string | null>(null);\n\tconst [showJson, setShowJson] = useState(false);\n\n\tconst gather = useCallback(async () => {\n\t\tsetLoading(true);\n\t\tsetError(null);\n\t\ttry {\n\t\t\tconst res = await fetchDebugBundle();\n\t\t\tsetBundle(res);\n\t\t\tsetShowJson(true);\n\t\t} catch (err) {\n\t\t\tsetError(err instanceof Error ? err.message : String(err));\n\t\t} finally {\n\t\t\tsetLoading(false);\n\t\t}\n\t}, []);\n\n\tconst copyToClipboard = useCallback(() => {\n\t\tif (!bundle) return;\n\t\tconst text = JSON.stringify(bundle, null, 2);\n\t\tvoid navigator.clipboard.writeText(text).catch(() => {});\n\t}, [bundle]);\n\n\tconst downloadJson = useCallback(() => {\n\t\tif (!bundle) return;\n\t\tconst text = JSON.stringify(bundle, null, 2);\n\t\tconst blob = new Blob([text], { type: \"application/json\" });\n\t\tconst url = URL.createObjectURL(blob);\n\t\tconst a = document.createElement(\"a\");\n\t\ta.href = url;\n\t\ta.download = `mega-compact-debug-bundle-${bundle.builtAt}.json`;\n\t\ta.click();\n\t\tURL.revokeObjectURL(url);\n\t}, [bundle]);\n\n\tconst criticalCount = bundle?.criticalEvents.length ?? 0;\n\n\treturn (\n\t\t<div className=\"card\">\n\t\t\t<div className=\"card-header\">\n\t\t\t\tDebug Bundle\n\t\t\t\t{criticalCount > 0 && (\n\t\t\t\t\t<span className=\"text-warn\" style={{ marginLeft: \"1em\" }}>\n\t\t\t\t\t\t{criticalCount} critical event{criticalCount !== 1 ? \"s\" : \"\"} found\n\t\t\t\t\t</span>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<div className=\"card-body\">\n\t\t\t\t<p className=\"text-muted\" style={{ marginBottom: \"0.75em\" }}>\n\t\t\t\t\tGather a diagnostic bundle (recent events, config flags, schema health,\n\t\t\t\t\tstore stats) to attach to a bug report. Critical/compaction events are\n\t\t\t\t\thighlighted.\n\t\t\t\t</p>\n\t\t\t\t<button onClick={gather} disabled={loading} style={{ marginRight: \"0.5em\" }}>\n\t\t\t\t\t{loading ? \"Gathering…\" : \"Gather Debug Logs\"}\n\t\t\t\t</button>\n\t\t\t\t{error && <div className=\"text-error\">{error}</div>}\n\t\t\t\t{bundle && showJson && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<div style={{ marginTop: \"0.75em\", marginBottom: \"0.5em\" }}>\n\t\t\t\t\t\t\t<button onClick={copyToClipboard} style={{ marginRight: \"0.5em\" }}>\n\t\t\t\t\t\t\t\tCopy to clipboard\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t<button onClick={downloadJson}>Download JSON</button>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tonClick={() => setShowJson((v) => !v)}\n\t\t\t\t\t\t\t\tstyle={{ marginLeft: \"0.5em\" }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{showJson ? \"Hide\" : \"Show\"}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t{criticalCount > 0 && (\n\t\t\t\t\t\t\t<div className=\"stat-section\">\n\t\t\t\t\t\t\t\t<div className=\"stat-label text-warn\">\n\t\t\t\t\t\t\t\t\tCritical events ({criticalCount})\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<pre className=\"text-mono\" style={{ maxHeight: \"12em\", overflow: \"auto\" }}>\n\t\t\t\t\t\t\t\t\t{JSON.stringify(bundle.criticalEvents, null, 2)}\n\t\t\t\t\t\t\t\t</pre>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<pre className=\"text-mono\" style={{ maxHeight: \"24em\", overflow: \"auto\" }}>\n\t\t\t\t\t\t\t{JSON.stringify(bundle, null, 2)}\n\t\t\t\t\t\t</pre>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Main tab component\n// ---------------------------------------------------------------------------\n\nexport default function MaintenanceTab(): React.ReactElement {\n\tconst {\n\t\tdata: dbStats,\n\t\tloading: statsLoading,\n\t\terror: statsError,\n\t} = useApi<DbStatsResponse>(\n\t\tuseCallback(() => fetchDbStats(), []),\n\t\t{ pollInterval: 15000 },\n\t);\n\n\tconst {\n\t\tdata: schemaHealth,\n\t\tloading: healthLoading,\n\t\terror: healthError,\n\t} = useApi<SchemaHealthResponse>(\n\t\tuseCallback(() => fetchSchemaHealth(), []),\n\t\t{ pollInterval: 10000 },\n\t);\n\n\treturn (\n\t\t<div className=\"maintenance-tab\">\n\t\t\t<div className=\"card-grid\">\n\t\t\t\t<SchemaHealthCard\n\t\t\t\t\tdata={schemaHealth}\n\t\t\t\t\tloading={healthLoading}\n\t\t\t\t\terror={healthError}\n\t\t\t\t/>\n\t\t\t\t<DbStatsCard data={dbStats} loading={statsLoading} error={statsError} />\n\t\t\t</div>\n\t\t\t<ActionsCard />\n\t\t\t<DebugBundleCard />\n\t\t</div>\n\t);\n}\n"],"names":["ACTIONS","fmtBytes","b","FileSizesCard","files","pageSize","pageCount","freelistPages","total","jsxs","jsx","TableRowCountsCard","tables","totalRows","s","t","DbStatsCard","data","loading","error","Fragment","ColumnAuditCard","columns","missing","c","SchemaHealthCard","line","i","ActionsCard","results","setResults","useState","running","setRunning","days","setDays","handleAction","useCallback","def","action","res","postMaintenanceAction","prev","err","isRunning","lastResult","r","e","DebugBundleCard","bundle","setBundle","setLoading","setError","showJson","setShowJson","gather","fetchDebugBundle","copyToClipboard","text","downloadJson","blob","url","a","criticalCount","v","MaintenanceTab","dbStats","statsLoading","statsError","useApi","fetchDbStats","schemaHealth","healthLoading","healthError","fetchSchemaHealth"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{j as s,r as p}from"./index-
|
|
2
|
-
//# sourceMappingURL=MemoryMapTab-
|
|
1
|
+
import{j as s,r as p}from"./index-B8k19B9g.js";const S={checkpoint:"#6366f1",turn:"#58a6ff","turn-content":"#22c55e",memory:"#f59e0b"},q={checkpoint:"Checkpoint",turn:"Turn","turn-content":"Turn Content",memory:"Memory"};function V(o,n){return`M 0,-${n} L ${o},0 L 0,${n} L -${o},0 Z`}function z(o){return!o||o==="active"?1:.5}function B(o,n,c,m,t,d,l){const h=d?S[m]??"#6366f1":"#d1d5db",i=t?"#ef4444":"none",u=z(l);switch(m){case"checkpoint":return s.jsx("circle",{cx:o,cy:n,r:t?c+3:c,fill:h,opacity:u,stroke:i,strokeWidth:t?2:0});case"turn":return s.jsx("circle",{cx:o,cy:n,r:t?c+3:c,fill:"none",stroke:h,strokeWidth:2.5,opacity:u});case"turn-content":return s.jsxs("g",{children:[s.jsx("circle",{cx:o,cy:n,r:t?c+3:c,fill:"none",stroke:h,strokeWidth:2.5,opacity:u}),s.jsx("circle",{cx:o,cy:n,r:Math.max(3,c*.3),fill:h,opacity:u})]});case"memory":const x=c*.85,j=c*.85;return s.jsx("path",{d:V(x,j),transform:`translate(${o}, ${n})`,fill:h,opacity:u,stroke:i,strokeWidth:t?2:0})}}const U=5e3,A=.005,P=.01,_=.9,Y=.1,$=50;function Q(o){const n=o.nodes.map((t,d)=>{const l=2*Math.PI*d/Math.max(o.nodes.length,1),h=200;return{...t,pos:{x:Math.cos(l)*h+300,y:Math.sin(l)*h+200},vx:0,vy:0,pinned:!1}}),c=new Map;n.forEach((t,d)=>c.set(t.id,d));const m=o.edges.map(t=>{const d=c.get(t.source),l=c.get(t.target);return d===void 0||l===void 0||d===l?null:{source:d,target:l,weight:t.weight,type:t.type}}).filter(t=>t!==null);return{nodes:n,edges:m}}function X(o){const{nodes:n,edges:c}=o,m=n.length;if(m!==0)for(let t=0;t<m;t++){if(n[t].pinned)continue;let d=0,l=0;for(let i=0;i<m;i++){if(t===i)continue;const u=n[t].pos.x-n[i].pos.x,x=n[t].pos.y-n[i].pos.y,j=u*u+x*x||1,b=U/j,g=Math.sqrt(j);d+=u/g*b,l+=x/g*b}for(const i of c){let u;if(i.source===t)u=i.target;else if(i.target===t)u=i.source;else continue;const x=n[u].pos.x-n[t].pos.x,j=n[u].pos.y-n[t].pos.y;d+=x*A*i.weight,l+=j*A*i.weight}d-=n[t].pos.x*P,l-=n[t].pos.y*P,n[t].vx=(n[t].vx+d)*_,n[t].vy=(n[t].vy+l)*_;const h=Math.sqrt(n[t].vx*n[t].vx+n[t].vy*n[t].vy);h>$&&(n[t].vx=n[t].vx/h*$,n[t].vy=n[t].vy/h*$),h>Y&&(n[t].pos.x+=n[t].vx,n[t].pos.y+=n[t].vy)}}const Z=300,J=.3,k=900,w=600,y=40;function M(o){switch(o){case"temporal":return"#6366f1";case"semantic":return"#22c55e";case"raptor_parent":return"#f59e0b"}}const N=({color:o,shape:n,label:c})=>{const m={display:"inline-block",width:"10px",height:"10px",verticalAlign:"middle",marginRight:"3px",borderRadius:n.startsWith("hollow")||n==="filled-circle"?"50%":void 0};let t;return n==="line"?s.jsx("span",{style:{color:o,marginRight:"6px"},children:c}):(n==="filled-circle"?t=s.jsx("span",{style:{...m,backgroundColor:o}}):n==="hollow-circle"?t=s.jsx("span",{style:{...m,border:`2px solid ${o}`,backgroundColor:"transparent"}}):n==="hollow-ring"?t=s.jsx("span",{style:{...m,border:`2px solid ${o}`,backgroundColor:"transparent",position:"relative"},children:s.jsx("span",{style:{display:"block",width:"4px",height:"4px",borderRadius:"50%",backgroundColor:o,margin:"2px auto"}})}):t=s.jsx("span",{style:{...m,clipPath:"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)",backgroundColor:o}}),s.jsxs(s.Fragment,{children:[s.jsxs("span",{className:"memory-map-legend-item",children:[t,c]})," "]}))},ee=()=>{const[o,n]=p.useState(null),[c,m]=p.useState(!0),[t,d]=p.useState(null),[l,h]=p.useState(null),[i,u]=p.useState(""),[x]=p.useState(""),[j,b]=p.useState(0),g=p.useRef(null),C=p.useRef(0);p.useEffect(()=>{let e=!1;const r=new URLSearchParams;return x&&r.set("sessionId",x),r.set("threshold","0.7"),r.set("maxEdgesPerNode","4"),m(!0),d(null),fetch(`/api/memory-map?${r.toString()}`).then(a=>{if(!a.ok)throw new Error(`HTTP ${a.status}`);return a.json()}).then(a=>{e||(n(a),g.current=Q(a),b(1),m(!1))}).catch(a=>{e||(d(a instanceof Error?a.message:"Unknown error"),m(!1))}),()=>{e=!0,cancelAnimationFrame(C.current)}},[x]),p.useEffect(()=>{if(!g.current||j===0)return;const e=g.current;let r=0;const a=()=>{r>=Z||(X(e),r++,b(r),C.current=requestAnimationFrame(a))};return C.current=requestAnimationFrame(a),()=>cancelAnimationFrame(C.current)},[j]);const W=p.useCallback((e,r)=>{const a=g.current;a&&(a.nodes[r].pinned=!a.nodes[r].pinned,a.nodes[r].pinned||(a.nodes[r].vx=0,a.nodes[r].vy=0),h(f=>f?.id===e.id?null:e),b(f=>f+1))},[]),L=p.useMemo(()=>{const e=g.current;if(!e||!i)return null;const r=i.toLowerCase();return new Set(e.nodes.map((a,f)=>a.summaryTruncated.toLowerCase().includes(r)||a.label.toLowerCase().includes(r)?f:-1).filter(a=>a>=0))},[i]),E=p.useMemo(()=>{const e=o?.validation;return e?e.gatesPassed<e.gatesRun?{level:"red",label:"Gate failure"}:e.warnings.length>0?{level:"yellow",label:`${e.warnings.length} warning(s)`}:{level:"green",label:"Healthy"}:{level:"yellow",label:"No validation"}},[o?.validation]),D={green:"#22c55e",yellow:"#eab308",red:"#ef4444"},F=p.useMemo(()=>{const e=o?.validation;if(!e)return`${o?.metadata.totalNodes??0} nodes`;const r=[];return e.sources.checkpoint>0&&r.push(`${e.sources.checkpoint} checkpoints`),e.sources.turn>0&&r.push(`${e.sources.turn} turns`),e.sources.turnContent>0&&r.push(`${e.sources.turnContent} turn-content`),e.sources.memory>0&&r.push(`${e.sources.memory} memories`),r.length===0&&r.push(`${o?.metadata.totalNodes??0} nodes`),r.join(" · ")},[o?.validation,o?.metadata.totalNodes]),I=p.useMemo(()=>{const e=o?.validation;if(!e)return"";const r=[];return r.push(e.sources.checkpoint>0?"✓ checkpoints":"✗ checkpoints"),r.push(e.sources.turn>0?"✓ turns":"✗ turns"),r.push(e.sources.turnContent>0?"✓ turn-content":"✗ turn-content"),r.push(e.sources.memory>0?"✓ memories":"✗ memories"),r.join(" | ")},[o?.validation]),O=p.useMemo(()=>{const e=o?.validation;return e?e.sources.checkpoint===0&&e.sources.turn===0&&e.sources.turnContent===0&&e.sources.memory===0:o?.metadata.totalNodes===0},[o?.validation,o?.metadata.totalNodes]);if(c)return s.jsx("div",{className:"memory-map-loading",children:"Loading memory graph..."});if(t)return s.jsxs("div",{className:"memory-map-error",children:[s.jsxs("p",{children:["Failed to load memory map: ",t]}),s.jsx("button",{className:"memory-map-retry-btn",onClick:()=>b(e=>e+1),children:"Retry"})]});if(!o||!g.current||O)return s.jsx("div",{className:"memory-map-empty",children:s.jsx("p",{children:"Memories appear after your first compaction. The graph shows checkpoints (compaction summaries) linked by semantic similarity and time. Run a longer session or lower the compaction tier to see it sooner."})});const v=g.current;return s.jsxs("div",{className:"memory-map-container",children:[s.jsxs("div",{className:"memory-map-toolbar",children:[s.jsx("input",{type:"text",placeholder:"Search memories...",value:i,onInput:e=>u(e.target.value),className:"memory-map-search"}),s.jsxs("span",{className:"memory-map-stats",children:[s.jsx("span",{className:"memory-map-count-badge",children:F}),s.jsx("br",{}),s.jsxs("span",{className:"memory-map-edges",children:[o.edges.length," edges"]})]}),s.jsx("span",{className:"memory-map-health-badge",style:{backgroundColor:D[E.level]??"#6b7280",color:"#fff",padding:"2px 8px",borderRadius:"10px",fontSize:"11px",fontWeight:600,marginLeft:"8px"},title:`Validation: ${E.label}`,children:E.level==="green"?"Healthy":E.level==="yellow"?"Warnings":"Critical"})]}),I?s.jsx("div",{className:"memory-map-source-avail",style:{fontSize:"11px",padding:"2px 12px",color:"#6b7280"},children:I}):null,s.jsxs("div",{className:"memory-map-legend",children:[s.jsx("span",{className:"memory-map-legend-section",children:"Nodes:"}),s.jsx(N,{type:"node",color:S.checkpoint,shape:"filled-circle",label:"Checkpoint"}),s.jsx(N,{type:"node",color:S.turn,shape:"hollow-circle",label:"Turn"}),s.jsx(N,{type:"node",color:S["turn-content"],shape:"hollow-ring",label:"Turn Content"}),s.jsx(N,{type:"node",color:S.memory,shape:"diamond",label:"Memory"}),s.jsx("span",{className:"memory-map-legend-sep",children:"|"}),s.jsx("span",{className:"memory-map-legend-section",children:"Edges:"}),s.jsx(N,{type:"edge",color:M("semantic"),shape:"line",label:"Semantic"}),s.jsx(N,{type:"edge",color:M("temporal"),shape:"line",label:"Temporal"}),s.jsx(N,{type:"edge",color:M("raptor_parent"),shape:"line",label:"Raptor"})]}),s.jsxs("svg",{width:k,height:w,viewBox:`0 0 ${k} ${w}`,className:"memory-map-svg",children:[v.edges.map((e,r)=>{const a=v.nodes[e.source],f=v.nodes[e.target],T=M(e.type),R=Math.max(1,e.weight*2.5);return s.jsx("line",{x1:y+a.pos.x/(v.nodes.length||1)*(k-2*y),y1:y+a.pos.y/(v.nodes.length||1)*(w-2*y),x2:y+f.pos.x/(v.nodes.length||1)*(k-2*y),y2:y+f.pos.y/(v.nodes.length||1)*(w-2*y),stroke:T,strokeWidth:R,opacity:J},`edge-${r}`)}),v.nodes.map((e,r)=>{const a=y+e.pos.x/(v.nodes.length||1)*(k-2*y),f=y+e.pos.y/(v.nodes.length||1)*(w-2*y),T=Math.min(20,8+e.tokenEstimate/500),R=L?L.has(r):!0,G=l?.id===e.id,H=e.label.length>20?e.label.slice(0,18)+"...":e.label;return s.jsxs("g",{className:"memory-map-node-group",onClick:()=>W(e,r),style:{cursor:"pointer"},children:[B(a,f,T,e.nodeType,G,R,e.dedupStatus),s.jsx("text",{x:a,y:f+T+12,textAnchor:"middle",fontSize:"9px",fill:"#374151",className:"memory-map-label",children:H})]},`node-${r}`)})]}),l?s.jsxs("div",{className:"memory-map-detail",children:[s.jsxs("h3",{children:[s.jsx("span",{className:"memory-map-detail-type",style:{display:"inline-block",fontSize:"12px",fontWeight:400,color:"#6b7280",marginRight:"6px"},children:q[l.nodeType]}),l.label]}),s.jsx("p",{children:l.summaryTruncated}),l.topicSummary?s.jsxs("p",{className:"memory-map-topic",children:["Topic: ",l.topicSummary]}):null,s.jsxs("p",{children:["Tokens: ",l.tokenEstimate," | Decisions: ",l.decisionCount]}),s.jsxs("p",{children:["Session: ",l.sessionId]}),s.jsxs("p",{children:["Raptor Level: ",l.raptorLevel]}),s.jsx("p",{className:"memory-map-snippet",children:l.textSnippet})]}):null]})};export{ee as default};
|
|
2
|
+
//# sourceMappingURL=MemoryMapTab-w5BZP3i-.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MemoryMapTab-tVRREYiG.js","sources":["../../src/memory-map-shapes.tsx","../../src/memory-map-layout.ts","../../src/tabs/MemoryMapTab.tsx"],"sourcesContent":["/**\n * memory-map-shapes.tsx — Node shape rendering utilities for MemoryMapTab (D3).\n *\n * Node shape encodes nodeType: checkpoint = filled circle, turn = hollow circle,\n * turn-content = hollow+ring, memory = diamond.\n * Delegate-shell pattern: thin rendering helpers, no state, no side effects.\n */\nimport type React from \"react\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type NodeType = \"checkpoint\" | \"turn\" | \"turn-content\" | \"memory\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nexport const NODE_COLORS: Record<NodeType, string> = {\n checkpoint: \"#6366f1\",\n turn: \"#58a6ff\",\n \"turn-content\": \"#22c55e\",\n memory: \"#f59e0b\",\n};\n\nexport const NODE_TYPE_LABELS: Record<NodeType, string> = {\n checkpoint: \"Checkpoint\",\n turn: \"Turn\",\n \"turn-content\": \"Turn Content\",\n memory: \"Memory\",\n};\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** SVG path for a diamond centered at (0,0) with given half-width/height. */\nfunction diamondPath(hw: number, hh: number): string {\n return `M 0,-${hh} L ${hw},0 L 0,${hh} L -${hw},0 Z`;\n}\n\nfunction nodeOpacity(dedupStatus: string | undefined): number {\n if (!dedupStatus || dedupStatus === \"active\") return 1;\n return 0.5;\n}\n\n// ---------------------------------------------------------------------------\n// Render function\n// ---------------------------------------------------------------------------\n\n/** Render an SVG shape for a node based on its nodeType. */\nexport function renderNodeShape(\n cx: number,\n cy: number,\n radius: number,\n nodeType: NodeType,\n isSelected: boolean,\n isFiltered: boolean,\n dedupStatus: string | undefined,\n): React.ReactElement {\n const fill = isFiltered ? NODE_COLORS[nodeType] ?? \"#6366f1\" : \"#d1d5db\";\n const strokeColor = isSelected ? \"#ef4444\" : \"none\";\n const opacity = nodeOpacity(dedupStatus);\n\n switch (nodeType) {\n case \"checkpoint\":\n return (\n <circle\n cx={cx}\n cy={cy}\n r={isSelected ? radius + 3 : radius}\n fill={fill}\n opacity={opacity}\n stroke={strokeColor}\n strokeWidth={isSelected ? 2 : 0}\n />\n );\n case \"turn\":\n return (\n <circle\n cx={cx}\n cy={cy}\n r={isSelected ? radius + 3 : radius}\n fill=\"none\"\n stroke={fill}\n strokeWidth={2.5}\n opacity={opacity}\n />\n );\n case \"turn-content\":\n return (\n <g>\n <circle\n cx={cx}\n cy={cy}\n r={isSelected ? radius + 3 : radius}\n fill=\"none\"\n stroke={fill}\n strokeWidth={2.5}\n opacity={opacity}\n />\n <circle\n cx={cx}\n cy={cy}\n r={Math.max(3, radius * 0.3)}\n fill={fill}\n opacity={opacity}\n />\n </g>\n );\n case \"memory\":\n const hw = radius * 0.85;\n const hh = radius * 0.85;\n return (\n <path\n d={diamondPath(hw, hh)}\n transform={`translate(${cx}, ${cy})`}\n fill={fill}\n opacity={opacity}\n stroke={strokeColor}\n strokeWidth={isSelected ? 2 : 0}\n />\n );\n }\n}\n","/**\n * memory-map-layout.ts — Force-directed layout engine for MemoryMapTab (D3).\n *\n * Uses Coulomb repulsion + Hooke attraction + center gravity to arrange nodes.\n * No external graph library. Mutates layout in place.\n * Self-contained types: only needs id + edges from graph data.\n */\n\n// ---------------------------------------------------------------------------\n// Types (self-contained — mirrors the subset used by the layout engine)\n// ---------------------------------------------------------------------------\n\ninterface GraphNodeMin {\n readonly id: string;\n readonly nodeType: string;\n readonly label: string;\n readonly summaryTruncated: string;\n readonly tokenEstimate: number;\n readonly timestamp: number;\n readonly dedupStatus: string | undefined;\n readonly raptorLevel: number;\n readonly topicSummary: string | undefined;\n readonly decisionCount: number;\n readonly textSnippet: string;\n readonly sessionId: string;\n}\n\ninterface GraphEdgeMin {\n readonly source: string;\n readonly target: string;\n readonly weight: number;\n readonly type: \"temporal\" | \"semantic\" | \"raptor_parent\";\n}\n\nexport interface Position {\n x: number;\n y: number;\n}\n\nexport interface LayoutNode extends GraphNodeMin {\n pos: Position;\n vx: number;\n vy: number;\n pinned: boolean;\n}\n\nexport interface LayoutEdge {\n source: number;\n target: number;\n weight: number;\n type: GraphEdge[\"type\"];\n}\n\nexport interface Layout {\n nodes: LayoutNode[];\n edges: LayoutEdge[];\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst REPULSION = 5_000;\nconst ATTRACTION = 0.005;\nconst CENTER_GRAVITY = 0.01;\nconst DAMPING = 0.9;\nconst MIN_VELOCITY = 0.1;\nconst SPEED_LIMIT = 50;\n\n// ---------------------------------------------------------------------------\n// Build\n// ---------------------------------------------------------------------------\n\n/** Build initial layout from graph data. */\nexport function buildLayout(data: { nodes: GraphNodeMin[]; edges: GraphEdgeMin[] }): Layout {\n const nodes: LayoutNode[] = data.nodes.map((n, i) => {\n const angle = (2 * Math.PI * i) / Math.max(data.nodes.length, 1);\n const radius = 200;\n return {\n ...n,\n pos: { x: Math.cos(angle) * radius + 300, y: Math.sin(angle) * radius + 200 },\n vx: 0,\n vy: 0,\n pinned: false,\n };\n });\n\n const nodeIndex = new Map<string, number>();\n nodes.forEach((n, i) => nodeIndex.set(n.id, i));\n\n const edges: LayoutEdge[] = data.edges\n .map((e) => {\n const si = nodeIndex.get(e.source);\n const ti = nodeIndex.get(e.target);\n if (si === undefined || ti === undefined || si === ti) return null;\n return { source: si, target: ti, weight: e.weight, type: e.type };\n })\n .filter((e): e is LayoutEdge => e !== null);\n\n return { nodes, edges };\n}\n\n// ---------------------------------------------------------------------------\n// Apply forces\n// ---------------------------------------------------------------------------\n\n/** Apply one iteration of the force simulation. Mutates layout in place. */\nexport function applyForces(layout: Layout): void {\n const { nodes, edges } = layout;\n const n = nodes.length;\n if (n === 0) return;\n\n for (let i = 0; i < n; i++) {\n if (nodes[i].pinned) continue;\n let fx = 0;\n let fy = 0;\n\n // Coulomb repulsion\n for (let j = 0; j < n; j++) {\n if (i === j) continue;\n const dx = nodes[i].pos.x - nodes[j].pos.x;\n const dy = nodes[i].pos.y - nodes[j].pos.y;\n const distSq = dx * dx + dy * dy || 1;\n const force = REPULSION / distSq;\n const dist = Math.sqrt(distSq);\n fx += (dx / dist) * force;\n fy += (dy / dist) * force;\n }\n\n // Hooke attraction along edges\n for (const e of edges) {\n let other: number;\n if (e.source === i) other = e.target;\n else if (e.target === i) other = e.source;\n else continue;\n const dx = nodes[other].pos.x - nodes[i].pos.x;\n const dy = nodes[other].pos.y - nodes[i].pos.y;\n const dist = Math.sqrt(dx * dx + dy * dy) || 1;\n fx += dx * ATTRACTION * e.weight;\n fy += dy * ATTRACTION * e.weight;\n }\n\n // Center gravity\n fx -= nodes[i].pos.x * CENTER_GRAVITY;\n fy -= nodes[i].pos.y * CENTER_GRAVITY;\n\n nodes[i].vx = (nodes[i].vx + fx) * DAMPING;\n nodes[i].vy = (nodes[i].vy + fy) * DAMPING;\n\n const speed = Math.sqrt(nodes[i].vx * nodes[i].vx + nodes[i].vy * nodes[i].vy);\n if (speed > SPEED_LIMIT) {\n nodes[i].vx = (nodes[i].vx / speed) * SPEED_LIMIT;\n nodes[i].vy = (nodes[i].vy / speed) * SPEED_LIMIT;\n }\n\n if (speed > MIN_VELOCITY) {\n nodes[i].pos.x += nodes[i].vx;\n nodes[i].pos.y += nodes[i].vy;\n }\n }\n}\n","/**\n * MemoryMapTab.tsx — D3 memory map with force-directed graph.\n * Node shape encodes nodeType: checkpoint=filled circle, turn=hollow circle,\n * turn-content=hollow+ring, memory=diamond.\n * Fetches from /api/memory-map, renders SVG force layout.\n */\nimport type React from \"react\";\nimport { useEffect, useRef, useState, useCallback, useMemo } from \"react\";\nimport { renderNodeShape, NODE_COLORS, NODE_TYPE_LABELS } from \"../memory-map-shapes.js\";\nimport type { NodeType } from \"../memory-map-shapes.js\";\nimport { buildLayout, applyForces } from \"../memory-map-layout.js\";\nimport type { LayoutNode, LayoutEdge } from \"../memory-map-layout.js\";\n\n// Types (mirror of api-contracts/memory-map.ts — client-side only)\n\ninterface GraphNode {\n id: string;\n sessionId: string;\n label: string;\n summaryTruncated: string;\n tokenEstimate: number;\n timestamp: number;\n dedupStatus: string | undefined;\n raptorLevel: number;\n topicSummary: string | undefined;\n decisionCount: number;\n textSnippet: string;\n /** Source type discriminator for UI node-shape encoding. */\n nodeType: \"checkpoint\" | \"turn\" | \"turn-content\" | \"memory\";\n}\n\ninterface GraphEdge {\n source: string;\n target: string;\n weight: number;\n type: \"temporal\" | \"semantic\" | \"raptor_parent\";\n}\n\ninterface GraphValidationReport {\n readonly gatesRun: number;\n readonly gatesPassed: number;\n readonly dropped: { nodes: number; edges: number };\n readonly warnings: Array<{ gate: string; code: string; count: number }>;\n readonly sources: {\n checkpoint: number;\n turn: number;\n turnContent: number;\n memory: number;\n };\n readonly builtAt: number;\n}\n\ninterface GraphMetadata {\n totalNodes: number;\n totalEdges: number;\n avgWeight: number;\n nodeTypeBreakdown: Record<string, number>;\n edgeTypeBreakdown: Record<string, number>;\n}\n\ninterface MemoryMapResponse {\n nodes: GraphNode[];\n edges: GraphEdge[];\n metadata: GraphMetadata;\n /** Validation report from the 9-gate pipeline. Optional for backward compat. */\n validation?: GraphValidationReport;\n}\n\n// Simulation rendering constants (layout math is in memory-map-layout.ts)\n\nconst MAX_ITERATIONS = 300;\nconst EDGE_ALPHA = 0.3;\nconst SVG_WIDTH = 900;\nconst SVG_HEIGHT = 600;\nconst PADDING = 40;\n\n// Helpers\n\nfunction edgeColor(type: GraphEdge[\"type\"]): string {\n switch (type) {\n case \"temporal\":\n return \"#6366f1\"; // indigo\n case \"semantic\":\n return \"#22c55e\"; // green\n case \"raptor_parent\":\n return \"#f59e0b\"; // amber\n }\n}\n\n// Minimal legend swatch component\ninterface SwatchProps {\n type: \"node\" | \"edge\";\n color: string;\n shape: \"filled-circle\" | \"hollow-circle\" | \"hollow-ring\" | \"diamond\" | \"line\";\n label: string;\n}\nconst Swatch: React.FC<SwatchProps> = ({ color, shape, label }) => {\n const base: React.CSSProperties = {\n display: \"inline-block\",\n width: \"10px\",\n height: \"10px\",\n verticalAlign: \"middle\",\n marginRight: \"3px\",\n borderRadius: shape.startsWith(\"hollow\") || shape === \"filled-circle\" ? \"50%\" : undefined,\n };\n let swatch: JSX.Element;\n if (shape === \"line\") {\n return <span style={{ color, marginRight: \"6px\" }}>{label}</span>;\n } else if (shape === \"filled-circle\") {\n swatch = <span style={{ ...base, backgroundColor: color }} />;\n } else if (shape === \"hollow-circle\") {\n swatch = <span style={{ ...base, border: `2px solid ${color}`, backgroundColor: \"transparent\" }} />;\n } else if (shape === \"hollow-ring\") {\n swatch = (\n <span style={{ ...base, border: `2px solid ${color}`, backgroundColor: \"transparent\", position: \"relative\" }}>\n <span style={{ display: \"block\", width: \"4px\", height: \"4px\", borderRadius: \"50%\", backgroundColor: color, margin: \"2px auto\" }} />\n </span>\n );\n } else {\n swatch = <span style={{ ...base, clipPath: \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\", backgroundColor: color }} />;\n }\n return <><span className=\"memory-map-legend-item\">{swatch}{label}</span> </>;\n};\n\n// Force simulation engine (delegated to memory-map-layout.ts)\nconst MemoryMapTab: React.FC = () => {\n const [data, setData] = useState<MemoryMapResponse | null>(null);\n const [loading, setLoading] = useState<boolean>(true);\n const [error, setError] = useState<string | null>(null);\n const [selectedNode, setSelectedNode] = useState<GraphNode | null>(null);\n const [searchQuery, setSearchQuery] = useState<string>(\"\");\n const [filterSession] = useState<string>(\"\");\n const [frame, setFrame] = useState<number>(0);\n\n const layoutRef = useRef<{ nodes: LayoutNode[]; edges: LayoutEdge[] } | null>(null);\n const animRef = useRef<number>(0);\n\n // Fetch graph data when filterSession changes\n useEffect(() => {\n let cancelled = false;\n const params = new URLSearchParams();\n if (filterSession) params.set(\"sessionId\", filterSession);\n params.set(\"threshold\", \"0.7\");\n params.set(\"maxEdgesPerNode\", \"4\");\n\n setLoading(true);\n setError(null);\n\n fetch(`/api/memory-map?${params.toString()}`)\n .then((r) => {\n if (!r.ok) throw new Error(`HTTP ${r.status}`);\n return r.json() as Promise<MemoryMapResponse>;\n })\n .then((d) => {\n if (!cancelled) {\n setData(d);\n layoutRef.current = buildLayout(d);\n setFrame(1);\n setLoading(false);\n }\n })\n .catch((e: unknown) => {\n if (!cancelled) {\n setError(e instanceof Error ? e.message : \"Unknown error\");\n setLoading(false);\n }\n });\n\n return () => {\n cancelled = true;\n cancelAnimationFrame(animRef.current);\n };\n }, [filterSession]);\n\n // Run force simulation via requestAnimationFrame\n useEffect(() => {\n if (!layoutRef.current || frame === 0) return;\n\n const layout = layoutRef.current;\n let iter = 0;\n\n const tick = () => {\n if (iter >= MAX_ITERATIONS) return;\n applyForces(layout);\n iter++;\n setFrame(iter);\n animRef.current = requestAnimationFrame(tick);\n };\n\n animRef.current = requestAnimationFrame(tick);\n return () => cancelAnimationFrame(animRef.current);\n }, [frame]);\n\n // Toggle pin / select a node\n const handleNodeClick = useCallback((node: LayoutNode, index: number) => {\n const layout = layoutRef.current;\n if (!layout) return;\n layout.nodes[index].pinned = !layout.nodes[index].pinned;\n if (!layout.nodes[index].pinned) {\n layout.nodes[index].vx = 0;\n layout.nodes[index].vy = 0;\n }\n setSelectedNode((prev) => (prev?.id === node.id ? null : (node as unknown as GraphNode)));\n setFrame((s) => s + 1);\n }, []);\n\n // Filtered node indices for search\n const filteredSet = useMemo<Set<number> | null>(() => {\n const layout = layoutRef.current;\n if (!layout || !searchQuery) return null;\n const q = searchQuery.toLowerCase();\n return new Set(\n layout.nodes\n .map((n, i) =>\n n.summaryTruncated.toLowerCase().includes(q) || n.label.toLowerCase().includes(q) ? i : -1,\n )\n .filter((i) => i >= 0),\n );\n }, [searchQuery]);\n\n // Health indicator helpers (D3)\n\n /**\n * Derive graph health from validation report:\n * green = all gates passed + no warnings\n * yellow = warnings present but no critical gate failed\n * red = a critical gate (gatesRun > gatesPassed) failed\n */\n const graphHealth = useMemo<{ level: \"green\" | \"yellow\" | \"red\"; label: string }>(() => {\n const v = data?.validation;\n if (!v) return { level: \"yellow\", label: \"No validation\" };\n if (v.gatesPassed < v.gatesRun) return { level: \"red\", label: \"Gate failure\" };\n if (v.warnings.length > 0) return { level: \"yellow\", label: `${v.warnings.length} warning(s)` };\n return { level: \"green\", label: \"Healthy\" };\n }, [data?.validation]);\n\n const healthColor: Record<string, string> = {\n green: \"#22c55e\",\n yellow: \"#eab308\",\n red: \"#ef4444\",\n };\n\n // Source availability indicators (D3)\n\n /** Count badge fragments from validation.sources. */\n const countBadge = useMemo<string>(() => {\n const v = data?.validation;\n if (!v) {\n const totalNodes = data?.metadata.totalNodes ?? 0;\n return `${totalNodes} nodes`;\n }\n const parts: string[] = [];\n if (v.sources.checkpoint > 0) parts.push(`${v.sources.checkpoint} checkpoints`);\n if (v.sources.turn > 0) parts.push(`${v.sources.turn} turns`);\n if (v.sources.turnContent > 0) parts.push(`${v.sources.turnContent} turn-content`);\n if (v.sources.memory > 0) parts.push(`${v.sources.memory} memories`);\n if (parts.length === 0) {\n parts.push(`${data?.metadata.totalNodes ?? 0} nodes`);\n }\n return parts.join(\" · \");\n }, [data?.validation, data?.metadata.totalNodes]);\n\n /** Per-source availability: ✓ for available sources, ✗ for empty ones. */\n const sourceAvail = useMemo<string>(() => {\n const v = data?.validation;\n if (!v) return \"\";\n const parts: string[] = [];\n parts.push(v.sources.checkpoint > 0 ? \"✓ checkpoints\" : \"✗ checkpoints\");\n parts.push(v.sources.turn > 0 ? \"✓ turns\" : \"✗ turns\");\n parts.push(v.sources.turnContent > 0 ? \"✓ turn-content\" : \"✗ turn-content\");\n parts.push(v.sources.memory > 0 ? \"✓ memories\" : \"✗ memories\");\n return parts.join(\" | \");\n }, [data?.validation]);\n\n /** Whether all four sources are empty (true empty state). */\n const allSourcesEmpty = useMemo<boolean>(() => {\n const v = data?.validation;\n if (!v) return data?.metadata.totalNodes === 0;\n return (\n v.sources.checkpoint === 0 &&\n v.sources.turn === 0 &&\n v.sources.turnContent === 0 &&\n v.sources.memory === 0\n );\n }, [data?.validation, data?.metadata.totalNodes]);\n\n // Loading state\n\n if (loading) {\n return <div className=\"memory-map-loading\">Loading memory graph...</div>;\n }\n\n // Error state\n\n if (error) {\n return (\n <div className=\"memory-map-error\">\n <p>Failed to load memory map: {error}</p>\n <button\n className=\"memory-map-retry-btn\"\n onClick={() => setFrame((s) => s + 1)}\n >\n Retry\n </button>\n </div>\n );\n }\n\n // Empty state (D2)\n\n if (!data || !layoutRef.current || allSourcesEmpty) {\n return (\n <div className=\"memory-map-empty\">\n <p>Memories appear after your first compaction. The graph shows checkpoints (compaction summaries) linked by semantic similarity and time. Run a longer session or lower the compaction tier to see it sooner.</p>\n </div>\n );\n }\n\n const layout = layoutRef.current;\n\n // Render\n\n return (\n <div className=\"memory-map-container\">\n {/* Toolbar */}\n <div className=\"memory-map-toolbar\">\n <input\n type=\"text\"\n placeholder=\"Search memories...\"\n value={searchQuery}\n onInput={(e: React.FormEvent<HTMLInputElement>) =>\n setSearchQuery((e.target as HTMLInputElement).value)\n }\n className=\"memory-map-search\"\n />\n <span className=\"memory-map-stats\">\n {/* Count badge */}\n <span className=\"memory-map-count-badge\">{countBadge}</span>\n <br />\n <span className=\"memory-map-edges\">{data.edges.length} edges</span>\n </span>\n {/* Graph-health indicator */}\n <span\n className=\"memory-map-health-badge\"\n style={{\n backgroundColor: healthColor[graphHealth.level] ?? \"#6b7280\",\n color: \"#fff\",\n padding: \"2px 8px\",\n borderRadius: \"10px\",\n fontSize: \"11px\",\n fontWeight: 600,\n marginLeft: \"8px\",\n }}\n title={`Validation: ${graphHealth.label}`}\n >\n {graphHealth.level === \"green\" ? \"Healthy\" : graphHealth.level === \"yellow\" ? \"Warnings\" : \"Critical\"}\n </span>\n </div>\n\n {/* Source availability indicators */}\n {sourceAvail ? (\n <div className=\"memory-map-source-avail\" style={{ fontSize: \"11px\", padding: \"2px 12px\", color: \"#6b7280\" }}>\n {sourceAvail}\n </div>\n ) : null}\n\n {/* Legend — node types + edge types */}\n <div className=\"memory-map-legend\">\n <span className=\"memory-map-legend-section\">Nodes:</span>\n <Swatch type=\"node\" color={NODE_COLORS.checkpoint} shape=\"filled-circle\" label=\"Checkpoint\" />\n <Swatch type=\"node\" color={NODE_COLORS.turn} shape=\"hollow-circle\" label=\"Turn\" />\n <Swatch type=\"node\" color={NODE_COLORS[\"turn-content\"]} shape=\"hollow-ring\" label=\"Turn Content\" />\n <Swatch type=\"node\" color={NODE_COLORS.memory} shape=\"diamond\" label=\"Memory\" />\n <span className=\"memory-map-legend-sep\">|</span>\n <span className=\"memory-map-legend-section\">Edges:</span>\n <Swatch type=\"edge\" color={edgeColor(\"semantic\")} shape=\"line\" label=\"Semantic\" />\n <Swatch type=\"edge\" color={edgeColor(\"temporal\")} shape=\"line\" label=\"Temporal\" />\n <Swatch type=\"edge\" color={edgeColor(\"raptor_parent\")} shape=\"line\" label=\"Raptor\" />\n </div>\n\n {/* SVG graph */}\n <svg\n width={SVG_WIDTH}\n height={SVG_HEIGHT}\n viewBox={`0 0 ${SVG_WIDTH} ${SVG_HEIGHT}`}\n className=\"memory-map-svg\"\n >\n {/* Edges */}\n {layout.edges.map((e, i) => {\n const src = layout.nodes[e.source];\n const tgt = layout.nodes[e.target];\n const color = edgeColor(e.type);\n const strokeW = Math.max(1, e.weight * 2.5);\n return (\n <line\n key={`edge-${i}`}\n x1={PADDING + (src.pos.x / (layout.nodes.length || 1)) * (SVG_WIDTH - 2 * PADDING)}\n y1={PADDING + (src.pos.y / (layout.nodes.length || 1)) * (SVG_HEIGHT - 2 * PADDING)}\n x2={PADDING + (tgt.pos.x / (layout.nodes.length || 1)) * (SVG_WIDTH - 2 * PADDING)}\n y2={PADDING + (tgt.pos.y / (layout.nodes.length || 1)) * (SVG_HEIGHT - 2 * PADDING)}\n stroke={color}\n strokeWidth={strokeW}\n opacity={EDGE_ALPHA}\n />\n );\n })}\n\n {/* Nodes — shape encodes nodeType */}\n {layout.nodes.map((n, i) => {\n const cx =\n PADDING + (n.pos.x / (layout.nodes.length || 1)) * (SVG_WIDTH - 2 * PADDING);\n const cy =\n PADDING + (n.pos.y / (layout.nodes.length || 1)) * (SVG_HEIGHT - 2 * PADDING);\n const radius = Math.min(20, 8 + n.tokenEstimate / 500);\n const isFiltered = filteredSet ? filteredSet.has(i) : true;\n const isSelected = selectedNode?.id === n.id;\n const nodeLabel = n.label.length > 20 ? n.label.slice(0, 18) + \"...\" : n.label;\n\n return (\n <g\n key={`node-${i}`}\n className=\"memory-map-node-group\"\n onClick={() => handleNodeClick(n, i)}\n style={{ cursor: \"pointer\" }}\n >\n {renderNodeShape(cx, cy, radius, n.nodeType as NodeType, isSelected, isFiltered, n.dedupStatus)}\n <text\n x={cx}\n y={cy + radius + 12}\n textAnchor=\"middle\"\n fontSize=\"9px\"\n fill=\"#374151\"\n className=\"memory-map-label\"\n >\n {nodeLabel}\n </text>\n </g>\n );\n })}\n </svg>\n\n {/* Node detail panel */}\n {selectedNode ? (\n <div className=\"memory-map-detail\">\n <h3>\n <span\n className=\"memory-map-detail-type\"\n style={{\n display: \"inline-block\",\n fontSize: \"12px\",\n fontWeight: 400,\n color: \"#6b7280\",\n marginRight: \"6px\",\n }}\n >\n {NODE_TYPE_LABELS[selectedNode.nodeType]}\n </span>\n {selectedNode.label}\n </h3>\n <p>{selectedNode.summaryTruncated}</p>\n {selectedNode.topicSummary ? (\n <p className=\"memory-map-topic\">Topic: {selectedNode.topicSummary}</p>\n ) : null}\n <p>\n Tokens: {selectedNode.tokenEstimate} | Decisions: {selectedNode.decisionCount}\n </p>\n <p>Session: {selectedNode.sessionId}</p>\n <p>Raptor Level: {selectedNode.raptorLevel}</p>\n <p className=\"memory-map-snippet\">{selectedNode.textSnippet}</p>\n </div>\n ) : null}\n </div>\n );\n};\n\nexport default MemoryMapTab;\n"],"names":["NODE_COLORS","NODE_TYPE_LABELS","diamondPath","hw","hh","nodeOpacity","dedupStatus","renderNodeShape","cx","cy","radius","nodeType","isSelected","isFiltered","fill","strokeColor","opacity","jsx","REPULSION","ATTRACTION","CENTER_GRAVITY","DAMPING","MIN_VELOCITY","SPEED_LIMIT","buildLayout","data","nodes","n","i","angle","nodeIndex","edges","e","si","ti","applyForces","layout","fx","fy","j","dx","dy","distSq","force","dist","other","speed","MAX_ITERATIONS","EDGE_ALPHA","SVG_WIDTH","SVG_HEIGHT","PADDING","edgeColor","type","Swatch","color","shape","label","base","swatch","jsxs","Fragment","MemoryMapTab","setData","useState","loading","setLoading","error","setError","selectedNode","setSelectedNode","searchQuery","setSearchQuery","filterSession","frame","setFrame","layoutRef","useRef","animRef","useEffect","cancelled","params","r","d","iter","tick","handleNodeClick","useCallback","node","index","prev","s","filteredSet","useMemo","q","graphHealth","v","healthColor","countBadge","parts","sourceAvail","allSourcesEmpty","src","tgt","strokeW","nodeLabel"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MemoryMapTab-w5BZP3i-.js","sources":["../../src/memory-map-shapes.tsx","../../src/memory-map-layout.ts","../../src/tabs/MemoryMapTab.tsx"],"sourcesContent":["/**\n * memory-map-shapes.tsx — Node shape rendering utilities for MemoryMapTab (D3).\n *\n * Node shape encodes nodeType: checkpoint = filled circle, turn = hollow circle,\n * turn-content = hollow+ring, memory = diamond.\n * Delegate-shell pattern: thin rendering helpers, no state, no side effects.\n */\nimport type React from \"react\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type NodeType = \"checkpoint\" | \"turn\" | \"turn-content\" | \"memory\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nexport const NODE_COLORS: Record<NodeType, string> = {\n checkpoint: \"#6366f1\",\n turn: \"#58a6ff\",\n \"turn-content\": \"#22c55e\",\n memory: \"#f59e0b\",\n};\n\nexport const NODE_TYPE_LABELS: Record<NodeType, string> = {\n checkpoint: \"Checkpoint\",\n turn: \"Turn\",\n \"turn-content\": \"Turn Content\",\n memory: \"Memory\",\n};\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** SVG path for a diamond centered at (0,0) with given half-width/height. */\nfunction diamondPath(hw: number, hh: number): string {\n return `M 0,-${hh} L ${hw},0 L 0,${hh} L -${hw},0 Z`;\n}\n\nfunction nodeOpacity(dedupStatus: string | undefined): number {\n if (!dedupStatus || dedupStatus === \"active\") return 1;\n return 0.5;\n}\n\n// ---------------------------------------------------------------------------\n// Render function\n// ---------------------------------------------------------------------------\n\n/** Render an SVG shape for a node based on its nodeType. */\nexport function renderNodeShape(\n cx: number,\n cy: number,\n radius: number,\n nodeType: NodeType,\n isSelected: boolean,\n isFiltered: boolean,\n dedupStatus: string | undefined,\n): React.ReactElement {\n const fill = isFiltered ? NODE_COLORS[nodeType] ?? \"#6366f1\" : \"#d1d5db\";\n const strokeColor = isSelected ? \"#ef4444\" : \"none\";\n const opacity = nodeOpacity(dedupStatus);\n\n switch (nodeType) {\n case \"checkpoint\":\n return (\n <circle\n cx={cx}\n cy={cy}\n r={isSelected ? radius + 3 : radius}\n fill={fill}\n opacity={opacity}\n stroke={strokeColor}\n strokeWidth={isSelected ? 2 : 0}\n />\n );\n case \"turn\":\n return (\n <circle\n cx={cx}\n cy={cy}\n r={isSelected ? radius + 3 : radius}\n fill=\"none\"\n stroke={fill}\n strokeWidth={2.5}\n opacity={opacity}\n />\n );\n case \"turn-content\":\n return (\n <g>\n <circle\n cx={cx}\n cy={cy}\n r={isSelected ? radius + 3 : radius}\n fill=\"none\"\n stroke={fill}\n strokeWidth={2.5}\n opacity={opacity}\n />\n <circle\n cx={cx}\n cy={cy}\n r={Math.max(3, radius * 0.3)}\n fill={fill}\n opacity={opacity}\n />\n </g>\n );\n case \"memory\":\n const hw = radius * 0.85;\n const hh = radius * 0.85;\n return (\n <path\n d={diamondPath(hw, hh)}\n transform={`translate(${cx}, ${cy})`}\n fill={fill}\n opacity={opacity}\n stroke={strokeColor}\n strokeWidth={isSelected ? 2 : 0}\n />\n );\n }\n}\n","/**\n * memory-map-layout.ts — Force-directed layout engine for MemoryMapTab (D3).\n *\n * Uses Coulomb repulsion + Hooke attraction + center gravity to arrange nodes.\n * No external graph library. Mutates layout in place.\n * Self-contained types: only needs id + edges from graph data.\n */\n\n// ---------------------------------------------------------------------------\n// Types (self-contained — mirrors the subset used by the layout engine)\n// ---------------------------------------------------------------------------\n\ninterface GraphNodeMin {\n readonly id: string;\n readonly nodeType: string;\n readonly label: string;\n readonly summaryTruncated: string;\n readonly tokenEstimate: number;\n readonly timestamp: number;\n readonly dedupStatus: string | undefined;\n readonly raptorLevel: number;\n readonly topicSummary: string | undefined;\n readonly decisionCount: number;\n readonly textSnippet: string;\n readonly sessionId: string;\n}\n\ninterface GraphEdgeMin {\n readonly source: string;\n readonly target: string;\n readonly weight: number;\n readonly type: \"temporal\" | \"semantic\" | \"raptor_parent\";\n}\n\nexport interface Position {\n x: number;\n y: number;\n}\n\nexport interface LayoutNode extends GraphNodeMin {\n pos: Position;\n vx: number;\n vy: number;\n pinned: boolean;\n}\n\nexport interface LayoutEdge {\n source: number;\n target: number;\n weight: number;\n type: GraphEdge[\"type\"];\n}\n\nexport interface Layout {\n nodes: LayoutNode[];\n edges: LayoutEdge[];\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst REPULSION = 5_000;\nconst ATTRACTION = 0.005;\nconst CENTER_GRAVITY = 0.01;\nconst DAMPING = 0.9;\nconst MIN_VELOCITY = 0.1;\nconst SPEED_LIMIT = 50;\n\n// ---------------------------------------------------------------------------\n// Build\n// ---------------------------------------------------------------------------\n\n/** Build initial layout from graph data. */\nexport function buildLayout(data: { nodes: GraphNodeMin[]; edges: GraphEdgeMin[] }): Layout {\n const nodes: LayoutNode[] = data.nodes.map((n, i) => {\n const angle = (2 * Math.PI * i) / Math.max(data.nodes.length, 1);\n const radius = 200;\n return {\n ...n,\n pos: { x: Math.cos(angle) * radius + 300, y: Math.sin(angle) * radius + 200 },\n vx: 0,\n vy: 0,\n pinned: false,\n };\n });\n\n const nodeIndex = new Map<string, number>();\n nodes.forEach((n, i) => nodeIndex.set(n.id, i));\n\n const edges: LayoutEdge[] = data.edges\n .map((e) => {\n const si = nodeIndex.get(e.source);\n const ti = nodeIndex.get(e.target);\n if (si === undefined || ti === undefined || si === ti) return null;\n return { source: si, target: ti, weight: e.weight, type: e.type };\n })\n .filter((e): e is LayoutEdge => e !== null);\n\n return { nodes, edges };\n}\n\n// ---------------------------------------------------------------------------\n// Apply forces\n// ---------------------------------------------------------------------------\n\n/** Apply one iteration of the force simulation. Mutates layout in place. */\nexport function applyForces(layout: Layout): void {\n const { nodes, edges } = layout;\n const n = nodes.length;\n if (n === 0) return;\n\n for (let i = 0; i < n; i++) {\n if (nodes[i].pinned) continue;\n let fx = 0;\n let fy = 0;\n\n // Coulomb repulsion\n for (let j = 0; j < n; j++) {\n if (i === j) continue;\n const dx = nodes[i].pos.x - nodes[j].pos.x;\n const dy = nodes[i].pos.y - nodes[j].pos.y;\n const distSq = dx * dx + dy * dy || 1;\n const force = REPULSION / distSq;\n const dist = Math.sqrt(distSq);\n fx += (dx / dist) * force;\n fy += (dy / dist) * force;\n }\n\n // Hooke attraction along edges\n for (const e of edges) {\n let other: number;\n if (e.source === i) other = e.target;\n else if (e.target === i) other = e.source;\n else continue;\n const dx = nodes[other].pos.x - nodes[i].pos.x;\n const dy = nodes[other].pos.y - nodes[i].pos.y;\n const dist = Math.sqrt(dx * dx + dy * dy) || 1;\n fx += dx * ATTRACTION * e.weight;\n fy += dy * ATTRACTION * e.weight;\n }\n\n // Center gravity\n fx -= nodes[i].pos.x * CENTER_GRAVITY;\n fy -= nodes[i].pos.y * CENTER_GRAVITY;\n\n nodes[i].vx = (nodes[i].vx + fx) * DAMPING;\n nodes[i].vy = (nodes[i].vy + fy) * DAMPING;\n\n const speed = Math.sqrt(nodes[i].vx * nodes[i].vx + nodes[i].vy * nodes[i].vy);\n if (speed > SPEED_LIMIT) {\n nodes[i].vx = (nodes[i].vx / speed) * SPEED_LIMIT;\n nodes[i].vy = (nodes[i].vy / speed) * SPEED_LIMIT;\n }\n\n if (speed > MIN_VELOCITY) {\n nodes[i].pos.x += nodes[i].vx;\n nodes[i].pos.y += nodes[i].vy;\n }\n }\n}\n","/**\n * MemoryMapTab.tsx — D3 memory map with force-directed graph.\n * Node shape encodes nodeType: checkpoint=filled circle, turn=hollow circle,\n * turn-content=hollow+ring, memory=diamond.\n * Fetches from /api/memory-map, renders SVG force layout.\n */\nimport type React from \"react\";\nimport { useEffect, useRef, useState, useCallback, useMemo } from \"react\";\nimport { renderNodeShape, NODE_COLORS, NODE_TYPE_LABELS } from \"../memory-map-shapes.js\";\nimport type { NodeType } from \"../memory-map-shapes.js\";\nimport { buildLayout, applyForces } from \"../memory-map-layout.js\";\nimport type { LayoutNode, LayoutEdge } from \"../memory-map-layout.js\";\n\n// Types (mirror of api-contracts/memory-map.ts — client-side only)\n\ninterface GraphNode {\n id: string;\n sessionId: string;\n label: string;\n summaryTruncated: string;\n tokenEstimate: number;\n timestamp: number;\n dedupStatus: string | undefined;\n raptorLevel: number;\n topicSummary: string | undefined;\n decisionCount: number;\n textSnippet: string;\n /** Source type discriminator for UI node-shape encoding. */\n nodeType: \"checkpoint\" | \"turn\" | \"turn-content\" | \"memory\";\n}\n\ninterface GraphEdge {\n source: string;\n target: string;\n weight: number;\n type: \"temporal\" | \"semantic\" | \"raptor_parent\";\n}\n\ninterface GraphValidationReport {\n readonly gatesRun: number;\n readonly gatesPassed: number;\n readonly dropped: { nodes: number; edges: number };\n readonly warnings: Array<{ gate: string; code: string; count: number }>;\n readonly sources: {\n checkpoint: number;\n turn: number;\n turnContent: number;\n memory: number;\n };\n readonly builtAt: number;\n}\n\ninterface GraphMetadata {\n totalNodes: number;\n totalEdges: number;\n avgWeight: number;\n nodeTypeBreakdown: Record<string, number>;\n edgeTypeBreakdown: Record<string, number>;\n}\n\ninterface MemoryMapResponse {\n nodes: GraphNode[];\n edges: GraphEdge[];\n metadata: GraphMetadata;\n /** Validation report from the 9-gate pipeline. Optional for backward compat. */\n validation?: GraphValidationReport;\n}\n\n// Simulation rendering constants (layout math is in memory-map-layout.ts)\n\nconst MAX_ITERATIONS = 300;\nconst EDGE_ALPHA = 0.3;\nconst SVG_WIDTH = 900;\nconst SVG_HEIGHT = 600;\nconst PADDING = 40;\n\n// Helpers\n\nfunction edgeColor(type: GraphEdge[\"type\"]): string {\n switch (type) {\n case \"temporal\":\n return \"#6366f1\"; // indigo\n case \"semantic\":\n return \"#22c55e\"; // green\n case \"raptor_parent\":\n return \"#f59e0b\"; // amber\n }\n}\n\n// Minimal legend swatch component\ninterface SwatchProps {\n type: \"node\" | \"edge\";\n color: string;\n shape: \"filled-circle\" | \"hollow-circle\" | \"hollow-ring\" | \"diamond\" | \"line\";\n label: string;\n}\nconst Swatch: React.FC<SwatchProps> = ({ color, shape, label }) => {\n const base: React.CSSProperties = {\n display: \"inline-block\",\n width: \"10px\",\n height: \"10px\",\n verticalAlign: \"middle\",\n marginRight: \"3px\",\n borderRadius: shape.startsWith(\"hollow\") || shape === \"filled-circle\" ? \"50%\" : undefined,\n };\n let swatch: JSX.Element;\n if (shape === \"line\") {\n return <span style={{ color, marginRight: \"6px\" }}>{label}</span>;\n } else if (shape === \"filled-circle\") {\n swatch = <span style={{ ...base, backgroundColor: color }} />;\n } else if (shape === \"hollow-circle\") {\n swatch = <span style={{ ...base, border: `2px solid ${color}`, backgroundColor: \"transparent\" }} />;\n } else if (shape === \"hollow-ring\") {\n swatch = (\n <span style={{ ...base, border: `2px solid ${color}`, backgroundColor: \"transparent\", position: \"relative\" }}>\n <span style={{ display: \"block\", width: \"4px\", height: \"4px\", borderRadius: \"50%\", backgroundColor: color, margin: \"2px auto\" }} />\n </span>\n );\n } else {\n swatch = <span style={{ ...base, clipPath: \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\", backgroundColor: color }} />;\n }\n return <><span className=\"memory-map-legend-item\">{swatch}{label}</span> </>;\n};\n\n// Force simulation engine (delegated to memory-map-layout.ts)\nconst MemoryMapTab: React.FC = () => {\n const [data, setData] = useState<MemoryMapResponse | null>(null);\n const [loading, setLoading] = useState<boolean>(true);\n const [error, setError] = useState<string | null>(null);\n const [selectedNode, setSelectedNode] = useState<GraphNode | null>(null);\n const [searchQuery, setSearchQuery] = useState<string>(\"\");\n const [filterSession] = useState<string>(\"\");\n const [frame, setFrame] = useState<number>(0);\n\n const layoutRef = useRef<{ nodes: LayoutNode[]; edges: LayoutEdge[] } | null>(null);\n const animRef = useRef<number>(0);\n\n // Fetch graph data when filterSession changes\n useEffect(() => {\n let cancelled = false;\n const params = new URLSearchParams();\n if (filterSession) params.set(\"sessionId\", filterSession);\n params.set(\"threshold\", \"0.7\");\n params.set(\"maxEdgesPerNode\", \"4\");\n\n setLoading(true);\n setError(null);\n\n fetch(`/api/memory-map?${params.toString()}`)\n .then((r) => {\n if (!r.ok) throw new Error(`HTTP ${r.status}`);\n return r.json() as Promise<MemoryMapResponse>;\n })\n .then((d) => {\n if (!cancelled) {\n setData(d);\n layoutRef.current = buildLayout(d);\n setFrame(1);\n setLoading(false);\n }\n })\n .catch((e: unknown) => {\n if (!cancelled) {\n setError(e instanceof Error ? e.message : \"Unknown error\");\n setLoading(false);\n }\n });\n\n return () => {\n cancelled = true;\n cancelAnimationFrame(animRef.current);\n };\n }, [filterSession]);\n\n // Run force simulation via requestAnimationFrame\n useEffect(() => {\n if (!layoutRef.current || frame === 0) return;\n\n const layout = layoutRef.current;\n let iter = 0;\n\n const tick = () => {\n if (iter >= MAX_ITERATIONS) return;\n applyForces(layout);\n iter++;\n setFrame(iter);\n animRef.current = requestAnimationFrame(tick);\n };\n\n animRef.current = requestAnimationFrame(tick);\n return () => cancelAnimationFrame(animRef.current);\n }, [frame]);\n\n // Toggle pin / select a node\n const handleNodeClick = useCallback((node: LayoutNode, index: number) => {\n const layout = layoutRef.current;\n if (!layout) return;\n layout.nodes[index].pinned = !layout.nodes[index].pinned;\n if (!layout.nodes[index].pinned) {\n layout.nodes[index].vx = 0;\n layout.nodes[index].vy = 0;\n }\n setSelectedNode((prev) => (prev?.id === node.id ? null : (node as unknown as GraphNode)));\n setFrame((s) => s + 1);\n }, []);\n\n // Filtered node indices for search\n const filteredSet = useMemo<Set<number> | null>(() => {\n const layout = layoutRef.current;\n if (!layout || !searchQuery) return null;\n const q = searchQuery.toLowerCase();\n return new Set(\n layout.nodes\n .map((n, i) =>\n n.summaryTruncated.toLowerCase().includes(q) || n.label.toLowerCase().includes(q) ? i : -1,\n )\n .filter((i) => i >= 0),\n );\n }, [searchQuery]);\n\n // Health indicator helpers (D3)\n\n /**\n * Derive graph health from validation report:\n * green = all gates passed + no warnings\n * yellow = warnings present but no critical gate failed\n * red = a critical gate (gatesRun > gatesPassed) failed\n */\n const graphHealth = useMemo<{ level: \"green\" | \"yellow\" | \"red\"; label: string }>(() => {\n const v = data?.validation;\n if (!v) return { level: \"yellow\", label: \"No validation\" };\n if (v.gatesPassed < v.gatesRun) return { level: \"red\", label: \"Gate failure\" };\n if (v.warnings.length > 0) return { level: \"yellow\", label: `${v.warnings.length} warning(s)` };\n return { level: \"green\", label: \"Healthy\" };\n }, [data?.validation]);\n\n const healthColor: Record<string, string> = {\n green: \"#22c55e\",\n yellow: \"#eab308\",\n red: \"#ef4444\",\n };\n\n // Source availability indicators (D3)\n\n /** Count badge fragments from validation.sources. */\n const countBadge = useMemo<string>(() => {\n const v = data?.validation;\n if (!v) {\n const totalNodes = data?.metadata.totalNodes ?? 0;\n return `${totalNodes} nodes`;\n }\n const parts: string[] = [];\n if (v.sources.checkpoint > 0) parts.push(`${v.sources.checkpoint} checkpoints`);\n if (v.sources.turn > 0) parts.push(`${v.sources.turn} turns`);\n if (v.sources.turnContent > 0) parts.push(`${v.sources.turnContent} turn-content`);\n if (v.sources.memory > 0) parts.push(`${v.sources.memory} memories`);\n if (parts.length === 0) {\n parts.push(`${data?.metadata.totalNodes ?? 0} nodes`);\n }\n return parts.join(\" · \");\n }, [data?.validation, data?.metadata.totalNodes]);\n\n /** Per-source availability: ✓ for available sources, ✗ for empty ones. */\n const sourceAvail = useMemo<string>(() => {\n const v = data?.validation;\n if (!v) return \"\";\n const parts: string[] = [];\n parts.push(v.sources.checkpoint > 0 ? \"✓ checkpoints\" : \"✗ checkpoints\");\n parts.push(v.sources.turn > 0 ? \"✓ turns\" : \"✗ turns\");\n parts.push(v.sources.turnContent > 0 ? \"✓ turn-content\" : \"✗ turn-content\");\n parts.push(v.sources.memory > 0 ? \"✓ memories\" : \"✗ memories\");\n return parts.join(\" | \");\n }, [data?.validation]);\n\n /** Whether all four sources are empty (true empty state). */\n const allSourcesEmpty = useMemo<boolean>(() => {\n const v = data?.validation;\n if (!v) return data?.metadata.totalNodes === 0;\n return (\n v.sources.checkpoint === 0 &&\n v.sources.turn === 0 &&\n v.sources.turnContent === 0 &&\n v.sources.memory === 0\n );\n }, [data?.validation, data?.metadata.totalNodes]);\n\n // Loading state\n\n if (loading) {\n return <div className=\"memory-map-loading\">Loading memory graph...</div>;\n }\n\n // Error state\n\n if (error) {\n return (\n <div className=\"memory-map-error\">\n <p>Failed to load memory map: {error}</p>\n <button\n className=\"memory-map-retry-btn\"\n onClick={() => setFrame((s) => s + 1)}\n >\n Retry\n </button>\n </div>\n );\n }\n\n // Empty state (D2)\n\n if (!data || !layoutRef.current || allSourcesEmpty) {\n return (\n <div className=\"memory-map-empty\">\n <p>Memories appear after your first compaction. The graph shows checkpoints (compaction summaries) linked by semantic similarity and time. Run a longer session or lower the compaction tier to see it sooner.</p>\n </div>\n );\n }\n\n const layout = layoutRef.current;\n\n // Render\n\n return (\n <div className=\"memory-map-container\">\n {/* Toolbar */}\n <div className=\"memory-map-toolbar\">\n <input\n type=\"text\"\n placeholder=\"Search memories...\"\n value={searchQuery}\n onInput={(e: React.FormEvent<HTMLInputElement>) =>\n setSearchQuery((e.target as HTMLInputElement).value)\n }\n className=\"memory-map-search\"\n />\n <span className=\"memory-map-stats\">\n {/* Count badge */}\n <span className=\"memory-map-count-badge\">{countBadge}</span>\n <br />\n <span className=\"memory-map-edges\">{data.edges.length} edges</span>\n </span>\n {/* Graph-health indicator */}\n <span\n className=\"memory-map-health-badge\"\n style={{\n backgroundColor: healthColor[graphHealth.level] ?? \"#6b7280\",\n color: \"#fff\",\n padding: \"2px 8px\",\n borderRadius: \"10px\",\n fontSize: \"11px\",\n fontWeight: 600,\n marginLeft: \"8px\",\n }}\n title={`Validation: ${graphHealth.label}`}\n >\n {graphHealth.level === \"green\" ? \"Healthy\" : graphHealth.level === \"yellow\" ? \"Warnings\" : \"Critical\"}\n </span>\n </div>\n\n {/* Source availability indicators */}\n {sourceAvail ? (\n <div className=\"memory-map-source-avail\" style={{ fontSize: \"11px\", padding: \"2px 12px\", color: \"#6b7280\" }}>\n {sourceAvail}\n </div>\n ) : null}\n\n {/* Legend — node types + edge types */}\n <div className=\"memory-map-legend\">\n <span className=\"memory-map-legend-section\">Nodes:</span>\n <Swatch type=\"node\" color={NODE_COLORS.checkpoint} shape=\"filled-circle\" label=\"Checkpoint\" />\n <Swatch type=\"node\" color={NODE_COLORS.turn} shape=\"hollow-circle\" label=\"Turn\" />\n <Swatch type=\"node\" color={NODE_COLORS[\"turn-content\"]} shape=\"hollow-ring\" label=\"Turn Content\" />\n <Swatch type=\"node\" color={NODE_COLORS.memory} shape=\"diamond\" label=\"Memory\" />\n <span className=\"memory-map-legend-sep\">|</span>\n <span className=\"memory-map-legend-section\">Edges:</span>\n <Swatch type=\"edge\" color={edgeColor(\"semantic\")} shape=\"line\" label=\"Semantic\" />\n <Swatch type=\"edge\" color={edgeColor(\"temporal\")} shape=\"line\" label=\"Temporal\" />\n <Swatch type=\"edge\" color={edgeColor(\"raptor_parent\")} shape=\"line\" label=\"Raptor\" />\n </div>\n\n {/* SVG graph */}\n <svg\n width={SVG_WIDTH}\n height={SVG_HEIGHT}\n viewBox={`0 0 ${SVG_WIDTH} ${SVG_HEIGHT}`}\n className=\"memory-map-svg\"\n >\n {/* Edges */}\n {layout.edges.map((e, i) => {\n const src = layout.nodes[e.source];\n const tgt = layout.nodes[e.target];\n const color = edgeColor(e.type);\n const strokeW = Math.max(1, e.weight * 2.5);\n return (\n <line\n key={`edge-${i}`}\n x1={PADDING + (src.pos.x / (layout.nodes.length || 1)) * (SVG_WIDTH - 2 * PADDING)}\n y1={PADDING + (src.pos.y / (layout.nodes.length || 1)) * (SVG_HEIGHT - 2 * PADDING)}\n x2={PADDING + (tgt.pos.x / (layout.nodes.length || 1)) * (SVG_WIDTH - 2 * PADDING)}\n y2={PADDING + (tgt.pos.y / (layout.nodes.length || 1)) * (SVG_HEIGHT - 2 * PADDING)}\n stroke={color}\n strokeWidth={strokeW}\n opacity={EDGE_ALPHA}\n />\n );\n })}\n\n {/* Nodes — shape encodes nodeType */}\n {layout.nodes.map((n, i) => {\n const cx =\n PADDING + (n.pos.x / (layout.nodes.length || 1)) * (SVG_WIDTH - 2 * PADDING);\n const cy =\n PADDING + (n.pos.y / (layout.nodes.length || 1)) * (SVG_HEIGHT - 2 * PADDING);\n const radius = Math.min(20, 8 + n.tokenEstimate / 500);\n const isFiltered = filteredSet ? filteredSet.has(i) : true;\n const isSelected = selectedNode?.id === n.id;\n const nodeLabel = n.label.length > 20 ? n.label.slice(0, 18) + \"...\" : n.label;\n\n return (\n <g\n key={`node-${i}`}\n className=\"memory-map-node-group\"\n onClick={() => handleNodeClick(n, i)}\n style={{ cursor: \"pointer\" }}\n >\n {renderNodeShape(cx, cy, radius, n.nodeType as NodeType, isSelected, isFiltered, n.dedupStatus)}\n <text\n x={cx}\n y={cy + radius + 12}\n textAnchor=\"middle\"\n fontSize=\"9px\"\n fill=\"#374151\"\n className=\"memory-map-label\"\n >\n {nodeLabel}\n </text>\n </g>\n );\n })}\n </svg>\n\n {/* Node detail panel */}\n {selectedNode ? (\n <div className=\"memory-map-detail\">\n <h3>\n <span\n className=\"memory-map-detail-type\"\n style={{\n display: \"inline-block\",\n fontSize: \"12px\",\n fontWeight: 400,\n color: \"#6b7280\",\n marginRight: \"6px\",\n }}\n >\n {NODE_TYPE_LABELS[selectedNode.nodeType]}\n </span>\n {selectedNode.label}\n </h3>\n <p>{selectedNode.summaryTruncated}</p>\n {selectedNode.topicSummary ? (\n <p className=\"memory-map-topic\">Topic: {selectedNode.topicSummary}</p>\n ) : null}\n <p>\n Tokens: {selectedNode.tokenEstimate} | Decisions: {selectedNode.decisionCount}\n </p>\n <p>Session: {selectedNode.sessionId}</p>\n <p>Raptor Level: {selectedNode.raptorLevel}</p>\n <p className=\"memory-map-snippet\">{selectedNode.textSnippet}</p>\n </div>\n ) : null}\n </div>\n );\n};\n\nexport default MemoryMapTab;\n"],"names":["NODE_COLORS","NODE_TYPE_LABELS","diamondPath","hw","hh","nodeOpacity","dedupStatus","renderNodeShape","cx","cy","radius","nodeType","isSelected","isFiltered","fill","strokeColor","opacity","jsx","REPULSION","ATTRACTION","CENTER_GRAVITY","DAMPING","MIN_VELOCITY","SPEED_LIMIT","buildLayout","data","nodes","n","i","angle","nodeIndex","edges","e","si","ti","applyForces","layout","fx","fy","j","dx","dy","distSq","force","dist","other","speed","MAX_ITERATIONS","EDGE_ALPHA","SVG_WIDTH","SVG_HEIGHT","PADDING","edgeColor","type","Swatch","color","shape","label","base","swatch","jsxs","Fragment","MemoryMapTab","setData","useState","loading","setLoading","error","setError","selectedNode","setSelectedNode","searchQuery","setSearchQuery","filterSession","frame","setFrame","layoutRef","useRef","animRef","useEffect","cancelled","params","r","d","iter","tick","handleNodeClick","useCallback","node","index","prev","s","filteredSet","useMemo","q","graphHealth","v","healthColor","countBadge","parts","sourceAvail","allSourcesEmpty","src","tgt","strokeW","nodeLabel"],"mappings":"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"}
|
package/extensions/dashboard-client/dist/assets/{MetricsTab-CHblYuTY.js → MetricsTab-BBCXa3xS.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{j as e,u as o,r as x,i as j,c as N}from"./index-
|
|
2
|
-
//# sourceMappingURL=MetricsTab-
|
|
1
|
+
import{j as e,u as o,r as x,i as j,c as N}from"./index-B8k19B9g.js";function i(s){return s>=1e3?`${(s/1e3).toFixed(1)}s`:`${s.toFixed(0)}ms`}function c({value:s,max:a,colorClass:r}){const p=a>0?Math.max(0,Math.min(100,s/a*100)):0;return e.jsx("div",{className:"perf-bar-track",children:e.jsx("div",{className:`perf-bar-fill ${r}`,style:{width:`${p}%`}})})}function _({perf:s}){const a=Math.max(s.turn_latency_ms.p95,s.provider_latency_ms.p95,1),r=Math.max(s.tps.avg,1);return e.jsxs("div",{className:"perf-chart",children:[e.jsxs("div",{className:"perf-header",children:[e.jsx("h3",{children:"Performance"}),e.jsxs("span",{className:"perf-window",children:[s.windowMinutes,"min window · ",s.sampleCount," samples"]})]}),e.jsxs("div",{className:"perf-grid",children:[e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"Turn latency p50 / p95"}),e.jsxs("span",{className:"perf-value",children:[i(s.turn_latency_ms.p50)," /"," ",i(s.turn_latency_ms.p95)]}),e.jsx(c,{value:s.turn_latency_ms.p95,max:a,colorClass:"perf-blue"})]}),e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"Provider latency p50 / p95"}),e.jsxs("span",{className:"perf-value",children:[i(s.provider_latency_ms.p50)," /"," ",i(s.provider_latency_ms.p95)]}),e.jsx(c,{value:s.provider_latency_ms.p95,max:a,colorClass:"perf-purple"})]}),e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"Tokens/sec (avg)"}),e.jsx("span",{className:"perf-value",children:s.tps.avg.toFixed(1)}),e.jsx(c,{value:s.tps.avg,max:r,colorClass:"perf-green"})]}),e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"Cache hit (avg / latest)"}),e.jsxs("span",{className:"perf-value",children:[s.cache_hit_pct.avg.toFixed(1),"% /"," ",s.cache_hit_pct.latest.toFixed(1),"%"]}),e.jsx(c,{value:s.cache_hit_pct.avg,max:100,colorClass:"perf-green"})]}),e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"DB recompute p95"}),e.jsx("span",{className:"perf-value",children:i(s.db_recompute_ms.p95)}),e.jsx(c,{value:s.db_recompute_ms.p95,max:a,colorClass:"perf-yellow"})]}),e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"Disk write p95"}),e.jsx("span",{className:"perf-value",children:i(s.disk_write_ms.p95)}),e.jsx(c,{value:s.disk_write_ms.p95,max:a,colorClass:"perf-yellow"})]})]}),e.jsxs("div",{className:"perf-resources",children:[e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"RSS"}),e.jsxs("span",{className:"perf-value",children:[s.rss_mb.latest.toFixed(0)," MB"]})]}),e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"Heap"}),e.jsxs("span",{className:"perf-value",children:[s.heap_mb.latest.toFixed(0)," MB"]})]}),e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"CPU user"}),e.jsxs("span",{className:"perf-value",children:[(s.cpu_user_ms.latest/1e3).toFixed(1),"s"]})]}),e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"CPU sys"}),e.jsxs("span",{className:"perf-value",children:[(s.cpu_sys_ms.latest/1e3).toFixed(1),"s"]})]})]}),s.diag&&e.jsxs("div",{className:"perf-diag",children:[e.jsxs("span",{className:"perf-label",children:["Fast-gate fires: ",s.diag.ctxFastGate]}),e.jsxs("span",{className:"perf-label",children:["Live trim fires: ",s.diag.liveTrimFires]}),e.jsxs("span",{className:"perf-label",children:["Live trim replays: ",s.diag.liveTrimReplays]})]})]})}function t(s){return s==null?"—":s>=100?`${Math.round(s)}ms`:`${s.toFixed(1)}ms`}function n(s,a){return s==null||typeof s!="number"?"—":s.toFixed(a)}function u(s){return s==null?"—":String(s)}function l({label:s,value:a}){return e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:s}),e.jsx("span",{className:"perf-value",children:a})]})}function d({title:s,children:a}){return e.jsxs("div",{className:"perf-card",children:[e.jsx("h3",{className:"perf-card-title",children:s}),e.jsx("div",{className:"perf-card-body",children:a})]})}function f({perf:s}){const a=`${n(s.cpu_user_ms.latest,1)} / ${n(s.cpu_sys_ms.latest,1)} ms`;return e.jsxs("div",{className:"perf-cards-grid",children:[e.jsxs(d,{title:"Model latency",children:[e.jsx(l,{label:"Turn p50",value:t(s.turn_latency_ms.p50)}),e.jsx(l,{label:"Turn p95",value:t(s.turn_latency_ms.p95)}),e.jsx(l,{label:"Provider p50",value:t(s.provider_latency_ms.p50)}),e.jsx(l,{label:"Provider p95",value:t(s.provider_latency_ms.p95)})]}),e.jsxs(d,{title:"Throughput",children:[e.jsx(l,{label:"TPS (avg)",value:n(s.tps.avg,1)}),e.jsx(l,{label:"Cache hit %",value:`${n(s.cache_hit_pct.avg,1)}%`})]}),e.jsxs(d,{title:"Process",children:[e.jsx(l,{label:"RSS",value:`${n(s.rss_mb.latest,1)} MB`}),e.jsx(l,{label:"Heap",value:`${n(s.heap_mb.latest,1)} MB`}),e.jsx(l,{label:"CPU user / sys",value:a})]}),e.jsxs(d,{title:"Snapshot cost",children:[e.jsx(l,{label:"DB recompute p50",value:t(s.db_recompute_ms.p50)}),e.jsx(l,{label:"DB recompute p95",value:t(s.db_recompute_ms.p95)}),e.jsx(l,{label:"Disk write p50",value:t(s.disk_write_ms.p50)})]}),e.jsxs(d,{title:"TUI lag proxy",children:[e.jsx(l,{label:"Live-trim fires",value:u(s.diag?.liveTrimFires)}),e.jsx(l,{label:"Cache replays",value:u(s.diag?.liveTrimReplays)}),e.jsx(l,{label:"Fast-gate skips",value:u(s.diag?.ctxFastGate)}),e.jsx("span",{className:"perf-card-note",children:"skip vs recompute vs replay cadence"})]})]})}function m({label:s,value:a,title:r}){return e.jsxs("div",{className:"model-field",title:r,children:[e.jsx("span",{className:"model-field-label",children:s}),e.jsx("span",{className:"model-field-value",children:a})]})}function b({name:s,providerName:a,provider:r,inputRate:p,outputRate:h}){const v=a||r||"—";return e.jsxs("div",{className:"model-badge",children:[e.jsx(m,{label:"Model",value:s,title:"The model pi is currently using — its pricing drives the cost figure."}),e.jsx(m,{label:"Provider",value:v,title:"The provider serving the model."}),e.jsx(m,{label:"Input Rate",value:`$${p.toFixed(6)}`,title:"USD per input token, from the model's pricing."}),e.jsx(m,{label:"Output Rate",value:`$${h.toFixed(6)}`,title:"USD per output token, from the model's pricing."})]})}function y(){const{data:s,error:a}=o(x.useCallback(()=>j({minutes:30}),[]),{pollInterval:1e4}),{data:r}=o(x.useCallback(()=>N(),[]),{pollInterval:1e4});return a&&!s?e.jsxs("div",{className:"tab-stub",children:["Error loading perf: ",a.message]}):s?e.jsxs("div",{className:"metrics-tab",children:[r?.model&&e.jsx(b,{name:r.model.name,providerName:r.model.providerName,provider:r.model.provider,inputRate:r.model.inputRate,outputRate:r.model.outputRate}),e.jsx(_,{perf:s}),e.jsx(f,{perf:s}),e.jsxs("div",{className:"perf-footer",children:[s.sampleCount," samples · updated ",s.updatedAt]})]}):e.jsx("div",{className:"tab-stub",children:"Loading perf…"})}export{y as default};
|
|
2
|
+
//# sourceMappingURL=MetricsTab-BBCXa3xS.js.map
|