@zaip-ai/cli 2.6.0 → 3.1.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 (312) hide show
  1. package/README.md +36 -13
  2. package/dist/services/adapters.d.ts +1 -1
  3. package/dist/services/adapters.d.ts.map +1 -1
  4. package/dist/services/adapters.js +5 -2
  5. package/dist/services/adapters.js.map +1 -1
  6. package/dist/services/agent-adapters.js +12 -9
  7. package/dist/services/agent-adapters.js.map +1 -1
  8. package/dist/services/codex-conversation-lifecycle-hook.d.ts.map +1 -1
  9. package/dist/services/codex-conversation-lifecycle-hook.js +32 -21
  10. package/dist/services/codex-conversation-lifecycle-hook.js.map +1 -1
  11. package/dist/services/install-agents-template.js +9 -1
  12. package/dist/services/install-agents-template.js.map +1 -1
  13. package/dist/services/runtime-template.test.js +25 -2
  14. package/dist/services/runtime-template.test.js.map +1 -1
  15. package/dist/services/transactional-files.d.ts.map +1 -1
  16. package/dist/services/transactional-files.js +59 -14
  17. package/dist/services/transactional-files.js.map +1 -1
  18. package/package.json +1 -1
  19. package/templates/.agents/README-ENG.md +75 -10
  20. package/templates/.agents/README.md +76 -10
  21. package/templates/.agents/config/agents/catalog.yaml +3 -0
  22. package/templates/.agents/config/agents/discovery.json +2 -2
  23. package/templates/.agents/config/clients/codex/agents/zaip-agent-analyst.toml +1 -1
  24. package/templates/.agents/config/clients/codex/agents/zaip-agent-auditor.toml +1 -1
  25. package/templates/.agents/config/clients/codex/agents/zaip-agent-backend.toml +1 -1
  26. package/templates/.agents/config/clients/codex/agents/zaip-agent-brand-strategist.toml +1 -1
  27. package/templates/.agents/config/clients/codex/agents/zaip-agent-builder.toml +1 -1
  28. package/templates/.agents/config/clients/codex/agents/zaip-agent-cloud-engineer.toml +1 -1
  29. package/templates/.agents/config/clients/codex/agents/zaip-agent-data-analyst.toml +1 -1
  30. package/templates/.agents/config/clients/codex/agents/zaip-agent-designer.toml +1 -1
  31. package/templates/.agents/config/clients/codex/agents/zaip-agent-finalizer.toml +2 -2
  32. package/templates/.agents/config/clients/codex/agents/zaip-agent-frontend.toml +1 -1
  33. package/templates/.agents/config/clients/codex/agents/zaip-agent-general-operations.toml +1 -1
  34. package/templates/.agents/config/clients/codex/agents/zaip-agent-governance-compliance.toml +1 -1
  35. package/templates/.agents/config/clients/codex/agents/zaip-agent-growth-strategist.toml +1 -1
  36. package/templates/.agents/config/clients/codex/agents/zaip-agent-integrator.toml +1 -1
  37. package/templates/.agents/config/clients/codex/agents/zaip-agent-marketing-analyst.toml +1 -1
  38. package/templates/.agents/config/clients/codex/agents/zaip-agent-orchestrator.toml +13 -10
  39. package/templates/.agents/config/clients/codex/agents/zaip-agent-refactoring-specialist.toml +1 -1
  40. package/templates/.agents/config/clients/codex/agents/zaip-agent-reviewer.toml +1 -1
  41. package/templates/.agents/config/clients/codex/agents/zaip-agent-sales-specialist.toml +1 -1
  42. package/templates/.agents/config/clients/codex/agents/zaip-agent-security-auditor.toml +1 -1
  43. package/templates/.agents/config/clients/codex/agents/zaip-agent-task-executor.toml +1 -1
  44. package/templates/.agents/config/clients/codex/agents/zaip-agent-website-developer.toml +1 -1
  45. package/templates/.agents/config/clients/codex/agents/zaip-agent-writer.toml +1 -1
  46. package/templates/.agents/config/project.yaml +10 -1
  47. package/templates/.agents/dashboard/.zaip-managed.json +274 -138
  48. package/templates/.agents/dashboard/README.md +16 -0
  49. package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-CGxeQak4.js → CostCalculationGuidePage-CEDZjl4V.js} +1 -1
  50. package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-tzS7YxYB.js → DashboardHelpDialog-DIWDmvAS.js} +930 -550
  51. package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-DEbCi1gP.js → PricingSettingsDialog-BBRBKaHa.js} +1 -1
  52. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-B9GWkEyN.css +1 -0
  53. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-BAvLPAee.js +3 -0
  54. package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-t1Om0Abw.js → TraceabilityWorkspace-C9dDhj34.js} +1 -1
  55. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-06__WZco.js +68 -0
  56. package/templates/.agents/dashboard/apps/frontend/dist/assets/dashboard-localization-CoAVMZN6.js +828 -0
  57. package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-DiGC-dsJ.js → icons-vendor-DEmo6Tn2.js} +1 -1
  58. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-BVzw_Wux.js +2 -0
  59. package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-kPO6yNed.js → react-vendor-CadYsm83.js} +1 -1
  60. package/templates/.agents/dashboard/apps/frontend/dist/assets/traceability-BzKK8kK3.js +1 -0
  61. package/templates/.agents/dashboard/apps/frontend/dist/index.html +5 -5
  62. package/templates/.agents/dashboard/apps/frontend/package.json +1 -1
  63. package/templates/.agents/dashboard/apps/frontend/src/AppDashboardContent.tsx +10 -5
  64. package/templates/.agents/dashboard/apps/frontend/src/AutonomySettings.tsx +82 -0
  65. package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsPage.dom.test.ts +38 -7
  66. package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsPage.tsx +164 -171
  67. package/templates/.agents/dashboard/apps/frontend/src/__tests__/app-composition-support.ts +6 -1
  68. package/templates/.agents/dashboard/apps/frontend/src/cost-monitor-population.test.tsx +149 -0
  69. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api-settings.ts +2 -1
  70. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +19 -0
  71. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +22 -1
  72. package/templates/.agents/dashboard/apps/frontend/src/dashboard-cost-facts.test.ts +54 -0
  73. package/templates/.agents/dashboard/apps/frontend/src/dashboard-cost-facts.ts +20 -2
  74. package/templates/.agents/dashboard/apps/frontend/src/dashboard-localization.test.ts +37 -43
  75. package/templates/.agents/dashboard/apps/frontend/src/dashboard-localization.ts +9 -251
  76. package/templates/.agents/dashboard/apps/frontend/src/dashboard-project-overview.ts +34 -7
  77. package/templates/.agents/dashboard/apps/frontend/src/dashboard-view-actions.test.ts +51 -0
  78. package/templates/.agents/dashboard/apps/frontend/src/dashboard-view-actions.ts +3 -1
  79. package/templates/.agents/dashboard/apps/frontend/src/operations-period-render.test.ts +35 -0
  80. package/templates/.agents/dashboard/apps/frontend/src/operations-period.test.ts +19 -4
  81. package/templates/.agents/dashboard/apps/frontend/src/operations-period.ts +5 -3
  82. package/templates/.agents/dashboard/apps/frontend/src/project-installation-status.test.ts +112 -23
  83. package/templates/.agents/dashboard/apps/frontend/src/project-installation-status.ts +49 -12
  84. package/templates/.agents/dashboard/apps/frontend/src/project-settings-copy.ts +181 -0
  85. package/templates/.agents/dashboard/apps/frontend/src/project-settings-model.ts +11 -1
  86. package/templates/.agents/dashboard/apps/frontend/src/project-settings-page.css +34 -51
  87. package/templates/.agents/dashboard/apps/frontend/src/project-settings-state.css +55 -0
  88. package/templates/.agents/dashboard/apps/frontend/src/project-settings.test.ts +12 -0
  89. package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +1 -1
  90. package/templates/.agents/dashboard/apps/frontend/src/traceability-task-pagination.ts +1 -2
  91. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.test.ts +6 -0
  92. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.ts +2 -0
  93. package/templates/.agents/dashboard/apps/frontend/src/use-app-trace-documents.ts +3 -1
  94. package/templates/.agents/dashboard/apps/frontend/src/use-app-trace-task-pagination.ts +4 -15
  95. package/templates/.agents/dashboard/apps/frontend/src/use-dashboard-app-model.tsx +2 -2
  96. package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
  97. package/templates/.agents/dashboard/modules/cost-monitor/src/complete-cost-average.test.ts +73 -0
  98. package/templates/.agents/dashboard/modules/cost-monitor/src/contracts.ts +9 -0
  99. package/templates/.agents/dashboard/modules/cost-monitor/src/period-averages.ts +60 -0
  100. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorContent.tsx +8 -22
  101. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +2 -3
  102. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostPeriodAverageCards.tsx +32 -8
  103. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-summary.ts +3 -2
  104. package/templates/.agents/dashboard/modules/cost-monitor/src/react/period-cost-groups.ts +1 -42
  105. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.ts +2 -1
  106. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.ts +3 -2
  107. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.ts +8 -2
  108. package/templates/.agents/dashboard/modules/cost-monitor/src/server/index.ts +1 -0
  109. package/templates/.agents/dashboard/modules/operations/package.json +1 -1
  110. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview-keeps-structure-classes-mutually-exclusive.test.ts +4 -3
  111. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.helpers.tsx +66 -3
  112. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.test.ts +71 -1
  113. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +36 -30
  114. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +5 -14
  115. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageOverview.tsx +3 -0
  116. package/templates/.agents/dashboard/modules/operations/src/react/OverviewCostKpi.tsx +46 -0
  117. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.test.ts +28 -1
  118. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.tsx +11 -4
  119. package/templates/.agents/dashboard/modules/operations/src/react/index.ts +1 -0
  120. package/templates/.agents/dashboard/modules/operations/src/react/operations-coverage-toast.test.ts +2 -2
  121. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +28 -8
  122. package/templates/.agents/dashboard/modules/operations/src/react/operations-page-contract.ts +19 -2
  123. package/templates/.agents/dashboard/modules/operations/src/react/overview-cost-card.test.tsx +89 -0
  124. package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.test.ts +3 -3
  125. package/templates/.agents/dashboard/modules/operations/src/work-board-model.ts +2 -1
  126. package/templates/.agents/dashboard/modules/traceability/package.json +1 -1
  127. package/templates/.agents/dashboard/packages/branding/package.json +1 -1
  128. package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
  129. package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
  130. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +279 -245
  131. package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +247 -215
  132. package/templates/.agents/dashboard/packages/local-runtime/package.json +2 -2
  133. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-runtime.mjs +15 -25
  134. package/templates/.agents/dashboard/packages/local-runtime/server.mjs +279 -245
  135. package/templates/.agents/dashboard/packages/local-runtime/src/active-codex-telemetry.ts +1 -1
  136. package/templates/.agents/dashboard/packages/local-runtime/src/project-installation-summary.test.ts +142 -0
  137. package/templates/.agents/dashboard/packages/local-runtime/src/project-installation-summary.ts +190 -0
  138. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.test.ts +65 -0
  139. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.ts +67 -66
  140. package/templates/.agents/dashboard/packages/local-runtime/src/server-browser-lease.test.ts +91 -0
  141. package/templates/.agents/dashboard/packages/local-runtime/src/server-browser-lease.ts +24 -4
  142. package/templates/.agents/dashboard/packages/local-runtime/src/server-hono-security.test.ts +17 -0
  143. package/templates/.agents/dashboard/packages/local-runtime/src/server-operations-routes.ts +21 -2
  144. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-refresh.test.ts +94 -2
  145. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-refresh.ts +62 -12
  146. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-synchronization.test.ts +26 -0
  147. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-synchronization.ts +4 -1
  148. package/templates/.agents/dashboard/packages/local-runtime/src/server-sqlite-task-trace.test.ts +97 -0
  149. package/templates/.agents/dashboard/packages/local-runtime/src/server-sqlite-task-trace.ts +10 -13
  150. package/templates/.agents/dashboard/packages/local-runtime/src/server-trace-routes.ts +2 -10
  151. package/templates/.agents/dashboard/packages/local-runtime/src/server-traceability-index.test.ts +84 -0
  152. package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +15 -1
  153. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-calendar.ts +17 -0
  154. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cold-parse.test.ts +78 -0
  155. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-dimension-facts.test.ts +12 -1
  156. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-projection.test.ts +94 -0
  157. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-projection.ts +5 -5
  158. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-duration-lookup.test.ts +59 -0
  159. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-entity-label-views.test.ts +72 -0
  160. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-file-index.test.ts +69 -0
  161. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-cache.ts +3 -1
  162. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-force-canonical.test.ts +3 -1
  163. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-incremental-refresh.test.ts +2 -0
  164. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-materialize-projections.ts +9 -0
  165. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-materialize-runs.ts +4 -5
  166. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-period-averages.ts +46 -0
  167. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-provider-alias-parity.test.ts +50 -0
  168. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-entity-group.test.ts +171 -0
  169. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-entity-group.ts +36 -16
  170. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-filtered-dimension.ts +13 -2
  171. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-summary.ts +25 -7
  172. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-temporal-dimension.ts +2 -0
  173. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-canonical-parsing.ts +7 -0
  174. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-canonical.ts +5 -15
  175. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-counts-every-root-execution-day-returns.test.ts +34 -10
  176. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-filesystem.ts +17 -3
  177. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-keeps-orphan-telemetry-out-kanban-without.test.ts +1 -1
  178. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-rebuild.ts +11 -0
  179. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-schema.ts +5 -4
  180. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.test.ts +54 -1
  181. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.ts +7 -3
  182. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +4 -1
  183. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-risk-population.test.ts +98 -0
  184. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-schema-base-views.ts +29 -16
  185. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-schema-dashboard-views.ts +2 -1
  186. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-seed.test.ts +2 -0
  187. package/templates/.agents/dashboard/packages/local-runtime/src/verify-project-settings.mjs +57 -0
  188. package/templates/.agents/dashboard/packages/ui/package.json +1 -1
  189. package/templates/.agents/dashboard/scripts/qualify-observability.mjs +130 -0
  190. package/templates/.agents/dashboard/scripts/verify-autonomy-settings.mjs +175 -0
  191. package/templates/.agents/dashboard/scripts/verify-observability.mjs +254 -0
  192. package/templates/.agents/dashboard/scripts/verify-project-setup.mjs +64 -0
  193. package/templates/.agents/dashboard/tests/e2e/lease-global-setup.ts +37 -0
  194. package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
  195. package/templates/.agents/dashboard/tests/e2e/playwright.config.ts +5 -3
  196. package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-period-transition.spec.ts +22 -1
  197. package/templates/.agents/dashboard/tests/e2e/specs/dashboard-performance-matrix.spec.ts +17 -8
  198. package/templates/.agents/dashboard/tests/e2e/specs/dashboard.spec.ts +47 -6
  199. package/templates/.agents/dashboard/tests/e2e/specs/lease-lifetime.spec.ts +14 -0
  200. package/templates/.agents/dashboard/tests/observability-fixture.mjs +200 -0
  201. package/templates/.agents/design/.zaip-managed.json +84 -40
  202. package/templates/.agents/design/apps/catalog/dist/assets/index-BJV597iq.js +72 -0
  203. package/templates/.agents/design/apps/catalog/dist/assets/index-BOjCcUaU.js +72 -0
  204. package/templates/.agents/design/apps/catalog/dist/assets/index-B_WhrCZe.js +72 -0
  205. package/templates/.agents/design/apps/catalog/dist/assets/index-CqtYXZfV.js +72 -0
  206. package/templates/.agents/design/apps/catalog/dist/assets/index-D_lfqoyx.js +72 -0
  207. package/templates/.agents/design/apps/catalog/dist/assets/index-i_PO2k9R.js +9 -0
  208. package/templates/.agents/design/apps/catalog/dist/index.html +1 -1
  209. package/templates/.agents/design/apps/catalog/dist/storybook/assets/CatalogShell-Cstn1UwA.js +1 -0
  210. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{Color-6AOWCN3U-B-kAgAjB.js → Color-6AOWCN3U-Cm-yJJz_.js} +1 -1
  211. package/templates/.agents/design/apps/catalog/dist/storybook/assets/Components.stories-D1WopB2L.js +137 -0
  212. package/templates/.agents/design/apps/catalog/dist/storybook/assets/DesignSystem.stories-DQ9PJ3N3.js +1 -0
  213. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{DocsRenderer-JROSPFPF-BVN7xHtv.js → DocsRenderer-JROSPFPF-Belk4jRr.js} +4 -4
  214. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{WithTooltip-7X4HQR7L-CDHtKYkz.js → WithTooltip-7X4HQR7L-DoPvjkS1.js} +1 -1
  215. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{chunk-DRQKCCAG-D6AsDkMK.js → chunk-DRQKCCAG-B1itKXEN.js} +1 -1
  216. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{chunk-W22LQPXL-B4m5uloN.js → chunk-W22LQPXL-C-Eb5SPY.js} +1 -1
  217. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{components-CN8YyTUg.js → components-DnyKLwhj.js} +5 -5
  218. package/templates/.agents/design/apps/catalog/dist/storybook/assets/formatter-L2YTDE3Q-D0OSgxWz.js +1 -0
  219. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{iframe-9yZfIsdT.js → iframe-DcXBsFPz.js} +3 -3
  220. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{react-18-BoCSnq6H.js → react-18-CRM89QRf.js} +1 -1
  221. package/templates/.agents/design/apps/catalog/dist/storybook/assets/react-C3tkVMIp.js +1 -0
  222. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{syntaxhighlighter-YFXUGROL-Bnn_nMwJ.js → syntaxhighlighter-YFXUGROL-B03jQGTF.js} +1 -1
  223. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{theming-DS_ue2sb.js → theming-4ZyufAga.js} +1 -1
  224. package/templates/.agents/design/apps/catalog/dist/storybook/iframe.html +1 -1
  225. package/templates/.agents/design/apps/catalog/dist/storybook/index.json +1 -1
  226. package/templates/.agents/design/apps/catalog/package.json +2 -2
  227. package/templates/.agents/design/apps/catalog/src/components/AutonomySpecimen.tsx +15 -0
  228. package/templates/.agents/design/apps/catalog/src/components/CostPopulationSpecimen.test.tsx +19 -0
  229. package/templates/.agents/design/apps/catalog/src/components/CostPopulationSpecimen.tsx +45 -0
  230. package/templates/.agents/design/apps/catalog/src/components/EstimatedCostSpecimen.tsx +48 -0
  231. package/templates/.agents/design/apps/catalog/src/components/ProjectStatusSpecimen.tsx +169 -0
  232. package/templates/.agents/design/apps/catalog/src/pages/ComponentsPage.tsx +55 -0
  233. package/templates/.agents/design/apps/catalog/src/stories/Components.stories.tsx +60 -0
  234. package/templates/.agents/design/packages/local-runtime/package.json +1 -1
  235. package/templates/.agents/requirements/autonomous-assurance.md +1 -1
  236. package/templates/.agents/requirements/cloud-hostinger-autonomy.md +1 -1
  237. package/templates/.agents/requirements/comparative-audit.md +1 -1
  238. package/templates/.agents/requirements/context-engine.md +1 -1
  239. package/templates/.agents/requirements/cost-observability.md +1 -1
  240. package/templates/.agents/requirements/dashboard-launch.md +1 -1
  241. package/templates/.agents/requirements/data-export.md +1 -1
  242. package/templates/.agents/requirements/design-system.md +1 -1
  243. package/templates/.agents/requirements/execution-engine.md +1 -1
  244. package/templates/.agents/requirements/kanban-dashboard.md +1 -1
  245. package/templates/.agents/requirements/model-orchestration.md +1 -1
  246. package/templates/.agents/requirements/public-distribution.md +1 -1
  247. package/templates/.agents/requirements/software-architecture.md +1 -1
  248. package/templates/.agents/requirements/strategic-improvements.md +1 -1
  249. package/templates/.agents/requirements/work-lifecycle.md +5 -5
  250. package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
  251. package/templates/.agents/rules/astra-diagnostic.md +3 -1
  252. package/templates/.agents/rules/autonomy-decision.md +10 -2
  253. package/templates/.agents/rules/core.md +12 -1
  254. package/templates/.agents/rules/run-lifecycle-closure.md +8 -6
  255. package/templates/.agents/rules/workflow.md +2 -2
  256. package/templates/.agents/runtime/VERSION +1 -1
  257. package/templates/.agents/runtime/bin/zaip.mjs +383 -350
  258. package/templates/.agents/runtime/checksums.sha256 +6 -6
  259. package/templates/.agents/runtime/manifest.json +1 -1
  260. package/templates/.agents/runtime/pnpm-lock.sha256 +1 -1
  261. package/templates/.agents/runtime/provenance.json +5 -5
  262. package/templates/.agents/runtime/sbom.cdx.json +3 -3
  263. package/templates/.agents/skills/zaip-skill-dev-environment/SKILL.md +2 -0
  264. package/templates/.agents/skills/zaip-skill-execution/SKILL.md +28 -5
  265. package/templates/.agents/skills/zaip-skill-execution/references/runtime-governance.md +17 -3
  266. package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +8 -9
  267. package/templates/.agents/skills/zaip-skill-github-deploy/references/deployment-workflow.md +10 -6
  268. package/templates/.agents/skills/zaip-skill-github-deploy/references/release-identity.md +17 -12
  269. package/templates/.agents/skills/zaip-skill-move-prd/SKILL.md +2 -0
  270. package/templates/.agents/skills/zaip-skill-prd/SKILL.md +2 -0
  271. package/templates/.agents/skills/zaip-skill-release-qualification/SKILL.md +21 -23
  272. package/templates/.agents/skills/zaip-skill-release-qualification/references/local-preparation.md +37 -13
  273. package/templates/.agents/skills/zaip-skill-setup/SKILL.md +2 -0
  274. package/templates/.agents/skills/zaip-skill-tool-setup/SKILL.md +2 -0
  275. package/templates/.agents/zaip-aios/INDEX.md +9 -1
  276. package/templates/.agents/zaip-aios/README.md +24 -2
  277. package/templates/.agents/zaip-aios/VERSION +1 -1
  278. package/templates/.agents/zaip-aios/guides/01-primeiros-passos.md +5 -1
  279. package/templates/.agents/zaip-aios/guides/03-tasks.md +15 -2
  280. package/templates/.agents/zaip-aios/guides/04-specs.md +13 -0
  281. package/templates/.agents/zaip-aios/guides/05-prds.md +13 -0
  282. package/templates/.agents/zaip-aios/guides/06-execucao.md +19 -4
  283. package/templates/.agents/zaip-aios/guides/07-revisao-e-validacao.md +14 -0
  284. package/templates/.agents/zaip-aios/guides/08-contexto-e-tokens.md +4 -3
  285. package/templates/.agents/zaip-aios/guides/09-agentes-e-squads.md +17 -9
  286. package/templates/.agents/zaip-aios/guides/10-seguranca.md +9 -0
  287. package/templates/.agents/zaip-aios/guides/11-observabilidade-e-custos.md +69 -0
  288. package/templates/.agents/zaip-aios/guides/12-instalacao-e-upgrade.md +9 -4
  289. package/templates/.agents/zaip-aios/guides/13-boas-praticas.md +7 -1
  290. package/templates/.agents/zaip-aios/guides/14-troubleshooting.md +18 -0
  291. package/templates/.agents/zaip-aios/guides/16-lifecycle-e-reconciliacao.md +54 -3
  292. package/templates/.agents/zaip-aios/guides/18-catalogo-de-agentes.md +10 -2
  293. package/templates/.agents/zaip-aios/guides/19-assurance-e-autonomia.md +186 -5
  294. package/templates/.agents/zaip-aios/guides/20-instalacao-detalhada.md +21 -15
  295. package/templates/.agents/zaip-aios/guides/21-telemetria-monitor-custos.md +18 -2
  296. package/templates/.agents/zaip-aios/guides/22-fluxos-e-roteamento.md +14 -2
  297. package/templates/.agents/zaip-aios/guides/23-orquestracao-de-modelos.md +190 -489
  298. package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +72 -13
  299. package/templates/.agents/zaip-aios/guides/27-telemetria-git-native.md +18 -0
  300. package/templates/.agents/zaip-aios/guides/28-lifecycle-completo.md +18 -1
  301. package/templates/template-manifest.json +454 -274
  302. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-1L7Qw-Gq.js +0 -3
  303. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-EInWr641.css +0 -1
  304. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-B6aZfo5f.js +0 -68
  305. package/templates/.agents/dashboard/apps/frontend/dist/assets/dashboard-localization-CLJ0lT9v.js +0 -231
  306. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-DgTmNHN5.js +0 -2
  307. package/templates/.agents/dashboard/apps/frontend/dist/assets/traceability-DQpKX9c1.js +0 -1
  308. package/templates/.agents/design/apps/catalog/dist/storybook/assets/CatalogShell-BWY-80s4.js +0 -1
  309. package/templates/.agents/design/apps/catalog/dist/storybook/assets/Components.stories-Be2mDUQj.js +0 -27
  310. package/templates/.agents/design/apps/catalog/dist/storybook/assets/DesignSystem.stories-DRx9blDs.js +0 -1
  311. package/templates/.agents/design/apps/catalog/dist/storybook/assets/formatter-L2YTDE3Q-EwuTh8Zk.js +0 -1
  312. package/templates/.agents/design/apps/catalog/dist/storybook/assets/react-DyL61NPT.js +0 -1
@@ -0,0 +1,171 @@
1
+ import { DatabaseSync } from "node:sqlite";
2
+ import { afterEach, describe, expect, it, vi } from "vitest";
3
+ import type { SqliteViewInput } from "./sqlite-query-context.js";
4
+ import { readEntityGroup } from "./sqlite-query-entity-group.js";
5
+
6
+ const databases: DatabaseSync[] = [];
7
+ afterEach(() => {
8
+ vi.restoreAllMocks();
9
+ for (const database of databases.splice(0)) database.close();
10
+ });
11
+
12
+ function fixture(kind: "spec" | "prd") {
13
+ const database = new DatabaseSync(":memory:");
14
+ databases.push(database);
15
+ database.exec(`
16
+ CREATE TABLE ${kind}s (id TEXT PRIMARY KEY, title TEXT, status TEXT, risk TEXT,
17
+ occurred_at TEXT, occurred_day_sp TEXT);
18
+ CREATE TABLE invocations (agent_invocation_id TEXT PRIMARY KEY, ${kind}_id TEXT,
19
+ occurred_at TEXT, occurred_day_sp TEXT, llm_call_count INTEGER, duration_ms REAL,
20
+ input_tokens REAL, cached_input_tokens REAL, output_tokens REAL, reasoning_tokens REAL,
21
+ total_tokens REAL, cost_usd REAL, cost_brl REAL);
22
+ `);
23
+ const entity = (id: string, day = "2026-09-10", status = "completed", risk = "standard") =>
24
+ database
25
+ .prepare(`INSERT INTO ${kind}s VALUES (?, ?, ?, ?, ?, ?)`)
26
+ .run(id, `Title ${id}`, status, risk, `${day}T12:00:00Z`, day);
27
+ const invocation = (id: string, parent: string, day: string, cost: number | null) =>
28
+ database
29
+ .prepare("INSERT INTO invocations VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
30
+ .run(
31
+ id,
32
+ parent,
33
+ `${day}T13:00:00Z`,
34
+ day,
35
+ cost === null ? null : 1,
36
+ cost,
37
+ cost,
38
+ cost,
39
+ cost,
40
+ cost,
41
+ cost,
42
+ cost,
43
+ cost,
44
+ );
45
+ const read = (input: SqliteViewInput = {}) =>
46
+ readEntityGroup(
47
+ { database },
48
+ kind === "spec" ? "cost_monitor_specs" : "cost_monitor_prds",
49
+ input,
50
+ kind,
51
+ );
52
+ return { database, entity, invocation, read };
53
+ }
54
+
55
+ describe.each(["spec", "prd"] as const)("canonical %s single grouped query", (kind) => {
56
+ it("computes full totals and deterministic pages with one SQL statement", () => {
57
+ const { database, entity, invocation, read } = fixture(kind);
58
+ for (let i = 0; i < 12; i++) {
59
+ const id = `E${String(i).padStart(2, "0")}`;
60
+ entity(id);
61
+ invocation(`I${i}`, id, "2026-09-10", 0.12345678901234566);
62
+ }
63
+ const prepare = vi.spyOn(database, "prepare");
64
+ const first = read({ limit: 10 });
65
+ expect(prepare).toHaveBeenCalledTimes(1);
66
+ prepare.mockClear();
67
+ const second = read({ limit: 10, offset: 10 });
68
+ expect(prepare).toHaveBeenCalledTimes(1);
69
+ expect(first.total_count).toBe(12);
70
+ expect(first.has_more).toBe(true);
71
+ expect(second.has_more).toBe(false);
72
+ expect(second.rows.map((row) => row.id)).toEqual(["E10", "E11"]);
73
+ expect(first.totals).toEqual(second.totals);
74
+ expect(first.totals).toMatchObject({
75
+ entity_count: 12,
76
+ invocation_count: 12,
77
+ total_duration: 1,
78
+ });
79
+ expect(first.rows[0]).toMatchObject({
80
+ id: "E00",
81
+ key: "E00",
82
+ total_cost_brl: 0.12345678901234566,
83
+ });
84
+ expect(Object.keys(first.rows[0] ?? {}).some((key) => key.startsWith("__"))).toBe(false);
85
+ const beyond = read({ limit: 10, offset: 99 });
86
+ expect(beyond).toMatchObject({
87
+ total_count: 12,
88
+ rows: [],
89
+ totals: first.totals,
90
+ has_more: false,
91
+ });
92
+ });
93
+
94
+ it("retains canonical entity dates, no-run unknowns and observed zero with filters", () => {
95
+ const { entity, invocation, read } = fixture(kind);
96
+ entity("CURRENT");
97
+ invocation("old-run", "CURRENT", "2026-08-01", 100);
98
+ entity("ZERO");
99
+ invocation("zero", "ZERO", "2026-09-10", 0);
100
+ entity("UNKNOWN");
101
+ invocation("unknown", "UNKNOWN", "2026-09-10", null);
102
+ entity("NO-RUN");
103
+ entity("OLD", "2026-08-01");
104
+ invocation("new-run", "OLD", "2026-09-10", 999);
105
+ entity("BLOCKED", "2026-09-10", "blocked", "critical");
106
+ const page = read({
107
+ from: "2026-09-01",
108
+ to: "2026-09-30",
109
+ status: "completed",
110
+ risk: "standard",
111
+ });
112
+ expect(page.total_count).toBe(4);
113
+ expect(page.totals).toEqual({
114
+ entity_count: 4,
115
+ invocation_count: 2,
116
+ total_duration: 0,
117
+ total_tokens: 0,
118
+ total_cost_usd: 0,
119
+ total_cost_brl: 0,
120
+ });
121
+ expect(page.rows.find((row) => row.id === "CURRENT")).toMatchObject({
122
+ invocation_count: 0,
123
+ total_cost_brl: null,
124
+ first_day: "2026-09-10",
125
+ occurred_at: "2026-09-10T12:00:00Z",
126
+ });
127
+ expect(page.rows.find((row) => row.id === "ZERO")).toMatchObject({
128
+ total_cost_brl: 0,
129
+ invocation_count: 1,
130
+ });
131
+ expect(page.rows.find((row) => row.id === "UNKNOWN")).toMatchObject({
132
+ total_cost_brl: null,
133
+ invocation_count: 1,
134
+ });
135
+ expect(page.rows.find((row) => row.id === "NO-RUN")).toMatchObject({
136
+ total_cost_brl: null,
137
+ invocation_count: 0,
138
+ });
139
+ expect(read({ query: "Title BLOCKED", risk: "critical" }).rows.map((row) => row.id)).toEqual([
140
+ "BLOCKED",
141
+ ]);
142
+ expect(read({ query: "CURRENT" }).totals.total_cost_brl).toBe(100);
143
+ });
144
+
145
+ it("returns nullable empty totals and clamps page boundaries without losing counts", () => {
146
+ const { entity, read } = fixture(kind);
147
+ expect(read({ limit: 0, offset: -2 })).toMatchObject({
148
+ rows: [],
149
+ total_count: 0,
150
+ limit: 1,
151
+ offset: 0,
152
+ has_more: false,
153
+ totals: {
154
+ entity_count: 0,
155
+ invocation_count: 0,
156
+ total_duration: null,
157
+ total_tokens: null,
158
+ total_cost_usd: null,
159
+ total_cost_brl: null,
160
+ },
161
+ });
162
+ entity("ONLY");
163
+ expect(read({ limit: 1000, offset: 1 })).toMatchObject({
164
+ rows: [],
165
+ total_count: 1,
166
+ limit: 200,
167
+ has_more: false,
168
+ totals: { entity_count: 1, invocation_count: 0, total_cost_brl: null },
169
+ });
170
+ });
171
+ });
@@ -2,7 +2,7 @@ import { type CostGroupKind, readCostGroupPage } from "./sqlite-cost-group-page.
2
2
  import type { SqliteQueryContext, SqliteViewInput } from "./sqlite-query-context.js";
3
3
  import type { SqliteViewName } from "./sqlite-read-model-types.js";
4
4
  export function readEntityGroup(
5
- context: SqliteQueryContext,
5
+ context: Pick<SqliteQueryContext, "database">,
6
6
  view: SqliteViewName,
7
7
  input: SqliteViewInput,
8
8
  groupKind: string,
@@ -55,7 +55,7 @@ export function readEntityGroup(
55
55
  const entityWhere = entityClauses.length === 0 ? "1" : entityClauses.join(" AND ");
56
56
  const invocationJoin =
57
57
  invocationClauses.length === 0 ? "" : ` AND ${invocationClauses.join(" AND ")}`;
58
- const ctes = `WITH grouped AS (
58
+ const ctes = `WITH grouped AS MATERIALIZED (
59
59
  SELECT entity.id AS group_value, entity.title, entity.status, entity.risk,
60
60
  COALESCE(MIN(i.occurred_day_sp), entity.occurred_day_sp) AS first_day,
61
61
  COALESCE(MAX(i.occurred_day_sp), entity.occurred_day_sp) AS last_day,
@@ -76,23 +76,43 @@ export function readEntityGroup(
76
76
  const limit = Math.min(200, Math.max(1, input.limit ?? 50));
77
77
  const offset = Math.max(0, input.offset ?? 0);
78
78
  const values = [...invocationValues, ...entityValues];
79
- const total_count = Number(
80
- (
81
- context.database
82
- .prepare(`${ctes} SELECT COUNT(*) AS count FROM grouped`)
83
- .get(...values) as { count: number }
84
- ).count,
85
- );
86
- const totals = context.database
79
+ // Materialize this population once for count, totals and the requested page.
80
+ // A totals-first LEFT JOIN retains totals even for an empty/out-of-range page.
81
+ const result = context.database
87
82
  .prepare(
88
- `${ctes} SELECT COUNT(*) AS entity_count, COALESCE(SUM(invocation_count), 0) AS invocation_count, ROUND(SUM(total_duration)) AS total_duration, SUM(total_tokens) AS total_tokens, SUM(total_cost_usd) AS total_cost_usd, SUM(total_cost_brl) AS total_cost_brl FROM grouped`,
89
- )
90
- .get(...values) as Record<string, unknown>;
91
- const rows = context.database
92
- .prepare(
93
- `${ctes} SELECT group_value AS id, group_value AS key, title, status, risk, first_day, last_day, occurred_at, invocation_count, llm_call_count, total_duration, total_input_tokens, total_cached_input_tokens, total_output_tokens, total_reasoning_tokens, total_tokens, total_cost_usd, total_cost_brl FROM grouped ORDER BY total_cost_brl DESC, group_value LIMIT ? OFFSET ?`,
83
+ `${ctes}, totals AS (
84
+ SELECT COUNT(*) AS __entity_count,
85
+ COALESCE(SUM(invocation_count), 0) AS __invocation_count,
86
+ ROUND(SUM(total_duration)) AS __total_duration,
87
+ SUM(total_tokens) AS __total_tokens,
88
+ SUM(total_cost_usd) AS __total_cost_usd,
89
+ SUM(total_cost_brl) AS __total_cost_brl FROM grouped
90
+ ), paged AS (
91
+ SELECT 1 AS __row_present, group_value AS id, group_value AS key,
92
+ title, status, risk, first_day, last_day, occurred_at, invocation_count,
93
+ llm_call_count, total_duration, total_input_tokens, total_cached_input_tokens,
94
+ total_output_tokens, total_reasoning_tokens, total_tokens, total_cost_usd,
95
+ total_cost_brl FROM grouped ORDER BY total_cost_brl DESC, group_value LIMIT ? OFFSET ?
96
+ ) SELECT totals.*, paged.* FROM totals LEFT JOIN paged ON 1
97
+ ORDER BY paged.total_cost_brl DESC, paged.id`,
94
98
  )
95
99
  .all(...values, limit, offset) as Array<Record<string, unknown>>;
100
+ const aggregate = result[0];
101
+ if (!aggregate) throw new Error("Canonical macro query did not return its aggregate row.");
102
+ const total_count = Number(aggregate.__entity_count);
103
+ const totals = {
104
+ entity_count: aggregate.__entity_count,
105
+ invocation_count: aggregate.__invocation_count,
106
+ total_duration: aggregate.__total_duration,
107
+ total_tokens: aggregate.__total_tokens,
108
+ total_cost_usd: aggregate.__total_cost_usd,
109
+ total_cost_brl: aggregate.__total_cost_brl,
110
+ };
111
+ const rows = result
112
+ .filter((row) => row.__row_present === 1)
113
+ .map((row) =>
114
+ Object.fromEntries(Object.entries(row).filter(([key]) => !key.startsWith("__"))),
115
+ );
96
116
  return {
97
117
  data_source: "sqlite_read_model" as const,
98
118
  view,
@@ -1,3 +1,4 @@
1
+ import { sqlitePeriodAverages, sqlitePeriodTotals } from "./sqlite-period-averages.js";
1
2
  import type { SqliteQueryContext, SqliteViewInput } from "./sqlite-query-context.js";
2
3
  import { costMonitorFilterDay } from "./sqlite-read-model-canonical.js";
3
4
  import type { SqliteViewName } from "./sqlite-read-model-types.js";
@@ -9,6 +10,8 @@ export function readFilteredDimension(
9
10
  ) {
10
11
  const temporalCostGroup =
11
12
  filteredCostGroup === "day" || filteredCostGroup === "month" || filteredCostGroup === "year";
13
+ let periodAverages: ReturnType<typeof sqlitePeriodAverages> | undefined;
14
+ let periodTotals: ReturnType<typeof sqlitePeriodTotals> | undefined;
12
15
 
13
16
  if (temporalCostGroup && input.workType) {
14
17
  // No canonical work_type exists at invocation grain, including for
@@ -20,6 +23,8 @@ export function readFilteredDimension(
20
23
  limit: Math.min(200, Math.max(1, input.limit ?? 50)),
21
24
  total_count: 0,
22
25
  has_more: false,
26
+ period_averages: sqlitePeriodAverages([]),
27
+ totals: sqlitePeriodTotals([]),
23
28
  rows: [],
24
29
  };
25
30
  }
@@ -152,9 +157,11 @@ export function readFilteredDimension(
152
157
  : "total_cost_brl DESC, key";
153
158
  let rows = context.database
154
159
  .prepare(
155
- `${facts} SELECT ${groupExpression} AS key, ${groupExpression} AS label, ${groupExpression} AS period_key, MIN(date(COALESCE(i.source_started_at, i.source_occurred_at, i.occurred_at), '-3 hours')) AS start_day, MAX(date(COALESCE(i.source_started_at, i.source_occurred_at, i.occurred_at), '-3 hours')) AS end_day, COUNT(*) AS invocation_count, SUM(i.llm_call_count) AS llm_call_count, SUM(i.source_event_count) AS source_event_count, NULL AS total_duration, SUM(i.input_tokens) AS total_input_tokens, SUM(i.cached_input_tokens) AS total_cached_input_tokens, SUM(i.output_tokens) AS total_output_tokens, SUM(i.reasoning_tokens) AS total_reasoning_tokens, SUM(i.total_tokens) AS total_tokens, SUM(i.cost_usd) AS total_cost_usd, SUM(i.cost_brl) AS total_cost_brl FROM facts i WHERE ${where} GROUP BY ${groupExpression} ORDER BY ${order} LIMIT ? OFFSET ?`,
160
+ `${facts} SELECT ${groupExpression} AS key, ${groupExpression} AS label, ${groupExpression} AS period_key, MIN(date(COALESCE(i.source_started_at, i.source_occurred_at, i.occurred_at), '-3 hours')) AS start_day, MAX(date(COALESCE(i.source_started_at, i.source_occurred_at, i.occurred_at), '-3 hours')) AS end_day, COUNT(*) AS invocation_count, SUM(i.llm_call_count) AS llm_call_count, SUM(i.source_event_count) AS source_event_count, NULL AS total_duration, SUM(i.input_tokens) AS total_input_tokens, SUM(i.cached_input_tokens) AS total_cached_input_tokens, SUM(i.output_tokens) AS total_output_tokens, SUM(i.reasoning_tokens) AS total_reasoning_tokens, SUM(i.total_tokens) AS total_tokens, SUM(i.cost_usd) AS total_cost_usd, SUM(i.cost_brl) AS total_cost_brl FROM facts i WHERE ${where} GROUP BY ${groupExpression} ORDER BY ${order}${temporalCostGroup ? "" : " LIMIT ? OFFSET ?"}`,
156
161
  )
157
- .all(...values, limit, offset) as Array<Record<string, unknown>>;
162
+ .all(...values, ...(temporalCostGroup ? [] : [limit, offset])) as Array<
163
+ Record<string, unknown>
164
+ >;
158
165
  if (temporalCostGroup) {
159
166
  const canonicalFilter = {
160
167
  from: input.from ?? null,
@@ -268,6 +275,8 @@ export function readFilteredDimension(
268
275
  };
269
276
  });
270
277
  total_count = allRows.length;
278
+ periodAverages = sqlitePeriodAverages(allRows);
279
+ periodTotals = sqlitePeriodTotals(allRows);
271
280
  rows = allRows.slice(offset, offset + limit);
272
281
  for (const row of rows) {
273
282
  const key = String(row.period_key);
@@ -287,6 +296,8 @@ export function readFilteredDimension(
287
296
  limit,
288
297
  total_count,
289
298
  has_more: offset + rows.length < total_count,
299
+ ...(periodAverages === undefined ? {} : { period_averages: periodAverages }),
300
+ ...(periodTotals === undefined ? {} : { totals: periodTotals }),
290
301
  rows,
291
302
  };
292
303
  }
@@ -79,7 +79,8 @@ export function queryCostMonitorSummaryAggregate(
79
79
  const sourceDay =
80
80
  "date(COALESCE(a.source_started_at, a.source_occurred_at, a.occurred_at), '-3 hours')";
81
81
  const clauses = [
82
- "(a.total_tokens IS NOT NULL OR a.cost_brl IS NOT NULL OR a.cost_usd IS NOT NULL)",
82
+ // Availability affects coverage, not membership. Excluding unknown Runs
83
+ // silently inflated coverage and made Cost Monitor disagree with Operations.
83
84
  `(? IS NULL OR ${sourceDay} >= ?)`,
84
85
  `(? IS NULL OR ${sourceDay} <= ?)`,
85
86
  ];
@@ -131,7 +132,7 @@ export function queryCostMonitorSummaryAggregate(
131
132
  SELECT ${sourceDay} AS day,
132
133
  CASE WHEN a.phase='conversation' THEN 'conversation'
133
134
  WHEN a.phase='planning' THEN 'planning' ELSE 'execution' END AS phase_key,
134
- a.task_id, a.model, a.agent_run_id, a.activity_source_kind,
135
+ a.task_id, a.model, a.agent_run_id, a.activity_source_kind, a.work_type AS work_key,
135
136
  a.source_event_count AS event_count,
136
137
  a.attributed_token_active_ms AS duration_ms,
137
138
  a.input_tokens, a.cached_input_tokens, a.output_tokens, a.reasoning_tokens,
@@ -158,8 +159,8 @@ export function queryCostMonitorSummaryAggregate(
158
159
  // population is evaluated once rather than once per dashboard widget.
159
160
  const factRows = context.database
160
161
  .prepare(`${selected}
161
- SELECT day, phase_key, ${aggregateColumns}
162
- FROM selected GROUP BY day, phase_key ORDER BY day, phase_key`)
162
+ SELECT day, phase_key, work_key, ${aggregateColumns}
163
+ FROM selected GROUP BY day, phase_key, work_key ORDER BY day, phase_key, work_key`)
163
164
  .all(...values) as Array<Record<string, unknown>>;
164
165
  const nullableColumns = [
165
166
  "duration_ms",
@@ -219,11 +220,13 @@ export function queryCostMonitorSummaryAggregate(
219
220
  SELECT entity_kind AS kind, id FROM canonical_work_items
220
221
  ), work_item_days AS (
221
222
  SELECT entity_kind AS kind, id, occurred_day_sp AS day FROM canonical_work_items
223
+ WHERE entity_kind <> 'task' OR COALESCE(status, 'draft') <> 'draft'
222
224
  UNION ALL
223
225
  SELECT 'task', a.task_id, MIN(a.occurred_day_sp) FROM activities a
224
226
  LEFT JOIN canonical_ids c ON c.kind='task' AND c.id=a.task_id
225
227
  WHERE a.task_id IS NOT NULL AND c.id IS NULL
226
228
  GROUP BY a.task_id
229
+ HAVING COALESCE(MAX(a.work_item_status), 'draft') <> 'draft'
227
230
  UNION ALL
228
231
  SELECT 'spec', a.spec_id, MIN(a.occurred_day_sp) FROM activities a
229
232
  LEFT JOIN canonical_ids c ON c.kind='spec' AND c.id=a.spec_id
@@ -301,7 +304,22 @@ export function queryCostMonitorSummaryAggregate(
301
304
  const planning = stripDurationPopulation(metric(byKey.get("planning")));
302
305
  const execution = stripDurationPopulation(metric(byKey.get("execution")));
303
306
  const total = stripDurationPopulation(metric(byKey.get("total")));
304
- const emptyMetric = stripDurationPopulation(metric());
307
+ const newWork = stripDurationPopulation(
308
+ metric(
309
+ rollup(
310
+ "new",
311
+ factRows.filter((row) => row.work_key === "new"),
312
+ ),
313
+ ),
314
+ );
315
+ const rework = stripDurationPopulation(
316
+ metric(
317
+ rollup(
318
+ "rework",
319
+ factRows.filter((row) => row.work_key === "rework"),
320
+ ),
321
+ ),
322
+ );
305
323
  const financialByDay = new Map(dailyRows.map((row) => [String(row.key), row]));
306
324
  const structuralByDay = new Map(structuralRows.map((row) => [String(row.day), row]));
307
325
  const days = [...new Set([...financialByDay.keys(), ...structuralByDay.keys()])].sort();
@@ -464,8 +482,8 @@ export function queryCostMonitorSummaryAggregate(
464
482
  planning,
465
483
  execution,
466
484
  total,
467
- new_work: total,
468
- rework: emptyMetric,
485
+ new_work: newWork,
486
+ rework,
469
487
  },
470
488
  task_count: number(totalRow?.task_count),
471
489
  model_groups,
@@ -1,3 +1,4 @@
1
+ import { sqlitePeriodAverages } from "./sqlite-period-averages.js";
1
2
  import type { SqliteQueryContext, SqliteViewInput } from "./sqlite-query-context.js";
2
3
  import { costMonitorFilterDay } from "./sqlite-read-model-canonical.js";
3
4
  import type { SqliteViewName } from "./sqlite-read-model-types.js";
@@ -127,6 +128,7 @@ export function readTemporalDimension(
127
128
  total_count: allRows.length,
128
129
  has_more: offset + rows.length < allRows.length,
129
130
  totals,
131
+ period_averages: sqlitePeriodAverages(allRows),
130
132
  rows,
131
133
  };
132
134
  }
@@ -1,5 +1,12 @@
1
1
  import { parseYaml } from "@zaip-ai/core";
2
2
 
3
+ /** Same accepted lifecycle paths as the parser, before any YAML or cache work. */
4
+ export function isCanonicalLifecyclePath(path: string): boolean {
5
+ return /^\.agents\/(?:data|records)\/(?:executions\/.*\/execution\.md|changes\/.*\/change\.md|(?:changes|executions)\/.*\/decisions\/.*\.md)$/.test(
6
+ path,
7
+ );
8
+ }
9
+
3
10
  export function frontMatterRecord(content: string): Record<string, unknown> | null {
4
11
  const source = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(content)?.[1];
5
12
  if (source === undefined) return null;
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  consolidatedValue,
3
3
  frontMatterRecord,
4
+ isCanonicalLifecyclePath,
4
5
  recordValue,
5
6
  stringValue,
6
7
  stringValues,
@@ -23,6 +24,9 @@ import {
23
24
  type PricingCatalog,
24
25
  } from "@zaip-ai/costs";
25
26
  import type { RunV2Fold, UsageRecordedV2 } from "../../../../../packages/decisions/src/index.js";
27
+ import { saoPauloDay } from "./sqlite-calendar.js";
28
+
29
+ export { saoPauloDay } from "./sqlite-calendar.js";
26
30
 
27
31
  const MAX_RECONCILED_RUN_INTERVAL_MS = 2 * 3_600_000;
28
32
 
@@ -112,6 +116,7 @@ export function readCanonicalLifecycleRecords(rows: Array<{ path: string; conten
112
116
  const changes: CanonicalChange[] = [];
113
117
  const decisions: CanonicalDecision[] = [];
114
118
  for (const row of rows) {
119
+ if (!isCanonicalLifecyclePath(row.path)) continue;
115
120
  const metadata = frontMatterRecord(row.content);
116
121
  if (metadata === null) continue;
117
122
  const id = stringValue(metadata.id);
@@ -689,21 +694,6 @@ export function usagePricingAudit(
689
694
  };
690
695
  }
691
696
 
692
- export function saoPauloDay(timestamp: string): string {
693
- const values = Object.fromEntries(
694
- new Intl.DateTimeFormat("en", {
695
- timeZone: "America/Sao_Paulo",
696
- year: "numeric",
697
- month: "2-digit",
698
- day: "2-digit",
699
- })
700
- .formatToParts(new Date(timestamp))
701
- .filter((part) => part.type !== "literal")
702
- .map((part) => [part.type, part.value]),
703
- ) as { year: string; month: string; day: string };
704
- return `${values.year}-${values.month}-${values.day}`;
705
- }
706
-
707
697
  export type TemporalInterval = { activityRowId: string; startMs: number; endMs: number };
708
698
 
709
699
  /**
@@ -6,6 +6,7 @@ import { rebuildSqliteReadModel, SqliteReadModelFileSystem } from "./sqlite-read
6
6
  import { expectPersistedFirstFoldCaches } from "./sqlite-read-model-cache.test-support.js";
7
7
 
8
8
  const roots: string[] = [];
9
+ const readers = new Set<SqliteReadModelFileSystem>();
9
10
  const sqliteTestTempRoot = join(
10
11
  resolve(import.meta.dirname, "../../../../../.."),
11
12
  ".tmp",
@@ -16,6 +17,8 @@ async function createSqliteTestRoot(): Promise<string> {
16
17
  return mkdtemp(join(sqliteTestTempRoot, "fixture-"));
17
18
  }
18
19
  afterEach(async () => {
20
+ for (const reader of readers) reader.close();
21
+ readers.clear();
19
22
  vi.useRealTimers();
20
23
  vi.restoreAllMocks();
21
24
  await Promise.all(
@@ -216,6 +219,7 @@ describe("SQLite dashboard read model", () => {
216
219
  );
217
220
  await rebuildSqliteReadModel(root);
218
221
  const filesystem = new SqliteReadModelFileSystem(root);
222
+ readers.add(filesystem);
219
223
  expect(filesystem.firstFoldAggregate({ from: null, to: null }).execution_day_count).toBe(2);
220
224
  expect(filesystem.firstFoldAggregate({ from: null, to: null }).duration_ms).toBe(2_400_000);
221
225
  expect(filesystem.topTasks({ from: null, to: null })).toMatchObject([
@@ -386,7 +390,7 @@ describe("SQLite dashboard read model", () => {
386
390
  expect(operationDays["2026-08-02"]).toMatchObject({
387
391
  runs: 2,
388
392
  specs: 1,
389
- tasks: 1,
393
+ tasks: 0,
390
394
  validations: 1,
391
395
  evidences: 0,
392
396
  usage: {
@@ -398,7 +402,7 @@ describe("SQLite dashboard read model", () => {
398
402
  expect(filesystem.viewPage("operations_daily", { limit: 50 }).rows).toContainEqual(
399
403
  expect.objectContaining({
400
404
  day: "2026-08-02",
401
- task_count: 1,
405
+ task_count: 0,
402
406
  spec_count: 1,
403
407
  validation_count: 1,
404
408
  evidence_count: 0,
@@ -417,7 +421,7 @@ describe("SQLite dashboard read model", () => {
417
421
  period_key: key,
418
422
  prd_count: 2,
419
423
  spec_count: 3,
420
- task_count: 3,
424
+ task_count: 0, // All three Tasks in this fixture are draft, unlike their observed Runs.
421
425
  validation_count: 1,
422
426
  evidence_count: 1,
423
427
  total_run_count: 3,
@@ -451,17 +455,17 @@ describe("SQLite dashboard read model", () => {
451
455
  [
452
456
  "cost_monitor_daily",
453
457
  "2026-08-02",
454
- { prd_count: 0, spec_count: 1, task_count: 1, validation_count: 1, evidence_count: 0 },
458
+ { prd_count: 0, spec_count: 1, task_count: 0, validation_count: 1, evidence_count: 0 },
455
459
  ],
456
460
  [
457
461
  "cost_monitor_monthly",
458
462
  "2026-08",
459
- { prd_count: 2, spec_count: 3, task_count: 3, validation_count: 1, evidence_count: 1 },
463
+ { prd_count: 2, spec_count: 3, task_count: 0, validation_count: 1, evidence_count: 1 },
460
464
  ],
461
465
  [
462
466
  "cost_monitor_annual",
463
467
  "2026",
464
- { prd_count: 2, spec_count: 3, task_count: 3, validation_count: 1, evidence_count: 1 },
468
+ { prd_count: 2, spec_count: 3, task_count: 0, validation_count: 1, evidence_count: 1 },
465
469
  ],
466
470
  ] as const) {
467
471
  expect(filesystem.viewPage(view, { limit: 50 }).rows).toContainEqual(
@@ -469,13 +473,13 @@ describe("SQLite dashboard read model", () => {
469
473
  );
470
474
  }
471
475
  expect(filesystem.viewPage("cost_monitor_daily", { limit: 50 }).rows).toContainEqual(
472
- expect.objectContaining({ key: "2026-08-03", prd_count: 1, spec_count: 1, task_count: 1 }),
476
+ expect.objectContaining({ key: "2026-08-03", prd_count: 1, spec_count: 1, task_count: 0 }),
473
477
  );
474
478
  expect(filesystem.viewPage("cost_monitor_monthly", { limit: 50 }).rows).toContainEqual(
475
- expect.objectContaining({ key: "2026-08", prd_count: 2, spec_count: 3, task_count: 3 }),
479
+ expect.objectContaining({ key: "2026-08", prd_count: 2, spec_count: 3, task_count: 0 }),
476
480
  );
477
481
  expect(filesystem.viewPage("cost_monitor_annual", { limit: 50 }).rows).toContainEqual(
478
- expect.objectContaining({ key: "2026", prd_count: 2, spec_count: 3, task_count: 3 }),
482
+ expect.objectContaining({ key: "2026", prd_count: 2, spec_count: 3, task_count: 0 }),
479
483
  );
480
484
  const annualCostPage = filesystem.viewPage("cost_monitor_annual", { limit: 50 });
481
485
  const dailyCostRows = filesystem.viewPage("cost_monitor_daily", { limit: 50 }).rows;
@@ -515,6 +519,21 @@ describe("SQLite dashboard read model", () => {
515
519
  observed.length === 0 ? null : observed.reduce((sum, value) => sum + value, 0),
516
520
  );
517
521
  }
522
+ const filteredFirst = filesystem.viewPage("cost_monitor_daily", {
523
+ limit: 1,
524
+ provider: "openai",
525
+ });
526
+ const filteredNext = filesystem.viewPage("cost_monitor_daily", {
527
+ limit: 1,
528
+ offset: 1,
529
+ provider: "openai",
530
+ });
531
+ expect(filteredFirst.totals).toEqual(filteredNext.totals);
532
+ expect(filteredFirst.period_averages).toEqual(filteredNext.period_averages);
533
+ expect(filteredFirst).toMatchObject({
534
+ totals: { task_count: 0, total_cost_brl: 15 },
535
+ period_averages: { BRL: { tasks: 0, tokens: 3, cost: 7.5 } },
536
+ });
518
537
  expect(
519
538
  filesystem.viewPage("cost_monitor_daily", { limit: 50, provider: "openai" }).rows,
520
539
  ).toContainEqual(
@@ -522,7 +541,7 @@ describe("SQLite dashboard read model", () => {
522
541
  key: "2026-08-02",
523
542
  prd_count: 0,
524
543
  spec_count: 1,
525
- task_count: 1,
544
+ task_count: 0,
526
545
  validation_count: 1,
527
546
  evidence_count: 0,
528
547
  }),
@@ -635,6 +654,7 @@ describe("SQLite dashboard read model", () => {
635
654
  });
636
655
  expect(filesystem.firstFoldAllTime()).toBe(allTime);
637
656
  filesystem.close();
657
+ readers.delete(filesystem);
638
658
 
639
659
  // Period membership follows the canonical macro day, not an invocation
640
660
  // that happened on another day. Search accepts either the macro ID or
@@ -674,6 +694,7 @@ describe("SQLite dashboard read model", () => {
674
694
  );
675
695
  await rebuildSqliteReadModel(root);
676
696
  const canonicalDayFilesystem = new SqliteReadModelFileSystem(root);
697
+ readers.add(canonicalDayFilesystem);
677
698
  expect(
678
699
  canonicalDayFilesystem.viewPage("cost_monitor_specs", {
679
700
  from: "2026-08-03",
@@ -702,6 +723,7 @@ describe("SQLite dashboard read model", () => {
702
723
  }),
703
724
  ).toMatchObject({ total_count: 0, rows: [] });
704
725
  canonicalDayFilesystem.close();
726
+ readers.delete(canonicalDayFilesystem);
705
727
 
706
728
  // A large result set keeps its subtotal for all 270 matching Tasks while
707
729
  // the page transports only 50 records.
@@ -717,6 +739,7 @@ describe("SQLite dashboard read model", () => {
717
739
  }
718
740
  await rebuildSqliteReadModel(root);
719
741
  const pageFilesystem = new SqliteReadModelFileSystem(root);
742
+ readers.add(pageFilesystem);
720
743
  const paged = pageFilesystem.viewPage("cost_monitor_tasks", {
721
744
  from: "2026-08-04",
722
745
  to: "2026-08-04",
@@ -735,5 +758,6 @@ describe("SQLite dashboard read model", () => {
735
758
  total_cost_brl: 1_350,
736
759
  });
737
760
  pageFilesystem.close();
761
+ readers.delete(pageFilesystem);
738
762
  });
739
763
  });
@@ -344,14 +344,28 @@ export class SqliteReadModelFileSystem extends WorkspaceFileSystem {
344
344
  return queryTopTasks(this.queryContext(), filter, limit);
345
345
  }
346
346
 
347
- canonicalTraceFiles(markers: readonly string[]): Array<{ path: string; content: string }> {
347
+ canonicalTraceFiles(
348
+ markers: readonly string[],
349
+ maxContentLength?: number,
350
+ ): Array<{ path: string; content: string }> {
348
351
  const selected = [...new Set(markers.filter(Boolean))];
349
352
  if (selected.length === 0) return [];
353
+ if (
354
+ maxContentLength !== undefined &&
355
+ (!Number.isSafeInteger(maxContentLength) || maxContentLength < 0)
356
+ )
357
+ throw new Error("Invalid trace content bound");
350
358
  const clauses = selected.map(() => "content LIKE ?").join(" OR ");
359
+ // SQL counts code points while the caller retains its UTF-16 length check.
360
+ // This conservative prefilter never excludes an otherwise admissible file.
361
+ const bound = maxContentLength === undefined ? "" : " AND length(content) <= ?";
351
362
  return this.database
352
363
  .prepare(`SELECT path, content FROM files
353
- WHERE (path LIKE '.agents/data/%' OR path LIKE '.agents/records/%') AND (${clauses}) ORDER BY path`)
354
- .all(...selected.map((marker) => `%${marker}%`)) as Array<{
364
+ WHERE (path LIKE '.agents/data/%' OR path LIKE '.agents/records/%')${bound} AND (${clauses}) ORDER BY path`)
365
+ .all(
366
+ ...(maxContentLength === undefined ? [] : [maxContentLength]),
367
+ ...selected.map((marker) => `%${marker}%`),
368
+ ) as Array<{
355
369
  path: string;
356
370
  content: string;
357
371
  }>;
@@ -210,7 +210,7 @@ describe("SQLite dashboard read model", () => {
210
210
  snapshot
211
211
  .prepare("SELECT value FROM zaip_vw_read_model_metadata WHERE key='schema_version'")
212
212
  .get(),
213
- ).toEqual({ value: "74" });
213
+ ).toEqual({ value: "79" });
214
214
  } finally {
215
215
  snapshot.close();
216
216
  }