@@ -44,6 +44,7 @@ import {
4444 handleGetUsageStats ,
4545 handleClearUsageStats ,
4646 handleExportUsageStats ,
47+ handleRebuildUsageStats ,
4748 handleRequestClearNonce ,
4849 handleGetDashboardSessions ,
4950 handleGetDashboardSessionDetail ,
@@ -1688,6 +1689,98 @@ describe("usageStatsMessageHandler", () => {
16881689 } )
16891690 } )
16901691
1692+ // ── handleRebuildUsageStats ───────────────────────────────────────────────
1693+
1694+ describe ( "handleRebuildUsageStats" , ( ) => {
1695+ it ( "rebuilds rollups and posts success result" , async ( ) => {
1696+ const rebuildRollupsFromEvents = vi . fn ( )
1697+ const getDatabase = vi . fn ( ( ) => ( { rebuildRollupsFromEvents } ) )
1698+ const provider = createMockProvider ( { getDatabase } as any )
1699+
1700+ const message : WebviewMessage = {
1701+ type : "rebuildUsageStats" ,
1702+ requestId : "req-rebuild-1" ,
1703+ }
1704+
1705+ await handleRebuildUsageStats ( provider , message )
1706+
1707+ expect ( rebuildRollupsFromEvents ) . toHaveBeenCalledTimes ( 1 )
1708+ expect ( provider . postMessageToWebview ) . toHaveBeenCalledWith ( {
1709+ type : "usageStatsChanged" ,
1710+ } )
1711+ expect ( provider . postMessageToWebview ) . toHaveBeenCalledWith ( {
1712+ type : "rebuildUsageStatsResponse" ,
1713+ requestId : "req-rebuild-1" ,
1714+ rebuildUsageStatsResult : { success : true } ,
1715+ } )
1716+ } )
1717+
1718+ it ( "returns error when service is unavailable" , async ( ) => {
1719+ const provider = createMockProvider ( undefined )
1720+
1721+ const message : WebviewMessage = {
1722+ type : "rebuildUsageStats" ,
1723+ requestId : "req-rebuild-2" ,
1724+ }
1725+
1726+ await handleRebuildUsageStats ( provider , message )
1727+
1728+ expect ( provider . postMessageToWebview ) . toHaveBeenCalledWith ( {
1729+ type : "rebuildUsageStatsResponse" ,
1730+ requestId : "req-rebuild-2" ,
1731+ rebuildUsageStatsResult : {
1732+ success : false ,
1733+ error : expect . stringContaining ( "STATS_HANDLER/rebuild/002" ) ,
1734+ } ,
1735+ } )
1736+ } )
1737+
1738+ it ( "returns error when database is not initialized" , async ( ) => {
1739+ const getDatabase = vi . fn ( ( ) => null )
1740+ const provider = createMockProvider ( { getDatabase } as any )
1741+
1742+ const message : WebviewMessage = {
1743+ type : "rebuildUsageStats" ,
1744+ requestId : "req-rebuild-3" ,
1745+ }
1746+
1747+ await handleRebuildUsageStats ( provider , message )
1748+
1749+ expect ( provider . postMessageToWebview ) . toHaveBeenCalledWith ( {
1750+ type : "rebuildUsageStatsResponse" ,
1751+ requestId : "req-rebuild-3" ,
1752+ rebuildUsageStatsResult : {
1753+ success : false ,
1754+ error : expect . stringContaining ( "STATS_HANDLER/rebuild/001" ) ,
1755+ } ,
1756+ } )
1757+ } )
1758+
1759+ it ( "returns error when rebuild throws" , async ( ) => {
1760+ const rebuildRollupsFromEvents = vi . fn ( ( ) => {
1761+ throw new Error ( "disk full" )
1762+ } )
1763+ const getDatabase = vi . fn ( ( ) => ( { rebuildRollupsFromEvents } ) )
1764+ const provider = createMockProvider ( { getDatabase } as any )
1765+
1766+ const message : WebviewMessage = {
1767+ type : "rebuildUsageStats" ,
1768+ requestId : "req-rebuild-4" ,
1769+ }
1770+
1771+ await handleRebuildUsageStats ( provider , message )
1772+
1773+ expect ( provider . postMessageToWebview ) . toHaveBeenCalledWith ( {
1774+ type : "rebuildUsageStatsResponse" ,
1775+ requestId : "req-rebuild-4" ,
1776+ rebuildUsageStatsResult : {
1777+ success : false ,
1778+ error : expect . stringContaining ( "STATS_HANDLER/rebuild/003" ) ,
1779+ } ,
1780+ } )
1781+ } )
1782+ } )
1783+
16911784 // ── History-first Dashboard task handlers ──────────────────────────────────
16921785
16931786 describe ( "handleGetDashboardTaskDetail" , ( ) => {
@@ -1766,6 +1859,71 @@ describe("usageStatsMessageHandler", () => {
17661859 toMs : Date . parse ( "2026-08-15T00:00:00.000Z" ) ,
17671860 } )
17681861 } )
1862+
1863+ it ( "returns error when taskId is missing" , async ( ) => {
1864+ const provider = createMockProvider ( { getDatabase : ( ) => null } as any )
1865+
1866+ await handleGetDashboardTaskDetail ( provider , {
1867+ type : "getDashboardTaskDetail" ,
1868+ requestId : "task-detail-missing" ,
1869+ // No taskId or text
1870+ } )
1871+
1872+ expect ( provider . postMessageToWebview ) . toHaveBeenCalledWith ( {
1873+ type : "dashboardTaskDetailResponse" ,
1874+ requestId : "task-detail-missing" ,
1875+ dashboardTaskDetail : null ,
1876+ error : expect . stringContaining ( "STATS_HANDLER/taskDetail/001" ) ,
1877+ } )
1878+ } )
1879+
1880+ it ( "returns error when database or task catalog is unavailable" , async ( ) => {
1881+ const provider = createMockProvider ( {
1882+ getDatabase : ( ) => null ,
1883+ getTaskCatalog : ( ) => null ,
1884+ } as any )
1885+
1886+ await handleGetDashboardTaskDetail ( provider , {
1887+ type : "getDashboardTaskDetail" ,
1888+ requestId : "task-detail-unavailable" ,
1889+ taskId : "root" ,
1890+ } )
1891+
1892+ expect ( provider . postMessageToWebview ) . toHaveBeenCalledWith ( {
1893+ type : "dashboardTaskDetailResponse" ,
1894+ requestId : "task-detail-unavailable" ,
1895+ dashboardTaskDetail : null ,
1896+ error : expect . stringContaining ( "STATS_HANDLER/taskDetail/002" ) ,
1897+ } )
1898+ } )
1899+
1900+ it ( "returns error when the projection throws" , async ( ) => {
1901+ const mockDb = createMockDatabase ( )
1902+ const taskCatalog = {
1903+ byId : new Map ( [ [ "root" , { id : "root" , task : "History root" , ts : 123 } ] ] ) ,
1904+ getDescendantTaskIds : vi . fn ( ( ) => {
1905+ throw new Error ( "catalog corrupted" )
1906+ } ) ,
1907+ }
1908+ const provider = createMockProvider ( {
1909+ getDatabase : ( ) => mockDb ,
1910+ getTaskCatalog : ( ) => taskCatalog ,
1911+ getCoordinator : ( ) => null ,
1912+ } as any )
1913+
1914+ await handleGetDashboardTaskDetail ( provider , {
1915+ type : "getDashboardTaskDetail" ,
1916+ requestId : "task-detail-throw" ,
1917+ taskId : "root" ,
1918+ } )
1919+
1920+ expect ( provider . postMessageToWebview ) . toHaveBeenCalledWith ( {
1921+ type : "dashboardTaskDetailResponse" ,
1922+ requestId : "task-detail-throw" ,
1923+ dashboardTaskDetail : null ,
1924+ error : expect . stringContaining ( "STATS_HANDLER/taskDetail/003" ) ,
1925+ } )
1926+ } )
17691927 } )
17701928
17711929 describe ( "handleGetDashboardTaskPage" , ( ) => {
0 commit comments