@zaip-ai/cli 3.3.0 → 3.4.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 (263) hide show
  1. package/dist/services/adapters.d.ts +1 -1
  2. package/dist/services/adapters.d.ts.map +1 -1
  3. package/dist/services/adapters.js +4 -3
  4. package/dist/services/adapters.js.map +1 -1
  5. package/dist/services/agent-catalog-upgrade.d.ts +3 -0
  6. package/dist/services/agent-catalog-upgrade.d.ts.map +1 -0
  7. package/dist/services/agent-catalog-upgrade.js +35 -0
  8. package/dist/services/agent-catalog-upgrade.js.map +1 -0
  9. package/dist/services/install-agents-template.d.ts.map +1 -1
  10. package/dist/services/install-agents-template.js +22 -22
  11. package/dist/services/install-agents-template.js.map +1 -1
  12. package/dist/services/install-template-policy.d.ts +3 -0
  13. package/dist/services/install-template-policy.d.ts.map +1 -0
  14. package/dist/services/install-template-policy.js +21 -0
  15. package/dist/services/install-template-policy.js.map +1 -0
  16. package/dist/services/logger.test.js +12 -2
  17. package/dist/services/logger.test.js.map +1 -1
  18. package/dist/services/sqlite-bootstrap.d.ts +1 -0
  19. package/dist/services/sqlite-bootstrap.d.ts.map +1 -1
  20. package/dist/services/sqlite-bootstrap.js +10 -1
  21. package/dist/services/sqlite-bootstrap.js.map +1 -1
  22. package/package.json +2 -2
  23. package/templates/.agents/config/agents/discovery.json +1 -1
  24. package/templates/.agents/dashboard/.zaip-managed.json +260 -116
  25. package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-BBFDrn64.js → CostCalculationGuidePage-C5NgEcVh.js} +1 -1
  26. package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-Cd-qo9w7.js → DashboardHelpDialog-CCMVnkkI.js} +1 -1
  27. package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-J7L5m8lk.js → PricingSettingsDialog-CGYcJ5EB.js} +1 -1
  28. package/templates/.agents/dashboard/apps/frontend/dist/assets/{ProjectSettingsPage-BpsAFy0g.js → ProjectSettingsPage-DVCPPV75.js} +1 -1
  29. package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-BzVtGLWS.js → TraceabilityWorkspace-CqK3Psfy.js} +1 -1
  30. package/templates/.agents/dashboard/apps/frontend/dist/assets/{cost-monitor-PoJA2PI1.css → cost-monitor-BsMfGfQi.css} +1 -1
  31. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-j3aUYH5G.js +68 -0
  32. package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-CWzf_RiP.js → icons-vendor-x8xxL9yW.js} +1 -1
  33. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-Cl5EWx8R.js +2 -0
  34. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-Cwylbh_N.css +1 -0
  35. package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-CtHdbZk3.js → react-vendor-CNOXIJHN.js} +1 -1
  36. package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-BKrDH2TR.js → traceability-CcpbpT1s.js} +1 -1
  37. package/templates/.agents/dashboard/apps/frontend/dist/index.html +7 -7
  38. package/templates/.agents/dashboard/apps/frontend/package.json +1 -1
  39. package/templates/.agents/dashboard/apps/frontend/src/App.tsx +12 -1
  40. package/templates/.agents/dashboard/apps/frontend/src/WorkspaceStatus.test.tsx +33 -0
  41. package/templates/.agents/dashboard/apps/frontend/src/WorkspaceStatus.tsx +58 -0
  42. package/templates/.agents/dashboard/apps/frontend/src/app-work-board-options.ts +41 -0
  43. package/templates/.agents/dashboard/apps/frontend/src/dashboard-runtime-status.ts +25 -0
  44. package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +1 -1
  45. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.ts +5 -1
  46. package/templates/.agents/dashboard/apps/frontend/src/use-app-work-board.test.ts +140 -0
  47. package/templates/.agents/dashboard/apps/frontend/src/use-app-work-board.ts +28 -41
  48. package/templates/.agents/dashboard/apps/frontend/src/use-runtime-status.ts +38 -0
  49. package/templates/.agents/dashboard/apps/frontend/src/workspace-status.css +33 -0
  50. package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
  51. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.test.ts +25 -3
  52. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.tsx +17 -19
  53. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.tsx +13 -167
  54. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostGroupsTable.tsx +2 -9
  55. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.test.ts +8 -8
  56. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +29 -52
  57. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableLoading.test.ts +1 -1
  58. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables-keeps-legacy-codex-identity-fields-blank.test.ts +2 -2
  59. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +4 -27
  60. package/templates/.agents/dashboard/modules/cost-monitor/src/react/MacroCostTable.test.ts +2 -2
  61. package/templates/.agents/dashboard/modules/cost-monitor/src/react/MacroCostTable.tsx +4 -3
  62. package/templates/.agents/dashboard/modules/cost-monitor/src/react/agent-model-presentation.test.ts +26 -0
  63. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-embedded.css +7 -0
  64. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-loaders.ts +173 -0
  65. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-page-props.ts +47 -0
  66. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-page-selectors.ts +1 -7
  67. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-page-range.ts +3 -9
  68. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.test.ts +44 -83
  69. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.ts +11 -111
  70. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.test.ts +47 -181
  71. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.ts +63 -91
  72. package/templates/.agents/dashboard/modules/cost-monitor/src/server/cost-monitor-unavailable.test.ts +55 -0
  73. package/templates/.agents/dashboard/modules/cost-monitor/src/server/cost-summary-duration.test.ts +189 -0
  74. package/templates/.agents/dashboard/modules/operations/package.json +1 -1
  75. package/templates/.agents/dashboard/modules/operations/src/react/OperationsEntityFilters.tsx +82 -0
  76. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +22 -31
  77. package/templates/.agents/dashboard/modules/operations/src/react/PagedWorkList.test.tsx +13 -1
  78. package/templates/.agents/dashboard/modules/operations/src/react/PagedWorkList.tsx +16 -3
  79. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +11 -27
  80. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +44 -193
  81. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportColumns.ts +186 -0
  82. package/templates/.agents/dashboard/modules/operations/src/react/export/excel-agent-participations.test.ts +28 -0
  83. package/templates/.agents/dashboard/modules/operations/src/react/export/export-layout.test.ts +2 -1
  84. package/templates/.agents/dashboard/modules/operations/src/react/operations-export-duration.ts +13 -0
  85. package/templates/.agents/dashboard/modules/operations/src/react/operations-filter-panel.css +4 -0
  86. package/templates/.agents/dashboard/modules/operations/src/react/use-operation-filter-feedback.ts +18 -0
  87. package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.test.ts +11 -0
  88. package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.ts +10 -2
  89. package/templates/.agents/dashboard/modules/operations/src/work-board-model.ts +1 -1
  90. package/templates/.agents/dashboard/modules/traceability/package.json +1 -1
  91. package/templates/.agents/dashboard/packages/branding/package.json +1 -1
  92. package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
  93. package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
  94. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +395 -341
  95. package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +346 -294
  96. package/templates/.agents/dashboard/packages/local-runtime/package.json +1 -1
  97. package/templates/.agents/dashboard/packages/local-runtime/scripts/rebuild-sqlite-read-model.mjs +2 -1
  98. package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-sqlite-read-model.mjs +4 -2
  99. package/templates/.agents/dashboard/packages/local-runtime/server.mjs +395 -341
  100. package/templates/.agents/dashboard/packages/local-runtime/src/active-codex-telemetry.test.ts +95 -0
  101. package/templates/.agents/dashboard/packages/local-runtime/src/active-codex-telemetry.ts +102 -12
  102. package/templates/.agents/dashboard/packages/local-runtime/src/server-board.test.ts +75 -1
  103. package/templates/.agents/dashboard/packages/local-runtime/src/server-costs-routes.ts +10 -0
  104. package/templates/.agents/dashboard/packages/local-runtime/src/server-lifecycle-diagnostics.ts +50 -0
  105. package/templates/.agents/dashboard/packages/local-runtime/src/server-macro-population.test.ts +165 -0
  106. package/templates/.agents/dashboard/packages/local-runtime/src/server-operations-page-filters.ts +65 -0
  107. package/templates/.agents/dashboard/packages/local-runtime/src/server-operations-pages.test.ts +111 -0
  108. package/templates/.agents/dashboard/packages/local-runtime/src/server-operations-pages.ts +53 -63
  109. package/templates/.agents/dashboard/packages/local-runtime/src/server-operations-runs-route.ts +19 -5
  110. package/templates/.agents/dashboard/packages/local-runtime/src/server-period-macro-metric.ts +11 -2
  111. package/templates/.agents/dashboard/packages/local-runtime/src/server-read-projections.ts +16 -9
  112. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-refresh.test.ts +46 -2
  113. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-synchronization.test.ts +10 -2
  114. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-synchronization.ts +4 -3
  115. package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +43 -1
  116. package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +46 -11
  117. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-filter-matrix.test.ts +188 -0
  118. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-summary-details.test.ts +85 -0
  119. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-summary-details.ts +147 -0
  120. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-cache.ts +64 -54
  121. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-macro-classification.test.ts +172 -0
  122. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-materialize-projections.ts +1 -1
  123. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-projection.ts +2 -1
  124. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.test.ts +7 -7
  125. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.ts +2 -1
  126. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-period-averages.ts +10 -1
  127. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-agent-dimension.ts +18 -82
  128. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-cached-cost-page.ts +169 -0
  129. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-developer.ts +205 -0
  130. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-entity-group.ts +13 -4
  131. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-filtered-dimension.ts +22 -23
  132. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-financial.ts +42 -209
  133. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-model-dimension.ts +18 -4
  134. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-provider-dimension.ts +9 -2
  135. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-summary.ts +76 -83
  136. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-view-page.ts +25 -161
  137. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-canonical.ts +18 -45
  138. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-counts-every-root-execution-day-returns.test.ts +2 -2
  139. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-filesystem.ts +16 -16
  140. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider.test.ts +1 -1
  141. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-rebuild.ts +47 -22
  142. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-schema.ts +3 -2
  143. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +11 -0
  144. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-rebuild-result.ts +15 -0
  145. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-schema-base-views.ts +4 -4
  146. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-schema-dashboard-views.ts +15 -56
  147. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-schema-macro-classification.ts +48 -0
  148. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-summary-cursor.ts +15 -0
  149. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-token-active-allocation.ts +46 -0
  150. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-work-stages.ts +60 -0
  151. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-history.mjs +5 -1
  152. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-claims.test.mjs +7 -1
  153. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.mjs +17 -2
  154. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-ownership.mjs +65 -0
  155. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-ownership.test.mjs +72 -0
  156. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-processes.mjs +32 -9
  157. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +39 -45
  158. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +5 -2
  159. package/templates/.agents/dashboard/packages/ui/package.json +1 -1
  160. package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
  161. package/templates/.agents/dashboard/tests/e2e/specs/dashboard-performance-matrix.spec.ts +1 -18
  162. package/templates/.agents/dashboard/tests/e2e/specs/export-row-identity.spec.ts +20 -0
  163. package/templates/.agents/dashboard/tests/e2e/specs/export-row-identity.ts +20 -0
  164. package/templates/.agents/design/.zaip-managed.json +82 -74
  165. package/templates/.agents/design/apps/catalog/dist/assets/index-0W0Gj_Gs.css +1 -0
  166. package/templates/.agents/design/apps/catalog/dist/assets/index-32GZO95T.js +72 -0
  167. package/templates/.agents/design/apps/catalog/dist/assets/{index-D_lfqoyx.js → index-BP8IxOxt.js} +3 -3
  168. package/templates/.agents/design/apps/catalog/dist/assets/{index-BOjCcUaU.js → index-QJsgr9Ht.js} +3 -3
  169. package/templates/.agents/design/apps/catalog/dist/index.html +2 -2
  170. package/templates/.agents/design/apps/catalog/dist/storybook/assets/CatalogShell-CvaciY0C.js +1 -0
  171. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{Color-6AOWCN3U-Cm-yJJz_.js → Color-6AOWCN3U-DwBV1A1Y.js} +1 -1
  172. package/templates/.agents/design/apps/catalog/dist/storybook/assets/Components.stories-3dqK5g3e.js +142 -0
  173. package/templates/.agents/design/apps/catalog/dist/storybook/assets/DesignSystem.stories-2OCgtT0I.js +1 -0
  174. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{DocsRenderer-JROSPFPF-Belk4jRr.js → DocsRenderer-JROSPFPF-CODg0rSl.js} +4 -4
  175. package/templates/.agents/design/apps/catalog/dist/storybook/assets/Primitives-BmeKjJW4.js +1 -0
  176. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{WithTooltip-7X4HQR7L-DoPvjkS1.js → WithTooltip-7X4HQR7L-C5MI-3uZ.js} +1 -1
  177. package/templates/.agents/design/apps/catalog/dist/storybook/assets/WorkspaceStatus.stories-Tb_iQqVK.js +17 -0
  178. package/templates/.agents/design/apps/catalog/dist/storybook/assets/WorkspaceStatusSpecimen-CD54pw0-.js +1 -0
  179. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{chunk-DRQKCCAG-B1itKXEN.js → chunk-DRQKCCAG-KSn75jcy.js} +1 -1
  180. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{chunk-W22LQPXL-C-Eb5SPY.js → chunk-W22LQPXL-C4LS1Thf.js} +1 -1
  181. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{components-DnyKLwhj.js → components-DV1BRgMY.js} +5 -5
  182. package/templates/.agents/design/apps/catalog/dist/storybook/assets/formatter-L2YTDE3Q-BU_68im1.js +1 -0
  183. package/templates/.agents/design/apps/catalog/dist/storybook/assets/iframe-0W0Gj_Gs.css +1 -0
  184. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{iframe-DcXBsFPz.js → iframe-CBbPFx5G.js} +4 -4
  185. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{react-18-CRM89QRf.js → react-18-C9IPGXtb.js} +1 -1
  186. package/templates/.agents/design/apps/catalog/dist/storybook/assets/react-CEv2qkJT.js +1 -0
  187. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{syntaxhighlighter-YFXUGROL-B03jQGTF.js → syntaxhighlighter-YFXUGROL-ZgDQjyWI.js} +1 -1
  188. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{theming-4ZyufAga.js → theming-Cx9-gH6l.js} +1 -1
  189. package/templates/.agents/design/apps/catalog/dist/storybook/iframe.html +2 -2
  190. package/templates/.agents/design/apps/catalog/dist/storybook/index.json +1 -1
  191. package/templates/.agents/design/apps/catalog/dist/storybook/sb-addons/a11y-2/manager-bundle.js +3 -3
  192. package/templates/.agents/design/apps/catalog/dist/storybook/sb-addons/docs-1/manager-bundle.js +4 -4
  193. package/templates/.agents/design/apps/catalog/dist/storybook/sb-addons/storybook-core-server-presets-0/common-manager-bundle.js +60 -60
  194. package/templates/.agents/design/apps/catalog/package.json +1 -1
  195. package/templates/.agents/design/apps/catalog/src/components/DashboardFiltersSpecimen.tsx +61 -0
  196. package/templates/.agents/design/apps/catalog/src/components/Primitives.tsx +24 -0
  197. package/templates/.agents/design/apps/catalog/src/components/WorkspaceStatusSpecimen.tsx +26 -0
  198. package/templates/.agents/design/apps/catalog/src/design-contract.test.ts +27 -13
  199. package/templates/.agents/design/apps/catalog/src/pages/ComponentsPage.tsx +38 -0
  200. package/templates/.agents/design/apps/catalog/src/pages/DesignSystemPage.tsx +15 -1
  201. package/templates/.agents/design/apps/catalog/src/stories/Components.stories.tsx +18 -0
  202. package/templates/.agents/design/apps/catalog/src/stories/DashboardFilters.stories.tsx +7 -0
  203. package/templates/.agents/design/apps/catalog/src/stories/WorkspaceStatus.stories.tsx +9 -0
  204. package/templates/.agents/design/apps/catalog/src/styles/components.css +83 -2
  205. package/templates/.agents/design/apps/catalog/src/styles.css +2 -0
  206. package/templates/.agents/design/packages/local-runtime/package.json +1 -1
  207. package/templates/.agents/design/tokens.json +32 -0
  208. package/templates/.agents/requirements/autonomous-assurance.md +1 -1
  209. package/templates/.agents/requirements/cloud-hostinger-autonomy.md +1 -1
  210. package/templates/.agents/requirements/comparative-audit.md +1 -1
  211. package/templates/.agents/requirements/context-engine.md +1 -1
  212. package/templates/.agents/requirements/cost-observability.md +1 -1
  213. package/templates/.agents/requirements/dashboard-launch.md +1 -1
  214. package/templates/.agents/requirements/data-export.md +1 -1
  215. package/templates/.agents/requirements/design-system.md +1 -1
  216. package/templates/.agents/requirements/execution-engine.md +1 -1
  217. package/templates/.agents/requirements/kanban-dashboard.md +1 -1
  218. package/templates/.agents/requirements/model-orchestration.md +1 -1
  219. package/templates/.agents/requirements/public-distribution.md +9 -3
  220. package/templates/.agents/requirements/software-architecture.md +1 -1
  221. package/templates/.agents/requirements/strategic-improvements.md +1 -1
  222. package/templates/.agents/requirements/work-lifecycle.md +1 -1
  223. package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
  224. package/templates/.agents/rules/autonomy-decision.md +1 -0
  225. package/templates/.agents/rules/workflow.md +1 -1
  226. package/templates/.agents/runtime/VERSION +1 -1
  227. package/templates/.agents/runtime/bin/zaip.mjs +25 -24
  228. package/templates/.agents/runtime/checksums.sha256 +5 -5
  229. package/templates/.agents/runtime/manifest.json +1 -1
  230. package/templates/.agents/runtime/provenance.json +4 -4
  231. package/templates/.agents/runtime/sbom.cdx.json +1 -1
  232. package/templates/.agents/skills/zaip-skill-execution/SKILL.md +13 -0
  233. package/templates/.agents/skills/zaip-skill-execution/references/autonomous-continuation.md +17 -0
  234. package/templates/.agents/skills/zaip-skill-execution/references/correction-cycle.md +2 -2
  235. package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +4 -2
  236. package/templates/.agents/skills/zaip-skill-github-deploy/references/deployment-workflow.md +4 -2
  237. package/templates/.agents/skills/zaip-skill-github-deploy/references/release-identity.md +2 -2
  238. package/templates/.agents/skills/zaip-skill-move-prd/SKILL.md +4 -0
  239. package/templates/.agents/skills/zaip-skill-move-spec/SKILL.md +4 -0
  240. package/templates/.agents/skills/zaip-skill-prd/SKILL.md +3 -3
  241. package/templates/.agents/skills/zaip-skill-release-qualification/SKILL.md +11 -8
  242. package/templates/.agents/skills/zaip-skill-release-qualification/references/local-preparation.md +13 -12
  243. package/templates/.agents/skills/zaip-skill-setup/SKILL.md +17 -2
  244. package/templates/.agents/skills/zaip-skill-setup/agents/openai.yaml +1 -1
  245. package/templates/.agents/skills/zaip-skill-spec/SKILL.md +2 -2
  246. package/templates/.agents/zaip-aios/VERSION +1 -1
  247. package/templates/template-manifest.json +392 -236
  248. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor--iPcnZdx.js +0 -68
  249. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-Cmlx8OYH.css +0 -1
  250. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-DfdlGa7c.js +0 -2
  251. package/templates/.agents/design/apps/catalog/dist/assets/index-BEmIE7WE.css +0 -1
  252. package/templates/.agents/design/apps/catalog/dist/assets/index-BJV597iq.js +0 -72
  253. package/templates/.agents/design/apps/catalog/dist/assets/index-B_WhrCZe.js +0 -72
  254. package/templates/.agents/design/apps/catalog/dist/assets/index-CqqYWY2f.js +0 -9
  255. package/templates/.agents/design/apps/catalog/dist/assets/index-CqtYXZfV.js +0 -72
  256. package/templates/.agents/design/apps/catalog/dist/assets/index-D9pj7Jlf.js +0 -9
  257. package/templates/.agents/design/apps/catalog/dist/assets/index-i_PO2k9R.js +0 -9
  258. package/templates/.agents/design/apps/catalog/dist/storybook/assets/CatalogShell-Cstn1UwA.js +0 -1
  259. package/templates/.agents/design/apps/catalog/dist/storybook/assets/Components.stories-D1WopB2L.js +0 -137
  260. package/templates/.agents/design/apps/catalog/dist/storybook/assets/DesignSystem.stories-DQ9PJ3N3.js +0 -1
  261. package/templates/.agents/design/apps/catalog/dist/storybook/assets/formatter-L2YTDE3Q-D0OSgxWz.js +0 -1
  262. package/templates/.agents/design/apps/catalog/dist/storybook/assets/iframe-BEmIE7WE.css +0 -1
  263. package/templates/.agents/design/apps/catalog/dist/storybook/assets/react-C3tkVMIp.js +0 -1
@@ -0,0 +1,95 @@
1
+ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { afterEach, describe, expect, it } from "vitest";
5
+
6
+ import { captureActiveCodexTelemetry } from "./active-codex-telemetry.js";
7
+
8
+ const roots: string[] = [];
9
+
10
+ afterEach(async () => {
11
+ await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
12
+ });
13
+
14
+ describe("active Codex telemetry capture", () => {
15
+ it("reports an idle capture explicitly instead of treating it as an opaque success", async () => {
16
+ const root = await runtimeFixture(
17
+ "process.stdout.write(JSON.stringify({ telemetry: { mode: 'active_exact_session', captured: [] } }, null, 2));\n",
18
+ );
19
+
20
+ await expect(captureActiveCodexTelemetry(root)).resolves.toMatchObject({
21
+ captured_runs: 0,
22
+ captured_segments: 0,
23
+ manifest_state: "initialized",
24
+ skipped_reason: "no_active_runs",
25
+ last_capture_at: expect.any(String),
26
+ });
27
+ });
28
+
29
+ it("returns a typed manifest condition when the lifecycle has not been initialized", async () => {
30
+ const root = await runtimeFixture(
31
+ "process.stderr.write('Lifecycle manifest is not initialized'); process.exitCode = 1;\n",
32
+ );
33
+
34
+ await expect(captureActiveCodexTelemetry(root)).resolves.toMatchObject({
35
+ captured_runs: 0,
36
+ captured_segments: 0,
37
+ manifest_state: "missing",
38
+ skipped_reason: "manifest_uninitialized",
39
+ });
40
+ });
41
+ it("does not accept CLI idle success as proof of initialized lifecycle", async () => {
42
+ const root = await runtimeFixture(
43
+ "process.stdout.write(JSON.stringify({ telemetry: { captured: [] } }));",
44
+ );
45
+ await rm(join(root, ".agents/records/lifecycle"), { recursive: true });
46
+ await expect(captureActiveCodexTelemetry(root)).resolves.toMatchObject({
47
+ manifest_state: "missing",
48
+ skipped_reason: "manifest_uninitialized",
49
+ });
50
+ });
51
+ it("preserves unavailable segment cardinality for a captured Run", async () => {
52
+ const root = await runtimeFixture(
53
+ "process.stdout.write(JSON.stringify({ telemetry: { captured: [{captured:true}] } }, null, 2));",
54
+ );
55
+ await expect(captureActiveCodexTelemetry(root)).resolves.toMatchObject({
56
+ captured_runs: 1,
57
+ captured_segments: null,
58
+ skipped_reason: null,
59
+ });
60
+ });
61
+ it("rejects malformed successful command output", async () => {
62
+ const root = await runtimeFixture(
63
+ "process.stdout.write(JSON.stringify({ error: 'unavailable' }));",
64
+ );
65
+ await expect(captureActiveCodexTelemetry(root)).rejects.toThrow("Invalid capture telemetry");
66
+ });
67
+ });
68
+
69
+ async function runtimeFixture(script: string): Promise<string> {
70
+ const root = await mkdtemp(join(tmpdir(), "zaip-active-telemetry-"));
71
+ roots.push(root);
72
+ const runtime = join(root, ".agents", "runtime", "bin");
73
+ await mkdir(runtime, { recursive: true });
74
+ await writeFile(join(runtime, "zaip.mjs"), script, "utf8");
75
+ if (!script.includes("not initialized")) {
76
+ const lifecycle = join(root, ".agents/records/lifecycle");
77
+ await mkdir(lifecycle, { recursive: true });
78
+ await writeFile(
79
+ join(lifecycle, "manifest.json"),
80
+ JSON.stringify({ schema_version: 1, updated_at: "2026-09-16T00:00:00Z", offsets: {} }),
81
+ );
82
+ await writeFile(
83
+ join(lifecycle, "summary.json"),
84
+ JSON.stringify({
85
+ schema_version: 1,
86
+ updated_at: "2026-09-16T00:00:00Z",
87
+ counts: { total: 0, by_kind: {}, by_status: {} },
88
+ freshness: {},
89
+ usage: {},
90
+ periods: {},
91
+ }),
92
+ );
93
+ }
94
+ return root;
95
+ }
@@ -1,25 +1,115 @@
1
1
  import { execFile } from "node:child_process";
2
2
  import { resolve } from "node:path";
3
3
  import { promisify } from "node:util";
4
+ import { WorkspaceFileSystem } from "@zaip-ai/core";
5
+ import { lifecycleManifestState } from "./server-lifecycle-diagnostics.js";
4
6
 
5
7
  const execFileAsync = promisify(execFile);
6
8
 
9
+ export type ActiveCodexTelemetryCapture = {
10
+ captured_runs: number;
11
+ /** The active CLI reports whether a Run changed, not its segment cardinality. */
12
+ captured_segments: number | null;
13
+ manifest_state: "initialized" | "missing" | "invalid";
14
+ skipped_reason:
15
+ | "manifest_uninitialized"
16
+ | "manifest_invalid"
17
+ | "no_active_runs"
18
+ | "no_new_segments"
19
+ | null;
20
+ last_capture_at: string;
21
+ };
22
+
7
23
  /**
8
24
  * Captures only active Runs whose persisted Codex correlation names a concrete
9
25
  * turn. The CLI reuses source segment and loop keys as its durable cursor;
10
26
  * this never reconciles or changes a Run lifecycle.
11
27
  */
12
- export async function captureActiveCodexTelemetry(workspaceRoot: string): Promise<void> {
28
+ export async function captureActiveCodexTelemetry(
29
+ workspaceRoot: string,
30
+ ): Promise<ActiveCodexTelemetryCapture> {
31
+ // The CLI intentionally treats an absent active-work index as an empty pass.
32
+ // Validate the canonical manifest first so that exit 0 cannot mask missing lifecycle.
33
+ const manifestState = await lifecycleManifestState(new WorkspaceFileSystem(workspaceRoot));
34
+ if (manifestState !== "initialized")
35
+ return {
36
+ captured_runs: 0,
37
+ captured_segments: 0,
38
+ manifest_state: manifestState,
39
+ skipped_reason: manifestState === "missing" ? "manifest_uninitialized" : "manifest_invalid",
40
+ last_capture_at: new Date().toISOString(),
41
+ };
13
42
  const cliPath = resolve(workspaceRoot, ".agents", "runtime", "bin", "zaip.mjs");
14
- await execFileAsync(
15
- process.execPath,
16
- [cliPath, "run", "usage", "--active", "--limit", "1", "--disable-codex-raw", "--json"],
17
- {
18
- cwd: workspaceRoot,
19
- encoding: "utf8",
20
- windowsHide: true,
21
- timeout: 55_000,
22
- maxBuffer: 1_024 * 1_024,
23
- },
24
- );
43
+ try {
44
+ const outcome = await execFileAsync(
45
+ process.execPath,
46
+ [cliPath, "run", "usage", "--active", "--limit", "1", "--disable-codex-raw", "--json"],
47
+ {
48
+ cwd: workspaceRoot,
49
+ encoding: "utf8",
50
+ windowsHide: true,
51
+ timeout: 55_000,
52
+ maxBuffer: 1_024 * 1_024,
53
+ },
54
+ );
55
+ const payload = parseJsonResult(outcome.stdout);
56
+ const captured = readCaptured(payload);
57
+ const capturedRuns = captured.filter((item) => item.captured).length;
58
+ return {
59
+ captured_runs: capturedRuns,
60
+ // Zero is factual for an idle pass. A non-idle pass has no segment count
61
+ // in the CLI contract, so retain unavailable rather than inventing one.
62
+ captured_segments: capturedRuns === 0 ? 0 : null,
63
+ manifest_state: "initialized",
64
+ skipped_reason:
65
+ captured.length === 0 ? "no_active_runs" : capturedRuns === 0 ? "no_new_segments" : null,
66
+ last_capture_at: new Date().toISOString(),
67
+ };
68
+ } catch (error) {
69
+ if (isManifestUninitialized(error)) {
70
+ return {
71
+ captured_runs: 0,
72
+ captured_segments: 0,
73
+ manifest_state: "missing",
74
+ skipped_reason: "manifest_uninitialized",
75
+ last_capture_at: new Date().toISOString(),
76
+ };
77
+ }
78
+ throw error;
79
+ }
80
+ }
81
+
82
+ function parseJsonResult(stdout: string): unknown {
83
+ if (!stdout.trim()) throw new Error("Active telemetry capture returned no JSON result");
84
+ try {
85
+ return JSON.parse(stdout.trim()) as unknown;
86
+ } catch {
87
+ throw new Error("Active telemetry capture returned invalid JSON");
88
+ }
89
+ }
90
+
91
+ function readCaptured(payload: unknown): Array<{ captured: boolean }> {
92
+ if (typeof payload !== "object" || payload === null) throw new Error("Invalid capture payload");
93
+ const telemetry = (payload as { telemetry?: unknown }).telemetry;
94
+ if (typeof telemetry !== "object" || telemetry === null)
95
+ throw new Error("Invalid capture telemetry");
96
+ const captured = (telemetry as { captured?: unknown }).captured;
97
+ if (!Array.isArray(captured)) throw new Error("Invalid capture entries");
98
+ return captured.map((item) => {
99
+ if (
100
+ typeof item !== "object" ||
101
+ item === null ||
102
+ typeof (item as { captured?: unknown }).captured !== "boolean"
103
+ )
104
+ throw new Error("Invalid capture entry");
105
+ return { captured: (item as { captured: boolean }).captured };
106
+ });
107
+ }
108
+
109
+ function isManifestUninitialized(error: unknown): boolean {
110
+ const details =
111
+ error instanceof Error
112
+ ? `${error.message}\n${"stdout" in error ? String(error.stdout ?? "") : ""}\n${"stderr" in error ? String(error.stderr ?? "") : ""}`
113
+ : String(error);
114
+ return details.includes("Lifecycle manifest is not initialized");
25
115
  }
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { boardPage } from "./server-board.js";
2
+ import { boardPage, boardStage } from "./server-board.js";
3
3
 
4
4
  describe("boardPage", () => {
5
5
  it("returns only the bounded entity page without Run-derived enrichment", () => {
@@ -126,6 +126,80 @@ describe("boardPage", () => {
126
126
  expect(page.total).toBe(2);
127
127
  expect(page.tasks.map((task) => task.id)).toEqual([linked.id, standalone.id]);
128
128
  });
129
+
130
+ it.each([
131
+ ["definition", "PRD-1"],
132
+ ["planning", "SPEC-1"],
133
+ ["ready", "TASK-READY"],
134
+ ["executing", "TASK-EXECUTING"],
135
+ ["verifying", "TASK-VERIFYING"],
136
+ ["completed", "TASK-COMPLETED"],
137
+ ["blocked", "TASK-BLOCKED"],
138
+ ["cancelled", "TASK-CANCELLED"],
139
+ ["failed", "TASK-FAILED"],
140
+ ] as const)("keeps the %s status page discriminated by canonical work state", (stage, id) => {
141
+ const tasks = [
142
+ "ready",
143
+ "executing",
144
+ "verifying",
145
+ "completed",
146
+ "blocked",
147
+ "cancelled",
148
+ "failed",
149
+ ].map((status) => ({
150
+ id: `TASK-${status.toUpperCase()}`,
151
+ title: status,
152
+ status: status === "ready" ? "planned" : status,
153
+ spec_id: "SPEC-1",
154
+ updated_at: "2026-09-16T10:00:00.000Z",
155
+ }));
156
+ const projection = {
157
+ changes: [],
158
+ tasks,
159
+ prds: [{ ...macro("PRD-1", "prd", []), lifecycle_status: "draft" }],
160
+ specs: [{ ...macro("SPEC-1", "spec", []), lifecycle_status: "draft" }],
161
+ } as unknown as Parameters<typeof boardPage>[0];
162
+ const page = boardPage(projection, boardStage(stage), 0, 10, [], {
163
+ query: "",
164
+ status: "",
165
+ risk: "",
166
+ origin: "",
167
+ kind: "",
168
+ });
169
+ const returnedIds = [...page.prds, ...page.specs, ...page.tasks].map((row) => row.id);
170
+ expect(returnedIds).toEqual([id]);
171
+ });
172
+
173
+ it.each([
174
+ ["prd", "draft", "definition"],
175
+ ["spec", "draft", "planning"],
176
+ ["prd", "ready", "ready"],
177
+ ["spec", "active", "executing"],
178
+ ["prd", "verifying", "verifying"],
179
+ ["spec", "delivered", "completed"],
180
+ ["prd", "blocked", "blocked"],
181
+ ["spec", "cancelled", "cancelled"],
182
+ ["prd", "failed", "failed"],
183
+ ] as const)("uses the canonical %s %s status on its %s board page", (kind, lifecycleStatus, stage) => {
184
+ const macroRow = {
185
+ ...macro(`${kind.toUpperCase()}-1`, kind, []),
186
+ lifecycle_status: lifecycleStatus,
187
+ };
188
+ const projection = {
189
+ changes: [],
190
+ tasks: [],
191
+ prds: kind === "prd" ? [macroRow] : [],
192
+ specs: kind === "spec" ? [macroRow] : [],
193
+ } as unknown as Parameters<typeof boardPage>[0];
194
+ const page = boardPage(projection, boardStage(stage), 0, 10, [], {
195
+ query: "",
196
+ status: "",
197
+ risk: "",
198
+ origin: "",
199
+ kind: "",
200
+ });
201
+ expect([...page.prds, ...page.specs].map((row) => row.id)).toEqual([macroRow.id]);
202
+ });
129
203
  });
130
204
 
131
205
  function macro(id: string, kind: "prd" | "spec", taskIds: string[]) {
@@ -34,6 +34,7 @@ export function registerCostsRoutes(app: Hono, dependencies: DashboardRouteConte
34
34
  const aggregateStartedAt = performance.now();
35
35
  const [source, rate] = await Promise.all([
36
36
  firstFoldCostSource(filesystem, {
37
+ query: context.req.query("query") ?? "",
37
38
  from,
38
39
  to,
39
40
  providers: queryValues(context, "provider"),
@@ -46,6 +47,15 @@ export function registerCostsRoutes(app: Hono, dependencies: DashboardRouteConte
46
47
  prds: queryValues(context, "prd"),
47
48
  executions: queryValues(context, "execution"),
48
49
  changes: queryValues(context, "change"),
50
+ priorities: queryValues(context, "priority"),
51
+ risks: queryValues(context, "risk"),
52
+ origins: queryValues(context, "origin"),
53
+ workTypes: [
54
+ ...new Set([
55
+ ...queryValues(context, "workType"),
56
+ ...queryValues(context, "work_type"),
57
+ ]),
58
+ ],
49
59
  }),
50
60
  currency === "BRL" ? readCurrentFxRate(filesystem) : Promise.resolve(null),
51
61
  ]);
@@ -0,0 +1,50 @@
1
+ import type { WorkspaceFileSystem } from "@zaip-ai/core";
2
+
3
+ export type LifecycleManifestState = "initialized" | "missing" | "invalid";
4
+ const record = (value: unknown): value is Record<string, unknown> =>
5
+ typeof value === "object" && value !== null && !Array.isArray(value);
6
+ const timestamp = (value: unknown) =>
7
+ typeof value === "string" && Number.isFinite(Date.parse(value));
8
+
9
+ /** Read lifecycle health from canonical records, never from the SQLite snapshot. */
10
+ export async function lifecycleManifestState(
11
+ filesystem: WorkspaceFileSystem,
12
+ ): Promise<LifecycleManifestState> {
13
+ const root = ".agents/records/lifecycle";
14
+ const [manifestExists, summaryExists] = await Promise.all([
15
+ filesystem.exists(`${root}/manifest.json`),
16
+ filesystem.exists(`${root}/summary.json`),
17
+ ]);
18
+ if (!manifestExists && !summaryExists) return "missing";
19
+ if (!manifestExists || !summaryExists) return "invalid";
20
+ try {
21
+ const [manifest, summary] = await Promise.all([
22
+ filesystem.readText(`${root}/manifest.json`).then((value) => JSON.parse(value) as unknown),
23
+ filesystem.readText(`${root}/summary.json`).then((value) => JSON.parse(value) as unknown),
24
+ ]);
25
+ if (
26
+ !record(manifest) ||
27
+ manifest.schema_version !== 1 ||
28
+ !timestamp(manifest.updated_at) ||
29
+ !record(manifest.offsets) ||
30
+ !Object.values(manifest.offsets).every(
31
+ (value) => Number.isSafeInteger(value) && Number(value) >= 0,
32
+ ) ||
33
+ !record(summary) ||
34
+ summary.schema_version !== 1 ||
35
+ !timestamp(summary.updated_at) ||
36
+ !record(summary.counts) ||
37
+ !Number.isSafeInteger(summary.counts.total) ||
38
+ Number(summary.counts.total) < 0 ||
39
+ !record(summary.counts.by_kind) ||
40
+ !record(summary.counts.by_status) ||
41
+ !record(summary.freshness) ||
42
+ !record(summary.usage) ||
43
+ !record(summary.periods)
44
+ )
45
+ return "invalid";
46
+ return "initialized";
47
+ } catch {
48
+ return "invalid";
49
+ }
50
+ }
@@ -0,0 +1,165 @@
1
+ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
2
+ import { join, resolve } from "node:path";
3
+ import { expect, it, vi } from "vitest";
4
+ import { createDashboardApp } from "./server.js";
5
+ import { requireV2Layout } from "./server-http-contracts.js";
6
+ import { buildFirstFoldQuickProjection } from "./server-read-projections.js";
7
+ import { rebuildSqliteReadModel, SqliteReadModelFileSystem } from "./sqlite-read-model.js";
8
+
9
+ it("keeps draft and ready SPEC/PRD cards, stages and classification consistent in compact and full responses", async () => {
10
+ const parent = resolve(import.meta.dirname, "../../../../../../.local/sqlite/tests");
11
+ await mkdir(parent, { recursive: true });
12
+ const root = await mkdtemp(join(parent, "macro-population-"));
13
+ let filesystem: SqliteReadModelFileSystem | undefined;
14
+ try {
15
+ await mkdir(join(root, ".agents/config"), { recursive: true });
16
+ await writeFile(
17
+ join(root, ".agents/config/project.yaml"),
18
+ "schema_version: 1\nzaip:\n enabled: true\nproject:\n id: macro-test\n name: macro-test\n timezone: UTC\nstack:\n id: zaip-aios-stack\n overrides: {}\nclients:\n codex: true\n claude: true\ntracking:\n enabled: true\n currency: BRL\n storage_mode: tracked_sanitized\n",
19
+ );
20
+ await writeFile(
21
+ join(root, ".agents/config/framework.lock.yaml"),
22
+ "lock_version: 1\nframework:\n version: 3.4.0\n distribution_sha256: null\nlayout:\n version: 3\nresolved_profile:\n id: null\n sha256: null\nmanaged_files: {}\n",
23
+ );
24
+ const record = async (kind: string, id: string, status: string, extra = "") => {
25
+ const directory = join(root, ".agents/records", kind, "2026/09");
26
+ await mkdir(directory, { recursive: true });
27
+ await writeFile(
28
+ join(directory, id + ".md"),
29
+ `---\nid: ${id}\ntitle: ${id}\nstatus: ${status}\ncreated_at: 2026-09-01T12:00:00.000Z\n${extra}---\n`,
30
+ );
31
+ };
32
+ for (const state of ["draft", "ready", "active", "active-completed"]) {
33
+ await record(
34
+ "specs",
35
+ "SPEC-MACRO",
36
+ state.startsWith("active") ? "active" : state,
37
+ "prd_id: PRD-MACRO\n",
38
+ );
39
+ await record("prds", "PRD-MACRO", state.startsWith("active") ? "active" : state);
40
+ if (state === "ready" || state.startsWith("active")) {
41
+ await record(
42
+ "tasks",
43
+ "TASK-MACRO",
44
+ state === "active-completed"
45
+ ? "completed"
46
+ : state.startsWith("active")
47
+ ? "verifying"
48
+ : "planned",
49
+ "change_id: CHG-MACRO\nrisk: standard\n",
50
+ );
51
+ const changes = join(root, ".agents/records/changes/2026/09/CHG-MACRO");
52
+ await mkdir(changes, { recursive: true });
53
+ await writeFile(
54
+ join(changes, "change.md"),
55
+ "---\nid: CHG-MACRO\ntitle: Macro delivery\nstatus: planned\ncreated_at: 2026-09-01T12:00:00.000Z\nsource:\n type: spec\n spec_id: SPEC-MACRO\ntask_ids: [TASK-MACRO]\n---\n",
56
+ );
57
+ }
58
+ await rebuildSqliteReadModel(root);
59
+ filesystem = new SqliteReadModelFileSystem(root);
60
+ const app = createDashboardApp(root, "fixture-only", undefined, {
61
+ filesystem,
62
+ watchSources: false,
63
+ });
64
+ const fullRead = vi.spyOn(filesystem, "firstFoldAllTime");
65
+ const entityRead = vi.spyOn(filesystem, "canonicalWorkPage");
66
+ const compact = await buildFirstFoldQuickProjection(
67
+ filesystem,
68
+ await requireV2Layout(filesystem),
69
+ { from: null, to: null },
70
+ );
71
+ expect(compact.summary.overview_metrics?.macro_metrics?.specs.status_counts).toMatchObject({
72
+ [state.startsWith("active") ? "verifying" : state === "ready" ? "ready" : "planning"]: 1,
73
+ });
74
+ expect(fullRead).not.toHaveBeenCalled();
75
+ expect(entityRead).not.toHaveBeenCalled();
76
+ for (const query of [
77
+ "scope=quick",
78
+ "scope=overview",
79
+ "scope=quick&from=2026-09-01&to=2026-09-30",
80
+ ]) {
81
+ const response = await app.request("/api/v2/operations?" + query, {
82
+ headers: { "x-zaip-session": "fixture-only" },
83
+ });
84
+ expect(response.status, await response.clone().text()).toBe(200);
85
+ const data = (await response.json()) as any;
86
+ const overview = data.summary.overview_metrics;
87
+ expect(overview.spec_count).toBe(1);
88
+ expect(overview.prd_count).toBe(1);
89
+ expect(overview.task_count).toBe(state === "draft" ? 0 : 1);
90
+ for (const [kind, draftStage] of [
91
+ ["specs", "planning"],
92
+ ["prds", "definition"],
93
+ ] as const) {
94
+ const metric = overview.macro_metrics[kind];
95
+ expect(metric.entity_count).toBe(1);
96
+ expect(metric.status_counts).toMatchObject({
97
+ [state.startsWith("active") ? "verifying" : state === "ready" ? "ready" : draftStage]:
98
+ 1,
99
+ });
100
+ expect(metric.classification_counts).toMatchObject({
101
+ [state === "draft" ? "empty" : "structured"]: 1,
102
+ });
103
+ for (const counts of [metric.status_counts, metric.classification_counts]) {
104
+ expect(
105
+ Object.values(counts).reduce((sum: number, value) => sum + Number(value), 0),
106
+ ).toBe(1);
107
+ }
108
+ expect(metric.total_tokens).toBeNull();
109
+ expect(metric.total_cost_brl).toBeNull();
110
+ }
111
+ if (query === "scope=quick") {
112
+ expect(data.tasks).toEqual([]);
113
+ }
114
+ }
115
+ const boardResponse = await app.request(
116
+ "/api/v2/operations?scope=board&stage=" +
117
+ (state.startsWith("active") ? "verifying" : state === "ready" ? "ready" : "planning"),
118
+ { headers: { "x-zaip-session": "fixture-only" } },
119
+ );
120
+ expect(boardResponse.status).toBe(200);
121
+ const board = (await boardResponse.json()) as any;
122
+ expect(board.specs[0]).toMatchObject({
123
+ task_count: state === "draft" ? 0 : 1,
124
+ task_ids: state === "draft" ? [] : ["TASK-MACRO"],
125
+ });
126
+ if (state === "ready" || state.startsWith("active")) {
127
+ expect(board.prds[0]).toMatchObject({ task_count: 1, task_ids: ["TASK-MACRO"] });
128
+ if (state !== "active-completed")
129
+ expect(board.tasks[0]).toMatchObject({ spec_id: "SPEC-MACRO", origin: "spec" });
130
+ for (const kind of ["spec", "prd"]) {
131
+ const response = await app.request(
132
+ "/api/v2/operations?scope=classification&kind=" + kind + "&classification=structured",
133
+ { headers: { "x-zaip-session": "fixture-only" } },
134
+ );
135
+ const classified = (await response.json()) as any;
136
+ expect(classified.total).toBe(1);
137
+ }
138
+ }
139
+ const stage = state.startsWith("active")
140
+ ? "verifying"
141
+ : state === "ready"
142
+ ? "ready"
143
+ : "planning";
144
+ const listResponse = await app.request(
145
+ "/api/v2/sqlite-views?view=operations_work_list&status=" + stage,
146
+ { headers: { "x-zaip-session": "fixture-only" } },
147
+ );
148
+ expect(listResponse.status).toBe(200);
149
+ const list = (await listResponse.json()) as any;
150
+ expect(list.rows.some((row: any) => row.id === "SPEC-MACRO" && row.stage === stage)).toBe(
151
+ true,
152
+ );
153
+ if (state.startsWith("active"))
154
+ expect(
155
+ list.rows.some((row: any) => row.id === "PRD-MACRO" && row.stage === "verifying"),
156
+ ).toBe(true);
157
+ filesystem.close();
158
+ filesystem = undefined;
159
+ }
160
+ } finally {
161
+ vi.restoreAllMocks();
162
+ filesystem?.close();
163
+ await rm(root, { recursive: true, force: true });
164
+ }
165
+ });
@@ -0,0 +1,65 @@
1
+ import type { Context } from "hono";
2
+ import type { OperationsCompactRun } from "./server-operations-pages.js";
3
+
4
+ interface OperationsPageFilterValues {
5
+ query: string;
6
+ status: string;
7
+ risk: string;
8
+ }
9
+
10
+ export function operationsPageFilters(context: Context): OperationsPageFilterValues {
11
+ return {
12
+ query: (context.req.query("query") ?? "").trim().toLocaleLowerCase(),
13
+ status: (context.req.query("status") ?? "").trim(),
14
+ risk: (context.req.query("risk") ?? "").trim(),
15
+ };
16
+ }
17
+
18
+ export function filterOperationsMetricRows(
19
+ rows: readonly OperationsCompactRun[],
20
+ filters: OperationsPageFilterValues,
21
+ ): OperationsCompactRun[] {
22
+ return rows.filter((row) => {
23
+ if (filters.status && row.status !== filters.status) return false;
24
+ if (!filters.query) return true;
25
+ return [
26
+ row.id,
27
+ row.task_id,
28
+ row.execution_id,
29
+ row.conversation_id,
30
+ row.parent_run_id,
31
+ row.run_kind,
32
+ row.phase,
33
+ row.agent,
34
+ ].some(
35
+ (value) => typeof value === "string" && value.toLocaleLowerCase().includes(filters.query),
36
+ );
37
+ });
38
+ }
39
+
40
+ export function filterLifecyclePageRows(
41
+ rows: readonly Record<string, unknown>[],
42
+ filters: OperationsPageFilterValues,
43
+ ): Record<string, unknown>[] {
44
+ return rows.filter((row) => {
45
+ if (filters.status && row.status !== filters.status) return false;
46
+ if (filters.risk && row.risk !== filters.risk) return false;
47
+ if (!filters.query) return true;
48
+ return [
49
+ row.id,
50
+ row.title,
51
+ row.status,
52
+ row.risk,
53
+ row.source,
54
+ row.origin,
55
+ row.scope_type,
56
+ row.scope_id,
57
+ ]
58
+ .flatMap((value) =>
59
+ typeof value === "object" && value !== null ? Object.values(value) : [value],
60
+ )
61
+ .some(
62
+ (value) => typeof value === "string" && value.toLocaleLowerCase().includes(filters.query),
63
+ );
64
+ });
65
+ }