@zaip-ai/cli 1.0.7 → 1.0.8

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 (410) hide show
  1. package/README.md +6 -4
  2. package/dist/services/adapters.d.ts +1 -1
  3. package/dist/services/adapters.d.ts.map +1 -1
  4. package/dist/services/adapters.js +15 -5
  5. package/dist/services/adapters.js.map +1 -1
  6. package/dist/services/adapters.test.js +1 -1
  7. package/dist/services/agent-adapters.d.ts +9 -0
  8. package/dist/services/agent-adapters.d.ts.map +1 -1
  9. package/dist/services/agent-adapters.js +38 -3
  10. package/dist/services/agent-adapters.js.map +1 -1
  11. package/dist/services/agent-adapters.test.js +8 -1
  12. package/dist/services/agent-adapters.test.js.map +1 -1
  13. package/dist/services/codex-config-template.d.ts +2 -1
  14. package/dist/services/codex-config-template.d.ts.map +1 -1
  15. package/dist/services/codex-config-template.js +13 -2
  16. package/dist/services/codex-config-template.js.map +1 -1
  17. package/dist/services/codex-rules.d.ts +1 -1
  18. package/dist/services/codex-rules.d.ts.map +1 -1
  19. package/dist/services/codex-rules.js +31 -7
  20. package/dist/services/codex-rules.js.map +1 -1
  21. package/dist/services/codex-subagent-hook-template.d.ts +1 -1
  22. package/dist/services/codex-subagent-hook-template.d.ts.map +1 -1
  23. package/dist/services/codex-subagent-hook-template.js +4 -1
  24. package/dist/services/codex-subagent-hook-template.js.map +1 -1
  25. package/dist/services/doctor.d.ts.map +1 -1
  26. package/dist/services/doctor.js +3 -1
  27. package/dist/services/doctor.js.map +1 -1
  28. package/dist/services/global-codex-config.d.ts +6 -3
  29. package/dist/services/global-codex-config.d.ts.map +1 -1
  30. package/dist/services/global-codex-config.js +82 -13
  31. package/dist/services/global-codex-config.js.map +1 -1
  32. package/dist/services/global-codex-config.test.js +57 -10
  33. package/dist/services/global-codex-config.test.js.map +1 -1
  34. package/dist/services/install-agents-template.d.ts.map +1 -1
  35. package/dist/services/install-agents-template.js +15 -2
  36. package/dist/services/install-agents-template.js.map +1 -1
  37. package/dist/services/logger.js +1 -1
  38. package/dist/services/logger.js.map +1 -1
  39. package/dist/services/logger.test.js +3 -3
  40. package/dist/services/logger.test.js.map +1 -1
  41. package/dist/services/runtime-template.test.js +21 -5
  42. package/dist/services/runtime-template.test.js.map +1 -1
  43. package/dist/services/template-manifest.d.ts.map +1 -1
  44. package/dist/services/template-manifest.js +2 -0
  45. package/dist/services/template-manifest.js.map +1 -1
  46. package/package.json +1 -1
  47. package/templates/.agents/config/agents/catalog.yaml +310 -10
  48. package/templates/.agents/config/clients/codex/agents/zaip-agent-brand-strategist.toml +30 -0
  49. package/templates/.agents/config/clients/codex/agents/zaip-agent-designer.toml +5 -5
  50. package/templates/.agents/config/clients/codex/agents/zaip-agent-finalizer.toml +1 -1
  51. package/templates/.agents/config/clients/codex/agents/zaip-agent-general-operations.toml +30 -0
  52. package/templates/.agents/config/clients/codex/agents/zaip-agent-governance-compliance.toml +30 -0
  53. package/templates/.agents/config/clients/codex/agents/zaip-agent-growth-strategist.toml +30 -0
  54. package/templates/.agents/config/clients/codex/agents/zaip-agent-marketing-analyst.toml +8 -8
  55. package/templates/.agents/config/clients/codex/agents/zaip-agent-orchestrator.toml +5 -3
  56. package/templates/.agents/config/clients/codex/agents/zaip-agent-sales-specialist.toml +30 -0
  57. package/templates/.agents/config/project.yaml +1 -1
  58. package/templates/.agents/dashboard/.zaip-managed.json +659 -163
  59. package/templates/.agents/dashboard/DATA-DICTIONARY.md +2227 -0
  60. package/templates/.agents/dashboard/README.md +48 -97
  61. package/templates/.agents/dashboard/apps/frontend/dist/assets/CostCalculationGuidePage-Z60df2r-.js +1 -0
  62. package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-Cv-JcoxP.js → DashboardHelpDialog-Cs6dzDmW.js} +294 -109
  63. package/templates/.agents/dashboard/apps/frontend/dist/assets/PricingSettingsDialog-Coc6pA-1.js +1 -0
  64. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-QE1k9yZB.css +1 -0
  65. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-_Pf5DA_A.js +3 -0
  66. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-BVlz3DLZ.js +1 -0
  67. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-CaKwQP43.css +1 -0
  68. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-BZ5WdaMN.css +1 -0
  69. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-Cf9ctPVt.js +68 -0
  70. package/templates/.agents/dashboard/apps/frontend/dist/assets/{dashboard-localization-C98LGC-Q.js → dashboard-localization-CLJ0lT9v.js} +1 -1
  71. package/templates/.agents/dashboard/apps/frontend/dist/assets/icons-vendor-DFBuc_qp.js +1 -0
  72. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-8A4DcNXM.js +2 -0
  73. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-DK_enB5Z.css +1 -0
  74. package/templates/.agents/dashboard/apps/frontend/dist/assets/react-vendor-CCQOHdVI.js +9 -0
  75. package/templates/.agents/dashboard/apps/frontend/dist/assets/rolldown-runtime-D9-fqq9M.js +1 -0
  76. package/templates/.agents/dashboard/apps/frontend/dist/assets/traceability-DFY7ZDlu.css +1 -0
  77. package/templates/.agents/dashboard/apps/frontend/dist/assets/traceability-pC2_0J8x.js +1 -0
  78. package/templates/.agents/dashboard/apps/frontend/dist/index.html +9 -2
  79. package/templates/.agents/dashboard/apps/frontend/package.json +1 -1
  80. package/templates/.agents/dashboard/apps/frontend/src/App.tsx +952 -595
  81. package/templates/.agents/dashboard/apps/frontend/src/AppLoadingBoundary.tsx +48 -0
  82. package/templates/.agents/dashboard/apps/frontend/src/AppLoadingPanels.tsx +2 -0
  83. package/templates/.agents/dashboard/apps/frontend/src/AppOverlays.tsx +247 -0
  84. package/templates/.agents/dashboard/apps/frontend/src/AppRequestGuards.tsx +95 -0
  85. package/templates/.agents/dashboard/apps/frontend/src/AppSetupRoutes.tsx +87 -0
  86. package/templates/.agents/dashboard/apps/frontend/src/CostCalculationGuidePage.tsx +641 -0
  87. package/templates/.agents/dashboard/apps/frontend/src/DashboardAlternateContent.tsx +159 -0
  88. package/templates/.agents/dashboard/apps/frontend/src/DashboardCapabilityNav.tsx +13 -13
  89. package/templates/.agents/dashboard/apps/frontend/src/DashboardGlobalSettings.tsx +56 -0
  90. package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsPage.tsx +257 -313
  91. package/templates/.agents/dashboard/apps/frontend/src/ProjectStackEditor.tsx +149 -0
  92. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.test.ts +35 -0
  93. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.tsx +111 -12
  94. package/templates/.agents/dashboard/apps/frontend/src/app-preferences.ts +15 -0
  95. package/templates/.agents/dashboard/apps/frontend/src/app-session-token.ts +20 -0
  96. package/templates/.agents/dashboard/apps/frontend/src/cost-calculation-guide.css +267 -0
  97. package/templates/.agents/dashboard/apps/frontend/src/cost-calculation-guide.test.ts +69 -0
  98. package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +70 -0
  99. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +111 -0
  100. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +432 -13
  101. package/templates/.agents/dashboard/apps/frontend/src/dashboard-localization.ts +1 -1
  102. package/templates/.agents/dashboard/apps/frontend/src/main.tsx +1 -0
  103. package/templates/.agents/dashboard/apps/frontend/src/operations-detail-hydration.test.ts +55 -0
  104. package/templates/.agents/dashboard/apps/frontend/src/operations-detail-hydration.ts +36 -0
  105. package/templates/.agents/dashboard/apps/frontend/src/operations-entity-page-projection.test.ts +126 -0
  106. package/templates/.agents/dashboard/apps/frontend/src/operations-entity-page-projection.ts +181 -0
  107. package/templates/.agents/dashboard/apps/frontend/src/operations-period-contract.test.ts +138 -0
  108. package/templates/.agents/dashboard/apps/frontend/src/operations-period-render.test.ts +105 -0
  109. package/templates/.agents/dashboard/apps/frontend/src/operations-period.test.ts +6 -3
  110. package/templates/.agents/dashboard/apps/frontend/src/operations-period.ts +9 -5
  111. package/templates/.agents/dashboard/apps/frontend/src/overview-status-page.test.ts +24 -0
  112. package/templates/.agents/dashboard/apps/frontend/src/period-transition-overlay.css +44 -0
  113. package/templates/.agents/dashboard/apps/frontend/src/project-settings-model.ts +121 -62
  114. package/templates/.agents/dashboard/apps/frontend/src/project-settings-page.css +471 -2
  115. package/templates/.agents/dashboard/apps/frontend/src/project-settings.test.ts +84 -17
  116. package/templates/.agents/dashboard/apps/frontend/src/snapshot-banner-semantics.test.ts +44 -0
  117. package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +196 -39
  118. package/templates/.agents/dashboard/apps/frontend/src/snapshot-notice.ts +15 -0
  119. package/templates/.agents/dashboard/apps/frontend/src/sqlite-cost-adapters.ts +26 -0
  120. package/templates/.agents/dashboard/apps/frontend/src/styles.css +14 -2
  121. package/templates/.agents/dashboard/apps/frontend/src/traceability-workspace.css +38 -2
  122. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.test.ts +187 -0
  123. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.ts +190 -0
  124. package/templates/.agents/dashboard/apps/frontend/src/use-app-effects.ts +121 -0
  125. package/templates/.agents/dashboard/apps/frontend/src/use-app-operations-pages.ts +398 -0
  126. package/templates/.agents/dashboard/apps/frontend/src/use-app-trace-documents.ts +141 -0
  127. package/templates/.agents/dashboard/apps/frontend/src/use-idle-cost-prefetch.ts +45 -0
  128. package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.test.ts +46 -0
  129. package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.ts +37 -0
  130. package/templates/.agents/dashboard/apps/frontend/vite.config.ts +55 -5
  131. package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
  132. package/templates/.agents/dashboard/modules/cost-monitor/src/contracts.ts +47 -6
  133. package/templates/.agents/dashboard/modules/cost-monitor/src/duration-estimate.ts +13 -0
  134. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.test.ts +64 -0
  135. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.tsx +275 -0
  136. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostCharts.test.ts +100 -15
  137. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostCharts.tsx +131 -40
  138. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.tsx +137 -19
  139. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostModelsAuditTable.test.ts +2 -0
  140. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostModelsAuditTable.tsx +13 -10
  141. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorContent.tsx +303 -0
  142. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.test.ts +226 -6
  143. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +479 -402
  144. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostSummary.tsx +5 -13
  145. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +312 -72
  146. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.tsx +373 -321
  147. package/templates/.agents/dashboard/modules/cost-monitor/src/react/MacroCostTable.test.ts +17 -0
  148. package/templates/.agents/dashboard/modules/cost-monitor/src/react/MacroCostTable.tsx +25 -6
  149. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-copy.ts +0 -2
  150. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-page-helpers.ts +17 -0
  151. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-responsive.css +6 -3
  152. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-row-filters.ts +123 -0
  153. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-summary.ts +8 -3
  154. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-views.ts +32 -0
  155. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor.css +52 -14
  156. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-table-presentation.ts +121 -0
  157. package/templates/.agents/dashboard/modules/cost-monitor/src/react/index.ts +3 -0
  158. package/templates/.agents/dashboard/modules/cost-monitor/src/react/period-cost-groups.test.ts +68 -0
  159. package/templates/.agents/dashboard/modules/cost-monitor/src/react/period-cost-groups.ts +32 -5
  160. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-compact-cost-page.ts +108 -0
  161. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.test.ts +12 -0
  162. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.ts +60 -0
  163. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-run-page.ts +106 -0
  164. package/templates/.agents/dashboard/modules/cost-monitor/src/server/aggregate.test.ts +2 -2
  165. package/templates/.agents/dashboard/modules/cost-monitor/src/server/aggregate.ts +5 -3
  166. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-pricing-fallback.test.ts +53 -0
  167. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.basics.test.ts +34 -0
  168. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.test.ts +168 -137
  169. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.ts +188 -29
  170. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.test.ts +956 -0
  171. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.ts +775 -0
  172. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-terminal-day.test.ts +95 -0
  173. package/templates/.agents/dashboard/modules/cost-monitor/src/server/index.ts +1 -0
  174. package/templates/.agents/dashboard/modules/cost-monitor/src/server/refactor-map-xr9l.json +61 -0
  175. package/templates/.agents/dashboard/modules/cost-monitor/src/task-cost-groups.test.ts +41 -0
  176. package/templates/.agents/dashboard/modules/cost-monitor/src/task-cost-groups.ts +55 -11
  177. package/templates/.agents/dashboard/modules/operations/package.json +2 -1
  178. package/templates/.agents/dashboard/modules/operations/src/contracts.ts +182 -0
  179. package/templates/.agents/dashboard/modules/operations/src/duration-population.test.ts +63 -1
  180. package/templates/.agents/dashboard/modules/operations/src/duration-population.ts +60 -5
  181. package/templates/.agents/dashboard/modules/operations/src/react/EntityDetailsDialog.tsx +14 -3
  182. package/templates/.agents/dashboard/modules/operations/src/react/EntityTables.test.ts +44 -1
  183. package/templates/.agents/dashboard/modules/operations/src/react/EntityTables.tsx +325 -18
  184. package/templates/.agents/dashboard/modules/operations/src/react/MacroPlanningDialog.tsx +1 -0
  185. package/templates/.agents/dashboard/modules/operations/src/react/OperationDateFilters.test.ts +9 -5
  186. package/templates/.agents/dashboard/modules/operations/src/react/OperationDateFilters.tsx +2 -2
  187. package/templates/.agents/dashboard/modules/operations/src/react/OperationsMainContent.tsx +168 -0
  188. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.helpers.tsx +95 -6
  189. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.test.ts +365 -14
  190. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +532 -131
  191. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +314 -358
  192. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageNavigation.tsx +68 -0
  193. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageOverview.tsx +169 -0
  194. package/templates/.agents/dashboard/modules/operations/src/react/PeriodSummaryTable.tsx +51 -8
  195. package/templates/.agents/dashboard/modules/operations/src/react/PrdDocumentDialog.test.tsx +32 -0
  196. package/templates/.agents/dashboard/modules/operations/src/react/PrdDocumentDialog.tsx +62 -6
  197. package/templates/.agents/dashboard/modules/operations/src/react/TaskBoard.test.ts +55 -0
  198. package/templates/.agents/dashboard/modules/operations/src/react/TaskBoard.tsx +27 -19
  199. package/templates/.agents/dashboard/modules/operations/src/react/TaskDetailsDialog.tsx +99 -42
  200. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkBoard.priority.test.ts +19 -0
  201. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkBoard.tsx +255 -34
  202. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.test.ts +163 -8
  203. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.tsx +101 -68
  204. package/templates/.agents/dashboard/modules/operations/src/react/conversation-rows.test.ts +72 -1
  205. package/templates/.agents/dashboard/modules/operations/src/react/conversation-rows.ts +78 -16
  206. package/templates/.agents/dashboard/modules/operations/src/react/execution-metrics.ts +6 -4
  207. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +50 -1
  208. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +143 -9
  209. package/templates/.agents/dashboard/modules/operations/src/react/export/export-layout.test.ts +29 -4
  210. package/templates/.agents/dashboard/modules/operations/src/react/macro-planning-dialog-content.css +49 -0
  211. package/templates/.agents/dashboard/modules/operations/src/react/macro-planning-dialog.css +93 -50
  212. package/templates/.agents/dashboard/modules/operations/src/react/manual-work-priority.test.ts +82 -0
  213. package/templates/.agents/dashboard/modules/operations/src/react/operation-date-range.test.ts +29 -2
  214. package/templates/.agents/dashboard/modules/operations/src/react/operation-date-range.ts +22 -1
  215. package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.test.ts +77 -4
  216. package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.ts +65 -5
  217. package/templates/.agents/dashboard/modules/operations/src/react/operations-coverage-toast.test.ts +54 -0
  218. package/templates/.agents/dashboard/modules/operations/src/react/operations-global-filters.test.ts +19 -0
  219. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +149 -12
  220. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview.status-cards.test.ts +27 -0
  221. package/templates/.agents/dashboard/modules/operations/src/react/operations-page-contract.ts +136 -0
  222. package/templates/.agents/dashboard/modules/operations/src/react/operations-period-scope.test.ts +160 -0
  223. package/templates/.agents/dashboard/modules/operations/src/react/operations-period-scope.ts +47 -0
  224. package/templates/.agents/dashboard/modules/operations/src/react/operations-query.ts +10 -0
  225. package/templates/.agents/dashboard/modules/operations/src/react/operations-responsive.css +3 -0
  226. package/templates/.agents/dashboard/modules/operations/src/react/operations-view-labels.ts +28 -0
  227. package/templates/.agents/dashboard/modules/operations/src/react/operations-view-order.test.ts +24 -7
  228. package/templates/.agents/dashboard/modules/operations/src/react/operations.css +42 -0
  229. package/templates/.agents/dashboard/modules/operations/src/react/period-summary-population.test.ts +54 -0
  230. package/templates/.agents/dashboard/modules/operations/src/react/period-summary-population.ts +32 -0
  231. package/templates/.agents/dashboard/modules/operations/src/react/period-summary.test.ts +165 -6
  232. package/templates/.agents/dashboard/modules/operations/src/react/period-summary.ts +148 -6
  233. package/templates/.agents/dashboard/modules/operations/src/react/popup-localization.test.ts +1 -1
  234. package/templates/.agents/dashboard/modules/operations/src/react/unified-work-board.css +132 -0
  235. package/templates/.agents/dashboard/modules/operations/src/react/unified-work-board.css.test.ts +13 -0
  236. package/templates/.agents/dashboard/modules/operations/src/react/unified-work-board.header.test.ts +16 -0
  237. package/templates/.agents/dashboard/modules/operations/src/react/use-infinite-column.ts +11 -5
  238. package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.test.ts +5 -3
  239. package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.ts +4 -83
  240. package/templates/.agents/dashboard/modules/operations/src/server/build-operations-projection.test.ts +291 -15
  241. package/templates/.agents/dashboard/modules/operations/src/server/build-operations-projection.ts +182 -472
  242. package/templates/.agents/dashboard/modules/operations/src/server/canonical-compat.test.ts +40 -0
  243. package/templates/.agents/dashboard/modules/operations/src/server/canonical-compat.ts +19 -6
  244. package/templates/.agents/dashboard/modules/operations/src/server/canonical-run-projection.ts +31 -6
  245. package/templates/.agents/dashboard/modules/operations/src/server/daily-duration-projection.ts +220 -0
  246. package/templates/.agents/dashboard/modules/operations/src/server/execution-duration-projection.ts +28 -0
  247. package/templates/.agents/dashboard/modules/operations/src/server/execution-relationship-counts.test.ts +27 -2
  248. package/templates/.agents/dashboard/modules/operations/src/server/execution-relationship-counts.ts +22 -13
  249. package/templates/.agents/dashboard/modules/operations/src/server/filter.test.ts +3 -3
  250. package/templates/.agents/dashboard/modules/operations/src/server/filter.ts +7 -2
  251. package/templates/.agents/dashboard/modules/operations/src/server/index.ts +3 -0
  252. package/templates/.agents/dashboard/modules/operations/src/server/macro.ts +3 -12
  253. package/templates/.agents/dashboard/modules/operations/src/server/manifest-usage.ts +65 -0
  254. package/templates/.agents/dashboard/modules/operations/src/server/operations-projection-aggregates.ts +297 -0
  255. package/templates/.agents/dashboard/modules/operations/src/server/quick-daily-operations-projection.ts +324 -0
  256. package/templates/.agents/dashboard/modules/operations/src/server/quick-operations-projection.test.ts +505 -0
  257. package/templates/.agents/dashboard/modules/operations/src/server/quick-operations-projection.ts +609 -0
  258. package/templates/.agents/dashboard/modules/operations/src/server/runs.ts +18 -19
  259. package/templates/.agents/dashboard/modules/operations/src/work-board-model.ts +76 -0
  260. package/templates/.agents/dashboard/modules/traceability/package.json +1 -1
  261. package/templates/.agents/dashboard/modules/traceability/src/server/build-task-trace.ts +3 -1
  262. package/templates/.agents/dashboard/packages/branding/package.json +1 -1
  263. package/templates/.agents/dashboard/packages/branding/src/index.ts +1 -1
  264. package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
  265. package/templates/.agents/dashboard/packages/contracts/src/index.ts +1 -0
  266. package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
  267. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +1756 -0
  268. package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +1608 -0
  269. package/templates/.agents/dashboard/packages/local-runtime/package.json +8 -3
  270. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-dashboard.mjs +12 -0
  271. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-runtime.mjs +83 -0
  272. package/templates/.agents/dashboard/packages/local-runtime/scripts/rebuild-sqlite-read-model.mjs +28 -0
  273. package/templates/.agents/dashboard/packages/local-runtime/scripts/test-sqlite-read-model.mjs +262 -0
  274. package/templates/.agents/dashboard/packages/local-runtime/scripts/test-unix-launchers.mjs +41 -0
  275. package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-sqlite-read-model.mjs +105 -0
  276. package/templates/.agents/dashboard/packages/local-runtime/server.mjs +1643 -107
  277. package/templates/.agents/dashboard/packages/local-runtime/src/agent-adapter-sync.ts +30 -0
  278. package/templates/.agents/dashboard/packages/local-runtime/src/agent-catalog-settings.test.ts +3 -2
  279. package/templates/.agents/dashboard/packages/local-runtime/src/agent-catalog-settings.ts +5 -0
  280. package/templates/.agents/dashboard/packages/local-runtime/src/manifest-runs.ts +72 -33
  281. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.test.ts +335 -4
  282. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.ts +392 -1
  283. package/templates/.agents/dashboard/packages/local-runtime/src/runtime.mjs +5 -5
  284. package/templates/.agents/dashboard/packages/local-runtime/src/server-board.test.ts +71 -0
  285. package/templates/.agents/dashboard/packages/local-runtime/src/server-board.ts +179 -0
  286. package/templates/.agents/dashboard/packages/local-runtime/src/server-cross-layer-parity.test.ts +245 -0
  287. package/templates/.agents/dashboard/packages/local-runtime/src/server-daily-read-models-route.ts +64 -0
  288. package/templates/.agents/dashboard/packages/local-runtime/src/server-daily-read-models.test.ts +204 -0
  289. package/templates/.agents/dashboard/packages/local-runtime/src/server-daily-read-models.ts +194 -0
  290. package/templates/.agents/dashboard/packages/local-runtime/src/server-operations-pages.test.ts +163 -0
  291. package/templates/.agents/dashboard/packages/local-runtime/src/server-operations-pages.ts +354 -0
  292. package/templates/.agents/dashboard/packages/local-runtime/src/server-operations-runs-route.test.ts +74 -0
  293. package/templates/.agents/dashboard/packages/local-runtime/src/server-operations-runs-route.ts +113 -0
  294. package/templates/.agents/dashboard/packages/local-runtime/src/server-overview.test.ts +68 -0
  295. package/templates/.agents/dashboard/packages/local-runtime/src/server-period.ts +47 -0
  296. package/templates/.agents/dashboard/packages/local-runtime/src/server-projections.ts +483 -0
  297. package/templates/.agents/dashboard/packages/local-runtime/src/server-settings.test.ts +5 -2
  298. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot.test.ts +163 -84
  299. package/templates/.agents/dashboard/packages/local-runtime/src/server-workspace.ts +145 -0
  300. package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +551 -266
  301. package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +1145 -308
  302. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-metric-contract.test.ts +53 -0
  303. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-metric-contract.ts +708 -0
  304. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +2232 -0
  305. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +6151 -0
  306. package/templates/.agents/dashboard/packages/local-runtime/src/work-priority-contract.test.ts +33 -0
  307. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-history.mjs +41 -0
  308. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-processes.mjs +210 -0
  309. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +437 -190
  310. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +299 -24
  311. package/templates/.agents/dashboard/packages/ui/package.json +1 -1
  312. package/templates/.agents/dashboard/packages/windows-launcher/LauncherVerificationBehaviorTests.cs +206 -0
  313. package/templates/.agents/dashboard/packages/windows-launcher/Program.cs +95 -8
  314. package/templates/.agents/dashboard/packages/windows-launcher/build-dashboard-launcher.ps1 +2 -2
  315. package/templates/.agents/dashboard/packages/windows-launcher/run-launcher-verification-tests.ps1 +22 -0
  316. package/templates/.agents/dashboard/read-model.dbml +2201 -0
  317. package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
  318. package/templates/.agents/dashboard/tests/e2e/playwright.config.ts +1 -1
  319. package/templates/.agents/dashboard/tests/e2e/specs/dashboard.spec.ts +214 -41
  320. package/templates/.agents/dashboard/work-priority.json +34 -0
  321. package/templates/.agents/dashboard/zaip-dashboard-linux.sh +45 -0
  322. package/templates/.agents/dashboard/zaip-dashboard-mac.command +3 -0
  323. package/templates/.agents/dashboard/zaip-dashboard-windows.exe +0 -0
  324. package/templates/.agents/design/.zaip-managed.json +3 -3
  325. package/templates/.agents/design/apps/catalog/package.json +1 -1
  326. package/templates/.agents/design/packages/local-runtime/package.json +1 -1
  327. package/templates/.agents/requirements/autonomous-assurance.md +1 -1
  328. package/templates/.agents/requirements/comparative-audit.md +1 -1
  329. package/templates/.agents/requirements/context-engine.md +1 -1
  330. package/templates/.agents/requirements/cost-observability.md +1 -1
  331. package/templates/.agents/requirements/dashboard-launch.md +24 -0
  332. package/templates/.agents/requirements/data-export.md +1 -1
  333. package/templates/.agents/requirements/design-system.md +1 -1
  334. package/templates/.agents/requirements/execution-engine.md +1 -1
  335. package/templates/.agents/requirements/kanban-dashboard.md +4 -3
  336. package/templates/.agents/requirements/model-orchestration.md +1 -1
  337. package/templates/.agents/requirements/public-distribution.md +9 -6
  338. package/templates/.agents/requirements/software-architecture.md +1 -1
  339. package/templates/.agents/requirements/strategic-improvements.md +1 -1
  340. package/templates/.agents/requirements/work-lifecycle.md +9 -3
  341. package/templates/.agents/requirements/zaip-strategic-95.md +4 -4
  342. package/templates/.agents/rules/autonomy-decision.md +15 -0
  343. package/templates/.agents/rules/core.md +1 -1
  344. package/templates/.agents/rules/run-lifecycle-closure.md +1 -1
  345. package/templates/.agents/rules/specialist-routing.md +19 -0
  346. package/templates/.agents/rules/workflow.md +1 -1
  347. package/templates/.agents/runtime/VERSION +1 -1
  348. package/templates/.agents/runtime/bin/zaip.mjs +114 -64
  349. package/templates/.agents/runtime/checksums.sha256 +6 -4
  350. package/templates/.agents/runtime/manifest.json +3 -1
  351. package/templates/.agents/runtime/pnpm-lock.sha256 +1 -0
  352. package/templates/.agents/runtime/provenance.json +11 -0
  353. package/templates/.agents/runtime/sbom.cdx.json +1929 -39
  354. package/templates/.agents/skills/zaip-aios/SKILL.md +1 -1
  355. package/templates/.agents/skills/zaip-skill-brand-governance/SKILL.md +15 -0
  356. package/templates/.agents/skills/zaip-skill-brand-governance/agents/openai.yaml +4 -0
  357. package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-standards.md +30 -0
  358. package/templates/.agents/skills/zaip-skill-dashboard-sqlite/SKILL.md +25 -0
  359. package/templates/.agents/skills/zaip-skill-dashboard-sqlite/agents/openai.yaml +4 -0
  360. package/templates/.agents/skills/zaip-skill-executar-fila-pronta/SKILL.md +18 -0
  361. package/templates/.agents/skills/zaip-skill-executar-fila-pronta/agents/openai.yaml +6 -0
  362. package/templates/.agents/skills/zaip-skill-executar-fila-pronta/scripts/ready-queue-fence.mjs +71 -0
  363. package/templates/.agents/skills/zaip-skill-executar-fila-pronta/scripts/ready-queue-fence.test.mjs +60 -0
  364. package/templates/.agents/skills/zaip-skill-executar-fila-pronta/scripts/scheduled-ready-queue-contract.test.mjs +111 -0
  365. package/templates/.agents/skills/zaip-skill-execution/SKILL.md +2 -2
  366. package/templates/.agents/skills/zaip-skill-frontend-launcher/references/launcher-contract.md +3 -1
  367. package/templates/.agents/skills/zaip-skill-general-operations/SKILL.md +12 -0
  368. package/templates/.agents/skills/zaip-skill-general-operations/agents/openai.yaml +4 -0
  369. package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +9 -7
  370. package/templates/.agents/skills/zaip-skill-github-deploy/agents/openai.yaml +2 -2
  371. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/github-deploy-contract.test.mjs +11 -38
  372. package/templates/.agents/skills/zaip-skill-governance-compliance/SKILL.md +12 -0
  373. package/templates/.agents/skills/zaip-skill-governance-compliance/agents/openai.yaml +4 -0
  374. package/templates/.agents/skills/zaip-skill-growth-strategy-revops/SKILL.md +15 -0
  375. package/templates/.agents/skills/zaip-skill-growth-strategy-revops/agents/openai.yaml +4 -0
  376. package/templates/.agents/skills/zaip-skill-growth-strategy-revops/references/growth-revops-framework.md +25 -0
  377. package/templates/.agents/skills/zaip-skill-instalar-agendamento/SKILL.md +17 -0
  378. package/templates/.agents/skills/zaip-skill-instalar-agendamento/agents/openai.yaml +6 -0
  379. package/templates/.agents/skills/zaip-skill-marketing/SKILL.md +3 -3
  380. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.mjs +76 -27
  381. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.mjs +128 -24
  382. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.test.mjs +122 -4
  383. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.mjs +66 -19
  384. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.test.mjs +193 -7
  385. package/templates/.agents/skills/zaip-skill-sales-methodology/SKILL.md +14 -0
  386. package/templates/.agents/skills/zaip-skill-sales-methodology/agents/openai.yaml +4 -0
  387. package/templates/.agents/skills/zaip-skill-sales-methodology/references/sales-process-framework.md +77 -0
  388. package/templates/.agents/skills/zaip-skill-setup/SKILL.md +5 -0
  389. package/templates/.agents/skills/zaip-skill-sqlite-read-model/SKILL.md +96 -0
  390. package/templates/.agents/skills/zaip-skill-sqlite-read-model/agents/openai.yaml +4 -0
  391. package/templates/.agents/skills/zaip-skill-sqlite-read-model/scripts/ensure-node.mjs +18 -0
  392. package/templates/.agents/zaip-aios/INDEX.md +1 -0
  393. package/templates/.agents/zaip-aios/README.md +37 -8
  394. package/templates/.agents/zaip-aios/VERSION +1 -1
  395. package/templates/.agents/zaip-aios/guides/09-agentes-e-squads.md +43 -6
  396. package/templates/.agents/zaip-aios/guides/10-seguranca.md +21 -7
  397. package/templates/.agents/zaip-aios/guides/17-como-o-custo-e-calculado.md +32 -0
  398. package/templates/template-manifest.json +945 -214
  399. package/templates/.agents/dashboard/apps/frontend/dist/assets/AgentCatalogSettingsPage-CLYIi7Vo.js +0 -1
  400. package/templates/.agents/dashboard/apps/frontend/dist/assets/AgentCatalogSettingsPage-DTDNVQGX.css +0 -1
  401. package/templates/.agents/dashboard/apps/frontend/dist/assets/PricingSettingsDialog-CzEggcRb.js +0 -1
  402. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-05YKn6Z4.js +0 -3
  403. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-YO3yqtgV.css +0 -1
  404. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-8AzCnl3a.js +0 -77
  405. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-DdBYQ_8D.css +0 -1
  406. package/templates/.agents/dashboard/apps/frontend/src/AgentCatalogSettingsPage.tsx +0 -617
  407. package/templates/.agents/dashboard/apps/frontend/src/agent-catalog-settings-page.css +0 -660
  408. package/templates/.agents/dashboard/apps/frontend/src/agent-catalog-settings.test.ts +0 -249
  409. package/templates/.agents/dashboard/dashboard.config.json +0 -4
  410. package/templates/.agents/dashboard/zaip-dashboard.exe +0 -0
@@ -0,0 +1,775 @@
1
+ import type {
2
+ OperationsProjection,
3
+ RunProjection,
4
+ UsageMetricProjection,
5
+ UsageProjection,
6
+ } from "@zaip-ai/dashboard-operations/contracts";
7
+ import {
8
+ canonicalAllTimeDurationMs,
9
+ isAfterLegacyEffortCutoff,
10
+ LEGACY_EFFORT_DAILY_MS,
11
+ LEGACY_EFFORT_SNAPSHOT,
12
+ saoPauloPeriodKey,
13
+ } from "@zaip-ai/dashboard-operations/contracts";
14
+ import {
15
+ normalizeTokenBackedDailyDuration,
16
+ hybridDailyDuration as sharedHybridDailyDuration,
17
+ rootExecutionDurationByDay as sharedRootExecutionDurationByDay,
18
+ } from "@zaip-ai/dashboard-operations/server";
19
+ import type { CostGroupRow, CostMonitorProjection } from "../contracts.js";
20
+ import { estimatedDurationMs, TOKEN_DURATION_ESTIMATE_BASIS } from "../duration-estimate.js";
21
+ import { buildCostMonitorProjection, usageForRuns } from "./build-cost-monitor-projection.js";
22
+
23
+ /** Fast Cost Monitor first fold backed only by the durable lifecycle summary. */
24
+ export function buildCostSummaryProjection(
25
+ summary: CostSummarySource,
26
+ operations: OperationsProjection,
27
+ currency: "BRL" | "USD",
28
+ fxRate: number | null,
29
+ ): CostMonitorProjection {
30
+ const effectiveSummaryRuns = (summary.run_metrics ?? []).map(effectiveSummaryRun);
31
+ const compactRuns = effectiveSummaryRuns
32
+ .filter((run) => {
33
+ const day = saoPauloPeriodKey(run.finished_at ?? run.started_at, "day");
34
+ return day !== null && inRange(day, operations.filters.from, operations.filters.to);
35
+ })
36
+ .map(summaryRunProjection);
37
+ const available =
38
+ operations.schema_version === 2
39
+ ? buildCostMonitorProjection(
40
+ {
41
+ ...operations,
42
+ tasks: operations.tasks ?? [],
43
+ runs: compactRuns,
44
+ } as OperationsProjection,
45
+ undefined,
46
+ )
47
+ : null;
48
+ // A Model/Provider table shows only concrete source dimensions. Summary
49
+ // cards retain all financial facts; unknown attribution is never reassigned.
50
+ const concreteDimensionRows = (rows: readonly CostGroupRow[]) =>
51
+ rows.filter((row) => {
52
+ const key = row.key.trim().toLowerCase();
53
+ return key.length > 0 && !["mixed", "unknown", "unavailable"].includes(key);
54
+ });
55
+ const hasRunMetrics = summary.run_metrics !== undefined;
56
+ const hasCanonicalSqliteFacts =
57
+ summary.cost_monitor_daily_duration !== undefined || summary.canonical_daily_duration_ms !== undefined;
58
+ // The SQLite path is fully sourced from canonical Run facts. Legacy daily
59
+ // buckets remain available only to the old manifest path.
60
+ const dailyPeriods = new Map<string, PeriodSummary>(
61
+ Object.entries(finishDayCostPeriods(summary)),
62
+ );
63
+ // A factual source interval can cross a Sao Paulo midnight. Preserve the
64
+ // elapsed-session day even where no separate financial source event exists.
65
+ for (const key of Object.keys(summary.cost_monitor_daily_duration ?? {}))
66
+ if (!dailyPeriods.has(key)) dailyPeriods.set(key, emptyPeriodSummary());
67
+ if (!hasRunMetrics && !hasCanonicalSqliteFacts) {
68
+ for (const day of Object.keys(LEGACY_EFFORT_DAILY_MS))
69
+ if (!dailyPeriods.has(day)) dailyPeriods.set(day, emptyPeriodSummary());
70
+ }
71
+ // Prefer the compact Run projection whenever it is available: it already
72
+ // assigns the shared effective duration to every tokenized Run. Falling
73
+ // back to root-only summary timing would turn a tokenized day into 0 s.
74
+ const periodEntries = [...dailyPeriods].filter(([key]) =>
75
+ inRange(key, operations.filters.from, operations.filters.to),
76
+ );
77
+ const factualDurationByDay = durationByRootExecutionDay(effectiveSummaryRuns);
78
+ const factualCostDurationByDay = summary.cost_monitor_daily_duration;
79
+ const durationForDay = (key: string, period: PeriodSummary): DurationSource => {
80
+ if (factualCostDurationByDay !== undefined) {
81
+ const value = factualCostDurationByDay[key];
82
+ return value === undefined
83
+ ? emptyDuration()
84
+ : {
85
+ value: {
86
+ known_sum: value.known_sum,
87
+ unknown: value.eligible_runs - value.known_runs,
88
+ complete: value.eligible_runs === value.known_runs,
89
+ coverage_ratio:
90
+ value.eligible_runs === 0 ? 1 : value.known_runs / value.eligible_runs,
91
+ },
92
+ population: runPopulation(value.eligible_runs, value.known_runs),
93
+ };
94
+ }
95
+ if (summary.canonical_daily_duration_ms !== undefined) {
96
+ const value = summary.canonical_daily_duration_ms[key];
97
+ return value === undefined
98
+ ? emptyDuration()
99
+ : {
100
+ value: { known_sum: value, unknown: 0, complete: true, coverage_ratio: 1 },
101
+ population: runPopulation(period.runs, period.runs),
102
+ };
103
+ }
104
+ if (hasRunMetrics) return factualDurationByDay.get(key) ?? emptyDuration();
105
+ return dailyDurationSource(key, period);
106
+ };
107
+ const durationBudget = periodEntries.reduce(
108
+ (total, [key, period]) => total + durationForDay(key, period).value.known_sum,
109
+ 0,
110
+ );
111
+ const normalizedDurationBudget =
112
+ !hasRunMetrics && !hasCanonicalSqliteFacts && operations.filters.from === null && operations.filters.to === null
113
+ ? canonicalAllTimeDurationMs(durationBudget)
114
+ : durationBudget;
115
+ const factualDailyRows = new Map(
116
+ (summary.daily_rows ?? []).map((row) => [row.key, row] as const),
117
+ );
118
+ const projectedDaily = periodEntries.map(([key, period]) =>
119
+ periodRow(key, period, fxRate, durationForDay(key, period), factualDailyRows.get(key)),
120
+ );
121
+ // Canonical SQLite duration is already deduplicated and assigned to the
122
+ // correct São Paulo calendar day. Rebalancing it by token population would
123
+ // preserve only the all-time total while corrupting each daily row.
124
+ const daily = hasCanonicalSqliteFacts
125
+ ? projectedDaily
126
+ : normalizeTokenBackedGroupBudget(
127
+ projectedDaily.map(ensureTokenBackedGroupDuration),
128
+ normalizedDurationBudget,
129
+ );
130
+ const runCount = daily.reduce((total, row) => total + row.run_count, 0);
131
+ const eventCount = daily.reduce((total, row) => total + row.event_count, 0);
132
+ // A completely unavailable population must not become a factual zero merely
133
+ // because the daily structural accumulator starts at zero.
134
+ const tokenTotal = !hasCanonicalSqliteFacts && compactRuns.every((run) => run.usage.total.tokens.total === null)
135
+ ? null
136
+ : sumNullable(daily.map((row) => row.total_tokens));
137
+ const brlTotal = !hasCanonicalSqliteFacts && compactRuns.every((run) => run.usage.total.cost.brl === null)
138
+ ? null
139
+ : sumNullable(daily.map((row) => row.estimated_brl));
140
+ const usdTotal = sumNullable(daily.map((row) => row.estimated_usd));
141
+ const observedDurationAverage = averageObservedPostCutoffRootDuration(summary.run_metrics ?? []);
142
+ const taskCount =
143
+ operations.summary.overview_metrics?.task_count ?? operations.summary.task_count;
144
+ // Period summaries expose the number of unavailable Runs. Compute coverage
145
+ // against exactly the Run population used by the cards, rather than event
146
+ // coverage (which is absent from the fast summary path).
147
+ const coverage = {
148
+ events: runCount,
149
+ tokens: daily.reduce((total, row) => total + row.coverage.tokens, 0),
150
+ usd: daily.reduce((total, row) => total + row.coverage.usd, 0),
151
+ brl: daily.reduce((total, row) => total + row.coverage.brl, 0),
152
+ };
153
+ return {
154
+ schema_version: 2,
155
+ layout_version: operations.layout_version,
156
+ readonly: true,
157
+ source: ".agents/records",
158
+ aggregate_only: true,
159
+ data_source: hasRunMetrics || hasCanonicalSqliteFacts ? "run_records" : "lifecycle_manifest_summary",
160
+ legacy_effort_baseline:
161
+ !hasRunMetrics && !hasCanonicalSqliteFacts && operations.filters.from === null && operations.filters.to === null
162
+ ? { cutoff: LEGACY_EFFORT_SNAPSHOT.cutoff, duration_ms: LEGACY_EFFORT_SNAPSHOT.durationMs }
163
+ : null,
164
+ currency,
165
+ pricing: { catalog_updated_at: null, fx_rate: fxRate, conversion_applied: fxRate !== null },
166
+ filters: operations.filters,
167
+ overview: {
168
+ task_count: taskCount,
169
+ run_count: runCount,
170
+ event_count: eventCount,
171
+ total_tokens: tokenTotal,
172
+ estimated_usd: usdTotal,
173
+ estimated_brl: brlTotal,
174
+ recorded_usd: null,
175
+ recorded_brl: null,
176
+ average_run_cost_usd: runCount === 0 || usdTotal === null ? null : usdTotal / runCount,
177
+ average_run_cost_brl: runCount === 0 || brlTotal === null ? null : brlTotal / runCount,
178
+ // Legacy effort has no individual Run cardinality, so it is not a
179
+ // legitimate contributor to an average per Run.
180
+ average_run_duration_ms: observedDurationAverage,
181
+ known_tokens_per_cycle: runCount === 0 || tokenTotal === null ? null : tokenTotal / runCount,
182
+ top_10_token_share: null,
183
+ coverage,
184
+ },
185
+ filters_available: {
186
+ providers: available?.filters_available.providers ?? [],
187
+ agents: available?.filters_available.agents ?? [],
188
+ models: available?.filters_available.models ?? [],
189
+ statuses: available?.filters_available.statuses ?? [],
190
+ priorities: available?.filters_available.priorities ?? [],
191
+ risks: available?.filters_available.risks ?? [],
192
+ phases: available?.filters_available.phases ?? [],
193
+ origins: available?.filters_available.origins ?? [],
194
+ work_types: available?.filters_available.work_types ?? [],
195
+ },
196
+ configured_agents: available?.configured_agents ?? [],
197
+ // Compact Run facts preserve total tokens and cost even though component
198
+ // telemetry is intentionally absent. Reuse their phase-aware aggregate
199
+ // instead of the quick Operations placeholder, which has no Run rows.
200
+ usage: summary.aggregate_usage ?? available?.usage ?? usageForRuns(compactRuns),
201
+ origins: emptyOrigins(),
202
+ prds: available?.prds ?? operations.prds,
203
+ specs: available?.specs ?? operations.specs,
204
+ // Keep summary first-paint bounded. Dimensional aggregates above were
205
+ // computed from compact facts, but Run transport stays page-only.
206
+ runs: [],
207
+ groups: {
208
+ // These two dimensions can contain one row per conversation or Task.
209
+ // They are rendered through the compact, paginated SQLite views after
210
+ // their tabs open, so carrying them in the first-fold summary only
211
+ // delays the Cost Monitor without contributing to its initial view.
212
+ conversations: [],
213
+ tasks: [],
214
+ providers: concreteDimensionRows(available?.groups.providers ?? []),
215
+ agents: available?.groups.agents ?? [],
216
+ // Model residuals preserve financial reconciliation in SQLite as
217
+ // unavailable, but are not a factual model category for the chart.
218
+ models: concreteDimensionRows(summary.model_groups ?? available?.groups.models ?? []),
219
+ daily,
220
+ monthly: mergePeriodRows(daily, 7),
221
+ annual: mergePeriodRows(daily, 4),
222
+ },
223
+ };
224
+ }
225
+
226
+ function dailyDurationSource(key: string, period: PeriodSummary): DurationSource {
227
+ return sharedHybridDailyDuration(key, period) as DurationSource;
228
+ }
229
+
230
+ function emptyPeriodSummary(): PeriodSummary {
231
+ const empty: KnownValue = { known_sum: 0, unknown: 0, complete: true, coverage_ratio: 1 };
232
+ return {
233
+ prds: 0,
234
+ specs: 0,
235
+ tasks: 0,
236
+ validations: 0,
237
+ evidences: 0,
238
+ runs: 0,
239
+ usage: { total_tokens: empty, cost: { ...empty, currency: "BRL" } },
240
+ };
241
+ }
242
+
243
+ export interface CostSummarySource {
244
+ periods: { daily: Record<string, PeriodSummary> };
245
+ /**
246
+ * SQLite's selected financial facts, retained for compact summaries where
247
+ * no Run transport is present. Values are factual and currency-specific.
248
+ */
249
+ daily_rows?: Array<{
250
+ key: string;
251
+ total_cost_usd: number | null;
252
+ total_cost_brl: number | null;
253
+ }>;
254
+ /** Distinct Tasks represented by the filtered aggregate population. */
255
+ task_count?: number;
256
+ aggregate_usage?: UsageProjection;
257
+ /** Segment-backed model aggregates for the SQLite first fold. */
258
+ model_groups?: CostGroupRow[];
259
+ /** @deprecated Root-execution duration; retained for non-SQLite callers. */
260
+ canonical_daily_duration_ms?: Record<string, number>;
261
+ /** Factual source duration paired with the financial invocation population. */
262
+ cost_monitor_daily_duration?: Record<
263
+ string,
264
+ { known_sum: number; eligible_runs: number; known_runs: number }
265
+ >;
266
+ run_metrics?: Array<{
267
+ id: string;
268
+ started_at: string;
269
+ finished_at: string | null;
270
+ task_id: string | null;
271
+ execution_id?: string | null;
272
+ conversation_id?: string | null;
273
+ agent?: string | null;
274
+ agent_name?: string | null;
275
+ provider?: string | null;
276
+ model?: string | null;
277
+ spec_id?: string | null;
278
+ prd_id?: string | null;
279
+ change_id?: string | null;
280
+ run_kind?: "run" | "subrun" | null;
281
+ phase: string | null;
282
+ parent_run_id: string | null;
283
+ status: string | null;
284
+ duration_ms: number | null;
285
+ /** Raw factual invocation duration, never a token estimate. */
286
+ source_duration_ms?: number | null;
287
+ duration_provenance?: "observed" | "estimated" | "unavailable";
288
+ estimation_basis?: string | null;
289
+ duration_started_at?: string | null;
290
+ total_tokens: number | null;
291
+ input_tokens?: number | null;
292
+ cached_input_tokens?: number | null;
293
+ output_tokens?: number | null;
294
+ reasoning_tokens?: number | null;
295
+ cost: number | null;
296
+ currency: string | null;
297
+ events: number | null;
298
+ }>;
299
+ }
300
+
301
+ /** Adapter from the durable compact Run fact to the Cost projection contract. */
302
+ function summaryRunProjection(
303
+ run: NonNullable<CostSummarySource["run_metrics"]>[number],
304
+ ): RunProjection {
305
+ const empty = {
306
+ events: 0,
307
+ duration_ms: null,
308
+ tokens: { input: null, cached_input: null, output: null, reasoning: null, total: null },
309
+ cost: { usd: null, brl: null },
310
+ coverage: { events: 0, tokens: 0, usd: 0, brl: 0 },
311
+ };
312
+ const usage = {
313
+ ...empty,
314
+ events: run.events ?? 0,
315
+ duration_ms: run.source_duration_ms ?? null,
316
+ tokens: {
317
+ ...empty.tokens,
318
+ input: run.input_tokens ?? null,
319
+ cached_input: run.cached_input_tokens ?? null,
320
+ output: run.output_tokens ?? null,
321
+ reasoning: run.reasoning_tokens ?? null,
322
+ total: run.total_tokens,
323
+ },
324
+ cost: { usd: null, brl: run.currency === "BRL" ? run.cost : null },
325
+ coverage: {
326
+ events: run.events ?? 0,
327
+ tokens: run.total_tokens === null ? 0 : 1,
328
+ usd: 0,
329
+ brl: run.cost === null ? 0 : 1,
330
+ },
331
+ };
332
+ const phase = run.phase === "conversation" || run.phase === "planning" ? run.phase : "execution";
333
+ return {
334
+ id: run.id,
335
+ artifact_path: `.agents/records/runs/${run.id}`,
336
+ status:
337
+ run.status === "failed" || run.status === "cancelled" || run.status === "running"
338
+ ? run.status
339
+ : "completed",
340
+ phase,
341
+ entrypoint: run.task_id === null ? "conversation" : "task",
342
+ work_type: "new",
343
+ run_role: run.run_kind === "subrun" ? "subagent" : "orchestrator",
344
+ run_kind: run.run_kind ?? "run",
345
+ run_purpose: "execution",
346
+ requires_finalizer: false,
347
+ parent_run_id: run.parent_run_id,
348
+ client: "unknown",
349
+ agent: run.agent ?? "unknown",
350
+ agent_name: run.agent_name ?? run.agent ?? "unknown",
351
+ provider: run.provider ?? "unavailable",
352
+ model: run.model ?? "unknown",
353
+ reasoning_effort: null,
354
+ effective_model: run.model ?? null,
355
+ effective_reasoning_effort: null,
356
+ effective_config_mixed: false,
357
+ call_count: null,
358
+ terminal_call_count: null,
359
+ failed_call_count: 0,
360
+ cancelled_call_count: 0,
361
+ conversation_id: run.conversation_id ?? run.id,
362
+ execution_id: run.execution_id ?? null,
363
+ task_id: run.task_id,
364
+ spec_id: run.spec_id ?? null,
365
+ prd_id: run.prd_id ?? null,
366
+ change_id: run.change_id ?? null,
367
+ started_at: run.started_at,
368
+ finished_at: run.finished_at,
369
+ duration_ms: run.duration_ms,
370
+ source_duration_ms: run.source_duration_ms ?? null,
371
+ ...(run.duration_provenance === undefined
372
+ ? {}
373
+ : { duration_provenance: run.duration_provenance }),
374
+ ...(run.estimation_basis === undefined ? {} : { estimation_basis: run.estimation_basis }),
375
+ usage: {
376
+ conversation: phase === "conversation" ? usage : empty,
377
+ planning: phase === "planning" ? usage : empty,
378
+ execution: phase === "execution" ? usage : empty,
379
+ total: usage,
380
+ new_work: usage,
381
+ rework: empty,
382
+ },
383
+ };
384
+ }
385
+
386
+ function effectiveSummaryRun(
387
+ run: NonNullable<CostSummarySource["run_metrics"]>[number],
388
+ ): NonNullable<CostSummarySource["run_metrics"]>[number] {
389
+ if (run.duration_ms !== null)
390
+ return {
391
+ ...run,
392
+ duration_provenance: run.duration_provenance ?? "unavailable",
393
+ estimation_basis: run.duration_provenance === "estimated" ? run.estimation_basis ?? null : null,
394
+ };
395
+ const duration_ms = estimatedDurationMs(run.total_tokens);
396
+ return duration_ms === null
397
+ ? { ...run, duration_provenance: "unavailable", estimation_basis: null }
398
+ : {
399
+ ...run,
400
+ duration_ms,
401
+ duration_provenance: "estimated",
402
+ estimation_basis: TOKEN_DURATION_ESTIMATE_BASIS,
403
+ };
404
+ }
405
+
406
+ function ensureTokenBackedGroupDuration(row: CostGroupRow): CostGroupRow {
407
+ if ((row.total_tokens ?? 0) <= 0 || (row.duration_ms ?? 0) > 0) return row;
408
+ const duration_ms = estimatedDurationMs(row.total_tokens);
409
+ if (duration_ms === null || duration_ms <= 0) return row;
410
+ const coverageCounts = row.coverage_counts;
411
+ return {
412
+ ...row,
413
+ duration_ms,
414
+ duration: { known_sum: duration_ms, unknown: 0, complete: true, coverage_ratio: 1 },
415
+ ...(coverageCounts === undefined
416
+ ? {}
417
+ : {
418
+ coverage_counts: {
419
+ ...coverageCounts,
420
+ ...(coverageCounts.metrics === undefined
421
+ ? {}
422
+ : {
423
+ metrics: {
424
+ ...coverageCounts.metrics,
425
+ duration: {
426
+ eligible_runs: row.run_count,
427
+ known_runs: row.run_count,
428
+ unknown_runs: 0,
429
+ },
430
+ },
431
+ }),
432
+ },
433
+ }),
434
+ };
435
+ }
436
+
437
+ function normalizeTokenBackedGroupBudget(
438
+ rows: readonly CostGroupRow[],
439
+ budget: number,
440
+ ): CostGroupRow[] {
441
+ return normalizeTokenBackedDailyDuration(rows, budget).map((row) => ({
442
+ ...row,
443
+ duration_ms:
444
+ row.duration.complete ? row.duration.known_sum : null,
445
+ }));
446
+ }
447
+
448
+ interface KnownValue {
449
+ known_sum: number;
450
+ unknown: number;
451
+ complete: boolean;
452
+ coverage_ratio: number;
453
+ }
454
+
455
+ interface PeriodSummary {
456
+ prds: number;
457
+ specs: number;
458
+ tasks: number;
459
+ validations: number;
460
+ evidences: number;
461
+ runs: number;
462
+ usage: {
463
+ total_tokens: KnownValue;
464
+ cost: KnownValue & { currency: string | null };
465
+ };
466
+ duration?: KnownValue;
467
+ events?: KnownValue;
468
+ }
469
+
470
+ /** Reconcile the fast summary with the completed-Run calendar used by detail. */
471
+ function finishDayCostPeriods(summary: CostSummarySource): Record<string, PeriodSummary> {
472
+ const runs = [
473
+ ...new Map((summary.run_metrics ?? []).map((run) => [run.id, run] as const)).values(),
474
+ ];
475
+ if (summary.run_metrics === undefined) return summary.periods.daily;
476
+
477
+ const byDay = new Map<string, typeof runs>();
478
+ for (const run of runs) {
479
+ // The compact SQLite source has already chosen source session time for
480
+ // started_at. Do not move token/cost to a later capture/finish day.
481
+ const day = saoPauloPeriodKey(run.started_at, "day");
482
+ if (day !== null) byDay.set(day, [...(byDay.get(day) ?? []), run]);
483
+ }
484
+ const days = new Set([...Object.keys(summary.periods.daily), ...byDay.keys()]);
485
+ return Object.fromEntries(
486
+ [...days].map((day) => {
487
+ const period = summary.periods.daily[day] ?? emptyPeriodSummary();
488
+ const dayRuns = byDay.get(day) ?? [];
489
+ const tokens = knownPeriodValue(dayRuns.map((run) => run.total_tokens));
490
+ const cost = knownPeriodValue(dayRuns.map((run) => run.cost));
491
+ const events = knownPeriodValue(dayRuns.map((run) => run.events));
492
+ return [
493
+ day,
494
+ {
495
+ ...period,
496
+ runs: dayRuns.length,
497
+ usage: {
498
+ total_tokens: tokens,
499
+ cost: {
500
+ ...cost,
501
+ currency:
502
+ dayRuns.find((run) => run.currency !== null)?.currency ??
503
+ period.usage.cost.currency,
504
+ },
505
+ },
506
+ events,
507
+ },
508
+ ];
509
+ }),
510
+ );
511
+ }
512
+
513
+ function knownPeriodValue(values: readonly (number | null)[]): KnownValue {
514
+ const known = values.filter((value): value is number => value !== null);
515
+ const unknown = values.length - known.length;
516
+ return {
517
+ known_sum: known.reduce((total, value) => total + value, 0),
518
+ unknown,
519
+ complete: unknown === 0,
520
+ coverage_ratio: values.length === 0 ? 1 : known.length / values.length,
521
+ };
522
+ }
523
+
524
+ function periodRow(
525
+ key: string,
526
+ period: PeriodSummary,
527
+ fxRate: number | null,
528
+ duration: DurationSource,
529
+ factualCosts?: { total_cost_usd: number | null; total_cost_brl: number | null },
530
+ ): CostGroupRow {
531
+ const periodBrl =
532
+ period.usage.cost.known_sum === 0 && period.usage.cost.unknown > 0
533
+ ? null
534
+ : period.usage.cost.known_sum;
535
+ // Do not derive or relabel a currency when SQLite supplied its factual
536
+ // value. The legacy manifest path retains its period/FX fallback.
537
+ const brl = factualCosts === undefined ? periodBrl : factualCosts.total_cost_brl;
538
+ const usd =
539
+ factualCosts === undefined
540
+ ? brl !== null && fxRate !== null && fxRate > 0
541
+ ? brl / fxRate
542
+ : null
543
+ : factualCosts.total_cost_usd;
544
+ const eventCount = period.events?.known_sum ?? 0;
545
+ const knownTokens = knownRuns(period.runs, period.usage.total_tokens.unknown);
546
+ const knownCost = knownRuns(period.runs, period.usage.cost.unknown);
547
+ return {
548
+ key,
549
+ label: key,
550
+ latest_started_at: `${key}T23:59:59.999-03:00`,
551
+ run_count: period.runs,
552
+ task_count: period.tasks,
553
+ tasksCreated: period.tasks,
554
+ tasksActive: period.tasks,
555
+ taskDaysActive: period.tasks,
556
+ prd_count: period.prds,
557
+ spec_count: period.specs,
558
+ evidence_count: period.evidences,
559
+ test_count: period.validations,
560
+ event_count: eventCount,
561
+ total_tokens:
562
+ period.usage.total_tokens.known_sum === 0 && period.usage.total_tokens.unknown > 0
563
+ ? null
564
+ : period.usage.total_tokens.known_sum,
565
+ estimated_usd: usd,
566
+ estimated_brl: brl,
567
+ // Keep the additive factual total visible even if the separate coverage
568
+ // counters report an incomplete financial population. Hiding it as
569
+ // unavailable breaks parity with Operations and discards calculable time.
570
+ // This is never model-inference latency or a token estimate.
571
+ duration_ms:
572
+ duration.population.known_runs > 0 ? duration.value.known_sum : null,
573
+ duration: duration.value,
574
+ coverage: {
575
+ events: period.runs,
576
+ tokens: knownTokens,
577
+ usd: knownCost,
578
+ brl: knownCost,
579
+ },
580
+ coverage_counts: {
581
+ source: "period_summary",
582
+ granularity: period.events === undefined ? "unavailable" : "event",
583
+ events: period.events?.known_sum ?? null,
584
+ tokens: null,
585
+ usd: null,
586
+ brl: null,
587
+ metrics: {
588
+ duration: duration.population,
589
+ tokens: runPopulation(period.runs, knownTokens),
590
+ usd: runPopulation(period.runs, knownCost),
591
+ brl: runPopulation(period.runs, knownCost),
592
+ },
593
+ },
594
+ };
595
+ }
596
+
597
+ function mergePeriodRows(rows: readonly CostGroupRow[], prefixLength: number): CostGroupRow[] {
598
+ const groups = new Map<string, CostGroupRow[]>();
599
+ for (const row of rows) {
600
+ const key = row.key.slice(0, prefixLength);
601
+ groups.set(key, [...(groups.get(key) ?? []), row]);
602
+ }
603
+ return [...groups]
604
+ .map(([key, values]) => {
605
+ const first = values[0]!;
606
+ const known = values.reduce((total, row) => total + row.duration.known_sum, 0);
607
+ const unknown = values.reduce((total, row) => total + row.duration.unknown, 0);
608
+ const durationPopulation = values.reduce(
609
+ (total, row) => total + (row.coverage_counts?.metrics?.duration?.eligible_runs ?? 0),
610
+ 0,
611
+ );
612
+ const durationKnownRuns = values.reduce(
613
+ (total, row) => total + (row.coverage_counts?.metrics?.duration?.known_runs ?? 0),
614
+ 0,
615
+ );
616
+ const runCount = values.reduce((total, row) => total + row.run_count, 0);
617
+ return {
618
+ ...first,
619
+ key,
620
+ label: key,
621
+ latest_started_at:
622
+ values
623
+ .map((row) => row.latest_started_at)
624
+ .sort()
625
+ .at(-1) ?? first.latest_started_at,
626
+ run_count: runCount,
627
+ task_count: values.reduce((total, row) => total + (row.task_count ?? 0), 0),
628
+ tasksCreated: values.reduce((total, row) => total + (row.tasksCreated ?? 0), 0),
629
+ tasksActive: values.reduce((total, row) => total + (row.tasksActive ?? 0), 0),
630
+ taskDaysActive: values.reduce((total, row) => total + (row.taskDaysActive ?? 0), 0),
631
+ prd_count: values.reduce((total, row) => total + row.prd_count, 0),
632
+ spec_count: values.reduce((total, row) => total + row.spec_count, 0),
633
+ evidence_count: values.reduce((total, row) => total + row.evidence_count, 0),
634
+ test_count: values.reduce((total, row) => total + row.test_count, 0),
635
+ event_count: values.reduce((total, row) => total + row.event_count, 0),
636
+ total_tokens: mergeNullableMetric(values.map((row) => row.total_tokens)),
637
+ estimated_usd: mergeNullableMetric(values.map((row) => row.estimated_usd)),
638
+ estimated_brl: mergeNullableMetric(values.map((row) => row.estimated_brl)),
639
+ // A period duration is factual only if every financial day in its
640
+ // population has an observed source interval. Never promote a
641
+ // partial daily union into a monthly/yearly numeric total.
642
+ duration_ms: unknown === 0 ? known : null,
643
+ duration: {
644
+ known_sum: known,
645
+ unknown,
646
+ complete: unknown === 0,
647
+ coverage_ratio: durationPopulation === 0 ? 1 : durationKnownRuns / durationPopulation,
648
+ },
649
+ coverage: {
650
+ events: values.reduce((total, row) => total + row.coverage.events, 0),
651
+ tokens: values.reduce((total, row) => total + row.coverage.tokens, 0),
652
+ usd: values.reduce((total, row) => total + row.coverage.usd, 0),
653
+ brl: values.reduce((total, row) => total + row.coverage.brl, 0),
654
+ },
655
+ ...(first.coverage_counts === undefined
656
+ ? {}
657
+ : {
658
+ coverage_counts: {
659
+ ...first.coverage_counts,
660
+ metrics: {
661
+ duration: runPopulation(durationPopulation, durationKnownRuns),
662
+ tokens: mergeMetricPopulation(values, "tokens"),
663
+ usd: mergeMetricPopulation(values, "usd"),
664
+ brl: mergeMetricPopulation(values, "brl"),
665
+ },
666
+ },
667
+ }),
668
+ };
669
+ })
670
+ .sort((left, right) => right.key.localeCompare(left.key));
671
+ }
672
+
673
+ function mergeMetricPopulation(
674
+ rows: readonly CostGroupRow[],
675
+ metric: "tokens" | "usd" | "brl",
676
+ ): ReturnType<typeof runPopulation> {
677
+ const populations = rows.map((row) => row.coverage_counts?.metrics?.[metric]);
678
+ return runPopulation(
679
+ populations.reduce((total, population) => total + (population?.eligible_runs ?? 0), 0),
680
+ populations.reduce((total, population) => total + (population?.known_runs ?? 0), 0),
681
+ );
682
+ }
683
+
684
+ /**
685
+ * Cost cards intentionally retain all-invocation count/tokens/cost, but their
686
+ * duration is the same non-overlapping root-execution population as
687
+ * Operations. Missing run metrics stays unavailable rather than borrowing
688
+ * the legacy aggregate (which mixes conversations and Sub-Runs).
689
+ */
690
+ interface DurationSource {
691
+ value: KnownValue;
692
+ population: ReturnType<typeof runPopulation>;
693
+ }
694
+
695
+ function durationByRootExecutionDay(
696
+ runs: readonly NonNullable<CostSummarySource["run_metrics"]>[number][],
697
+ ): Map<string, DurationSource> {
698
+ return sharedRootExecutionDurationByDay(runs) as Map<string, DurationSource>;
699
+ }
700
+
701
+ function averageObservedPostCutoffRootDuration(
702
+ runs: readonly NonNullable<CostSummarySource["run_metrics"]>[number][],
703
+ ): number | null {
704
+ const known = runs.filter(
705
+ (run): run is typeof run & { duration_ms: number } =>
706
+ run.phase === "execution" &&
707
+ run.parent_run_id == null &&
708
+ isAfterLegacyEffortCutoff(run.duration_started_at ?? run.started_at) &&
709
+ run.duration_ms !== null &&
710
+ run.duration_ms >= 0,
711
+ );
712
+ return known.length === 0
713
+ ? null
714
+ : known.reduce((total, run) => total + run.duration_ms, 0) / known.length;
715
+ }
716
+
717
+ function emptyDuration(): DurationSource {
718
+ return {
719
+ value: { known_sum: 0, unknown: 0, complete: true, coverage_ratio: 1 },
720
+ population: runPopulation(0, 0),
721
+ };
722
+ }
723
+
724
+ function inRange(key: string, from: string | null, to: string | null): boolean {
725
+ const dayForBound = (value: string | null) => {
726
+ if (value === null) return null;
727
+ // Direct projection callers can still provide a date-only value. It is a
728
+ // São Paulo calendar label, whereas timestamp bounds need conversion.
729
+ if (/^\d{4}-\d{2}-\d{2}$/.test(value)) return value;
730
+ return saoPauloPeriodKey(value, "day");
731
+ };
732
+ const fromDay = dayForBound(from);
733
+ const toDay = dayForBound(to);
734
+ return (fromDay === null || key >= fromDay) && (toDay === null || key <= toDay);
735
+ }
736
+
737
+ function sumNullable(values: readonly (number | null)[]): number | null {
738
+ const known = values.filter((value): value is number => value !== null);
739
+ return known.length === 0 ? null : known.reduce((total, value) => total + value, 0);
740
+ }
741
+
742
+ function mergeNullableMetric(values: readonly (number | null)[]): number | null {
743
+ return values.some((value) => value === null)
744
+ ? null
745
+ : values.reduce<number>((total, value) => total + (value ?? 0), 0);
746
+ }
747
+
748
+ function knownRuns(eligibleRuns: number, unknownRuns: number): number {
749
+ return Math.max(0, eligibleRuns - unknownRuns);
750
+ }
751
+
752
+ function runPopulation(eligible_runs: number, known_runs: number) {
753
+ return { eligible_runs, known_runs, unknown_runs: eligible_runs - known_runs };
754
+ }
755
+
756
+ function emptyMetric(): UsageMetricProjection {
757
+ return {
758
+ events: 0,
759
+ tokens: { input: null, cached_input: null, output: null, reasoning: null, total: null },
760
+ cost: { usd: null, brl: null },
761
+ coverage: { events: 0, tokens: 0, usd: 0, brl: 0 },
762
+ };
763
+ }
764
+
765
+ function emptyOrigins(): CostMonitorProjection["origins"] {
766
+ const usage = (): UsageProjection => ({
767
+ conversation: emptyMetric(),
768
+ planning: emptyMetric(),
769
+ execution: emptyMetric(),
770
+ total: emptyMetric(),
771
+ new_work: emptyMetric(),
772
+ rework: emptyMetric(),
773
+ });
774
+ return { conversation: usage(), task: usage(), spec: usage(), prd: usage() };
775
+ }