@zaip-ai/cli 3.7.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. package/README.md +5 -5
  2. package/dist/commands/init.d.ts.map +1 -1
  3. package/dist/commands/init.js +6 -0
  4. package/dist/commands/init.js.map +1 -1
  5. package/dist/services/adapters.d.ts +1 -1
  6. package/dist/services/adapters.d.ts.map +1 -1
  7. package/dist/services/adapters.js +22 -4
  8. package/dist/services/adapters.js.map +1 -1
  9. package/dist/services/adapters.test.js +24 -0
  10. package/dist/services/adapters.test.js.map +1 -1
  11. package/dist/services/agent-adapters.js +1 -1
  12. package/dist/services/agent-adapters.js.map +1 -1
  13. package/dist/services/backup-gitignore.d.ts +9 -0
  14. package/dist/services/backup-gitignore.d.ts.map +1 -0
  15. package/dist/services/backup-gitignore.js +66 -0
  16. package/dist/services/backup-gitignore.js.map +1 -0
  17. package/dist/services/backup-gitignore.test.d.ts +2 -0
  18. package/dist/services/backup-gitignore.test.d.ts.map +1 -0
  19. package/dist/services/backup-gitignore.test.js +27 -0
  20. package/dist/services/backup-gitignore.test.js.map +1 -0
  21. package/dist/services/codex-conversation-lifecycle-hook.d.ts.map +1 -1
  22. package/dist/services/codex-conversation-lifecycle-hook.js +15 -7
  23. package/dist/services/codex-conversation-lifecycle-hook.js.map +1 -1
  24. package/dist/services/install-agents-template.d.ts.map +1 -1
  25. package/dist/services/install-agents-template.js +43 -127
  26. package/dist/services/install-agents-template.js.map +1 -1
  27. package/dist/services/install-template-policy.d.ts.map +1 -1
  28. package/dist/services/install-template-policy.js +2 -0
  29. package/dist/services/install-template-policy.js.map +1 -1
  30. package/dist/services/legacy-records-migration.d.ts +15 -0
  31. package/dist/services/legacy-records-migration.d.ts.map +1 -0
  32. package/dist/services/legacy-records-migration.js +109 -0
  33. package/dist/services/legacy-records-migration.js.map +1 -0
  34. package/dist/services/local-state-migration.d.ts +8 -1
  35. package/dist/services/local-state-migration.d.ts.map +1 -1
  36. package/dist/services/local-state-migration.js +67 -32
  37. package/dist/services/local-state-migration.js.map +1 -1
  38. package/dist/services/logger.d.ts.map +1 -1
  39. package/dist/services/logger.js +2 -0
  40. package/dist/services/logger.js.map +1 -1
  41. package/dist/services/project-model-migration.d.ts +3 -0
  42. package/dist/services/project-model-migration.d.ts.map +1 -0
  43. package/dist/services/project-model-migration.js +163 -0
  44. package/dist/services/project-model-migration.js.map +1 -0
  45. package/dist/services/project-model-migration.test.d.ts +2 -0
  46. package/dist/services/project-model-migration.test.d.ts.map +1 -0
  47. package/dist/services/project-model-migration.test.js +62 -0
  48. package/dist/services/project-model-migration.test.js.map +1 -0
  49. package/dist/services/sqlite-bootstrap.d.ts.map +1 -1
  50. package/dist/services/sqlite-bootstrap.js +9 -1
  51. package/dist/services/sqlite-bootstrap.js.map +1 -1
  52. package/dist/services/template-manifest.d.ts.map +1 -1
  53. package/dist/services/template-manifest.js +2 -0
  54. package/dist/services/template-manifest.js.map +1 -1
  55. package/dist/services/transactional-files.d.ts +1 -0
  56. package/dist/services/transactional-files.d.ts.map +1 -1
  57. package/dist/services/transactional-files.js +3 -0
  58. package/dist/services/transactional-files.js.map +1 -1
  59. package/dist/types.d.ts +1 -0
  60. package/dist/types.d.ts.map +1 -1
  61. package/package.json +1 -1
  62. package/templates/.agents/README-ENG.md +90 -34
  63. package/templates/.agents/README.md +59 -32
  64. package/templates/.agents/config/agents/catalog.yaml +23 -23
  65. package/templates/.agents/config/agents/discovery.json +2 -2
  66. package/templates/.agents/config/clients/codex/agents/zaip-agent-analyst.toml +2 -2
  67. package/templates/.agents/config/clients/codex/agents/zaip-agent-auditor.toml +2 -2
  68. package/templates/.agents/config/clients/codex/agents/zaip-agent-backend.toml +2 -2
  69. package/templates/.agents/config/clients/codex/agents/zaip-agent-brand-strategist.toml +2 -2
  70. package/templates/.agents/config/clients/codex/agents/zaip-agent-builder.toml +2 -2
  71. package/templates/.agents/config/clients/codex/agents/zaip-agent-cloud-engineer.toml +2 -2
  72. package/templates/.agents/config/clients/codex/agents/zaip-agent-data-analyst.toml +2 -2
  73. package/templates/.agents/config/clients/codex/agents/zaip-agent-designer.toml +2 -2
  74. package/templates/.agents/config/clients/codex/agents/zaip-agent-finalizer.toml +2 -2
  75. package/templates/.agents/config/clients/codex/agents/zaip-agent-frontend.toml +2 -2
  76. package/templates/.agents/config/clients/codex/agents/zaip-agent-general-operations.toml +2 -2
  77. package/templates/.agents/config/clients/codex/agents/zaip-agent-governance-compliance.toml +2 -2
  78. package/templates/.agents/config/clients/codex/agents/zaip-agent-growth-strategist.toml +2 -2
  79. package/templates/.agents/config/clients/codex/agents/zaip-agent-integrator.toml +2 -2
  80. package/templates/.agents/config/clients/codex/agents/zaip-agent-marketing-analyst.toml +2 -2
  81. package/templates/.agents/config/clients/codex/agents/zaip-agent-orchestrator.toml +3 -3
  82. package/templates/.agents/config/clients/codex/agents/zaip-agent-refactoring-specialist.toml +2 -2
  83. package/templates/.agents/config/clients/codex/agents/zaip-agent-reviewer.toml +2 -2
  84. package/templates/.agents/config/clients/codex/agents/zaip-agent-sales-specialist.toml +2 -2
  85. package/templates/.agents/config/clients/codex/agents/zaip-agent-security-auditor.toml +2 -2
  86. package/templates/.agents/config/clients/codex/agents/zaip-agent-task-executor.toml +2 -2
  87. package/templates/.agents/config/clients/codex/agents/zaip-agent-website-developer.toml +2 -2
  88. package/templates/.agents/config/clients/codex/agents/zaip-agent-writer.toml +2 -2
  89. package/templates/.agents/config/clients.yaml +1 -1
  90. package/templates/.agents/config/pricing/models.json +57 -1
  91. package/templates/.agents/config/project.yaml +21 -7
  92. package/templates/.agents/dashboard/.zaip-managed.json +195 -115
  93. package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-C5NgEcVh.js → CostCalculationGuidePage-f4ZGJRg3.js} +1 -1
  94. package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-BDQR0U4a.js → DashboardHelpDialog-DlN5EMmD.js} +249 -136
  95. package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-CGYcJ5EB.js → PricingSettingsDialog-v9zGRTlk.js} +1 -1
  96. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-BRdoeTWk.js +3 -0
  97. package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-Ckxk_izu.js → TraceabilityWorkspace-B_5u4Xnp.js} +1 -1
  98. package/templates/.agents/dashboard/apps/frontend/dist/assets/{cost-monitor-BsMfGfQi.css → cost-monitor-C2AFYBu_.css} +1 -1
  99. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-D7PrDZy9.js +68 -0
  100. package/templates/.agents/dashboard/apps/frontend/dist/assets/{dashboard-localization-jvdDfNKs.js → dashboard-localization-CF7B1Hjn.js} +90 -34
  101. package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-x8xxL9yW.js → icons-vendor-Cv3WBFIF.js} +1 -1
  102. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-C4rLXrz_.js +2 -0
  103. package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-CNOXIJHN.js → react-vendor-mHgsmxb6.js} +1 -1
  104. package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-CcpbpT1s.js → traceability-B0CPyEVq.js} +1 -1
  105. package/templates/.agents/dashboard/apps/frontend/dist/index.html +6 -6
  106. package/templates/.agents/dashboard/apps/frontend/package.json +1 -1
  107. package/templates/.agents/dashboard/apps/frontend/src/AppDashboardContent.tsx +11 -1
  108. package/templates/.agents/dashboard/apps/frontend/src/AppLoadingBoundary.tsx +3 -2
  109. package/templates/.agents/dashboard/apps/frontend/src/AppLoadingPanels.tsx +1 -1
  110. package/templates/.agents/dashboard/apps/frontend/src/AppOverlays.tsx +1 -1
  111. package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsPage.tsx +9 -13
  112. package/templates/.agents/dashboard/apps/frontend/src/cost-monitor-population.test.tsx +4 -2
  113. package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +9 -5
  114. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api-settings.ts +3 -2
  115. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +2 -2
  116. package/templates/.agents/dashboard/apps/frontend/src/dashboard-identity.test.ts +3 -3
  117. package/templates/.agents/dashboard/apps/frontend/src/dashboard-identity.ts +1 -1
  118. package/templates/.agents/dashboard/apps/frontend/src/dashboard-localization.test.ts +2 -1
  119. package/templates/.agents/dashboard/apps/frontend/src/operations-period-render.test.ts +40 -3
  120. package/templates/.agents/dashboard/apps/frontend/src/project-settings-model.ts +12 -1
  121. package/templates/.agents/dashboard/apps/frontend/src/project-settings.test.ts +19 -0
  122. package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +1 -1
  123. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.test.ts +3 -1
  124. package/templates/.agents/dashboard/apps/frontend/src/use-dashboard-app-model.tsx +14 -23
  125. package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
  126. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.test.ts +3 -3
  127. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.tsx +2 -3
  128. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionTable.tsx +2 -6
  129. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostGroupsTable.period-values.test.tsx +66 -0
  130. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostGroupsTable.tsx +29 -34
  131. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorContent.tsx +2 -2
  132. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.embedded.test.ts +11 -0
  133. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +1 -13
  134. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostPeriodAverageCards.test.tsx +23 -0
  135. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostPeriodAverageCards.tsx +2 -1
  136. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableDisplay.ts +6 -11
  137. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables-keeps-legacy-codex-identity-fields-blank.test.ts +6 -6
  138. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +10 -12
  139. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-group-page-totals.ts +23 -0
  140. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-group-period-values.tsx +34 -0
  141. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-embedded.css +0 -7
  142. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-table-formatters.ts +4 -9
  143. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-table-presentation.ts +2 -3
  144. package/templates/.agents/dashboard/modules/operations/package.json +1 -1
  145. package/templates/.agents/dashboard/modules/operations/src/react/DeveloperAttributionPanel.tsx +2 -12
  146. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.helpers.tsx +2 -2
  147. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.test.ts +1 -6
  148. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +34 -36
  149. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverviewCharts.tsx +12 -3
  150. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverviewTopPanel.tsx +12 -14
  151. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +4 -4
  152. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageOverview.tsx +23 -4
  153. package/templates/.agents/dashboard/modules/operations/src/react/OverviewCostKpi.tsx +30 -2
  154. package/templates/.agents/dashboard/modules/operations/src/react/TaskDetailsDialog.tsx +2 -13
  155. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkBoard.priority.test.ts +8 -1
  156. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkBoard.tsx +8 -16
  157. package/templates/.agents/dashboard/modules/operations/src/react/WorkColumnState.tsx +34 -0
  158. package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.test.ts +1 -1
  159. package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.ts +1 -1
  160. package/templates/.agents/dashboard/modules/operations/src/react/operations-average-unmeasured.test.ts +10 -0
  161. package/templates/.agents/dashboard/modules/operations/src/react/operations-content-visibility.ts +3 -0
  162. package/templates/.agents/dashboard/modules/operations/src/react/operations-coverage-toast.test.ts +4 -3
  163. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +12 -1
  164. package/templates/.agents/dashboard/modules/operations/src/react/operations-page-contract.ts +1 -0
  165. package/templates/.agents/dashboard/modules/operations/src/react/operations-skeleton.css +80 -0
  166. package/templates/.agents/dashboard/modules/operations/src/react/operations.css +2 -11
  167. package/templates/.agents/dashboard/modules/operations/src/react/overview-cost-card.test.tsx +36 -0
  168. package/templates/.agents/dashboard/modules/operations/src/react/overview-metric-format.test.ts +11 -0
  169. package/templates/.agents/dashboard/modules/operations/src/react/overview-metric-format.ts +28 -3
  170. package/templates/.agents/dashboard/modules/operations/src/react/overview-metric-stats.ts +44 -0
  171. package/templates/.agents/dashboard/modules/operations/src/react/work-card-label.ts +5 -0
  172. package/templates/.agents/dashboard/modules/operations/src/react/work-column-state.ts +11 -0
  173. package/templates/.agents/dashboard/modules/operations/src/react/work-item-filter.ts +13 -0
  174. package/templates/.agents/dashboard/modules/traceability/package.json +1 -1
  175. package/templates/.agents/dashboard/packages/branding/package.json +1 -1
  176. package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
  177. package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
  178. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +173 -173
  179. package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +120 -120
  180. package/templates/.agents/dashboard/packages/local-runtime/package.json +1 -1
  181. package/templates/.agents/dashboard/packages/local-runtime/server.mjs +173 -173
  182. package/templates/.agents/dashboard/packages/local-runtime/src/active-codex-telemetry.test.ts +31 -0
  183. package/templates/.agents/dashboard/packages/local-runtime/src/active-codex-telemetry.ts +74 -1
  184. package/templates/.agents/dashboard/packages/local-runtime/src/agent-catalog-settings.test.ts +15 -15
  185. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.test.ts +2 -2
  186. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.ts +1 -1
  187. package/templates/.agents/dashboard/packages/local-runtime/src/server-identity.test.ts +1 -1
  188. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-synchronization.test.ts +25 -3
  189. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-synchronization.ts +51 -16
  190. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot.test.ts +1 -1
  191. package/templates/.agents/dashboard/packages/local-runtime/src/server-ui-security.ts +37 -0
  192. package/templates/.agents/dashboard/packages/local-runtime/src/server-workspace.ts +1 -1
  193. package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +11 -33
  194. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-rebuild.ts +12 -13
  195. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.test.ts +71 -1
  196. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.ts +141 -25
  197. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-worktree-sources.test.ts +60 -0
  198. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-rebuild-fingerprint-options.ts +13 -0
  199. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.mjs +26 -2
  200. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.test.mjs +5 -0
  201. package/templates/.agents/dashboard/packages/ui/package.json +1 -1
  202. package/templates/.agents/dashboard/packages/ui/src/DashboardHeader.test.mjs +5 -0
  203. package/templates/.agents/dashboard/packages/ui/src/DashboardHeader.tsx +4 -4
  204. package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
  205. package/templates/.agents/dashboard/tests/e2e/playwright.config.ts +4 -0
  206. package/templates/.agents/dashboard/tests/e2e/specs/dashboard-performance-matrix.spec.ts +15 -23
  207. package/templates/.agents/dashboard/tests/e2e/specs/dashboard.spec.ts +1 -1
  208. package/templates/.agents/dashboard/tests/e2e/specs/performance-matrix-types.ts +15 -0
  209. package/templates/.agents/dashboard/tests/e2e/specs/performance-observability.ts +30 -0
  210. package/templates/.agents/dashboard/tests/e2e/specs/performance-work-row-identity.ts +6 -0
  211. package/templates/.agents/design/.zaip-managed.json +13 -9
  212. package/templates/.agents/design/apps/catalog/dist/assets/index-DkpQYoyC.js +72 -0
  213. package/templates/.agents/design/apps/catalog/dist/index.html +1 -1
  214. package/templates/.agents/design/apps/catalog/package.json +1 -1
  215. package/templates/.agents/design/apps/catalog/src/components/CostPopulationSpecimen.test.tsx +8 -4
  216. package/templates/.agents/design/apps/catalog/src/components/CostPopulationSpecimen.tsx +10 -3
  217. package/templates/.agents/design/apps/catalog/src/components/DashboardFiltersSpecimen.tsx +0 -15
  218. package/templates/.agents/design/apps/catalog/src/pages/ComponentsPage.tsx +3 -3
  219. package/templates/.agents/design/apps/catalog/src/stories/DashboardFilters.stories.tsx +0 -1
  220. package/templates/.agents/design/packages/local-runtime/package.json +1 -1
  221. package/templates/.agents/requirements/autonomous-assurance.md +1 -1
  222. package/templates/.agents/requirements/cloud-hostinger-autonomy.md +1 -1
  223. package/templates/.agents/requirements/comparative-audit.md +1 -1
  224. package/templates/.agents/requirements/context-engine.md +1 -1
  225. package/templates/.agents/requirements/cost-observability.md +1 -1
  226. package/templates/.agents/requirements/dashboard-launch.md +1 -1
  227. package/templates/.agents/requirements/data-export.md +1 -1
  228. package/templates/.agents/requirements/design-system.md +1 -1
  229. package/templates/.agents/requirements/execution-engine.md +1 -1
  230. package/templates/.agents/requirements/kanban-dashboard.md +1 -1
  231. package/templates/.agents/requirements/model-orchestration.md +6 -6
  232. package/templates/.agents/requirements/public-distribution.md +1 -1
  233. package/templates/.agents/requirements/software-architecture.md +1 -1
  234. package/templates/.agents/requirements/strategic-improvements.md +1 -1
  235. package/templates/.agents/requirements/work-lifecycle.md +1 -1
  236. package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
  237. package/templates/.agents/rules/autonomy-decision.md +2 -2
  238. package/templates/.agents/rules/workflow.md +1 -1
  239. package/templates/.agents/runtime/VERSION +1 -1
  240. package/templates/.agents/runtime/bin/zaip.mjs +73 -64
  241. package/templates/.agents/runtime/checksums.sha256 +5 -5
  242. package/templates/.agents/runtime/manifest.json +1 -1
  243. package/templates/.agents/runtime/provenance.json +4 -4
  244. package/templates/.agents/runtime/sbom.cdx.json +1 -1
  245. package/templates/.agents/skills/zaip-skill-adapters/SKILL.md +1 -1
  246. package/templates/.agents/skills/zaip-skill-executar-fila-pronta/SKILL.md +7 -7
  247. package/templates/.agents/skills/zaip-skill-executar-fila-pronta/scripts/ready-queue-fence.mjs +32 -7
  248. package/templates/.agents/skills/zaip-skill-executar-fila-pronta/scripts/ready-queue-fence.test.mjs +134 -1
  249. package/templates/.agents/skills/zaip-skill-executar-fila-pronta/scripts/ready-queue-lease.mjs +57 -0
  250. package/templates/.agents/skills/zaip-skill-executar-fila-pronta/scripts/scheduled-ready-queue-contract.test.mjs +9 -6
  251. package/templates/.agents/skills/zaip-skill-execution/SKILL.md +1 -1
  252. package/templates/.agents/skills/zaip-skill-execution/references/runtime-governance.md +2 -2
  253. package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +5 -5
  254. package/templates/.agents/skills/zaip-skill-github-deploy/agents/openai.yaml +2 -2
  255. package/templates/.agents/skills/zaip-skill-github-deploy/references/deployment-workflow.md +5 -3
  256. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/github-deploy-contract.test.mjs +40 -5
  257. package/templates/.agents/skills/zaip-skill-instalar-agendamento/SKILL.md +2 -2
  258. package/templates/.agents/skills/zaip-skill-release-qualification/SKILL.md +6 -0
  259. package/templates/.agents/skills/zaip-skill-release-qualification/references/local-preparation.md +54 -6
  260. package/templates/.agents/zaip-aios/README.md +4 -4
  261. package/templates/.agents/zaip-aios/VERSION +1 -1
  262. package/templates/.agents/zaip-aios/guides/01-primeiros-passos.md +4 -3
  263. package/templates/.agents/zaip-aios/guides/03-tasks.md +5 -4
  264. package/templates/.agents/zaip-aios/guides/04-specs.md +4 -1
  265. package/templates/.agents/zaip-aios/guides/05-prds.md +7 -3
  266. package/templates/.agents/zaip-aios/guides/06-execucao.md +9 -4
  267. package/templates/.agents/zaip-aios/guides/09-agentes-e-squads.md +9 -5
  268. package/templates/.agents/zaip-aios/guides/11-observabilidade-e-custos.md +10 -2
  269. package/templates/.agents/zaip-aios/guides/12-instalacao-e-upgrade.md +10 -5
  270. package/templates/.agents/zaip-aios/guides/13-boas-praticas.md +12 -1
  271. package/templates/.agents/zaip-aios/guides/14-troubleshooting.md +3 -1
  272. package/templates/.agents/zaip-aios/guides/16-lifecycle-e-reconciliacao.md +12 -7
  273. package/templates/.agents/zaip-aios/guides/17-como-o-custo-e-calculado.md +1 -1
  274. package/templates/.agents/zaip-aios/guides/18-catalogo-de-agentes.md +5 -1
  275. package/templates/.agents/zaip-aios/guides/19-assurance-e-autonomia.md +19 -15
  276. package/templates/.agents/zaip-aios/guides/20-instalacao-detalhada.md +13 -9
  277. package/templates/.agents/zaip-aios/guides/21-telemetria-monitor-custos.md +4 -3
  278. package/templates/.agents/zaip-aios/guides/22-fluxos-e-roteamento.md +9 -7
  279. package/templates/.agents/zaip-aios/guides/23-orquestracao-de-modelos.md +40 -25
  280. package/templates/.agents/zaip-aios/guides/24-calculo-de-custos-openai.md +8 -8
  281. package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +14 -5
  282. package/templates/.agents/zaip-aios/guides/27-telemetria-git-native.md +6 -0
  283. package/templates/.agents/zaip-aios/guides/28-lifecycle-completo.md +129 -11
  284. package/templates/template-manifest.json +310 -218
  285. package/templates/tsconfig.base.json +22 -0
  286. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-OulA4CoX.js +0 -3
  287. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-j3aUYH5G.js +0 -68
  288. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-CqfSgtk9.js +0 -2
@@ -1,6 +1,10 @@
1
+ import { execFile } from "node:child_process";
1
2
  import { createHash } from "node:crypto";
2
3
  import { readdir, readFile, stat } from "node:fs/promises";
3
4
  import { join, relative, resolve } from "node:path";
5
+ import { promisify } from "node:util";
6
+
7
+ const execFileAsync = promisify(execFile);
4
8
 
5
9
  const textExtensions = new Set([".json", ".jsonl", ".md", ".yaml", ".yml", ".txt"]);
6
10
 
@@ -45,8 +49,141 @@ export type SqliteReadModelSourceCheckpoint = Omit<SqliteReadModelSourceCandidat
45
49
  type FingerprintOptions = {
46
50
  previous?: ReadonlyMap<string, SqliteReadModelSourceCheckpoint>;
47
51
  verifyContent?: boolean;
52
+ /** Explicit roots allow deterministic testing without a Git checkout. */
53
+ sourceRoots?: readonly string[] | undefined;
48
54
  };
49
55
 
56
+ export async function dashboardCanonicalSourceRoots(workspaceRoot: string): Promise<string[]> {
57
+ const primary = resolve(workspaceRoot);
58
+ const gitRoot = await execFileAsync("git", ["rev-parse", "--show-toplevel"], {
59
+ cwd: primary,
60
+ encoding: "utf8",
61
+ windowsHide: true,
62
+ timeout: 5_000,
63
+ }).catch(() => ({ stdout: "" }));
64
+ if (resolve(gitRoot.stdout.trim()).toLowerCase() !== primary.toLowerCase()) return [primary];
65
+ const output = await execFileAsync("git", ["worktree", "list", "--porcelain"], {
66
+ cwd: primary,
67
+ encoding: "utf8",
68
+ windowsHide: true,
69
+ timeout: 15_000,
70
+ }).catch(() => ({ stdout: "" }));
71
+ // Git supplies only worktrees registered to this repository. Ignore unrelated
72
+ // sibling folders and ordinary task workspaces; they are not Codex worktrees.
73
+ const registeredRoots = output.stdout
74
+ .split(/\r?\n/u)
75
+ .filter((line) => line.startsWith("worktree "))
76
+ .map((line) => resolve(line.slice(9).trim()));
77
+ const codexRoots = registeredRoots.filter(isCodexManagedWorktreeRoot);
78
+ // The first registered checkout is the repository's main worktree and may
79
+ // contain canonical history absent from a Codex worktree's branch.
80
+ return [...new Set([primary, ...registeredRoots.slice(0, 1), ...codexRoots])];
81
+ }
82
+
83
+ export function isCodexManagedWorktreeRoot(root: string): boolean {
84
+ // Internal Task workspaces can sit below a managed checkout but are not
85
+ // separate Codex checkouts. Avoid re-scanning that nested copy on every
86
+ // dashboard refresh.
87
+ return /[\\/]\.codex[\\/]worktrees(?:[\\/][^\\/]+){1,2}$/iu.test(root);
88
+ }
89
+
90
+ function canonicalRevision(content: string, source: string): [string, number, number] {
91
+ if (source.endsWith(".jsonl")) {
92
+ const dates = [...content.matchAll(/"occurred_at"\s*:\s*"([^"]+)"/gu)];
93
+ return [
94
+ dates.reduce((latest, match) => ((match[1] ?? "") > latest ? (match[1] ?? "") : latest), ""),
95
+ dates.length,
96
+ content.length,
97
+ ];
98
+ }
99
+ const updated = /^updated_at:\s*([^\r\n]+)/mu.exec(content)?.[1]?.trim() ?? "";
100
+ const created = /^created_at:\s*([^\r\n]+)/mu.exec(content)?.[1]?.trim() ?? "";
101
+ const revision = Number(/^revision:\s*(\d+)/mu.exec(content)?.[1] ?? 0);
102
+ return [updated || created, revision, content.length];
103
+ }
104
+
105
+ async function selectCanonicalSources(
106
+ roots: readonly string[],
107
+ ): Promise<Array<{ path: string; source: string }>> {
108
+ const locations = new Map<string, string[]>();
109
+ for (const [index, root] of roots.entries()) {
110
+ const directories =
111
+ index === 0
112
+ ? [
113
+ ".agents/config",
114
+ ...[
115
+ "tasks",
116
+ "specs",
117
+ "prds",
118
+ "runs",
119
+ "executions",
120
+ "changes",
121
+ "lifecycle/historical-developer-attribution",
122
+ ].flatMap((kind) => [`.agents/data/${kind}`, `.agents/records/${kind}`]),
123
+ ]
124
+ : [
125
+ "tasks",
126
+ "specs",
127
+ "prds",
128
+ "runs",
129
+ "executions",
130
+ "changes",
131
+ "lifecycle/historical-developer-attribution",
132
+ ].map((kind) => `.agents/records/${kind}`);
133
+ const paths = (
134
+ await Promise.all(directories.map((directory) => listFiles(resolve(root, directory))))
135
+ ).flat();
136
+ for (const path of paths) {
137
+ const source = relative(root, path).replaceAll("\\", "/");
138
+ if (
139
+ !textExtensions.has(path.slice(path.lastIndexOf(".")).toLowerCase()) ||
140
+ !isDashboardCanonicalSource(source)
141
+ )
142
+ continue;
143
+ const peers = locations.get(source) ?? [];
144
+ peers.push(path);
145
+ locations.set(source, peers);
146
+ }
147
+ }
148
+ const selected: Array<{ path: string; source: string }> = [];
149
+ const entries = [...locations.entries()];
150
+ for (let offset = 0; offset < entries.length; offset += 32) {
151
+ selected.push(
152
+ ...(await Promise.all(
153
+ entries.slice(offset, offset + 32).map(async ([source, paths]) => {
154
+ const firstPath = paths[0];
155
+ if (firstPath === undefined) throw new Error(`No canonical source for ${source}`);
156
+ if (paths.length === 1) return { source, path: firstPath };
157
+ // Worktree checkout mtimes do not represent canonical record recency.
158
+ // Compare embedded revision timestamps and prefer the first registered
159
+ // source on an exact tie, so repeated scans remain deterministic.
160
+ const revisions = await Promise.all(
161
+ paths.map(async (path) => canonicalRevision(await readFile(path, "utf8"), source)),
162
+ );
163
+ let winner = 0;
164
+ for (let index = 1; index < paths.length; index += 1) {
165
+ const left = revisions[index];
166
+ const right = revisions[winner];
167
+ if (left === undefined || right === undefined)
168
+ throw new Error(`Incomplete canonical revisions for ${source}`);
169
+ if (
170
+ left[0] > right[0] ||
171
+ (left[0] === right[0] &&
172
+ (left[1] > right[1] || (left[1] === right[1] && left[2] > right[2])))
173
+ )
174
+ winner = index;
175
+ }
176
+ const selectedPath = paths[winner];
177
+ if (selectedPath === undefined)
178
+ throw new Error(`No selected canonical source for ${source}`);
179
+ return { source, path: selectedPath };
180
+ }),
181
+ )),
182
+ );
183
+ }
184
+ return selected.sort((left, right) => left.source.localeCompare(right.source));
185
+ }
186
+
50
187
  export async function sourceFingerprint(
51
188
  workspaceRoot: string,
52
189
  options: FingerprintOptions = {},
@@ -56,29 +193,9 @@ export async function sourceFingerprint(
56
193
  hashedFiles: number;
57
194
  reusedFiles: number;
58
195
  }> {
59
- const candidates = (
60
- await Promise.all(
61
- [
62
- ".agents/config",
63
- ...[
64
- "tasks",
65
- "specs",
66
- "prds",
67
- "runs",
68
- "executions",
69
- "changes",
70
- "lifecycle/historical-developer-attribution",
71
- ].flatMap((kind) => [`.agents/data/${kind}`, `.agents/records/${kind}`]),
72
- ].map((root) => listFiles(resolve(workspaceRoot, root))),
73
- )
74
- )
75
- .flat()
76
- .filter(
77
- (path) =>
78
- textExtensions.has(path.slice(path.lastIndexOf(".")).toLowerCase()) &&
79
- isDashboardCanonicalSource(relative(workspaceRoot, path).replaceAll("\\", "/")),
80
- )
81
- .sort();
196
+ const candidates = await selectCanonicalSources(
197
+ options.sourceRoots ?? (await dashboardCanonicalSourceRoots(workspaceRoot)),
198
+ );
82
199
  const candidatesWithMetadata: SqliteReadModelSourceCandidate[] = [];
83
200
  let hashedFiles = 0;
84
201
  let reusedFiles = 0;
@@ -91,8 +208,7 @@ export async function sourceFingerprint(
91
208
  candidatesWithMetadata.push(
92
209
  ...(
93
210
  await Promise.all(
94
- candidates.slice(offset, offset + 32).map(async (candidate) => {
95
- const source = relative(workspaceRoot, candidate).replaceAll("\\", "/");
211
+ candidates.slice(offset, offset + 32).map(async ({ path: candidate, source }) => {
96
212
  try {
97
213
  for (let attempt = 0; attempt < 3; attempt += 1) {
98
214
  const metadata = await stat(candidate);
@@ -0,0 +1,60 @@
1
+ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
2
+ import { join, resolve } from "node:path";
3
+ import { DatabaseSync } from "node:sqlite";
4
+ import { describe, expect, it } from "vitest";
5
+ import { rebuildSqliteReadModel } from "./sqlite-read-model.js";
6
+
7
+ const tempRoot = join(
8
+ resolve(import.meta.dirname, "../../../../../.."),
9
+ ".tmp",
10
+ "sqlite-read-model-tests",
11
+ );
12
+
13
+ describe("SQLite worktree source aggregation", () => {
14
+ it("materializes recent worktree Tasks once and refreshes when a sibling changes", async () => {
15
+ await mkdir(tempRoot, { recursive: true });
16
+ const root = await mkdtemp(join(tempRoot, "fixture-"));
17
+ const sibling = await mkdtemp(join(tempRoot, "fixture-"));
18
+ try {
19
+ await mkdir(join(root, ".agents/config"), { recursive: true });
20
+ await mkdir(join(root, ".agents/records/tasks"), { recursive: true });
21
+ await mkdir(join(sibling, ".agents/records/tasks"), { recursive: true });
22
+ await writeFile(join(root, ".agents/config/project.yaml"), "zaip:\n enabled: true\n");
23
+ const oldRecord =
24
+ "---\nid: TASK-DUPLICATE\ntitle: Old\nstatus: executing\ncreated_at: 2026-09-17T10:00:00Z\nupdated_at: 2026-09-17T10:00:00Z\n---\n";
25
+ const newRecord = oldRecord.replace("Old", "Recent").replaceAll("2026-09-17", "2026-09-23");
26
+ await writeFile(join(root, ".agents/records/tasks/TASK-DUPLICATE.md"), oldRecord);
27
+ await writeFile(join(sibling, ".agents/records/tasks/TASK-DUPLICATE.md"), newRecord);
28
+ await writeFile(
29
+ join(sibling, ".agents/records/tasks/TASK-NEW.md"),
30
+ newRecord.replaceAll("TASK-DUPLICATE", "TASK-NEW"),
31
+ );
32
+ const options = { sourceRoots: [root, sibling] };
33
+ await rebuildSqliteReadModel(root, options);
34
+ const database = new DatabaseSync(join(root, ".local/sqlite/zaip-aios-dashboard.sqlite"), {
35
+ readOnly: true,
36
+ });
37
+ try {
38
+ expect(
39
+ database.prepare("SELECT count(*) AS n FROM zaip_vw_task_summary").get(),
40
+ ).toMatchObject({ n: 2 });
41
+ expect(
42
+ database
43
+ .prepare("SELECT task_count FROM zaip_vw_daily_aggregates WHERE day=?")
44
+ .get("2026-09-23"),
45
+ ).toMatchObject({ task_count: 2 });
46
+ } finally {
47
+ database.close();
48
+ }
49
+ await writeFile(
50
+ join(sibling, ".agents/records/tasks/TASK-THIRD.md"),
51
+ newRecord.replaceAll("TASK-DUPLICATE", "TASK-THIRD"),
52
+ );
53
+ const refreshed = await rebuildSqliteReadModel(root, options);
54
+ expect(refreshed.refresh.added_sources).toBe(1);
55
+ } finally {
56
+ await rm(root, { recursive: true, force: true });
57
+ await rm(sibling, { recursive: true, force: true });
58
+ }
59
+ });
60
+ });
@@ -0,0 +1,13 @@
1
+ import { persistedSourceCheckpoint } from "./sqlite-read-model-schema.js";
2
+
3
+ export interface SqliteRebuildOptions {
4
+ forceCanonical?: boolean;
5
+ preferExisting?: boolean;
6
+ sourceRoots?: readonly string[];
7
+ }
8
+
9
+ export function rebuildFingerprintOptions(path: string, options: SqliteRebuildOptions) {
10
+ return options.forceCanonical
11
+ ? { verifyContent: true, sourceRoots: options.sourceRoots }
12
+ : { previous: persistedSourceCheckpoint(path), sourceRoots: options.sourceRoots };
13
+ }
@@ -1,5 +1,9 @@
1
+ import { execFile } from "node:child_process";
1
2
  import { createServer as createHttpServer } from "node:http";
2
3
  import { basename } from "node:path";
4
+ import { promisify } from "node:util";
5
+
6
+ const execFileAsync = promisify(execFile);
3
7
 
4
8
  const escapeHtml = (text) =>
5
9
  String(text).replace(
@@ -8,6 +12,21 @@ const escapeHtml = (text) =>
8
12
  ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[character],
9
13
  );
10
14
 
15
+ async function githubRepository(workspaceRoot) {
16
+ if (!workspaceRoot) return null;
17
+ try {
18
+ const { stdout } = await execFileAsync(
19
+ "git",
20
+ ["-C", workspaceRoot, "remote", "get-url", "origin"],
21
+ { encoding: "utf8", windowsHide: true, timeout: 1500 },
22
+ );
23
+ const match = stdout.trim().match(/github\.com(?::|\/)([^/\s]+)\/([^/\s]+?)(?:\.git)?$/i);
24
+ return match ? `${match[1]}/${match[2]}` : null;
25
+ } catch {
26
+ return null;
27
+ }
28
+ }
29
+
11
30
  export async function createDashboardLaunchPage({
12
31
  port,
13
32
  host,
@@ -16,6 +35,10 @@ export async function createDashboardLaunchPage({
16
35
  delay,
17
36
  workspaceRoot = "",
18
37
  }) {
38
+ const repository = await githubRepository(workspaceRoot);
39
+ const repositoryBadge = repository
40
+ ? `<a class="repository-badge" href="https://github.com/${escapeHtml(repository)}" target="_blank" rel="noopener noreferrer" aria-label="Repositório GitHub ${escapeHtml(repository)}"><svg aria-hidden="true" viewBox="0 0 16 16" fill="currentColor"><path d="M8 0a8 8 0 0 0-2.53 15.59c.4.07.55-.17.55-.39v-1.5c-2.23.49-2.7-.95-2.7-.95-.36-.93-.89-1.18-.89-1.18-.73-.5.05-.49.05-.49.8.06 1.23.82 1.23.82.71 1.22 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.9-3.64-3.95 0-.87.31-1.58.82-2.14-.08-.2-.36-1.01.08-2.11 0 0 .67-.21 2.2.82a7.67 7.67 0 0 1 4 0c1.53-1.03 2.2-.82 2.2-.82.44 1.1.16 1.91.08 2.11.51.56.82 1.27.82 2.14 0 3.06-1.87 3.75-3.65 3.95.28.24.53.71.53 1.44v2.27c0 .22.14.47.55.39A8 8 0 0 0 8 0Z"/></svg>${escapeHtml(repository)}</a>`
41
+ : "";
19
42
  let redirectUrl = null;
20
43
  let failure = null;
21
44
  let progress = {
@@ -86,17 +109,18 @@ export async function createDashboardLaunchPage({
86
109
  <head>
87
110
  <meta charset="utf-8">
88
111
  <meta name="viewport" content="width=device-width,initial-scale=1">
89
- <title>Dashboard Zaip AIOS</title>
112
+ <title>Dashboard ZAIP AIOS</title>
90
113
  <style>
91
114
  :root{color-scheme:dark;font-family:Inter,system-ui,sans-serif;background:#010610;color:#f1f5f9}
92
115
  *{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}
93
116
  .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:not(.handoff):not(.failure){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{position:relative;height:9px;margin-top:20px;border-radius:999px;background:#172033;overflow:hidden}.track::after{content:"";position:absolute;z-index:2;inset:0;background:linear-gradient(90deg,transparent 0%,rgba(224,242,254,.14) 35%,rgba(224,242,254,.8) 50%,rgba(224,242,254,.14) 65%,transparent 100%);transform:translateX(-100%);animation:launch-activity 1.35s ease-in-out infinite;pointer-events:none}.progress.terminal-failure .track::after{animation:none;transform:none;background:rgba(254,202,202,.2)}.progress.terminal-failure .bar{background:#f87171}.bar{position:relative;z-index:1;height:100%;width:4%;border-radius:inherit;background:linear-gradient(90deg,#38bdf8,#818cf8);transition:width .35s ease}@keyframes launch-activity{to{transform:translateX(100%)}}@media (prefers-reduced-motion:reduce){.track::after{animation:none;transform:none;background:linear-gradient(90deg,transparent 0%,rgba(224,242,254,.2) 50%,transparent 100%)}}.handoff,.failure{display:none;margin-top:16px;color:#dbeafe}.failure{color:#fecaca}
94
117
  .activity{min-height:1.3em}.steps{display:grid;gap:7px;max-height:12.5rem;overflow:auto;margin:18px 0 0;padding:0;list-style:none}.steps li{position:relative;padding-left:20px;color:#94a3b8;font-size:.82rem}.steps li::before{content:"";position:absolute;left:1px;top:.4em;width:8px;height:8px;border-radius:50%;background:#475569}.steps li[data-state="active"]{color:#dbeafe}.steps li[data-state="active"]::before{background:#38bdf8;box-shadow:0 0 0 4px rgba(56,189,248,.16)}.progress.terminal-failure .steps li[data-state="active"]::before{background:#f87171}@media (prefers-reduced-motion:reduce){.bar{transition:none}}
118
+ .launch-heading{margin-bottom:18px}.launch-heading h1{margin:0;font-size:clamp(1.2rem,2.4vw,1.55rem)}.workspace-identity{display:flex;flex-wrap:wrap;align-items:center;gap:10px}.repository-badge{display:inline-flex;align-items:center;gap:7px;max-width:100%;padding:6px 10px;border-radius:999px;background:#f8fafc;color:#0f172a;font-size:.78rem;font-weight:700;text-decoration:none;overflow-wrap:anywhere}.repository-badge svg{width:15px;height:15px;flex:none}.repository-badge:focus-visible{outline:2px solid #7dd3fc;outline-offset:3px}
95
119
  </style>
96
120
  </head>
97
121
  <body>
98
122
  <main class="launch-overlay" aria-label="Preparando dashboard" aria-busy="true">
99
- <section class="progress" aria-live="polite" role="status"><div aria-label="Workspace" style="margin-bottom:20px;overflow-wrap:anywhere"><strong>${escapeHtml(basename(workspaceRoot))}</strong><span>${escapeHtml(workspaceRoot)}</span></div><strong id="phase">Iniciando o launcher local</strong><span id="detail">Abrindo a página de preparação.</span><span class="activity" id="activity" aria-hidden="true">Atividade em andamento.</span><div class="track" id="track" role="progressbar" aria-label="Preparação em andamento" aria-valuemin="0" aria-valuemax="100" aria-valuenow="4" aria-valuetext="Iniciando o launcher local"><div class="bar" id="bar"></div></div><ol class="steps" id="steps" aria-label="Etapas de preparação"><li data-state="active">Iniciando o launcher local</li></ol><span class="handoff" id="handoff">O dashboard está pronto. Abrindo a tela principal automaticamente…</span><span class="failure" id="failure" role="alert"></span></section>
123
+ <section class="progress" aria-live="polite" role="status"><div class="launch-heading"><h1>Dashboard ZAIP AIOS</h1></div><div aria-label="Workspace" style="margin-bottom:20px;overflow-wrap:anywhere"><div class="workspace-identity"><strong>${escapeHtml(basename(workspaceRoot))}</strong>${repositoryBadge}</div><span>${escapeHtml(workspaceRoot)}</span></div><strong id="phase">Iniciando o launcher local</strong><span id="detail">Abrindo a página de preparação.</span><span class="activity" id="activity" aria-hidden="true">Atividade em andamento.</span><div class="track" id="track" role="progressbar" aria-label="Preparação em andamento" aria-valuemin="0" aria-valuemax="100" aria-valuenow="4" aria-valuetext="Iniciando o launcher local"><div class="bar" id="bar"></div></div><ol class="steps" id="steps" aria-label="Etapas de preparação"><li data-state="active">Iniciando o launcher local</li></ol><span class="handoff" id="handoff">O dashboard está pronto. Abrindo a tela principal automaticamente…</span><span class="failure" id="failure" role="alert"></span></section>
100
124
  </main>
101
125
  <script>
102
126
  let handoffTarget=null,progressRequestInFlight=false,terminalFailure=false,lastProgressPercent=4,compilationStartedAt=null,compilationDetail="",compilationTicker=null,activeStepKey="",activeStepStartedAt=Date.now();
@@ -12,6 +12,9 @@ describe("dashboard launch page", () => {
12
12
 
13
13
  expect(page.status).toBe(200);
14
14
  const html = await page.text();
15
+ expect(html).toContain("<h1>Dashboard ZAIP AIOS</h1>");
16
+ expect(html).toContain('class="repository-badge"');
17
+ expect(html).toContain("zaip-ai/zaip-aios</a>");
15
18
  expect(html).toContain('class="launch-overlay"');
16
19
  expect(html).toContain("position:fixed;inset:0;width:100vw;height:100vh");
17
20
  expect(html).toContain("display:grid;place-items:center");
@@ -69,6 +72,8 @@ describe("dashboard launch page", () => {
69
72
  );
70
73
  await page.route("**/api/v2/health", () => new Promise(() => {}));
71
74
  await page.goto(`http://${host}:${launchPage.port}/?token=temporary`);
75
+ if (process.env.ZAIP_LAUNCH_SCREENSHOT_PATH)
76
+ await page.screenshot({ path: process.env.ZAIP_LAUNCH_SCREENSHOT_PATH });
72
77
 
73
78
  await expect
74
79
  .poll(() =>
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zaip-ai/dashboard-ui",
3
- "version": "3.7.0",
3
+ "version": "4.0.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -2,6 +2,7 @@ import { readFileSync } from "node:fs";
2
2
  import { describe, expect, it } from "vitest";
3
3
 
4
4
  const styles = readFileSync(new URL("ui.css", import.meta.url), "utf8");
5
+ const headerSource = readFileSync(new URL("DashboardHeader.tsx", import.meta.url), "utf8");
5
6
 
6
7
  describe("DashboardHeader", () => {
7
8
  it("optically balances the repository badge horizontal spacing", () => {
@@ -9,6 +10,10 @@ describe("DashboardHeader", () => {
9
10
  expect(rule).toContain("padding-block: 0.3rem");
10
11
  expect(rule).toContain("padding-inline: 0.6rem 0.72rem");
11
12
  });
13
+ it("labels the timestamp as telemetry rather than overall snapshot freshness", () => {
14
+ expect(headerSource).toContain('updated: "Última telemetria"');
15
+ expect(headerSource).toContain('waiting: "Sem telemetria medida"');
16
+ });
12
17
  });
13
18
 
14
19
  function cssRule(source, selector) {
@@ -38,8 +38,8 @@ export function DashboardHeader({
38
38
  refresh: "Atualizar",
39
39
  refreshing: "Atualizando…",
40
40
  settings: "Configurações",
41
- updated: "Atualizado",
42
- waiting: "Aguardando atualização",
41
+ updated: "Última telemetria",
42
+ waiting: "Sem telemetria medida",
43
43
  }
44
44
  : {
45
45
  filters: "Filters",
@@ -47,8 +47,8 @@ export function DashboardHeader({
47
47
  refresh: "Refresh",
48
48
  refreshing: "Refreshing…",
49
49
  settings: "Settings",
50
- updated: "Updated",
51
- waiting: "Waiting for refresh",
50
+ updated: "Last telemetry",
51
+ waiting: "No measured telemetry",
52
52
  };
53
53
  const updatedLabel =
54
54
  lastUpdatedAt === null
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zaip-ai/dashboard-e2e",
3
- "version": "3.7.0",
3
+ "version": "4.0.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -42,6 +42,10 @@ export default defineConfig({
42
42
  // Match the Windows launcher: first paint uses the latest validated
43
43
  // immutable seed while canonical refresh work stays off the served path.
44
44
  ZAIP_SQLITE_PREFER_LAST_VALID_SEED: "1",
45
+ // Browser qualification reads a fixed Git candidate. Live host capture
46
+ // would mutate its canonical records during the clean-worktree gate.
47
+ // Source-watch/capture behavior has separate runtime tests.
48
+ ZAIP_DASHBOARD_WATCH_SOURCES: "0",
45
49
  // Keep pre-bind progress observable if the web-server health gate times out.
46
50
  ZAIP_DASHBOARD_LAUNCH_PROGRESS: "1",
47
51
  },
@@ -1,24 +1,13 @@
1
1
  import { expect, type Locator, type Page, test } from "@playwright/test";
2
2
  import { exportRowIdentity } from "./export-row-identity.js";
3
-
4
- type Metric = {
5
- surface: string;
6
- period: "this-month" | "all";
7
- ttfv_ms: number;
8
- settled_ms: number;
9
- request_count: number;
10
- };
11
-
12
- type SqlitePage = {
13
- offset: number;
14
- limit: number;
15
- total_count: number;
16
- has_more: boolean;
17
- rows: readonly Record<string, unknown>[];
18
- };
3
+ import type { Metric, SqlitePage } from "./performance-matrix-types.js";
4
+ import {
5
+ assertPerformanceWarnings,
6
+ observePerformanceWarnings,
7
+ } from "./performance-observability.js";
8
+ import { workRowIdentities } from "./performance-work-row-identity.js";
19
9
 
20
10
  type PeriodQuery = { from: string | null; to: string | null };
21
-
22
11
  const costViews = [
23
12
  ["Diário", "daily", "cost_monitor_daily"],
24
13
  ["Mensal", "monthly", "cost_monitor_monthly"],
@@ -91,11 +80,12 @@ test("measures Cost, Operation and Traceability surfaces without full snapshot h
91
80
  page.on("requestfinished", finishApiRequest);
92
81
  page.on("requestfailed", finishApiRequest);
93
82
  page.on("response", (response) => {
83
+ const startedAt = requestStartedAt.get(response.request());
84
+ const elapsed = startedAt === undefined ? undefined : performance.now() - startedAt;
94
85
  if (process.env.ZAIP_E2E_LOG_TIMINGS === "1") {
95
- const startedAt = requestStartedAt.get(response.request());
96
- if (startedAt !== undefined) {
86
+ if (elapsed !== undefined) {
97
87
  console.log(
98
- `DASHBOARD_API_TIMING ${Math.round(performance.now() - startedAt)}ms ${response.status()} ${response.url()}`,
88
+ `DASHBOARD_API_TIMING ${Math.round(elapsed)}ms ${response.status()} ${response.url()}`,
99
89
  );
100
90
  }
101
91
  }
@@ -115,6 +105,7 @@ test("measures Cost, Operation and Traceability surfaces without full snapshot h
115
105
  }
116
106
  });
117
107
  page.on("pageerror", (error) => pageErrors.push(error.message));
108
+ const performanceWarnings = observePerformanceWarnings(page, requestStartedAt);
118
109
 
119
110
  await installExportSink(page);
120
111
  await openDashboard(page);
@@ -156,6 +147,7 @@ test("measures Cost, Operation and Traceability surfaces without full snapshot h
156
147
  await verifyCompleteWorkListExport(page);
157
148
 
158
149
  expect(pageErrors).toEqual([]);
150
+ assertPerformanceWarnings(performanceWarnings);
159
151
  expect(apiFailures).toEqual([]);
160
152
  expect(idleSnapshots).toEqual([]);
161
153
  console.log(`DASHBOARD_PERFORMANCE_MATRIX ${JSON.stringify(metrics)}`);
@@ -359,7 +351,7 @@ async function assertWorkListPagination(
359
351
  const totalText = await pager.locator("output").textContent();
360
352
  const total = Number(totalText?.match(/de\s+(\d+)/)?.[1] ?? 0);
361
353
  if (total > 10) {
362
- const firstPageRows = await rowSignatures(rows);
354
+ const firstPageRows = await workRowIdentities(rows);
363
355
  const next = pager.getByRole("button", { name: "Próxima" });
364
356
  await expect(next).toBeEnabled();
365
357
  await assertNoFullscreenOverlay(page);
@@ -369,7 +361,7 @@ async function assertWorkListPagination(
369
361
  await expect(pager.locator("output")).toContainText("11–", { timeout: 10_000 });
370
362
  await expect(rows).toHaveCount(Math.min(10, total - 10), { timeout: 10_000 });
371
363
  await expect(surface).not.toHaveAttribute("aria-busy", "true", { timeout: 10_000 });
372
- expect(await rowSignatures(rows)).not.toEqual(firstPageRows);
364
+ expect(await workRowIdentities(rows)).not.toEqual(firstPageRows);
373
365
  // Filter hydration must not reset an already loaded page after navigation.
374
366
  await waitForApiQuiet(matchesSelection);
375
367
  await expect(pager.locator("output")).toContainText("11–", { timeout: 10_000 });
@@ -381,7 +373,7 @@ async function assertWorkListPagination(
381
373
  await expect(pager.locator("output")).toContainText("1–", { timeout: 10_000 });
382
374
  await expect(rows).toHaveCount(Math.min(10, total), { timeout: 10_000 });
383
375
  await expect(surface).not.toHaveAttribute("aria-busy", "true", { timeout: 10_000 });
384
- expect(await rowSignatures(rows)).toEqual(firstPageRows);
376
+ expect(await workRowIdentities(rows)).toEqual(firstPageRows);
385
377
  await assertNoFullscreenOverlay(page);
386
378
  }
387
379
  }
@@ -173,7 +173,7 @@ test("renders the modern read-only dashboard and meets accessibility gates", asy
173
173
  // Identity is loaded independently; both the initial title and the title
174
174
  // with the observed repository identify the same accessible navigation.
175
175
  await expect(
176
- page.getByRole("navigation", { name: /^Dashboard Zaip AIOS(?: .+)? menu$/ }),
176
+ page.getByRole("navigation", { name: /^Dashboard ZAIP AIOS(?: .+)? menu$/ }),
177
177
  ).toBeVisible();
178
178
  const capabilityNav = page.getByRole("navigation", { name: "Áreas do dashboard" });
179
179
  const globalControls = page.locator(".dashboard-global-controls");
@@ -0,0 +1,15 @@
1
+ export type Metric = {
2
+ surface: string;
3
+ period: "this-month" | "all";
4
+ ttfv_ms: number;
5
+ settled_ms: number;
6
+ request_count: number;
7
+ };
8
+
9
+ export type SqlitePage = {
10
+ offset: number;
11
+ limit: number;
12
+ total_count: number;
13
+ has_more: boolean;
14
+ rows: readonly Record<string, unknown>[];
15
+ };
@@ -0,0 +1,30 @@
1
+ import { expect, type Page, type Request } from "@playwright/test";
2
+
3
+ export function observePerformanceWarnings(page: Page, requestStartedAt: WeakMap<Request, number>) {
4
+ const reactKeyWarnings: string[] = [];
5
+ const healthAndReadyTimings: number[] = [];
6
+ page.on("response", (response) => {
7
+ const startedAt = requestStartedAt.get(response.request());
8
+ if (startedAt === undefined) return;
9
+ if (["/api/v2/health", "/api/v2/ready"].includes(new URL(response.url()).pathname)) {
10
+ healthAndReadyTimings.push(performance.now() - startedAt);
11
+ }
12
+ });
13
+ page.on("console", (message) => {
14
+ if (message.type() === "warning" && /unique "key"|unique key/i.test(message.text())) {
15
+ reactKeyWarnings.push(message.text());
16
+ }
17
+ });
18
+ return { healthAndReadyTimings, reactKeyWarnings };
19
+ }
20
+
21
+ export function assertPerformanceWarnings(
22
+ observations: ReturnType<typeof observePerformanceWarnings>,
23
+ ) {
24
+ expect(observations.reactKeyWarnings).toEqual([]);
25
+ expect(observations.healthAndReadyTimings.length).toBeGreaterThan(0);
26
+ expect(
27
+ Math.max(...observations.healthAndReadyTimings),
28
+ "health and ready remain responsive under load",
29
+ ).toBeLessThan(10_000);
30
+ }
@@ -0,0 +1,6 @@
1
+ import type { Locator } from "@playwright/test";
2
+
3
+ /** Live telemetry can change metrics while a paginated row keeps the same identity. */
4
+ export function workRowIdentities(rows: Locator): Promise<string[]> {
5
+ return rows.locator(".operations-work-list-identity small").allTextContents();
6
+ }