@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
@@ -26,6 +26,37 @@ describe("active Codex telemetry capture", () => {
26
26
  });
27
27
  });
28
28
 
29
+ it("does not execute a CLI against historical running entries in a stale worktree", async () => {
30
+ const root = await runtimeFixture("process.exitCode = 8;\n");
31
+ await writeFile(
32
+ join(root, ".agents/records/lifecycle/active-work.json"),
33
+ JSON.stringify({
34
+ schema_version: 1,
35
+ items: [{ kind: "run", status: "running", updated_at: "2026-09-01T00:00:00Z" }],
36
+ }),
37
+ );
38
+ await expect(captureActiveCodexTelemetry(root)).resolves.toMatchObject({
39
+ skipped_reason: "no_recent_active_runs",
40
+ captured_runs: 0,
41
+ });
42
+ });
43
+ it("still captures a recently active worktree Run", async () => {
44
+ const root = await runtimeFixture(
45
+ "process.stdout.write(JSON.stringify({telemetry:{captured:[{captured:true}]}}));\n",
46
+ );
47
+ await writeFile(
48
+ join(root, ".agents/records/lifecycle/active-work.json"),
49
+ JSON.stringify({
50
+ schema_version: 1,
51
+ items: [{ kind: "run", status: "running", updated_at: new Date().toISOString() }],
52
+ }),
53
+ );
54
+ await expect(captureActiveCodexTelemetry(root)).resolves.toMatchObject({
55
+ captured_runs: 1,
56
+ skipped_reason: null,
57
+ });
58
+ });
59
+
29
60
  it("returns a typed manifest condition when the lifecycle has not been initialized", async () => {
30
61
  const root = await runtimeFixture(
31
62
  "process.stderr.write('Lifecycle manifest is not initialized'); process.exitCode = 1;\n",
@@ -1,8 +1,10 @@
1
1
  import { execFile } from "node:child_process";
2
- import { resolve } from "node:path";
2
+ import { readFile, stat } from "node:fs/promises";
3
+ import { join, resolve } from "node:path";
3
4
  import { promisify } from "node:util";
4
5
  import { WorkspaceFileSystem } from "@zaip-ai/core";
5
6
  import { lifecycleManifestState } from "./server-lifecycle-diagnostics.js";
7
+ import { dashboardCanonicalSourceRoots } from "./sqlite-read-model-source-fingerprint.js";
6
8
 
7
9
  const execFileAsync = promisify(execFile);
8
10
 
@@ -15,6 +17,7 @@ export type ActiveCodexTelemetryCapture = {
15
17
  | "manifest_uninitialized"
16
18
  | "manifest_invalid"
17
19
  | "no_active_runs"
20
+ | "no_recent_active_runs"
18
21
  | "no_new_segments"
19
22
  | null;
20
23
  last_capture_at: string;
@@ -39,6 +42,16 @@ export async function captureActiveCodexTelemetry(
39
42
  skipped_reason: manifestState === "missing" ? "manifest_uninitialized" : "manifest_invalid",
40
43
  last_capture_at: new Date().toISOString(),
41
44
  };
45
+ const activeRuns = await recentActiveRuns(workspaceRoot);
46
+ if (activeRuns !== null && activeRuns.recent === 0) {
47
+ return {
48
+ captured_runs: 0,
49
+ captured_segments: 0,
50
+ manifest_state: "initialized",
51
+ skipped_reason: activeRuns.stale > 0 ? "no_recent_active_runs" : "no_active_runs",
52
+ last_capture_at: new Date().toISOString(),
53
+ };
54
+ }
42
55
  const cliPath = resolve(workspaceRoot, ".agents", "runtime", "bin", "zaip.mjs");
43
56
  try {
44
57
  const outcome = await execFileAsync(
@@ -79,6 +92,66 @@ export async function captureActiveCodexTelemetry(
79
92
  }
80
93
  }
81
94
 
95
+ /** A stale lifecycle index is not proof of a live Codex invocation. */
96
+ async function recentActiveRuns(
97
+ workspaceRoot: string,
98
+ ): Promise<{ recent: number; stale: number } | null> {
99
+ const path = join(workspaceRoot, ".agents", "records", "lifecycle", "active-work.json");
100
+ const metadata = await stat(path).catch((error: NodeJS.ErrnoException) => {
101
+ if (error.code === "ENOENT") return null;
102
+ throw error;
103
+ });
104
+ if (metadata === null) return null;
105
+ if (metadata.size > 8 * 1024 * 1024) throw new Error("Active-work index exceeds capture limit");
106
+ const parsed: unknown = JSON.parse(await readFile(path, "utf8"));
107
+ if (
108
+ typeof parsed !== "object" ||
109
+ parsed === null ||
110
+ !Array.isArray((parsed as { items?: unknown }).items)
111
+ )
112
+ throw new Error("Invalid active-work index for telemetry capture");
113
+ const cutoff = Date.now() - 72 * 60 * 60 * 1_000;
114
+ const runs = (parsed as { items: unknown[] }).items.filter(
115
+ (item) =>
116
+ typeof item === "object" &&
117
+ item !== null &&
118
+ (item as { kind?: unknown }).kind === "run" &&
119
+ (item as { status?: unknown }).status === "running",
120
+ );
121
+ const recent = runs.filter((item) => {
122
+ const updated = (item as { updated_at?: unknown }).updated_at;
123
+ return (
124
+ typeof updated === "string" &&
125
+ Number.isFinite(Date.parse(updated)) &&
126
+ Date.parse(updated) >= cutoff
127
+ );
128
+ }).length;
129
+ return { recent, stale: runs.length - recent };
130
+ }
131
+
132
+ /** Capture each canonical checkout before refreshing the combined SQLite view. */
133
+ export async function captureRepositoryActiveCodexTelemetry(
134
+ workspaceRoot: string,
135
+ ): Promise<ActiveCodexTelemetryCapture> {
136
+ const roots = await dashboardCanonicalSourceRoots(workspaceRoot);
137
+ const results = await Promise.all(roots.map((root) => captureActiveCodexTelemetry(root)));
138
+ const primary = results[0];
139
+ if (primary === undefined) throw new Error("No dashboard workspace was discovered");
140
+ const capturedRuns = results.reduce((count, result) => count + result.captured_runs, 0);
141
+ return {
142
+ captured_runs: capturedRuns,
143
+ captured_segments: capturedRuns === 0 ? 0 : null,
144
+ manifest_state: primary.manifest_state,
145
+ skipped_reason:
146
+ capturedRuns > 0
147
+ ? null
148
+ : results.some((result) => result.skipped_reason === "no_new_segments")
149
+ ? "no_new_segments"
150
+ : primary.skipped_reason,
151
+ last_capture_at: new Date().toISOString(),
152
+ };
153
+ }
154
+
82
155
  function parseJsonResult(stdout: string): unknown {
83
156
  if (!stdout.trim()) throw new Error("Active telemetry capture returned no JSON result");
84
157
  try {
@@ -30,9 +30,9 @@ describe("agent catalog settings", () => {
30
30
  const settings = await readAgentCatalogSettings(new WorkspaceFileSystem(workspaceRoot));
31
31
 
32
32
  expect(settings).toMatchObject({
33
- default_model: "gpt-5.6-terra",
33
+ default_model: "gpt-6-sol",
34
34
  default_reasoning_effort: "medium",
35
- allowed_models: ["gpt-5.6-luna", "gpt-5.6-terra", "gpt-5.6-sol", "gpt-6-astra"],
35
+ allowed_models: ["gpt-6-luna", "gpt-6-sol", "gpt-6-astra"],
36
36
  allowed_reasoning_efforts: ["low", "medium", "high", "xhigh"],
37
37
  });
38
38
  });
@@ -47,17 +47,17 @@ describe("agent catalog settings", () => {
47
47
  ]),
48
48
  ).toEqual(
49
49
  expect.arrayContaining([
50
- ["agent-orchestrator", "gpt-5.6-terra", "medium"],
51
- ["agent-builder", "gpt-5.6-terra", "medium"],
52
- ["agent-task-executor", "gpt-5.6-terra", "medium"],
53
- ["agent-analyst", "gpt-5.6-sol", "medium"],
54
- ["agent-finalizer", "gpt-5.6-terra", "medium"],
55
- ["agent-reviewer", "gpt-5.6-terra", "medium"],
56
- ["agent-integrator", "gpt-5.6-terra", "high"],
57
- ["agent-auditor", "gpt-5.6-sol", "high"],
58
- ["agent-text-summarizer", "gpt-5.6-terra", "medium"],
59
- ["agent-data-analyst", "gpt-5.6-terra", "medium"],
60
- ["agent-refactoring-specialist", "gpt-5.6-terra", "medium"],
50
+ ["agent-orchestrator", "gpt-6-sol", "medium"],
51
+ ["agent-builder", "gpt-6-sol", "medium"],
52
+ ["agent-task-executor", "gpt-6-sol", "medium"],
53
+ ["agent-analyst", "gpt-6-sol", "medium"],
54
+ ["agent-finalizer", "gpt-6-sol", "medium"],
55
+ ["agent-reviewer", "gpt-6-sol", "medium"],
56
+ ["agent-integrator", "gpt-6-sol", "high"],
57
+ ["agent-auditor", "gpt-6-sol", "high"],
58
+ ["agent-text-summarizer", "gpt-6-sol", "medium"],
59
+ ["agent-data-analyst", "gpt-6-sol", "medium"],
60
+ ["agent-refactoring-specialist", "gpt-6-sol", "medium"],
61
61
  ]),
62
62
  );
63
63
  expect(current.agents.some((agent) => agent.model.preferred[0] === "policy-selected")).toBe(
@@ -73,7 +73,7 @@ describe("agent catalog settings", () => {
73
73
  ...agent,
74
74
  model: {
75
75
  ...agent.model,
76
- preferred: ["gpt-5.6-terra"],
76
+ preferred: ["gpt-6-sol"],
77
77
  reasoning_effort: "high" as const,
78
78
  },
79
79
  }
@@ -201,7 +201,7 @@ describe("agent catalog settings", () => {
201
201
  const target = current.agents[0];
202
202
  if (target === undefined) throw new Error("Catalog must contain an agent");
203
203
  const options = {
204
- allowed_models: ["gpt-5.6-terra"],
204
+ allowed_models: ["gpt-6-sol"],
205
205
  allowed_reasoning_efforts: ["low", "medium", "high", "xhigh"],
206
206
  };
207
207
 
@@ -269,10 +269,10 @@ describe("project settings persistence", () => {
269
269
  ...current,
270
270
  model_orchestration: {
271
271
  mode: "auto",
272
- default_model: "gpt-5.6-terra",
272
+ default_model: "gpt-6-sol",
273
273
  default_effort: "medium",
274
274
  default_velocity: "standard",
275
- allowed_models: ["gpt-5.6-luna", "gpt-5.6-terra", "gpt-5.6-sol"],
275
+ allowed_models: ["gpt-6-luna", "gpt-6-sol"],
276
276
  allowed_efforts: ["low", "medium", "high", "xhigh"],
277
277
  max_auto_effort: "xhigh",
278
278
  automatic_sources: ["spec", "prd"],
@@ -545,7 +545,7 @@ export function renderSoftwareArchitecture(config: ProjectConfig): string {
545
545
  "",
546
546
  ]);
547
547
  const executionDetails =
548
- config.execution && config.execution.runtime !== "manual"
548
+ config.execution && "autonomous" in config.execution
549
549
  ? [
550
550
  `- **Runtime:** ${config.execution.runtime}`,
551
551
  `- **Provider:** ${markdownCell(config.execution.autonomous.provider)}`,
@@ -31,7 +31,7 @@ describe("dashboard identity endpoint", () => {
31
31
 
32
32
  expect(response.status, await response.clone().text()).toBe(200);
33
33
  await expect(response.json()).resolves.toEqual({
34
- title: "Dashboard Zaip AIOS",
34
+ title: "Dashboard ZAIP AIOS",
35
35
  repository_name: "",
36
36
  });
37
37
  expect(refreshReadModel).not.toHaveBeenCalled();
@@ -1,12 +1,13 @@
1
1
  import { join } from "node:path";
2
2
  import { afterEach, describe, expect, it, vi } from "vitest";
3
3
 
4
- const watchers: Array<{ path: string; listener: () => void }> = [];
4
+ const watchers: Array<{ path: string; listener: () => void; close: ReturnType<typeof vi.fn> }> = [];
5
5
 
6
6
  vi.mock("node:fs", () => ({
7
7
  watch: vi.fn((path: string, _options: unknown, listener: () => void) => {
8
- watchers.push({ path, listener });
9
- return { unref: vi.fn() };
8
+ const close = vi.fn();
9
+ watchers.push({ path, listener, close });
10
+ return { unref: vi.fn(), close };
10
11
  }),
11
12
  }));
12
13
 
@@ -19,6 +20,27 @@ afterEach(() => {
19
20
  });
20
21
 
21
22
  describe("snapshot source synchronization", () => {
23
+ it("observes newly registered checkout records and stops observing removed checkouts", async () => {
24
+ vi.useFakeTimers();
25
+ let roots = ["C:/main", "C:/codex/worktree"];
26
+ const refresh = vi.fn(async () => undefined);
27
+ startSnapshotSynchronization({
28
+ workspaceRoot: roots[0]!,
29
+ discoverSourceRoots: async () => roots,
30
+ staleSeed: false,
31
+ watchSources: true,
32
+ refresh,
33
+ });
34
+ await vi.advanceTimersByTimeAsync(1);
35
+ const sibling = watchers.find(({ path }) => path === join(roots[1]!, ".agents", "records"));
36
+ expect(sibling).toBeDefined();
37
+ sibling?.listener();
38
+ await vi.advanceTimersByTimeAsync(300);
39
+ expect(refresh).toHaveBeenCalled();
40
+ roots = [roots[0]!];
41
+ await vi.advanceTimersByTimeAsync(60_000);
42
+ expect(sibling?.close).toHaveBeenCalledOnce();
43
+ });
22
44
  it("reports capture failure separately while refreshing canonical data", async () => {
23
45
  vi.useFakeTimers();
24
46
  const error = new Error("capture timed out");
@@ -4,6 +4,8 @@ import type { ActiveCodexTelemetryCapture } from "./active-codex-telemetry.js";
4
4
 
5
5
  export function startSnapshotSynchronization(input: {
6
6
  workspaceRoot: string;
7
+ /** Same registered repository sources used by the SQLite fingerprint. */
8
+ discoverSourceRoots?: () => Promise<readonly string[]>;
7
9
  staleSeed: boolean;
8
10
  watchSources: boolean;
9
11
  refresh: () => Promise<void>;
@@ -27,25 +29,58 @@ export function startSnapshotSynchronization(input: {
27
29
  }, 300);
28
30
  pendingRefresh.unref();
29
31
  };
30
- for (const sourceRoot of [
31
- join(input.workspaceRoot, ".agents", "data"),
32
- join(input.workspaceRoot, ".agents", "records"),
33
- join(input.workspaceRoot, ".agents", "config"),
34
- ]) {
32
+ const watchers = new Map<string, ReturnType<typeof watch>>();
33
+ const syncWatchers = (roots: readonly string[]) => {
34
+ const wanted = new Set(
35
+ roots.flatMap((root) =>
36
+ ["data", "records", "config"].map((kind) => join(root, ".agents", kind)),
37
+ ),
38
+ );
39
+ for (const [path, watcher] of watchers) {
40
+ if (!wanted.has(path)) {
41
+ watcher.close();
42
+ watchers.delete(path);
43
+ scheduleRefresh();
44
+ }
45
+ }
46
+ for (const path of wanted) {
47
+ if (watchers.has(path)) continue;
48
+ try {
49
+ const watcher = watch(path, { recursive: true }, scheduleRefresh);
50
+ watcher.unref();
51
+ watchers.set(path, watcher);
52
+ } catch {
53
+ // The periodic fingerprint remains the fallback on unsupported filesystems.
54
+ }
55
+ }
56
+ };
57
+ syncWatchers([input.workspaceRoot]);
58
+ const discover = async () => {
59
+ if (input.discoverSourceRoots === undefined) return;
35
60
  try {
36
- const watcher = watch(sourceRoot, { recursive: true }, scheduleRefresh);
37
- watcher.unref();
38
- } catch {
39
- // Reuse-triggered refresh remains the portable fallback.
61
+ syncWatchers(await input.discoverSourceRoots());
62
+ } catch (error) {
63
+ input.onRefreshFailure?.({ trigger: "source_change", error });
40
64
  }
41
- }
65
+ };
66
+ void discover();
67
+ let captureInFlight = false;
42
68
  const captureAndRefresh = () => {
43
- if (input.captureActiveTelemetry === undefined) return scheduleRefresh();
44
- void input
45
- .captureActiveTelemetry()
46
- .then((result) => input.onCaptureSuccess?.(result))
47
- .catch((error: unknown) => input.onCaptureFailure?.(error))
48
- .finally(scheduleRefresh);
69
+ if (captureInFlight) return;
70
+ captureInFlight = true;
71
+ void (async () => {
72
+ try {
73
+ await discover();
74
+ if (input.captureActiveTelemetry !== undefined) {
75
+ input.onCaptureSuccess?.(await input.captureActiveTelemetry());
76
+ }
77
+ } catch (error) {
78
+ input.onCaptureFailure?.(error);
79
+ } finally {
80
+ scheduleRefresh();
81
+ captureInFlight = false;
82
+ }
83
+ })();
49
84
  };
50
85
  // Run at most once a minute. File watchers only project canonical changes;
51
86
  // they never launch telemetry or lifecycle work.
@@ -514,7 +514,7 @@ describe("dashboard backend snapshot", () => {
514
514
  });
515
515
  await expect(response.json()).resolves.toMatchObject({
516
516
  dashboard: {
517
- title: "Dashboard Zaip AIOS",
517
+ title: "Dashboard ZAIP AIOS",
518
518
  repository_name: "",
519
519
  },
520
520
  operations: { readonly: true, summary: { source_latest_at: "2026-07-14T00:00:05.000Z" } },
@@ -0,0 +1,37 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import type { Context } from "hono";
3
+
4
+ export const DASHBOARD_LOOPBACK_HOST = "127.0.0.1";
5
+
6
+ export function isAllowedOrigin(origin: string): boolean {
7
+ try {
8
+ const parsed = new URL(origin);
9
+ return (
10
+ parsed.protocol === "http:" &&
11
+ (parsed.hostname === DASHBOARD_LOOPBACK_HOST || parsed.hostname === "localhost")
12
+ );
13
+ } catch {
14
+ return false;
15
+ }
16
+ }
17
+
18
+ export function isSafeUiPath(pathname: string): boolean {
19
+ try {
20
+ const decoded = decodeURIComponent(pathname).replaceAll("\\", "/");
21
+ return !decoded.includes("\0") && !decoded.split("/").some((segment) => segment === "..");
22
+ } catch {
23
+ return false;
24
+ }
25
+ }
26
+
27
+ export function defaultSessionToken(): string {
28
+ return process.env.ZAIP_UI_TOKEN ?? randomBytes(24).toString("base64url");
29
+ }
30
+
31
+ export function shouldBootstrapBrowserSession(context: Context): boolean {
32
+ if (context.req.method !== "GET" && context.req.method !== "HEAD") return false;
33
+ if (context.req.path !== "/" && context.req.path !== "/index.html") return false;
34
+ const origin = context.req.header("origin");
35
+ if (origin !== undefined && !isAllowedOrigin(origin)) return false;
36
+ return context.req.header("sec-fetch-site") !== "cross-site";
37
+ }
@@ -11,7 +11,7 @@ export async function dashboardIdentity(
11
11
  filesystem: WorkspaceFileSystem,
12
12
  workspaceRoot: string,
13
13
  ): Promise<{ title: string; repository_name: string }> {
14
- let title = process.env.ZAIP_DASHBOARD_TITLE?.trim() || "Dashboard Zaip AIOS";
14
+ let title = process.env.ZAIP_DASHBOARD_TITLE?.trim() || "Dashboard ZAIP AIOS";
15
15
  let repositorySetting = "auto";
16
16
  try {
17
17
  if (await filesystem.exists(DASHBOARD_CONFIG_PATH)) {
@@ -1,4 +1,3 @@
1
- import { randomBytes } from "node:crypto";
2
1
  import { readFile } from "node:fs/promises";
3
2
  import { basename, resolve } from "node:path";
4
3
  import { serve } from "@hono/node-server";
@@ -9,7 +8,7 @@ import { type Context, Hono } from "hono";
9
8
  import { getCookie, setCookie } from "hono/cookie";
10
9
  import {
11
10
  type ActiveCodexTelemetryCapture,
12
- captureActiveCodexTelemetry,
11
+ captureRepositoryActiveCodexTelemetry,
13
12
  } from "./active-codex-telemetry.js";
14
13
  import { runAgentAdapterSync } from "./agent-adapter-sync.js";
15
14
  import {
@@ -44,10 +43,18 @@ import { startSnapshotSynchronization } from "./server-snapshot-synchronization.
44
43
  import { writeReadModelStartup, writeStartupPhase } from "./server-startup.js";
45
44
  import { selectedCurrency } from "./server-summary-helpers.js";
46
45
  import { registerTraceRoutes } from "./server-trace-routes.js";
46
+ import {
47
+ defaultSessionToken,
48
+ DASHBOARD_LOOPBACK_HOST as HOST,
49
+ isAllowedOrigin,
50
+ isSafeUiPath,
51
+ shouldBootstrapBrowserSession,
52
+ } from "./server-ui-security.js";
47
53
  import {
48
54
  createWorkReconciliation,
49
55
  waitForWorkReconciliation,
50
56
  } from "./server-work-reconciliation.js";
57
+ import { dashboardCanonicalSourceRoots } from "./sqlite-read-model-source-fingerprint.js";
51
58
 
52
59
  export { reconciliationNeedsRefresh } from "./server-work-reconciliation.js";
53
60
 
@@ -76,7 +83,6 @@ export {
76
83
  validateSqliteReadModelSchema,
77
84
  } from "./sqlite-read-model.js";
78
85
 
79
- const HOST = "127.0.0.1";
80
86
  const RUNTIME_KIND = "zaip-dashboard-sqlite-runtime";
81
87
  const SESSION_COOKIE = "zaip-dashboard-sqlite-session";
82
88
 
@@ -98,35 +104,6 @@ interface DashboardAppOptions {
98
104
  launcherOwned?: boolean;
99
105
  }
100
106
 
101
- function isAllowedOrigin(origin: string): boolean {
102
- try {
103
- const parsed = new URL(origin);
104
- return (
105
- parsed.protocol === "http:" && (parsed.hostname === HOST || parsed.hostname === "localhost")
106
- );
107
- } catch {
108
- return false;
109
- }
110
- }
111
- function isSafeUiPath(pathname: string): boolean {
112
- try {
113
- const decoded = decodeURIComponent(pathname).replaceAll("\\", "/");
114
- return !decoded.includes("\0") && !decoded.split("/").some((segment) => segment === "..");
115
- } catch {
116
- return false;
117
- }
118
- }
119
- function defaultSessionToken(): string {
120
- return process.env.ZAIP_UI_TOKEN ?? randomBytes(24).toString("base64url");
121
- }
122
- function shouldBootstrapBrowserSession(context: Context): boolean {
123
- if (context.req.method !== "GET" && context.req.method !== "HEAD") return false;
124
- if (context.req.path !== "/" && context.req.path !== "/index.html") return false;
125
- const origin = context.req.header("origin");
126
- if (origin !== undefined && !isAllowedOrigin(origin)) return false;
127
- return context.req.header("sec-fetch-site") !== "cross-site";
128
- }
129
-
130
107
  /**
131
108
  * Keep the entity/macro details on the snapshot filesystem, while making the
132
109
  * first-fold counters and token/cost facts come from SQL.
@@ -262,11 +239,12 @@ export function createDashboardApp(
262
239
  };
263
240
  startSnapshotSynchronization({
264
241
  workspaceRoot,
242
+ discoverSourceRoots: () => dashboardCanonicalSourceRoots(workspaceRoot),
265
243
  staleSeed: isSqliteSnapshot && snapshotState === "updating",
266
244
  watchSources: isSqliteSnapshot && options.watchSources === true,
267
245
  refresh: rebuildProjection,
268
246
  ...(isSqliteSnapshot && options.watchSources === true
269
- ? { captureActiveTelemetry: () => captureActiveCodexTelemetry(workspaceRoot) }
247
+ ? { captureActiveTelemetry: () => captureRepositoryActiveCodexTelemetry(workspaceRoot) }
270
248
  : {}),
271
249
  onRefreshFailure: projectionRefreshDiagnostics.record,
272
250
  onCaptureSuccess: (result) => {
@@ -30,24 +30,27 @@ import {
30
30
  validateSqliteReadModelSchema,
31
31
  } from "./sqlite-read-model-schema.js";
32
32
  import { sourceFingerprint } from "./sqlite-read-model-source-fingerprint.js";
33
+ import {
34
+ rebuildFingerprintOptions,
35
+ type SqliteRebuildOptions,
36
+ } from "./sqlite-rebuild-fingerprint-options.js";
33
37
  import type { SqliteRebuildResult } from "./sqlite-rebuild-result.js";
34
38
  import { readSnapshotFileCount } from "./sqlite-snapshot-cache.js";
35
39
  import { deriveCanonicalWorkStages } from "./sqlite-work-stages.js";
36
40
  export async function rebuildSqliteReadModel(
37
41
  workspaceRoot: string,
38
- options: { forceCanonical?: boolean; preferExisting?: boolean } = {},
42
+ options: SqliteRebuildOptions = {},
39
43
  ): Promise<SqliteRebuildResult> {
40
44
  const path = sqliteReadModelPath(workspaceRoot);
41
- // A reusable snapshot still has to match its canonical fingerprint. This
42
- // avoids advertising every launch as stale while preserving the stale seed
43
- // path for a changed source or an incompatible database.
45
+ // Reuse only when schema and canonical fingerprint still match; otherwise rebuild.
44
46
  if (options.preferExisting && !options.forceCanonical) {
45
47
  try {
46
48
  validateSqliteReadModelSchema(path);
47
49
  const fingerprintStartedAt = performance.now();
48
- const sourceSnapshot = await sourceFingerprint(workspaceRoot, {
49
- previous: persistedSourceCheckpoint(path),
50
- });
50
+ const sourceSnapshot = await sourceFingerprint(
51
+ workspaceRoot,
52
+ rebuildFingerprintOptions(path, options),
53
+ );
51
54
  const fingerprint = `${sourceSnapshot.fingerprint}\ncurrent_day=${saoPauloDay(new Date().toISOString())}`;
52
55
  const database = new DatabaseSync(path, { readOnly: true });
53
56
  try {
@@ -108,9 +111,7 @@ export async function rebuildSqliteReadModel(
108
111
  reportLaunchProgress("source_fingerprint_started", 8, "Inventariando fontes canônicas.");
109
112
  let sourceSnapshot = await sourceFingerprint(
110
113
  workspaceRoot,
111
- options.forceCanonical
112
- ? { verifyContent: true }
113
- : { previous: persistedSourceCheckpoint(path) },
114
+ rebuildFingerprintOptions(path, options),
114
115
  );
115
116
  let refresh = {
116
117
  reused_sources: sourceSnapshot.reusedFiles,
@@ -157,9 +158,7 @@ export async function rebuildSqliteReadModel(
157
158
  // Capture canonical inputs only after acquiring exclusive writer ownership.
158
159
  sourceSnapshot = await sourceFingerprint(
159
160
  workspaceRoot,
160
- options.forceCanonical
161
- ? { verifyContent: true }
162
- : { previous: persistedSourceCheckpoint(path) },
161
+ rebuildFingerprintOptions(path, options),
163
162
  );
164
163
  refresh = {
165
164
  reused_sources: sourceSnapshot.reusedFiles,
@@ -1,7 +1,9 @@
1
+ import { execFileSync } from "node:child_process";
1
2
  import { mkdir, mkdtemp, rename, rm, stat, utimes, writeFile } from "node:fs/promises";
2
- import { join, resolve } from "node:path";
3
+ import { basename, join, resolve } from "node:path";
3
4
  import { afterEach, describe, expect, it, vi } from "vitest";
4
5
  import {
6
+ isCodexManagedWorktreeRoot,
5
7
  type SqliteReadModelSourceCandidate,
6
8
  sourceFingerprint,
7
9
  } from "./sqlite-read-model-source-fingerprint.js";
@@ -26,6 +28,74 @@ afterEach(async () => {
26
28
  });
27
29
 
28
30
  describe("persistent source fingerprint checkpoints", () => {
31
+ it("includes direct Codex checkouts but not nested Task workspaces", () => {
32
+ expect(isCodexManagedWorktreeRoot("C:\\Users\\david\\.codex\\worktrees\\v38-readiness")).toBe(
33
+ true,
34
+ );
35
+ expect(isCodexManagedWorktreeRoot("/home/david/.codex/worktrees/v38-readiness")).toBe(true);
36
+ expect(isCodexManagedWorktreeRoot("C:\\Users\\david\\.codex\\worktrees\\v38\\zaip-aios")).toBe(
37
+ true,
38
+ );
39
+ expect(isCodexManagedWorktreeRoot("/home/david/.codex/worktrees/v38/zaip-aios")).toBe(true);
40
+ expect(
41
+ isCodexManagedWorktreeRoot(
42
+ "C:\\Users\\david\\.codex\\worktrees\\v38\\zaip-aios\\.local\\task-workspaces\\tree",
43
+ ),
44
+ ).toBe(false);
45
+ });
46
+ it("aggregates registered roots by canonical ID and chooses the newest record, not checkout mtime", async () => {
47
+ const { root, path } = await fixture();
48
+ const sibling = await mkdtemp(
49
+ join(resolve(import.meta.dirname, "../../../../..", ".local/sqlite/tests"), "worktree-"),
50
+ );
51
+ roots.push(sibling);
52
+ const siblingPath = join(sibling, ".agents/records/tasks/task.md");
53
+ await mkdir(join(sibling, ".agents/records/tasks"), { recursive: true });
54
+ await writeFile(path, "---\nid: TASK-1\nupdated_at: 2026-09-17T12:00:00Z\n---\nold\n");
55
+ await writeFile(siblingPath, "---\nid: TASK-1\nupdated_at: 2026-09-23T12:00:00Z\n---\nnew\n");
56
+ await utimes(path, new Date("2026-09-24"), new Date("2026-09-24"));
57
+ const snapshot = await sourceFingerprint(root, { sourceRoots: [root, sibling] });
58
+ expect(snapshot.candidates).toHaveLength(1);
59
+ expect(snapshot.candidates[0]?.path).toBe(siblingPath);
60
+ await writeFile(
61
+ join(sibling, ".agents/records/tasks/another.md"),
62
+ "---\nid: TASK-2\nupdated_at: 2026-09-23T12:00:00Z\n---\n",
63
+ );
64
+ const expanded = await sourceFingerprint(root, { sourceRoots: [root, sibling] });
65
+ expect(expanded.candidates.map((candidate) => candidate.source)).toEqual([
66
+ ".agents/records/tasks/another.md",
67
+ ".agents/records/tasks/task.md",
68
+ ]);
69
+ });
70
+
71
+ it("automatically discovers a registered Codex worktree and includes its canonical Task", async () => {
72
+ const { root } = await fixture();
73
+ execFileSync("git", ["init", "-q", root]);
74
+ execFileSync("git", ["-C", root, "add", ".agents/records/tasks/task.md"]);
75
+ execFileSync("git", [
76
+ "-C",
77
+ root,
78
+ "-c",
79
+ "user.name=Test",
80
+ "-c",
81
+ "user.email=test@example.invalid",
82
+ "commit",
83
+ "-qm",
84
+ "base",
85
+ ]);
86
+ const candidate = join(root, ".codex", "worktrees", "candidate", basename(root));
87
+ await mkdir(resolve(candidate, ".."), { recursive: true });
88
+ execFileSync("git", ["-C", root, "worktree", "add", "-q", "-b", "candidate", candidate]);
89
+ await writeFile(
90
+ join(candidate, ".agents/records/tasks/new.md"),
91
+ "---\nid: TASK-NEW\ncreated_at: 2026-09-23T12:00:00Z\n---\n",
92
+ );
93
+ const discovered = await sourceFingerprint(root);
94
+ expect(discovered.candidates.map((item) => item.source)).toContain(
95
+ ".agents/records/tasks/new.md",
96
+ );
97
+ });
98
+
29
99
  it("includes current data records, retains legacy records, and excludes generated projections", async () => {
30
100
  const { root } = await fixture();
31
101
  await mkdir(join(root, ".agents/data/runs/2026/09"), { recursive: true });