pi-mega-compact 0.11.1 → 0.11.2

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.
Files changed (53) hide show
  1. package/dist/extensions/dashboard-server/api-contracts/endpoints.js +19 -0
  2. package/dist/extensions/dashboard-server/api-contracts/maintenance.js +7 -0
  3. package/dist/extensions/dashboard-server/api-contracts.test.js +1 -1
  4. package/dist/extensions/dashboard-server/routes-maintenance.js +293 -0
  5. package/dist/extensions/dashboard-server/routes.js +1 -0
  6. package/dist/extensions/dashboard-server/server.js +3 -1
  7. package/dist/src/store/sqlite/maintenance.js +20 -1
  8. package/extensions/dashboard-client/dist/assets/{AchievementTiles-DZp_xQOW.js → AchievementTiles-Cml6YC8w.js} +2 -2
  9. package/extensions/dashboard-client/dist/assets/{AchievementTiles-DZp_xQOW.js.map → AchievementTiles-Cml6YC8w.js.map} +1 -1
  10. package/extensions/dashboard-client/dist/assets/{AchievementsTab-BzFHpAHM.js → AchievementsTab-B8NqDt7I.js} +2 -2
  11. package/extensions/dashboard-client/dist/assets/{AchievementsTab-BzFHpAHM.js.map → AchievementsTab-B8NqDt7I.js.map} +1 -1
  12. package/extensions/dashboard-client/dist/assets/{CacheTab-DEQbTq2T.js → CacheTab-BCLzVL4S.js} +2 -2
  13. package/extensions/dashboard-client/dist/assets/{CacheTab-DEQbTq2T.js.map → CacheTab-BCLzVL4S.js.map} +1 -1
  14. package/extensions/dashboard-client/dist/assets/{ConfigTab-DQ4FG33J.js → ConfigTab-CBYvp2mV.js} +2 -2
  15. package/extensions/dashboard-client/dist/assets/{ConfigTab-DQ4FG33J.js.map → ConfigTab-CBYvp2mV.js.map} +1 -1
  16. package/extensions/dashboard-client/dist/assets/{EventsTab-D5HoEVYo.js → EventsTab-DlTJqiDm.js} +2 -2
  17. package/extensions/dashboard-client/dist/assets/{EventsTab-D5HoEVYo.js.map → EventsTab-DlTJqiDm.js.map} +1 -1
  18. package/extensions/dashboard-client/dist/assets/{GameTab-Jzsc4yeY.js → GameTab-DkGTqKJW.js} +2 -2
  19. package/extensions/dashboard-client/dist/assets/{GameTab-Jzsc4yeY.js.map → GameTab-DkGTqKJW.js.map} +1 -1
  20. package/extensions/dashboard-client/dist/assets/MaintenanceTab-Cw43zmUx.js +2 -0
  21. package/extensions/dashboard-client/dist/assets/MaintenanceTab-Cw43zmUx.js.map +1 -0
  22. package/extensions/dashboard-client/dist/assets/{MetricsTab-D_XnsEYX.js → MetricsTab-BFo7pKM-.js} +2 -2
  23. package/extensions/dashboard-client/dist/assets/{MetricsTab-D_XnsEYX.js.map → MetricsTab-BFo7pKM-.js.map} +1 -1
  24. package/extensions/dashboard-client/dist/assets/{OverviewTab-BMREvAth.js → OverviewTab-CClCUd3-.js} +2 -2
  25. package/extensions/dashboard-client/dist/assets/{OverviewTab-BMREvAth.js.map → OverviewTab-CClCUd3-.js.map} +1 -1
  26. package/extensions/dashboard-client/dist/assets/{ReposTab-DuyhOktG.js → ReposTab-_3R4RSLZ.js} +2 -2
  27. package/extensions/dashboard-client/dist/assets/{ReposTab-DuyhOktG.js.map → ReposTab-_3R4RSLZ.js.map} +1 -1
  28. package/extensions/dashboard-client/dist/assets/{SessionsTab-mz_vz8i2.js → SessionsTab-CCYd-kSz.js} +2 -2
  29. package/extensions/dashboard-client/dist/assets/{SessionsTab-mz_vz8i2.js.map → SessionsTab-CCYd-kSz.js.map} +1 -1
  30. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-B8AIjNTY.js → TimeSavedCard-0TqsrY6y.js} +2 -2
  31. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-B8AIjNTY.js.map → TimeSavedCard-0TqsrY6y.js.map} +1 -1
  32. package/extensions/dashboard-client/dist/assets/{TopicsTab-DKuct4oD.js → TopicsTab-DRLJmVv0.js} +2 -2
  33. package/extensions/dashboard-client/dist/assets/{TopicsTab-DKuct4oD.js.map → TopicsTab-DRLJmVv0.js.map} +1 -1
  34. package/extensions/dashboard-client/dist/assets/{TurnsTab-11MGLxY8.js → TurnsTab-CLNM0T5R.js} +2 -2
  35. package/extensions/dashboard-client/dist/assets/{TurnsTab-11MGLxY8.js.map → TurnsTab-CLNM0T5R.js.map} +1 -1
  36. package/extensions/dashboard-client/dist/assets/{index-CqLN7STl.js → index-BcoSz-L4.js} +10 -10
  37. package/extensions/dashboard-client/dist/assets/{index-CqLN7STl.js.map → index-BcoSz-L4.js.map} +1 -1
  38. package/extensions/dashboard-client/dist/assets/{useSSE-CXrQSbVY.js → useSSE-Cezlih5V.js} +2 -2
  39. package/extensions/dashboard-client/dist/assets/{useSSE-CXrQSbVY.js.map → useSSE-Cezlih5V.js.map} +1 -1
  40. package/extensions/dashboard-client/dist/index.html +1 -1
  41. package/extensions/dashboard-client/src/App.tsx +5 -1
  42. package/extensions/dashboard-client/src/api/client.ts +23 -0
  43. package/extensions/dashboard-client/src/tabs/MaintenanceTab.tsx +293 -0
  44. package/extensions/dashboard-server/api-contracts/endpoints.ts +30 -0
  45. package/extensions/dashboard-server/api-contracts/index.ts +12 -0
  46. package/extensions/dashboard-server/api-contracts/maintenance.ts +84 -0
  47. package/extensions/dashboard-server/api-contracts.test.ts +1 -1
  48. package/extensions/dashboard-server/api-contracts.ts +9 -0
  49. package/extensions/dashboard-server/routes-maintenance.ts +345 -0
  50. package/extensions/dashboard-server/routes.ts +1 -0
  51. package/extensions/dashboard-server/server.ts +2 -0
  52. package/package.json +1 -1
  53. package/src/store/sqlite/maintenance.ts +20 -1
@@ -1,2 +1,2 @@
1
- import{j as e}from"./index-CqLN7STl.js";function l(a){const t=a??0;return t>=1048576?`${(t/1048576).toFixed(1)} MiB`:t>=1024?`${(t/1024).toFixed(1)} KiB`:`${t} B`}function n(a){const t=a??0;return t>=3600?`${(t/3600).toFixed(1)}h`:t>=60?`${Math.round(t/60)}m`:t>=1?`${t.toFixed(1)}s`:`${Math.round(t*1e3)}ms`}function r(a){const c=(a??0)*100;return c>=10?`${Math.round(c)}%`:`${c.toFixed(1)}%`}function s({label:a,value:t}){return e.jsxs("div",{className:"ov-stat-row",children:[e.jsx("span",{className:"ov-stat-label",children:a}),e.jsx("span",{className:"ov-stat-value",children:t})]})}function u(a){return e.jsxs("div",{className:"card cache-hits-card",children:[e.jsx("h3",{children:"💾 Cache Hits & Compactions"}),e.jsx(s,{label:"Cache Hits (session)",value:a.cacheHitsSession.toLocaleString()}),e.jsx(s,{label:"Cache Hits (total)",value:a.cacheHitsTotal.toLocaleString()}),e.jsx(s,{label:"Tokens Saved (session)",value:a.tokensSavedSession.toLocaleString()}),e.jsx(s,{label:"Tokens Saved (total)",value:a.tokensSavedTotal.toLocaleString()}),e.jsx(s,{label:"Compactions (session)",value:a.compactionsSession.toLocaleString()}),e.jsx(s,{label:"Compactions (total)",value:a.compactionsTotal.toLocaleString()})]})}function o({label:a,value:t}){return e.jsxs("div",{className:"ov-stat-row",children:[e.jsx("span",{className:"ov-stat-label",children:a}),e.jsx("span",{className:"ov-stat-value",children:t})]})}function d(a){return e.jsxs("div",{className:"card time-saved-card",children:[e.jsx("h3",{children:"⏱ Time Saved (est.)"}),e.jsx(o,{label:"Compact (session)",value:n(a.compactSessionSec)}),e.jsx(o,{label:"Compact (total)",value:n(a.compactTotalSec)}),e.jsx(o,{label:"Cache Hit (session)",value:n(a.cacheHitSessionSec)}),e.jsx(o,{label:"Cache Hit (total)",value:n(a.cacheHitTotalSec)})]})}export{u as C,d as T,l as a,r as f};
2
- //# sourceMappingURL=TimeSavedCard-B8AIjNTY.js.map
1
+ import{j as e}from"./index-BcoSz-L4.js";function l(a){const t=a??0;return t>=1048576?`${(t/1048576).toFixed(1)} MiB`:t>=1024?`${(t/1024).toFixed(1)} KiB`:`${t} B`}function n(a){const t=a??0;return t>=3600?`${(t/3600).toFixed(1)}h`:t>=60?`${Math.round(t/60)}m`:t>=1?`${t.toFixed(1)}s`:`${Math.round(t*1e3)}ms`}function r(a){const c=(a??0)*100;return c>=10?`${Math.round(c)}%`:`${c.toFixed(1)}%`}function s({label:a,value:t}){return e.jsxs("div",{className:"ov-stat-row",children:[e.jsx("span",{className:"ov-stat-label",children:a}),e.jsx("span",{className:"ov-stat-value",children:t})]})}function u(a){return e.jsxs("div",{className:"card cache-hits-card",children:[e.jsx("h3",{children:"💾 Cache Hits & Compactions"}),e.jsx(s,{label:"Cache Hits (session)",value:a.cacheHitsSession.toLocaleString()}),e.jsx(s,{label:"Cache Hits (total)",value:a.cacheHitsTotal.toLocaleString()}),e.jsx(s,{label:"Tokens Saved (session)",value:a.tokensSavedSession.toLocaleString()}),e.jsx(s,{label:"Tokens Saved (total)",value:a.tokensSavedTotal.toLocaleString()}),e.jsx(s,{label:"Compactions (session)",value:a.compactionsSession.toLocaleString()}),e.jsx(s,{label:"Compactions (total)",value:a.compactionsTotal.toLocaleString()})]})}function o({label:a,value:t}){return e.jsxs("div",{className:"ov-stat-row",children:[e.jsx("span",{className:"ov-stat-label",children:a}),e.jsx("span",{className:"ov-stat-value",children:t})]})}function d(a){return e.jsxs("div",{className:"card time-saved-card",children:[e.jsx("h3",{children:"⏱ Time Saved (est.)"}),e.jsx(o,{label:"Compact (session)",value:n(a.compactSessionSec)}),e.jsx(o,{label:"Compact (total)",value:n(a.compactTotalSec)}),e.jsx(o,{label:"Cache Hit (session)",value:n(a.cacheHitSessionSec)}),e.jsx(o,{label:"Cache Hit (total)",value:n(a.cacheHitTotalSec)})]})}export{u as C,d as T,l as a,r as f};
2
+ //# sourceMappingURL=TimeSavedCard-0TqsrY6y.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TimeSavedCard-B8AIjNTY.js","sources":["../../src/utils/format.ts","../../src/components/CacheHitsCard.tsx","../../src/components/TimeSavedCard.tsx"],"sourcesContent":["/**\n * dashboard-client/src/utils/format.ts — shared formatting helpers.\n *\n * Mirrors the format functions from the old static dashboard (html.ts)\n * so the React rewrite shows identical values.\n */\n\n/** Format bytes as KiB/MiB/B (matches html.ts fmtBytes). */\nexport function fmtBytes(b: number | null | undefined): string {\n\tconst n = b ?? 0;\n\tif (n >= 1_048_576) return `${(n / 1_048_576).toFixed(1)} MiB`;\n\tif (n >= 1024) return `${(n / 1024).toFixed(1)} KiB`;\n\treturn `${n} B`;\n}\n\n/** Format seconds as h/m/s/ms (matches html.ts fmtSec). */\nexport function fmtSec(s: number | null | undefined): string {\n\tconst n = s ?? 0;\n\tif (n >= 3600) return `${(n / 3600).toFixed(1)}h`;\n\tif (n >= 60) return `${Math.round(n / 60)}m`;\n\tif (n >= 1) return `${n.toFixed(1)}s`;\n\treturn `${Math.round(n * 1000)}ms`;\n}\n\n/**\n * Display a 0–1 fraction as a percentage string.\n * Uses one decimal place below 10%, rounded above (matches html.ts pct logic).\n */\nexport function fmtPctFromFraction(\n\tv: number | null | undefined,\n): string {\n\tconst n = v ?? 0;\n\tconst pct = n * 100;\n\tif (pct >= 10) return `${Math.round(pct)}%`;\n\treturn `${pct.toFixed(1)}%`;\n}\n\n/** Round a 0–1 fraction to a one-decimal percentage (for trophy values). */\nexport function fmtPct(v: number | null | undefined): string {\n\tconst n = v ?? 0;\n\treturn `${Math.round(n * 10) / 10}%`;\n}\n\n/** Format milliseconds (matches html.ts fmtMs). */\nexport function fmtMs(v: number | null | undefined): string {\n\tif (v == null) return \"\\u2014\";\n\treturn v >= 100 ? `${Math.round(v)}ms` : `${v.toFixed(1)}ms`;\n}\n\n/** Format a number with fixed decimals or em-dash for null (matches fmtNum). */\nexport function fmtNum(\n\tv: number | null | undefined,\n\tdec: number,\n): string {\n\tif (v == null || typeof v !== \"number\") return \"\\u2014\";\n\treturn v.toFixed(dec);\n}\n\n/** Collapse an array of numbers into a range string or single value. */\nexport function collapseNum(samples: number[]): string {\n\tif (samples.length === 0) return \"\\u2014\";\n\tconst lo = Math.min(...samples);\n\tconst hi = Math.max(...samples);\n\tif (lo === hi) return lo.toLocaleString();\n\treturn `${lo.toLocaleString()}\\u2013${hi.toLocaleString()}`;\n}\n\n/** Collapse an array of rates into a range string or single value. */\nexport function collapseRate(samples: number[]): string {\n\tif (samples.length === 0) return \"\\u2014\";\n\tconst lo = Math.min(...samples);\n\tconst hi = Math.max(...samples);\n\tif (lo === hi) return `$${lo.toFixed(6)}`;\n\treturn `$${lo.toFixed(6)}\\u2013$${hi.toFixed(6)}`;\n}\n\n/** Format a date string or null as locale string or em-dash. */\nexport function fmtDate(ts: string | number | null | undefined): string {\n\tif (!ts) return \"\\u2014\";\n\ttry {\n\t\treturn new Date(ts).toLocaleString();\n\t} catch {\n\t\treturn \"\\u2014\";\n\t}\n}\n","/**\n * dashboard-client/src/components/CacheHitsCard.tsx — Cache Hits & Compactions card.\n *\n * 6 fields: Cache Hits (session), Cache Hits (total),\n * Tokens Saved (session), Tokens Saved (total),\n * Compactions (session), Compactions (total).\n */\n\nimport type React from \"react\";\n\nexport interface CacheHitsCardProps {\n\t/** Cache hits in the current session. */\n\tcacheHitsSession: number;\n\t/** Total cache hits across all sessions. */\n\tcacheHitsTotal: number;\n\t/** Tokens saved by cache hits this session. */\n\ttokensSavedSession: number;\n\t/** Total tokens saved by cache hits. */\n\ttokensSavedTotal: number;\n\t/** Compactions performed this session. */\n\tcompactionsSession: number;\n\t/** Total compactions performed. */\n\tcompactionsTotal: number;\n}\n\nfunction StatRow({\n\tlabel,\n\tvalue,\n}: {\n\tlabel: string;\n\tvalue: string | number;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"ov-stat-row\">\n\t\t\t<span className=\"ov-stat-label\">{label}</span>\n\t\t\t<span className=\"ov-stat-value\">{value}</span>\n\t\t</div>\n\t);\n}\n\nexport function CacheHitsCard(\n\tprops: CacheHitsCardProps,\n): React.ReactElement {\n\treturn (\n\t\t<div className=\"card cache-hits-card\">\n\t\t\t<h3>💾 Cache Hits &amp; Compactions</h3>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Cache Hits (session)\"\n\t\t\t\tvalue={props.cacheHitsSession.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Cache Hits (total)\"\n\t\t\t\tvalue={props.cacheHitsTotal.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Tokens Saved (session)\"\n\t\t\t\tvalue={props.tokensSavedSession.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Tokens Saved (total)\"\n\t\t\t\tvalue={props.tokensSavedTotal.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Compactions (session)\"\n\t\t\t\tvalue={props.compactionsSession.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Compactions (total)\"\n\t\t\t\tvalue={props.compactionsTotal.toLocaleString()}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/components/TimeSavedCard.tsx — Time Saved (est.) card.\n *\n * 4 fields: Compact (session), Compact (total),\n * Cache Hit (session), Cache Hit (total).\n */\n\nimport type React from \"react\";\nimport { fmtSec } from \"../utils/format\";\n\nexport interface TimeSavedCardProps {\n\t/** Seconds saved by compaction this session. */\n\tcompactSessionSec: number;\n\t/** Total seconds saved by compaction. */\n\tcompactTotalSec: number;\n\t/** Seconds saved by cache hits this session. */\n\tcacheHitSessionSec: number;\n\t/** Total seconds saved by cache hits. */\n\tcacheHitTotalSec: number;\n}\n\nfunction StatRow({\n\tlabel,\n\tvalue,\n}: {\n\tlabel: string;\n\tvalue: string;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"ov-stat-row\">\n\t\t\t<span className=\"ov-stat-label\">{label}</span>\n\t\t\t<span className=\"ov-stat-value\">{value}</span>\n\t\t</div>\n\t);\n}\n\nexport function TimeSavedCard(\n\tprops: TimeSavedCardProps,\n): React.ReactElement {\n\treturn (\n\t\t<div className=\"card time-saved-card\">\n\t\t\t<h3>⏱ Time Saved (est.)</h3>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Compact (session)\"\n\t\t\t\tvalue={fmtSec(props.compactSessionSec)}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Compact (total)\"\n\t\t\t\tvalue={fmtSec(props.compactTotalSec)}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Cache Hit (session)\"\n\t\t\t\tvalue={fmtSec(props.cacheHitSessionSec)}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Cache Hit (total)\"\n\t\t\t\tvalue={fmtSec(props.cacheHitTotalSec)}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n"],"names":["fmtBytes","b","n","fmtSec","s","fmtPctFromFraction","v","pct","StatRow","label","value","jsxs","jsx","CacheHitsCard","props","TimeSavedCard"],"mappings":"wCAQO,SAASA,EAASC,EAAsC,CAC9D,MAAMC,EAAID,GAAK,EACf,OAAIC,GAAK,QAAkB,IAAIA,EAAI,SAAW,QAAQ,CAAC,CAAC,OACpDA,GAAK,KAAa,IAAIA,EAAI,MAAM,QAAQ,CAAC,CAAC,OACvC,GAAGA,CAAC,IACZ,CAGO,SAASC,EAAOC,EAAsC,CAC5D,MAAMF,EAAIE,GAAK,EACf,OAAIF,GAAK,KAAa,IAAIA,EAAI,MAAM,QAAQ,CAAC,CAAC,IAC1CA,GAAK,GAAW,GAAG,KAAK,MAAMA,EAAI,EAAE,CAAC,IACrCA,GAAK,EAAU,GAAGA,EAAE,QAAQ,CAAC,CAAC,IAC3B,GAAG,KAAK,MAAMA,EAAI,GAAI,CAAC,IAC/B,CAMO,SAASG,EACfC,EACS,CAET,MAAMC,GADID,GAAK,GACC,IAChB,OAAIC,GAAO,GAAW,GAAG,KAAK,MAAMA,CAAG,CAAC,IACjC,GAAGA,EAAI,QAAQ,CAAC,CAAC,GACzB,CCVA,SAASC,EAAQ,CAChB,MAAAC,EACA,MAAAC,CACD,EAGuB,CACtB,OACCC,EAAAA,KAAC,MAAA,CAAI,UAAU,cACd,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,SAAAH,EAAM,EACvCG,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,SAAAF,CAAA,CAAM,CAAA,EACxC,CAEF,CAEO,SAASG,EACfC,EACqB,CACrB,OACCH,EAAAA,KAAC,MAAA,CAAI,UAAU,uBACd,SAAA,CAAAC,EAAAA,IAAC,MAAG,SAAA,6BAAA,CAA+B,EACnCA,EAAAA,IAACJ,EAAA,CACA,MAAM,uBACN,MAAOM,EAAM,iBAAiB,eAAA,CAAe,CAAA,EAE9CF,EAAAA,IAACJ,EAAA,CACA,MAAM,qBACN,MAAOM,EAAM,eAAe,eAAA,CAAe,CAAA,EAE5CF,EAAAA,IAACJ,EAAA,CACA,MAAM,yBACN,MAAOM,EAAM,mBAAmB,eAAA,CAAe,CAAA,EAEhDF,EAAAA,IAACJ,EAAA,CACA,MAAM,uBACN,MAAOM,EAAM,iBAAiB,eAAA,CAAe,CAAA,EAE9CF,EAAAA,IAACJ,EAAA,CACA,MAAM,wBACN,MAAOM,EAAM,mBAAmB,eAAA,CAAe,CAAA,EAEhDF,EAAAA,IAACJ,EAAA,CACA,MAAM,sBACN,MAAOM,EAAM,iBAAiB,eAAA,CAAe,CAAA,CAC9C,EACD,CAEF,CCnDA,SAASN,EAAQ,CAChB,MAAAC,EACA,MAAAC,CACD,EAGuB,CACtB,OACCC,EAAAA,KAAC,MAAA,CAAI,UAAU,cACd,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,SAAAH,EAAM,EACvCG,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,SAAAF,CAAA,CAAM,CAAA,EACxC,CAEF,CAEO,SAASK,EACfD,EACqB,CACrB,OACCH,EAAAA,KAAC,MAAA,CAAI,UAAU,uBACd,SAAA,CAAAC,EAAAA,IAAC,MAAG,SAAA,qBAAA,CAAmB,EACvBA,EAAAA,IAACJ,EAAA,CACA,MAAM,oBACN,MAAOL,EAAOW,EAAM,iBAAiB,CAAA,CAAA,EAEtCF,EAAAA,IAACJ,EAAA,CACA,MAAM,kBACN,MAAOL,EAAOW,EAAM,eAAe,CAAA,CAAA,EAEpCF,EAAAA,IAACJ,EAAA,CACA,MAAM,sBACN,MAAOL,EAAOW,EAAM,kBAAkB,CAAA,CAAA,EAEvCF,EAAAA,IAACJ,EAAA,CACA,MAAM,oBACN,MAAOL,EAAOW,EAAM,gBAAgB,CAAA,CAAA,CACrC,EACD,CAEF"}
1
+ {"version":3,"file":"TimeSavedCard-0TqsrY6y.js","sources":["../../src/utils/format.ts","../../src/components/CacheHitsCard.tsx","../../src/components/TimeSavedCard.tsx"],"sourcesContent":["/**\n * dashboard-client/src/utils/format.ts — shared formatting helpers.\n *\n * Mirrors the format functions from the old static dashboard (html.ts)\n * so the React rewrite shows identical values.\n */\n\n/** Format bytes as KiB/MiB/B (matches html.ts fmtBytes). */\nexport function fmtBytes(b: number | null | undefined): string {\n\tconst n = b ?? 0;\n\tif (n >= 1_048_576) return `${(n / 1_048_576).toFixed(1)} MiB`;\n\tif (n >= 1024) return `${(n / 1024).toFixed(1)} KiB`;\n\treturn `${n} B`;\n}\n\n/** Format seconds as h/m/s/ms (matches html.ts fmtSec). */\nexport function fmtSec(s: number | null | undefined): string {\n\tconst n = s ?? 0;\n\tif (n >= 3600) return `${(n / 3600).toFixed(1)}h`;\n\tif (n >= 60) return `${Math.round(n / 60)}m`;\n\tif (n >= 1) return `${n.toFixed(1)}s`;\n\treturn `${Math.round(n * 1000)}ms`;\n}\n\n/**\n * Display a 0–1 fraction as a percentage string.\n * Uses one decimal place below 10%, rounded above (matches html.ts pct logic).\n */\nexport function fmtPctFromFraction(\n\tv: number | null | undefined,\n): string {\n\tconst n = v ?? 0;\n\tconst pct = n * 100;\n\tif (pct >= 10) return `${Math.round(pct)}%`;\n\treturn `${pct.toFixed(1)}%`;\n}\n\n/** Round a 0–1 fraction to a one-decimal percentage (for trophy values). */\nexport function fmtPct(v: number | null | undefined): string {\n\tconst n = v ?? 0;\n\treturn `${Math.round(n * 10) / 10}%`;\n}\n\n/** Format milliseconds (matches html.ts fmtMs). */\nexport function fmtMs(v: number | null | undefined): string {\n\tif (v == null) return \"\\u2014\";\n\treturn v >= 100 ? `${Math.round(v)}ms` : `${v.toFixed(1)}ms`;\n}\n\n/** Format a number with fixed decimals or em-dash for null (matches fmtNum). */\nexport function fmtNum(\n\tv: number | null | undefined,\n\tdec: number,\n): string {\n\tif (v == null || typeof v !== \"number\") return \"\\u2014\";\n\treturn v.toFixed(dec);\n}\n\n/** Collapse an array of numbers into a range string or single value. */\nexport function collapseNum(samples: number[]): string {\n\tif (samples.length === 0) return \"\\u2014\";\n\tconst lo = Math.min(...samples);\n\tconst hi = Math.max(...samples);\n\tif (lo === hi) return lo.toLocaleString();\n\treturn `${lo.toLocaleString()}\\u2013${hi.toLocaleString()}`;\n}\n\n/** Collapse an array of rates into a range string or single value. */\nexport function collapseRate(samples: number[]): string {\n\tif (samples.length === 0) return \"\\u2014\";\n\tconst lo = Math.min(...samples);\n\tconst hi = Math.max(...samples);\n\tif (lo === hi) return `$${lo.toFixed(6)}`;\n\treturn `$${lo.toFixed(6)}\\u2013$${hi.toFixed(6)}`;\n}\n\n/** Format a date string or null as locale string or em-dash. */\nexport function fmtDate(ts: string | number | null | undefined): string {\n\tif (!ts) return \"\\u2014\";\n\ttry {\n\t\treturn new Date(ts).toLocaleString();\n\t} catch {\n\t\treturn \"\\u2014\";\n\t}\n}\n","/**\n * dashboard-client/src/components/CacheHitsCard.tsx — Cache Hits & Compactions card.\n *\n * 6 fields: Cache Hits (session), Cache Hits (total),\n * Tokens Saved (session), Tokens Saved (total),\n * Compactions (session), Compactions (total).\n */\n\nimport type React from \"react\";\n\nexport interface CacheHitsCardProps {\n\t/** Cache hits in the current session. */\n\tcacheHitsSession: number;\n\t/** Total cache hits across all sessions. */\n\tcacheHitsTotal: number;\n\t/** Tokens saved by cache hits this session. */\n\ttokensSavedSession: number;\n\t/** Total tokens saved by cache hits. */\n\ttokensSavedTotal: number;\n\t/** Compactions performed this session. */\n\tcompactionsSession: number;\n\t/** Total compactions performed. */\n\tcompactionsTotal: number;\n}\n\nfunction StatRow({\n\tlabel,\n\tvalue,\n}: {\n\tlabel: string;\n\tvalue: string | number;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"ov-stat-row\">\n\t\t\t<span className=\"ov-stat-label\">{label}</span>\n\t\t\t<span className=\"ov-stat-value\">{value}</span>\n\t\t</div>\n\t);\n}\n\nexport function CacheHitsCard(\n\tprops: CacheHitsCardProps,\n): React.ReactElement {\n\treturn (\n\t\t<div className=\"card cache-hits-card\">\n\t\t\t<h3>💾 Cache Hits &amp; Compactions</h3>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Cache Hits (session)\"\n\t\t\t\tvalue={props.cacheHitsSession.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Cache Hits (total)\"\n\t\t\t\tvalue={props.cacheHitsTotal.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Tokens Saved (session)\"\n\t\t\t\tvalue={props.tokensSavedSession.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Tokens Saved (total)\"\n\t\t\t\tvalue={props.tokensSavedTotal.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Compactions (session)\"\n\t\t\t\tvalue={props.compactionsSession.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Compactions (total)\"\n\t\t\t\tvalue={props.compactionsTotal.toLocaleString()}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/components/TimeSavedCard.tsx — Time Saved (est.) card.\n *\n * 4 fields: Compact (session), Compact (total),\n * Cache Hit (session), Cache Hit (total).\n */\n\nimport type React from \"react\";\nimport { fmtSec } from \"../utils/format\";\n\nexport interface TimeSavedCardProps {\n\t/** Seconds saved by compaction this session. */\n\tcompactSessionSec: number;\n\t/** Total seconds saved by compaction. */\n\tcompactTotalSec: number;\n\t/** Seconds saved by cache hits this session. */\n\tcacheHitSessionSec: number;\n\t/** Total seconds saved by cache hits. */\n\tcacheHitTotalSec: number;\n}\n\nfunction StatRow({\n\tlabel,\n\tvalue,\n}: {\n\tlabel: string;\n\tvalue: string;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"ov-stat-row\">\n\t\t\t<span className=\"ov-stat-label\">{label}</span>\n\t\t\t<span className=\"ov-stat-value\">{value}</span>\n\t\t</div>\n\t);\n}\n\nexport function TimeSavedCard(\n\tprops: TimeSavedCardProps,\n): React.ReactElement {\n\treturn (\n\t\t<div className=\"card time-saved-card\">\n\t\t\t<h3>⏱ Time Saved (est.)</h3>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Compact (session)\"\n\t\t\t\tvalue={fmtSec(props.compactSessionSec)}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Compact (total)\"\n\t\t\t\tvalue={fmtSec(props.compactTotalSec)}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Cache Hit (session)\"\n\t\t\t\tvalue={fmtSec(props.cacheHitSessionSec)}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Cache Hit (total)\"\n\t\t\t\tvalue={fmtSec(props.cacheHitTotalSec)}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n"],"names":["fmtBytes","b","n","fmtSec","s","fmtPctFromFraction","v","pct","StatRow","label","value","jsxs","jsx","CacheHitsCard","props","TimeSavedCard"],"mappings":"wCAQO,SAASA,EAASC,EAAsC,CAC9D,MAAMC,EAAID,GAAK,EACf,OAAIC,GAAK,QAAkB,IAAIA,EAAI,SAAW,QAAQ,CAAC,CAAC,OACpDA,GAAK,KAAa,IAAIA,EAAI,MAAM,QAAQ,CAAC,CAAC,OACvC,GAAGA,CAAC,IACZ,CAGO,SAASC,EAAOC,EAAsC,CAC5D,MAAMF,EAAIE,GAAK,EACf,OAAIF,GAAK,KAAa,IAAIA,EAAI,MAAM,QAAQ,CAAC,CAAC,IAC1CA,GAAK,GAAW,GAAG,KAAK,MAAMA,EAAI,EAAE,CAAC,IACrCA,GAAK,EAAU,GAAGA,EAAE,QAAQ,CAAC,CAAC,IAC3B,GAAG,KAAK,MAAMA,EAAI,GAAI,CAAC,IAC/B,CAMO,SAASG,EACfC,EACS,CAET,MAAMC,GADID,GAAK,GACC,IAChB,OAAIC,GAAO,GAAW,GAAG,KAAK,MAAMA,CAAG,CAAC,IACjC,GAAGA,EAAI,QAAQ,CAAC,CAAC,GACzB,CCVA,SAASC,EAAQ,CAChB,MAAAC,EACA,MAAAC,CACD,EAGuB,CACtB,OACCC,EAAAA,KAAC,MAAA,CAAI,UAAU,cACd,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,SAAAH,EAAM,EACvCG,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,SAAAF,CAAA,CAAM,CAAA,EACxC,CAEF,CAEO,SAASG,EACfC,EACqB,CACrB,OACCH,EAAAA,KAAC,MAAA,CAAI,UAAU,uBACd,SAAA,CAAAC,EAAAA,IAAC,MAAG,SAAA,6BAAA,CAA+B,EACnCA,EAAAA,IAACJ,EAAA,CACA,MAAM,uBACN,MAAOM,EAAM,iBAAiB,eAAA,CAAe,CAAA,EAE9CF,EAAAA,IAACJ,EAAA,CACA,MAAM,qBACN,MAAOM,EAAM,eAAe,eAAA,CAAe,CAAA,EAE5CF,EAAAA,IAACJ,EAAA,CACA,MAAM,yBACN,MAAOM,EAAM,mBAAmB,eAAA,CAAe,CAAA,EAEhDF,EAAAA,IAACJ,EAAA,CACA,MAAM,uBACN,MAAOM,EAAM,iBAAiB,eAAA,CAAe,CAAA,EAE9CF,EAAAA,IAACJ,EAAA,CACA,MAAM,wBACN,MAAOM,EAAM,mBAAmB,eAAA,CAAe,CAAA,EAEhDF,EAAAA,IAACJ,EAAA,CACA,MAAM,sBACN,MAAOM,EAAM,iBAAiB,eAAA,CAAe,CAAA,CAC9C,EACD,CAEF,CCnDA,SAASN,EAAQ,CAChB,MAAAC,EACA,MAAAC,CACD,EAGuB,CACtB,OACCC,EAAAA,KAAC,MAAA,CAAI,UAAU,cACd,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,SAAAH,EAAM,EACvCG,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,SAAAF,CAAA,CAAM,CAAA,EACxC,CAEF,CAEO,SAASK,EACfD,EACqB,CACrB,OACCH,EAAAA,KAAC,MAAA,CAAI,UAAU,uBACd,SAAA,CAAAC,EAAAA,IAAC,MAAG,SAAA,qBAAA,CAAmB,EACvBA,EAAAA,IAACJ,EAAA,CACA,MAAM,oBACN,MAAOL,EAAOW,EAAM,iBAAiB,CAAA,CAAA,EAEtCF,EAAAA,IAACJ,EAAA,CACA,MAAM,kBACN,MAAOL,EAAOW,EAAM,eAAe,CAAA,CAAA,EAEpCF,EAAAA,IAACJ,EAAA,CACA,MAAM,sBACN,MAAOL,EAAOW,EAAM,kBAAkB,CAAA,CAAA,EAEvCF,EAAAA,IAACJ,EAAA,CACA,MAAM,oBACN,MAAOL,EAAOW,EAAM,gBAAgB,CAAA,CAAA,CACrC,EACD,CAEF"}
@@ -1,2 +1,2 @@
1
- import{u as m,r as a,m as u,n as p,j as e}from"./index-CqLN7STl.js";function b(s){return s?new Date(s).toLocaleString():"—"}function f(){const{data:s,loading:h,error:n}=m(a.useCallback(()=>u(),[]),{pollInterval:3e4}),[l,x]=a.useState(""),[i,o]=a.useState(null),r=m(a.useCallback(()=>i?p(i):Promise.reject(),[i]),{pollInterval:0}),d=a.useMemo(()=>{if(!s)return[];const t=l.trim().toLowerCase();return t?s.topics.filter(c=>c.label.toLowerCase().includes(t)||c.termScore.some(j=>j.term.toLowerCase().includes(t))):s.topics},[s,l]);return n&&!s?e.jsxs("div",{className:"tab-stub",children:["Error loading topics: ",n.message]}):h&&!s?e.jsx("div",{className:"tab-stub",children:"Loading topics…"}):s?s.totalTopics===0?e.jsxs("div",{className:"tab-stub",children:[e.jsx("h3",{children:"Wiki"}),e.jsx("p",{children:"No topics yet. Topics are auto-generated after every 10th compaction from real memory embeddings (k-means + TF-IDF)."}),e.jsx("p",{children:"Check back after a few more compaction cycles."})]}):e.jsxs("div",{className:"tab-content topics-tab",children:[e.jsx("h3",{children:"Wiki"}),e.jsxs("p",{className:"subtitle",children:[s.totalTopics," topic",s.totalTopics!==1?"s":""," ·"," ",s.totalAssigned," assigned memori",s.totalAssigned!==1?"es":"y",s.lastRebuildAt!=null&&e.jsxs(e.Fragment,{children:[" · last rebuild ",new Date(s.lastRebuildAt).toLocaleString()]})]}),e.jsx("input",{type:"search",className:"topics-search",placeholder:"Filter topics by label or term…",value:l,onChange:t=>x(t.target.value)}),i&&e.jsxs("section",{className:"topic-drilldown",children:[e.jsxs("h4",{children:[e.jsx("button",{type:"button",className:"link-btn",onClick:()=>o(null),children:"← back"})," ","Topic ",e.jsx("code",{children:i}),r.data&&e.jsxs(e.Fragment,{children:[" · ",r.data.label]}),r.data&&e.jsxs(e.Fragment,{children:[" · ",r.data.assignments.length," memories"]})]}),r.error?e.jsxs("div",{className:"tab-stub",children:["Error: ",r.error.message]}):r.loading&&!r.data?e.jsx("div",{className:"tab-stub",children:"Loading memories…"}):r.data?e.jsxs("table",{className:"data-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Memory id"}),e.jsx("th",{children:"Confidence"}),e.jsx("th",{children:"Assigned"})]})}),e.jsx("tbody",{children:r.data.assignments.map(t=>e.jsxs("tr",{children:[e.jsx("td",{children:e.jsx("code",{children:t.memoryId})}),e.jsx("td",{children:t.confidence!=null?t.confidence.toFixed(2):"—"}),e.jsx("td",{children:b(t.assignedAt)})]},t.memoryId))})]}):null]}),!i&&e.jsxs("table",{className:"data-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Label"}),e.jsx("th",{children:"Memories"}),e.jsx("th",{children:"Top Terms"}),e.jsx("th",{})]})}),e.jsxs("tbody",{children:[d.map(t=>e.jsxs("tr",{className:"topic-row",onClick:()=>o(t.id),style:{cursor:"pointer"},children:[e.jsx("td",{className:"topic-label",children:t.label}),e.jsx("td",{className:"topic-count",children:t.memoryCount}),e.jsx("td",{className:"topic-terms",children:t.termScore.slice(0,8).map(c=>c.term).join(", ")}),e.jsx("td",{children:e.jsx("button",{type:"button",className:"mini-btn",children:"drill"})})]},t.id)),d.length===0&&e.jsx("tr",{children:e.jsxs("td",{colSpan:4,className:"muted",children:["No topics match “",l,"”."]})})]})]})]}):e.jsx("div",{className:"tab-stub",children:"No topic data available."})}export{f as default};
2
- //# sourceMappingURL=TopicsTab-DKuct4oD.js.map
1
+ import{u as m,r as a,m as u,n as p,j as e}from"./index-BcoSz-L4.js";function b(s){return s?new Date(s).toLocaleString():"—"}function f(){const{data:s,loading:h,error:n}=m(a.useCallback(()=>u(),[]),{pollInterval:3e4}),[l,x]=a.useState(""),[i,o]=a.useState(null),r=m(a.useCallback(()=>i?p(i):Promise.reject(),[i]),{pollInterval:0}),d=a.useMemo(()=>{if(!s)return[];const t=l.trim().toLowerCase();return t?s.topics.filter(c=>c.label.toLowerCase().includes(t)||c.termScore.some(j=>j.term.toLowerCase().includes(t))):s.topics},[s,l]);return n&&!s?e.jsxs("div",{className:"tab-stub",children:["Error loading topics: ",n.message]}):h&&!s?e.jsx("div",{className:"tab-stub",children:"Loading topics…"}):s?s.totalTopics===0?e.jsxs("div",{className:"tab-stub",children:[e.jsx("h3",{children:"Wiki"}),e.jsx("p",{children:"No topics yet. Topics are auto-generated after every 10th compaction from real memory embeddings (k-means + TF-IDF)."}),e.jsx("p",{children:"Check back after a few more compaction cycles."})]}):e.jsxs("div",{className:"tab-content topics-tab",children:[e.jsx("h3",{children:"Wiki"}),e.jsxs("p",{className:"subtitle",children:[s.totalTopics," topic",s.totalTopics!==1?"s":""," ·"," ",s.totalAssigned," assigned memori",s.totalAssigned!==1?"es":"y",s.lastRebuildAt!=null&&e.jsxs(e.Fragment,{children:[" · last rebuild ",new Date(s.lastRebuildAt).toLocaleString()]})]}),e.jsx("input",{type:"search",className:"topics-search",placeholder:"Filter topics by label or term…",value:l,onChange:t=>x(t.target.value)}),i&&e.jsxs("section",{className:"topic-drilldown",children:[e.jsxs("h4",{children:[e.jsx("button",{type:"button",className:"link-btn",onClick:()=>o(null),children:"← back"})," ","Topic ",e.jsx("code",{children:i}),r.data&&e.jsxs(e.Fragment,{children:[" · ",r.data.label]}),r.data&&e.jsxs(e.Fragment,{children:[" · ",r.data.assignments.length," memories"]})]}),r.error?e.jsxs("div",{className:"tab-stub",children:["Error: ",r.error.message]}):r.loading&&!r.data?e.jsx("div",{className:"tab-stub",children:"Loading memories…"}):r.data?e.jsxs("table",{className:"data-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Memory id"}),e.jsx("th",{children:"Confidence"}),e.jsx("th",{children:"Assigned"})]})}),e.jsx("tbody",{children:r.data.assignments.map(t=>e.jsxs("tr",{children:[e.jsx("td",{children:e.jsx("code",{children:t.memoryId})}),e.jsx("td",{children:t.confidence!=null?t.confidence.toFixed(2):"—"}),e.jsx("td",{children:b(t.assignedAt)})]},t.memoryId))})]}):null]}),!i&&e.jsxs("table",{className:"data-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Label"}),e.jsx("th",{children:"Memories"}),e.jsx("th",{children:"Top Terms"}),e.jsx("th",{})]})}),e.jsxs("tbody",{children:[d.map(t=>e.jsxs("tr",{className:"topic-row",onClick:()=>o(t.id),style:{cursor:"pointer"},children:[e.jsx("td",{className:"topic-label",children:t.label}),e.jsx("td",{className:"topic-count",children:t.memoryCount}),e.jsx("td",{className:"topic-terms",children:t.termScore.slice(0,8).map(c=>c.term).join(", ")}),e.jsx("td",{children:e.jsx("button",{type:"button",className:"mini-btn",children:"drill"})})]},t.id)),d.length===0&&e.jsx("tr",{children:e.jsxs("td",{colSpan:4,className:"muted",children:["No topics match “",l,"”."]})})]})]})]}):e.jsx("div",{className:"tab-stub",children:"No topic data available."})}export{f as default};
2
+ //# sourceMappingURL=TopicsTab-DRLJmVv0.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TopicsTab-DKuct4oD.js","sources":["../../src/tabs/TopicsTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/tabs/TopicsTab.tsx — Auto-categorizing wiki (S51 + S52 polish).\n *\n * Fetches /api/topics and renders the k-means + TF-IDF topic clusters. S52 polish\n * adds: (1) a search box filtering topics by label / discriminative term, and\n * (2) a topic drill-down — click a topic to load its member memories\n * (/api/topics/:id/memories). Read-only; no write operations.\n */\n\nimport type React from \"react\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport { useApi } from \"../hooks/useApi\";\nimport { fetchTopics, fetchTopicMemories } from \"../api/client\";\nimport type { TopicsResponse, TopicMemoriesResponse } from \"@contracts\";\n\nfunction fmtTs(ms: number | null): string {\n\tif (!ms) return \"—\";\n\treturn new Date(ms).toLocaleString();\n}\n\nexport default function TopicsTab(): React.ReactElement {\n\tconst { data, loading, error } = useApi<TopicsResponse>(\n\t\tuseCallback(() => fetchTopics(), []),\n\t\t{ pollInterval: 30_000 },\n\t);\n\tconst [query, setQuery] = useState(\"\");\n\tconst [drillTopicId, setDrillTopicId] = useState<string | null>(null);\n\n\tconst drill = useApi<TopicMemoriesResponse>(\n\t\tuseCallback(\n\t\t\t() =>\n\t\t\t\tdrillTopicId ? fetchTopicMemories(drillTopicId) : Promise.reject(),\n\t\t\t[drillTopicId],\n\t\t),\n\t\t{ pollInterval: 0 },\n\t);\n\n\tconst filtered = useMemo(() => {\n\t\tif (!data) return [];\n\t\tconst q = query.trim().toLowerCase();\n\t\tif (!q) return data.topics;\n\t\treturn data.topics.filter(\n\t\t\t(t) =>\n\t\t\t\tt.label.toLowerCase().includes(q) ||\n\t\t\t\tt.termScore.some((s) => s.term.toLowerCase().includes(q)),\n\t\t);\n\t}, [data, query]);\n\n\tif (error && !data) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">Error loading topics: {error.message}</div>\n\t\t);\n\t}\n\tif (loading && !data) {\n\t\treturn <div className=\"tab-stub\">Loading topics…</div>;\n\t}\n\tif (!data) {\n\t\treturn <div className=\"tab-stub\">No topic data available.</div>;\n\t}\n\n\tif (data.totalTopics === 0) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">\n\t\t\t\t<h3>Wiki</h3>\n\t\t\t\t<p>\n\t\t\t\t\tNo topics yet. Topics are auto-generated after every 10th compaction\n\t\t\t\t\tfrom real memory embeddings (k-means + TF-IDF).\n\t\t\t\t</p>\n\t\t\t\t<p>Check back after a few more compaction cycles.</p>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className=\"tab-content topics-tab\">\n\t\t\t<h3>Wiki</h3>\n\t\t\t<p className=\"subtitle\">\n\t\t\t\t{data.totalTopics} topic{data.totalTopics !== 1 ? \"s\" : \"\"} ·{\" \"}\n\t\t\t\t{data.totalAssigned} assigned memori\n\t\t\t\t{data.totalAssigned !== 1 ? \"es\" : \"y\"}\n\t\t\t\t{data.lastRebuildAt != null && (\n\t\t\t\t\t<> · last rebuild {new Date(data.lastRebuildAt).toLocaleString()}</>\n\t\t\t\t)}\n\t\t\t</p>\n\n\t\t\t<input\n\t\t\t\ttype=\"search\"\n\t\t\t\tclassName=\"topics-search\"\n\t\t\t\tplaceholder=\"Filter topics by label or term…\"\n\t\t\t\tvalue={query}\n\t\t\t\tonChange={(e) => setQuery(e.target.value)}\n\t\t\t/>\n\n\t\t\t{drillTopicId && (\n\t\t\t\t<section className=\"topic-drilldown\">\n\t\t\t\t\t<h4>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName=\"link-btn\"\n\t\t\t\t\t\t\tonClick={() => setDrillTopicId(null)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t← back\n\t\t\t\t\t\t</button>{\" \"}\n\t\t\t\t\t\tTopic <code>{drillTopicId}</code>\n\t\t\t\t\t\t{drill.data && <> · {drill.data.label}</>}\n\t\t\t\t\t\t{drill.data && <> · {drill.data.assignments.length} memories</>}\n\t\t\t\t\t</h4>\n\t\t\t\t\t{drill.error ? (\n\t\t\t\t\t\t<div className=\"tab-stub\">\n\t\t\t\t\t\t\tError: {(drill.error as Error).message}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : drill.loading && !drill.data ? (\n\t\t\t\t\t\t<div className=\"tab-stub\">Loading memories…</div>\n\t\t\t\t\t) : drill.data ? (\n\t\t\t\t\t\t<table className=\"data-table\">\n\t\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t<th>Memory id</th>\n\t\t\t\t\t\t\t\t\t<th>Confidence</th>\n\t\t\t\t\t\t\t\t\t<th>Assigned</th>\n\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t{drill.data.assignments.map((a) => (\n\t\t\t\t\t\t\t\t\t<tr key={a.memoryId}>\n\t\t\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t\t\t<code>{a.memoryId}</code>\n\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t\t\t{a.confidence != null ? a.confidence.toFixed(2) : \"—\"}\n\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t<td>{fmtTs(a.assignedAt)}</td>\n\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t</table>\n\t\t\t\t\t) : null}\n\t\t\t\t</section>\n\t\t\t)}\n\n\t\t\t{!drillTopicId && (\n\t\t\t\t<table className=\"data-table\">\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<th>Label</th>\n\t\t\t\t\t\t\t<th>Memories</th>\n\t\t\t\t\t\t\t<th>Top Terms</th>\n\t\t\t\t\t\t\t<th></th>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</thead>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t{filtered.map((t) => (\n\t\t\t\t\t\t\t<tr\n\t\t\t\t\t\t\t\tkey={t.id}\n\t\t\t\t\t\t\t\tclassName=\"topic-row\"\n\t\t\t\t\t\t\t\tonClick={() => setDrillTopicId(t.id)}\n\t\t\t\t\t\t\t\tstyle={{ cursor: \"pointer\" }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<td className=\"topic-label\">{t.label}</td>\n\t\t\t\t\t\t\t\t<td className=\"topic-count\">{t.memoryCount}</td>\n\t\t\t\t\t\t\t\t<td className=\"topic-terms\">\n\t\t\t\t\t\t\t\t\t{t.termScore\n\t\t\t\t\t\t\t\t\t\t.slice(0, 8)\n\t\t\t\t\t\t\t\t\t\t.map((s) => s.term)\n\t\t\t\t\t\t\t\t\t\t.join(\", \")}\n\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t<button type=\"button\" className=\"mini-btn\">\n\t\t\t\t\t\t\t\t\t\tdrill\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t))}\n\t\t\t\t\t\t{filtered.length === 0 && (\n\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t<td colSpan={4} className=\"muted\">\n\t\t\t\t\t\t\t\t\tNo topics match “{query}”.\n\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</tbody>\n\t\t\t\t</table>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"],"names":["fmtTs","ms","TopicsTab","data","loading","error","useApi","useCallback","fetchTopics","query","setQuery","useState","drillTopicId","setDrillTopicId","drill","fetchTopicMemories","filtered","useMemo","q","t","s","jsxs","jsx","Fragment","e","a"],"mappings":"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"}
1
+ {"version":3,"file":"TopicsTab-DRLJmVv0.js","sources":["../../src/tabs/TopicsTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/tabs/TopicsTab.tsx — Auto-categorizing wiki (S51 + S52 polish).\n *\n * Fetches /api/topics and renders the k-means + TF-IDF topic clusters. S52 polish\n * adds: (1) a search box filtering topics by label / discriminative term, and\n * (2) a topic drill-down — click a topic to load its member memories\n * (/api/topics/:id/memories). Read-only; no write operations.\n */\n\nimport type React from \"react\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport { useApi } from \"../hooks/useApi\";\nimport { fetchTopics, fetchTopicMemories } from \"../api/client\";\nimport type { TopicsResponse, TopicMemoriesResponse } from \"@contracts\";\n\nfunction fmtTs(ms: number | null): string {\n\tif (!ms) return \"—\";\n\treturn new Date(ms).toLocaleString();\n}\n\nexport default function TopicsTab(): React.ReactElement {\n\tconst { data, loading, error } = useApi<TopicsResponse>(\n\t\tuseCallback(() => fetchTopics(), []),\n\t\t{ pollInterval: 30_000 },\n\t);\n\tconst [query, setQuery] = useState(\"\");\n\tconst [drillTopicId, setDrillTopicId] = useState<string | null>(null);\n\n\tconst drill = useApi<TopicMemoriesResponse>(\n\t\tuseCallback(\n\t\t\t() =>\n\t\t\t\tdrillTopicId ? fetchTopicMemories(drillTopicId) : Promise.reject(),\n\t\t\t[drillTopicId],\n\t\t),\n\t\t{ pollInterval: 0 },\n\t);\n\n\tconst filtered = useMemo(() => {\n\t\tif (!data) return [];\n\t\tconst q = query.trim().toLowerCase();\n\t\tif (!q) return data.topics;\n\t\treturn data.topics.filter(\n\t\t\t(t) =>\n\t\t\t\tt.label.toLowerCase().includes(q) ||\n\t\t\t\tt.termScore.some((s) => s.term.toLowerCase().includes(q)),\n\t\t);\n\t}, [data, query]);\n\n\tif (error && !data) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">Error loading topics: {error.message}</div>\n\t\t);\n\t}\n\tif (loading && !data) {\n\t\treturn <div className=\"tab-stub\">Loading topics…</div>;\n\t}\n\tif (!data) {\n\t\treturn <div className=\"tab-stub\">No topic data available.</div>;\n\t}\n\n\tif (data.totalTopics === 0) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">\n\t\t\t\t<h3>Wiki</h3>\n\t\t\t\t<p>\n\t\t\t\t\tNo topics yet. Topics are auto-generated after every 10th compaction\n\t\t\t\t\tfrom real memory embeddings (k-means + TF-IDF).\n\t\t\t\t</p>\n\t\t\t\t<p>Check back after a few more compaction cycles.</p>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className=\"tab-content topics-tab\">\n\t\t\t<h3>Wiki</h3>\n\t\t\t<p className=\"subtitle\">\n\t\t\t\t{data.totalTopics} topic{data.totalTopics !== 1 ? \"s\" : \"\"} ·{\" \"}\n\t\t\t\t{data.totalAssigned} assigned memori\n\t\t\t\t{data.totalAssigned !== 1 ? \"es\" : \"y\"}\n\t\t\t\t{data.lastRebuildAt != null && (\n\t\t\t\t\t<> · last rebuild {new Date(data.lastRebuildAt).toLocaleString()}</>\n\t\t\t\t)}\n\t\t\t</p>\n\n\t\t\t<input\n\t\t\t\ttype=\"search\"\n\t\t\t\tclassName=\"topics-search\"\n\t\t\t\tplaceholder=\"Filter topics by label or term…\"\n\t\t\t\tvalue={query}\n\t\t\t\tonChange={(e) => setQuery(e.target.value)}\n\t\t\t/>\n\n\t\t\t{drillTopicId && (\n\t\t\t\t<section className=\"topic-drilldown\">\n\t\t\t\t\t<h4>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName=\"link-btn\"\n\t\t\t\t\t\t\tonClick={() => setDrillTopicId(null)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t← back\n\t\t\t\t\t\t</button>{\" \"}\n\t\t\t\t\t\tTopic <code>{drillTopicId}</code>\n\t\t\t\t\t\t{drill.data && <> · {drill.data.label}</>}\n\t\t\t\t\t\t{drill.data && <> · {drill.data.assignments.length} memories</>}\n\t\t\t\t\t</h4>\n\t\t\t\t\t{drill.error ? (\n\t\t\t\t\t\t<div className=\"tab-stub\">\n\t\t\t\t\t\t\tError: {(drill.error as Error).message}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : drill.loading && !drill.data ? (\n\t\t\t\t\t\t<div className=\"tab-stub\">Loading memories…</div>\n\t\t\t\t\t) : drill.data ? (\n\t\t\t\t\t\t<table className=\"data-table\">\n\t\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t<th>Memory id</th>\n\t\t\t\t\t\t\t\t\t<th>Confidence</th>\n\t\t\t\t\t\t\t\t\t<th>Assigned</th>\n\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t{drill.data.assignments.map((a) => (\n\t\t\t\t\t\t\t\t\t<tr key={a.memoryId}>\n\t\t\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t\t\t<code>{a.memoryId}</code>\n\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t\t\t{a.confidence != null ? a.confidence.toFixed(2) : \"—\"}\n\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t<td>{fmtTs(a.assignedAt)}</td>\n\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t</table>\n\t\t\t\t\t) : null}\n\t\t\t\t</section>\n\t\t\t)}\n\n\t\t\t{!drillTopicId && (\n\t\t\t\t<table className=\"data-table\">\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<th>Label</th>\n\t\t\t\t\t\t\t<th>Memories</th>\n\t\t\t\t\t\t\t<th>Top Terms</th>\n\t\t\t\t\t\t\t<th></th>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</thead>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t{filtered.map((t) => (\n\t\t\t\t\t\t\t<tr\n\t\t\t\t\t\t\t\tkey={t.id}\n\t\t\t\t\t\t\t\tclassName=\"topic-row\"\n\t\t\t\t\t\t\t\tonClick={() => setDrillTopicId(t.id)}\n\t\t\t\t\t\t\t\tstyle={{ cursor: \"pointer\" }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<td className=\"topic-label\">{t.label}</td>\n\t\t\t\t\t\t\t\t<td className=\"topic-count\">{t.memoryCount}</td>\n\t\t\t\t\t\t\t\t<td className=\"topic-terms\">\n\t\t\t\t\t\t\t\t\t{t.termScore\n\t\t\t\t\t\t\t\t\t\t.slice(0, 8)\n\t\t\t\t\t\t\t\t\t\t.map((s) => s.term)\n\t\t\t\t\t\t\t\t\t\t.join(\", \")}\n\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t<button type=\"button\" className=\"mini-btn\">\n\t\t\t\t\t\t\t\t\t\tdrill\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t))}\n\t\t\t\t\t\t{filtered.length === 0 && (\n\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t<td colSpan={4} className=\"muted\">\n\t\t\t\t\t\t\t\t\tNo topics match “{query}”.\n\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</tbody>\n\t\t\t\t</table>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"],"names":["fmtTs","ms","TopicsTab","data","loading","error","useApi","useCallback","fetchTopics","query","setQuery","useState","drillTopicId","setDrillTopicId","drill","fetchTopicMemories","filtered","useMemo","q","t","s","jsxs","jsx","Fragment","e","a"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{u as f,r,o as C,q as w,s as I,t as T,v as $,j as e}from"./index-CqLN7STl.js";function j(n){return n?new Date(n).toLocaleString():"—"}function E(n){return n==="green"?"band band-green":n==="yellow"?"band band-yellow":n==="red"?"band band-red":"band"}function L(n){return n==="checkpoint"?"ckpt":n==="cluster_summary"?"raptor":"mem"}function S(){const{data:n,loading:i,error:d}=f(r.useCallback(()=>C(),[]),{pollInterval:1e4}),{data:c}=f(r.useCallback(()=>w(),[]),{pollInterval:5e3}),[s,l]=r.useState(null),[m,x]=r.useState(null),[v,p]=r.useState(!1),[N,u]=r.useState(null),[b,o]=r.useState(null),g=r.useCallback(async t=>{if(s===t){l(null),x(null);return}l(t),p(!0),x(null);try{const a=await I(t);x(a)}finally{p(!1)}},[s]),y=r.useCallback(async(t,a)=>{u(`fork:${t}:${a}`),o(null);try{const h=await T(t,a);o(`Forked → ${h.childConversationId} (${h.recalledCount} recalled)`)}catch(h){o(`Fork failed: ${h.message}`)}finally{u(null)}},[]),k=r.useCallback(async(t,a)=>{u(`rewind:${t}:${a}`),o(null);try{await $(t,a),o(`Rewind intent queued for turn ${a}`)}catch(h){o(`Rewind failed: ${h.message}`)}finally{u(null)}},[]);return d&&!n?e.jsxs("div",{className:"tab-stub",children:["Error loading turns: ",d.message]}):i&&!n?e.jsx("div",{className:"tab-stub",children:"Loading turns…"}):!n||n.conversations.length===0?e.jsxs("div",{className:"tab-stub",children:[e.jsx("h3",{children:"Turn-by-turn memory"}),e.jsxs("p",{children:["No turns recorded yet. Per-turn tracking starts when"," ",e.jsx("code",{children:"MEGACOMPACT_TURNS_DB=1"})," and the session runs through a compaction. Each turn records its context metrics + the checkpoints recalled into it."]})]}):e.jsxs("div",{className:"turns-tab",children:[e.jsx("h3",{children:"Turn-by-turn memory tracking + recall"}),b&&e.jsx("div",{className:"turns-notice",children:b}),c&&c.intents.length>0&&e.jsxs("section",{className:"turns-intents",children:[e.jsxs("h4",{children:["Pending rewind intents (",c.intents.length,")"]}),e.jsx("ul",{children:c.intents.map(t=>e.jsxs("li",{children:[j(t.createdAt)," — rewind ",e.jsx("code",{children:t.conversationId})," to turn ",t.targetTurnIndex]},t.id))})]}),e.jsxs("section",{className:"turns-conv-list",children:[e.jsxs("h4",{children:["Conversations (",n.conversations.length,")"]}),e.jsxs("table",{className:"turns-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Conversation"}),e.jsx("th",{children:"Turns"}),e.jsx("th",{children:"Recall"}),e.jsx("th",{children:"Epochs"}),e.jsx("th",{children:"Avg ctx%"}),e.jsx("th",{children:"Last turn"}),e.jsx("th",{})]})}),e.jsx("tbody",{children:n.conversations.map(t=>e.jsx(R,{c:t,active:n.activeConversationId===t.conversationId,expanded:s===t.conversationId,onExpand:()=>g(t.conversationId)},t.conversationId))})]})]}),s&&e.jsxs("section",{className:"turns-detail",children:[e.jsxs("h4",{children:["Turns in ",e.jsx("code",{children:s})]}),v?e.jsx("div",{className:"tab-stub",children:"Loading turns…"}):m?e.jsx(A,{detail:m,busy:N,onFork:y,onRewind:k}):e.jsx("div",{className:"tab-stub",children:"No detail."})]})]})}function R({c:n,active:i,expanded:d,onExpand:c}){return e.jsx(e.Fragment,{children:e.jsxs("tr",{className:i?"turns-row active":"turns-row",onClick:c,style:{cursor:"pointer"},children:[e.jsxs("td",{children:[d?"▾":"▸"," ",e.jsx("code",{children:n.conversationId}),i&&e.jsx("span",{className:"pill",children:"active"})]}),e.jsx("td",{children:n.turnCount}),e.jsx("td",{children:n.totalRecall}),e.jsx("td",{children:n.epochCount}),e.jsxs("td",{children:[(n.avgCtxPercent*100).toFixed(0),"%"]}),e.jsx("td",{children:j(n.lastTurnAt)}),e.jsx("td",{})]})})}function A({detail:n,busy:i,onFork:d,onRewind:c}){return e.jsxs("table",{className:"turns-detail-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"#"}),e.jsx("th",{children:"Role"}),e.jsx("th",{children:"Ctx"}),e.jsx("th",{children:"Band"}),e.jsx("th",{children:"Epoch"}),e.jsx("th",{children:"Recalled checkpoints (memory recall)"}),e.jsx("th",{children:"Ended"}),e.jsx("th",{children:"Actions"})]})}),e.jsx("tbody",{children:n.turns.map(s=>e.jsxs("tr",{children:[e.jsx("td",{children:s.turnIndex}),e.jsx("td",{children:s.role}),e.jsxs("td",{children:[s.ctxTokens??"—",s.ctxPercent!=null&&e.jsxs("span",{className:"muted",children:[" ","· ",(s.ctxPercent*100).toFixed(0),"%"]})]}),e.jsx("td",{children:e.jsx("span",{className:E(s.pressureBand),children:s.pressureBand??"—"})}),e.jsx("td",{children:s.epochId?e.jsx("code",{children:s.epochId.slice(0,8)}):"—"}),e.jsx("td",{className:"recall-cell",children:s.recall.length===0?e.jsx("span",{className:"muted",children:"—"}):e.jsx("ul",{className:"recall-list",children:s.recall.map(l=>e.jsxs("li",{children:[e.jsx("code",{children:l.checkpointId.slice(0,12)})," ",e.jsxs("span",{className:"muted",children:[L(l.source)," · ",l.score.toFixed(2),l.raptorLevel!=null?` · L${l.raptorLevel}`:""]})]},l.checkpointId))})}),e.jsx("td",{children:j(s.endedAt)}),e.jsxs("td",{className:"actions-cell",children:[e.jsx("button",{type:"button",className:"mini-btn",disabled:i!==null,onClick:()=>d(s.conversationId,s.turnIndex),children:"fork"}),e.jsx("button",{type:"button",className:"mini-btn",disabled:i!==null,onClick:()=>c(s.conversationId,s.turnIndex),children:"rewind"})]})]},`${s.conversationId}:${s.turnIndex}`))})]})}export{S as default};
2
- //# sourceMappingURL=TurnsTab-11MGLxY8.js.map
1
+ import{u as f,r,o as C,q as w,s as I,t as T,v as $,j as e}from"./index-BcoSz-L4.js";function j(n){return n?new Date(n).toLocaleString():"—"}function E(n){return n==="green"?"band band-green":n==="yellow"?"band band-yellow":n==="red"?"band band-red":"band"}function L(n){return n==="checkpoint"?"ckpt":n==="cluster_summary"?"raptor":"mem"}function S(){const{data:n,loading:i,error:d}=f(r.useCallback(()=>C(),[]),{pollInterval:1e4}),{data:c}=f(r.useCallback(()=>w(),[]),{pollInterval:5e3}),[s,l]=r.useState(null),[m,x]=r.useState(null),[v,p]=r.useState(!1),[N,u]=r.useState(null),[b,o]=r.useState(null),g=r.useCallback(async t=>{if(s===t){l(null),x(null);return}l(t),p(!0),x(null);try{const a=await I(t);x(a)}finally{p(!1)}},[s]),y=r.useCallback(async(t,a)=>{u(`fork:${t}:${a}`),o(null);try{const h=await T(t,a);o(`Forked → ${h.childConversationId} (${h.recalledCount} recalled)`)}catch(h){o(`Fork failed: ${h.message}`)}finally{u(null)}},[]),k=r.useCallback(async(t,a)=>{u(`rewind:${t}:${a}`),o(null);try{await $(t,a),o(`Rewind intent queued for turn ${a}`)}catch(h){o(`Rewind failed: ${h.message}`)}finally{u(null)}},[]);return d&&!n?e.jsxs("div",{className:"tab-stub",children:["Error loading turns: ",d.message]}):i&&!n?e.jsx("div",{className:"tab-stub",children:"Loading turns…"}):!n||n.conversations.length===0?e.jsxs("div",{className:"tab-stub",children:[e.jsx("h3",{children:"Turn-by-turn memory"}),e.jsxs("p",{children:["No turns recorded yet. Per-turn tracking starts when"," ",e.jsx("code",{children:"MEGACOMPACT_TURNS_DB=1"})," and the session runs through a compaction. Each turn records its context metrics + the checkpoints recalled into it."]})]}):e.jsxs("div",{className:"turns-tab",children:[e.jsx("h3",{children:"Turn-by-turn memory tracking + recall"}),b&&e.jsx("div",{className:"turns-notice",children:b}),c&&c.intents.length>0&&e.jsxs("section",{className:"turns-intents",children:[e.jsxs("h4",{children:["Pending rewind intents (",c.intents.length,")"]}),e.jsx("ul",{children:c.intents.map(t=>e.jsxs("li",{children:[j(t.createdAt)," — rewind ",e.jsx("code",{children:t.conversationId})," to turn ",t.targetTurnIndex]},t.id))})]}),e.jsxs("section",{className:"turns-conv-list",children:[e.jsxs("h4",{children:["Conversations (",n.conversations.length,")"]}),e.jsxs("table",{className:"turns-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Conversation"}),e.jsx("th",{children:"Turns"}),e.jsx("th",{children:"Recall"}),e.jsx("th",{children:"Epochs"}),e.jsx("th",{children:"Avg ctx%"}),e.jsx("th",{children:"Last turn"}),e.jsx("th",{})]})}),e.jsx("tbody",{children:n.conversations.map(t=>e.jsx(R,{c:t,active:n.activeConversationId===t.conversationId,expanded:s===t.conversationId,onExpand:()=>g(t.conversationId)},t.conversationId))})]})]}),s&&e.jsxs("section",{className:"turns-detail",children:[e.jsxs("h4",{children:["Turns in ",e.jsx("code",{children:s})]}),v?e.jsx("div",{className:"tab-stub",children:"Loading turns…"}):m?e.jsx(A,{detail:m,busy:N,onFork:y,onRewind:k}):e.jsx("div",{className:"tab-stub",children:"No detail."})]})]})}function R({c:n,active:i,expanded:d,onExpand:c}){return e.jsx(e.Fragment,{children:e.jsxs("tr",{className:i?"turns-row active":"turns-row",onClick:c,style:{cursor:"pointer"},children:[e.jsxs("td",{children:[d?"▾":"▸"," ",e.jsx("code",{children:n.conversationId}),i&&e.jsx("span",{className:"pill",children:"active"})]}),e.jsx("td",{children:n.turnCount}),e.jsx("td",{children:n.totalRecall}),e.jsx("td",{children:n.epochCount}),e.jsxs("td",{children:[(n.avgCtxPercent*100).toFixed(0),"%"]}),e.jsx("td",{children:j(n.lastTurnAt)}),e.jsx("td",{})]})})}function A({detail:n,busy:i,onFork:d,onRewind:c}){return e.jsxs("table",{className:"turns-detail-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"#"}),e.jsx("th",{children:"Role"}),e.jsx("th",{children:"Ctx"}),e.jsx("th",{children:"Band"}),e.jsx("th",{children:"Epoch"}),e.jsx("th",{children:"Recalled checkpoints (memory recall)"}),e.jsx("th",{children:"Ended"}),e.jsx("th",{children:"Actions"})]})}),e.jsx("tbody",{children:n.turns.map(s=>e.jsxs("tr",{children:[e.jsx("td",{children:s.turnIndex}),e.jsx("td",{children:s.role}),e.jsxs("td",{children:[s.ctxTokens??"—",s.ctxPercent!=null&&e.jsxs("span",{className:"muted",children:[" ","· ",(s.ctxPercent*100).toFixed(0),"%"]})]}),e.jsx("td",{children:e.jsx("span",{className:E(s.pressureBand),children:s.pressureBand??"—"})}),e.jsx("td",{children:s.epochId?e.jsx("code",{children:s.epochId.slice(0,8)}):"—"}),e.jsx("td",{className:"recall-cell",children:s.recall.length===0?e.jsx("span",{className:"muted",children:"—"}):e.jsx("ul",{className:"recall-list",children:s.recall.map(l=>e.jsxs("li",{children:[e.jsx("code",{children:l.checkpointId.slice(0,12)})," ",e.jsxs("span",{className:"muted",children:[L(l.source)," · ",l.score.toFixed(2),l.raptorLevel!=null?` · L${l.raptorLevel}`:""]})]},l.checkpointId))})}),e.jsx("td",{children:j(s.endedAt)}),e.jsxs("td",{className:"actions-cell",children:[e.jsx("button",{type:"button",className:"mini-btn",disabled:i!==null,onClick:()=>d(s.conversationId,s.turnIndex),children:"fork"}),e.jsx("button",{type:"button",className:"mini-btn",disabled:i!==null,onClick:()=>c(s.conversationId,s.turnIndex),children:"rewind"})]})]},`${s.conversationId}:${s.turnIndex}`))})]})}export{S as default};
2
+ //# sourceMappingURL=TurnsTab-CLNM0T5R.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TurnsTab-11MGLxY8.js","sources":["../../src/tabs/TurnsTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/tabs/TurnsTab.tsx — Turn-by-turn memory tracking + recall (S52).\n *\n * Fetches /api/turns (conversation list), expands the active conversation into\n * per-turn detail (/api/turns/conversation/:id), and renders:\n * - Conversation summary list (turn count, recall total, epochs, last turn).\n * - Per-turn rows: turn index, role, ctx tokens/percent + pressure band,\n * epoch id, and the injected-checkpoint recall set (the memory recalled\n * at each turn, with score + source).\n * - Pending rewind intents (S52A) + Fork action (S50C primitive).\n *\n * Read-mostly via /api/turns; fork/intent/prune via POST. No absolute URLs\n * (PREVENT-PI-004: loopback-only, same-origin static bundle).\n */\n\nimport type React from \"react\";\nimport { useCallback, useState } from \"react\";\nimport { useApi } from \"../hooks/useApi\";\nimport {\n\tfetchTurns,\n\tfetchConversationTurns,\n\tfetchTurnIntents,\n\tpostFork,\n\tpostTurnIntent,\n} from \"../api/client\";\nimport type {\n\tTurnsResponse,\n\tConversationTurnsResponse,\n\tRewindIntentsResponse,\n\tTurnRow,\n\tConversationSummary,\n} from \"@contracts\";\n\nfunction fmtTs(ms: number): string {\n\tif (!ms) return \"—\";\n\treturn new Date(ms).toLocaleString();\n}\n\nfunction bandClass(band: TurnRow[\"pressureBand\"]): string {\n\tif (band === \"green\") return \"band band-green\";\n\tif (band === \"yellow\") return \"band band-yellow\";\n\tif (band === \"red\") return \"band band-red\";\n\treturn \"band\";\n}\n\nfunction sourceLabel(s: TurnRow[\"recall\"][number][\"source\"]): string {\n\tif (s === \"checkpoint\") return \"ckpt\";\n\tif (s === \"cluster_summary\") return \"raptor\";\n\treturn \"mem\";\n}\n\nexport default function TurnsTab(): React.ReactElement {\n\tconst {\n\t\tdata: turns,\n\t\tloading,\n\t\terror,\n\t} = useApi<TurnsResponse>(\n\t\tuseCallback(() => fetchTurns(), []),\n\t\t{\n\t\t\tpollInterval: 10_000,\n\t\t},\n\t);\n\tconst { data: intents } = useApi<RewindIntentsResponse>(\n\t\tuseCallback(() => fetchTurnIntents(), []),\n\t\t{ pollInterval: 5_000 },\n\t);\n\tconst [expanded, setExpanded] = useState<string | null>(null);\n\tconst [detail, setDetail] = useState<ConversationTurnsResponse | null>(null);\n\tconst [detailLoading, setDetailLoading] = useState(false);\n\tconst [busy, setBusy] = useState<string | null>(null);\n\tconst [notice, setNotice] = useState<string | null>(null);\n\n\tconst expand = useCallback(\n\t\tasync (conversationId: string) => {\n\t\t\tif (expanded === conversationId) {\n\t\t\t\tsetExpanded(null);\n\t\t\t\tsetDetail(null);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsetExpanded(conversationId);\n\t\t\tsetDetailLoading(true);\n\t\t\tsetDetail(null);\n\t\t\ttry {\n\t\t\t\tconst d = await fetchConversationTurns(conversationId);\n\t\t\t\tsetDetail(d);\n\t\t\t} finally {\n\t\t\t\tsetDetailLoading(false);\n\t\t\t}\n\t\t},\n\t\t[expanded],\n\t);\n\n\tconst onFork = useCallback(\n\t\tasync (conversationId: string, turnIndex: number) => {\n\t\t\tsetBusy(`fork:${conversationId}:${turnIndex}`);\n\t\t\tsetNotice(null);\n\t\t\ttry {\n\t\t\t\tconst out = await postFork(conversationId, turnIndex);\n\t\t\t\tsetNotice(\n\t\t\t\t\t`Forked → ${out.childConversationId} (${out.recalledCount} recalled)`,\n\t\t\t\t);\n\t\t\t} catch (e) {\n\t\t\t\tsetNotice(`Fork failed: ${(e as Error).message}`);\n\t\t\t} finally {\n\t\t\t\tsetBusy(null);\n\t\t\t}\n\t\t},\n\t\t[],\n\t);\n\n\tconst onRewind = useCallback(\n\t\tasync (conversationId: string, turnIndex: number) => {\n\t\t\tsetBusy(`rewind:${conversationId}:${turnIndex}`);\n\t\t\tsetNotice(null);\n\t\t\ttry {\n\t\t\t\tawait postTurnIntent(conversationId, turnIndex);\n\t\t\t\tsetNotice(`Rewind intent queued for turn ${turnIndex}`);\n\t\t\t} catch (e) {\n\t\t\t\tsetNotice(`Rewind failed: ${(e as Error).message}`);\n\t\t\t} finally {\n\t\t\t\tsetBusy(null);\n\t\t\t}\n\t\t},\n\t\t[],\n\t);\n\n\tif (error && !turns) {\n\t\treturn <div className=\"tab-stub\">Error loading turns: {error.message}</div>;\n\t}\n\tif (loading && !turns) {\n\t\treturn <div className=\"tab-stub\">Loading turns…</div>;\n\t}\n\tif (!turns || turns.conversations.length === 0) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">\n\t\t\t\t<h3>Turn-by-turn memory</h3>\n\t\t\t\t<p>\n\t\t\t\t\tNo turns recorded yet. Per-turn tracking starts when{\" \"}\n\t\t\t\t\t<code>MEGACOMPACT_TURNS_DB=1</code> and the session runs through a\n\t\t\t\t\tcompaction. Each turn records its context metrics + the checkpoints\n\t\t\t\t\trecalled into it.\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className=\"turns-tab\">\n\t\t\t<h3>Turn-by-turn memory tracking + recall</h3>\n\t\t\t{notice && <div className=\"turns-notice\">{notice}</div>}\n\n\t\t\t{intents && intents.intents.length > 0 && (\n\t\t\t\t<section className=\"turns-intents\">\n\t\t\t\t\t<h4>Pending rewind intents ({intents.intents.length})</h4>\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t{intents.intents.map((i) => (\n\t\t\t\t\t\t\t<li key={i.id}>\n\t\t\t\t\t\t\t\t{fmtTs(i.createdAt)} — rewind <code>{i.conversationId}</code> to\n\t\t\t\t\t\t\t\tturn {i.targetTurnIndex}\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</ul>\n\t\t\t\t</section>\n\t\t\t)}\n\n\t\t\t<section className=\"turns-conv-list\">\n\t\t\t\t<h4>Conversations ({turns.conversations.length})</h4>\n\t\t\t\t<table className=\"turns-table\">\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<th>Conversation</th>\n\t\t\t\t\t\t\t<th>Turns</th>\n\t\t\t\t\t\t\t<th>Recall</th>\n\t\t\t\t\t\t\t<th>Epochs</th>\n\t\t\t\t\t\t\t<th>Avg ctx%</th>\n\t\t\t\t\t\t\t<th>Last turn</th>\n\t\t\t\t\t\t\t<th></th>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</thead>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t{turns.conversations.map((c: ConversationSummary) => (\n\t\t\t\t\t\t\t<ConversationRow\n\t\t\t\t\t\t\t\tkey={c.conversationId}\n\t\t\t\t\t\t\t\tc={c}\n\t\t\t\t\t\t\t\tactive={turns.activeConversationId === c.conversationId}\n\t\t\t\t\t\t\t\texpanded={expanded === c.conversationId}\n\t\t\t\t\t\t\t\tonExpand={() => expand(c.conversationId)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</tbody>\n\t\t\t\t</table>\n\t\t\t</section>\n\n\t\t\t{expanded && (\n\t\t\t\t<section className=\"turns-detail\">\n\t\t\t\t\t<h4>\n\t\t\t\t\t\tTurns in <code>{expanded}</code>\n\t\t\t\t\t</h4>\n\t\t\t\t\t{detailLoading ? (\n\t\t\t\t\t\t<div className=\"tab-stub\">Loading turns…</div>\n\t\t\t\t\t) : detail ? (\n\t\t\t\t\t\t<TurnDetail\n\t\t\t\t\t\t\tdetail={detail}\n\t\t\t\t\t\t\tbusy={busy}\n\t\t\t\t\t\t\tonFork={onFork}\n\t\t\t\t\t\t\tonRewind={onRewind}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<div className=\"tab-stub\">No detail.</div>\n\t\t\t\t\t)}\n\t\t\t\t</section>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction ConversationRow({\n\tc,\n\tactive,\n\texpanded,\n\tonExpand,\n}: {\n\tc: ConversationSummary;\n\tactive: boolean;\n\texpanded: boolean;\n\tonExpand: () => void;\n}): React.ReactElement {\n\treturn (\n\t\t<>\n\t\t\t<tr\n\t\t\t\tclassName={active ? \"turns-row active\" : \"turns-row\"}\n\t\t\t\tonClick={onExpand}\n\t\t\t\tstyle={{ cursor: \"pointer\" }}\n\t\t\t>\n\t\t\t\t<td>\n\t\t\t\t\t{expanded ? \"▾\" : \"▸\"} <code>{c.conversationId}</code>\n\t\t\t\t\t{active && <span className=\"pill\">active</span>}\n\t\t\t\t</td>\n\t\t\t\t<td>{c.turnCount}</td>\n\t\t\t\t<td>{c.totalRecall}</td>\n\t\t\t\t<td>{c.epochCount}</td>\n\t\t\t\t<td>{(c.avgCtxPercent * 100).toFixed(0)}%</td>\n\t\t\t\t<td>{fmtTs(c.lastTurnAt)}</td>\n\t\t\t\t<td />\n\t\t\t</tr>\n\t\t</>\n\t);\n}\n\nfunction TurnDetail({\n\tdetail,\n\tbusy,\n\tonFork,\n\tonRewind,\n}: {\n\tdetail: ConversationTurnsResponse;\n\tbusy: string | null;\n\tonFork: (conversationId: string, turnIndex: number) => void;\n\tonRewind: (conversationId: string, turnIndex: number) => void;\n}): React.ReactElement {\n\treturn (\n\t\t<table className=\"turns-detail-table\">\n\t\t\t<thead>\n\t\t\t\t<tr>\n\t\t\t\t\t<th>#</th>\n\t\t\t\t\t<th>Role</th>\n\t\t\t\t\t<th>Ctx</th>\n\t\t\t\t\t<th>Band</th>\n\t\t\t\t\t<th>Epoch</th>\n\t\t\t\t\t<th>Recalled checkpoints (memory recall)</th>\n\t\t\t\t\t<th>Ended</th>\n\t\t\t\t\t<th>Actions</th>\n\t\t\t\t</tr>\n\t\t\t</thead>\n\t\t\t<tbody>\n\t\t\t\t{detail.turns.map((t) => (\n\t\t\t\t\t<tr key={`${t.conversationId}:${t.turnIndex}`}>\n\t\t\t\t\t\t<td>{t.turnIndex}</td>\n\t\t\t\t\t\t<td>{t.role}</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t{t.ctxTokens ?? \"—\"}\n\t\t\t\t\t\t\t{t.ctxPercent != null && (\n\t\t\t\t\t\t\t\t<span className=\"muted\">\n\t\t\t\t\t\t\t\t\t{\" \"}\n\t\t\t\t\t\t\t\t\t· {(t.ctxPercent * 100).toFixed(0)}%\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t<span className={bandClass(t.pressureBand)}>\n\t\t\t\t\t\t\t\t{t.pressureBand ?? \"—\"}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>{t.epochId ? <code>{t.epochId.slice(0, 8)}</code> : \"—\"}</td>\n\t\t\t\t\t\t<td className=\"recall-cell\">\n\t\t\t\t\t\t\t{t.recall.length === 0 ? (\n\t\t\t\t\t\t\t\t<span className=\"muted\">—</span>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<ul className=\"recall-list\">\n\t\t\t\t\t\t\t\t\t{t.recall.map((r) => (\n\t\t\t\t\t\t\t\t\t\t<li key={r.checkpointId}>\n\t\t\t\t\t\t\t\t\t\t\t<code>{r.checkpointId.slice(0, 12)}</code>{\" \"}\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"muted\">\n\t\t\t\t\t\t\t\t\t\t\t\t{sourceLabel(r.source)} · {r.score.toFixed(2)}\n\t\t\t\t\t\t\t\t\t\t\t\t{r.raptorLevel != null ? ` · L${r.raptorLevel}` : \"\"}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>{fmtTs(t.endedAt)}</td>\n\t\t\t\t\t\t<td className=\"actions-cell\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"mini-btn\"\n\t\t\t\t\t\t\t\tdisabled={busy !== null}\n\t\t\t\t\t\t\t\tonClick={() => onFork(t.conversationId, t.turnIndex)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tfork\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"mini-btn\"\n\t\t\t\t\t\t\t\tdisabled={busy !== null}\n\t\t\t\t\t\t\t\tonClick={() => onRewind(t.conversationId, t.turnIndex)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\trewind\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\n\t\t\t\t))}\n\t\t\t</tbody>\n\t\t</table>\n\t);\n}\n"],"names":["fmtTs","ms","bandClass","band","sourceLabel","s","TurnsTab","turns","loading","error","useApi","useCallback","fetchTurns","intents","fetchTurnIntents","expanded","setExpanded","useState","detail","setDetail","detailLoading","setDetailLoading","busy","setBusy","notice","setNotice","expand","conversationId","d","fetchConversationTurns","onFork","turnIndex","out","postFork","e","onRewind","postTurnIntent","jsxs","jsx","i","c","ConversationRow","TurnDetail","active","onExpand","Fragment","t","r"],"mappings":"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"}
1
+ {"version":3,"file":"TurnsTab-CLNM0T5R.js","sources":["../../src/tabs/TurnsTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/tabs/TurnsTab.tsx — Turn-by-turn memory tracking + recall (S52).\n *\n * Fetches /api/turns (conversation list), expands the active conversation into\n * per-turn detail (/api/turns/conversation/:id), and renders:\n * - Conversation summary list (turn count, recall total, epochs, last turn).\n * - Per-turn rows: turn index, role, ctx tokens/percent + pressure band,\n * epoch id, and the injected-checkpoint recall set (the memory recalled\n * at each turn, with score + source).\n * - Pending rewind intents (S52A) + Fork action (S50C primitive).\n *\n * Read-mostly via /api/turns; fork/intent/prune via POST. No absolute URLs\n * (PREVENT-PI-004: loopback-only, same-origin static bundle).\n */\n\nimport type React from \"react\";\nimport { useCallback, useState } from \"react\";\nimport { useApi } from \"../hooks/useApi\";\nimport {\n\tfetchTurns,\n\tfetchConversationTurns,\n\tfetchTurnIntents,\n\tpostFork,\n\tpostTurnIntent,\n} from \"../api/client\";\nimport type {\n\tTurnsResponse,\n\tConversationTurnsResponse,\n\tRewindIntentsResponse,\n\tTurnRow,\n\tConversationSummary,\n} from \"@contracts\";\n\nfunction fmtTs(ms: number): string {\n\tif (!ms) return \"—\";\n\treturn new Date(ms).toLocaleString();\n}\n\nfunction bandClass(band: TurnRow[\"pressureBand\"]): string {\n\tif (band === \"green\") return \"band band-green\";\n\tif (band === \"yellow\") return \"band band-yellow\";\n\tif (band === \"red\") return \"band band-red\";\n\treturn \"band\";\n}\n\nfunction sourceLabel(s: TurnRow[\"recall\"][number][\"source\"]): string {\n\tif (s === \"checkpoint\") return \"ckpt\";\n\tif (s === \"cluster_summary\") return \"raptor\";\n\treturn \"mem\";\n}\n\nexport default function TurnsTab(): React.ReactElement {\n\tconst {\n\t\tdata: turns,\n\t\tloading,\n\t\terror,\n\t} = useApi<TurnsResponse>(\n\t\tuseCallback(() => fetchTurns(), []),\n\t\t{\n\t\t\tpollInterval: 10_000,\n\t\t},\n\t);\n\tconst { data: intents } = useApi<RewindIntentsResponse>(\n\t\tuseCallback(() => fetchTurnIntents(), []),\n\t\t{ pollInterval: 5_000 },\n\t);\n\tconst [expanded, setExpanded] = useState<string | null>(null);\n\tconst [detail, setDetail] = useState<ConversationTurnsResponse | null>(null);\n\tconst [detailLoading, setDetailLoading] = useState(false);\n\tconst [busy, setBusy] = useState<string | null>(null);\n\tconst [notice, setNotice] = useState<string | null>(null);\n\n\tconst expand = useCallback(\n\t\tasync (conversationId: string) => {\n\t\t\tif (expanded === conversationId) {\n\t\t\t\tsetExpanded(null);\n\t\t\t\tsetDetail(null);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsetExpanded(conversationId);\n\t\t\tsetDetailLoading(true);\n\t\t\tsetDetail(null);\n\t\t\ttry {\n\t\t\t\tconst d = await fetchConversationTurns(conversationId);\n\t\t\t\tsetDetail(d);\n\t\t\t} finally {\n\t\t\t\tsetDetailLoading(false);\n\t\t\t}\n\t\t},\n\t\t[expanded],\n\t);\n\n\tconst onFork = useCallback(\n\t\tasync (conversationId: string, turnIndex: number) => {\n\t\t\tsetBusy(`fork:${conversationId}:${turnIndex}`);\n\t\t\tsetNotice(null);\n\t\t\ttry {\n\t\t\t\tconst out = await postFork(conversationId, turnIndex);\n\t\t\t\tsetNotice(\n\t\t\t\t\t`Forked → ${out.childConversationId} (${out.recalledCount} recalled)`,\n\t\t\t\t);\n\t\t\t} catch (e) {\n\t\t\t\tsetNotice(`Fork failed: ${(e as Error).message}`);\n\t\t\t} finally {\n\t\t\t\tsetBusy(null);\n\t\t\t}\n\t\t},\n\t\t[],\n\t);\n\n\tconst onRewind = useCallback(\n\t\tasync (conversationId: string, turnIndex: number) => {\n\t\t\tsetBusy(`rewind:${conversationId}:${turnIndex}`);\n\t\t\tsetNotice(null);\n\t\t\ttry {\n\t\t\t\tawait postTurnIntent(conversationId, turnIndex);\n\t\t\t\tsetNotice(`Rewind intent queued for turn ${turnIndex}`);\n\t\t\t} catch (e) {\n\t\t\t\tsetNotice(`Rewind failed: ${(e as Error).message}`);\n\t\t\t} finally {\n\t\t\t\tsetBusy(null);\n\t\t\t}\n\t\t},\n\t\t[],\n\t);\n\n\tif (error && !turns) {\n\t\treturn <div className=\"tab-stub\">Error loading turns: {error.message}</div>;\n\t}\n\tif (loading && !turns) {\n\t\treturn <div className=\"tab-stub\">Loading turns…</div>;\n\t}\n\tif (!turns || turns.conversations.length === 0) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">\n\t\t\t\t<h3>Turn-by-turn memory</h3>\n\t\t\t\t<p>\n\t\t\t\t\tNo turns recorded yet. Per-turn tracking starts when{\" \"}\n\t\t\t\t\t<code>MEGACOMPACT_TURNS_DB=1</code> and the session runs through a\n\t\t\t\t\tcompaction. Each turn records its context metrics + the checkpoints\n\t\t\t\t\trecalled into it.\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className=\"turns-tab\">\n\t\t\t<h3>Turn-by-turn memory tracking + recall</h3>\n\t\t\t{notice && <div className=\"turns-notice\">{notice}</div>}\n\n\t\t\t{intents && intents.intents.length > 0 && (\n\t\t\t\t<section className=\"turns-intents\">\n\t\t\t\t\t<h4>Pending rewind intents ({intents.intents.length})</h4>\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t{intents.intents.map((i) => (\n\t\t\t\t\t\t\t<li key={i.id}>\n\t\t\t\t\t\t\t\t{fmtTs(i.createdAt)} — rewind <code>{i.conversationId}</code> to\n\t\t\t\t\t\t\t\tturn {i.targetTurnIndex}\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</ul>\n\t\t\t\t</section>\n\t\t\t)}\n\n\t\t\t<section className=\"turns-conv-list\">\n\t\t\t\t<h4>Conversations ({turns.conversations.length})</h4>\n\t\t\t\t<table className=\"turns-table\">\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<th>Conversation</th>\n\t\t\t\t\t\t\t<th>Turns</th>\n\t\t\t\t\t\t\t<th>Recall</th>\n\t\t\t\t\t\t\t<th>Epochs</th>\n\t\t\t\t\t\t\t<th>Avg ctx%</th>\n\t\t\t\t\t\t\t<th>Last turn</th>\n\t\t\t\t\t\t\t<th></th>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</thead>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t{turns.conversations.map((c: ConversationSummary) => (\n\t\t\t\t\t\t\t<ConversationRow\n\t\t\t\t\t\t\t\tkey={c.conversationId}\n\t\t\t\t\t\t\t\tc={c}\n\t\t\t\t\t\t\t\tactive={turns.activeConversationId === c.conversationId}\n\t\t\t\t\t\t\t\texpanded={expanded === c.conversationId}\n\t\t\t\t\t\t\t\tonExpand={() => expand(c.conversationId)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</tbody>\n\t\t\t\t</table>\n\t\t\t</section>\n\n\t\t\t{expanded && (\n\t\t\t\t<section className=\"turns-detail\">\n\t\t\t\t\t<h4>\n\t\t\t\t\t\tTurns in <code>{expanded}</code>\n\t\t\t\t\t</h4>\n\t\t\t\t\t{detailLoading ? (\n\t\t\t\t\t\t<div className=\"tab-stub\">Loading turns…</div>\n\t\t\t\t\t) : detail ? (\n\t\t\t\t\t\t<TurnDetail\n\t\t\t\t\t\t\tdetail={detail}\n\t\t\t\t\t\t\tbusy={busy}\n\t\t\t\t\t\t\tonFork={onFork}\n\t\t\t\t\t\t\tonRewind={onRewind}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<div className=\"tab-stub\">No detail.</div>\n\t\t\t\t\t)}\n\t\t\t\t</section>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction ConversationRow({\n\tc,\n\tactive,\n\texpanded,\n\tonExpand,\n}: {\n\tc: ConversationSummary;\n\tactive: boolean;\n\texpanded: boolean;\n\tonExpand: () => void;\n}): React.ReactElement {\n\treturn (\n\t\t<>\n\t\t\t<tr\n\t\t\t\tclassName={active ? \"turns-row active\" : \"turns-row\"}\n\t\t\t\tonClick={onExpand}\n\t\t\t\tstyle={{ cursor: \"pointer\" }}\n\t\t\t>\n\t\t\t\t<td>\n\t\t\t\t\t{expanded ? \"▾\" : \"▸\"} <code>{c.conversationId}</code>\n\t\t\t\t\t{active && <span className=\"pill\">active</span>}\n\t\t\t\t</td>\n\t\t\t\t<td>{c.turnCount}</td>\n\t\t\t\t<td>{c.totalRecall}</td>\n\t\t\t\t<td>{c.epochCount}</td>\n\t\t\t\t<td>{(c.avgCtxPercent * 100).toFixed(0)}%</td>\n\t\t\t\t<td>{fmtTs(c.lastTurnAt)}</td>\n\t\t\t\t<td />\n\t\t\t</tr>\n\t\t</>\n\t);\n}\n\nfunction TurnDetail({\n\tdetail,\n\tbusy,\n\tonFork,\n\tonRewind,\n}: {\n\tdetail: ConversationTurnsResponse;\n\tbusy: string | null;\n\tonFork: (conversationId: string, turnIndex: number) => void;\n\tonRewind: (conversationId: string, turnIndex: number) => void;\n}): React.ReactElement {\n\treturn (\n\t\t<table className=\"turns-detail-table\">\n\t\t\t<thead>\n\t\t\t\t<tr>\n\t\t\t\t\t<th>#</th>\n\t\t\t\t\t<th>Role</th>\n\t\t\t\t\t<th>Ctx</th>\n\t\t\t\t\t<th>Band</th>\n\t\t\t\t\t<th>Epoch</th>\n\t\t\t\t\t<th>Recalled checkpoints (memory recall)</th>\n\t\t\t\t\t<th>Ended</th>\n\t\t\t\t\t<th>Actions</th>\n\t\t\t\t</tr>\n\t\t\t</thead>\n\t\t\t<tbody>\n\t\t\t\t{detail.turns.map((t) => (\n\t\t\t\t\t<tr key={`${t.conversationId}:${t.turnIndex}`}>\n\t\t\t\t\t\t<td>{t.turnIndex}</td>\n\t\t\t\t\t\t<td>{t.role}</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t{t.ctxTokens ?? \"—\"}\n\t\t\t\t\t\t\t{t.ctxPercent != null && (\n\t\t\t\t\t\t\t\t<span className=\"muted\">\n\t\t\t\t\t\t\t\t\t{\" \"}\n\t\t\t\t\t\t\t\t\t· {(t.ctxPercent * 100).toFixed(0)}%\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t<span className={bandClass(t.pressureBand)}>\n\t\t\t\t\t\t\t\t{t.pressureBand ?? \"—\"}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>{t.epochId ? <code>{t.epochId.slice(0, 8)}</code> : \"—\"}</td>\n\t\t\t\t\t\t<td className=\"recall-cell\">\n\t\t\t\t\t\t\t{t.recall.length === 0 ? (\n\t\t\t\t\t\t\t\t<span className=\"muted\">—</span>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<ul className=\"recall-list\">\n\t\t\t\t\t\t\t\t\t{t.recall.map((r) => (\n\t\t\t\t\t\t\t\t\t\t<li key={r.checkpointId}>\n\t\t\t\t\t\t\t\t\t\t\t<code>{r.checkpointId.slice(0, 12)}</code>{\" \"}\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"muted\">\n\t\t\t\t\t\t\t\t\t\t\t\t{sourceLabel(r.source)} · {r.score.toFixed(2)}\n\t\t\t\t\t\t\t\t\t\t\t\t{r.raptorLevel != null ? ` · L${r.raptorLevel}` : \"\"}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>{fmtTs(t.endedAt)}</td>\n\t\t\t\t\t\t<td className=\"actions-cell\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"mini-btn\"\n\t\t\t\t\t\t\t\tdisabled={busy !== null}\n\t\t\t\t\t\t\t\tonClick={() => onFork(t.conversationId, t.turnIndex)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tfork\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"mini-btn\"\n\t\t\t\t\t\t\t\tdisabled={busy !== null}\n\t\t\t\t\t\t\t\tonClick={() => onRewind(t.conversationId, t.turnIndex)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\trewind\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\n\t\t\t\t))}\n\t\t\t</tbody>\n\t\t</table>\n\t);\n}\n"],"names":["fmtTs","ms","bandClass","band","sourceLabel","s","TurnsTab","turns","loading","error","useApi","useCallback","fetchTurns","intents","fetchTurnIntents","expanded","setExpanded","useState","detail","setDetail","detailLoading","setDetailLoading","busy","setBusy","notice","setNotice","expand","conversationId","d","fetchConversationTurns","onFork","turnIndex","out","postFork","e","onRewind","postTurnIntent","jsxs","jsx","i","c","ConversationRow","TurnDetail","active","onExpand","Fragment","t","r"],"mappings":"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"}