@zaip-ai/cli 1.3.7 → 1.4.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 (332) hide show
  1. package/README.md +86 -1
  2. package/dist/commands/init.d.ts +1 -0
  3. package/dist/commands/init.d.ts.map +1 -1
  4. package/dist/commands/init.js +26 -0
  5. package/dist/commands/init.js.map +1 -1
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +3 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/services/adapters.js +4 -4
  11. package/dist/services/adapters.js.map +1 -1
  12. package/dist/services/codex-config-template.d.ts +2 -2
  13. package/dist/services/codex-config-template.d.ts.map +1 -1
  14. package/dist/services/codex-config-template.js +3 -3
  15. package/dist/services/codex-config-template.js.map +1 -1
  16. package/dist/services/codex-rules.d.ts +1 -1
  17. package/dist/services/codex-rules.d.ts.map +1 -1
  18. package/dist/services/codex-rules.js +9 -24
  19. package/dist/services/codex-rules.js.map +1 -1
  20. package/dist/services/delivery-git-preflight.d.ts +23 -0
  21. package/dist/services/delivery-git-preflight.d.ts.map +1 -0
  22. package/dist/services/delivery-git-preflight.js +69 -0
  23. package/dist/services/delivery-git-preflight.js.map +1 -0
  24. package/dist/services/doctor.d.ts.map +1 -1
  25. package/dist/services/doctor.js +13 -1
  26. package/dist/services/doctor.js.map +1 -1
  27. package/dist/services/install-agents-template.d.ts.map +1 -1
  28. package/dist/services/install-agents-template.js +22 -28
  29. package/dist/services/install-agents-template.js.map +1 -1
  30. package/dist/services/install-profile.d.ts +8 -0
  31. package/dist/services/install-profile.d.ts.map +1 -0
  32. package/dist/services/install-profile.js +56 -0
  33. package/dist/services/install-profile.js.map +1 -0
  34. package/dist/services/logger.d.ts.map +1 -1
  35. package/dist/services/logger.js +6 -5
  36. package/dist/services/logger.js.map +1 -1
  37. package/dist/services/stack-git.d.ts +9 -0
  38. package/dist/services/stack-git.d.ts.map +1 -0
  39. package/dist/services/stack-git.js +188 -0
  40. package/dist/services/stack-git.js.map +1 -0
  41. package/dist/services/stack-install.d.ts +14 -0
  42. package/dist/services/stack-install.d.ts.map +1 -0
  43. package/dist/services/stack-install.js +176 -0
  44. package/dist/services/stack-install.js.map +1 -0
  45. package/dist/services/stack-node.d.ts +12 -0
  46. package/dist/services/stack-node.d.ts.map +1 -0
  47. package/dist/services/stack-node.js +150 -0
  48. package/dist/services/stack-node.js.map +1 -0
  49. package/dist/services/stack-package-manager.d.ts +12 -0
  50. package/dist/services/stack-package-manager.d.ts.map +1 -0
  51. package/dist/services/stack-package-manager.js +178 -0
  52. package/dist/services/stack-package-manager.js.map +1 -0
  53. package/dist/services/stack-plan.d.ts +35 -0
  54. package/dist/services/stack-plan.d.ts.map +1 -0
  55. package/dist/services/stack-plan.js +130 -0
  56. package/dist/services/stack-plan.js.map +1 -0
  57. package/dist/services/stack-terraform.d.ts +13 -0
  58. package/dist/services/stack-terraform.d.ts.map +1 -0
  59. package/dist/services/stack-terraform.js +274 -0
  60. package/dist/services/stack-terraform.js.map +1 -0
  61. package/dist/services/template-manifest.d.ts.map +1 -1
  62. package/dist/services/template-manifest.js +14 -1
  63. package/dist/services/template-manifest.js.map +1 -1
  64. package/dist/types.d.ts +4 -0
  65. package/dist/types.d.ts.map +1 -1
  66. package/package.json +1 -1
  67. package/templates/.agents/.env.example +34 -0
  68. package/templates/{README.md → .agents/README.md} +124 -60
  69. package/templates/.agents/config/agents/catalog.yaml +23 -23
  70. package/templates/.agents/config/clients/codex/agents/zaip-agent-analyst.toml +1 -0
  71. package/templates/.agents/config/clients/codex/agents/zaip-agent-auditor.toml +1 -0
  72. package/templates/.agents/config/clients/codex/agents/zaip-agent-backend.toml +5 -4
  73. package/templates/.agents/config/clients/codex/agents/zaip-agent-brand-strategist.toml +1 -0
  74. package/templates/.agents/config/clients/codex/agents/zaip-agent-builder.toml +1 -0
  75. package/templates/.agents/config/clients/codex/agents/zaip-agent-cloud-engineer.toml +10 -7
  76. package/templates/.agents/config/clients/codex/agents/zaip-agent-data-analyst.toml +1 -0
  77. package/templates/.agents/config/clients/codex/agents/zaip-agent-designer.toml +1 -0
  78. package/templates/.agents/config/clients/codex/agents/zaip-agent-finalizer.toml +1 -0
  79. package/templates/.agents/config/clients/codex/agents/zaip-agent-frontend.toml +5 -4
  80. package/templates/.agents/config/clients/codex/agents/zaip-agent-general-operations.toml +1 -0
  81. package/templates/.agents/config/clients/codex/agents/zaip-agent-governance-compliance.toml +1 -0
  82. package/templates/.agents/config/clients/codex/agents/zaip-agent-growth-strategist.toml +1 -0
  83. package/templates/.agents/config/clients/codex/agents/zaip-agent-integrator.toml +1 -0
  84. package/templates/.agents/config/clients/codex/agents/zaip-agent-marketing-analyst.toml +5 -4
  85. package/templates/.agents/config/clients/codex/agents/zaip-agent-orchestrator.toml +1 -0
  86. package/templates/.agents/config/clients/codex/agents/zaip-agent-refactoring-specialist.toml +1 -0
  87. package/templates/.agents/config/clients/codex/agents/zaip-agent-reviewer.toml +1 -0
  88. package/templates/.agents/config/clients/codex/agents/zaip-agent-sales-specialist.toml +1 -0
  89. package/templates/.agents/config/clients/codex/agents/zaip-agent-security-auditor.toml +1 -0
  90. package/templates/.agents/config/clients/codex/agents/zaip-agent-task-executor.toml +1 -0
  91. package/templates/.agents/config/clients/codex/agents/zaip-agent-website-developer.toml +5 -4
  92. package/templates/.agents/config/clients/codex/agents/zaip-agent-writer.toml +1 -0
  93. package/templates/.agents/config/pricing/models.json +25 -1
  94. package/templates/.agents/config/project.yaml +2 -0
  95. package/templates/.agents/dashboard/.zaip-managed.json +214 -94
  96. package/templates/.agents/dashboard/DATA-DICTIONARY.md +1 -1
  97. package/templates/.agents/dashboard/README.md +58 -19
  98. package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-DwVZOmMV.js → CostCalculationGuidePage-snUCQYTC.js} +1 -1
  99. package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog--czwAlcH.js → DashboardHelpDialog-oZVlf-l5.js} +787 -723
  100. package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-CyjMXkm8.js → PricingSettingsDialog-BPtVUGgs.js} +1 -1
  101. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-3Awyaovx.js +3 -0
  102. package/templates/.agents/dashboard/apps/frontend/dist/assets/{ProjectSettingsPage-BomxqCBU.css → ProjectSettingsPage-GgzpZ_PY.css} +1 -1
  103. package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-CAqYVin1.js → TraceabilityWorkspace-BYjVOHI_.js} +1 -1
  104. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-DbaLbU2q.js +68 -0
  105. package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-DXBOtWNI.js → icons-vendor-TPUT2IUt.js} +1 -1
  106. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-Cmlx8OYH.css +1 -0
  107. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-ZJFXmK7m.js +2 -0
  108. package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-DaNXQPyk.js → react-vendor-Ct48XHGL.js} +1 -1
  109. package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-I4AKqVDX.js → traceability-BDe4_Ubl.js} +1 -1
  110. package/templates/.agents/dashboard/apps/frontend/dist/index.html +6 -6
  111. package/templates/.agents/dashboard/apps/frontend/src/App.tsx +73 -67
  112. package/templates/.agents/dashboard/apps/frontend/src/AppLoadingBoundary.tsx +35 -7
  113. package/templates/.agents/dashboard/apps/frontend/src/AppWorkBoard.ts +55 -0
  114. package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsPage.tsx +15 -2
  115. package/templates/.agents/dashboard/apps/frontend/src/ProjectStackEditor.tsx +33 -6
  116. package/templates/.agents/dashboard/apps/frontend/src/app-loading-boundary.css +98 -0
  117. package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +5 -5
  118. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api-reconciliation.ts +33 -0
  119. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +75 -0
  120. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +9 -8
  121. package/templates/.agents/dashboard/apps/frontend/src/project-settings-model.ts +15 -3
  122. package/templates/.agents/dashboard/apps/frontend/src/project-settings-page.css +0 -104
  123. package/templates/.agents/dashboard/apps/frontend/src/project-settings.test.ts +61 -0
  124. package/templates/.agents/dashboard/apps/frontend/src/project-stack-versions.css +117 -0
  125. package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +78 -2
  126. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.test.ts +28 -0
  127. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.ts +8 -5
  128. package/templates/.agents/dashboard/apps/frontend/src/use-app-effects.ts +180 -1
  129. package/templates/.agents/dashboard/modules/cost-monitor/src/contracts.ts +7 -4
  130. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorContent.tsx +13 -7
  131. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +14 -0
  132. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableDisplay.ts +211 -0
  133. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +152 -157
  134. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.tsx +155 -142
  135. package/templates/.agents/dashboard/modules/cost-monitor/src/react/InvocationManifestQuery.test.ts +145 -0
  136. package/templates/.agents/dashboard/modules/cost-monitor/src/react/period-cost-groups.ts +7 -5
  137. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-compact-cost-page.ts +4 -1
  138. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.ts +4 -1
  139. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-run-page.ts +4 -1
  140. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.ts +4 -4
  141. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +79 -1
  142. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +105 -11
  143. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +477 -327
  144. package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +430 -285
  145. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-runtime.mjs +14 -2
  146. package/templates/.agents/dashboard/packages/local-runtime/scripts/rebuild-sqlite-read-model.mjs +6 -26
  147. package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-sqlite-read-model.mjs +1 -1
  148. package/templates/.agents/dashboard/packages/local-runtime/scripts/verify-persistent-launch.mjs +268 -0
  149. package/templates/.agents/dashboard/packages/local-runtime/server.mjs +482 -332
  150. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.test.ts +243 -1
  151. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.ts +252 -41
  152. package/templates/.agents/dashboard/packages/local-runtime/src/server-agent-assets.ts +39 -0
  153. package/templates/.agents/dashboard/packages/local-runtime/src/server-browser-lease.ts +33 -0
  154. package/templates/.agents/dashboard/packages/local-runtime/src/server-reconciliation-refresh.test.ts +148 -11
  155. package/templates/.agents/dashboard/packages/local-runtime/src/server-reconciliation-result.test.ts +68 -0
  156. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-refresh.test.ts +19 -0
  157. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-refresh.ts +39 -43
  158. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-revision.test.ts +42 -0
  159. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-revision.ts +26 -0
  160. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-synchronization.ts +34 -0
  161. package/templates/.agents/dashboard/packages/local-runtime/src/server-startup.ts +30 -0
  162. package/templates/.agents/dashboard/packages/local-runtime/src/server-work-reconciliation.test.ts +89 -0
  163. package/templates/.agents/dashboard/packages/local-runtime/src/server-work-reconciliation.ts +88 -0
  164. package/templates/.agents/dashboard/packages/local-runtime/src/server-workspace.ts +68 -7
  165. package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +11 -5
  166. package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +129 -99
  167. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-agent-productivity.test.ts +111 -0
  168. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-agent-productivity.ts +140 -0
  169. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.test.ts +127 -4
  170. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.ts +145 -5
  171. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-aggregates.ts +156 -23
  172. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-projection.ts +18 -9
  173. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-projection.ts +52 -0
  174. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-persistence.ts +35 -13
  175. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-force-canonical.test.ts +56 -0
  176. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-incremental-cache.test.ts +29 -0
  177. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-incremental-cache.ts +136 -0
  178. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-incremental-refresh.test.ts +251 -0
  179. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-projection.ts +22 -7
  180. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-cache.test-support.ts +1 -1
  181. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-canonical-parsing.ts +42 -0
  182. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-canonical.ts +793 -0
  183. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider-duration.test.ts +270 -0
  184. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider-fixture.ts +3 -2
  185. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider.test.ts +18 -4
  186. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.test.ts +87 -0
  187. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.ts +105 -16
  188. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +131 -59
  189. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +1000 -1115
  190. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-cache.ts +13 -92
  191. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-claims.test.mjs +79 -0
  192. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.mjs +27 -0
  193. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-lifecycle.mjs +6 -6
  194. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-prerequisites.mjs +1 -1
  195. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-refresh.mjs +2 -10
  196. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-server.mjs +142 -0
  197. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +231 -239
  198. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +18 -29
  199. package/templates/.agents/dashboard/packages/windows-launcher/Program.cs +6 -0
  200. package/templates/.agents/dashboard/stack-dependencies.json +14 -0
  201. package/templates/.agents/dashboard/zaip-dashboard-windows.exe +0 -0
  202. package/templates/.agents/requirements/autonomous-assurance.md +1 -1
  203. package/templates/.agents/requirements/cloud-hostinger-autonomy.md +47 -0
  204. package/templates/.agents/requirements/comparative-audit.md +1 -1
  205. package/templates/.agents/requirements/context-engine.md +1 -1
  206. package/templates/.agents/requirements/cost-observability.md +1 -1
  207. package/templates/.agents/requirements/dashboard-launch.md +2 -2
  208. package/templates/.agents/requirements/data-export.md +1 -1
  209. package/templates/.agents/requirements/design-system.md +1 -1
  210. package/templates/.agents/requirements/execution-engine.md +1 -1
  211. package/templates/.agents/requirements/kanban-dashboard.md +1 -1
  212. package/templates/.agents/requirements/model-orchestration.md +1 -1
  213. package/templates/.agents/requirements/public-distribution.md +1 -1
  214. package/templates/.agents/requirements/software-architecture.md +1 -1
  215. package/templates/.agents/requirements/strategic-improvements.md +1 -1
  216. package/templates/.agents/requirements/work-lifecycle.md +1 -1
  217. package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
  218. package/templates/.agents/rules/autonomy-decision.md +1 -1
  219. package/templates/.agents/rules/cloud-hostinger-autonomy.md +21 -0
  220. package/templates/.agents/rules/core.md +5 -4
  221. package/templates/.agents/rules/local-sqlite-storage.md +18 -0
  222. package/templates/.agents/rules/meta-mcp.md +21 -0
  223. package/templates/.agents/rules/workflow.md +1 -0
  224. package/templates/.agents/runtime/bin/zaip.mjs +305 -137
  225. package/templates/.agents/runtime/checksums.sha256 +2 -2
  226. package/templates/.agents/runtime/provenance.json +2 -2
  227. package/templates/.agents/skills/zaip-skill-api-to-mcp/SKILL.md +4 -0
  228. package/templates/.agents/skills/zaip-skill-brand-governance/SKILL.md +25 -9
  229. package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-framework.md +2 -2
  230. package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-standards.md +2 -2
  231. package/templates/.agents/skills/zaip-skill-change/references/observable-evidence.md +15 -0
  232. package/templates/.agents/skills/zaip-skill-dashboard-sqlite/SKILL.md +13 -5
  233. package/templates/.agents/skills/zaip-skill-data-analyst/SKILL.md +10 -5
  234. package/templates/.agents/skills/zaip-skill-execution/SKILL.md +5 -4
  235. package/templates/.agents/skills/zaip-skill-frontend-launcher/SKILL.md +4 -3
  236. package/templates/.agents/skills/zaip-skill-frontend-launcher/references/launcher-contract.md +5 -3
  237. package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +5 -5
  238. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/preflight.mjs +78 -13
  239. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/preflight.test.mjs +59 -0
  240. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/yaml-parser.mjs +157 -0
  241. package/templates/.agents/skills/zaip-skill-growth-strategy-revops/SKILL.md +11 -6
  242. package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/SKILL.md +17 -0
  243. package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/agents/openai.yaml +7 -0
  244. package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/references/autonomous-cloud-inputs.example.json +41 -0
  245. package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/references/autonomous-runner.md +84 -0
  246. package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/references/operational-contract.md +19 -0
  247. package/templates/.agents/skills/zaip-skill-local-credentials/SKILL.md +43 -0
  248. package/templates/.agents/skills/zaip-skill-local-credentials/agents/openai.yaml +6 -0
  249. package/templates/.agents/skills/zaip-skill-local-credentials/references/dotenv-resolution.md +47 -0
  250. package/templates/.agents/skills/zaip-skill-marketing/SKILL.md +8 -3
  251. package/templates/.agents/skills/zaip-skill-meta-ads/SKILL.md +16 -0
  252. package/templates/.agents/skills/zaip-skill-meta-ads/agents/openai.yaml +4 -0
  253. package/templates/.agents/skills/zaip-skill-meta-ads/references/setup.md +3 -0
  254. package/templates/.agents/skills/zaip-skill-meta-ads-setup/SKILL.md +24 -0
  255. package/templates/.agents/skills/zaip-skill-meta-ads-setup/agents/openai.yaml +4 -0
  256. package/templates/.agents/skills/zaip-skill-meta-ads-setup/references/diagnostics.md +13 -0
  257. package/templates/.agents/skills/zaip-skill-meta-ads-setup/references/official-sources.md +10 -0
  258. package/templates/.agents/skills/zaip-skill-meta-devtools-api-health/SKILL.md +12 -0
  259. package/templates/.agents/skills/zaip-skill-meta-devtools-api-health/agents/openai.yaml +4 -0
  260. package/templates/.agents/skills/zaip-skill-meta-devtools-api-health/references/LICENSE +21 -0
  261. package/templates/.agents/skills/zaip-skill-meta-devtools-api-health/references/upstream.md +77 -0
  262. package/templates/.agents/skills/zaip-skill-meta-devtools-api-integration/SKILL.md +12 -0
  263. package/templates/.agents/skills/zaip-skill-meta-devtools-api-integration/agents/openai.yaml +4 -0
  264. package/templates/.agents/skills/zaip-skill-meta-devtools-api-integration/references/LICENSE +21 -0
  265. package/templates/.agents/skills/zaip-skill-meta-devtools-api-integration/references/upstream.md +126 -0
  266. package/templates/.agents/skills/zaip-skill-meta-devtools-app-health-check/SKILL.md +12 -0
  267. package/templates/.agents/skills/zaip-skill-meta-devtools-app-health-check/agents/openai.yaml +4 -0
  268. package/templates/.agents/skills/zaip-skill-meta-devtools-app-health-check/references/LICENSE +21 -0
  269. package/templates/.agents/skills/zaip-skill-meta-devtools-app-health-check/references/upstream.md +67 -0
  270. package/templates/.agents/skills/zaip-skill-meta-devtools-app-review-prep/SKILL.md +12 -0
  271. package/templates/.agents/skills/zaip-skill-meta-devtools-app-review-prep/agents/openai.yaml +4 -0
  272. package/templates/.agents/skills/zaip-skill-meta-devtools-app-review-prep/references/LICENSE +21 -0
  273. package/templates/.agents/skills/zaip-skill-meta-devtools-app-review-prep/references/upstream.md +69 -0
  274. package/templates/.agents/skills/zaip-skill-meta-devtools-compliance-check/SKILL.md +12 -0
  275. package/templates/.agents/skills/zaip-skill-meta-devtools-compliance-check/agents/openai.yaml +4 -0
  276. package/templates/.agents/skills/zaip-skill-meta-devtools-compliance-check/references/LICENSE +21 -0
  277. package/templates/.agents/skills/zaip-skill-meta-devtools-compliance-check/references/upstream.md +79 -0
  278. package/templates/.agents/skills/zaip-skill-meta-devtools-debug-access-token/SKILL.md +14 -0
  279. package/templates/.agents/skills/zaip-skill-meta-devtools-debug-access-token/agents/openai.yaml +4 -0
  280. package/templates/.agents/skills/zaip-skill-meta-devtools-debug-access-token/references/LICENSE +21 -0
  281. package/templates/.agents/skills/zaip-skill-meta-devtools-debug-access-token/references/upstream.md +144 -0
  282. package/templates/.agents/skills/zaip-skill-meta-devtools-debug-webhooks/SKILL.md +12 -0
  283. package/templates/.agents/skills/zaip-skill-meta-devtools-debug-webhooks/agents/openai.yaml +4 -0
  284. package/templates/.agents/skills/zaip-skill-meta-devtools-debug-webhooks/references/LICENSE +21 -0
  285. package/templates/.agents/skills/zaip-skill-meta-devtools-debug-webhooks/references/upstream.md +83 -0
  286. package/templates/.agents/skills/zaip-skill-meta-devtools-search-docs/SKILL.md +10 -0
  287. package/templates/.agents/skills/zaip-skill-meta-devtools-search-docs/agents/openai.yaml +4 -0
  288. package/templates/.agents/skills/zaip-skill-meta-devtools-search-docs/references/LICENSE +21 -0
  289. package/templates/.agents/skills/zaip-skill-meta-devtools-search-docs/references/setup.md +11 -0
  290. package/templates/.agents/skills/zaip-skill-meta-devtools-search-docs/references/upstream.md +55 -0
  291. package/templates/.agents/skills/zaip-skill-meta-devtools-webhook-setup/SKILL.md +12 -0
  292. package/templates/.agents/skills/zaip-skill-meta-devtools-webhook-setup/agents/openai.yaml +4 -0
  293. package/templates/.agents/skills/zaip-skill-meta-devtools-webhook-setup/references/LICENSE +21 -0
  294. package/templates/.agents/skills/zaip-skill-meta-devtools-webhook-setup/references/upstream.md +56 -0
  295. package/templates/.agents/skills/zaip-skill-sales-methodology/SKILL.md +12 -7
  296. package/templates/.agents/skills/zaip-skill-sqlite-read-model/SKILL.md +11 -4
  297. package/templates/.agents/skills/zaip-skill-tool-setup/SKILL.md +6 -4
  298. package/templates/.agents/skills/zaip-skill-tool-setup/references/codex-config.md +4 -2
  299. package/templates/.agents/skills/zaip-skill-tool-setup/references/secrets.md +1 -0
  300. package/templates/.agents/tools/catalog.yaml +6 -0
  301. package/templates/.agents/tools/cloud-runner-dns.mjs +28 -0
  302. package/templates/.agents/tools/cloud-runner-terraform.mjs +212 -0
  303. package/templates/.agents/tools/cloud-runner.integration.test.mjs +239 -0
  304. package/templates/.agents/tools/cloud-runner.mjs +786 -0
  305. package/templates/.agents/tools/cloud-runner.test.mjs +534 -0
  306. package/templates/.agents/tools/cloud-terraform-plan-policy.mjs +262 -0
  307. package/templates/.agents/tools/mcp/development/meta-devtools/README.md +14 -0
  308. package/templates/.agents/tools/mcp/development/meta-devtools/manifest.yaml +28 -0
  309. package/templates/.agents/tools/mcp/infra/cloudflare/manifest.yaml +2 -3
  310. package/templates/.agents/tools/mcp/infra/hostinger/manifest.yaml +1 -3
  311. package/templates/.agents/tools/mcp/marketing/meta-ads/README.md +15 -13
  312. package/templates/.agents/tools/mcp/marketing/meta-ads/manifest.yaml +15 -10
  313. package/templates/.agents/tools/profiles/development.yaml +3 -0
  314. package/templates/infra/terraform/.terraform.lock.hcl +42 -0
  315. package/templates/infra/terraform/README.md +31 -0
  316. package/templates/infra/terraform/backend.tf.json +13 -0
  317. package/templates/infra/terraform/deployment-inputs.example.yaml +22 -0
  318. package/templates/infra/terraform/fixtures/approved-targets.json +32 -0
  319. package/templates/infra/terraform/fixtures/plan-approved.json +67 -0
  320. package/templates/infra/terraform/main.tf +77 -0
  321. package/templates/infra/terraform/outputs.tf +20 -0
  322. package/templates/infra/terraform/terraform.tfvars.example +26 -0
  323. package/templates/infra/terraform/variables.tf +91 -0
  324. package/templates/infra/terraform/versions.tf +18 -0
  325. package/templates/scripts/validate-cloud-hostinger-contract.mjs +89 -0
  326. package/templates/scripts/validate-cloud-terraform-plan.mjs +1 -0
  327. package/templates/template-manifest.json +613 -173
  328. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-B_Oj6Dlf.js +0 -3
  329. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-C09KmlSw.js +0 -68
  330. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-CblPpexd.js +0 -2
  331. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-hPPfVGQv.css +0 -1
  332. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-stale-seed.ts +0 -50
@@ -9,7 +9,12 @@ type CostDimensionAggregateRow = {
9
9
  key: string;
10
10
  label: string;
11
11
  invocation_count: number;
12
- task_count: number;
12
+ task_count: number | null;
13
+ conversation_count: number;
14
+ prd_count: number | null;
15
+ spec_count: number | null;
16
+ test_count: number | null;
17
+ evidence_count: number | null;
13
18
  total_duration: number | null;
14
19
  source_event_count: number | null;
15
20
  total_tokens: number | null;
@@ -72,7 +77,7 @@ export function buildCostDimensionAggregates(
72
77
  );
73
78
  const activities = database
74
79
  .prepare(`SELECT activity_row_id, agent_invocation_id, task_id, duration_ms,
75
- source_event_count, provider, model, total_tokens, cost_usd, cost_brl,
80
+ source_event_count, provider, model, total_tokens, cost_usd, cost_brl, run_id,
76
81
  activity_source_kind, zaip_agent, zaip_agent_persona, zaip_agent_job,
77
82
  execution_id, conversation_id, occurred_at, occurred_day_sp, llm_call_count,
78
83
  input_tokens, cached_input_tokens, output_tokens, reasoning_tokens
@@ -99,6 +104,11 @@ export function buildCostDimensionAggregates(
99
104
  label: key,
100
105
  invocation_count: 0,
101
106
  task_count: 0,
107
+ conversation_count: 0,
108
+ prd_count: 0,
109
+ spec_count: 0,
110
+ test_count: 0,
111
+ evidence_count: 0,
102
112
  total_duration: null,
103
113
  source_event_count: null,
104
114
  total_tokens: null,
@@ -174,31 +184,127 @@ export function buildCostDimensionAggregates(
174
184
  }
175
185
  }
176
186
  }
177
- const taskKeys = new Map<"model" | "provider", Map<string, Set<string>>>(
178
- dimensions.map((dimension) => [dimension, new Map()]),
187
+ // Productivity is a creation fact, never inferred from a later Run that
188
+ // happened to reference the Task. A multi-model creation Run has no
189
+ // defensible single owner, so its entities remain unavailable by model.
190
+ const modelsByCreationRun = new Map<string, Set<string>>();
191
+ for (const [id, invocationSegments] of segmentsByInvocation) {
192
+ const keys = [
193
+ ...new Set(
194
+ invocationSegments
195
+ .filter((segment) => {
196
+ const model = observedDimensionValue(segment.model);
197
+ const provider = observedDimensionValue(segment.provider);
198
+ return (
199
+ model !== null &&
200
+ provider !== null &&
201
+ allowedProviders.has(provider) &&
202
+ (typeof segment.total_tokens === "number" ||
203
+ typeof segment.cost_usd === "number" ||
204
+ typeof segment.cost_brl === "number")
205
+ );
206
+ })
207
+ .map((segment) => observedDimensionValue(segment.model)!),
208
+ ),
209
+ ];
210
+ const runId = activityByInvocation.get(id)?.run_id;
211
+ if (typeof runId !== "string") continue;
212
+ const observed = modelsByCreationRun.get(runId) ?? new Set<string>();
213
+ for (const key of keys) observed.add(key);
214
+ modelsByCreationRun.set(runId, observed);
215
+ }
216
+ const modelByCreationRun = new Map(
217
+ [...modelsByCreationRun].flatMap(([runId, models]) =>
218
+ models.size === 1 ? [[runId, [...models][0]!] as const] : [],
219
+ ),
179
220
  );
221
+ const createdSpecsByModel = new Map<string, Set<string>>();
222
+ const createdPrdsByModel = new Map<string, Set<string>>();
223
+ for (const item of database
224
+ .prepare(
225
+ "SELECT entity_kind, id, creation_run_id FROM canonical_work_items WHERE creation_run_id IS NOT NULL",
226
+ )
227
+ .all() as Array<{ entity_kind: string; id: string; creation_run_id: string }>) {
228
+ const model = modelByCreationRun.get(item.creation_run_id);
229
+ if (model === undefined) continue;
230
+ const target =
231
+ item.entity_kind === "spec"
232
+ ? createdSpecsByModel
233
+ : item.entity_kind === "prd"
234
+ ? createdPrdsByModel
235
+ : null;
236
+ if (target === null) continue;
237
+ const values = target.get(model) ?? new Set<string>();
238
+ values.add(item.id);
239
+ target.set(model, values);
240
+ }
241
+ const artifactsByModel = new Map<string, { tests: number; evidences: number }>();
242
+ for (const artifact of database
243
+ .prepare(
244
+ "SELECT path, artifact_kind, artifact_run_id FROM files WHERE artifact_run_id IS NOT NULL AND artifact_kind IN ('validation', 'evidence')",
245
+ )
246
+ .all() as Array<{ path: string; artifact_kind: string; artifact_run_id: string }>) {
247
+ if (artifact.artifact_kind === "validation" && !artifact.path.includes("/artifacts/tests/"))
248
+ continue;
249
+ const model = modelByCreationRun.get(artifact.artifact_run_id);
250
+ if (model === undefined) continue;
251
+ const current = artifactsByModel.get(model) ?? { tests: 0, evidences: 0 };
252
+ if (artifact.artifact_kind === "validation") current.tests += 1;
253
+ else current.evidences += 1;
254
+ artifactsByModel.set(model, current);
255
+ }
256
+ for (const [model, artifacts] of artifactsByModel) {
257
+ const row = ensure("model", model);
258
+ row.test_count = artifacts.tests;
259
+ row.evidence_count = artifacts.evidences;
260
+ }
261
+ for (const [model, specs] of createdSpecsByModel) ensure("model", model).spec_count = specs.size;
262
+ for (const [model, prds] of createdPrdsByModel) ensure("model", model).prd_count = prds.size;
263
+ const modelTasks = new Map<string, Set<string>>();
264
+ const modelConversations = new Map<string, Set<string>>();
265
+ const providerTasks = new Map<string, Set<string>>();
180
266
  for (const [id, invocationSegments] of segmentsByInvocation) {
181
- const taskId = activityByInvocation.get(id)?.task_id;
182
- if (typeof taskId !== "string") continue;
183
- for (const dimension of dimensions) {
184
- const byTask = taskKeys.get(dimension)!;
185
- const keys = byTask.get(taskId) ?? new Set<string>();
186
- for (const segment of invocationSegments) {
187
- const key = observedDimensionValue(segment[dimension]);
188
- const provider = observedDimensionValue(segment.provider);
189
- const hasFinancialFact =
190
- typeof segment.total_tokens === "number" ||
191
- typeof segment.cost_usd === "number" ||
192
- typeof segment.cost_brl === "number";
193
- if (key !== null && provider !== null && allowedProviders.has(provider) && hasFinancialFact)
194
- keys.add(key);
267
+ const activity = activityByInvocation.get(id);
268
+ const taskId = activity?.task_id;
269
+ for (const segment of invocationSegments) {
270
+ const provider = observedDimensionValue(segment.provider);
271
+ const model = observedDimensionValue(segment.model);
272
+ const hasFinancialFact =
273
+ typeof segment.total_tokens === "number" ||
274
+ typeof segment.cost_usd === "number" ||
275
+ typeof segment.cost_brl === "number";
276
+ if (provider === null || !allowedProviders.has(provider) || !hasFinancialFact) continue;
277
+ if (model !== null) {
278
+ if (typeof taskId === "string" && activity?.activity_source_kind !== "unassisted_turn") {
279
+ const tasks = modelTasks.get(model) ?? new Set<string>();
280
+ tasks.add(taskId);
281
+ modelTasks.set(model, tasks);
282
+ }
195
283
  }
196
- byTask.set(taskId, keys);
284
+ const conversationId = activity?.conversation_id;
285
+ const isConversation =
286
+ typeof conversationId === "string" &&
287
+ (activity?.activity_source_kind === "unassisted_turn" || typeof taskId !== "string");
288
+ if (isConversation) {
289
+ const conversationModel = model ?? "unavailable";
290
+ const conversations = modelConversations.get(conversationModel) ?? new Set<string>();
291
+ conversations.add(conversationId);
292
+ modelConversations.set(conversationModel, conversations);
293
+ }
294
+ if (typeof taskId !== "string") continue;
295
+ const tasks = providerTasks.get(provider) ?? new Set<string>();
296
+ tasks.add(taskId);
297
+ providerTasks.set(provider, tasks);
197
298
  }
198
299
  }
199
- for (const dimension of dimensions)
200
- for (const keys of taskKeys.get(dimension)!.values())
201
- for (const key of keys) ensure(dimension, key).task_count += 1;
300
+ // A Task participates once per observed model. It can therefore appear in
301
+ // more than one Modelos LLM row, and the model footer is intentionally the
302
+ // sum of those row memberships.
303
+ for (const [model, tasks] of modelTasks) ensure("model", model).task_count = tasks.size;
304
+ for (const [model, conversations] of modelConversations)
305
+ ensure("model", model).conversation_count = conversations.size;
306
+ for (const [provider, tasks] of providerTasks)
307
+ ensure("provider", provider).task_count = tasks.size;
202
308
  for (const activity of activities) {
203
309
  if (typeof activity.agent_invocation_id === "string") continue;
204
310
  const hasFinancialFact =
@@ -212,7 +318,6 @@ export function buildCostDimensionAggregates(
212
318
  const key = observedDimensionValue(activity[dimension]) ?? "unavailable";
213
319
  const target = ensure(dimension, key);
214
320
  target.invocation_count += 1;
215
- if (typeof activity.task_id === "string") target.task_count += 1;
216
321
  if (typeof activity.duration_ms === "number")
217
322
  target.total_duration = (target.total_duration ?? 0) + activity.duration_ms;
218
323
  if (typeof activity.source_event_count === "number")
@@ -221,6 +326,29 @@ export function buildCostDimensionAggregates(
221
326
  add(target, "total_cost_usd", activity.cost_usd);
222
327
  add(target, "total_cost_brl", activity.cost_brl);
223
328
  }
329
+ const model = observedDimensionValue(activity.model);
330
+ const conversationId = activity.conversation_id;
331
+ if (model !== null) {
332
+ if (
333
+ typeof activity.task_id === "string" &&
334
+ activity.activity_source_kind !== "unassisted_turn"
335
+ ) {
336
+ const tasks = modelTasks.get(model) ?? new Set<string>();
337
+ tasks.add(activity.task_id);
338
+ modelTasks.set(model, tasks);
339
+ ensure("model", model).task_count = tasks.size;
340
+ }
341
+ }
342
+ if (
343
+ typeof conversationId === "string" &&
344
+ (activity.activity_source_kind === "unassisted_turn" || typeof activity.task_id !== "string")
345
+ ) {
346
+ const conversationModel = model ?? "unavailable";
347
+ const conversations = modelConversations.get(conversationModel) ?? new Set<string>();
348
+ conversations.add(conversationId);
349
+ modelConversations.set(conversationModel, conversations);
350
+ ensure("model", conversationModel).conversation_count = conversations.size;
351
+ }
224
352
  }
225
353
  const base = Object.fromEntries(
226
354
  dimensions.map((dimension) => [
@@ -256,6 +384,11 @@ export function buildCostDimensionAggregates(
256
384
  occurred_at: "",
257
385
  invocation_count: 0,
258
386
  task_count: 0,
387
+ conversation_count: 0,
388
+ prd_count: null,
389
+ spec_count: null,
390
+ test_count: null,
391
+ evidence_count: null,
259
392
  llm_call_count: null,
260
393
  total_duration: null,
261
394
  duration_unknown: 0,
@@ -3,39 +3,48 @@ import type { DatabaseSync } from "node:sqlite";
3
3
  /** Freezes legacy Cost facts and their entity labels once for fast date-only pages. */
4
4
  export function materializeCostGroupDailyProjection(database: DatabaseSync): void {
5
5
  database.exec(`
6
- CREATE TABLE cost_group_daily_projection AS SELECT * FROM zaip_vw_cost_monitor_group_daily_cache;
7
- CREATE INDEX cost_group_daily_projection_lookup ON cost_group_daily_projection(group_kind, day, group_value);
6
+ CREATE TABLE IF NOT EXISTS cost_group_daily_projection AS SELECT * FROM zaip_vw_cost_monitor_group_daily_cache LIMIT 0;
7
+ DELETE FROM cost_group_daily_projection;
8
+ INSERT INTO cost_group_daily_projection SELECT * FROM zaip_vw_cost_monitor_group_daily_cache;
9
+ CREATE INDEX IF NOT EXISTS cost_group_daily_projection_lookup ON cost_group_daily_projection(group_kind, day, group_value);
8
10
 
9
11
  -- The public entity views expand canonical records and activities. Reading
10
12
  -- them for every grouped page was the remaining multi-second cost, most
11
13
  -- visibly for conversations. Persist exactly the three presentation fields
12
14
  -- the old LEFT JOIN supplied, keyed by the already-materialized population.
13
- CREATE TABLE cost_group_entity_projection AS
15
+ CREATE TABLE IF NOT EXISTS cost_group_entity_projection(group_kind TEXT, group_value TEXT, title TEXT, status TEXT, risk TEXT);
16
+ DELETE FROM cost_group_entity_projection;
17
+ INSERT INTO cost_group_entity_projection
18
+ WITH tasks AS MATERIALIZED (SELECT * FROM zaip_vw_tasks),
19
+ specs AS MATERIALIZED (SELECT * FROM zaip_vw_specs),
20
+ prds AS MATERIALIZED (SELECT * FROM zaip_vw_prds),
21
+ executions AS MATERIALIZED (SELECT * FROM zaip_vw_executions),
22
+ conversations AS MATERIALIZED (SELECT * FROM zaip_vw_conversations)
14
23
  SELECT 'task' AS group_kind, groups.group_value, entity.title, entity.status, entity.risk
15
24
  FROM (SELECT DISTINCT group_value FROM cost_group_daily_projection
16
25
  WHERE group_kind = 'task' AND group_value IS NOT NULL) groups
17
- LEFT JOIN zaip_vw_tasks entity ON entity.id = groups.group_value
26
+ LEFT JOIN tasks entity ON entity.id = groups.group_value
18
27
  UNION ALL
19
28
  SELECT 'spec', groups.group_value, entity.title, entity.status, entity.risk
20
29
  FROM (SELECT DISTINCT group_value FROM cost_group_daily_projection
21
30
  WHERE group_kind = 'spec' AND group_value IS NOT NULL) groups
22
- LEFT JOIN zaip_vw_specs entity ON entity.id = groups.group_value
31
+ LEFT JOIN specs entity ON entity.id = groups.group_value
23
32
  UNION ALL
24
33
  SELECT 'prd', groups.group_value, entity.title, entity.status, entity.risk
25
34
  FROM (SELECT DISTINCT group_value FROM cost_group_daily_projection
26
35
  WHERE group_kind = 'prd' AND group_value IS NOT NULL) groups
27
- LEFT JOIN zaip_vw_prds entity ON entity.id = groups.group_value
36
+ LEFT JOIN prds entity ON entity.id = groups.group_value
28
37
  UNION ALL
29
38
  SELECT 'execution', groups.group_value, NULL, entity.status, NULL
30
39
  FROM (SELECT DISTINCT group_value FROM cost_group_daily_projection
31
40
  WHERE group_kind = 'execution' AND group_value IS NOT NULL) groups
32
- LEFT JOIN zaip_vw_executions entity ON entity.id = groups.group_value
41
+ LEFT JOIN executions entity ON entity.id = groups.group_value
33
42
  UNION ALL
34
43
  SELECT 'conversation', groups.group_value, NULL, entity.status, NULL
35
44
  FROM (SELECT DISTINCT group_value FROM cost_group_daily_projection
36
45
  WHERE group_kind = 'conversation' AND group_value IS NOT NULL) groups
37
- LEFT JOIN zaip_vw_conversations entity ON entity.id = groups.group_value;
38
- CREATE UNIQUE INDEX cost_group_entity_projection_lookup
46
+ LEFT JOIN conversations entity ON entity.id = groups.group_value;
47
+ CREATE UNIQUE INDEX IF NOT EXISTS cost_group_entity_projection_lookup
39
48
  ON cost_group_entity_projection(group_kind, group_value);
40
49
  `);
41
50
  }
@@ -0,0 +1,52 @@
1
+ import type { DatabaseSync } from "node:sqlite";
2
+
3
+ // Expand the persisted usage payloads once so the join can use an automatic
4
+ // index instead of decoding every historical segment for each invocation.
5
+ export const costInvocationProjectionSelect = `WITH usage AS MATERIALIZED (SELECT * FROM invocation_usage)
6
+ SELECT i.*,
7
+ COUNT(u.usage_index) AS pricing_segment_count,
8
+ CASE WHEN COUNT(DISTINCT COALESCE(u.provider, '') || '|' || COALESCE(u.model, '') || '|' || COALESCE(u.service_tier, 'default') || '|' || COALESCE(CAST(u.context_input_multiplier AS TEXT), '') || '|' || COALESCE(CAST(u.context_output_multiplier AS TEXT), '')) > 1 THEN 1 ELSE 0 END AS pricing_mixed,
9
+ SUM(u.uncached_input_tokens) AS uncached_input_tokens,
10
+ SUM(u.visible_output_tokens) AS visible_output_tokens,
11
+ CASE COUNT(DISTINCT u.input_rate_usd_per_million) WHEN 1 THEN MIN(u.input_rate_usd_per_million) ELSE NULL END AS input_rate_usd_per_million,
12
+ CASE COUNT(DISTINCT u.cached_input_rate_usd_per_million) WHEN 1 THEN MIN(u.cached_input_rate_usd_per_million) ELSE NULL END AS cached_input_rate_usd_per_million,
13
+ CASE COUNT(DISTINCT u.output_rate_usd_per_million) WHEN 1 THEN MIN(u.output_rate_usd_per_million) ELSE NULL END AS output_rate_usd_per_million,
14
+ CASE COUNT(DISTINCT u.reasoning_rate_usd_per_million) WHEN 1 THEN MIN(u.reasoning_rate_usd_per_million) ELSE NULL END AS reasoning_rate_usd_per_million,
15
+ CASE COUNT(DISTINCT u.context_input_multiplier) WHEN 1 THEN MIN(u.context_input_multiplier) ELSE NULL END AS context_input_multiplier,
16
+ CASE COUNT(DISTINCT u.context_output_multiplier) WHEN 1 THEN MIN(u.context_output_multiplier) ELSE NULL END AS context_output_multiplier,
17
+ CASE COUNT(DISTINCT u.speed_cost_multiplier) WHEN 1 THEN MIN(u.speed_cost_multiplier) ELSE NULL END AS speed_cost_multiplier,
18
+ CASE COUNT(DISTINCT u.pricing_scenario) WHEN 1 THEN MIN(u.pricing_scenario) ELSE 'mixed' END AS pricing_scenario,
19
+ SUM(u.standard_cost_usd) AS standard_cost_usd,
20
+ SUM(u.speed_uplift_usd) AS speed_uplift_usd,
21
+ SUM(u.input_cost_usd) AS input_cost_usd,
22
+ SUM(u.cached_input_cost_usd) AS cached_input_cost_usd,
23
+ SUM(u.output_cost_usd) AS output_cost_usd,
24
+ SUM(u.reasoning_cost_usd) AS reasoning_cost_usd,
25
+ SUM(u.calculated_cost_usd) AS calculated_cost_usd,
26
+ SUM(u.recorded_cost_usd) AS recorded_cost_usd,
27
+ CASE COUNT(DISTINCT CASE WHEN u.recorded_cost_usd IS NOT NULL THEN u.fx_rate END)
28
+ WHEN 1 THEN MIN(CASE WHEN u.recorded_cost_usd IS NOT NULL THEN u.fx_rate END)
29
+ ELSE NULL
30
+ END AS recorded_fx_rate,
31
+ SUM(CASE WHEN u.recorded_cost_usd IS NOT NULL THEN u.cost_brl END) AS recorded_brl,
32
+ (SELECT json_extract(fx.content, '$.rate')
33
+ FROM files fx
34
+ WHERE fx.path LIKE '.agents/config/pricing/fx/%.json'
35
+ ORDER BY CASE WHEN fx.path LIKE '%/current-usd-brl.json' THEN 0 ELSE 1 END,
36
+ json_extract(fx.content, '$.as_of') DESC
37
+ LIMIT 1) AS current_fx_rate,
38
+ SUM(u.cost_variance_usd) AS cost_variance_usd,
39
+ CASE COUNT(DISTINCT u.pricing_model) WHEN 1 THEN MIN(u.pricing_model) ELSE NULL END AS audit_pricing_model,
40
+ CASE COUNT(DISTINCT u.pricing_source) WHEN 1 THEN MIN(u.pricing_source) ELSE NULL END AS audit_pricing_source
41
+ FROM invocations i LEFT JOIN usage u USING(agent_invocation_id)
42
+ GROUP BY i.agent_invocation_id`;
43
+
44
+ export function readCostInvocationProjection(
45
+ database: DatabaseSync,
46
+ ): Array<Record<string, unknown>> {
47
+ const sql = costInvocationProjectionSelect
48
+ .replaceAll(/\binvocation_usage\b/g, "zaip_vw_invocation_usage")
49
+ .replaceAll(/\binvocations\b/g, "zaip_vw_invocations")
50
+ .replaceAll(/\bfiles\b/g, "zaip_vw_files");
51
+ return database.prepare(sql).all() as Array<Record<string, unknown>>;
52
+ }
@@ -96,20 +96,8 @@ export function persistFirstFoldPayloads(
96
96
  for (const path of paths) {
97
97
  const database = new DatabaseSync(path);
98
98
  try {
99
- const insert = database.prepare(`INSERT INTO zaip_aios_activities(
100
- activity_row_id, activity_source_kind, activity_key, source_path, source_hash,
101
- recorded_at, run_role, root_run_id, payload_type, payload_json
102
- ) VALUES (?, 'technical_payload', ?, ?, '', datetime('now'), 'technical', 'technical', ?, ?)`);
103
99
  database.exec("BEGIN;");
104
- for (const [payloadType, key] of technicalPayloads) {
105
- insert.run(
106
- `TECH-${randomUUID().toLowerCase()}`,
107
- key,
108
- `sqlite://${payloadType}/${key.split(":")[1]}`,
109
- payloadType,
110
- payloads[payloadType],
111
- );
112
- }
100
+ persistFirstFoldPayloadsInDatabase(database, payloads);
113
101
  database.exec("COMMIT;");
114
102
  } catch (error) {
115
103
  database.exec("ROLLBACK;");
@@ -119,3 +107,37 @@ export function persistFirstFoldPayloads(
119
107
  }
120
108
  }
121
109
  }
110
+
111
+ /** Adds first-fold payloads to the caller's current transaction. */
112
+ export function persistFirstFoldPayloadsInDatabase(
113
+ database: DatabaseSync,
114
+ payloads: FirstFoldPayloads,
115
+ ): void {
116
+ const insert = database.prepare(`INSERT INTO zaip_aios_activities(
117
+ activity_row_id, activity_source_kind, activity_key, source_path, source_hash,
118
+ recorded_at, run_role, root_run_id, payload_type, payload_json
119
+ ) VALUES (?, 'technical_payload', ?, ?, '', datetime('now'), 'technical', 'technical', ?, ?)`);
120
+ for (const [payloadType, key] of technicalPayloads) {
121
+ const existing = database
122
+ .prepare(
123
+ "SELECT activity_row_id,payload_json FROM zaip_aios_activities WHERE payload_type=? AND activity_key=?",
124
+ )
125
+ .get(payloadType, key) as { activity_row_id: string; payload_json: string } | undefined;
126
+ if (existing) {
127
+ if (existing.payload_json !== payloads[payloadType])
128
+ database
129
+ .prepare(
130
+ "UPDATE zaip_aios_activities SET payload_json=?,recorded_at=datetime('now') WHERE activity_row_id=?",
131
+ )
132
+ .run(payloads[payloadType], existing.activity_row_id);
133
+ continue;
134
+ }
135
+ insert.run(
136
+ `TECH-${randomUUID().toLowerCase()}`,
137
+ key,
138
+ `sqlite://${payloadType}/${key.split(":")[1]}`,
139
+ payloadType,
140
+ payloads[payloadType],
141
+ );
142
+ }
143
+ }
@@ -0,0 +1,56 @@
1
+ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
2
+ import { join, resolve } from "node:path";
3
+ import { DatabaseSync } from "node:sqlite";
4
+ import { afterEach, describe, expect, it } from "vitest";
5
+ import { rebuildSqliteReadModel } from "./sqlite-read-model.js";
6
+
7
+ const roots: string[] = [];
8
+
9
+ async function fixture(): Promise<string> {
10
+ const directory = resolve(import.meta.dirname, "../../../../..", ".local/sqlite/tests");
11
+ await mkdir(directory, { recursive: true });
12
+ const root = await mkdtemp(join(directory, "force-canonical-"));
13
+ roots.push(root);
14
+ await mkdir(join(root, ".agents/config"), { recursive: true });
15
+ await writeFile(join(root, ".agents/config/project.yaml"), "zaip:\n enabled: true\n");
16
+ return root;
17
+ }
18
+
19
+ afterEach(async () => {
20
+ await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
21
+ });
22
+
23
+ describe("forceCanonical SQLite refresh", () => {
24
+ it("bypasses a healthy generation and verifies canonical sources again", async () => {
25
+ const root = await fixture();
26
+ const initial = await rebuildSqliteReadModel(root);
27
+ await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({
28
+ cache: "generation",
29
+ refresh: { processed_sources: 0 },
30
+ });
31
+ await expect(rebuildSqliteReadModel(root, { forceCanonical: true })).resolves.toMatchObject({
32
+ cache: "rebuilt",
33
+ path: initial.path,
34
+ refresh: { processed_sources: 1 },
35
+ });
36
+ });
37
+
38
+ it("rebuilds a generation whose persisted schema marker is incompatible", async () => {
39
+ const root = await fixture();
40
+ const initial = await rebuildSqliteReadModel(root);
41
+ const database = new DatabaseSync(initial.path);
42
+ try {
43
+ database
44
+ .prepare(
45
+ "UPDATE zaip_aios_activities SET payload_json=json_set(payload_json, '$.value', 'invalid') WHERE payload_type='metadata' AND activity_key='metadata:schema_version'",
46
+ )
47
+ .run();
48
+ } finally {
49
+ database.close();
50
+ }
51
+ await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({
52
+ cache: "rebuilt",
53
+ path: initial.path,
54
+ });
55
+ });
56
+ });
@@ -0,0 +1,29 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { affectedTemporalIntervals } from "./sqlite-incremental-cache.js";
3
+
4
+ describe("temporal delta dependencies", () => {
5
+ it("includes old overlap neighbors after removal while excluding disjoint history", () => {
6
+ const old = [
7
+ { activityRowId: "removed", startMs: 10, endMs: 20 },
8
+ { activityRowId: "neighbor", startMs: 18, endMs: 30 },
9
+ { activityRowId: "chain", startMs: 29, endMs: 40 },
10
+ { activityRowId: "untouched", startMs: 100, endMs: 120 },
11
+ ];
12
+ const result = affectedTemporalIntervals(old, old.slice(1), new Set(["removed"]));
13
+ expect([...result.ids].sort()).toEqual(["chain", "neighbor", "removed"]);
14
+ expect(result.intervals.map((row) => row.activityRowId)).toEqual(["neighbor", "chain"]);
15
+ });
16
+ it("covers both old and new components of a moved interval without crossing a gap", () => {
17
+ const history = [
18
+ { activityRowId: "old-neighbor", startMs: 0, endMs: 10 },
19
+ { activityRowId: "gap", startMs: 30, endMs: 40 },
20
+ { activityRowId: "new-neighbor", startMs: 100, endMs: 110 },
21
+ ];
22
+ const result = affectedTemporalIntervals(
23
+ [...history, { activityRowId: "moved", startMs: 5, endMs: 15 }],
24
+ [...history, { activityRowId: "moved", startMs: 105, endMs: 115 }],
25
+ new Set(["moved"]),
26
+ );
27
+ expect([...result.ids].sort()).toEqual(["moved", "new-neighbor", "old-neighbor"]);
28
+ });
29
+ });
@@ -0,0 +1,136 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import type { DatabaseSync } from "node:sqlite";
3
+
4
+ /** Parsed canonical records survive worker restarts in the same transaction as their facts. */
5
+ export class SqliteParsedSourceCache {
6
+ constructor(private readonly database: DatabaseSync) {}
7
+
8
+ read<T>(kind: string, path: string, hash: string, parse: () => T): T {
9
+ const key = `parsed_source:${kind}:${path}`;
10
+ const cached = this.database
11
+ .prepare(
12
+ "SELECT source_hash, payload_json FROM zaip_aios_activities WHERE payload_type='parsed_source' AND activity_key=?",
13
+ )
14
+ .get(key) as { source_hash: string; payload_json: string } | undefined;
15
+ if (cached?.source_hash === hash) {
16
+ try {
17
+ return JSON.parse(cached.payload_json) as T;
18
+ } catch {
19
+ /* A damaged derived cache is repaired from this source only. */
20
+ }
21
+ }
22
+ const value = parse();
23
+ this.database
24
+ .prepare(
25
+ "DELETE FROM zaip_aios_activities WHERE payload_type='parsed_source' AND activity_key=?",
26
+ )
27
+ .run(key);
28
+ this.database
29
+ .prepare(`INSERT INTO zaip_aios_activities(
30
+ activity_row_id, activity_source_kind, activity_key, source_path, source_hash,
31
+ recorded_at, run_role, root_run_id, payload_type, payload_json
32
+ ) VALUES (?, 'technical_payload', ?, ?, ?, ?, 'technical', 'technical', 'parsed_source', ?)`)
33
+ .run(
34
+ `TECH-${randomUUID()}`,
35
+ key,
36
+ path,
37
+ hash,
38
+ new Date().toISOString(),
39
+ JSON.stringify(value),
40
+ );
41
+ return value;
42
+ }
43
+ }
44
+
45
+ export type CachedTemporalInterval = { activityRowId: string; startMs: number; endMs: number };
46
+
47
+ /** Upserts changed derived rows while keeping untouched row identities and processing timestamps. */
48
+ export type IncrementalPayloadRow = {
49
+ row_key: string;
50
+ payload_json: string;
51
+ occurred_day_sp?: string | null;
52
+ };
53
+ export function synchronizePayloadRows(
54
+ database: DatabaseSync,
55
+ type: string,
56
+ select: string | readonly IncrementalPayloadRow[],
57
+ ): void {
58
+ const previous = new Map(
59
+ (
60
+ database
61
+ .prepare(
62
+ "SELECT activity_row_id,activity_key,payload_json FROM zaip_aios_activities WHERE payload_type=?",
63
+ )
64
+ .all(type) as Array<{ activity_row_id: string; activity_key: string; payload_json: string }>
65
+ ).map((row) => [row.activity_key, row]),
66
+ );
67
+ const insert = database.prepare(`INSERT INTO zaip_aios_activities(
68
+ activity_row_id,activity_source_kind,activity_key,source_path,source_hash,recorded_at,run_role,root_run_id,payload_type,payload_json,occurred_day_sp
69
+ ) VALUES (?,'technical_payload',?,?,'',?,'technical','technical',?,?,?)`);
70
+ const update = database.prepare(
71
+ "UPDATE zaip_aios_activities SET payload_json=?,recorded_at=?,occurred_day_sp=? WHERE activity_row_id=?",
72
+ );
73
+ const remove = database.prepare("DELETE FROM zaip_aios_activities WHERE activity_row_id=?");
74
+ const rows =
75
+ typeof select === "string"
76
+ ? (database.prepare(select).all() as IncrementalPayloadRow[])
77
+ : select;
78
+ for (const row of rows) {
79
+ const key = `${type}:${row.row_key}`;
80
+ const old = previous.get(key);
81
+ let payload = row.payload_json;
82
+ if (type === "source_state" && old) {
83
+ const value = JSON.parse(payload);
84
+ const original = JSON.parse(old.payload_json);
85
+ if (value.source_hash === original.source_hash)
86
+ value.last_processed_at = original.last_processed_at;
87
+ payload = JSON.stringify(value);
88
+ }
89
+ if (!old)
90
+ insert.run(
91
+ `TECH-${randomUUID()}`,
92
+ key,
93
+ `sqlite://${type}`,
94
+ new Date().toISOString(),
95
+ type,
96
+ payload,
97
+ row.occurred_day_sp ?? null,
98
+ );
99
+ else if (payload !== old.payload_json)
100
+ update.run(
101
+ payload,
102
+ new Date().toISOString(),
103
+ row.occurred_day_sp ?? null,
104
+ old.activity_row_id,
105
+ );
106
+ previous.delete(key);
107
+ }
108
+ for (const row of previous.values()) remove.run(row.activity_row_id);
109
+ }
110
+
111
+ /** Include the connected old/new overlap component so neighbors are recalculated consistently. */
112
+ export function affectedTemporalIntervals(
113
+ oldIntervals: readonly CachedTemporalInterval[],
114
+ newIntervals: readonly CachedTemporalInterval[],
115
+ dirtyIds: ReadonlySet<string>,
116
+ ): { ids: Set<string>; intervals: CachedTemporalInterval[] } {
117
+ const ids = new Set(dirtyIds);
118
+ const ranges = [...oldIntervals, ...newIntervals].filter((interval) =>
119
+ ids.has(interval.activityRowId),
120
+ );
121
+ let changed = true;
122
+ while (changed) {
123
+ changed = false;
124
+ for (const interval of newIntervals) {
125
+ if (ids.has(interval.activityRowId)) continue;
126
+ if (
127
+ ranges.some((range) => interval.startMs < range.endMs && interval.endMs > range.startMs)
128
+ ) {
129
+ ids.add(interval.activityRowId);
130
+ ranges.push(interval);
131
+ changed = true;
132
+ }
133
+ }
134
+ }
135
+ return { ids, intervals: newIntervals.filter((interval) => ids.has(interval.activityRowId)) };
136
+ }