@zaip-ai/cli 1.0.7 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (444) 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 +39 -4
  10. package/dist/services/agent-adapters.js.map +1 -1
  11. package/dist/services/agent-adapters.test.js +13 -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 +7 -0
  45. package/dist/services/template-manifest.js.map +1 -1
  46. package/package.json +1 -1
  47. package/templates/.agents/architecture/software-architecture.md +131 -0
  48. package/templates/.agents/branding/brandbook.docx +0 -0
  49. package/templates/.agents/branding/brandbook.md +60 -0
  50. package/templates/.agents/config/agents/catalog.yaml +310 -10
  51. package/templates/.agents/config/clients/codex/agents/zaip-agent-brand-strategist.toml +30 -0
  52. package/templates/.agents/config/clients/codex/agents/zaip-agent-designer.toml +5 -5
  53. package/templates/.agents/config/clients/codex/agents/zaip-agent-finalizer.toml +2 -2
  54. package/templates/.agents/config/clients/codex/agents/zaip-agent-general-operations.toml +30 -0
  55. package/templates/.agents/config/clients/codex/agents/zaip-agent-governance-compliance.toml +30 -0
  56. package/templates/.agents/config/clients/codex/agents/zaip-agent-growth-strategist.toml +30 -0
  57. package/templates/.agents/config/clients/codex/agents/zaip-agent-marketing-analyst.toml +8 -8
  58. package/templates/.agents/config/clients/codex/agents/zaip-agent-orchestrator.toml +5 -3
  59. package/templates/.agents/config/clients/codex/agents/zaip-agent-sales-specialist.toml +30 -0
  60. package/templates/.agents/config/project.yaml +1 -1
  61. package/templates/.agents/dashboard/.tmp-run-list.json +254 -0
  62. package/templates/.agents/dashboard/.zaip-managed.json +775 -163
  63. package/templates/.agents/dashboard/DATA-DICTIONARY.md +2227 -0
  64. package/templates/.agents/dashboard/README.md +48 -97
  65. package/templates/.agents/dashboard/apps/frontend/dist/assets/CostCalculationGuidePage-DxR_pgSV.js +1 -0
  66. package/templates/.agents/dashboard/apps/frontend/dist/assets/DashboardHelpDialog-4jZLTWE_.js +2156 -0
  67. package/templates/.agents/dashboard/apps/frontend/dist/assets/PricingSettingsDialog-CKcsqb-r.js +1 -0
  68. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-BomxqCBU.css +1 -0
  69. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-DmmJD2Th.js +3 -0
  70. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-BwtitWa_.js +1 -0
  71. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-CaKwQP43.css +1 -0
  72. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-BZ5WdaMN.css +1 -0
  73. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-N5Csr0RP.js +68 -0
  74. package/templates/.agents/dashboard/apps/frontend/dist/assets/{dashboard-localization-C98LGC-Q.js → dashboard-localization-CLJ0lT9v.js} +1 -1
  75. package/templates/.agents/dashboard/apps/frontend/dist/assets/icons-vendor-C0fj2uU9.js +1 -0
  76. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-C4aIB1PV.js +2 -0
  77. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-DK_enB5Z.css +1 -0
  78. package/templates/.agents/dashboard/apps/frontend/dist/assets/react-vendor-BEsJ-FYH.js +9 -0
  79. package/templates/.agents/dashboard/apps/frontend/dist/assets/rolldown-runtime-D9-fqq9M.js +1 -0
  80. package/templates/.agents/dashboard/apps/frontend/dist/assets/traceability-B6y6Gw12.js +1 -0
  81. package/templates/.agents/dashboard/apps/frontend/dist/assets/traceability-DFY7ZDlu.css +1 -0
  82. package/templates/.agents/dashboard/apps/frontend/dist/index.html +9 -2
  83. package/templates/.agents/dashboard/apps/frontend/package.json +1 -1
  84. package/templates/.agents/dashboard/apps/frontend/src/App.tsx +1129 -600
  85. package/templates/.agents/dashboard/apps/frontend/src/AppLoadingBoundary.tsx +48 -0
  86. package/templates/.agents/dashboard/apps/frontend/src/AppLoadingPanels.tsx +2 -0
  87. package/templates/.agents/dashboard/apps/frontend/src/AppOverlays.tsx +247 -0
  88. package/templates/.agents/dashboard/apps/frontend/src/AppRequestGuards.tsx +95 -0
  89. package/templates/.agents/dashboard/apps/frontend/src/AppSetupRoutes.tsx +87 -0
  90. package/templates/.agents/dashboard/apps/frontend/src/CostCalculationGuidePage.tsx +641 -0
  91. package/templates/.agents/dashboard/apps/frontend/src/DashboardAlternateContent.tsx +159 -0
  92. package/templates/.agents/dashboard/apps/frontend/src/DashboardCapabilityNav.tsx +13 -13
  93. package/templates/.agents/dashboard/apps/frontend/src/DashboardGlobalSettings.tsx +56 -0
  94. package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsPage.tsx +266 -315
  95. package/templates/.agents/dashboard/apps/frontend/src/ProjectStackEditor.tsx +151 -0
  96. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.test.ts +37 -0
  97. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.tsx +114 -12
  98. package/templates/.agents/dashboard/apps/frontend/src/app-preferences.ts +15 -0
  99. package/templates/.agents/dashboard/apps/frontend/src/app-session-token.ts +20 -0
  100. package/templates/.agents/dashboard/apps/frontend/src/cost-calculation-guide.css +267 -0
  101. package/templates/.agents/dashboard/apps/frontend/src/cost-calculation-guide.test.ts +69 -0
  102. package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +85 -0
  103. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +133 -0
  104. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +453 -13
  105. package/templates/.agents/dashboard/apps/frontend/src/dashboard-localization.ts +1 -1
  106. package/templates/.agents/dashboard/apps/frontend/src/main.tsx +1 -0
  107. package/templates/.agents/dashboard/apps/frontend/src/operations-detail-hydration.test.ts +55 -0
  108. package/templates/.agents/dashboard/apps/frontend/src/operations-detail-hydration.ts +36 -0
  109. package/templates/.agents/dashboard/apps/frontend/src/operations-entity-page-projection.test.ts +126 -0
  110. package/templates/.agents/dashboard/apps/frontend/src/operations-entity-page-projection.ts +181 -0
  111. package/templates/.agents/dashboard/apps/frontend/src/operations-period-contract.test.ts +138 -0
  112. package/templates/.agents/dashboard/apps/frontend/src/operations-period-render.test.ts +105 -0
  113. package/templates/.agents/dashboard/apps/frontend/src/operations-period.test.ts +6 -3
  114. package/templates/.agents/dashboard/apps/frontend/src/operations-period.ts +9 -5
  115. package/templates/.agents/dashboard/apps/frontend/src/overview-status-page.test.ts +26 -0
  116. package/templates/.agents/dashboard/apps/frontend/src/period-transition-overlay.css +44 -0
  117. package/templates/.agents/dashboard/apps/frontend/src/project-settings-model.ts +121 -62
  118. package/templates/.agents/dashboard/apps/frontend/src/project-settings-page.css +482 -3
  119. package/templates/.agents/dashboard/apps/frontend/src/project-settings.test.ts +84 -17
  120. package/templates/.agents/dashboard/apps/frontend/src/snapshot-banner-semantics.test.ts +78 -0
  121. package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +234 -39
  122. package/templates/.agents/dashboard/apps/frontend/src/snapshot-notice.ts +15 -0
  123. package/templates/.agents/dashboard/apps/frontend/src/sqlite-cost-adapters.ts +26 -0
  124. package/templates/.agents/dashboard/apps/frontend/src/styles.css +14 -2
  125. package/templates/.agents/dashboard/apps/frontend/src/traceability-workspace.css +38 -2
  126. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.test.ts +253 -0
  127. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.ts +380 -0
  128. package/templates/.agents/dashboard/apps/frontend/src/use-app-effects.ts +175 -0
  129. package/templates/.agents/dashboard/apps/frontend/src/use-app-operations-pages.ts +395 -0
  130. package/templates/.agents/dashboard/apps/frontend/src/use-app-trace-documents.ts +141 -0
  131. package/templates/.agents/dashboard/apps/frontend/src/use-idle-cost-prefetch.ts +45 -0
  132. package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.test.ts +46 -0
  133. package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.ts +36 -0
  134. package/templates/.agents/dashboard/apps/frontend/vite.config.ts +58 -5
  135. package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
  136. package/templates/.agents/dashboard/modules/cost-monitor/src/contracts.ts +47 -6
  137. package/templates/.agents/dashboard/modules/cost-monitor/src/duration-estimate.ts +13 -0
  138. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.test.ts +134 -0
  139. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.tsx +290 -0
  140. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostCharts.test.ts +133 -19
  141. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostCharts.tsx +134 -43
  142. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.tsx +137 -19
  143. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostModelsAuditTable.test.ts +2 -0
  144. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostModelsAuditTable.tsx +13 -10
  145. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorContent.tsx +328 -0
  146. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.test.ts +302 -6
  147. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +627 -400
  148. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostSummary.tsx +5 -13
  149. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +370 -72
  150. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.tsx +467 -326
  151. package/templates/.agents/dashboard/modules/cost-monitor/src/react/MacroCostTable.test.ts +17 -0
  152. package/templates/.agents/dashboard/modules/cost-monitor/src/react/MacroCostTable.tsx +25 -6
  153. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-copy.ts +0 -2
  154. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-page-helpers.ts +17 -0
  155. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-responsive.css +6 -3
  156. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-row-filters.ts +123 -0
  157. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-summary.ts +8 -3
  158. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-views.ts +32 -0
  159. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor.css +55 -14
  160. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-table-presentation.ts +121 -0
  161. package/templates/.agents/dashboard/modules/cost-monitor/src/react/index.ts +3 -0
  162. package/templates/.agents/dashboard/modules/cost-monitor/src/react/period-cost-groups.test.ts +68 -0
  163. package/templates/.agents/dashboard/modules/cost-monitor/src/react/period-cost-groups.ts +33 -5
  164. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-compact-cost-page.ts +119 -0
  165. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.test.ts +12 -0
  166. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.ts +146 -0
  167. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-run-page.ts +118 -0
  168. package/templates/.agents/dashboard/modules/cost-monitor/src/server/aggregate.test.ts +2 -2
  169. package/templates/.agents/dashboard/modules/cost-monitor/src/server/aggregate.ts +5 -3
  170. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-pricing-fallback.test.ts +53 -0
  171. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.basics.test.ts +34 -0
  172. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.test.ts +168 -161
  173. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.ts +188 -29
  174. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.test.ts +757 -0
  175. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.ts +784 -0
  176. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-terminal-day.test.ts +100 -0
  177. package/templates/.agents/dashboard/modules/cost-monitor/src/server/index.ts +1 -0
  178. package/templates/.agents/dashboard/modules/cost-monitor/src/server/refactor-map-xr9l.json +61 -0
  179. package/templates/.agents/dashboard/modules/cost-monitor/src/server/source-size-cost-server/build-cost-monitor-projection-agents.test.ts +31 -0
  180. package/templates/.agents/dashboard/modules/cost-monitor/src/server/source-size-cost-server/build-cost-summary-projection-duration.test.ts +414 -0
  181. package/templates/.agents/dashboard/modules/cost-monitor/src/task-cost-groups.test.ts +41 -0
  182. package/templates/.agents/dashboard/modules/cost-monitor/src/task-cost-groups.ts +55 -11
  183. package/templates/.agents/dashboard/modules/operations/package.json +2 -1
  184. package/templates/.agents/dashboard/modules/operations/src/contracts.ts +185 -0
  185. package/templates/.agents/dashboard/modules/operations/src/duration-population.test.ts +63 -1
  186. package/templates/.agents/dashboard/modules/operations/src/duration-population.ts +60 -5
  187. package/templates/.agents/dashboard/modules/operations/src/react/EntityDetailsDialog.tsx +14 -3
  188. package/templates/.agents/dashboard/modules/operations/src/react/EntityTables.test.ts +44 -1
  189. package/templates/.agents/dashboard/modules/operations/src/react/EntityTables.tsx +345 -18
  190. package/templates/.agents/dashboard/modules/operations/src/react/MacroPlanningDialog.tsx +1 -0
  191. package/templates/.agents/dashboard/modules/operations/src/react/OperationDateFilters.test.ts +9 -5
  192. package/templates/.agents/dashboard/modules/operations/src/react/OperationDateFilters.tsx +2 -2
  193. package/templates/.agents/dashboard/modules/operations/src/react/OperationsMainContent.tsx +168 -0
  194. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.helpers.tsx +95 -6
  195. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.test.ts +367 -14
  196. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +562 -131
  197. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +353 -355
  198. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageNavigation.tsx +65 -0
  199. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageOverview.tsx +169 -0
  200. package/templates/.agents/dashboard/modules/operations/src/react/PeriodSummaryTable.tsx +73 -8
  201. package/templates/.agents/dashboard/modules/operations/src/react/PrdDocumentDialog.test.tsx +32 -0
  202. package/templates/.agents/dashboard/modules/operations/src/react/PrdDocumentDialog.tsx +62 -6
  203. package/templates/.agents/dashboard/modules/operations/src/react/TaskBoard.test.ts +55 -0
  204. package/templates/.agents/dashboard/modules/operations/src/react/TaskBoard.tsx +27 -19
  205. package/templates/.agents/dashboard/modules/operations/src/react/TaskDetailsDialog.tsx +105 -42
  206. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkBoard.priority.test.ts +19 -0
  207. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkBoard.tsx +265 -36
  208. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.test.ts +171 -8
  209. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.tsx +98 -68
  210. package/templates/.agents/dashboard/modules/operations/src/react/conversation-rows.test.ts +72 -1
  211. package/templates/.agents/dashboard/modules/operations/src/react/conversation-rows.ts +78 -17
  212. package/templates/.agents/dashboard/modules/operations/src/react/execution-metrics.ts +6 -4
  213. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +431 -1
  214. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +574 -20
  215. package/templates/.agents/dashboard/modules/operations/src/react/export/export-layout.test.ts +42 -4
  216. package/templates/.agents/dashboard/modules/operations/src/react/export/xlsx-runtime-e2e.test.ts +248 -0
  217. package/templates/.agents/dashboard/modules/operations/src/react/macro-planning-dialog-content.css +49 -0
  218. package/templates/.agents/dashboard/modules/operations/src/react/macro-planning-dialog.css +93 -50
  219. package/templates/.agents/dashboard/modules/operations/src/react/manual-work-priority.test.ts +82 -0
  220. package/templates/.agents/dashboard/modules/operations/src/react/operation-date-range.test.ts +29 -2
  221. package/templates/.agents/dashboard/modules/operations/src/react/operation-date-range.ts +22 -1
  222. package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.test.ts +77 -4
  223. package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.ts +67 -5
  224. package/templates/.agents/dashboard/modules/operations/src/react/operations-coverage-toast.test.ts +54 -0
  225. package/templates/.agents/dashboard/modules/operations/src/react/operations-global-filters.test.ts +22 -0
  226. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +149 -12
  227. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview.status-cards.test.ts +27 -0
  228. package/templates/.agents/dashboard/modules/operations/src/react/operations-page-contract.ts +176 -0
  229. package/templates/.agents/dashboard/modules/operations/src/react/operations-period-scope.test.ts +160 -0
  230. package/templates/.agents/dashboard/modules/operations/src/react/operations-period-scope.ts +47 -0
  231. package/templates/.agents/dashboard/modules/operations/src/react/operations-query.ts +10 -0
  232. package/templates/.agents/dashboard/modules/operations/src/react/operations-responsive.css +3 -0
  233. package/templates/.agents/dashboard/modules/operations/src/react/operations-view-labels.ts +28 -0
  234. package/templates/.agents/dashboard/modules/operations/src/react/operations-view-order.test.ts +21 -7
  235. package/templates/.agents/dashboard/modules/operations/src/react/operations.css +42 -0
  236. package/templates/.agents/dashboard/modules/operations/src/react/period-summary-population.test.ts +54 -0
  237. package/templates/.agents/dashboard/modules/operations/src/react/period-summary-population.ts +32 -0
  238. package/templates/.agents/dashboard/modules/operations/src/react/period-summary.test.ts +241 -6
  239. package/templates/.agents/dashboard/modules/operations/src/react/period-summary.ts +148 -6
  240. package/templates/.agents/dashboard/modules/operations/src/react/popup-localization.test.ts +1 -1
  241. package/templates/.agents/dashboard/modules/operations/src/react/unified-work-board.css +132 -0
  242. package/templates/.agents/dashboard/modules/operations/src/react/unified-work-board.css.test.ts +13 -0
  243. package/templates/.agents/dashboard/modules/operations/src/react/unified-work-board.header.test.ts +16 -0
  244. package/templates/.agents/dashboard/modules/operations/src/react/use-infinite-column.ts +11 -5
  245. package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.test.ts +7 -4
  246. package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.ts +5 -84
  247. package/templates/.agents/dashboard/modules/operations/src/server/build-operations-projection.test.ts +291 -15
  248. package/templates/.agents/dashboard/modules/operations/src/server/build-operations-projection.ts +182 -472
  249. package/templates/.agents/dashboard/modules/operations/src/server/canonical-compat.test.ts +40 -0
  250. package/templates/.agents/dashboard/modules/operations/src/server/canonical-compat.ts +19 -6
  251. package/templates/.agents/dashboard/modules/operations/src/server/canonical-run-projection.ts +31 -6
  252. package/templates/.agents/dashboard/modules/operations/src/server/daily-duration-projection.ts +220 -0
  253. package/templates/.agents/dashboard/modules/operations/src/server/execution-duration-projection.ts +28 -0
  254. package/templates/.agents/dashboard/modules/operations/src/server/execution-relationship-counts.test.ts +39 -2
  255. package/templates/.agents/dashboard/modules/operations/src/server/execution-relationship-counts.ts +25 -13
  256. package/templates/.agents/dashboard/modules/operations/src/server/filter.test.ts +3 -3
  257. package/templates/.agents/dashboard/modules/operations/src/server/filter.ts +7 -2
  258. package/templates/.agents/dashboard/modules/operations/src/server/index.ts +3 -0
  259. package/templates/.agents/dashboard/modules/operations/src/server/macro.ts +3 -12
  260. package/templates/.agents/dashboard/modules/operations/src/server/manifest-usage.ts +65 -0
  261. package/templates/.agents/dashboard/modules/operations/src/server/operations-projection-aggregates.ts +297 -0
  262. package/templates/.agents/dashboard/modules/operations/src/server/quick-daily-operations-projection.ts +330 -0
  263. package/templates/.agents/dashboard/modules/operations/src/server/quick-operations-projection.test.ts +505 -0
  264. package/templates/.agents/dashboard/modules/operations/src/server/quick-operations-projection.ts +609 -0
  265. package/templates/.agents/dashboard/modules/operations/src/server/runs.ts +18 -19
  266. package/templates/.agents/dashboard/modules/operations/src/work-board-model.ts +76 -0
  267. package/templates/.agents/dashboard/modules/traceability/package.json +1 -1
  268. package/templates/.agents/dashboard/modules/traceability/src/server/build-task-trace.ts +3 -1
  269. package/templates/.agents/dashboard/packages/branding/package.json +1 -1
  270. package/templates/.agents/dashboard/packages/branding/src/index.ts +1 -1
  271. package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
  272. package/templates/.agents/dashboard/packages/contracts/src/index.ts +2 -0
  273. package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
  274. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +1759 -0
  275. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs.metafile.json +7333 -0
  276. package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +1611 -0
  277. package/templates/.agents/dashboard/packages/local-runtime/package.json +8 -3
  278. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-dashboard.mjs +20 -0
  279. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-runtime.mjs +114 -0
  280. package/templates/.agents/dashboard/packages/local-runtime/scripts/rebuild-sqlite-read-model.mjs +31 -0
  281. package/templates/.agents/dashboard/packages/local-runtime/scripts/source-size-runtime-scripts/sqlite-read-model-fixture.mjs +397 -0
  282. package/templates/.agents/dashboard/packages/local-runtime/scripts/test-sqlite-read-model.mjs +589 -0
  283. package/templates/.agents/dashboard/packages/local-runtime/scripts/test-unix-launchers.mjs +53 -0
  284. package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-sqlite-read-model.mjs +203 -0
  285. package/templates/.agents/dashboard/packages/local-runtime/server.mjs +1646 -107
  286. package/templates/.agents/dashboard/packages/local-runtime/src/agent-adapter-sync.ts +30 -0
  287. package/templates/.agents/dashboard/packages/local-runtime/src/agent-catalog-settings.test.ts +3 -2
  288. package/templates/.agents/dashboard/packages/local-runtime/src/agent-catalog-settings.ts +5 -0
  289. package/templates/.agents/dashboard/packages/local-runtime/src/manifest-runs.ts +72 -33
  290. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.test.ts +339 -4
  291. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.ts +392 -1
  292. package/templates/.agents/dashboard/packages/local-runtime/src/runtime.mjs +5 -5
  293. package/templates/.agents/dashboard/packages/local-runtime/src/server-board.test.ts +110 -0
  294. package/templates/.agents/dashboard/packages/local-runtime/src/server-board.ts +189 -0
  295. package/templates/.agents/dashboard/packages/local-runtime/src/server-cross-layer-parity.test.ts +245 -0
  296. package/templates/.agents/dashboard/packages/local-runtime/src/server-daily-read-models-route.ts +64 -0
  297. package/templates/.agents/dashboard/packages/local-runtime/src/server-daily-read-models.test.ts +204 -0
  298. package/templates/.agents/dashboard/packages/local-runtime/src/server-daily-read-models.ts +194 -0
  299. package/templates/.agents/dashboard/packages/local-runtime/src/server-operations-pages.test.ts +163 -0
  300. package/templates/.agents/dashboard/packages/local-runtime/src/server-operations-pages.ts +354 -0
  301. package/templates/.agents/dashboard/packages/local-runtime/src/server-operations-runs-route.test.ts +74 -0
  302. package/templates/.agents/dashboard/packages/local-runtime/src/server-operations-runs-route.ts +113 -0
  303. package/templates/.agents/dashboard/packages/local-runtime/src/server-overview.test.ts +68 -0
  304. package/templates/.agents/dashboard/packages/local-runtime/src/server-period.ts +47 -0
  305. package/templates/.agents/dashboard/packages/local-runtime/src/server-projections.ts +483 -0
  306. package/templates/.agents/dashboard/packages/local-runtime/src/server-settings.test.ts +5 -2
  307. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot.test.ts +178 -84
  308. package/templates/.agents/dashboard/packages/local-runtime/src/server-workspace.ts +149 -0
  309. package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +675 -267
  310. package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +1212 -309
  311. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-metric-contract.test.ts +53 -0
  312. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-metric-contract.ts +722 -0
  313. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +3743 -0
  314. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +7017 -0
  315. package/templates/.agents/dashboard/packages/local-runtime/src/work-priority-contract.test.ts +33 -0
  316. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-history.mjs +41 -0
  317. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-processes.mjs +210 -0
  318. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +514 -190
  319. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +324 -24
  320. package/templates/.agents/dashboard/packages/ui/package.json +1 -1
  321. package/templates/.agents/dashboard/packages/windows-launcher/LauncherVerificationBehaviorTests.cs +206 -0
  322. package/templates/.agents/dashboard/packages/windows-launcher/Program.cs +95 -8
  323. package/templates/.agents/dashboard/packages/windows-launcher/build-dashboard-launcher.ps1 +2 -2
  324. package/templates/.agents/dashboard/packages/windows-launcher/run-launcher-verification-tests.ps1 +22 -0
  325. package/templates/.agents/dashboard/read-model.dbml +2201 -0
  326. package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
  327. package/templates/.agents/dashboard/tests/e2e/playwright.config.ts +1 -1
  328. package/templates/.agents/dashboard/tests/e2e/specs/dashboard.spec.ts +216 -41
  329. package/templates/.agents/dashboard/work-priority.json +34 -0
  330. package/templates/.agents/dashboard/zaip-dashboard-linux.sh +45 -0
  331. package/templates/.agents/dashboard/zaip-dashboard-mac.command +3 -0
  332. package/templates/.agents/dashboard/zaip-dashboard-windows.exe +0 -0
  333. package/templates/.agents/design/.zaip-managed.json +3 -3
  334. package/templates/.agents/design/apps/catalog/package.json +1 -1
  335. package/templates/.agents/design/packages/local-runtime/package.json +1 -1
  336. package/templates/.agents/growth/estrategia-bootstrap-90-dias.md +169 -0
  337. package/templates/.agents/growth/strategy.md +27 -0
  338. package/templates/.agents/marketing/estrategia-marketing-zaip-90-dias.md +197 -0
  339. package/templates/.agents/marketing/strategy.md +29 -0
  340. package/templates/.agents/requirements/autonomous-assurance.md +1 -1
  341. package/templates/.agents/requirements/comparative-audit.md +1 -1
  342. package/templates/.agents/requirements/context-engine.md +1 -1
  343. package/templates/.agents/requirements/cost-observability.md +1 -1
  344. package/templates/.agents/requirements/dashboard-launch.md +24 -0
  345. package/templates/.agents/requirements/data-export.md +1 -1
  346. package/templates/.agents/requirements/design-system.md +1 -1
  347. package/templates/.agents/requirements/execution-engine.md +1 -1
  348. package/templates/.agents/requirements/kanban-dashboard.md +4 -3
  349. package/templates/.agents/requirements/model-orchestration.md +1 -1
  350. package/templates/.agents/requirements/public-distribution.md +9 -6
  351. package/templates/.agents/requirements/software-architecture.md +1 -1
  352. package/templates/.agents/requirements/strategic-improvements.md +1 -1
  353. package/templates/.agents/requirements/work-lifecycle.md +9 -3
  354. package/templates/.agents/requirements/zaip-strategic-95.md +4 -4
  355. package/templates/.agents/rules/autonomy-decision.md +15 -0
  356. package/templates/.agents/rules/core.md +1 -1
  357. package/templates/.agents/rules/run-lifecycle-closure.md +1 -1
  358. package/templates/.agents/rules/specialist-routing.md +19 -0
  359. package/templates/.agents/rules/workflow.md +1 -1
  360. package/templates/.agents/runtime/VERSION +1 -1
  361. package/templates/.agents/runtime/bin/zaip.mjs +118 -67
  362. package/templates/.agents/runtime/checksums.sha256 +6 -4
  363. package/templates/.agents/runtime/manifest.json +3 -1
  364. package/templates/.agents/runtime/pnpm-lock.sha256 +1 -0
  365. package/templates/.agents/runtime/provenance.json +11 -0
  366. package/templates/.agents/runtime/sbom.cdx.json +1929 -39
  367. package/templates/.agents/sales/playbook.md +32 -0
  368. package/templates/.agents/sales/roteiro-comercial-zaip.md +252 -0
  369. package/templates/.agents/skills/zaip-aios/SKILL.md +1 -1
  370. package/templates/.agents/skills/zaip-skill-brand-governance/SKILL.md +22 -0
  371. package/templates/.agents/skills/zaip-skill-brand-governance/agents/openai.yaml +4 -0
  372. package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-framework.md +39 -0
  373. package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-standards.md +30 -0
  374. package/templates/.agents/skills/zaip-skill-dashboard-sqlite/SKILL.md +25 -0
  375. package/templates/.agents/skills/zaip-skill-dashboard-sqlite/agents/openai.yaml +4 -0
  376. package/templates/.agents/skills/zaip-skill-enforce-architecture/SKILL.md +2 -0
  377. package/templates/.agents/skills/zaip-skill-executar-fila-pronta/SKILL.md +18 -0
  378. package/templates/.agents/skills/zaip-skill-executar-fila-pronta/agents/openai.yaml +6 -0
  379. package/templates/.agents/skills/zaip-skill-executar-fila-pronta/scripts/ready-queue-fence.mjs +71 -0
  380. package/templates/.agents/skills/zaip-skill-executar-fila-pronta/scripts/ready-queue-fence.test.mjs +60 -0
  381. package/templates/.agents/skills/zaip-skill-executar-fila-pronta/scripts/scheduled-ready-queue-contract.test.mjs +111 -0
  382. package/templates/.agents/skills/zaip-skill-execution/SKILL.md +2 -2
  383. package/templates/.agents/skills/zaip-skill-frontend-launcher/references/launcher-contract.md +3 -1
  384. package/templates/.agents/skills/zaip-skill-general-operations/SKILL.md +12 -0
  385. package/templates/.agents/skills/zaip-skill-general-operations/agents/openai.yaml +4 -0
  386. package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +9 -7
  387. package/templates/.agents/skills/zaip-skill-github-deploy/agents/openai.yaml +2 -2
  388. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/github-deploy-contract.test.mjs +11 -38
  389. package/templates/.agents/skills/zaip-skill-governance-compliance/SKILL.md +12 -0
  390. package/templates/.agents/skills/zaip-skill-governance-compliance/agents/openai.yaml +4 -0
  391. package/templates/.agents/skills/zaip-skill-growth-strategy-revops/SKILL.md +21 -0
  392. package/templates/.agents/skills/zaip-skill-growth-strategy-revops/agents/openai.yaml +4 -0
  393. package/templates/.agents/skills/zaip-skill-growth-strategy-revops/references/growth-revops-framework.md +25 -0
  394. package/templates/.agents/skills/zaip-skill-instalar-agendamento/SKILL.md +17 -0
  395. package/templates/.agents/skills/zaip-skill-instalar-agendamento/agents/openai.yaml +6 -0
  396. package/templates/.agents/skills/zaip-skill-marketing/SKILL.md +9 -3
  397. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.mjs +99 -93
  398. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.mjs +132 -23
  399. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.test.mjs +149 -1
  400. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.mjs +76 -19
  401. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.test.mjs +217 -7
  402. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/source-size-telemetry/model-identity-reconciliation.mjs +77 -0
  403. package/templates/.agents/skills/zaip-skill-sales-methodology/SKILL.md +20 -0
  404. package/templates/.agents/skills/zaip-skill-sales-methodology/agents/openai.yaml +4 -0
  405. package/templates/.agents/skills/zaip-skill-sales-methodology/references/sales-process-framework.md +77 -0
  406. package/templates/.agents/skills/zaip-skill-setup/SKILL.md +5 -0
  407. package/templates/.agents/skills/zaip-skill-sqlite-read-model/SKILL.md +96 -0
  408. package/templates/.agents/skills/zaip-skill-sqlite-read-model/agents/openai.yaml +4 -0
  409. package/templates/.agents/skills/zaip-skill-sqlite-read-model/scripts/ensure-node.mjs +41 -0
  410. package/templates/.agents/zaip-aios/INDEX.md +11 -0
  411. package/templates/.agents/zaip-aios/README.md +38 -8
  412. package/templates/.agents/zaip-aios/VERSION +1 -1
  413. package/templates/.agents/zaip-aios/guides/09-agentes-e-squads.md +43 -6
  414. package/templates/.agents/zaip-aios/guides/10-seguranca.md +21 -7
  415. package/templates/.agents/zaip-aios/guides/17-como-o-custo-e-calculado.md +32 -0
  416. package/templates/.agents/zaip-aios/guides/18-catalogo-de-agentes.md +76 -0
  417. package/templates/.agents/zaip-aios/guides/19-assurance-e-autonomia.md +72 -0
  418. package/templates/.agents/zaip-aios/guides/20-instalacao-detalhada.md +330 -0
  419. package/templates/.agents/zaip-aios/guides/21-telemetria-monitor-custos.md +52 -0
  420. package/templates/.agents/zaip-aios/guides/22-fluxos-e-roteamento.md +69 -0
  421. package/templates/.agents/zaip-aios/guides/23-orquestracao-de-modelos.md +483 -0
  422. package/templates/.agents/zaip-aios/guides/24-calculo-de-custos-openai.md +85 -0
  423. package/templates/.agents/zaip-aios/guides/25-fontes-de-precos-openai.md +18 -0
  424. package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +44 -0
  425. package/templates/.agents/zaip-aios/guides/27-telemetria-git-native.md +167 -0
  426. package/templates/.agents/zaip-aios/guides/28-lifecycle-completo.md +144 -0
  427. package/templates/.agents/zaip-aios/guides/assets/diagrams/lifecycles-task-spec-prd.png +0 -0
  428. package/templates/.agents/zaip-aios/guides/assets/diagrams/prd-lifecycle.png +0 -0
  429. package/templates/.agents/zaip-aios/guides/assets/diagrams/spec-lifecycle.png +0 -0
  430. package/templates/.agents/zaip-aios/guides/assets/diagrams/task-lifecycle.png +0 -0
  431. package/templates/template-manifest.json +1082 -215
  432. package/templates/.agents/dashboard/apps/frontend/dist/assets/AgentCatalogSettingsPage-CLYIi7Vo.js +0 -1
  433. package/templates/.agents/dashboard/apps/frontend/dist/assets/AgentCatalogSettingsPage-DTDNVQGX.css +0 -1
  434. package/templates/.agents/dashboard/apps/frontend/dist/assets/DashboardHelpDialog-Cv-JcoxP.js +0 -1320
  435. package/templates/.agents/dashboard/apps/frontend/dist/assets/PricingSettingsDialog-CzEggcRb.js +0 -1
  436. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-05YKn6Z4.js +0 -3
  437. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-YO3yqtgV.css +0 -1
  438. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-8AzCnl3a.js +0 -77
  439. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-DdBYQ_8D.css +0 -1
  440. package/templates/.agents/dashboard/apps/frontend/src/AgentCatalogSettingsPage.tsx +0 -617
  441. package/templates/.agents/dashboard/apps/frontend/src/agent-catalog-settings-page.css +0 -660
  442. package/templates/.agents/dashboard/apps/frontend/src/agent-catalog-settings.test.ts +0 -249
  443. package/templates/.agents/dashboard/dashboard.config.json +0 -4
  444. package/templates/.agents/dashboard/zaip-dashboard.exe +0 -0
@@ -14,6 +14,7 @@ import { formatRoundedDuration } from "./format-rounded-duration.js";
14
14
  import { MacroPlanningDialog } from "./MacroPlanningDialog.js";
15
15
  import { type OperationsLocale, riskLabel } from "./status-labels.js";
16
16
  import { taskTotals } from "./TaskBoard.js";
17
+ import { TaskDetailsDialog } from "./TaskDetailsDialog.js";
17
18
  import { taskOrigin } from "./task-origin.js";
18
19
  import { useCurrentTime } from "./use-current-time.js";
19
20
  import { useInfiniteColumn } from "./use-infinite-column.js";
@@ -36,23 +37,44 @@ type WorkItem =
36
37
  | { kind: "prd" | "spec"; row: MacroProjection };
37
38
 
38
39
  export function UnifiedWorkBoard({
40
+ allPrds,
39
41
  allSpecs,
40
42
  allTasks,
43
+ boardTotals,
44
+ boardKindTotals,
45
+ boardStates,
41
46
  changes,
42
47
  locale,
43
48
  onOpenDocument,
44
49
  onOpenTask,
50
+ onPriorityChange,
51
+ onLoadMore,
52
+ onTypeChange,
45
53
  prds,
46
54
  runs,
47
55
  specs,
48
56
  tasks,
49
57
  }: {
58
+ allPrds: readonly MacroProjection[];
50
59
  allSpecs: readonly MacroProjection[];
51
60
  allTasks: readonly DashboardTaskProjection[];
61
+ boardTotals?: Partial<Record<WorkStage, number>> | undefined;
62
+ boardKindTotals?:
63
+ | Partial<
64
+ Record<
65
+ WorkStage,
66
+ { all: number; task: number; "standalone-task": number; prd: number; spec: number }
67
+ >
68
+ >
69
+ | undefined;
70
+ boardStates?: Partial<Record<WorkStage, { loading: boolean; error: string | null }>> | undefined;
52
71
  changes: readonly ChangeProjection[];
53
72
  locale: OperationsLocale;
54
73
  onOpenDocument: (kind: "prd" | "spec", id: string) => void;
55
74
  onOpenTask: (taskId: string) => Promise<boolean>;
75
+ onPriorityChange: (itemIds: readonly string[]) => Promise<void>;
76
+ onLoadMore?: ((stage: WorkStage) => void) | undefined;
77
+ onTypeChange?: ((value: WorkTypeFilter) => void) | undefined;
56
78
  prds: readonly MacroProjection[];
57
79
  runs: readonly RunProjection[];
58
80
  specs: readonly MacroProjection[];
@@ -62,18 +84,29 @@ export function UnifiedWorkBoard({
62
84
  const [typeFilter, setTypeFilter] = useState<WorkTypeFilter>("all");
63
85
  const [selectedStage, setSelectedStage] = useState<WorkStage | null>(null);
64
86
  const [selectedMacro, setSelectedMacro] = useState<MacroProjection | null>(null);
87
+ const [selectedTask, setSelectedTask] = useState<DashboardTaskProjection | null>(null);
65
88
  const [query, setQuery] = useState("");
66
- const totalsByTask = useMemo(() => taskTotals(runs, tasks), [runs, tasks]);
67
- const items = useMemo(
89
+ const [draggedId, setDraggedId] = useState<string | null>(null);
90
+ const [optimisticOrder, setOptimisticOrder] = useState<readonly string[] | null>(null);
91
+ // Card telemetry comes from the compact per-Task projection. Do not scan the
92
+ // complete Run collection when a card opens; absent compact telemetry remains
93
+ // unavailable instead of being reconstructed from a partial page of Runs.
94
+ const totalsByTask = useMemo(() => taskTotals([], tasks), [tasks]);
95
+ const allItems = useMemo(
68
96
  () =>
69
97
  sortWorkItems(
70
98
  [
71
- ...prds.map((row): WorkItem => ({ kind: "prd", row })),
72
- ...specs.map((row): WorkItem => ({ kind: "spec", row })),
73
- ...tasks.map((row): WorkItem => ({ kind: "task", row })),
74
- ].filter((item) => isWorkItemVisible(item, typeFilter)),
99
+ ...allPrds.map((row): WorkItem => ({ kind: "prd", row })),
100
+ ...allSpecs.map((row): WorkItem => ({ kind: "spec", row })),
101
+ ...allTasks.map((row): WorkItem => ({ kind: "task", row })),
102
+ ],
103
+ optimisticOrder,
75
104
  ),
76
- [prds, specs, tasks, typeFilter],
105
+ [allPrds, allSpecs, allTasks, optimisticOrder],
106
+ );
107
+ const items = useMemo(
108
+ () => allItems.filter((item) => isWorkItemVisible(item, typeFilter)),
109
+ [allItems, typeFilter],
77
110
  );
78
111
  const progressByMacro = useMemo(
79
112
  () =>
@@ -88,12 +121,19 @@ export function UnifiedWorkBoard({
88
121
  : items.filter((item) => itemStage(item, allTasks) === selectedStage);
89
122
  const openItem = (item: WorkItem) => {
90
123
  setSelectedStage(null);
91
- if (item.kind === "task") void onOpenTask(item.row.id);
124
+ if (item.kind === "task") setSelectedTask(item.row);
92
125
  else setSelectedMacro(item.row);
93
126
  };
94
127
  return (
95
128
  <section className="operations-unified-work">
96
- <WorkTypeFilters locale={locale} onChange={setTypeFilter} value={typeFilter} />
129
+ <WorkTypeFilters
130
+ locale={locale}
131
+ onChange={(value) => {
132
+ setTypeFilter(value);
133
+ onTypeChange?.(value);
134
+ }}
135
+ value={typeFilter}
136
+ />
97
137
  <section
98
138
  aria-label={locale === "pt-BR" ? "Kanban de trabalho" : "Work Kanban"}
99
139
  className="operations-board operations-work-board"
@@ -103,6 +143,7 @@ export function UnifiedWorkBoard({
103
143
  return (
104
144
  <WorkColumn
105
145
  changes={changes}
146
+ globalItems={allItems}
106
147
  items={rows}
107
148
  key={stage}
108
149
  locale={locale}
@@ -111,9 +152,33 @@ export function UnifiedWorkBoard({
111
152
  setQuery("");
112
153
  setSelectedStage(stage);
113
154
  }}
155
+ onLoadMore={onLoadMore === undefined ? undefined : () => onLoadMore(stage)}
114
156
  onOpenItem={openItem}
157
+ onPriorityChange={async (nextOrder) => {
158
+ const previous = optimisticOrder;
159
+ setOptimisticOrder(nextOrder);
160
+ try {
161
+ await onPriorityChange(nextOrder);
162
+ } catch {
163
+ setOptimisticOrder(previous);
164
+ }
165
+ }}
166
+ onDragEnd={() => setDraggedId(null)}
167
+ onDragStart={setDraggedId}
168
+ draggedId={draggedId}
115
169
  progressByMacro={progressByMacro}
116
170
  stage={stage}
171
+ totalItems={
172
+ typeFilter === "all"
173
+ ? (boardKindTotals?.[stage]?.all ?? boardTotals?.[stage] ?? rows.length)
174
+ : typeFilter === "task" ||
175
+ typeFilter === "standalone-task" ||
176
+ typeFilter === "prd" ||
177
+ typeFilter === "spec"
178
+ ? (boardKindTotals?.[stage]?.[typeFilter] ?? rows.length)
179
+ : rows.length
180
+ }
181
+ state={boardStates?.[stage]}
117
182
  totalsByTask={totalsByTask}
118
183
  />
119
184
  );
@@ -146,10 +211,31 @@ export function UnifiedWorkBoard({
146
211
  tasks={allTasks}
147
212
  />
148
213
  ) : null}
214
+ {selectedTask ? (
215
+ <TaskDetailsDialog
216
+ detail={{ task: selectedTask, body: "", artifact_path: selectedTask.artifact_path }}
217
+ locale={locale}
218
+ onClose={() => setSelectedTask(null)}
219
+ onOpenTrace={(taskId) => {
220
+ setSelectedTask(null);
221
+ void onOpenTask(taskId);
222
+ }}
223
+ operations={{ decisions: [], runs }}
224
+ summary
225
+ summaryRunCount={exactTaskRunCount(selectedTask)}
226
+ />
227
+ ) : null}
149
228
  </section>
150
229
  );
151
230
  }
152
231
 
232
+ function exactTaskRunCount(task: DashboardTaskProjection): number | null {
233
+ const runCount = (task as DashboardTaskProjection & { run_count?: unknown }).run_count;
234
+ return typeof runCount === "number" && Number.isInteger(runCount) && runCount >= 0
235
+ ? runCount
236
+ : null;
237
+ }
238
+
153
239
  export function WorkTypeFilters({
154
240
  locale,
155
241
  onChange,
@@ -166,7 +252,7 @@ export function WorkTypeFilters({
166
252
  all: "Tudo",
167
253
  prd: "PRDs",
168
254
  spec: "SPECs",
169
- "standalone-task": "Tarefas Avulsas",
255
+ "standalone-task": "Tarefa Avulsa",
170
256
  }
171
257
  : {
172
258
  task: "Tasks",
@@ -175,7 +261,7 @@ export function WorkTypeFilters({
175
261
  spec: "SPECs",
176
262
  "standalone-task": "Standalone Tasks",
177
263
  };
178
- const filterOrder: readonly WorkTypeFilter[] = ["all", "task", "prd", "spec"];
264
+ const filterOrder: readonly WorkTypeFilter[] = ["all", "task", "standalone-task", "prd", "spec"];
179
265
  return (
180
266
  <nav
181
267
  aria-label={locale === "pt-BR" ? "Filtrar tipo de trabalho" : "Filter work type"}
@@ -197,26 +283,46 @@ export function WorkTypeFilters({
197
283
 
198
284
  function WorkColumn({
199
285
  changes,
286
+ globalItems,
200
287
  items,
288
+ totalItems,
289
+ state,
201
290
  locale,
202
291
  nowMs,
203
292
  onOpenColumn,
293
+ onLoadMore,
204
294
  onOpenItem,
295
+ onPriorityChange,
296
+ onDragEnd,
297
+ onDragStart,
298
+ draggedId,
205
299
  progressByMacro,
206
300
  stage,
207
301
  totalsByTask,
208
302
  }: {
209
303
  changes: readonly ChangeProjection[];
304
+ globalItems: readonly WorkItem[];
210
305
  items: readonly WorkItem[];
306
+ totalItems: number;
307
+ state: { loading: boolean; error: string | null } | undefined;
211
308
  locale: OperationsLocale;
212
309
  nowMs: number;
213
310
  onOpenColumn: () => void;
311
+ onLoadMore?: (() => void) | undefined;
214
312
  onOpenItem: (item: WorkItem) => void;
313
+ onPriorityChange: (itemIds: readonly string[]) => Promise<void>;
314
+ onDragEnd: () => void;
315
+ onDragStart: (id: string) => void;
316
+ draggedId: string | null;
215
317
  progressByMacro: ReadonlyMap<string, MacroWorkProgress>;
216
318
  stage: WorkStage;
217
319
  totalsByTask: ReturnType<typeof taskTotals>;
218
320
  }) {
219
- const { hasMore, sentinelRef, visibleCount } = useInfiniteColumn(items.length);
321
+ const { hasMore, sentinelRef, visibleCount } = useInfiniteColumn(
322
+ items.length,
323
+ totalItems,
324
+ onLoadMore,
325
+ );
220
326
  return (
221
327
  <article className={`operations-column is-${stage}`}>
222
328
  <header>
@@ -224,16 +330,16 @@ function WorkColumn({
224
330
  {workStageLabel(stage, locale)}
225
331
  </button>
226
332
  <button
227
- aria-label={`${items.length} — ${workStageLabel(stage, locale)}`}
333
+ aria-label={`${totalItems} — ${workStageLabel(stage, locale)}`}
228
334
  className="operations-column-count"
229
335
  onClick={onOpenColumn}
230
336
  type="button"
231
337
  >
232
- {items.length}
338
+ {totalItems}
233
339
  </button>
234
340
  </header>
235
341
  <div className="operations-column-body">
236
- {items.slice(0, visibleCount).map((item) => (
342
+ {items.slice(0, visibleCount).map((item, index) => (
237
343
  <WorkCard
238
344
  changes={changes}
239
345
  item={item}
@@ -241,17 +347,52 @@ function WorkColumn({
241
347
  locale={locale}
242
348
  nowMs={nowMs}
243
349
  onOpen={() => onOpenItem(item)}
350
+ onMove={(direction) => {
351
+ const next = index + direction;
352
+ if (next < 0 || next >= items.length) return;
353
+ const reordered = [...items];
354
+ [reordered[index], reordered[next]] = [reordered[next]!, reordered[index]!];
355
+ void onPriorityChange(mergeManualWorkOrder(globalItems, items, reordered));
356
+ }}
357
+ onDrop={() => {
358
+ const from = items.findIndex((candidate) => candidate.row.id === draggedId);
359
+ if (from < 0 || from === index) return;
360
+ const reordered = [...items];
361
+ const [moved] = reordered.splice(from, 1);
362
+ if (moved === undefined) return;
363
+ reordered.splice(index, 0, moved);
364
+ void onPriorityChange(mergeManualWorkOrder(globalItems, items, reordered));
365
+ }}
366
+ onDragEnd={onDragEnd}
367
+ onDragStart={() => onDragStart(item.row.id)}
368
+ order={index + 1}
244
369
  progress={progressByMacro.get(item.row.id)}
245
370
  stage={stage}
246
371
  totalsByTask={totalsByTask}
247
372
  />
248
373
  ))}
249
- {items.length === 0 ? (
374
+ {items.length === 0 && !state?.loading ? (
250
375
  <p className="operations-empty">{locale === "pt-BR" ? "Sem itens" : "No items"}</p>
251
376
  ) : null}
252
377
  {hasMore ? (
253
- <div className="operations-infinite-sentinel" ref={sentinelRef}>
254
- {visibleCount} de {items.length} · carregando mais…
378
+ <div
379
+ aria-live="polite"
380
+ className="operations-infinite-sentinel"
381
+ ref={sentinelRef}
382
+ role={state?.error ? "alert" : "status"}
383
+ >
384
+ {state?.error ? (
385
+ <>
386
+ <span>{state.error}</span>
387
+ <button onClick={onLoadMore} type="button">
388
+ Tentar novamente
389
+ </button>
390
+ </>
391
+ ) : state?.loading ? (
392
+ "Carregando mais…"
393
+ ) : (
394
+ `${visibleCount} de ${totalItems} · carregando mais…`
395
+ )}
255
396
  </div>
256
397
  ) : null}
257
398
  </div>
@@ -265,6 +406,11 @@ function WorkCard({
265
406
  locale,
266
407
  nowMs,
267
408
  onOpen,
409
+ onMove,
410
+ onDrop,
411
+ onDragEnd,
412
+ onDragStart,
413
+ order,
268
414
  progress,
269
415
  stage,
270
416
  totalsByTask,
@@ -274,6 +420,11 @@ function WorkCard({
274
420
  locale: OperationsLocale;
275
421
  nowMs: number;
276
422
  onOpen: () => void;
423
+ onMove: (direction: -1 | 1) => void;
424
+ onDrop: () => void;
425
+ onDragEnd: () => void;
426
+ onDragStart: () => void;
427
+ order: number;
277
428
  progress: MacroWorkProgress | undefined;
278
429
  stage: WorkStage;
279
430
  totalsByTask: ReturnType<typeof taskTotals>;
@@ -288,19 +439,64 @@ function WorkCard({
288
439
  ? [macro.duration_ms, macro.usage.total.tokens.total, macro.usage.total.cost.brl]
289
440
  : [totals?.durationMs ?? null, totals?.tokens ?? null, totals?.costBrl ?? null];
290
441
  return (
291
- <button
442
+ <article
292
443
  className={`operations-task-card operations-work-card is-kind-${origin}`}
293
- onClick={onOpen}
294
- type="button"
444
+ draggable={stage === "ready"}
445
+ onDragEnd={stage === "ready" ? onDragEnd : undefined}
446
+ onDragOver={stage === "ready" ? (event) => event.preventDefault() : undefined}
447
+ onDragStart={stage === "ready" ? onDragStart : undefined}
448
+ onDrop={
449
+ stage === "ready"
450
+ ? (event) => {
451
+ event.preventDefault();
452
+ onDrop();
453
+ }
454
+ : undefined
455
+ }
295
456
  >
296
- <span className={`operations-work-kind is-${item.kind}`}>{kindLabel}</span>
297
- <span className={`operations-work-status is-${stage}`}>
298
- {workStageBadgeLabel(stage, locale)}
299
- </span>
300
- {task ? (
301
- <span className={`operations-risk is-${task.risk}`}>{riskLabel(task.risk, locale)}</span>
457
+ <button
458
+ aria-label={openWorkCardLabel(locale, item.row.title)}
459
+ className="operations-work-card-open"
460
+ onClick={onOpen}
461
+ type="button"
462
+ >
463
+ {stage === "ready" ? (
464
+ <span className="operations-work-card-first-line">
465
+ <span className="operations-work-order">#{order}</span>
466
+ </span>
467
+ ) : null}
468
+ <span className={`operations-work-kind is-${item.kind}`}>{kindLabel}</span>
469
+ {order === 1 && stage === "ready" ? (
470
+ <span className="operations-work-next">Próximo</span>
471
+ ) : null}
472
+ {stage !== "ready" ? (
473
+ <span className={`operations-work-status is-${stage}`}>
474
+ {workStageBadgeLabel(stage, locale)}
475
+ </span>
476
+ ) : null}
477
+ {task ? (
478
+ <span className={`operations-risk is-${task.risk}`}>{riskLabel(task.risk, locale)}</span>
479
+ ) : null}
480
+ <strong title={item.row.title}>{item.row.title}</strong>
481
+ </button>
482
+ {stage === "ready" ? (
483
+ <div className="operations-work-reorder">
484
+ <button
485
+ aria-label={locale === "pt-BR" ? "Mover acima" : "Move up"}
486
+ onClick={() => onMove(-1)}
487
+ type="button"
488
+ >
489
+ ↑
490
+ </button>
491
+ <button
492
+ aria-label={locale === "pt-BR" ? "Mover abaixo" : "Move down"}
493
+ onClick={() => onMove(1)}
494
+ type="button"
495
+ >
496
+ ↓
497
+ </button>
498
+ </div>
302
499
  ) : null}
303
- <strong title={item.row.title}>{item.row.title}</strong>
304
500
  <small title={item.row.id}>{item.row.id}</small>
305
501
  {item.row.created_at ? (
306
502
  <small className="operations-card-created">
@@ -343,7 +539,25 @@ function WorkCard({
343
539
  </div>
344
540
  ))}
345
541
  </dl>
346
- </button>
542
+ </article>
543
+ );
544
+ }
545
+
546
+ export function openWorkCardLabel(locale: OperationsLocale, title: string): string {
547
+ return locale === "pt-BR" ? `Abrir ${title}` : `Open ${title}`;
548
+ }
549
+
550
+ /** Replaces only visible-column slots, preserving the global order of all other work. */
551
+ export function mergeManualWorkOrder(
552
+ globalItems: readonly WorkItem[],
553
+ previousColumn: readonly WorkItem[],
554
+ reorderedColumn: readonly WorkItem[],
555
+ ): string[] {
556
+ const columnIds = new Set(previousColumn.map((item) => item.row.id));
557
+ const reorderedIds = reorderedColumn.map((item) => item.row.id);
558
+ let cursor = 0;
559
+ return globalItems.map((item) =>
560
+ columnIds.has(item.row.id) ? (reorderedIds[cursor++] ?? item.row.id) : item.row.id,
347
561
  );
348
562
  }
349
563
 
@@ -448,18 +662,33 @@ function itemStage(item: WorkItem, tasks: readonly DashboardTaskProjection[]): W
448
662
  return item.kind === "task" ? taskWorkStage(item.row) : macroWorkStage(item.row, tasks);
449
663
  }
450
664
 
451
- function sortWorkItems(items: WorkItem[]): WorkItem[] {
452
- const priorityOrder = { urgent: 0, high: 1, medium: 2, low: 3 } as const;
665
+ export function sortWorkItems(
666
+ items: WorkItem[],
667
+ optimisticOrder: readonly string[] | null = null,
668
+ ): WorkItem[] {
669
+ const optimisticRanks =
670
+ optimisticOrder === null ? null : new Map(optimisticOrder.map((id, index) => [id, index]));
453
671
  return items.sort(
454
672
  (left, right) =>
455
- workItemTimestamp(right).localeCompare(workItemTimestamp(left)) ||
456
- String(itemStage(left, [])).localeCompare(String(itemStage(right, []))) ||
457
- (left.kind === "task" ? priorityOrder[left.row.priority] : 4) -
458
- (right.kind === "task" ? priorityOrder[right.row.priority] : 4) ||
459
- right.row.id.localeCompare(left.row.id),
673
+ compareManualOrder(
674
+ optimisticRanks?.get(left.row.id) ?? left.row.manual_order,
675
+ optimisticRanks?.get(right.row.id) ?? right.row.manual_order,
676
+ ) ||
677
+ workItemTimestamp(left).localeCompare(workItemTimestamp(right)) ||
678
+ left.row.id.localeCompare(right.row.id),
460
679
  );
461
680
  }
462
681
 
682
+ function compareManualOrder(
683
+ left: number | null | undefined,
684
+ right: number | null | undefined,
685
+ ): number {
686
+ if (left != null && right != null) return left - right;
687
+ if (left != null) return -1;
688
+ if (right != null) return 1;
689
+ return 0;
690
+ }
691
+
463
692
  function workItemTimestamp(item: WorkItem): string {
464
693
  return item.kind === "task"
465
694
  ? item.row.updated_at
@@ -1,9 +1,55 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { fileURLToPath } from "node:url";
1
3
  import { describe, expect, it } from "vitest";
2
- import type { DashboardTaskProjection, RunProjection } from "../contracts.js";
3
- import { buildWorkListRows } from "./UnifiedWorkList.js";
4
+ import type { DashboardTaskProjection, MacroProjection, RunProjection } from "../contracts.js";
5
+ import { buildWorkListRows, formatWorkListDuration } from "./UnifiedWorkList.js";
4
6
 
5
7
  describe("buildWorkListRows", () => {
6
- it("aggregates run, sub-run, execution, duration, token and cost indicators for a task", () => {
8
+ it("labels only active missing time as in progress and preserves temporal absence elsewhere", () => {
9
+ expect(formatWorkListDuration(null, "executing", "pt-BR")).toBe("Em andamento");
10
+ expect(formatWorkListDuration(null, "blocked", "pt-BR")).toBe("Sem atribuição temporal");
11
+ expect(formatWorkListDuration(0, "cancelled", "pt-BR")).toBe("0 seg");
12
+ });
13
+
14
+ it("keeps the operational list to its eight standard columns", () => {
15
+ const source = readFileSync(
16
+ fileURLToPath(new URL("./UnifiedWorkList.tsx", import.meta.url)),
17
+ "utf8",
18
+ );
19
+ const keys = [...source.matchAll(/key: "([^"]+)"/g)].map((match) => match[1]);
20
+ expect(keys.slice(0, 8)).toEqual([
21
+ "item",
22
+ "status",
23
+ "type",
24
+ "risk",
25
+ "progress",
26
+ "time",
27
+ "tokens",
28
+ "cost",
29
+ ]);
30
+ expect(source).toContain('label: "Item"');
31
+ expect(source).toContain('label: "Status"');
32
+ expect(source).toContain('label: locale === "pt-BR" ? "Tipo" : "Type"');
33
+ expect(source).toContain('label: locale === "pt-BR" ? "Risco" : "Risk"');
34
+ expect(source).toContain('label: locale === "pt-BR" ? "Progresso" : "Progress"');
35
+ expect(source).toContain('label: locale === "pt-BR" ? "Tempo" : "Time"');
36
+ expect(source).toContain('label: "Tokens"');
37
+ expect(source).toContain('label: locale === "pt-BR" ? "Custo" : "Cost"');
38
+ expect(keys).not.toEqual(
39
+ expect.arrayContaining(["runs", "lifecycleElapsed", "executions", "tasks", "duration"]),
40
+ );
41
+ expect(source).not.toContain("taskOriginLabel");
42
+ });
43
+
44
+ it("propagates the selected type so the server can fetch that canonical collection", () => {
45
+ const source = readFileSync(
46
+ fileURLToPath(new URL("./UnifiedWorkList.tsx", import.meta.url)),
47
+ "utf8",
48
+ );
49
+ expect(source).toContain("onTypeChange?.(kind)");
50
+ });
51
+
52
+ it("uses paginated Runs only when task telemetry is absent", () => {
7
53
  const task = {
8
54
  id: "TASK-1",
9
55
  title: "List operational work",
@@ -18,6 +64,7 @@ describe("buildWorkListRows", () => {
18
64
  task_id: task.id,
19
65
  execution_id: "EXEC-1",
20
66
  duration_ms: 1_000,
67
+ source_duration_ms: 1_000,
21
68
  phase: "execution",
22
69
  parent_run_id: null,
23
70
  usage: { total: { tokens: { total: 120 }, cost: { brl: 0.25 } } },
@@ -29,15 +76,18 @@ describe("buildWorkListRows", () => {
29
76
  items: [{ kind: "task", row: task }],
30
77
  runs: [
31
78
  { ...baseRun, id: "RUN-1", run_kind: "run" },
32
- { ...baseRun, id: "RUN-2", run_kind: "subrun", parent_run_id: "RUN-1", duration_ms: 500 },
79
+ {
80
+ ...baseRun,
81
+ id: "RUN-2",
82
+ run_kind: "subrun",
83
+ parent_run_id: "RUN-1",
84
+ duration_ms: 500,
85
+ source_duration_ms: 500,
86
+ },
33
87
  ],
34
88
  });
35
89
 
36
90
  expect(rows[0]).toMatchObject({
37
- runCount: 1,
38
- subrunCount: 1,
39
- executionCount: 1,
40
- taskCount: 1,
41
91
  durationMs: 1_000,
42
92
  tokens: 240,
43
93
  costBrl: 0.5,
@@ -45,4 +95,117 @@ describe("buildWorkListRows", () => {
45
95
  stage: "executing",
46
96
  });
47
97
  });
98
+
99
+ it("prefers consolidated task telemetry over incomplete paginated Runs", () => {
100
+ const task = {
101
+ id: "TASK-FAST-SNAPSHOT",
102
+ title: "Telemetry from task projection",
103
+ status: "executing",
104
+ progress: 50,
105
+ spec_id: null,
106
+ telemetry: { duration_ms: 1_500, tokens: 9_000, cost_brl: 7.5 },
107
+ } as DashboardTaskProjection;
108
+
109
+ const [row] = buildWorkListRows({
110
+ allSpecs: [],
111
+ allTasks: [task],
112
+ changes: [],
113
+ items: [{ kind: "task", row: task }],
114
+ runs: [
115
+ {
116
+ id: "RUN-PAGE",
117
+ task_id: "TASK-FAST-SNAPSHOT",
118
+ run_kind: "run",
119
+ phase: "execution",
120
+ parent_run_id: null,
121
+ duration_ms: 10,
122
+ source_duration_ms: 10,
123
+ usage: { total: { tokens: { total: 1 }, cost: { brl: 0.01 } } },
124
+ } as RunProjection,
125
+ ],
126
+ });
127
+
128
+ expect(row).toMatchObject({ durationMs: 1_500, tokens: 9_000, costBrl: 7.5 });
129
+ });
130
+
131
+ it("renders a known zero only for tasks with an explicit no-activity lifecycle state", () => {
132
+ const noActivity = {
133
+ id: "TASK-READY-NO-RUNS",
134
+ title: "Prepared without execution",
135
+ status: "planned",
136
+ risk: "lite",
137
+ progress: 0,
138
+ spec_id: null,
139
+ execution_started: false,
140
+ execution_count: 0,
141
+ } as DashboardTaskProjection;
142
+ const unavailable = {
143
+ ...noActivity,
144
+ id: "TASK-PARTIAL-PAGE",
145
+ execution_started: true,
146
+ execution_count: 1,
147
+ } as DashboardTaskProjection;
148
+ const cancelledNoActivity = {
149
+ ...noActivity,
150
+ id: "TASK-CANCELLED-NO-RUNS",
151
+ status: "cancelled",
152
+ } as unknown as DashboardTaskProjection;
153
+ delete (cancelledNoActivity as { execution_count?: number }).execution_count;
154
+ const measured = {
155
+ ...noActivity,
156
+ id: "TASK-MEASURED",
157
+ execution_started: true,
158
+ execution_count: 1,
159
+ telemetry: { duration_ms: 60_000, tokens: 10, cost_brl: 1 },
160
+ } as DashboardTaskProjection;
161
+
162
+ const rows = buildWorkListRows({
163
+ allSpecs: [],
164
+ allTasks: [noActivity, unavailable, cancelledNoActivity, measured],
165
+ changes: [],
166
+ items: [
167
+ { kind: "task", row: noActivity },
168
+ { kind: "task", row: unavailable },
169
+ { kind: "task", row: cancelledNoActivity },
170
+ { kind: "task", row: measured },
171
+ ],
172
+ runs: [],
173
+ });
174
+
175
+ expect(rows.map((row) => row.durationMs)).toEqual([0, null, 0, 60_000]);
176
+ expect(rows.reduce((total, row) => total + (row.durationMs ?? 0), 0)).toBe(60_000);
177
+ });
178
+
179
+ it("renders a known zero for a macro with no materialized children or Runs", () => {
180
+ const emptyMacro = {
181
+ id: "SPEC-EMPTY",
182
+ title: "Empty specification",
183
+ kind: "spec",
184
+ lifecycle_status: "draft",
185
+ work_status: "planning",
186
+ created_at: null,
187
+ parent_id: null,
188
+ artifact_path: ".agents/records/specs/SPEC-EMPTY.md",
189
+ execution_ids: [],
190
+ task_ids: [],
191
+ planned_tasks: [],
192
+ run_ids: [],
193
+ task_count: 0,
194
+ execution_count: 0,
195
+ run_count: 0,
196
+ duration_ms: null,
197
+ quality: { task_completion_rate: 0 },
198
+ usage: { total: { tokens: { total: null }, cost: { brl: null } } },
199
+ } as unknown as MacroProjection;
200
+
201
+ const [row] = buildWorkListRows({
202
+ allSpecs: [emptyMacro],
203
+ allTasks: [],
204
+ changes: [],
205
+ items: [{ kind: "spec", row: emptyMacro }],
206
+ runs: [],
207
+ });
208
+
209
+ expect(row?.durationMs).toBe(0);
210
+ });
48
211
  });