@zaip-ai/cli 1.3.0 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/README.md +3 -2
  2. package/dist/services/agent-adapters.js +1 -1
  3. package/dist/services/agent-adapters.js.map +1 -1
  4. package/dist/services/agent-adapters.test.js +2 -1
  5. package/dist/services/agent-adapters.test.js.map +1 -1
  6. package/dist/services/codex-pre-tool-hook-template.d.ts.map +1 -1
  7. package/dist/services/codex-pre-tool-hook-template.js +89 -7
  8. package/dist/services/codex-pre-tool-hook-template.js.map +1 -1
  9. package/dist/services/codex-rules.d.ts +1 -1
  10. package/dist/services/codex-rules.d.ts.map +1 -1
  11. package/dist/services/codex-rules.js +7 -0
  12. package/dist/services/codex-rules.js.map +1 -1
  13. package/dist/services/install-agents-template.d.ts.map +1 -1
  14. package/dist/services/install-agents-template.js +1 -0
  15. package/dist/services/install-agents-template.js.map +1 -1
  16. package/dist/services/runtime-template.test.js +31 -7
  17. package/dist/services/runtime-template.test.js.map +1 -1
  18. package/dist/services/template-manifest.d.ts.map +1 -1
  19. package/dist/services/template-manifest.js +7 -3
  20. package/dist/services/template-manifest.js.map +1 -1
  21. package/package.json +1 -1
  22. package/templates/.agents/config/agents/catalog.yaml +7 -7
  23. package/templates/.agents/config/clients/codex/agents/zaip-agent-backend.toml +2 -2
  24. package/templates/.agents/config/clients/codex/agents/zaip-agent-designer.toml +2 -2
  25. package/templates/.agents/config/clients/codex/agents/zaip-agent-frontend.toml +8 -8
  26. package/templates/.agents/dashboard/.zaip-managed.json +373 -205
  27. package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-DxR_pgSV.js → CostCalculationGuidePage-ovxurkIk.js} +1 -1
  28. package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-4jZLTWE_.js → DashboardHelpDialog-BXy6nti1.js} +268 -86
  29. package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-CKcsqb-r.js → PricingSettingsDialog-vSvvOHQp.js} +1 -1
  30. package/templates/.agents/dashboard/apps/frontend/dist/assets/{ProjectSettingsPage-DmmJD2Th.js → ProjectSettingsPage-zH758vfs.js} +1 -1
  31. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-CTH2wDs5.js +1 -0
  32. package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-CaKwQP43.css → TraceabilityWorkspace-DvvavDLY.css} +1 -1
  33. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-DKwP1stV.js +68 -0
  34. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-PoJA2PI1.css +1 -0
  35. package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-C0fj2uU9.js → icons-vendor-B_lDDHn1.js} +1 -1
  36. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-B31GMG5O.css +1 -0
  37. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-CuMcoUni.js +2 -0
  38. package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-BEsJ-FYH.js → react-vendor-B3TJrD4O.js} +1 -1
  39. package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-B6y6Gw12.js → traceability-7f1j5wx3.js} +1 -1
  40. package/templates/.agents/dashboard/apps/frontend/dist/index.html +7 -7
  41. package/templates/.agents/dashboard/apps/frontend/playwright.dom.config.ts +32 -0
  42. package/templates/.agents/dashboard/apps/frontend/src/App.tsx +132 -245
  43. package/templates/.agents/dashboard/apps/frontend/src/AppOverlays.tsx +0 -21
  44. package/templates/.agents/dashboard/apps/frontend/src/DashboardAlternateContent.tsx +9 -0
  45. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.dom.e2e.ts +56 -0
  46. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.test.ts +18 -1
  47. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.tsx +75 -8
  48. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +25 -1
  49. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +7 -9
  50. package/templates/.agents/dashboard/apps/frontend/src/operations-period-render.test.ts +4 -4
  51. package/templates/.agents/dashboard/apps/frontend/src/overview-status-page.test.ts +1 -1
  52. package/templates/.agents/dashboard/apps/frontend/src/snapshot-banner-semantics.test.ts +7 -0
  53. package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +20 -8
  54. package/templates/.agents/dashboard/apps/frontend/src/sqlite-page-export.test.ts +32 -0
  55. package/templates/.agents/dashboard/apps/frontend/src/sqlite-page-export.ts +21 -0
  56. package/templates/.agents/dashboard/apps/frontend/src/styles.css +19 -0
  57. package/templates/.agents/dashboard/apps/frontend/src/traceability-task-pagination.test.ts +32 -0
  58. package/templates/.agents/dashboard/apps/frontend/src/traceability-task-pagination.ts +36 -0
  59. package/templates/.agents/dashboard/apps/frontend/src/traceability-workspace.css +6 -2
  60. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.test.ts +48 -0
  61. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.ts +31 -27
  62. package/templates/.agents/dashboard/apps/frontend/src/use-app-trace-documents.ts +7 -1
  63. package/templates/.agents/dashboard/apps/frontend/src/use-app-work-list-page.test.ts +163 -0
  64. package/templates/.agents/dashboard/apps/frontend/src/use-app-work-list-page.ts +136 -0
  65. package/templates/.agents/dashboard/apps/frontend/src/use-operations-detail-export.ts +76 -0
  66. package/templates/.agents/dashboard/apps/frontend/src/work-list-load-dedup.test.ts +23 -0
  67. package/templates/.agents/dashboard/apps/frontend/src/work-list-load-dedup.ts +27 -0
  68. package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.test.ts +38 -14
  69. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionPanel.tsx +60 -0
  70. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionTable.tsx +191 -0
  71. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.loading.test.ts +14 -0
  72. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.run-page.test.ts +18 -0
  73. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.tsx +18 -3
  74. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorContent.tsx +8 -2
  75. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorLoadErrors.tsx +35 -0
  76. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.test.ts +47 -1
  77. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +50 -58
  78. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableLoading.test.ts +132 -0
  79. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableLoading.tsx +70 -0
  80. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +128 -138
  81. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.tsx +17 -67
  82. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-copy.ts +2 -0
  83. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-views.ts +3 -1
  84. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-page-range.ts +35 -0
  85. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-compact-cost-page.ts +16 -4
  86. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.test.ts +37 -2
  87. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.ts +44 -8
  88. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-run-page.ts +6 -1
  89. package/templates/.agents/dashboard/modules/operations/src/contracts.ts +20 -3
  90. package/templates/.agents/dashboard/modules/operations/src/react/DeveloperAttributionPanel.test.ts +54 -0
  91. package/templates/.agents/dashboard/modules/operations/src/react/DeveloperAttributionPanel.tsx +247 -0
  92. package/templates/.agents/dashboard/modules/operations/src/react/OperationsMainContent.tsx +39 -13
  93. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.helpers.tsx +107 -2
  94. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.macro-metrics.test.ts +55 -0
  95. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.test.ts +20 -28
  96. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +162 -165
  97. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverviewTopPanel.tsx +127 -0
  98. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +13 -46
  99. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageOverview.tsx +3 -0
  100. package/templates/.agents/dashboard/modules/operations/src/react/PagedWorkList.test.tsx +43 -0
  101. package/templates/.agents/dashboard/modules/operations/src/react/PagedWorkList.tsx +181 -0
  102. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.test.ts +4 -2
  103. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.tsx +13 -0
  104. package/templates/.agents/dashboard/modules/operations/src/react/developer-identities.test.ts +18 -0
  105. package/templates/.agents/dashboard/modules/operations/src/react/developer-identities.ts +30 -0
  106. package/templates/.agents/dashboard/modules/operations/src/react/execution-metrics.ts +1 -0
  107. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +8 -0
  108. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +3 -0
  109. package/templates/.agents/dashboard/modules/operations/src/react/export/export-layout.test.ts +14 -5
  110. package/templates/.agents/dashboard/modules/operations/src/react/index.ts +1 -0
  111. package/templates/.agents/dashboard/modules/operations/src/react/operations-coverage-toast.test.ts +4 -3
  112. package/templates/.agents/dashboard/modules/operations/src/react/operations-date-filters.css +1 -1
  113. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +21 -11
  114. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview.css +4 -0
  115. package/templates/.agents/dashboard/modules/operations/src/react/operations-page-contract.ts +8 -1
  116. package/templates/.agents/dashboard/modules/operations/src/react/operations-view-order.test.ts +1 -0
  117. package/templates/.agents/dashboard/modules/operations/src/react/period-summary.ts +1 -0
  118. package/templates/.agents/dashboard/modules/operations/src/server/metric-coverage.ts +1 -0
  119. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +527 -335
  120. package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +501 -309
  121. package/templates/.agents/dashboard/packages/local-runtime/gitignore.template +2 -0
  122. package/templates/.agents/dashboard/packages/local-runtime/scripts/rebuild-sqlite-read-model.mjs +3 -1
  123. package/templates/.agents/dashboard/packages/local-runtime/scripts/test-sqlite-read-model.mjs +3 -3
  124. package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-sqlite-read-model.mjs +25 -15
  125. package/templates/.agents/dashboard/packages/local-runtime/server.mjs +527 -335
  126. package/templates/.agents/dashboard/packages/local-runtime/src/server-board.test.ts +34 -0
  127. package/templates/.agents/dashboard/packages/local-runtime/src/server-board.ts +15 -8
  128. package/templates/.agents/dashboard/packages/local-runtime/src/server-classification-page.test.ts +87 -0
  129. package/templates/.agents/dashboard/packages/local-runtime/src/server-period-macro-metric.test.ts +44 -0
  130. package/templates/.agents/dashboard/packages/local-runtime/src/server-period-macro-metric.ts +125 -0
  131. package/templates/.agents/dashboard/packages/local-runtime/src/server-reconciliation-refresh.test.ts +66 -0
  132. package/templates/.agents/dashboard/packages/local-runtime/src/server-request-authority.test.ts +61 -0
  133. package/templates/.agents/dashboard/packages/local-runtime/src/server-request-authority.ts +18 -0
  134. package/templates/.agents/dashboard/packages/local-runtime/src/server-run-projections.test.ts +42 -0
  135. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-refresh.ts +97 -0
  136. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot.test.ts +3 -1
  137. package/templates/.agents/dashboard/packages/local-runtime/src/server-sqlite-task-trace.ts +91 -0
  138. package/templates/.agents/dashboard/packages/local-runtime/src/server.test-fixtures.ts +36 -0
  139. package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +98 -123
  140. package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +111 -135
  141. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-artifact-counts.ts +28 -0
  142. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.test.ts +63 -0
  143. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.ts +109 -0
  144. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-aggregates.ts +497 -0
  145. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-fast-page-parity.test-support.ts +65 -0
  146. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-page.test.ts +176 -0
  147. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-page.ts +119 -0
  148. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-projection.ts +41 -0
  149. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.test.ts +16 -0
  150. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.ts +29 -0
  151. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-cache.ts +355 -0
  152. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-persistence.ts +121 -0
  153. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-timing.ts +27 -0
  154. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-projection.ts +15 -0
  155. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.test.ts +293 -0
  156. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.ts +371 -0
  157. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-cache.test-support.ts +23 -0
  158. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-first-fold-types.ts +89 -0
  159. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider-fixture.ts +227 -0
  160. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider.test.ts +691 -0
  161. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.ts +81 -0
  162. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +440 -863
  163. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +1120 -1086
  164. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-cache.ts +129 -0
  165. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-install.test.ts +26 -0
  166. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-install.ts +28 -0
  167. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-seed.test.ts +116 -0
  168. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.mjs +146 -0
  169. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.test.mjs +165 -0
  170. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-refresh.mjs +140 -0
  171. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +188 -299
  172. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +51 -70
  173. package/templates/.agents/dashboard/packages/windows-launcher/Program.cs +5 -2
  174. package/templates/.agents/dashboard/tests/e2e/playwright.config.ts +4 -1
  175. package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-loading.spec.ts +142 -0
  176. package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-pagination.spec.ts +232 -0
  177. package/templates/.agents/dashboard/tests/e2e/specs/dashboard-performance-matrix.spec.ts +743 -0
  178. package/templates/.agents/dashboard/tests/e2e/specs/dashboard.spec.ts +183 -210
  179. package/templates/.agents/dashboard/zaip-dashboard-windows.exe +0 -0
  180. package/templates/.agents/requirements/autonomous-assurance.md +6 -6
  181. package/templates/.agents/requirements/comparative-audit.md +1 -1
  182. package/templates/.agents/requirements/context-engine.md +1 -1
  183. package/templates/.agents/requirements/cost-observability.md +1 -1
  184. package/templates/.agents/requirements/dashboard-launch.md +1 -1
  185. package/templates/.agents/requirements/data-export.md +1 -1
  186. package/templates/.agents/requirements/design-system.md +1 -1
  187. package/templates/.agents/requirements/execution-engine.md +3 -3
  188. package/templates/.agents/requirements/kanban-dashboard.md +10 -2
  189. package/templates/.agents/requirements/model-orchestration.md +1 -1
  190. package/templates/.agents/requirements/public-distribution.md +1 -1
  191. package/templates/.agents/requirements/software-architecture.md +1 -1
  192. package/templates/.agents/requirements/strategic-improvements.md +1 -1
  193. package/templates/.agents/requirements/work-lifecycle.md +4 -4
  194. package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
  195. package/templates/.agents/rules/dashboard-ui-consistency.md +14 -0
  196. package/templates/.agents/rules/frontend-lite.md +4 -4
  197. package/templates/.agents/rules/run-lifecycle-closure.md +4 -4
  198. package/templates/.agents/runtime/bin/zaip.mjs +1137 -1037
  199. package/templates/.agents/runtime/checksums.sha256 +2 -2
  200. package/templates/.agents/runtime/provenance.json +2 -2
  201. package/templates/.agents/skills/criar-pasta-obsidian/scripts/generate-obsidian-vault.test.mjs +20 -16
  202. package/templates/.agents/skills/zaip-skill-agent-catalog/SKILL.md +22 -0
  203. package/templates/.agents/skills/zaip-skill-agent-catalog/agents/openai.yaml +4 -0
  204. package/templates/.agents/skills/zaip-skill-author-skills/SKILL.md +3 -2
  205. package/templates/.agents/skills/zaip-skill-author-skills/scripts/audit-skill-catalog.mjs +49 -0
  206. package/templates/.agents/skills/zaip-skill-author-skills/scripts/author-skill-scripts.test.mjs +27 -0
  207. package/templates/.agents/skills/zaip-skill-author-skills/scripts/run-skill-tests.mjs +37 -0
  208. package/templates/.agents/skills/zaip-skill-backend/SKILL.md +1 -0
  209. package/templates/.agents/skills/zaip-skill-change/SKILL.md +1 -1
  210. package/templates/.agents/skills/zaip-skill-change/references/observable-evidence.md +83 -0
  211. package/templates/.agents/skills/zaip-skill-dashboard-diagnostics/SKILL.md +22 -0
  212. package/templates/.agents/skills/zaip-skill-dashboard-diagnostics/agents/openai.yaml +4 -0
  213. package/templates/.agents/skills/zaip-skill-execution/SKILL.md +1 -1
  214. package/templates/.agents/skills/zaip-skill-frontend/SKILL.md +4 -3
  215. package/templates/.agents/skills/zaip-skill-frontend/agents/openai.yaml +2 -2
  216. package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +10 -10
  217. package/templates/.agents/skills/zaip-skill-lifecycle-closure/SKILL.md +27 -0
  218. package/templates/.agents/skills/zaip-skill-lifecycle-closure/agents/openai.yaml +4 -0
  219. package/templates/.agents/skills/zaip-skill-prd/SKILL.md +4 -0
  220. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.mjs +72 -22
  221. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-explicit-recovery.mjs +223 -0
  222. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.mjs +42 -1
  223. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.test.mjs +101 -0
  224. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.test.mjs +53 -0
  225. package/templates/.agents/skills/zaip-skill-release-qualification/SKILL.md +20 -0
  226. package/templates/.agents/skills/zaip-skill-release-qualification/agents/openai.yaml +4 -0
  227. package/templates/.agents/skills/zaip-skill-review/SKILL.md +5 -0
  228. package/templates/.agents/skills/zaip-skill-rules/SKILL.md +1 -1
  229. package/templates/.agents/skills/zaip-skill-spec/SKILL.md +4 -0
  230. package/templates/.agents/skills/zaip-skill-sqlite-read-model/SKILL.md +22 -90
  231. package/templates/.agents/zaip-aios/INDEX.md +57 -32
  232. package/templates/.agents/zaip-aios/README.md +22 -12
  233. package/templates/.agents/zaip-aios/guides/02-requirements.md +5 -0
  234. package/templates/.agents/zaip-aios/guides/06-execucao.md +13 -4
  235. package/templates/.agents/zaip-aios/guides/07-revisao-e-validacao.md +7 -0
  236. package/templates/.agents/zaip-aios/guides/10-seguranca.md +23 -0
  237. package/templates/.agents/zaip-aios/guides/11-observabilidade-e-custos.md +6 -6
  238. package/templates/.agents/zaip-aios/guides/13-boas-praticas.md +3 -0
  239. package/templates/.agents/zaip-aios/guides/16-lifecycle-e-reconciliacao.md +12 -3
  240. package/templates/.agents/zaip-aios/guides/17-como-o-custo-e-calculado.md +5 -5
  241. package/templates/.agents/zaip-aios/guides/19-assurance-e-autonomia.md +23 -0
  242. package/templates/.agents/zaip-aios/guides/20-instalacao-detalhada.md +44 -8
  243. package/templates/.agents/zaip-aios/guides/21-telemetria-monitor-custos.md +8 -14
  244. package/templates/.agents/zaip-aios/guides/22-fluxos-e-roteamento.md +5 -0
  245. package/templates/.agents/zaip-aios/guides/23-orquestracao-de-modelos.md +6 -6
  246. package/templates/.agents/zaip-aios/guides/24-calculo-de-custos-openai.md +8 -8
  247. package/templates/.agents/zaip-aios/guides/25-fontes-de-precos-openai.md +3 -2
  248. package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +92 -10
  249. package/templates/.agents/zaip-aios/guides/27-telemetria-git-native.md +8 -3
  250. package/templates/.agents/zaip-aios/guides/28-lifecycle-completo.md +5 -0
  251. package/templates/template-manifest.json +555 -170
  252. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-BwtitWa_.js +0 -1
  253. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-BZ5WdaMN.css +0 -1
  254. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-N5Csr0RP.js +0 -68
  255. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-C4aIB1PV.js +0 -2
  256. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-DK_enB5Z.css +0 -1
  257. package/templates/.agents/dashboard/apps/frontend/src/use-idle-cost-prefetch.ts +0 -45
  258. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs.metafile.json +0 -7333
@@ -32,8 +32,6 @@ type DocumentDetail = {
32
32
  export function AppOverlays({
33
33
  costLocale,
34
34
  documentDetail,
35
- error,
36
- failedArea,
37
35
  helpOpen,
38
36
  loadingArea,
39
37
  operations,
@@ -46,7 +44,6 @@ export function AppOverlays({
46
44
  closeDocument,
47
45
  onCloseHelp,
48
46
  onCloseTrace,
49
- onDismissError,
50
47
  onDismissReconciliation,
51
48
  onOpenDocument,
52
49
  onOpenTrace,
@@ -54,13 +51,10 @@ export function AppOverlays({
54
51
  onOpenTraceMacro,
55
52
  onRefreshCancel,
56
53
  onRefreshFromDialog,
57
- onRetry,
58
54
  setTraceLink,
59
55
  }: {
60
56
  costLocale: CostLocale;
61
57
  documentDetail: DocumentDetail | null;
62
- error: string | null;
63
- failedArea: LoadingArea | null;
64
58
  helpOpen: boolean;
65
59
  loadingArea: LoadingArea | null;
66
60
  operations: OperationsProjection;
@@ -76,7 +70,6 @@ export function AppOverlays({
76
70
  closeDocument: () => void;
77
71
  onCloseHelp: () => void;
78
72
  onCloseTrace: () => void;
79
- onDismissError: () => void;
80
73
  onDismissReconciliation: () => void;
81
74
  onOpenDocument: (kind: "prd" | "spec", id: string) => void;
82
75
  onOpenTrace: (taskId: string) => void;
@@ -84,24 +77,10 @@ export function AppOverlays({
84
77
  onOpenTraceMacro: (label: "PRD" | "SPEC", id: string) => void;
85
78
  onRefreshCancel: () => void;
86
79
  onRefreshFromDialog: (reconcileOpenWork: boolean) => void;
87
- onRetry: () => void;
88
80
  setTraceLink: (value: null) => void;
89
81
  }) {
90
82
  return (
91
83
  <>
92
- {error ? (
93
- <div aria-live="assertive" className="app-warning" role="alert">
94
- <span>{error}</span>
95
- {failedArea ? (
96
- <button onClick={onRetry} type="button">
97
- {costLocale === "pt-BR" ? "Tentar novamente" : "Try again"}
98
- </button>
99
- ) : null}
100
- <button onClick={onDismissError} type="button">
101
- ×
102
- </button>
103
- </div>
104
- ) : null}
105
84
  {showTrace ? null : traceLoadingTaskId ? (
106
85
  <TaskTraceLoadingPanel locale={costLocale} taskId={traceLoadingTaskId} />
107
86
  ) : trace ? (
@@ -35,6 +35,7 @@ type DashboardAlternateContentProps = {
35
35
  onLoadingChange: (loading: boolean) => void;
36
36
  onLocaleChange: (locale: CostLocale) => void;
37
37
  onOpenTrace: (taskId: string) => void;
38
+ onLoadMoreTraceTasks: (loadAll?: boolean) => Promise<unknown>;
38
39
  onRefresh: () => void;
39
40
  onRetry: () => void;
40
41
  onSelectTraceTask: (taskId: string) => void;
@@ -44,6 +45,8 @@ type DashboardAlternateContentProps = {
44
45
  selectedTraceTaskId: string;
45
46
  trace: TaskTrace | null;
46
47
  traceLoadingTaskId: string | null;
48
+ traceTasksHasMore: boolean;
49
+ traceTasksLoading: boolean;
47
50
  traceTasks: OperationsProjection["tasks"];
48
51
  };
49
52
 
@@ -64,6 +67,7 @@ export function renderDashboardAlternateContent({
64
67
  onLoadingChange,
65
68
  onLocaleChange,
66
69
  onOpenTrace,
70
+ onLoadMoreTraceTasks,
67
71
  onRefresh,
68
72
  onRetry,
69
73
  onSelectTraceTask,
@@ -73,6 +77,8 @@ export function renderDashboardAlternateContent({
73
77
  selectedTraceTaskId,
74
78
  trace,
75
79
  traceLoadingTaskId,
80
+ traceTasksHasMore,
81
+ traceTasksLoading,
76
82
  traceTasks,
77
83
  }: DashboardAlternateContentProps) {
78
84
  if (dashboardView === "cost-monitor") {
@@ -118,9 +124,12 @@ export function renderDashboardAlternateContent({
118
124
  onOpenChange={onOpenTraceChange}
119
125
  onOpenPrd={(prdId) => onOpenTraceMacro("PRD", prdId)}
120
126
  onOpenSpec={(specId) => onOpenTraceMacro("SPEC", specId)}
127
+ onLoadMoreTasks={onLoadMoreTraceTasks}
121
128
  onSelectTask={onSelectTraceTask}
122
129
  selectedTaskId={selectedTraceTaskId}
123
130
  tasks={traceTasks.length > 0 ? traceTasks : operations.tasks}
131
+ hasMoreTasks={traceTasksHasMore}
132
+ isLoadingTasks={traceTasksLoading}
124
133
  trace={trace}
125
134
  />
126
135
  </Suspense>
@@ -0,0 +1,56 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ test("opens every task from a preselected traceability combobox and preserves search and keyboard selection", async ({
4
+ page,
5
+ }) => {
6
+ const operations = page.waitForResponse(
7
+ (response) =>
8
+ response.status() === 200 &&
9
+ response.url().includes("/api/v2/operations") &&
10
+ response.url().includes("scope=quick"),
11
+ );
12
+ await page.goto("/?token=e2e-token");
13
+ await operations;
14
+
15
+ const traceabilityButton = page
16
+ .getByRole("navigation", { name: "Áreas do dashboard" })
17
+ .getByRole("button", { name: /Rastreabilidade/ });
18
+ await traceabilityButton.click();
19
+ await expect(traceabilityButton).toHaveAttribute("aria-current", "page");
20
+
21
+ const taskSelector = page.getByRole("combobox", { name: "Buscar task por nome ou ID" });
22
+ const taskOptions = page
23
+ .getByRole("listbox", { name: "Buscar task por nome ou ID" })
24
+ .getByRole("option");
25
+ const taskList = page.getByRole("listbox", { name: "Buscar task por nome ou ID" });
26
+ await expect(taskSelector).toBeVisible();
27
+ await expect(taskSelector).toHaveAttribute("aria-expanded", "false");
28
+
29
+ const selectedTitle = await taskSelector.inputValue();
30
+ await taskSelector.focus();
31
+ await expect(taskSelector).toHaveAttribute("aria-expanded", "true");
32
+ const initialTaskCount = await taskOptions.count();
33
+ expect(initialTaskCount).toBe(12);
34
+ await taskList.evaluate((element) => {
35
+ element.scrollTop = element.scrollHeight;
36
+ element.dispatchEvent(new Event("scroll", { bubbles: true }));
37
+ });
38
+ await expect.poll(() => taskOptions.count()).toBeGreaterThan(initialTaskCount);
39
+
40
+ await taskSelector.fill(selectedTitle);
41
+ await expect(taskOptions).toHaveCount(1);
42
+
43
+ await taskSelector.click();
44
+ await expect(taskOptions).toHaveCount(initialTaskCount);
45
+ const thirdOptionId = await taskOptions.nth(2).getAttribute("id");
46
+ await taskSelector.press("ArrowDown");
47
+ await taskSelector.press("ArrowDown");
48
+ const activeOptionId = await taskSelector.getAttribute("aria-activedescendant");
49
+ expect(activeOptionId).toBe(thirdOptionId);
50
+ const activeOption = page.locator(`[id="${activeOptionId}"]`);
51
+ const activeTitle = await activeOption.locator("strong").innerText();
52
+
53
+ await taskSelector.press("Enter");
54
+ await expect(taskSelector).toHaveAttribute("aria-expanded", "false");
55
+ await expect(taskSelector).toHaveValue(activeTitle);
56
+ });
@@ -1,6 +1,10 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import { describe, expect, it } from "vitest";
3
- import { filterTraceabilityTasks, traceabilityTaskOptionId } from "./TraceabilityWorkspace.js";
3
+ import {
4
+ filterTraceabilityTasks,
5
+ traceabilityTaskOptionId,
6
+ visibleTraceabilityTasks,
7
+ } from "./TraceabilityWorkspace.js";
4
8
 
5
9
  describe("TraceabilityWorkspace task search", () => {
6
10
  const tasks = [
@@ -16,6 +20,15 @@ describe("TraceabilityWorkspace task search", () => {
16
20
  expect(filterTraceabilityTasks(tasks, "missing")).toEqual([]);
17
21
  });
18
22
 
23
+ it("shows every task when the selected combobox is opened", () => {
24
+ expect(
25
+ visibleTraceabilityTasks(tasks, "Preparar lançamento", true).map((task) => task.id),
26
+ ).toEqual(["TASK-ALPHA", "TASK-BETA"]);
27
+ expect(
28
+ visibleTraceabilityTasks(tasks, "Preparar lançamento", false).map((task) => task.id),
29
+ ).toEqual(["TASK-ALPHA"]);
30
+ });
31
+
19
32
  it("keeps selection and keyboard interaction accessible", () => {
20
33
  const source = readFileSync(new URL("TraceabilityWorkspace.tsx", import.meta.url), "utf8");
21
34
 
@@ -26,6 +39,10 @@ describe("TraceabilityWorkspace task search", () => {
26
39
  expect(source).toContain('event.key === "Enter"');
27
40
  expect(source).toContain('event.key === "ArrowDown"');
28
41
  expect(source).toContain("setActiveIndex");
42
+ expect(source).toContain("onClick={() => openAllTasks()}");
43
+ expect(source).toContain("onFocus={() => openAllTasks()}");
44
+ expect(source).toContain("openAllTasks(false)");
45
+ expect(source).toContain("setShowAllTasks(true)");
29
46
  expect(source).toContain("aria-activedescendant");
30
47
  expect(source).toContain("traceabilityTaskOptionId(activeTaskId)");
31
48
  expect(source).toContain('role="status"');
@@ -2,9 +2,11 @@ import type { OperationsProjection } from "@zaip-ai/dashboard-operations/contrac
2
2
  import type { TaskTrace } from "@zaip-ai/dashboard-traceability/contracts";
3
3
  import { TaskTracePanel } from "@zaip-ai/dashboard-traceability/react";
4
4
  import { useEffect, useMemo, useState } from "react";
5
+ import { nextTraceabilityVisibleCount } from "./traceability-task-pagination.js";
5
6
  import "./traceability-workspace.css";
6
7
 
7
8
  type TraceabilityTask = OperationsProjection["tasks"][number];
9
+ export const traceabilityTaskInitialBatchSize = 12;
8
10
 
9
11
  export function filterTraceabilityTasks(
10
12
  tasks: readonly TraceabilityTask[],
@@ -17,6 +19,14 @@ export function filterTraceabilityTasks(
17
19
  );
18
20
  }
19
21
 
22
+ export function visibleTraceabilityTasks(
23
+ tasks: readonly TraceabilityTask[],
24
+ query: string,
25
+ showAllTasks: boolean,
26
+ ): TraceabilityTask[] {
27
+ return showAllTasks ? [...tasks] : filterTraceabilityTasks(tasks, query);
28
+ }
29
+
20
30
  export function traceabilityTaskOptionId(taskId: string): string {
21
31
  return `traceability-task-option-${taskId}`;
22
32
  }
@@ -24,6 +34,9 @@ export function traceabilityTaskOptionId(taskId: string): string {
24
34
  export function TraceabilityWorkspace({
25
35
  locale,
26
36
  loadingTaskId,
37
+ hasMoreTasks,
38
+ isLoadingTasks,
39
+ onLoadMoreTasks,
27
40
  onSelectTask,
28
41
  onOpenChange,
29
42
  onOpenPrd,
@@ -34,6 +47,9 @@ export function TraceabilityWorkspace({
34
47
  }: {
35
48
  locale: "pt-BR" | "en-US";
36
49
  loadingTaskId: string | null;
50
+ hasMoreTasks: boolean;
51
+ isLoadingTasks: boolean;
52
+ onLoadMoreTasks: (loadAll?: boolean) => Promise<unknown>;
37
53
  onSelectTask: (taskId: string) => void;
38
54
  onOpenChange: (changeId: string) => void;
39
55
  onOpenPrd: (prdId: string) => void;
@@ -48,11 +64,15 @@ export function TraceabilityWorkspace({
48
64
  const selectedTask = sortedTasks.find((task) => task.id === selectedTaskId);
49
65
  const [query, setQuery] = useState(() => selectedTask?.title ?? selectedTaskId);
50
66
  const [isListOpen, setIsListOpen] = useState(false);
67
+ const [showAllTasks, setShowAllTasks] = useState(false);
51
68
  const [activeIndex, setActiveIndex] = useState(0);
69
+ const [visibleCount, setVisibleCount] = useState(traceabilityTaskInitialBatchSize);
52
70
  const filteredTasks = useMemo(
53
- () => filterTraceabilityTasks(sortedTasks, query),
54
- [query, sortedTasks],
71
+ () => visibleTraceabilityTasks(sortedTasks, query, showAllTasks),
72
+ [query, showAllTasks, sortedTasks],
55
73
  );
74
+ const visibleTasks = filteredTasks.slice(0, visibleCount);
75
+ const hasMoreVisibleTasks = visibleTasks.length < filteredTasks.length;
56
76
  const searchInputId = "traceability-task-search";
57
77
  const resultsId = "traceability-task-results";
58
78
  const taskLabel = locale === "pt-BR" ? "Task selecionada" : "Selected task";
@@ -68,17 +88,42 @@ export function TraceabilityWorkspace({
68
88
  const selectTask = (task: TraceabilityTask) => {
69
89
  setQuery(task.title);
70
90
  setIsListOpen(false);
91
+ setShowAllTasks(false);
71
92
  onSelectTask(task.id);
72
93
  };
73
94
 
95
+ const openAllTasks = (resetList = true) => {
96
+ setIsListOpen(true);
97
+ setShowAllTasks(true);
98
+ if (resetList) {
99
+ setActiveIndex(0);
100
+ setVisibleCount(traceabilityTaskInitialBatchSize);
101
+ }
102
+ };
103
+
104
+ const loadMoreTasks = (event: React.UIEvent<HTMLDivElement>) => {
105
+ const { clientHeight, scrollHeight, scrollTop } = event.currentTarget;
106
+ if (scrollTop + clientHeight < scrollHeight - 32) return;
107
+ if (hasMoreTasks) void onLoadMoreTasks();
108
+ if (visibleTasks.length < filteredTasks.length) {
109
+ setVisibleCount((current) =>
110
+ nextTraceabilityVisibleCount(
111
+ current,
112
+ filteredTasks.length,
113
+ traceabilityTaskInitialBatchSize,
114
+ ),
115
+ );
116
+ }
117
+ };
118
+
74
119
  const onSearchKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
75
120
  if (event.key === "ArrowDown") {
76
121
  event.preventDefault();
77
- setIsListOpen(true);
78
- setActiveIndex((index) => Math.min(index + 1, Math.max(0, filteredTasks.length - 1)));
122
+ openAllTasks(false);
123
+ setActiveIndex((index) => Math.min(index + 1, Math.max(0, sortedTasks.length - 1)));
79
124
  } else if (event.key === "ArrowUp") {
80
125
  event.preventDefault();
81
- setIsListOpen(true);
126
+ openAllTasks(false);
82
127
  setActiveIndex((index) => Math.max(0, index - 1));
83
128
  } else if (event.key === "Enter" && isListOpen) {
84
129
  const task = filteredTasks[activeIndex];
@@ -107,9 +152,16 @@ export function TraceabilityWorkspace({
107
152
  onChange={(event) => {
108
153
  setQuery(event.target.value);
109
154
  setActiveIndex(0);
155
+ setShowAllTasks(false);
156
+ setVisibleCount(traceabilityTaskInitialBatchSize);
110
157
  setIsListOpen(true);
158
+ // Do not turn a keystroke into a full repository walk. More
159
+ // candidates are acquired only by explicit list scrolling; a
160
+ // server-side search can be wired here when its bounded query
161
+ // contract is available.
111
162
  }}
112
- onFocus={() => setIsListOpen(true)}
163
+ onClick={() => openAllTasks()}
164
+ onFocus={() => openAllTasks()}
113
165
  onKeyDown={onSearchKeyDown}
114
166
  role="combobox"
115
167
  type="search"
@@ -120,10 +172,11 @@ export function TraceabilityWorkspace({
120
172
  aria-label={searchLabel}
121
173
  className="traceability-task-results"
122
174
  id={resultsId}
175
+ onScroll={loadMoreTasks}
123
176
  role="listbox"
124
177
  >
125
178
  {filteredTasks.length > 0 ? (
126
- filteredTasks.map((task, index) => (
179
+ visibleTasks.map((task, index) => (
127
180
  <div key={task.id} role="presentation">
128
181
  <button
129
182
  aria-selected={task.id === selectedTaskId}
@@ -134,7 +187,6 @@ export function TraceabilityWorkspace({
134
187
  type="button"
135
188
  >
136
189
  <strong>{task.title}</strong>
137
- <small>{task.id}</small>
138
190
  </button>
139
191
  </div>
140
192
  ))
@@ -145,6 +197,21 @@ export function TraceabilityWorkspace({
145
197
  )}
146
198
  </div>
147
199
  ) : null}
200
+ {isListOpen && filteredTasks.length > 0 ? (
201
+ <p aria-live="polite" className="traceability-task-pagination-status" role="status">
202
+ {isLoadingTasks
203
+ ? locale === "pt-BR"
204
+ ? "Carregando mais tasks…"
205
+ : "Loading more tasks…"
206
+ : hasMoreVisibleTasks || hasMoreTasks
207
+ ? locale === "pt-BR"
208
+ ? `${visibleTasks.length} de ${filteredTasks.length} tasks exibidas. Role para carregar mais.`
209
+ : `${visibleTasks.length} of ${filteredTasks.length} tasks shown. Scroll to load more.`
210
+ : locale === "pt-BR"
211
+ ? `${filteredTasks.length} tasks exibidas. Fim da lista.`
212
+ : `${filteredTasks.length} tasks shown. End of list.`}
213
+ </p>
214
+ ) : null}
148
215
  </div>
149
216
  <small>
150
217
  {locale === "pt-BR"
@@ -21,7 +21,7 @@ describe("DashboardApiClient reconciliation", () => {
21
21
  vi.stubGlobal("fetch", fetchMock);
22
22
 
23
23
  const pending = new DashboardApiClient("session").reconcileOpenWork();
24
- const rejection = expect(pending).rejects.toThrow("125 segundos");
24
+ const rejection = expect(pending).rejects.toThrow("180 segundos");
25
25
  await vi.advanceTimersByTimeAsync(30_000);
26
26
  expect(fetchMock.mock.calls[0]?.[1].signal?.aborted).toBe(false);
27
27
 
@@ -116,6 +116,30 @@ describe("DashboardApiClient cost monitor", () => {
116
116
  expect(requestPath).not.toContain("run_kind=");
117
117
  });
118
118
 
119
+ it("sends the Work List stage through the canonical status query parameter", async () => {
120
+ vi.stubGlobal("window", globalThis);
121
+ const fetchMock = vi.fn((_path: string) =>
122
+ Promise.resolve(
123
+ new Response(JSON.stringify({ rows: [] }), {
124
+ headers: { "content-type": "application/json" },
125
+ status: 200,
126
+ }),
127
+ ),
128
+ );
129
+ vi.stubGlobal("fetch", fetchMock);
130
+
131
+ await new DashboardApiClient("session").sqliteViewPage("operations_work_list", undefined, {
132
+ limit: 10,
133
+ origin: "standalone",
134
+ status: "executing",
135
+ });
136
+
137
+ const requestPath = String(fetchMock.mock.calls[0]?.[0]);
138
+ expect(requestPath).toContain("status=executing");
139
+ expect(requestPath).toContain("origin=standalone");
140
+ expect(requestPath).not.toContain("stage=executing");
141
+ });
142
+
119
143
  it("adds fresh only to an explicit bootstrap aggregate read", async () => {
120
144
  vi.stubGlobal("window", globalThis);
121
145
  const fetchMock = vi.fn((_path: string | URL | Request) =>
@@ -10,7 +10,6 @@ import type {
10
10
  TaskDetailProjection,
11
11
  } from "@zaip-ai/dashboard-operations/contracts";
12
12
  import type { TaskTrace } from "@zaip-ai/dashboard-traceability/contracts";
13
-
14
13
  export interface ReconciliationBlockedItem {
15
14
  id: string;
16
15
  reason: string | null;
@@ -56,7 +55,6 @@ export interface SqliteViewPage {
56
55
  totals?: Record<string, unknown>;
57
56
  rows: Array<Record<string, unknown>>;
58
57
  }
59
-
60
58
  export type OperationsScope = "quick" | "overview" | "detail";
61
59
  export type WorkBoardStage =
62
60
  | "definition"
@@ -252,6 +250,7 @@ export class DashboardApiClient {
252
250
  origin?: string;
253
251
  workType?: string;
254
252
  priority?: string;
253
+ kind?: string;
255
254
  } = {},
256
255
  signal?: AbortSignal,
257
256
  ): Promise<SqliteViewPage> {
@@ -267,6 +266,7 @@ export class DashboardApiClient {
267
266
  if (options.origin) query.set("origin", options.origin);
268
267
  if (options.workType) query.set("workType", options.workType);
269
268
  if (options.priority) query.set("priority", options.priority);
269
+ if (options.kind) query.set("kind", options.kind);
270
270
  return this.get(withPeriod(`/api/v2/sqlite-views?${query.toString()}`, period), signal);
271
271
  }
272
272
 
@@ -455,11 +455,9 @@ export class DashboardApiClient {
455
455
  spec(specId: string): Promise<SpecDetailProjection> {
456
456
  return this.get(dashboardApiPaths.spec(specId));
457
457
  }
458
-
459
- taskTrace(taskId: string): Promise<TaskTrace> {
460
- return this.get(dashboardApiPaths.taskTrace(taskId));
458
+ taskTrace(taskId: string, signal?: AbortSignal): Promise<TaskTrace> {
459
+ return this.get(dashboardApiPaths.taskTrace(taskId), signal);
461
460
  }
462
-
463
461
  pricing(): Promise<PricingCatalog> {
464
462
  return this.get("/api/v2/pricing");
465
463
  }
@@ -593,9 +591,9 @@ function operationsPageParams(
593
591
  }
594
592
 
595
593
  export const dashboardRequestTimeoutMs = 60_000;
596
- // The local runtime permits reconciliation for up to two minutes. Keep a small
597
- // transport margin so the browser never cancels a valid server-side operation.
598
- export const reconciliationRequestTimeoutMs = 125_000;
594
+ // The command may use two minutes plus a projection rebuild; keep enough
595
+ // transport margin to avoid false browser failures after healthy reconciliation.
596
+ export const reconciliationRequestTimeoutMs = 180_000;
599
597
 
600
598
  export async function fetchWithTimeout(
601
599
  path: string,
@@ -94,12 +94,12 @@ describe("App-owned Operations period render", () => {
94
94
  expect(css).toContain("prefers-reduced-motion: reduce");
95
95
  });
96
96
 
97
- it("uses the same global loading gate for snapshot, page, and board requests", () => {
97
+ it("reserves the global gate for a period replacement, not secondary pages", () => {
98
98
  const app = readFileSync(new URL("./App.tsx", import.meta.url), "utf8");
99
99
  expect(app).toContain("const globalLoadingPending =");
100
- expect(app).toContain("loadingArea !== null");
101
- expect(app).toContain("entityPage.loading");
102
- expect(app).toContain("Object.values(boardStates).some((state) => state.loading)");
100
+ expect(app).toContain("periodTransitionPending ||");
101
+ expect(app).not.toContain("entityPage.loading ||");
102
+ expect(app).not.toContain("Object.values(boardStates).some((state) => state.loading)");
103
103
  expect(app).toContain("<PeriodTransitionShell pending={globalLoadingPending}>");
104
104
  });
105
105
  });
@@ -6,7 +6,7 @@ const source = readFileSync(new URL("./App.tsx", import.meta.url), "utf8");
6
6
  describe("overview status page loading", () => {
7
7
  it("requests a dedicated stage and kind page instead of reusing the mixed board page", () => {
8
8
  expect(source).toContain("const loadOverviewStatusPage");
9
- expect(source).toContain("api.operationsBoard(period, stage, offset, { kind })");
9
+ expect(source).toContain('kind: kind === "task" ? "all-tasks" : kind');
10
10
  expect(source).toContain(
11
11
  'kind === "task" ? page.tasks : kind === "spec" ? page.specs : page.prds',
12
12
  );
@@ -44,6 +44,7 @@ describe("snapshot update banner semantics", () => {
44
44
  it("presents a stale local snapshot as neutral status and reserves alert red for errors", () => {
45
45
  const app = readFileSync(new URL("./App.tsx", import.meta.url), "utf8");
46
46
  const boundary = readFileSync(new URL("./AppLoadingBoundary.tsx", import.meta.url), "utf8");
47
+ const overlays = readFileSync(new URL("./AppOverlays.tsx", import.meta.url), "utf8");
47
48
  const styles = readFileSync(new URL("./styles.css", import.meta.url), "utf8");
48
49
  const snapshot = app.slice(
49
50
  app.indexOf("const initialDataPending"),
@@ -70,7 +71,13 @@ describe("snapshot update banner semantics", () => {
70
71
  expect(error).toContain('aria-live="assertive"');
71
72
  expect(error).toContain('"Fechar erro"');
72
73
  expect(error).toContain('"Dismiss error"');
74
+ expect(overlays).not.toContain('role="alert"');
75
+ expect(overlays).not.toContain('className="app-warning"');
76
+ expect(overlays).not.toContain("startupReconciliation");
77
+ expect(overlays).not.toContain('"Fechar aviso de reconciliação"');
78
+ expect(overlays).not.toContain('"Dismiss reconciliation notice"');
73
79
  expect(styles).toContain(".app-snapshot-status {");
80
+ expect(styles).toContain(".app-refresh-status-close {");
74
81
  expect(styles).toContain("background: rgba(8, 47, 73, 0.96);");
75
82
  expect(styles).toContain(".app-warning.app-error {");
76
83
  expect(styles).toContain("background: rgba(69, 16, 16, 0.96);");
@@ -48,15 +48,18 @@ describe("atomic Cost snapshot loading", () => {
48
48
  expect(costSelection).not.toContain("loadOperationsDetails");
49
49
  });
50
50
 
51
- it("opens the global overlay while the Cost page loads a selected group", () => {
51
+ it("never blocks the dashboard or starts a full snapshot for a paged Cost request", () => {
52
52
  const app = readFileSync(new URL("./App.tsx", import.meta.url), "utf8");
53
53
  const globalGate = app.slice(
54
54
  app.indexOf("const globalLoadingPending"),
55
55
  app.indexOf("const renderedOperations"),
56
56
  );
57
- expect(app).toContain("const [costSurfaceLoading, setCostSurfaceLoading] = useState(false);");
58
- expect(globalGate).toContain("costSurfaceLoading");
59
- expect(globalGate).toContain('loadingArea !== "costs"');
57
+ expect(app).toContain("const [, setCostSurfaceLoading] = useState(false);");
58
+ expect(globalGate).not.toContain("costSurfaceLoading");
59
+ expect(globalGate).not.toContain("operationsSurfaceLoading");
60
+ expect(globalGate).not.toContain("entityPage.loading");
61
+ expect(app).not.toContain("api.snapshot(currency, period)");
62
+ expect(app).not.toContain("useIdleCostPrefetch");
60
63
  });
61
64
 
62
65
  it("does not request Cost Monitor while the initial route is Operations", () => {
@@ -132,6 +135,12 @@ describe("atomic Cost snapshot loading", () => {
132
135
  expect(effects).toContain("void refresh(false, false, true)");
133
136
  });
134
137
 
138
+ it("does not reconcile open work automatically", () => {
139
+ const app = readFileSync(new URL("./App.tsx", import.meta.url), "utf8");
140
+ expect(app).not.toContain("startupReconciliation");
141
+ expect(app).toContain("await refresh(false, reconcileOpenWork, !reconcileOpenWork)");
142
+ });
143
+
135
144
  it("removes the global Cost detail request and keeps stale request guards", () => {
136
145
  const app = readFileSync(new URL("./App.tsx", import.meta.url), "utf8");
137
146
  const costPage = readFileSync(
@@ -231,13 +240,16 @@ describe("atomic Cost snapshot loading", () => {
231
240
  app.indexOf("const loadCostDetails"),
232
241
  );
233
242
 
234
- expect(boardHydration).toContain("for (const stage of initialWorkBoardStages)");
235
- expect(boardHydration).toContain("window.requestIdleCallback(hydrateBoard)");
236
- expect(boardHydration).toContain("window.setTimeout(hydrateBoard, 0)");
243
+ expect(boardHydration).toContain("offset += 3");
244
+ expect(boardHydration).toContain(
245
+ "await Promise.all(batch.map((stage) => loadMoreBoard(stage)))",
246
+ );
247
+ expect(boardHydration).toContain("window.requestIdleCallback(() => void hydrateBoard())");
248
+ expect(boardHydration).toContain("window.setTimeout(() => void hydrateBoard(), 0)");
237
249
  expect(boardHydration).toContain("!boardInitialPageRef.current.has(stage)");
238
250
  expect(boardHydration).toContain("boardInitialPageRef.current.add(stage)");
239
251
  expect(boardHydration).toContain("!boardInFlightRef.current.has(stage)");
240
- expect(boardHydration).toContain("void loadMoreBoard(stage)");
252
+ expect(boardHydration).toContain("boardInitialPageRef.current.add(stage)");
241
253
  });
242
254
 
243
255
  it("merges concurrent board pages without replacing rows from another stage", () => {
@@ -0,0 +1,32 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { allSqliteExportPages } from "./sqlite-page-export.js";
3
+
4
+ describe("complete SQLite export", () => {
5
+ it("exports every filtered page, even when the visual page contains only ten rows", async () => {
6
+ const second = vi.fn().mockResolvedValue({
7
+ offset: 100,
8
+ total_count: 145,
9
+ has_more: false,
10
+ rows: Array.from({ length: 45 }, (_, id) => ({ id: `standalone-${id}` })),
11
+ });
12
+ const first = {
13
+ offset: 0,
14
+ total_count: 145,
15
+ has_more: true,
16
+ rows: Array.from({ length: 100 }, (_, id) => ({ id: `standalone-${id}` })),
17
+ };
18
+ const pages = [] as Array<readonly { id: string }[]>;
19
+ for await (const page of allSqliteExportPages(first, second)) pages.push(page);
20
+
21
+ expect(pages.flat()).toHaveLength(145);
22
+ expect(second).toHaveBeenCalledWith(100);
23
+ });
24
+
25
+ it("keeps the active PRD or standalone-task kind in the export source", async () => {
26
+ const source = await import("node:fs/promises").then(({ readFile }) =>
27
+ readFile(new URL("./use-operations-detail-export.ts", import.meta.url), "utf8"),
28
+ );
29
+ expect(source).toContain('source === "operations_work_list" && filters.kind');
30
+ expect(source).toContain("limit: 100");
31
+ });
32
+ });
@@ -0,0 +1,21 @@
1
+ export type SqliteExportPage<Row extends Record<string, unknown>> = {
2
+ offset: number;
3
+ total_count: number;
4
+ has_more: boolean;
5
+ rows: readonly Row[];
6
+ };
7
+
8
+ /** Export transport deliberately follows every server page, unlike the UI. */
9
+ export async function* allSqliteExportPages<Row extends Record<string, unknown>>(
10
+ firstPage: SqliteExportPage<Row>,
11
+ loadPage: (offset: number) => Promise<SqliteExportPage<Row>>,
12
+ ): AsyncGenerator<readonly Row[]> {
13
+ let page = firstPage;
14
+ while (true) {
15
+ if (page.rows.length === 0) return;
16
+ yield page.rows;
17
+ const nextOffset = page.offset + page.rows.length;
18
+ if (!page.has_more || nextOffset >= page.total_count) return;
19
+ page = await loadPage(nextOffset);
20
+ }
21
+ }
@@ -438,6 +438,25 @@ select:focus-visible {
438
438
  font-size: 0.78rem;
439
439
  }
440
440
 
441
+ .app-refresh-status-close {
442
+ flex: 0 0 auto;
443
+ align-self: flex-start;
444
+ border: 0;
445
+ border-radius: 6px;
446
+ padding: 0 5px;
447
+ color: #cbd5e1;
448
+ background: transparent;
449
+ cursor: pointer;
450
+ font-size: 1.25rem;
451
+ line-height: 1;
452
+ }
453
+
454
+ .app-refresh-status-close:hover,
455
+ .app-refresh-status-close:focus-visible {
456
+ color: #f8fafc;
457
+ background: rgba(148, 163, 184, 0.16);
458
+ }
459
+
441
460
  .app-reconciliation-result {
442
461
  position: fixed;
443
462
  z-index: 80;