@zaip-ai/cli 1.0.8 → 1.3.1

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 (360) hide show
  1. package/README.md +1 -1
  2. package/dist/services/adapters.d.ts +1 -1
  3. package/dist/services/adapters.js +1 -1
  4. package/dist/services/agent-adapters.js +3 -3
  5. package/dist/services/agent-adapters.js.map +1 -1
  6. package/dist/services/agent-adapters.test.js +7 -1
  7. package/dist/services/agent-adapters.test.js.map +1 -1
  8. package/dist/services/codex-pre-tool-hook-template.d.ts.map +1 -1
  9. package/dist/services/codex-pre-tool-hook-template.js +89 -7
  10. package/dist/services/codex-pre-tool-hook-template.js.map +1 -1
  11. package/dist/services/codex-rules.d.ts +1 -1
  12. package/dist/services/codex-rules.d.ts.map +1 -1
  13. package/dist/services/codex-rules.js +7 -0
  14. package/dist/services/codex-rules.js.map +1 -1
  15. package/dist/services/install-agents-template.d.ts.map +1 -1
  16. package/dist/services/install-agents-template.js +1 -0
  17. package/dist/services/install-agents-template.js.map +1 -1
  18. package/dist/services/logger.test.js +2 -2
  19. package/dist/services/runtime-template.test.js +31 -7
  20. package/dist/services/runtime-template.test.js.map +1 -1
  21. package/dist/services/template-manifest.d.ts.map +1 -1
  22. package/dist/services/template-manifest.js +12 -3
  23. package/dist/services/template-manifest.js.map +1 -1
  24. package/package.json +1 -1
  25. package/templates/.agents/architecture/software-architecture.md +131 -0
  26. package/templates/.agents/branding/brandbook.docx +0 -0
  27. package/templates/.agents/branding/brandbook.md +60 -0
  28. package/templates/.agents/config/agents/catalog.yaml +7 -7
  29. package/templates/.agents/config/clients/codex/agents/zaip-agent-backend.toml +2 -2
  30. package/templates/.agents/config/clients/codex/agents/zaip-agent-designer.toml +2 -2
  31. package/templates/.agents/config/clients/codex/agents/zaip-agent-finalizer.toml +1 -1
  32. package/templates/.agents/config/clients/codex/agents/zaip-agent-frontend.toml +8 -8
  33. package/templates/.agents/config/clients/codex/agents/zaip-agent-orchestrator.toml +1 -1
  34. package/templates/.agents/dashboard/.tmp-run-list.json +254 -0
  35. package/templates/.agents/dashboard/.zaip-managed.json +457 -173
  36. package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-Z60df2r-.js → CostCalculationGuidePage-ovxurkIk.js} +1 -1
  37. package/templates/.agents/dashboard/apps/frontend/dist/assets/DashboardHelpDialog-BgVgrfhQ.js +2310 -0
  38. package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-Coc6pA-1.js → PricingSettingsDialog-vSvvOHQp.js} +1 -1
  39. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-BomxqCBU.css +1 -0
  40. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-zH758vfs.js +3 -0
  41. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-DLn-Mz2M.js +1 -0
  42. package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-CaKwQP43.css → TraceabilityWorkspace-DvvavDLY.css} +1 -1
  43. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-DKwP1stV.js +68 -0
  44. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-PoJA2PI1.css +1 -0
  45. package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-DFBuc_qp.js → icons-vendor-B_lDDHn1.js} +1 -1
  46. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-B31GMG5O.css +1 -0
  47. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-CZQlsLV9.js +2 -0
  48. package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-CCQOHdVI.js → react-vendor-B3TJrD4O.js} +1 -1
  49. package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-pC2_0J8x.js → traceability-7f1j5wx3.js} +1 -1
  50. package/templates/.agents/dashboard/apps/frontend/dist/index.html +7 -7
  51. package/templates/.agents/dashboard/apps/frontend/package.json +1 -1
  52. package/templates/.agents/dashboard/apps/frontend/playwright.dom.config.ts +32 -0
  53. package/templates/.agents/dashboard/apps/frontend/src/App.tsx +199 -140
  54. package/templates/.agents/dashboard/apps/frontend/src/AppOverlays.tsx +0 -21
  55. package/templates/.agents/dashboard/apps/frontend/src/DashboardAlternateContent.tsx +20 -11
  56. package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsPage.tsx +14 -7
  57. package/templates/.agents/dashboard/apps/frontend/src/ProjectStackEditor.tsx +4 -2
  58. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.dom.e2e.ts +56 -0
  59. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.test.ts +21 -2
  60. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.tsx +89 -19
  61. package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +19 -4
  62. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +49 -3
  63. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +29 -10
  64. package/templates/.agents/dashboard/apps/frontend/src/operations-period-render.test.ts +4 -4
  65. package/templates/.agents/dashboard/apps/frontend/src/overview-status-page.test.ts +4 -2
  66. package/templates/.agents/dashboard/apps/frontend/src/project-settings-page.css +36 -26
  67. package/templates/.agents/dashboard/apps/frontend/src/project-settings.test.ts +2 -2
  68. package/templates/.agents/dashboard/apps/frontend/src/snapshot-banner-semantics.test.ts +47 -6
  69. package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +59 -9
  70. package/templates/.agents/dashboard/apps/frontend/src/sqlite-page-export.test.ts +32 -0
  71. package/templates/.agents/dashboard/apps/frontend/src/sqlite-page-export.ts +21 -0
  72. package/templates/.agents/dashboard/apps/frontend/src/styles.css +19 -0
  73. package/templates/.agents/dashboard/apps/frontend/src/traceability-task-pagination.test.ts +32 -0
  74. package/templates/.agents/dashboard/apps/frontend/src/traceability-task-pagination.ts +36 -0
  75. package/templates/.agents/dashboard/apps/frontend/src/traceability-workspace.css +6 -2
  76. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.test.ts +137 -23
  77. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.ts +229 -35
  78. package/templates/.agents/dashboard/apps/frontend/src/use-app-effects.ts +61 -7
  79. package/templates/.agents/dashboard/apps/frontend/src/use-app-operations-pages.ts +3 -6
  80. package/templates/.agents/dashboard/apps/frontend/src/use-app-trace-documents.ts +7 -1
  81. package/templates/.agents/dashboard/apps/frontend/src/use-app-work-list-page.test.ts +163 -0
  82. package/templates/.agents/dashboard/apps/frontend/src/use-app-work-list-page.ts +136 -0
  83. package/templates/.agents/dashboard/apps/frontend/src/use-operations-detail-export.ts +76 -0
  84. package/templates/.agents/dashboard/apps/frontend/src/work-list-load-dedup.test.ts +23 -0
  85. package/templates/.agents/dashboard/apps/frontend/src/work-list-load-dedup.ts +27 -0
  86. package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.test.ts +39 -15
  87. package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.ts +3 -4
  88. package/templates/.agents/dashboard/apps/frontend/vite.config.ts +4 -1
  89. package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
  90. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.test.ts +89 -19
  91. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.tsx +31 -16
  92. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostCharts.test.ts +43 -14
  93. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostCharts.tsx +5 -5
  94. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionPanel.tsx +60 -0
  95. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionTable.tsx +191 -0
  96. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.loading.test.ts +14 -0
  97. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.run-page.test.ts +18 -0
  98. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.tsx +18 -3
  99. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostModelsAuditTable.tsx +1 -1
  100. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorContent.tsx +75 -44
  101. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorLoadErrors.tsx +35 -0
  102. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.test.ts +162 -40
  103. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +221 -79
  104. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableLoading.test.ts +132 -0
  105. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableLoading.tsx +70 -0
  106. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +203 -155
  107. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.tsx +164 -125
  108. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-copy.ts +2 -0
  109. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-views.ts +3 -1
  110. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor.css +5 -2
  111. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-page-range.ts +35 -0
  112. package/templates/.agents/dashboard/modules/cost-monitor/src/react/index.ts +2 -2
  113. package/templates/.agents/dashboard/modules/cost-monitor/src/react/period-cost-groups.ts +2 -1
  114. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-compact-cost-page.ts +32 -9
  115. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.test.ts +37 -2
  116. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.ts +131 -9
  117. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-run-page.ts +34 -17
  118. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.test.ts +0 -24
  119. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.test.ts +225 -424
  120. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.ts +24 -15
  121. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-terminal-day.test.ts +6 -1
  122. package/templates/.agents/dashboard/modules/cost-monitor/src/server/source-size-cost-server/build-cost-monitor-projection-agents.test.ts +31 -0
  123. package/templates/.agents/dashboard/modules/cost-monitor/src/server/source-size-cost-server/build-cost-summary-projection-duration.test.ts +414 -0
  124. package/templates/.agents/dashboard/modules/operations/package.json +1 -1
  125. package/templates/.agents/dashboard/modules/operations/src/contracts.ts +46 -26
  126. package/templates/.agents/dashboard/modules/operations/src/react/DeveloperAttributionPanel.test.ts +54 -0
  127. package/templates/.agents/dashboard/modules/operations/src/react/DeveloperAttributionPanel.tsx +247 -0
  128. package/templates/.agents/dashboard/modules/operations/src/react/EntityTables.tsx +31 -11
  129. package/templates/.agents/dashboard/modules/operations/src/react/OperationsMainContent.tsx +39 -13
  130. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.helpers.tsx +107 -2
  131. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.macro-metrics.test.ts +55 -0
  132. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.test.ts +23 -29
  133. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +211 -184
  134. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverviewTopPanel.tsx +127 -0
  135. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +60 -51
  136. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageNavigation.tsx +1 -4
  137. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageOverview.tsx +3 -0
  138. package/templates/.agents/dashboard/modules/operations/src/react/PagedWorkList.test.tsx +43 -0
  139. package/templates/.agents/dashboard/modules/operations/src/react/PagedWorkList.tsx +181 -0
  140. package/templates/.agents/dashboard/modules/operations/src/react/PeriodSummaryTable.tsx +32 -10
  141. package/templates/.agents/dashboard/modules/operations/src/react/TaskDetailsDialog.tsx +9 -3
  142. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkBoard.tsx +13 -5
  143. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.test.ts +16 -6
  144. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.tsx +14 -4
  145. package/templates/.agents/dashboard/modules/operations/src/react/conversation-rows.ts +1 -2
  146. package/templates/.agents/dashboard/modules/operations/src/react/developer-identities.test.ts +18 -0
  147. package/templates/.agents/dashboard/modules/operations/src/react/developer-identities.ts +30 -0
  148. package/templates/.agents/dashboard/modules/operations/src/react/execution-metrics.ts +1 -0
  149. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +393 -4
  150. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +484 -61
  151. package/templates/.agents/dashboard/modules/operations/src/react/export/export-layout.test.ts +23 -1
  152. package/templates/.agents/dashboard/modules/operations/src/react/export/xlsx-runtime-e2e.test.ts +248 -0
  153. package/templates/.agents/dashboard/modules/operations/src/react/index.ts +1 -0
  154. package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.test.ts +4 -4
  155. package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.ts +6 -4
  156. package/templates/.agents/dashboard/modules/operations/src/react/operations-coverage-toast.test.ts +4 -3
  157. package/templates/.agents/dashboard/modules/operations/src/react/operations-date-filters.css +1 -1
  158. package/templates/.agents/dashboard/modules/operations/src/react/operations-global-filters.test.ts +4 -1
  159. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +22 -12
  160. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview.css +4 -0
  161. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview.status-cards.test.ts +1 -1
  162. package/templates/.agents/dashboard/modules/operations/src/react/operations-page-contract.ts +53 -6
  163. package/templates/.agents/dashboard/modules/operations/src/react/operations-view-order.test.ts +2 -4
  164. package/templates/.agents/dashboard/modules/operations/src/react/period-summary.test.ts +82 -6
  165. package/templates/.agents/dashboard/modules/operations/src/react/period-summary.ts +1 -0
  166. package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.test.ts +2 -1
  167. package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.ts +1 -1
  168. package/templates/.agents/dashboard/modules/operations/src/server/execution-relationship-counts.test.ts +19 -7
  169. package/templates/.agents/dashboard/modules/operations/src/server/execution-relationship-counts.ts +4 -1
  170. package/templates/.agents/dashboard/modules/operations/src/server/metric-coverage.ts +1 -0
  171. package/templates/.agents/dashboard/modules/operations/src/server/quick-daily-operations-projection.ts +11 -5
  172. package/templates/.agents/dashboard/modules/traceability/package.json +1 -1
  173. package/templates/.agents/dashboard/packages/branding/package.json +1 -1
  174. package/templates/.agents/dashboard/packages/branding/src/index.ts +1 -1
  175. package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
  176. package/templates/.agents/dashboard/packages/contracts/src/index.ts +1 -0
  177. package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
  178. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +533 -338
  179. package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +506 -311
  180. package/templates/.agents/dashboard/packages/local-runtime/gitignore.template +2 -0
  181. package/templates/.agents/dashboard/packages/local-runtime/package.json +1 -1
  182. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-dashboard.mjs +15 -7
  183. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-runtime.mjs +44 -13
  184. package/templates/.agents/dashboard/packages/local-runtime/scripts/rebuild-sqlite-read-model.mjs +8 -3
  185. package/templates/.agents/dashboard/packages/local-runtime/scripts/source-size-runtime-scripts/sqlite-read-model-fixture.mjs +397 -0
  186. package/templates/.agents/dashboard/packages/local-runtime/scripts/test-sqlite-read-model.mjs +472 -145
  187. package/templates/.agents/dashboard/packages/local-runtime/scripts/test-unix-launchers.mjs +15 -3
  188. package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-sqlite-read-model.mjs +141 -33
  189. package/templates/.agents/dashboard/packages/local-runtime/server.mjs +533 -338
  190. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.test.ts +6 -2
  191. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.ts +3 -3
  192. package/templates/.agents/dashboard/packages/local-runtime/src/server-board.test.ts +89 -16
  193. package/templates/.agents/dashboard/packages/local-runtime/src/server-board.ts +33 -16
  194. package/templates/.agents/dashboard/packages/local-runtime/src/server-classification-page.test.ts +87 -0
  195. package/templates/.agents/dashboard/packages/local-runtime/src/server-period-macro-metric.test.ts +44 -0
  196. package/templates/.agents/dashboard/packages/local-runtime/src/server-period-macro-metric.ts +125 -0
  197. package/templates/.agents/dashboard/packages/local-runtime/src/server-reconciliation-refresh.test.ts +66 -0
  198. package/templates/.agents/dashboard/packages/local-runtime/src/server-request-authority.test.ts +61 -0
  199. package/templates/.agents/dashboard/packages/local-runtime/src/server-request-authority.ts +18 -0
  200. package/templates/.agents/dashboard/packages/local-runtime/src/server-run-projections.test.ts +42 -0
  201. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-refresh.ts +97 -0
  202. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot.test.ts +22 -5
  203. package/templates/.agents/dashboard/packages/local-runtime/src/server-sqlite-task-trace.ts +91 -0
  204. package/templates/.agents/dashboard/packages/local-runtime/src/server-workspace.ts +7 -3
  205. package/templates/.agents/dashboard/packages/local-runtime/src/server.test-fixtures.ts +36 -0
  206. package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +230 -132
  207. package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +224 -182
  208. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-artifact-counts.ts +28 -0
  209. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.test.ts +63 -0
  210. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.ts +109 -0
  211. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-aggregates.ts +497 -0
  212. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-fast-page-parity.test-support.ts +65 -0
  213. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-page.test.ts +176 -0
  214. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-page.ts +119 -0
  215. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-projection.ts +41 -0
  216. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.test.ts +16 -0
  217. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.ts +29 -0
  218. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-cache.ts +355 -0
  219. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-persistence.ts +121 -0
  220. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-timing.ts +27 -0
  221. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-metric-contract.ts +16 -2
  222. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-projection.ts +15 -0
  223. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.test.ts +223 -0
  224. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.ts +304 -0
  225. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-cache.test-support.ts +23 -0
  226. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-first-fold-types.ts +89 -0
  227. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider-fixture.ts +227 -0
  228. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider.test.ts +691 -0
  229. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.ts +81 -0
  230. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +1655 -567
  231. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +2168 -1268
  232. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-cache.ts +129 -0
  233. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-install.test.ts +26 -0
  234. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-install.ts +28 -0
  235. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-seed.test.ts +116 -0
  236. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.mjs +146 -0
  237. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.test.mjs +165 -0
  238. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-refresh.mjs +140 -0
  239. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +255 -289
  240. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +94 -88
  241. package/templates/.agents/dashboard/packages/ui/package.json +1 -1
  242. package/templates/.agents/dashboard/packages/windows-launcher/Program.cs +5 -2
  243. package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
  244. package/templates/.agents/dashboard/tests/e2e/playwright.config.ts +4 -1
  245. package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-loading.spec.ts +142 -0
  246. package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-pagination.spec.ts +232 -0
  247. package/templates/.agents/dashboard/tests/e2e/specs/dashboard-performance-matrix.spec.ts +743 -0
  248. package/templates/.agents/dashboard/tests/e2e/specs/dashboard.spec.ts +189 -214
  249. package/templates/.agents/dashboard/zaip-dashboard-windows.exe +0 -0
  250. package/templates/.agents/design/.zaip-managed.json +3 -3
  251. package/templates/.agents/design/apps/catalog/package.json +1 -1
  252. package/templates/.agents/design/packages/local-runtime/package.json +1 -1
  253. package/templates/.agents/growth/estrategia-bootstrap-90-dias.md +169 -0
  254. package/templates/.agents/growth/strategy.md +27 -0
  255. package/templates/.agents/marketing/estrategia-marketing-zaip-90-dias.md +197 -0
  256. package/templates/.agents/marketing/strategy.md +29 -0
  257. package/templates/.agents/requirements/autonomous-assurance.md +6 -6
  258. package/templates/.agents/requirements/comparative-audit.md +1 -1
  259. package/templates/.agents/requirements/context-engine.md +1 -1
  260. package/templates/.agents/requirements/cost-observability.md +1 -1
  261. package/templates/.agents/requirements/dashboard-launch.md +1 -1
  262. package/templates/.agents/requirements/data-export.md +1 -1
  263. package/templates/.agents/requirements/design-system.md +1 -1
  264. package/templates/.agents/requirements/execution-engine.md +3 -3
  265. package/templates/.agents/requirements/kanban-dashboard.md +10 -2
  266. package/templates/.agents/requirements/model-orchestration.md +1 -1
  267. package/templates/.agents/requirements/public-distribution.md +1 -1
  268. package/templates/.agents/requirements/software-architecture.md +1 -1
  269. package/templates/.agents/requirements/strategic-improvements.md +1 -1
  270. package/templates/.agents/requirements/work-lifecycle.md +4 -4
  271. package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
  272. package/templates/.agents/rules/dashboard-ui-consistency.md +14 -0
  273. package/templates/.agents/rules/frontend-lite.md +4 -4
  274. package/templates/.agents/rules/run-lifecycle-closure.md +4 -4
  275. package/templates/.agents/runtime/VERSION +1 -1
  276. package/templates/.agents/runtime/bin/zaip.mjs +1142 -1041
  277. package/templates/.agents/runtime/checksums.sha256 +6 -6
  278. package/templates/.agents/runtime/manifest.json +1 -1
  279. package/templates/.agents/runtime/pnpm-lock.sha256 +1 -1
  280. package/templates/.agents/runtime/provenance.json +5 -5
  281. package/templates/.agents/runtime/sbom.cdx.json +3 -3
  282. package/templates/.agents/sales/playbook.md +32 -0
  283. package/templates/.agents/sales/roteiro-comercial-zaip.md +252 -0
  284. package/templates/.agents/skills/criar-pasta-obsidian/scripts/generate-obsidian-vault.test.mjs +20 -16
  285. package/templates/.agents/skills/zaip-aios/SKILL.md +1 -1
  286. package/templates/.agents/skills/zaip-skill-agent-catalog/SKILL.md +22 -0
  287. package/templates/.agents/skills/zaip-skill-agent-catalog/agents/openai.yaml +4 -0
  288. package/templates/.agents/skills/zaip-skill-author-skills/SKILL.md +3 -2
  289. package/templates/.agents/skills/zaip-skill-author-skills/scripts/audit-skill-catalog.mjs +49 -0
  290. package/templates/.agents/skills/zaip-skill-author-skills/scripts/author-skill-scripts.test.mjs +27 -0
  291. package/templates/.agents/skills/zaip-skill-author-skills/scripts/run-skill-tests.mjs +37 -0
  292. package/templates/.agents/skills/zaip-skill-backend/SKILL.md +1 -0
  293. package/templates/.agents/skills/zaip-skill-brand-governance/SKILL.md +9 -2
  294. package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-framework.md +39 -0
  295. package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-standards.md +1 -1
  296. package/templates/.agents/skills/zaip-skill-change/SKILL.md +1 -1
  297. package/templates/.agents/skills/zaip-skill-change/references/observable-evidence.md +83 -0
  298. package/templates/.agents/skills/zaip-skill-dashboard-diagnostics/SKILL.md +22 -0
  299. package/templates/.agents/skills/zaip-skill-dashboard-diagnostics/agents/openai.yaml +4 -0
  300. package/templates/.agents/skills/zaip-skill-enforce-architecture/SKILL.md +2 -0
  301. package/templates/.agents/skills/zaip-skill-execution/SKILL.md +1 -1
  302. package/templates/.agents/skills/zaip-skill-frontend/SKILL.md +4 -3
  303. package/templates/.agents/skills/zaip-skill-frontend/agents/openai.yaml +2 -2
  304. package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +10 -10
  305. package/templates/.agents/skills/zaip-skill-growth-strategy-revops/SKILL.md +6 -0
  306. package/templates/.agents/skills/zaip-skill-lifecycle-closure/SKILL.md +27 -0
  307. package/templates/.agents/skills/zaip-skill-lifecycle-closure/agents/openai.yaml +4 -0
  308. package/templates/.agents/skills/zaip-skill-marketing/SKILL.md +6 -0
  309. package/templates/.agents/skills/zaip-skill-prd/SKILL.md +4 -0
  310. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.mjs +111 -104
  311. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-explicit-recovery.mjs +223 -0
  312. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.mjs +55 -9
  313. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.test.mjs +145 -14
  314. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.mjs +19 -9
  315. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.test.mjs +82 -5
  316. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/source-size-telemetry/model-identity-reconciliation.mjs +77 -0
  317. package/templates/.agents/skills/zaip-skill-release-qualification/SKILL.md +20 -0
  318. package/templates/.agents/skills/zaip-skill-release-qualification/agents/openai.yaml +4 -0
  319. package/templates/.agents/skills/zaip-skill-review/SKILL.md +5 -0
  320. package/templates/.agents/skills/zaip-skill-rules/SKILL.md +1 -1
  321. package/templates/.agents/skills/zaip-skill-sales-methodology/SKILL.md +6 -0
  322. package/templates/.agents/skills/zaip-skill-spec/SKILL.md +4 -0
  323. package/templates/.agents/skills/zaip-skill-sqlite-read-model/SKILL.md +22 -90
  324. package/templates/.agents/skills/zaip-skill-sqlite-read-model/scripts/ensure-node.mjs +28 -5
  325. package/templates/.agents/zaip-aios/INDEX.md +57 -22
  326. package/templates/.agents/zaip-aios/README.md +24 -13
  327. package/templates/.agents/zaip-aios/VERSION +1 -1
  328. package/templates/.agents/zaip-aios/guides/02-requirements.md +5 -0
  329. package/templates/.agents/zaip-aios/guides/06-execucao.md +13 -4
  330. package/templates/.agents/zaip-aios/guides/07-revisao-e-validacao.md +7 -0
  331. package/templates/.agents/zaip-aios/guides/10-seguranca.md +23 -0
  332. package/templates/.agents/zaip-aios/guides/11-observabilidade-e-custos.md +6 -6
  333. package/templates/.agents/zaip-aios/guides/13-boas-praticas.md +3 -0
  334. package/templates/.agents/zaip-aios/guides/16-lifecycle-e-reconciliacao.md +12 -3
  335. package/templates/.agents/zaip-aios/guides/17-como-o-custo-e-calculado.md +5 -5
  336. package/templates/.agents/zaip-aios/guides/18-catalogo-de-agentes.md +76 -0
  337. package/templates/.agents/zaip-aios/guides/19-assurance-e-autonomia.md +95 -0
  338. package/templates/.agents/zaip-aios/guides/20-instalacao-detalhada.md +366 -0
  339. package/templates/.agents/zaip-aios/guides/21-telemetria-monitor-custos.md +46 -0
  340. package/templates/.agents/zaip-aios/guides/22-fluxos-e-roteamento.md +74 -0
  341. package/templates/.agents/zaip-aios/guides/23-orquestracao-de-modelos.md +483 -0
  342. package/templates/.agents/zaip-aios/guides/24-calculo-de-custos-openai.md +85 -0
  343. package/templates/.agents/zaip-aios/guides/25-fontes-de-precos-openai.md +19 -0
  344. package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +111 -0
  345. package/templates/.agents/zaip-aios/guides/27-telemetria-git-native.md +172 -0
  346. package/templates/.agents/zaip-aios/guides/28-lifecycle-completo.md +149 -0
  347. package/templates/.agents/zaip-aios/guides/assets/diagrams/lifecycles-task-spec-prd.png +0 -0
  348. package/templates/.agents/zaip-aios/guides/assets/diagrams/prd-lifecycle.png +0 -0
  349. package/templates/.agents/zaip-aios/guides/assets/diagrams/spec-lifecycle.png +0 -0
  350. package/templates/.agents/zaip-aios/guides/assets/diagrams/task-lifecycle.png +0 -0
  351. package/templates/template-manifest.json +756 -235
  352. package/templates/.agents/dashboard/apps/frontend/dist/assets/DashboardHelpDialog-Cs6dzDmW.js +0 -1505
  353. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-QE1k9yZB.css +0 -1
  354. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-_Pf5DA_A.js +0 -3
  355. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-BVlz3DLZ.js +0 -1
  356. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-BZ5WdaMN.css +0 -1
  357. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-Cf9ctPVt.js +0 -68
  358. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-8A4DcNXM.js +0 -2
  359. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-DK_enB5Z.css +0 -1
  360. package/templates/.agents/dashboard/apps/frontend/src/use-idle-cost-prefetch.ts +0 -45
@@ -1,6 +1,6 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { createHash, randomBytes } from "node:crypto";
3
- import { appendFileSync, closeSync, mkdirSync, openSync } from "node:fs";
3
+ import { appendFileSync, mkdirSync } from "node:fs";
4
4
  import {
5
5
  access,
6
6
  mkdir,
@@ -12,18 +12,20 @@ import {
12
12
  utimes,
13
13
  writeFile,
14
14
  } from "node:fs/promises";
15
- import { createServer as createHttpServer } from "node:http";
16
15
  import { createServer } from "node:net";
17
16
  import { tmpdir } from "node:os";
18
17
  import { dirname, join, relative, resolve, win32 } from "node:path";
19
18
  import process from "node:process";
20
19
  import { fileURLToPath } from "node:url";
21
20
  import { collectPreviousDashboardSessions } from "./start-dashboard-history.mjs";
21
+ import { createDashboardLaunchPage } from "./start-dashboard-launch-page.mjs";
22
22
  import {
23
+ isProcessAlive,
23
24
  stopOwnedDashboardProcess,
24
25
  stopProcessTree,
25
26
  teardownWarning,
26
27
  } from "./start-dashboard-processes.mjs";
28
+ import { refreshIsRunning, startSeedRefresh } from "./start-dashboard-refresh.mjs";
27
29
 
28
30
  export {
29
31
  isAncestorProcess,
@@ -38,7 +40,10 @@ export const maxPortAttempts = 25;
38
40
  export const runtimeKind = "zaip-dashboard-sqlite-runtime";
39
41
  const packageRoot = dirname(fileURLToPath(import.meta.url));
40
42
  export const workspaceRoot = resolve(packageRoot, "../../../..");
41
- export const workspaceKey = createHash("sha256").update(`${workspaceRoot}:dashboard-sqlite`).digest("hex").slice(0, 16);
43
+ export const workspaceKey = createHash("sha256")
44
+ .update(`${workspaceRoot}:dashboard-sqlite`)
45
+ .digest("hex")
46
+ .slice(0, 16);
42
47
  export const sessionDirectory = join(tmpdir(), "zaip-aios", `dashboard-sqlite-${workspaceKey}`);
43
48
  export const sessionPath = join(sessionDirectory, "dashboard-sqlite-session.json");
44
49
  export const portRegistryPath = join(sessionDirectory, "dashboard-sqlite-ports.json");
@@ -46,20 +51,15 @@ export const lockPath = join(sessionDirectory, "dashboard-sqlite-launcher.lock")
46
51
  export const launcherLogPath = join(sessionDirectory, "dashboard-sqlite-launcher.log");
47
52
  const frontendRoot = resolve(workspaceRoot, ".agents/dashboard/apps/frontend/dist");
48
53
  const sqliteReadModelDirectory = resolve(workspaceRoot, ".local", "dashboard-sqlite");
49
- // Keep the immutable seed cache in one durable workspace location. Runtime
50
- // generations and the isolated background refresher must never derive a
51
- // different cache directory from their temporary SQLite path.
54
+ // Keep the immutable seed cache durable and independent of temporary SQLite generations.
52
55
  const sqliteSnapshotCacheDirectory = join(sqliteReadModelDirectory, "cache");
53
- // Node's bytecode cache is disposable runtime acceleration, never dashboard
54
- // data. Keep it beside the private SQLite generations so fresh-port semantics
55
- // and canonical sources remain unchanged.
56
+ // Node's bytecode cache is disposable acceleration beside private SQLite generations.
56
57
  const nodeCompileCacheDirectory = join(sqliteReadModelDirectory, "node-compile-cache");
57
58
  const installedServer = resolve(packageRoot, "server.mjs");
58
59
  const sourceServer = resolve(packageRoot, "dist/server.cjs");
59
60
  const healthPath = "/api/v2/health";
60
- // Fresh-generation probe marker: changes the immutable source fingerprint only.
61
61
  // Keep the preparation lock through a full build so concurrent clicks coalesce safely.
62
- const lockTimeoutMs = 120_000;
62
+ const lockTimeoutMs = 210_000;
63
63
  const staleLockMs = 30_000;
64
64
  const lockHeartbeatFloorMs = 10;
65
65
  // A cold immutable seed can legitimately take ~176 s on a busy Windows
@@ -259,6 +259,10 @@ export async function findReusableDashboardSession({
259
259
  const port = matches.find((candidate) => candidate !== null);
260
260
  return port === undefined ? null : { ...session, port };
261
261
  }
262
+
263
+ async function backgroundRefreshIsRunning() {
264
+ return refreshIsRunning(join(sessionDirectory, "dashboard-sqlite-refresh.json"), isProcessAlive);
265
+ }
262
266
  async function latestModifiedAt(paths) {
263
267
  let latest = 0;
264
268
  for (const path of paths) {
@@ -283,9 +287,18 @@ async function runSqliteBuild(target) {
283
287
  const command = process.execPath;
284
288
  const args = frontend
285
289
  ? [resolve(workspaceRoot, "node_modules/vite/bin/vite.js"), "build"]
286
- : [resolve(workspaceRoot, ".agents/dashboard/packages/local-runtime/scripts/build-sqlite-runtime.mjs")];
290
+ : [
291
+ resolve(
292
+ workspaceRoot,
293
+ ".agents/dashboard/packages/local-runtime/scripts/build-sqlite-runtime.mjs",
294
+ ),
295
+ ];
287
296
  const output = await new Promise((resolveBuild, rejectBuild) => {
288
- const child = spawn(command, args, { cwd: frontend ? resolve(workspaceRoot, ".agents/dashboard/apps/frontend") : packageRoot, windowsHide: true, stdio: "pipe" });
297
+ const child = spawn(command, args, {
298
+ cwd: frontend ? resolve(workspaceRoot, ".agents/dashboard/apps/frontend") : packageRoot,
299
+ windowsHide: true,
300
+ stdio: "pipe",
301
+ });
289
302
  let outputText = "";
290
303
  const appendOutput = (chunk) => {
291
304
  outputText = `${outputText}${chunk}`.slice(-8_000);
@@ -299,7 +312,9 @@ async function runSqliteBuild(target) {
299
312
  if (code === 0) resolveBuild();
300
313
  else
301
314
  rejectBuild(
302
- new Error(`SQLite dashboard ${target} build failed (${code}): ${formatLauncherError(outputText)}`),
315
+ new Error(
316
+ `SQLite dashboard ${target} build failed (${code}): ${formatLauncherError(outputText)}`,
317
+ ),
303
318
  );
304
319
  });
305
320
  });
@@ -331,6 +346,7 @@ export async function withLauncherLock(
331
346
  path = lockPath,
332
347
  timeoutMs = lockTimeoutMs,
333
348
  staleAfterMs = staleLockMs,
349
+ onWait = () => {},
334
350
  } = {},
335
351
  ) {
336
352
  await mkdir(directory, { recursive: true });
@@ -357,6 +373,7 @@ export async function withLauncherLock(
357
373
  await rm(path, { recursive: true, force: true });
358
374
  continue;
359
375
  }
376
+ onWait();
360
377
  await delay(100);
361
378
  }
362
379
  }
@@ -424,7 +441,12 @@ export function browserLaunchCommands(
424
441
  ],
425
442
  ];
426
443
  }
427
- return [[platform === "darwin" ? "open" : "xdg-open", [target]]];
444
+ return platform === "darwin"
445
+ ? [["open", [target]]]
446
+ : [
447
+ ["xdg-open", [target]],
448
+ ["gio", ["open", target]],
449
+ ];
428
450
  }
429
451
  export async function openBrowser(target, spawnImpl = spawn) {
430
452
  if (process.env.ZAIP_UI_NO_BROWSER === "1") return true;
@@ -455,126 +477,8 @@ export async function openBrowser(target, spawnImpl = spawn) {
455
477
  appendLauncherLog(`Could not dispatch the dashboard URL to the default browser: ${target}`);
456
478
  return false;
457
479
  }
458
- export async function startDashboardLaunchPage(port) {
459
- let redirectUrl = null;
460
- let progress = {
461
- percent: 4,
462
- phase: "Iniciando o launcher local",
463
- detail: "Abrindo a página de preparação.",
464
- };
465
- const connections = new Set();
466
- let resolveRedirectObserved;
467
- const redirectObserved = new Promise((resolveObserved) => {
468
- resolveRedirectObserved = resolveObserved;
469
- });
470
- const server = createHttpServer((request, response) => {
471
- response.setHeader("Cache-Control", "no-store");
472
- if (request.url?.startsWith("/api/v2/ready")) {
473
- if (redirectUrl !== null) resolveRedirectObserved(true);
474
- response.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
475
- response.end(JSON.stringify({ target: redirectUrl }));
476
- return;
477
- }
478
- if (request.url?.startsWith("/api/v2/progress")) {
479
- response.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
480
- response.end(JSON.stringify(progress));
481
- return;
482
- }
483
- if (request.url?.startsWith(healthPath)) {
484
- response.writeHead(503, { "Content-Type": "application/json; charset=utf-8" });
485
- response.end(JSON.stringify({ kind: "zaip-dashboard-launcher", status: "starting" }));
486
- return;
487
- }
488
- response.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
489
- response.end(`<!doctype html>
490
- <html lang="pt-BR">
491
- <head>
492
- <meta charset="utf-8">
493
- <meta name="viewport" content="width=device-width,initial-scale=1">
494
- <title>Dashboard Zaip AIOS</title>
495
- <style>
496
- :root{color-scheme:dark;font-family:Inter,system-ui,sans-serif;background:#010610;color:#f1f5f9}
497
- *{box-sizing:border-box}body{margin:0;background:#010610}.launch-overlay{position:fixed;inset:0;width:100vw;height:100vh;display:grid;place-items:center;padding:clamp(18px,5vw,72px);background:radial-gradient(circle at 50% 35%,rgba(0,176,240,.11),transparent 42%),#010610}
498
- .progress{width:min(100%,760px);padding:clamp(24px,4vw,42px);border:1px solid rgba(125,211,252,.2);border-radius:20px;background:rgba(3,9,22,.94);box-shadow:0 24px 80px rgba(0,0,0,.45);backdrop-filter:blur(10px)}.progress strong,.progress span{display:block}.progress strong{font-size:clamp(1.05rem,2vw,1.35rem)}.progress span{color:#b6c6db;font-size:clamp(.88rem,1.5vw,1rem);margin-top:7px}.track{height:9px;margin-top:20px;border-radius:999px;background:#172033;overflow:hidden}.bar{height:100%;width:4%;border-radius:inherit;background:linear-gradient(90deg,#38bdf8,#818cf8);transition:width .35s ease}.handoff{display:none;margin-top:16px;color:#dbeafe}.handoff a{color:#7dd3fc;font-weight:700}
499
- </style>
500
- </head>
501
- <body>
502
- <main class="launch-overlay" aria-label="Preparando dashboard">
503
- <section class="progress" aria-live="polite" role="status"><strong id="phase">Iniciando o launcher local</strong><span id="detail">Abrindo a página de preparação.</span><div class="track"><div class="bar" id="bar"></div></div><span class="handoff" id="handoff">O dashboard está pronto. Se ele não abrir automaticamente, <a id="handoff-link" href="#">abra o dashboard agora</a>.</span></section>
504
- </main>
505
- <script>
506
- let handoffTarget=null;
507
- function showHandoff(target){handoffTarget=target;const box=document.getElementById("handoff");const link=document.getElementById("handoff-link");link.href=target;box.style.display="block";document.getElementById("phase").textContent="Dashboard pronto";document.getElementById("detail").textContent="Concluindo a abertura da tela principal."}
508
- async function updateProgress(){try{const r=await fetch("/api/v2/progress",{cache:"no-store"});const p=await r.json();if(!handoffTarget){document.getElementById("phase").textContent=p.phase;document.getElementById("detail").textContent=p.detail};document.getElementById("bar").style.width=Math.max(4,Math.min(100,Number(p.percent)||4))+"%"}catch{}}
509
- async function waitForDashboard(){
510
- try{
511
- await updateProgress();
512
- const ready=await fetch("/api/v2/ready",{cache:"no-store"});
513
- const next=await ready.json();
514
- if(next.target){showHandoff(next.target);setTimeout(()=>location.replace(next.target),0);return}
515
- const response=await fetch("${healthPath}",{cache:"no-store"});
516
- const payload=await response.json();
517
- if(response.ok&&payload.kind==="${runtimeKind}"){location.reload();return}
518
- }catch{}
519
- setTimeout(waitForDashboard,250)
520
- }
521
- updateProgress();setTimeout(waitForDashboard,100)
522
- // A browser extension or a failed navigation must never leave a silent
523
- // skeleton. The visible link remains actionable while the temporary
524
- // launcher server keeps serving this page through the handoff grace.
525
- setTimeout(()=>{if(handoffTarget)showHandoff(handoffTarget)},4000)
526
- </script>
527
- </body>
528
- </html>`);
529
- });
530
- server.on("connection", (connection) => {
531
- connections.add(connection);
532
- connection.once("close", () => connections.delete(connection));
533
- });
534
- await new Promise((resolveListen, rejectListen) => {
535
- server.once("error", rejectListen);
536
- server.listen({ host, port }, resolveListen);
537
- });
538
- server.unref();
539
- const address = server.address();
540
- const listeningPort = typeof address === "object" && address !== null ? address.port : port;
541
- return {
542
- port: listeningPort,
543
- redirect: (target) => {
544
- redirectUrl = target;
545
- },
546
- setProgress: (next) => {
547
- progress = { ...progress, ...next, percent: Math.max(progress.percent, next.percent ?? progress.percent) };
548
- },
549
- waitForRedirect: async (timeoutMs = 1_500) =>
550
- Promise.race([redirectObserved, delay(timeoutMs).then(() => false)]),
551
- closeAfterHandoffGrace: (graceMs = 12_000) => {
552
- const timer = setTimeout(() => {
553
- void server.close();
554
- server.closeAllConnections?.();
555
- for (const connection of connections) connection.destroy();
556
- }, graceMs);
557
- timer.unref?.();
558
- },
559
- close: ({ forceAfterMs = 750 } = {}) =>
560
- new Promise((resolveClose, rejectClose) => {
561
- let forceTimer = null;
562
- const finish = (error) => {
563
- if (forceTimer !== null) clearTimeout(forceTimer);
564
- if (error) rejectClose(error);
565
- else resolveClose();
566
- };
567
- server.close(finish);
568
- // The preparation page polls while redirecting. A browser keep-alive
569
- // or an interrupted polling request must not keep this transient
570
- // server alive indefinitely after its handoff was issued.
571
- forceTimer = setTimeout(() => {
572
- server.closeAllConnections?.();
573
- for (const connection of connections) connection.destroy();
574
- }, forceAfterMs);
575
- forceTimer.unref?.();
576
- }),
577
- };
480
+ export function startDashboardLaunchPage(port) {
481
+ return createDashboardLaunchPage({ port, host, runtimeKind, healthPath, delay });
578
482
  }
579
483
  async function redirectLaunchPage(launchPage, target) {
580
484
  launchPage.redirect(target);
@@ -628,7 +532,13 @@ export async function previousDashboardSessions({
628
532
  workspaceKey,
629
533
  });
630
534
  }
631
- async function startDashboardServer(serverPath, token, excludedPorts, initialPort = null, onProgress = () => {}) {
535
+ async function startDashboardServer(
536
+ serverPath,
537
+ token,
538
+ excludedPorts,
539
+ initialPort = null,
540
+ onProgress = () => {},
541
+ ) {
632
542
  const failures = [];
633
543
  for (let attempt = 1; attempt <= maxServerStartAttempts; attempt += 1) {
634
544
  const port =
@@ -677,15 +587,31 @@ async function startDashboardServer(serverPath, token, excludedPorts, initialPor
677
587
  onProgress({
678
588
  percent: event.percent,
679
589
  phase: "Configurando o banco SQLite local",
680
- detail: "Esta é a instalação/atualização da cópia local descartável; nenhum servidor externo é instalado.",
590
+ detail:
591
+ "Esta é a instalação/atualização da cópia local descartável; nenhum servidor externo é instalado.",
681
592
  });
682
593
  if (event?.event === "dashboard_sqlite_startup_phase" && event.phase === "main_entered")
683
- onProgress({ percent: 50, phase: "Lendo os registros do projeto", detail: "Preparando o read model SQLite local." });
594
+ onProgress({
595
+ percent: 50,
596
+ phase: "Lendo os registros do projeto",
597
+ detail: "Preparando o read model SQLite local.",
598
+ });
684
599
  if (event?.event === "dashboard_sqlite_read_model") snapshotCache = event.cache;
685
600
  if (event?.event === "dashboard_sqlite_read_model")
686
- onProgress({ percent: 82, phase: "Banco local pronto", detail: event.cache === "rebuilt" ? "O read model SQLite foi reconstruído para os dados atuais." : "Uma cópia local do read model foi preparada." });
601
+ onProgress({
602
+ percent: 82,
603
+ phase: "Banco local pronto",
604
+ detail:
605
+ event.cache === "rebuilt"
606
+ ? "O read model SQLite foi reconstruído para os dados atuais."
607
+ : "Uma cópia local do read model foi preparada.",
608
+ });
687
609
  if (event?.event === "dashboard_sqlite_startup_phase" && event.phase === "listening")
688
- onProgress({ percent: 88, phase: "Iniciando a interface", detail: "Verificando saúde e disponibilidade dos dados." });
610
+ onProgress({
611
+ percent: 88,
612
+ phase: "Iniciando a interface",
613
+ detail: "Verificando saúde e disponibilidade dos dados.",
614
+ });
689
615
  } catch {
690
616
  // Only structured startup telemetry affects the user-facing progress.
691
617
  }
@@ -707,10 +633,15 @@ async function startDashboardServer(serverPath, token, excludedPorts, initialPor
707
633
  await removeGeneratedReadModel(dbPath);
708
634
  const detail = stripTerminalControlCodes(stderr)
709
635
  .split("\n")
710
- .filter((line) => !line.includes("ExperimentalWarning") && !line.includes("node --trace-warnings"))
636
+ .filter(
637
+ (line) =>
638
+ !line.includes("ExperimentalWarning") && !line.includes("node --trace-warnings"),
639
+ )
711
640
  .join("\n")
712
641
  .trim();
713
- failures.push(`porta ${port}: ${error.message}${detail ? ` — ${formatLauncherError(detail, 600)}` : ""}`);
642
+ failures.push(
643
+ `porta ${port}: ${error.message}${detail ? ` — ${formatLauncherError(detail, 600)}` : ""}`,
644
+ );
714
645
  appendLauncherLog(
715
646
  `Dashboard start attempt ${attempt} failed on port ${port}: ${error.message}`,
716
647
  );
@@ -744,59 +675,29 @@ async function removeGeneratedReadModel(candidate) {
744
675
  if (attempt < 20) await delay(250);
745
676
  }
746
677
  }
747
- appendLauncherLog(`Could not remove closed SQLite read model after retries: ${resolvedCandidate}`);
678
+ appendLauncherLog(
679
+ `Could not remove closed SQLite read model after retries: ${resolvedCandidate}`,
680
+ );
748
681
  return false;
749
682
  }
750
- function refreshSnapshotSeedInBackground() {
751
- const refreshPath = resolve(sqliteReadModelDirectory, `refresh-${process.pid}-${randomBytes(4).toString("hex")}.sqlite`);
683
+ async function refreshSnapshotSeedInBackground() {
752
684
  const refreshStatusPath = join(sessionDirectory, "dashboard-sqlite-refresh.json");
753
685
  const refreshLogPath = join(sessionDirectory, "dashboard-sqlite-refresh.log");
754
- mkdirSync(sessionDirectory, { recursive: true });
755
- const refreshLogDescriptor = openSync(refreshLogPath, "a");
756
- let worker;
757
- try {
758
- worker = spawn(process.execPath, [resolve(packageRoot, "scripts/rebuild-sqlite-read-model.mjs")], {
759
- cwd: workspaceRoot,
760
- env: {
761
- ...process.env,
762
- ZAIP_SQLITE_DB_PATH: refreshPath,
763
- ZAIP_SQLITE_PREFER_LAST_VALID_SEED: "0",
764
- ZAIP_DASHBOARD_LAUNCH_PROGRESS: "0",
765
- ZAIP_SQLITE_REFRESH_CLEANUP: "1",
766
- ZAIP_SQLITE_CACHE_DIR: sqliteSnapshotCacheDirectory,
767
- },
768
- // A detached worker keeps its own append-only evidence file. Pipes can
769
- // disappear with a fast launcher exit and silently abort the refresh.
770
- stdio: ["ignore", refreshLogDescriptor, refreshLogDescriptor],
771
- detached: true,
772
- windowsHide: true,
773
- });
774
- } finally {
775
- closeSync(refreshLogDescriptor);
776
- }
777
- void writeJsonAtomic(refreshStatusPath, {
778
- status: "running",
779
- pid: worker.pid ?? null,
780
- path: refreshPath,
686
+ return startSeedRefresh({
687
+ appendLog: appendLauncherLog,
781
688
  cacheDirectory: sqliteSnapshotCacheDirectory,
782
- startedAt: new Date().toISOString(),
783
- }).catch(() => {});
784
- worker.once("error", (error) => {
785
- appendLauncherLog(`Background SQLite seed refresh failed to start: ${error.message}`);
786
- void writeJsonAtomic(refreshStatusPath, { status: "failed", error: error.message, finishedAt: new Date().toISOString() }).catch(() => {});
787
- });
788
- worker.once("exit", (code) => {
789
- const status = code === 0 ? "completed" : "failed";
790
- appendLauncherLog(`Background SQLite seed refresh ${status} (${code ?? "unknown"}); inspect ${refreshLogPath}.`);
791
- void writeJsonAtomic(refreshStatusPath, {
792
- status,
793
- exitCode: code ?? null,
794
- logPath: refreshLogPath,
795
- finishedAt: new Date().toISOString(),
796
- }).catch(() => {});
689
+ isRunning: backgroundRefreshIsRunning,
690
+ isProcessAlive,
691
+ lockPath: join(sessionDirectory, "dashboard-sqlite-refresh.lock"),
692
+ packageRoot,
693
+ randomBytes,
694
+ refreshLogPath,
695
+ refreshStatusPath,
696
+ sqliteDirectory: sqliteReadModelDirectory,
697
+ stopProcessTree,
698
+ workspaceRoot,
699
+ writeJsonAtomic,
797
700
  });
798
- worker.unref();
799
- appendLauncherLog(`Started background SQLite seed refresh at ${refreshPath}; cache ${sqliteSnapshotCacheDirectory}; worker log ${refreshLogPath}.`);
800
701
  }
801
702
  async function writeLauncherStatus(status, message = "") {
802
703
  const path = process.env.ZAIP_LAUNCH_STATUS;
@@ -806,7 +707,15 @@ async function writeLauncherStatus(status, message = "") {
806
707
  await rename(temporaryPath, path);
807
708
  }
808
709
  function phaseTiming(phase, startedAt, details = {}) {
809
- appendLauncherLog(JSON.stringify({ event: "dashboard_sqlite_phase", phase, elapsed_ms: Date.now() - startedAt, launcher_pid: process.pid, ...details }));
710
+ appendLauncherLog(
711
+ JSON.stringify({
712
+ event: "dashboard_sqlite_phase",
713
+ phase,
714
+ elapsed_ms: Date.now() - startedAt,
715
+ launcher_pid: process.pid,
716
+ ...details,
717
+ }),
718
+ );
810
719
  }
811
720
  async function main() {
812
721
  let ownedChild = null;
@@ -827,7 +736,8 @@ async function main() {
827
736
  launchPage.setProgress({
828
737
  percent: 10,
829
738
  phase: "Validando pré-requisitos locais",
830
- detail: "Verificando Node.js 22 e o suporte a node:sqlite; isto não instala um banco de dados.",
739
+ detail:
740
+ "Verificando Node.js 22 e o suporte a node:sqlite; isto não instala um banco de dados.",
831
741
  });
832
742
  await assertDashboardPrerequisites();
833
743
  launchPage.setProgress({
@@ -835,110 +745,162 @@ async function main() {
835
745
  phase: "Preparando a sessão do dashboard",
836
746
  detail: "Coordenando esta abertura local com segurança.",
837
747
  });
838
- await withLauncherLock(async () => {
839
- phaseTiming("lock_acquired", launchStartedAt);
840
- const buildStartedAt = Date.now();
841
- launchPage.setProgress({
842
- percent: 28,
843
- phase: "Verificando os artefatos do dashboard",
844
- detail: "Usando o build existente quando ele já está atualizado.",
845
- });
846
- const buildSignature = await ensureFreshDashboardBuild();
847
- phaseTiming("build_complete", buildStartedAt, { build_signature: buildSignature });
848
- // A second deliberate click must use the already healthy compatible
849
- // runtime. Build signature makes this safe across dashboard updates;
850
- // an incompatible session continues through a replacement handoff.
851
- const reusable = await findReusableDashboardSession({
852
- expectedBuildSignature: buildSignature,
853
- expectedSnapshotState: "current",
854
- });
855
- if (reusable !== null) {
856
- appendLauncherLog(`Reused healthy compatible dashboard session on port ${reusable.port}, PID ${reusable.serverPid ?? "unknown"}.`);
857
- await redirectLaunchPage(launchPage, dashboardUrl(reusable.port, reusable.token));
858
- launchPage = null;
859
- await writeLauncherStatus("ok");
860
- return;
861
- }
862
- const previousSessions = await previousDashboardSessions();
863
- const excludedPorts = new Set([
864
- ...previousSessions.map((session) => session.port),
865
- launchPort,
866
- ]);
867
- const serverPath = await assertRuntimeReady();
868
- const readyStartedAt = Date.now();
869
- launchPage.setProgress({
870
- percent: 42,
871
- phase: "Abrindo o banco local descartável",
872
- detail: "Criando uma cópia privada do read model SQLite para esta sessão.",
873
- });
874
- const { child, port, dbPath, snapshotCache } = await startDashboardServer(
875
- serverPath,
876
- token,
877
- excludedPorts,
878
- null,
879
- (progress) => launchPage?.setProgress(progress),
880
- );
881
- phaseTiming("server_ready", readyStartedAt, { server_pid: child.pid, port, db_path: dbPath });
882
- ownedChild = child;
883
- try {
748
+ let reportedLockWait = false;
749
+ await withLauncherLock(
750
+ async () => {
751
+ phaseTiming("lock_acquired", launchStartedAt);
752
+ const buildStartedAt = Date.now();
884
753
  launchPage.setProgress({
885
- percent: 92,
886
- phase: snapshotCache === "stale_seed" ? "Abrindo snapshot local validado" : "Dashboard pronto",
887
- detail: snapshotCache === "stale_seed"
888
- ? "Os dados canônicos estão sendo atualizados em segundo plano para a próxima abertura."
889
- : "Validando saúde e dados iniciais antes de abrir a tela principal.",
754
+ percent: 28,
755
+ phase: "Verificando os artefatos do dashboard",
756
+ detail: "Usando o build existente quando ele já está atualizado.",
890
757
  });
891
- if (snapshotCache === "stale_seed") await delay(350);
892
- await redirectLaunchPage(launchPage, dashboardUrl(port, token, snapshotCache === "stale_seed"));
893
- phaseTiming("handoff_complete", launchStartedAt, { server_pid: child.pid, port });
894
- launchPage = null;
895
- if (snapshotCache === "stale_seed")
896
- refreshSnapshotSeedInBackground();
897
- currentSession = {
898
- kind: runtimeKind,
899
- workspace: workspaceRoot,
900
- workspaceKey,
901
- rootPid: process.pid,
902
- serverPid: child.pid,
903
- port,
904
- token,
905
- dbPath,
906
- buildSignature,
907
- generationId: `${process.pid}-${child.pid}-${port}-${randomBytes(6).toString("hex")}`,
908
- // Never pin subsequent clicks to a stale seed. A completed
909
- // background refresh is consumed by a fresh handoff on the next
910
- // click, then the old updating generation is retired below.
911
- snapshotState: snapshotCache === "stale_seed" ? "updating" : "current",
912
- createdAt: new Date().toISOString(),
913
- };
914
- await writeDashboardSession(currentSession);
915
- await recordPortStatus(currentSession, "active");
916
- const warnings = [];
917
- for (const previous of previousSessions) {
918
- const status = await stopOwnedDashboard(previous);
919
- await recordPortStatus(previous, status);
920
- if (status === "closed") await removeGeneratedReadModel(previous.dbPath);
921
- if (teardownWarning(status))
922
- warnings.push(`não foi possível fechar a porta anterior ${previous.port}`);
923
- else if (status === "skipped_unowned")
758
+ const buildSignature = await ensureFreshDashboardBuild();
759
+ phaseTiming("build_complete", buildStartedAt, { build_signature: buildSignature });
760
+ // A second deliberate click must use the already healthy compatible
761
+ // runtime. Build signature makes this safe across dashboard updates;
762
+ // an incompatible session continues through a replacement handoff.
763
+ const reusable = await findReusableDashboardSession({
764
+ expectedBuildSignature: buildSignature,
765
+ expectedSnapshotState: "current",
766
+ });
767
+ if (reusable !== null) {
768
+ appendLauncherLog(
769
+ `Reused healthy compatible dashboard session on port ${reusable.port}, PID ${reusable.serverPid ?? "unknown"}.`,
770
+ );
771
+ await redirectLaunchPage(launchPage, dashboardUrl(reusable.port, reusable.token));
772
+ launchPage = null;
773
+ await writeLauncherStatus("ok");
774
+ return;
775
+ }
776
+ // A stale seed is still a valid read-only dashboard while its one
777
+ // canonical refresh runs. Reuse it instead of turning repeated clicks
778
+ // into competing full SQLite rebuilds and private server generations.
779
+ if (await backgroundRefreshIsRunning()) {
780
+ const updating = await findReusableDashboardSession({
781
+ expectedBuildSignature: buildSignature,
782
+ expectedSnapshotState: "updating",
783
+ });
784
+ if (updating !== null) {
924
785
  appendLauncherLog(
925
- `Skipped teardown of port ${previous.port}: registered server PID does not own its live listener.`,
786
+ `Reused updating dashboard session on port ${updating.port}; canonical seed refresh is already running.`,
926
787
  );
788
+ await redirectLaunchPage(launchPage, dashboardUrl(updating.port, updating.token, true));
789
+ launchPage = null;
790
+ await writeLauncherStatus("ok");
791
+ return;
792
+ }
927
793
  }
928
- if (warnings.length > 0)
929
- appendLauncherLog(
930
- `Dashboard launched on port ${port}; prior-port cleanup: ${warnings.join("; ")}`,
794
+ const previousSessions = await previousDashboardSessions();
795
+ const excludedPorts = new Set([
796
+ ...previousSessions.map((session) => session.port),
797
+ launchPort,
798
+ ]);
799
+ const serverPath = await assertRuntimeReady();
800
+ const readyStartedAt = Date.now();
801
+ launchPage.setProgress({
802
+ percent: 42,
803
+ phase: "Abrindo o banco local descartável",
804
+ detail: "Criando uma cópia privada do read model SQLite para esta sessão.",
805
+ });
806
+ const { child, port, dbPath, snapshotCache } = await startDashboardServer(
807
+ serverPath,
808
+ token,
809
+ excludedPorts,
810
+ null,
811
+ (progress) => launchPage?.setProgress(progress),
812
+ );
813
+ phaseTiming("server_ready", readyStartedAt, {
814
+ server_pid: child.pid,
815
+ port,
816
+ db_path: dbPath,
817
+ });
818
+ ownedChild = child;
819
+ try {
820
+ launchPage.setProgress({
821
+ percent: 92,
822
+ phase:
823
+ snapshotCache === "stale_seed"
824
+ ? "Abrindo snapshot local validado"
825
+ : "Dashboard pronto",
826
+ detail:
827
+ snapshotCache === "stale_seed"
828
+ ? "Os dados canônicos estão sendo atualizados em segundo plano para a próxima abertura."
829
+ : "Validando saúde e dados iniciais antes de abrir a tela principal.",
830
+ });
831
+ if (snapshotCache === "stale_seed") await delay(350);
832
+ await redirectLaunchPage(
833
+ launchPage,
834
+ dashboardUrl(port, token, snapshotCache === "stale_seed"),
931
835
  );
932
- await writeLauncherStatus("ok");
933
- } catch (error) {
934
- await stopProcessTree(child.pid);
935
- if (currentSession !== null) await recordPortStatus(currentSession, "failed");
936
- await clearOwnedDashboardSession();
937
- throw error;
938
- }
939
- });
836
+ phaseTiming("handoff_complete", launchStartedAt, { server_pid: child.pid, port });
837
+ launchPage = null;
838
+ if (snapshotCache === "stale_seed") await refreshSnapshotSeedInBackground();
839
+ currentSession = {
840
+ kind: runtimeKind,
841
+ workspace: workspaceRoot,
842
+ workspaceKey,
843
+ rootPid: process.pid,
844
+ serverPid: child.pid,
845
+ port,
846
+ token,
847
+ dbPath,
848
+ buildSignature,
849
+ generationId: `${process.pid}-${child.pid}-${port}-${randomBytes(6).toString("hex")}`,
850
+ // Never pin subsequent clicks to a stale seed. A completed
851
+ // background refresh is consumed by a fresh handoff on the next
852
+ // click, then the old updating generation is retired below.
853
+ snapshotState: snapshotCache === "stale_seed" ? "updating" : "current",
854
+ createdAt: new Date().toISOString(),
855
+ };
856
+ await writeDashboardSession(currentSession);
857
+ await recordPortStatus(currentSession, "active");
858
+ const warnings = [];
859
+ for (const previous of previousSessions) {
860
+ const status = await stopOwnedDashboard(previous);
861
+ await recordPortStatus(previous, status);
862
+ if (status === "closed") await removeGeneratedReadModel(previous.dbPath);
863
+ if (teardownWarning(status))
864
+ warnings.push(`não foi possível fechar a porta anterior ${previous.port}`);
865
+ else if (status === "skipped_unowned")
866
+ appendLauncherLog(
867
+ `Skipped teardown of port ${previous.port}: registered server PID does not own its live listener.`,
868
+ );
869
+ }
870
+ if (warnings.length > 0)
871
+ appendLauncherLog(
872
+ `Dashboard launched on port ${port}; prior-port cleanup: ${warnings.join("; ")}`,
873
+ );
874
+ await writeLauncherStatus("ok");
875
+ } catch (error) {
876
+ await stopProcessTree(child.pid);
877
+ if (currentSession !== null) await recordPortStatus(currentSession, "failed");
878
+ await clearOwnedDashboardSession();
879
+ throw error;
880
+ }
881
+ },
882
+ {
883
+ onWait: () => {
884
+ if (reportedLockWait) return;
885
+ reportedLockWait = true;
886
+ launchPage?.setProgress({
887
+ percent: 22,
888
+ phase: "Aguardando outra abertura do dashboard",
889
+ detail: "A outra sessão está concluindo o carregamento local antes desta continuar.",
890
+ });
891
+ },
892
+ },
893
+ );
940
894
  } catch (error) {
941
- if (launchPage !== null) await launchPage.close().catch(() => {});
895
+ if (launchPage !== null) {
896
+ launchPage.setFailure({
897
+ percent: 100,
898
+ phase: "Não foi possível preparar o dashboard",
899
+ detail: formatLauncherError(error instanceof Error ? error.message : String(error), 900),
900
+ });
901
+ launchPage.closeAfterFailureObservation();
902
+ launchPage = null;
903
+ }
942
904
  throw error;
943
905
  }
944
906
  if (ownedChild === null) return;
@@ -1000,7 +962,11 @@ async function waitForDashboard(port, child) {
1000
962
  }
1001
963
  await delay(100);
1002
964
  }
1003
- throw new Error(`Timed out waiting for ${dashboardHealthUrl(port)}`);
965
+ // A cold read-model timeout is not a port collision. Retrying would start
966
+ // up to four more full builds and exceed the launcher deadline.
967
+ const timedOut = new Error(`Timed out waiting for ${dashboardHealthUrl(port)}`);
968
+ timedOut.retryable = false;
969
+ throw timedOut;
1004
970
  }
1005
971
  function exists(path) {
1006
972
  return access(path).then(