@zaip-ai/cli 1.0.8 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. package/README.md +1 -1
  2. package/dist/services/adapters.d.ts +1 -1
  3. package/dist/services/adapters.js +1 -1
  4. package/dist/services/agent-adapters.js +3 -3
  5. package/dist/services/agent-adapters.js.map +1 -1
  6. package/dist/services/agent-adapters.test.js +7 -1
  7. package/dist/services/agent-adapters.test.js.map +1 -1
  8. package/dist/services/codex-pre-tool-hook-template.d.ts.map +1 -1
  9. package/dist/services/codex-pre-tool-hook-template.js +89 -7
  10. package/dist/services/codex-pre-tool-hook-template.js.map +1 -1
  11. package/dist/services/codex-rules.d.ts +1 -1
  12. package/dist/services/codex-rules.d.ts.map +1 -1
  13. package/dist/services/codex-rules.js +7 -0
  14. package/dist/services/codex-rules.js.map +1 -1
  15. package/dist/services/install-agents-template.d.ts.map +1 -1
  16. package/dist/services/install-agents-template.js +1 -0
  17. package/dist/services/install-agents-template.js.map +1 -1
  18. package/dist/services/logger.test.js +2 -2
  19. package/dist/services/runtime-template.test.js +31 -7
  20. package/dist/services/runtime-template.test.js.map +1 -1
  21. package/dist/services/template-manifest.d.ts.map +1 -1
  22. package/dist/services/template-manifest.js +12 -3
  23. package/dist/services/template-manifest.js.map +1 -1
  24. package/package.json +1 -1
  25. package/templates/.agents/architecture/software-architecture.md +131 -0
  26. package/templates/.agents/branding/brandbook.docx +0 -0
  27. package/templates/.agents/branding/brandbook.md +60 -0
  28. package/templates/.agents/config/agents/catalog.yaml +7 -7
  29. package/templates/.agents/config/clients/codex/agents/zaip-agent-backend.toml +2 -2
  30. package/templates/.agents/config/clients/codex/agents/zaip-agent-designer.toml +2 -2
  31. package/templates/.agents/config/clients/codex/agents/zaip-agent-finalizer.toml +1 -1
  32. package/templates/.agents/config/clients/codex/agents/zaip-agent-frontend.toml +8 -8
  33. package/templates/.agents/config/clients/codex/agents/zaip-agent-orchestrator.toml +1 -1
  34. package/templates/.agents/dashboard/.tmp-run-list.json +254 -0
  35. package/templates/.agents/dashboard/.zaip-managed.json +457 -173
  36. package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-Z60df2r-.js → CostCalculationGuidePage-ovxurkIk.js} +1 -1
  37. package/templates/.agents/dashboard/apps/frontend/dist/assets/DashboardHelpDialog-BgVgrfhQ.js +2310 -0
  38. package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-Coc6pA-1.js → PricingSettingsDialog-vSvvOHQp.js} +1 -1
  39. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-BomxqCBU.css +1 -0
  40. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-zH758vfs.js +3 -0
  41. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-DLn-Mz2M.js +1 -0
  42. package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-CaKwQP43.css → TraceabilityWorkspace-DvvavDLY.css} +1 -1
  43. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-DKwP1stV.js +68 -0
  44. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-PoJA2PI1.css +1 -0
  45. package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-DFBuc_qp.js → icons-vendor-B_lDDHn1.js} +1 -1
  46. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-B31GMG5O.css +1 -0
  47. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-CZQlsLV9.js +2 -0
  48. package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-CCQOHdVI.js → react-vendor-B3TJrD4O.js} +1 -1
  49. package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-pC2_0J8x.js → traceability-7f1j5wx3.js} +1 -1
  50. package/templates/.agents/dashboard/apps/frontend/dist/index.html +7 -7
  51. package/templates/.agents/dashboard/apps/frontend/package.json +1 -1
  52. package/templates/.agents/dashboard/apps/frontend/playwright.dom.config.ts +32 -0
  53. package/templates/.agents/dashboard/apps/frontend/src/App.tsx +199 -140
  54. package/templates/.agents/dashboard/apps/frontend/src/AppOverlays.tsx +0 -21
  55. package/templates/.agents/dashboard/apps/frontend/src/DashboardAlternateContent.tsx +20 -11
  56. package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsPage.tsx +14 -7
  57. package/templates/.agents/dashboard/apps/frontend/src/ProjectStackEditor.tsx +4 -2
  58. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.dom.e2e.ts +56 -0
  59. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.test.ts +21 -2
  60. package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.tsx +89 -19
  61. package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +19 -4
  62. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +49 -3
  63. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +29 -10
  64. package/templates/.agents/dashboard/apps/frontend/src/operations-period-render.test.ts +4 -4
  65. package/templates/.agents/dashboard/apps/frontend/src/overview-status-page.test.ts +4 -2
  66. package/templates/.agents/dashboard/apps/frontend/src/project-settings-page.css +36 -26
  67. package/templates/.agents/dashboard/apps/frontend/src/project-settings.test.ts +2 -2
  68. package/templates/.agents/dashboard/apps/frontend/src/snapshot-banner-semantics.test.ts +47 -6
  69. package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +59 -9
  70. package/templates/.agents/dashboard/apps/frontend/src/sqlite-page-export.test.ts +32 -0
  71. package/templates/.agents/dashboard/apps/frontend/src/sqlite-page-export.ts +21 -0
  72. package/templates/.agents/dashboard/apps/frontend/src/styles.css +19 -0
  73. package/templates/.agents/dashboard/apps/frontend/src/traceability-task-pagination.test.ts +32 -0
  74. package/templates/.agents/dashboard/apps/frontend/src/traceability-task-pagination.ts +36 -0
  75. package/templates/.agents/dashboard/apps/frontend/src/traceability-workspace.css +6 -2
  76. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.test.ts +137 -23
  77. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.ts +229 -35
  78. package/templates/.agents/dashboard/apps/frontend/src/use-app-effects.ts +61 -7
  79. package/templates/.agents/dashboard/apps/frontend/src/use-app-operations-pages.ts +3 -6
  80. package/templates/.agents/dashboard/apps/frontend/src/use-app-trace-documents.ts +7 -1
  81. package/templates/.agents/dashboard/apps/frontend/src/use-app-work-list-page.test.ts +163 -0
  82. package/templates/.agents/dashboard/apps/frontend/src/use-app-work-list-page.ts +136 -0
  83. package/templates/.agents/dashboard/apps/frontend/src/use-operations-detail-export.ts +76 -0
  84. package/templates/.agents/dashboard/apps/frontend/src/work-list-load-dedup.test.ts +23 -0
  85. package/templates/.agents/dashboard/apps/frontend/src/work-list-load-dedup.ts +27 -0
  86. package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.test.ts +39 -15
  87. package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.ts +3 -4
  88. package/templates/.agents/dashboard/apps/frontend/vite.config.ts +4 -1
  89. package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
  90. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.test.ts +89 -19
  91. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.tsx +31 -16
  92. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostCharts.test.ts +43 -14
  93. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostCharts.tsx +5 -5
  94. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionPanel.tsx +60 -0
  95. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionTable.tsx +191 -0
  96. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.loading.test.ts +14 -0
  97. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.run-page.test.ts +18 -0
  98. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.tsx +18 -3
  99. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostModelsAuditTable.tsx +1 -1
  100. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorContent.tsx +75 -44
  101. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorLoadErrors.tsx +35 -0
  102. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.test.ts +162 -40
  103. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +221 -79
  104. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableLoading.test.ts +132 -0
  105. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableLoading.tsx +70 -0
  106. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +203 -155
  107. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.tsx +164 -125
  108. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-copy.ts +2 -0
  109. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-views.ts +3 -1
  110. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor.css +5 -2
  111. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-page-range.ts +35 -0
  112. package/templates/.agents/dashboard/modules/cost-monitor/src/react/index.ts +2 -2
  113. package/templates/.agents/dashboard/modules/cost-monitor/src/react/period-cost-groups.ts +2 -1
  114. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-compact-cost-page.ts +32 -9
  115. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.test.ts +37 -2
  116. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.ts +131 -9
  117. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-run-page.ts +34 -17
  118. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.test.ts +0 -24
  119. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.test.ts +225 -424
  120. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.ts +24 -15
  121. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-terminal-day.test.ts +6 -1
  122. package/templates/.agents/dashboard/modules/cost-monitor/src/server/source-size-cost-server/build-cost-monitor-projection-agents.test.ts +31 -0
  123. package/templates/.agents/dashboard/modules/cost-monitor/src/server/source-size-cost-server/build-cost-summary-projection-duration.test.ts +414 -0
  124. package/templates/.agents/dashboard/modules/operations/package.json +1 -1
  125. package/templates/.agents/dashboard/modules/operations/src/contracts.ts +46 -26
  126. package/templates/.agents/dashboard/modules/operations/src/react/DeveloperAttributionPanel.test.ts +54 -0
  127. package/templates/.agents/dashboard/modules/operations/src/react/DeveloperAttributionPanel.tsx +247 -0
  128. package/templates/.agents/dashboard/modules/operations/src/react/EntityTables.tsx +31 -11
  129. package/templates/.agents/dashboard/modules/operations/src/react/OperationsMainContent.tsx +39 -13
  130. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.helpers.tsx +107 -2
  131. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.macro-metrics.test.ts +55 -0
  132. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.test.ts +23 -29
  133. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +211 -184
  134. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverviewTopPanel.tsx +127 -0
  135. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +60 -51
  136. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageNavigation.tsx +1 -4
  137. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageOverview.tsx +3 -0
  138. package/templates/.agents/dashboard/modules/operations/src/react/PagedWorkList.test.tsx +43 -0
  139. package/templates/.agents/dashboard/modules/operations/src/react/PagedWorkList.tsx +181 -0
  140. package/templates/.agents/dashboard/modules/operations/src/react/PeriodSummaryTable.tsx +32 -10
  141. package/templates/.agents/dashboard/modules/operations/src/react/TaskDetailsDialog.tsx +9 -3
  142. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkBoard.tsx +13 -5
  143. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.test.ts +16 -6
  144. package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.tsx +14 -4
  145. package/templates/.agents/dashboard/modules/operations/src/react/conversation-rows.ts +1 -2
  146. package/templates/.agents/dashboard/modules/operations/src/react/developer-identities.test.ts +18 -0
  147. package/templates/.agents/dashboard/modules/operations/src/react/developer-identities.ts +30 -0
  148. package/templates/.agents/dashboard/modules/operations/src/react/execution-metrics.ts +1 -0
  149. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +393 -4
  150. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +484 -61
  151. package/templates/.agents/dashboard/modules/operations/src/react/export/export-layout.test.ts +23 -1
  152. package/templates/.agents/dashboard/modules/operations/src/react/export/xlsx-runtime-e2e.test.ts +248 -0
  153. package/templates/.agents/dashboard/modules/operations/src/react/index.ts +1 -0
  154. package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.test.ts +4 -4
  155. package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.ts +6 -4
  156. package/templates/.agents/dashboard/modules/operations/src/react/operations-coverage-toast.test.ts +4 -3
  157. package/templates/.agents/dashboard/modules/operations/src/react/operations-date-filters.css +1 -1
  158. package/templates/.agents/dashboard/modules/operations/src/react/operations-global-filters.test.ts +4 -1
  159. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +22 -12
  160. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview.css +4 -0
  161. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview.status-cards.test.ts +1 -1
  162. package/templates/.agents/dashboard/modules/operations/src/react/operations-page-contract.ts +53 -6
  163. package/templates/.agents/dashboard/modules/operations/src/react/operations-view-order.test.ts +2 -4
  164. package/templates/.agents/dashboard/modules/operations/src/react/period-summary.test.ts +82 -6
  165. package/templates/.agents/dashboard/modules/operations/src/react/period-summary.ts +1 -0
  166. package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.test.ts +2 -1
  167. package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.ts +1 -1
  168. package/templates/.agents/dashboard/modules/operations/src/server/execution-relationship-counts.test.ts +19 -7
  169. package/templates/.agents/dashboard/modules/operations/src/server/execution-relationship-counts.ts +4 -1
  170. package/templates/.agents/dashboard/modules/operations/src/server/metric-coverage.ts +1 -0
  171. package/templates/.agents/dashboard/modules/operations/src/server/quick-daily-operations-projection.ts +11 -5
  172. package/templates/.agents/dashboard/modules/traceability/package.json +1 -1
  173. package/templates/.agents/dashboard/packages/branding/package.json +1 -1
  174. package/templates/.agents/dashboard/packages/branding/src/index.ts +1 -1
  175. package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
  176. package/templates/.agents/dashboard/packages/contracts/src/index.ts +1 -0
  177. package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
  178. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +533 -338
  179. package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +506 -311
  180. package/templates/.agents/dashboard/packages/local-runtime/gitignore.template +2 -0
  181. package/templates/.agents/dashboard/packages/local-runtime/package.json +1 -1
  182. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-dashboard.mjs +15 -7
  183. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-runtime.mjs +44 -13
  184. package/templates/.agents/dashboard/packages/local-runtime/scripts/rebuild-sqlite-read-model.mjs +8 -3
  185. package/templates/.agents/dashboard/packages/local-runtime/scripts/source-size-runtime-scripts/sqlite-read-model-fixture.mjs +397 -0
  186. package/templates/.agents/dashboard/packages/local-runtime/scripts/test-sqlite-read-model.mjs +472 -145
  187. package/templates/.agents/dashboard/packages/local-runtime/scripts/test-unix-launchers.mjs +15 -3
  188. package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-sqlite-read-model.mjs +141 -33
  189. package/templates/.agents/dashboard/packages/local-runtime/server.mjs +533 -338
  190. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.test.ts +6 -2
  191. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.ts +3 -3
  192. package/templates/.agents/dashboard/packages/local-runtime/src/server-board.test.ts +89 -16
  193. package/templates/.agents/dashboard/packages/local-runtime/src/server-board.ts +33 -16
  194. package/templates/.agents/dashboard/packages/local-runtime/src/server-classification-page.test.ts +87 -0
  195. package/templates/.agents/dashboard/packages/local-runtime/src/server-period-macro-metric.test.ts +44 -0
  196. package/templates/.agents/dashboard/packages/local-runtime/src/server-period-macro-metric.ts +125 -0
  197. package/templates/.agents/dashboard/packages/local-runtime/src/server-reconciliation-refresh.test.ts +66 -0
  198. package/templates/.agents/dashboard/packages/local-runtime/src/server-request-authority.test.ts +61 -0
  199. package/templates/.agents/dashboard/packages/local-runtime/src/server-request-authority.ts +18 -0
  200. package/templates/.agents/dashboard/packages/local-runtime/src/server-run-projections.test.ts +42 -0
  201. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-refresh.ts +97 -0
  202. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot.test.ts +22 -5
  203. package/templates/.agents/dashboard/packages/local-runtime/src/server-sqlite-task-trace.ts +91 -0
  204. package/templates/.agents/dashboard/packages/local-runtime/src/server-workspace.ts +7 -3
  205. package/templates/.agents/dashboard/packages/local-runtime/src/server.test-fixtures.ts +36 -0
  206. package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +230 -132
  207. package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +224 -182
  208. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-artifact-counts.ts +28 -0
  209. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.test.ts +63 -0
  210. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.ts +109 -0
  211. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-aggregates.ts +497 -0
  212. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-fast-page-parity.test-support.ts +65 -0
  213. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-page.test.ts +176 -0
  214. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-page.ts +119 -0
  215. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-projection.ts +41 -0
  216. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.test.ts +16 -0
  217. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.ts +29 -0
  218. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-cache.ts +355 -0
  219. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-persistence.ts +121 -0
  220. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-timing.ts +27 -0
  221. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-metric-contract.ts +16 -2
  222. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-projection.ts +15 -0
  223. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.test.ts +223 -0
  224. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.ts +304 -0
  225. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-cache.test-support.ts +23 -0
  226. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-first-fold-types.ts +89 -0
  227. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider-fixture.ts +227 -0
  228. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider.test.ts +691 -0
  229. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.ts +81 -0
  230. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +1655 -567
  231. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +2168 -1268
  232. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-cache.ts +129 -0
  233. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-install.test.ts +26 -0
  234. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-install.ts +28 -0
  235. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-seed.test.ts +116 -0
  236. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.mjs +146 -0
  237. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.test.mjs +165 -0
  238. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-refresh.mjs +140 -0
  239. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +255 -289
  240. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +94 -88
  241. package/templates/.agents/dashboard/packages/ui/package.json +1 -1
  242. package/templates/.agents/dashboard/packages/windows-launcher/Program.cs +5 -2
  243. package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
  244. package/templates/.agents/dashboard/tests/e2e/playwright.config.ts +4 -1
  245. package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-loading.spec.ts +142 -0
  246. package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-pagination.spec.ts +232 -0
  247. package/templates/.agents/dashboard/tests/e2e/specs/dashboard-performance-matrix.spec.ts +743 -0
  248. package/templates/.agents/dashboard/tests/e2e/specs/dashboard.spec.ts +189 -214
  249. package/templates/.agents/dashboard/zaip-dashboard-windows.exe +0 -0
  250. package/templates/.agents/design/.zaip-managed.json +3 -3
  251. package/templates/.agents/design/apps/catalog/package.json +1 -1
  252. package/templates/.agents/design/packages/local-runtime/package.json +1 -1
  253. package/templates/.agents/growth/estrategia-bootstrap-90-dias.md +169 -0
  254. package/templates/.agents/growth/strategy.md +27 -0
  255. package/templates/.agents/marketing/estrategia-marketing-zaip-90-dias.md +197 -0
  256. package/templates/.agents/marketing/strategy.md +29 -0
  257. package/templates/.agents/requirements/autonomous-assurance.md +6 -6
  258. package/templates/.agents/requirements/comparative-audit.md +1 -1
  259. package/templates/.agents/requirements/context-engine.md +1 -1
  260. package/templates/.agents/requirements/cost-observability.md +1 -1
  261. package/templates/.agents/requirements/dashboard-launch.md +1 -1
  262. package/templates/.agents/requirements/data-export.md +1 -1
  263. package/templates/.agents/requirements/design-system.md +1 -1
  264. package/templates/.agents/requirements/execution-engine.md +3 -3
  265. package/templates/.agents/requirements/kanban-dashboard.md +10 -2
  266. package/templates/.agents/requirements/model-orchestration.md +1 -1
  267. package/templates/.agents/requirements/public-distribution.md +1 -1
  268. package/templates/.agents/requirements/software-architecture.md +1 -1
  269. package/templates/.agents/requirements/strategic-improvements.md +1 -1
  270. package/templates/.agents/requirements/work-lifecycle.md +4 -4
  271. package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
  272. package/templates/.agents/rules/dashboard-ui-consistency.md +14 -0
  273. package/templates/.agents/rules/frontend-lite.md +4 -4
  274. package/templates/.agents/rules/run-lifecycle-closure.md +4 -4
  275. package/templates/.agents/runtime/VERSION +1 -1
  276. package/templates/.agents/runtime/bin/zaip.mjs +1142 -1041
  277. package/templates/.agents/runtime/checksums.sha256 +6 -6
  278. package/templates/.agents/runtime/manifest.json +1 -1
  279. package/templates/.agents/runtime/pnpm-lock.sha256 +1 -1
  280. package/templates/.agents/runtime/provenance.json +5 -5
  281. package/templates/.agents/runtime/sbom.cdx.json +3 -3
  282. package/templates/.agents/sales/playbook.md +32 -0
  283. package/templates/.agents/sales/roteiro-comercial-zaip.md +252 -0
  284. package/templates/.agents/skills/criar-pasta-obsidian/scripts/generate-obsidian-vault.test.mjs +20 -16
  285. package/templates/.agents/skills/zaip-aios/SKILL.md +1 -1
  286. package/templates/.agents/skills/zaip-skill-agent-catalog/SKILL.md +22 -0
  287. package/templates/.agents/skills/zaip-skill-agent-catalog/agents/openai.yaml +4 -0
  288. package/templates/.agents/skills/zaip-skill-author-skills/SKILL.md +3 -2
  289. package/templates/.agents/skills/zaip-skill-author-skills/scripts/audit-skill-catalog.mjs +49 -0
  290. package/templates/.agents/skills/zaip-skill-author-skills/scripts/author-skill-scripts.test.mjs +27 -0
  291. package/templates/.agents/skills/zaip-skill-author-skills/scripts/run-skill-tests.mjs +37 -0
  292. package/templates/.agents/skills/zaip-skill-backend/SKILL.md +1 -0
  293. package/templates/.agents/skills/zaip-skill-brand-governance/SKILL.md +9 -2
  294. package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-framework.md +39 -0
  295. package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-standards.md +1 -1
  296. package/templates/.agents/skills/zaip-skill-change/SKILL.md +1 -1
  297. package/templates/.agents/skills/zaip-skill-change/references/observable-evidence.md +83 -0
  298. package/templates/.agents/skills/zaip-skill-dashboard-diagnostics/SKILL.md +22 -0
  299. package/templates/.agents/skills/zaip-skill-dashboard-diagnostics/agents/openai.yaml +4 -0
  300. package/templates/.agents/skills/zaip-skill-enforce-architecture/SKILL.md +2 -0
  301. package/templates/.agents/skills/zaip-skill-execution/SKILL.md +1 -1
  302. package/templates/.agents/skills/zaip-skill-frontend/SKILL.md +4 -3
  303. package/templates/.agents/skills/zaip-skill-frontend/agents/openai.yaml +2 -2
  304. package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +10 -10
  305. package/templates/.agents/skills/zaip-skill-growth-strategy-revops/SKILL.md +6 -0
  306. package/templates/.agents/skills/zaip-skill-lifecycle-closure/SKILL.md +27 -0
  307. package/templates/.agents/skills/zaip-skill-lifecycle-closure/agents/openai.yaml +4 -0
  308. package/templates/.agents/skills/zaip-skill-marketing/SKILL.md +6 -0
  309. package/templates/.agents/skills/zaip-skill-prd/SKILL.md +4 -0
  310. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.mjs +111 -104
  311. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-explicit-recovery.mjs +223 -0
  312. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.mjs +55 -9
  313. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.test.mjs +145 -14
  314. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.mjs +19 -9
  315. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.test.mjs +82 -5
  316. package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/source-size-telemetry/model-identity-reconciliation.mjs +77 -0
  317. package/templates/.agents/skills/zaip-skill-release-qualification/SKILL.md +20 -0
  318. package/templates/.agents/skills/zaip-skill-release-qualification/agents/openai.yaml +4 -0
  319. package/templates/.agents/skills/zaip-skill-review/SKILL.md +5 -0
  320. package/templates/.agents/skills/zaip-skill-rules/SKILL.md +1 -1
  321. package/templates/.agents/skills/zaip-skill-sales-methodology/SKILL.md +6 -0
  322. package/templates/.agents/skills/zaip-skill-spec/SKILL.md +4 -0
  323. package/templates/.agents/skills/zaip-skill-sqlite-read-model/SKILL.md +22 -90
  324. package/templates/.agents/skills/zaip-skill-sqlite-read-model/scripts/ensure-node.mjs +28 -5
  325. package/templates/.agents/zaip-aios/INDEX.md +57 -22
  326. package/templates/.agents/zaip-aios/README.md +24 -13
  327. package/templates/.agents/zaip-aios/VERSION +1 -1
  328. package/templates/.agents/zaip-aios/guides/02-requirements.md +5 -0
  329. package/templates/.agents/zaip-aios/guides/06-execucao.md +13 -4
  330. package/templates/.agents/zaip-aios/guides/07-revisao-e-validacao.md +7 -0
  331. package/templates/.agents/zaip-aios/guides/10-seguranca.md +23 -0
  332. package/templates/.agents/zaip-aios/guides/11-observabilidade-e-custos.md +6 -6
  333. package/templates/.agents/zaip-aios/guides/13-boas-praticas.md +3 -0
  334. package/templates/.agents/zaip-aios/guides/16-lifecycle-e-reconciliacao.md +12 -3
  335. package/templates/.agents/zaip-aios/guides/17-como-o-custo-e-calculado.md +5 -5
  336. package/templates/.agents/zaip-aios/guides/18-catalogo-de-agentes.md +76 -0
  337. package/templates/.agents/zaip-aios/guides/19-assurance-e-autonomia.md +95 -0
  338. package/templates/.agents/zaip-aios/guides/20-instalacao-detalhada.md +366 -0
  339. package/templates/.agents/zaip-aios/guides/21-telemetria-monitor-custos.md +46 -0
  340. package/templates/.agents/zaip-aios/guides/22-fluxos-e-roteamento.md +74 -0
  341. package/templates/.agents/zaip-aios/guides/23-orquestracao-de-modelos.md +483 -0
  342. package/templates/.agents/zaip-aios/guides/24-calculo-de-custos-openai.md +85 -0
  343. package/templates/.agents/zaip-aios/guides/25-fontes-de-precos-openai.md +19 -0
  344. package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +111 -0
  345. package/templates/.agents/zaip-aios/guides/27-telemetria-git-native.md +172 -0
  346. package/templates/.agents/zaip-aios/guides/28-lifecycle-completo.md +149 -0
  347. package/templates/.agents/zaip-aios/guides/assets/diagrams/lifecycles-task-spec-prd.png +0 -0
  348. package/templates/.agents/zaip-aios/guides/assets/diagrams/prd-lifecycle.png +0 -0
  349. package/templates/.agents/zaip-aios/guides/assets/diagrams/spec-lifecycle.png +0 -0
  350. package/templates/.agents/zaip-aios/guides/assets/diagrams/task-lifecycle.png +0 -0
  351. package/templates/template-manifest.json +756 -235
  352. package/templates/.agents/dashboard/apps/frontend/dist/assets/DashboardHelpDialog-Cs6dzDmW.js +0 -1505
  353. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-QE1k9yZB.css +0 -1
  354. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-_Pf5DA_A.js +0 -3
  355. package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-BVlz3DLZ.js +0 -1
  356. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-BZ5WdaMN.css +0 -1
  357. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-Cf9ctPVt.js +0 -68
  358. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-8A4DcNXM.js +0 -2
  359. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-DK_enB5Z.css +0 -1
  360. package/templates/.agents/dashboard/apps/frontend/src/use-idle-cost-prefetch.ts +0 -45
@@ -1,28 +1,35 @@
1
1
  import { readFile, rename, writeFile } from "node:fs/promises";
2
2
  import { join, resolve } from "node:path";
3
+ import {
4
+ applyExplicitTurnRecovery,
5
+ normalizeExplicitTurnRecoverySchema,
6
+ parseExplicitTurnMappings,
7
+ planExplicitTurnRecovery,
8
+ } from "./reconcile-telemetry-explicit-recovery.mjs";
3
9
  import {
4
10
  aggregate,
5
11
  duplicateUsageAssignments,
6
12
  duplicateUsageImpact,
7
13
  exactCompletedSegment,
8
14
  filesUnder,
9
- jsonLines,
10
15
  isExactDuplicateUsageGroup,
16
+ jsonLines,
11
17
  loadSegments,
12
18
  pricingFor,
13
19
  recordOccurredAt,
14
20
  recordSequence,
15
21
  recordType,
16
22
  sameCost,
23
+ supersedableUsageBeforeTerminal,
17
24
  usageStatus,
18
25
  usageView,
19
- supersedableUsageBeforeTerminal,
20
26
  withSequence,
21
27
  } from "./reconcile-telemetry-lib.mjs";
22
28
  import {
23
29
  remeasureSelectedRuns,
24
30
  timingEnrichmentRunIds,
25
31
  } from "./reconcile-telemetry-remeasurement.mjs";
32
+ import { reconcileGenericModelIdentities } from "./source-size-telemetry/model-identity-reconciliation.mjs";
26
33
 
27
34
  const workspace = resolve(process.cwd());
28
35
  const apply = process.argv.includes("--apply");
@@ -31,6 +38,7 @@ const reprice = process.argv.includes("--reprice");
31
38
  const deduplicate = process.argv.includes("--deduplicate");
32
39
  const remeasure = process.argv.includes("--remeasure");
33
40
  const timingOnly = process.argv.includes("--timing-only");
41
+ const explicitRecovery = process.argv.includes("--explicit-turn-recovery");
34
42
  if (timingOnly && !remeasure) {
35
43
  throw new Error("--timing-only requires --remeasure");
36
44
  }
@@ -54,13 +62,19 @@ const selectedSessionFiles = process.argv
54
62
  : [],
55
63
  )
56
64
  .filter(Boolean);
65
+ const explicitMappings = parseExplicitTurnMappings(
66
+ process.argv,
67
+ explicitRecovery,
68
+ selectedRunIds,
69
+ selectedSessionFiles,
70
+ );
57
71
  if (remeasure && selectedRunIds.size === 0) {
58
72
  throw new Error("--remeasure requires at least one explicit --run <RUN-ID>");
59
73
  }
60
74
  if (apply && deduplicate && selectedRunIds.size === 0) {
61
75
  throw new Error("--apply --deduplicate requires at least one explicit --run <RUN-ID>");
62
76
  }
63
- const applyBackfill = apply && !deduplicate && !remeasure;
77
+ const applyBackfill = apply && !deduplicate && !remeasure && !explicitRecovery;
64
78
 
65
79
  const runFiles = await filesUnder(join(workspace, ".agents", "records", "runs"), ".jsonl");
66
80
  const runs = [];
@@ -191,9 +205,38 @@ const allSegments = await loadSegments(
191
205
  workspace,
192
206
  selectedSessionFiles.length === 0 ? null : selectedSessionFiles,
193
207
  );
194
- // Native usage can be captured before the Codex session emits task_complete.
195
- // A normal backfill must not replace those observed tokens or costs, but it can
196
- // append an exact, timing-only correction once that terminal boundary appears.
208
+ let explicitSchemaNormalized = false;
209
+ if (apply && explicitRecovery) {
210
+ const run = runs.find((candidate) => candidate.started.run_id === [...selectedRunIds][0]);
211
+ if (run) {
212
+ const normalized = await normalizeExplicitTurnRecoverySchema(
213
+ run.file,
214
+ run.records,
215
+ explicitMappings,
216
+ );
217
+ if (normalized !== run.records) {
218
+ run.records = normalized;
219
+ run.usage = normalized
220
+ .filter((record) => recordType(record) === "usage.recorded")
221
+ .map(usageView);
222
+ explicitSchemaNormalized = true;
223
+ }
224
+ }
225
+ }
226
+ const explicitRecoveryPlan = explicitRecovery
227
+ ? (() => {
228
+ const runId = [...selectedRunIds][0];
229
+ const run = runs.find((candidate) => candidate.started.run_id === runId);
230
+ return run
231
+ ? planExplicitTurnRecovery({ run, segments: allSegments, mappings: explicitMappings })
232
+ : { run_id: runId, eligible: false, reasons: ["run-not-found"], turns: [], recovered: [] };
233
+ })()
234
+ : null;
235
+ if (apply && explicitRecovery && explicitRecoveryPlan.eligible) {
236
+ const run = runs.find((candidate) => candidate.started.run_id === explicitRecoveryPlan.run_id);
237
+ await applyExplicitTurnRecovery({ run, plan: explicitRecoveryPlan });
238
+ explicitRecoveryPlan.applied = true;
239
+ }
197
240
  const timingRunIds = timingEnrichmentRunIds({
198
241
  remeasure,
199
242
  applyBackfill,
@@ -207,8 +250,6 @@ const remeasurement =
207
250
  allSegments,
208
251
  runs,
209
252
  selectedRunIds: timingRunIds,
210
- // Automatic backfill is intentionally timing-only. Explicit remeasurement
211
- // retains its existing token/cost correction behavior unless requested.
212
253
  timingOnly: remeasure ? timingOnly : true,
213
254
  workspace,
214
255
  })
@@ -318,86 +359,35 @@ if (reprice) {
318
359
  }
319
360
  }
320
361
 
321
- const segmentsByKey = new Map(allSegments.map((segment) => [segment.key, segment]));
322
- const genericModel = (model) => typeof model === "string" && /^gpt-5$/i.test(model.trim());
323
- let modelIdentityCorrections = 0;
324
- for (const run of runs) {
325
- const superseded = new Set(run.usage.map((usage) => usage.supersedes_event_id).filter(Boolean));
326
- const effective = run.usage.filter((usage) => !superseded.has(usage.event_id));
327
- const corrections = effective.flatMap((usage) => {
328
- if (!genericModel(usage.model ?? run.started.model)) return [];
329
- const segment = usage.source_segment_key
330
- ? (segmentsByKey.get(usage.source_segment_key) ?? null)
331
- : null;
332
- return segment?.model && !genericModel(segment.model) ? [{ usage, segment }] : [];
333
- });
334
- modelIdentityCorrections += corrections.length;
335
- if (!applyBackfill || corrections.length === 0) continue;
336
-
337
- const correctionByTarget = new Map(corrections.map((item) => [item.usage.event_id, item]));
338
- const updated = [];
339
- let correctionIndex = run.usage.filter(
340
- (usage) => usage.activity_kind === "model_identity_reconciliation",
341
- ).length;
342
- for (const record of run.records) {
343
- updated.push(record);
344
- const original = usageView(record);
345
- const correction = original ? correctionByTarget.get(original.event_id) : null;
346
- if (!correction) continue;
347
- correctionIndex += 1;
348
- const cost = await pricingFor(workspace, correction.segment.model, original.tokens);
349
- updated.push({
350
- schema_version: 2,
351
- event_id: `${run.started.run_id}:model:${String(correctionIndex).padStart(6, "0")}`,
352
- run_id: run.started.run_id,
353
- sequence: 0,
354
- occurred_at: original.occurred_at,
355
- type: "usage.recorded",
356
- phase: original.phase,
357
- activity_kind: "model_identity_reconciliation",
358
- classification_source: original.classification_source ?? "current_context",
359
- tokens: original.tokens,
360
- cost,
361
- provider: original.provider ?? run.started.provider ?? "openai",
362
- model: correction.segment.model,
363
- source_segment_key: original.source_segment_key,
364
- supersedes_event_id: original.event_id,
365
- source_occurred_at:
366
- original.source_occurred_at ??
367
- correction.segment.finished_at ??
368
- correction.segment.started_at,
369
- ...(original.context_stats === undefined ? {} : { context_stats: original.context_stats }),
370
- runtime: {
371
- reasoning_effort: correction.segment.effort ?? original.runtime?.reasoning_effort ?? null,
372
- service_tier: correction.segment.service_tier ?? original.runtime?.service_tier ?? null,
373
- },
374
- });
375
- }
376
- const resequenced = updated.map((record, index) => withSequence(record, index + 1));
377
- const temporary = `${run.file}.model.tmp`;
378
- await writeFile(
379
- temporary,
380
- `${resequenced.map((record) => JSON.stringify(record)).join("\n")}\n`,
381
- "utf8",
382
- );
383
- await rename(temporary, run.file);
384
- }
362
+ const modelIdentityCorrections = await reconcileGenericModelIdentities({
363
+ applyBackfill,
364
+ pricingFor,
365
+ runs,
366
+ segments: allSegments,
367
+ usageView,
368
+ withSequence,
369
+ workspace,
370
+ });
385
371
 
386
372
  const duplicateGroups = duplicateUsageAssignments(runs);
387
373
  const exactDuplicateGroups = duplicateGroups.filter(isExactDuplicateUsageGroup);
388
374
  const aliasReviewGroups = duplicateGroups.filter((group) => !isExactDuplicateUsageGroup(group));
389
- const selectedDuplicateGroups = selectedRunIds.size === 0
390
- ? exactDuplicateGroups
391
- : exactDuplicateGroups.filter((group) =>
392
- group.some(({ run }) => selectedRunIds.has(run.started.run_id)),
393
- );
394
- const selectedAliasReviewGroups = selectedRunIds.size === 0
395
- ? aliasReviewGroups
396
- : aliasReviewGroups.filter((group) =>
397
- group.some(({ run }) => selectedRunIds.has(run.started.run_id)),
398
- );
375
+ const selectedDuplicateGroups =
376
+ selectedRunIds.size === 0
377
+ ? exactDuplicateGroups
378
+ : exactDuplicateGroups.filter((group) =>
379
+ group.some(({ run }) => selectedRunIds.has(run.started.run_id)),
380
+ );
381
+ const selectedAliasReviewGroups =
382
+ selectedRunIds.size === 0
383
+ ? aliasReviewGroups
384
+ : aliasReviewGroups.filter((group) =>
385
+ group.some(({ run }) => selectedRunIds.has(run.started.run_id)),
386
+ );
399
387
  const duplicateAssignments = selectedDuplicateGroups.flatMap((group) =>
400
- group.slice(1).filter(({ run }) => selectedRunIds.size === 0 || selectedRunIds.has(run.started.run_id)),
388
+ group
389
+ .slice(1)
390
+ .filter(({ run }) => selectedRunIds.size === 0 || selectedRunIds.has(run.started.run_id)),
401
391
  );
402
392
  let deduplicatedEvents = 0;
403
393
  if (apply && deduplicate) {
@@ -641,16 +631,17 @@ for (const candidate of candidates) {
641
631
  }
642
632
  const eligible = candidates.filter(
643
633
  (candidate) =>
634
+ (selectedRunIds.size === 0 || selectedRunIds.has(candidate.run.started.run_id)) &&
644
635
  byRun.get(candidate.run.started.run_id).length === 1 &&
645
636
  bySegment.get(candidate.segment.key).length === 1,
646
637
  );
647
638
 
648
639
  if (applyBackfill) {
649
640
  for (const { run, segment, confidence } of eligible) {
650
- // Re-read each Run under the serial apply loop: a preceding timing repair may
651
- // have reordered or appended a correction after the initial scan.
652
641
  const persistedRecords = jsonLines(await readFile(run.file, "utf8"));
653
- const finishIndex = persistedRecords.findIndex((record) => recordType(record) === "run.finished");
642
+ const finishIndex = persistedRecords.findIndex(
643
+ (record) => recordType(record) === "run.finished",
644
+ );
654
645
  const insertAt = finishIndex < 0 ? persistedRecords.length : finishIndex;
655
646
  const tokens = aggregate(segment);
656
647
  const model = segment.model ?? run.started.model ?? null;
@@ -665,7 +656,9 @@ if (applyBackfill) {
665
656
  occurred_at: persistedRecords.find((record) => recordType(record) === "run.finished")
666
657
  ? new Date(
667
658
  Date.parse(
668
- recordOccurredAt(persistedRecords.find((record) => recordType(record) === "run.finished")),
659
+ recordOccurredAt(
660
+ persistedRecords.find((record) => recordType(record) === "run.finished"),
661
+ ),
669
662
  ) - 1,
670
663
  ).toISOString()
671
664
  : new Date().toISOString(),
@@ -686,9 +679,11 @@ if (applyBackfill) {
686
679
  ...(segment.finished_at ? { source_finished_at: segment.finished_at } : {}),
687
680
  runtime: { reasoning_effort: segment.effort, service_tier: segment.service_tier },
688
681
  };
689
- const updated = [...persistedRecords.slice(0, insertAt), event, ...persistedRecords.slice(insertAt)].map(
690
- (record, index) => withSequence(record, index + 1),
691
- );
682
+ const updated = [
683
+ ...persistedRecords.slice(0, insertAt),
684
+ event,
685
+ ...persistedRecords.slice(insertAt),
686
+ ].map((record, index) => withSequence(record, index + 1));
692
687
  const temporary = `${run.file}.reconcile.tmp`;
693
688
  await writeFile(
694
689
  temporary,
@@ -719,23 +714,35 @@ console.log(
719
714
  ? apply
720
715
  ? "apply-deduplicate"
721
716
  : "dry-run-deduplicate"
722
- : remeasure
717
+ : explicitRecovery
723
718
  ? apply
724
- ? "apply-remeasure"
725
- : "dry-run-remeasure"
726
- : apply
727
- ? reprice
728
- ? "apply-reprice"
729
- : approximate
730
- ? "apply-approximate"
731
- : "apply"
732
- : reprice
733
- ? "dry-run-reprice"
734
- : approximate
735
- ? "dry-run-approximate"
736
- : "dry-run",
719
+ ? "apply-explicit-turn-recovery"
720
+ : "dry-run-explicit-turn-recovery"
721
+ : remeasure
722
+ ? apply
723
+ ? "apply-remeasure"
724
+ : "dry-run-remeasure"
725
+ : apply
726
+ ? reprice
727
+ ? "apply-reprice"
728
+ : approximate
729
+ ? "apply-approximate"
730
+ : "apply"
731
+ : reprice
732
+ ? "dry-run-reprice"
733
+ : approximate
734
+ ? "dry-run-approximate"
735
+ : "dry-run",
737
736
  run_files: runs.length,
738
737
  remeasurement,
738
+ explicit_turn_recovery: explicitRecoveryPlan && {
739
+ run_id: explicitRecoveryPlan.run_id,
740
+ eligible: explicitRecoveryPlan.eligible,
741
+ applied: explicitRecoveryPlan.applied === true,
742
+ reasons: explicitRecoveryPlan.reasons,
743
+ turns: explicitRecoveryPlan.turns,
744
+ schema_normalized: explicitSchemaNormalized,
745
+ },
739
746
  local_session_files: new Set(segments.map((segment) => segment.file)).size,
740
747
  local_segments_available: segments.length,
741
748
  already_measured: runs.filter((run) => run.measured).length,
@@ -0,0 +1,223 @@
1
+ import { open, readFile, rename, rm, writeFile } from "node:fs/promises";
2
+ import {
3
+ aggregate,
4
+ jsonLines,
5
+ recordPhase,
6
+ recordType,
7
+ usageStatus,
8
+ usageView,
9
+ withSequence,
10
+ } from "./reconcile-telemetry-lib.mjs";
11
+
12
+ export function parseExplicitTurnMappings(args, enabled, runIds, sessionFiles) {
13
+ const mappings = args.flatMap((argument, index, values) => {
14
+ if (argument !== "--explicit-turn") return [];
15
+ const [spec_id, turn_id, total, usd, brl] = String(values[index + 1] ?? "").split("|");
16
+ return [{ spec_id, turn_id, total: Number(total), usd: Number(usd), brl: Number(brl) }];
17
+ });
18
+ if (enabled && (runIds.size !== 1 || sessionFiles.length !== 1))
19
+ throw new Error("--explicit-turn-recovery requires exactly one --run and one --session-file");
20
+ if (enabled && mappings.length === 0)
21
+ throw new Error(
22
+ "--explicit-turn-recovery requires one or more --explicit-turn SPEC|TURN|TOTAL|USD|BRL",
23
+ );
24
+ return mappings;
25
+ }
26
+
27
+ // This deliberately accepts no temporal heuristic. A recovery is useful only
28
+ // when a human supplies the expected SPEC-to-turn mapping and every identity
29
+ // boundary independently agrees with the persisted Run.
30
+ export function planExplicitTurnRecovery({ run, segments, mappings }) {
31
+ const runId = run?.started?.run_id;
32
+ const finished = run?.records?.find((record) => recordType(record) === "run.finished");
33
+ const usedKeys = new Set(
34
+ run.usage.filter((usage) => usage.source_segment_key).map((usage) => usage.source_segment_key),
35
+ );
36
+ const problems = [];
37
+ if (!runId || !finished) problems.push("run-not-finished");
38
+ if (!run?.started?.client_thread_id) problems.push("run-client-thread-unavailable");
39
+ if (!Array.isArray(mappings) || mappings.length === 0) problems.push("explicit-mapping-required");
40
+ const turnIds = new Set();
41
+ const recovered = [];
42
+ for (const mapping of mappings ?? []) {
43
+ if (!mapping.spec_id || !mapping.turn_id) {
44
+ problems.push("mapping-spec-and-turn-required");
45
+ continue;
46
+ }
47
+ if (turnIds.has(mapping.turn_id)) {
48
+ problems.push("duplicate-explicit-turn");
49
+ continue;
50
+ }
51
+ turnIds.add(mapping.turn_id);
52
+ const matches = segments.filter(
53
+ (segment) =>
54
+ segment.internal_turn_ids?.includes(mapping.turn_id) || segment.turn_id === mapping.turn_id,
55
+ );
56
+ if (matches.length !== 1) {
57
+ problems.push(
58
+ matches.length === 0
59
+ ? `turn-not-found:${mapping.turn_id}`
60
+ : `turn-ambiguous:${mapping.turn_id}`,
61
+ );
62
+ continue;
63
+ }
64
+ const segment = matches[0];
65
+ if (segment.session_agent_path !== run.started.client_thread_id)
66
+ problems.push(`session-agent-path-mismatch:${mapping.turn_id}`);
67
+ if (segment.model !== run.started.model || segment.effort !== run.started.reasoning_effort)
68
+ problems.push(`model-effort-mismatch:${mapping.turn_id}`);
69
+ if (usedKeys.has(segment.key)) problems.push(`turn-already-used:${mapping.turn_id}`);
70
+ if (!segment.finished_at) problems.push(`turn-not-finished:${mapping.turn_id}`);
71
+ if (!segment.raw?.includes(mapping.spec_id))
72
+ problems.push(`spec-evidence-missing:${mapping.turn_id}`);
73
+ const tokens = aggregate(segment);
74
+ if (mapping.total !== undefined && tokens.total !== mapping.total)
75
+ problems.push(`token-total-mismatch:${mapping.turn_id}`);
76
+ recovered.push({ mapping, segment, tokens });
77
+ }
78
+ return {
79
+ run_id: runId,
80
+ eligible: problems.length === 0 && recovered.length === mappings.length,
81
+ reasons: problems,
82
+ turns: recovered.map(({ mapping, segment, tokens }) => ({
83
+ spec_id: mapping.spec_id,
84
+ turn_id: mapping.turn_id,
85
+ source_segment_key: segment.key,
86
+ source_started_at: segment.started_at,
87
+ source_finished_at: segment.finished_at,
88
+ tokens,
89
+ })),
90
+ recovered,
91
+ };
92
+ }
93
+
94
+ export async function applyExplicitTurnRecovery({ run, plan }) {
95
+ if (!plan.eligible)
96
+ throw new Error(`Explicit recovery is not eligible: ${plan.reasons.join(", ")}`);
97
+ const finished = run.records.find((record) => recordType(record) === "run.finished");
98
+ const superseded = usageStatus(run.usage).effective.at(-1);
99
+ if (!superseded) throw new Error("Explicit recovery needs a supersedable effective usage event");
100
+ const sequence = run.records.length + 1;
101
+ const events = plan.recovered.map(({ mapping, segment, tokens }, index) => ({
102
+ schema_version: 2,
103
+ event_id: `${run.started.run_id}:explicit-turn-recovery:${String(sequence + index).padStart(6, "0")}`,
104
+ run_id: run.started.run_id,
105
+ sequence: sequence + index,
106
+ occurred_at: segment.finished_at,
107
+ type: "usage.recorded",
108
+ phase: recordPhase(finished),
109
+ activity_kind: "retrospective_explicit_turn_recovery",
110
+ classification_source: "explicit",
111
+ tokens: { ...tokens, source: "provider_reported" },
112
+ cost: { usd: mapping.usd, brl: mapping.brl },
113
+ provider: run.started.provider ?? "openai",
114
+ model: segment.model,
115
+ source_segment_key: segment.key,
116
+ attributed_spec_id: mapping.spec_id,
117
+ supersedes_event_id: index === 0 ? superseded.event_id : null,
118
+ retrospective_correction: true,
119
+ source_occurred_at: segment.finished_at,
120
+ source_started_at: segment.started_at,
121
+ source_finished_at: segment.finished_at,
122
+ runtime: { reasoning_effort: segment.effort, service_tier: segment.service_tier },
123
+ }));
124
+ await appendExplicitTurnRecovery(run.file, run.records, events);
125
+ return events;
126
+ }
127
+
128
+ // Kept separate from the general reconcile path: it only normalizes fields
129
+ // emitted by this explicit recovery writer, and only when the same scoped
130
+ // command is being resumed after an interrupted projection check.
131
+ export async function normalizeExplicitTurnRecoverySchema(file, expectedRecords, mappings = []) {
132
+ const specByTurn = new Map(mappings.map((mapping) => [mapping.turn_id, mapping.spec_id]));
133
+ const changed = expectedRecords.some((record) => {
134
+ const usage = usageView(record);
135
+ return (
136
+ usage?.activity_kind === "retrospective_explicit_turn_recovery" &&
137
+ (usage.classification_source !== "explicit" ||
138
+ "explicit_turn_recovery" in usage ||
139
+ "explicit_spec_id" in usage ||
140
+ usage.attributed_spec_id === undefined)
141
+ );
142
+ });
143
+ if (!changed) return expectedRecords;
144
+ const lockPath = `${file}.lock`;
145
+ const handle = await open(lockPath, "wx");
146
+ await handle.close();
147
+ try {
148
+ const persisted = jsonLines(await readFile(file, "utf8"));
149
+ const ids = (records) => records.map((record) => record?.event_id ?? record?.[2]);
150
+ if (
151
+ persisted.length !== expectedRecords.length ||
152
+ ids(persisted).some((id, index) => id !== ids(expectedRecords)[index])
153
+ )
154
+ throw new Error("Run history changed before explicit recovery schema normalization");
155
+ let recoveryIndex = 0;
156
+ const normalized = persisted.map((record) => {
157
+ const usage = usageView(record);
158
+ if (usage?.activity_kind !== "retrospective_explicit_turn_recovery") return record;
159
+ const { explicit_turn_recovery, explicit_spec_id, ...rest } = usage;
160
+ const recoveredTurn = [...specByTurn.keys()].find((turn) =>
161
+ rest.source_segment_key?.includes(turn),
162
+ );
163
+ const mappedSpecId = mappings[recoveryIndex++]?.spec_id;
164
+ return {
165
+ ...rest,
166
+ classification_source: "explicit",
167
+ ...(typeof rest.attributed_spec_id === "string"
168
+ ? {}
169
+ : typeof explicit_spec_id === "string"
170
+ ? { attributed_spec_id: explicit_spec_id }
171
+ : recoveredTurn
172
+ ? { attributed_spec_id: specByTurn.get(recoveredTurn) }
173
+ : typeof mappedSpecId === "string"
174
+ ? { attributed_spec_id: mappedSpecId }
175
+ : {}),
176
+ };
177
+ });
178
+ const temporary = `${file}.explicit-recovery-schema.tmp`;
179
+ await writeFile(
180
+ temporary,
181
+ `${normalized.map((record) => JSON.stringify(record)).join("\n")}\n`,
182
+ "utf8",
183
+ );
184
+ await rename(temporary, file);
185
+ return normalized;
186
+ } finally {
187
+ await rm(lockPath, { force: true });
188
+ }
189
+ }
190
+
191
+ export async function appendExplicitTurnRecovery(file, expectedRecords, events) {
192
+ if (!Array.isArray(events) || events.length === 0)
193
+ throw new Error("Explicit recovery events required");
194
+ const lockPath = `${file}.lock`;
195
+ const handle = await open(lockPath, "wx");
196
+ await handle.close();
197
+ try {
198
+ const persisted = jsonLines(await readFile(file, "utf8"));
199
+ const ids = (records) => records.map((record) => record?.event_id ?? record?.[2]);
200
+ if (
201
+ persisted.length !== expectedRecords.length ||
202
+ ids(persisted).some((id, index) => id !== ids(expectedRecords)[index])
203
+ )
204
+ throw new Error("Run history changed before explicit recovery");
205
+ const finishIndex = persisted.findIndex((record) => recordType(record) === "run.finished");
206
+ if (finishIndex < 0) throw new Error("Explicit recovery requires run.finished");
207
+ const before = persisted.slice(0, finishIndex);
208
+ const finish = persisted[finishIndex];
209
+ const after = persisted.slice(finishIndex + 1);
210
+ const updated = [...before, ...after, ...events, finish].map((record, index) =>
211
+ withSequence(record, index + 1),
212
+ );
213
+ const temporary = `${file}.explicit-recovery.tmp`;
214
+ await writeFile(
215
+ temporary,
216
+ `${updated.map((record) => JSON.stringify(record)).join("\n")}\n`,
217
+ "utf8",
218
+ );
219
+ await rename(temporary, file);
220
+ } finally {
221
+ await rm(lockPath, { force: true });
222
+ }
223
+ }
@@ -116,12 +116,15 @@ export function supersedableUsageBeforeTerminal(records) {
116
116
  const finishIndex = records.findIndex((record) => recordType(record) === "run.finished");
117
117
  const beforeTerminal = records.slice(0, finishIndex < 0 ? records.length : finishIndex);
118
118
  const usage = beforeTerminal.map(usageView).filter(Boolean);
119
- return [...usage]
120
- .reverse()
121
- .find(
122
- (event) =>
123
- event.tokens?.total === null && !usage.some((other) => other.supersedes_event_id === event.event_id),
124
- ) ?? null;
119
+ return (
120
+ [...usage]
121
+ .reverse()
122
+ .find(
123
+ (event) =>
124
+ event.tokens?.total === null &&
125
+ !usage.some((other) => other.supersedes_event_id === event.event_id),
126
+ ) ?? null
127
+ );
125
128
  }
126
129
 
127
130
  export function withSequence(record, sequence) {
@@ -183,11 +186,13 @@ export function duplicateUsageAssignments(runs) {
183
186
  return [...groups.values()]
184
187
  .filter((group) => new Set(group.map(({ run }) => run.started.run_id)).size > 1)
185
188
  .map((group) =>
186
- [...group].sort((left, right) =>
189
+ [...group].sort(
190
+ (left, right) =>
187
191
  provenanceRank(left.usage) - provenanceRank(right.usage) ||
188
192
  String(left.run.started.occurred_at).localeCompare(
189
193
  String(right.run.started.occurred_at),
190
- ) || left.run.started.run_id.localeCompare(right.run.started.run_id),
194
+ ) ||
195
+ left.run.started.run_id.localeCompare(right.run.started.run_id),
191
196
  ),
192
197
  );
193
198
  }
@@ -238,7 +243,20 @@ export function exactCompletedSegment(started, segments) {
238
243
  if (!started?.client_turn_id) return { segment: null, ambiguous: false };
239
244
  const runStartedAt = Date.parse(started.occurred_at ?? "");
240
245
  const matches = segments.filter((segment) => {
241
- if (segment.turn_id !== started.client_turn_id || !segment.finished_at) return false;
246
+ // Older Codex sub-runs can persist the internal turn id exposed in a
247
+ // response item's metadata instead of the enclosing task_started id. It
248
+ // is an observed identity for this exact local interval, never a token
249
+ // matching heuristic.
250
+ const observedInternalTurnIds = Array.isArray(segment.internal_turn_ids)
251
+ ? segment.internal_turn_ids
252
+ : [];
253
+ if (
254
+ (segment.turn_id !== started.client_turn_id &&
255
+ !observedInternalTurnIds.includes(started.client_turn_id)) ||
256
+ !segment.finished_at
257
+ ) {
258
+ return false;
259
+ }
242
260
  const segmentFinishedAt = Date.parse(segment.finished_at);
243
261
  return (
244
262
  Number.isFinite(runStartedAt) &&
@@ -325,6 +343,7 @@ export async function loadSegments(workspace, sessionFiles = null) {
325
343
  let canonicalSessionMetaSeen = false;
326
344
  let workspaceMatches = false;
327
345
  let sessionId = null;
346
+ let sessionAgentPath = null;
328
347
  let current = null;
329
348
  let index = 0;
330
349
  let model = null;
@@ -360,6 +379,16 @@ export async function loadSegments(workspace, sessionFiles = null) {
360
379
  canonicalSessionMetaSeen = true;
361
380
  workspaceMatches = normalized(payload.cwd) === normalized(workspace);
362
381
  sessionId = nextSessionId;
382
+ const declaredAgentPath =
383
+ typeof payload.agent_path === "string"
384
+ ? payload.agent_path
385
+ : typeof payload?.source?.subagent?.thread_spawn?.agent_path === "string"
386
+ ? payload.source.subagent.thread_spawn.agent_path
387
+ : null;
388
+ // A child rollout may embed its parent session metadata immediately
389
+ // after its own. Retain the child identity rather than downgrading to
390
+ // the parent metadata that cannot identify the subagent.
391
+ sessionAgentPath = declaredAgentPath ?? sessionAgentPath;
363
392
  }
364
393
  if (!workspaceMatches) continue;
365
394
  const settings = payload?.type === "thread_settings_applied" ? payload.thread_settings : null;
@@ -388,12 +417,14 @@ export async function loadSegments(workspace, sessionFiles = null) {
388
417
  key: `${normalized(file)}#${index}`,
389
418
  file,
390
419
  session_id: sessionId,
420
+ session_agent_path: sessionAgentPath,
391
421
  turn_id: typeof payload.turn_id === "string" ? payload.turn_id : null,
392
422
  started_at: record.timestamp ?? null,
393
423
  finished_at: null,
394
424
  model,
395
425
  effort,
396
426
  service_tier: serviceTier,
427
+ internal_turn_ids: [],
397
428
  usage: [],
398
429
  raw: [],
399
430
  };
@@ -417,12 +448,27 @@ export async function loadSegments(workspace, sessionFiles = null) {
417
448
  }
418
449
  }
419
450
  if (!current) continue;
451
+ const internalTurnId = payload?.internal_chat_message_metadata_passthrough?.turn_id;
452
+ if (
453
+ typeof internalTurnId === "string" &&
454
+ !current.internal_turn_ids.includes(internalTurnId)
455
+ ) {
456
+ current.internal_turn_ids.push(internalTurnId);
457
+ }
420
458
  if (line.includes("RUN-") || line.includes("TASK-")) current.raw.push(line);
421
459
  if (payload?.type === "task_complete") {
422
460
  current.finished_at = record.timestamp ?? null;
423
461
  if (current.usage.length) segments.push(current);
424
462
  current = null;
425
463
  }
464
+ if (current && payload?.type === "turn_aborted" && payload.turn_id === current.turn_id) {
465
+ // An interrupted Codex turn is still an observed terminal boundary.
466
+ // Preserve its collected token snapshots, but never fabricate a later
467
+ // finish from the Run history or wall clock.
468
+ current.finished_at = record.timestamp ?? null;
469
+ if (current.usage.length) segments.push(current);
470
+ current = null;
471
+ }
426
472
  }
427
473
  if (current?.usage.length) segments.push(current);
428
474
  }