@zaip-ai/cli 1.3.8 → 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 (315) hide show
  1. package/README.md +58 -3
  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 +17 -6
  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 +2 -0
  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-plan.d.ts +3 -1
  42. package/dist/services/stack-plan.d.ts.map +1 -1
  43. package/dist/services/stack-plan.js +15 -1
  44. package/dist/services/stack-plan.js.map +1 -1
  45. package/dist/services/stack-terraform.d.ts +13 -0
  46. package/dist/services/stack-terraform.d.ts.map +1 -0
  47. package/dist/services/stack-terraform.js +274 -0
  48. package/dist/services/stack-terraform.js.map +1 -0
  49. package/dist/services/template-manifest.d.ts.map +1 -1
  50. package/dist/services/template-manifest.js +14 -1
  51. package/dist/services/template-manifest.js.map +1 -1
  52. package/dist/types.d.ts +1 -0
  53. package/dist/types.d.ts.map +1 -1
  54. package/package.json +1 -1
  55. package/templates/.agents/.env.example +34 -0
  56. package/templates/{README.md → .agents/README.md} +124 -60
  57. package/templates/.agents/config/agents/catalog.yaml +23 -23
  58. package/templates/.agents/config/clients/codex/agents/zaip-agent-analyst.toml +1 -0
  59. package/templates/.agents/config/clients/codex/agents/zaip-agent-auditor.toml +1 -0
  60. package/templates/.agents/config/clients/codex/agents/zaip-agent-backend.toml +5 -4
  61. package/templates/.agents/config/clients/codex/agents/zaip-agent-brand-strategist.toml +1 -0
  62. package/templates/.agents/config/clients/codex/agents/zaip-agent-builder.toml +1 -0
  63. package/templates/.agents/config/clients/codex/agents/zaip-agent-cloud-engineer.toml +10 -7
  64. package/templates/.agents/config/clients/codex/agents/zaip-agent-data-analyst.toml +1 -0
  65. package/templates/.agents/config/clients/codex/agents/zaip-agent-designer.toml +1 -0
  66. package/templates/.agents/config/clients/codex/agents/zaip-agent-finalizer.toml +1 -0
  67. package/templates/.agents/config/clients/codex/agents/zaip-agent-frontend.toml +5 -4
  68. package/templates/.agents/config/clients/codex/agents/zaip-agent-general-operations.toml +1 -0
  69. package/templates/.agents/config/clients/codex/agents/zaip-agent-governance-compliance.toml +1 -0
  70. package/templates/.agents/config/clients/codex/agents/zaip-agent-growth-strategist.toml +1 -0
  71. package/templates/.agents/config/clients/codex/agents/zaip-agent-integrator.toml +1 -0
  72. package/templates/.agents/config/clients/codex/agents/zaip-agent-marketing-analyst.toml +5 -4
  73. package/templates/.agents/config/clients/codex/agents/zaip-agent-orchestrator.toml +1 -0
  74. package/templates/.agents/config/clients/codex/agents/zaip-agent-refactoring-specialist.toml +1 -0
  75. package/templates/.agents/config/clients/codex/agents/zaip-agent-reviewer.toml +1 -0
  76. package/templates/.agents/config/clients/codex/agents/zaip-agent-sales-specialist.toml +1 -0
  77. package/templates/.agents/config/clients/codex/agents/zaip-agent-security-auditor.toml +1 -0
  78. package/templates/.agents/config/clients/codex/agents/zaip-agent-task-executor.toml +1 -0
  79. package/templates/.agents/config/clients/codex/agents/zaip-agent-website-developer.toml +5 -4
  80. package/templates/.agents/config/clients/codex/agents/zaip-agent-writer.toml +1 -0
  81. package/templates/.agents/config/pricing/models.json +25 -1
  82. package/templates/.agents/config/project.yaml +2 -0
  83. package/templates/.agents/dashboard/.zaip-managed.json +200 -88
  84. package/templates/.agents/dashboard/DATA-DICTIONARY.md +1 -1
  85. package/templates/.agents/dashboard/README.md +58 -19
  86. package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-DwVZOmMV.js → CostCalculationGuidePage-snUCQYTC.js} +1 -1
  87. package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-VcLx9iOO.js → DashboardHelpDialog-oZVlf-l5.js} +72 -8
  88. package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-CyjMXkm8.js → PricingSettingsDialog-BPtVUGgs.js} +1 -1
  89. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-3Awyaovx.js +3 -0
  90. package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-DFZwIXSC.js → TraceabilityWorkspace-BYjVOHI_.js} +1 -1
  91. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-DbaLbU2q.js +68 -0
  92. package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-DXBOtWNI.js → icons-vendor-TPUT2IUt.js} +1 -1
  93. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-Cmlx8OYH.css +1 -0
  94. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-ZJFXmK7m.js +2 -0
  95. package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-DaNXQPyk.js → react-vendor-Ct48XHGL.js} +1 -1
  96. package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-I4AKqVDX.js → traceability-BDe4_Ubl.js} +1 -1
  97. package/templates/.agents/dashboard/apps/frontend/dist/index.html +6 -6
  98. package/templates/.agents/dashboard/apps/frontend/src/App.tsx +73 -67
  99. package/templates/.agents/dashboard/apps/frontend/src/AppLoadingBoundary.tsx +35 -7
  100. package/templates/.agents/dashboard/apps/frontend/src/AppWorkBoard.ts +55 -0
  101. package/templates/.agents/dashboard/apps/frontend/src/ProjectStackEditor.tsx +11 -0
  102. package/templates/.agents/dashboard/apps/frontend/src/app-loading-boundary.css +98 -0
  103. package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +5 -5
  104. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api-reconciliation.ts +33 -0
  105. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +75 -0
  106. package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +7 -8
  107. package/templates/.agents/dashboard/apps/frontend/src/project-settings-model.ts +14 -2
  108. package/templates/.agents/dashboard/apps/frontend/src/project-settings.test.ts +35 -0
  109. package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +78 -2
  110. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.test.ts +28 -0
  111. package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.ts +8 -5
  112. package/templates/.agents/dashboard/apps/frontend/src/use-app-effects.ts +180 -1
  113. package/templates/.agents/dashboard/modules/cost-monitor/src/contracts.ts +7 -4
  114. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorContent.tsx +13 -7
  115. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +14 -0
  116. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableDisplay.ts +211 -0
  117. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +152 -157
  118. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.tsx +155 -142
  119. package/templates/.agents/dashboard/modules/cost-monitor/src/react/InvocationManifestQuery.test.ts +145 -0
  120. package/templates/.agents/dashboard/modules/cost-monitor/src/react/period-cost-groups.ts +7 -5
  121. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-compact-cost-page.ts +4 -1
  122. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.ts +4 -1
  123. package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-run-page.ts +4 -1
  124. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.ts +4 -4
  125. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +79 -1
  126. package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +105 -11
  127. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +482 -332
  128. package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +430 -285
  129. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-runtime.mjs +14 -2
  130. package/templates/.agents/dashboard/packages/local-runtime/scripts/rebuild-sqlite-read-model.mjs +6 -26
  131. package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-sqlite-read-model.mjs +1 -1
  132. package/templates/.agents/dashboard/packages/local-runtime/scripts/verify-persistent-launch.mjs +268 -0
  133. package/templates/.agents/dashboard/packages/local-runtime/server.mjs +482 -332
  134. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.test.ts +90 -1
  135. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.ts +112 -22
  136. package/templates/.agents/dashboard/packages/local-runtime/src/server-agent-assets.ts +39 -0
  137. package/templates/.agents/dashboard/packages/local-runtime/src/server-browser-lease.ts +33 -0
  138. package/templates/.agents/dashboard/packages/local-runtime/src/server-reconciliation-refresh.test.ts +148 -11
  139. package/templates/.agents/dashboard/packages/local-runtime/src/server-reconciliation-result.test.ts +68 -0
  140. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-refresh.test.ts +19 -0
  141. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-refresh.ts +39 -43
  142. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-revision.test.ts +42 -0
  143. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-revision.ts +26 -0
  144. package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-synchronization.ts +34 -0
  145. package/templates/.agents/dashboard/packages/local-runtime/src/server-startup.ts +30 -0
  146. package/templates/.agents/dashboard/packages/local-runtime/src/server-work-reconciliation.test.ts +89 -0
  147. package/templates/.agents/dashboard/packages/local-runtime/src/server-work-reconciliation.ts +88 -0
  148. package/templates/.agents/dashboard/packages/local-runtime/src/server-workspace.ts +68 -7
  149. package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +11 -5
  150. package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +129 -99
  151. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-agent-productivity.test.ts +111 -0
  152. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-agent-productivity.ts +140 -0
  153. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.test.ts +127 -4
  154. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.ts +145 -5
  155. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-aggregates.ts +156 -23
  156. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-projection.ts +18 -9
  157. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-projection.ts +52 -0
  158. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-persistence.ts +35 -13
  159. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-force-canonical.test.ts +56 -0
  160. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-incremental-cache.test.ts +29 -0
  161. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-incremental-cache.ts +136 -0
  162. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-incremental-refresh.test.ts +251 -0
  163. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-projection.ts +22 -7
  164. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-cache.test-support.ts +1 -1
  165. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-canonical-parsing.ts +42 -0
  166. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-canonical.ts +793 -0
  167. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider-duration.test.ts +270 -0
  168. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider-fixture.ts +3 -2
  169. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider.test.ts +18 -4
  170. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.test.ts +87 -0
  171. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.ts +105 -16
  172. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +131 -59
  173. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +1000 -1115
  174. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-cache.ts +13 -92
  175. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-claims.test.mjs +79 -0
  176. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.mjs +27 -0
  177. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-lifecycle.mjs +6 -6
  178. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-prerequisites.mjs +1 -1
  179. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-refresh.mjs +2 -10
  180. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-server.mjs +142 -0
  181. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +231 -239
  182. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +18 -29
  183. package/templates/.agents/dashboard/packages/windows-launcher/Program.cs +6 -0
  184. package/templates/.agents/dashboard/zaip-dashboard-windows.exe +0 -0
  185. package/templates/.agents/requirements/autonomous-assurance.md +1 -1
  186. package/templates/.agents/requirements/cloud-hostinger-autonomy.md +47 -0
  187. package/templates/.agents/requirements/comparative-audit.md +1 -1
  188. package/templates/.agents/requirements/context-engine.md +1 -1
  189. package/templates/.agents/requirements/cost-observability.md +1 -1
  190. package/templates/.agents/requirements/dashboard-launch.md +2 -2
  191. package/templates/.agents/requirements/data-export.md +1 -1
  192. package/templates/.agents/requirements/design-system.md +1 -1
  193. package/templates/.agents/requirements/execution-engine.md +1 -1
  194. package/templates/.agents/requirements/kanban-dashboard.md +1 -1
  195. package/templates/.agents/requirements/model-orchestration.md +1 -1
  196. package/templates/.agents/requirements/public-distribution.md +1 -1
  197. package/templates/.agents/requirements/software-architecture.md +1 -1
  198. package/templates/.agents/requirements/strategic-improvements.md +1 -1
  199. package/templates/.agents/requirements/work-lifecycle.md +1 -1
  200. package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
  201. package/templates/.agents/rules/autonomy-decision.md +1 -1
  202. package/templates/.agents/rules/cloud-hostinger-autonomy.md +21 -0
  203. package/templates/.agents/rules/core.md +5 -4
  204. package/templates/.agents/rules/local-sqlite-storage.md +18 -0
  205. package/templates/.agents/rules/meta-mcp.md +21 -0
  206. package/templates/.agents/rules/workflow.md +1 -0
  207. package/templates/.agents/runtime/bin/zaip.mjs +305 -137
  208. package/templates/.agents/runtime/checksums.sha256 +2 -2
  209. package/templates/.agents/runtime/provenance.json +2 -2
  210. package/templates/.agents/skills/zaip-skill-api-to-mcp/SKILL.md +4 -0
  211. package/templates/.agents/skills/zaip-skill-brand-governance/SKILL.md +25 -9
  212. package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-framework.md +2 -2
  213. package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-standards.md +2 -2
  214. package/templates/.agents/skills/zaip-skill-change/references/observable-evidence.md +15 -0
  215. package/templates/.agents/skills/zaip-skill-dashboard-sqlite/SKILL.md +13 -5
  216. package/templates/.agents/skills/zaip-skill-data-analyst/SKILL.md +10 -5
  217. package/templates/.agents/skills/zaip-skill-execution/SKILL.md +5 -4
  218. package/templates/.agents/skills/zaip-skill-frontend-launcher/SKILL.md +4 -3
  219. package/templates/.agents/skills/zaip-skill-frontend-launcher/references/launcher-contract.md +5 -3
  220. package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +5 -5
  221. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/preflight.mjs +78 -13
  222. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/preflight.test.mjs +59 -0
  223. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/yaml-parser.mjs +157 -0
  224. package/templates/.agents/skills/zaip-skill-growth-strategy-revops/SKILL.md +11 -6
  225. package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/SKILL.md +17 -0
  226. package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/agents/openai.yaml +7 -0
  227. package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/references/autonomous-cloud-inputs.example.json +41 -0
  228. package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/references/autonomous-runner.md +84 -0
  229. package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/references/operational-contract.md +19 -0
  230. package/templates/.agents/skills/zaip-skill-local-credentials/SKILL.md +43 -0
  231. package/templates/.agents/skills/zaip-skill-local-credentials/agents/openai.yaml +6 -0
  232. package/templates/.agents/skills/zaip-skill-local-credentials/references/dotenv-resolution.md +47 -0
  233. package/templates/.agents/skills/zaip-skill-marketing/SKILL.md +8 -3
  234. package/templates/.agents/skills/zaip-skill-meta-ads/SKILL.md +16 -0
  235. package/templates/.agents/skills/zaip-skill-meta-ads/agents/openai.yaml +4 -0
  236. package/templates/.agents/skills/zaip-skill-meta-ads/references/setup.md +3 -0
  237. package/templates/.agents/skills/zaip-skill-meta-ads-setup/SKILL.md +24 -0
  238. package/templates/.agents/skills/zaip-skill-meta-ads-setup/agents/openai.yaml +4 -0
  239. package/templates/.agents/skills/zaip-skill-meta-ads-setup/references/diagnostics.md +13 -0
  240. package/templates/.agents/skills/zaip-skill-meta-ads-setup/references/official-sources.md +10 -0
  241. package/templates/.agents/skills/zaip-skill-meta-devtools-api-health/SKILL.md +12 -0
  242. package/templates/.agents/skills/zaip-skill-meta-devtools-api-health/agents/openai.yaml +4 -0
  243. package/templates/.agents/skills/zaip-skill-meta-devtools-api-health/references/LICENSE +21 -0
  244. package/templates/.agents/skills/zaip-skill-meta-devtools-api-health/references/upstream.md +77 -0
  245. package/templates/.agents/skills/zaip-skill-meta-devtools-api-integration/SKILL.md +12 -0
  246. package/templates/.agents/skills/zaip-skill-meta-devtools-api-integration/agents/openai.yaml +4 -0
  247. package/templates/.agents/skills/zaip-skill-meta-devtools-api-integration/references/LICENSE +21 -0
  248. package/templates/.agents/skills/zaip-skill-meta-devtools-api-integration/references/upstream.md +126 -0
  249. package/templates/.agents/skills/zaip-skill-meta-devtools-app-health-check/SKILL.md +12 -0
  250. package/templates/.agents/skills/zaip-skill-meta-devtools-app-health-check/agents/openai.yaml +4 -0
  251. package/templates/.agents/skills/zaip-skill-meta-devtools-app-health-check/references/LICENSE +21 -0
  252. package/templates/.agents/skills/zaip-skill-meta-devtools-app-health-check/references/upstream.md +67 -0
  253. package/templates/.agents/skills/zaip-skill-meta-devtools-app-review-prep/SKILL.md +12 -0
  254. package/templates/.agents/skills/zaip-skill-meta-devtools-app-review-prep/agents/openai.yaml +4 -0
  255. package/templates/.agents/skills/zaip-skill-meta-devtools-app-review-prep/references/LICENSE +21 -0
  256. package/templates/.agents/skills/zaip-skill-meta-devtools-app-review-prep/references/upstream.md +69 -0
  257. package/templates/.agents/skills/zaip-skill-meta-devtools-compliance-check/SKILL.md +12 -0
  258. package/templates/.agents/skills/zaip-skill-meta-devtools-compliance-check/agents/openai.yaml +4 -0
  259. package/templates/.agents/skills/zaip-skill-meta-devtools-compliance-check/references/LICENSE +21 -0
  260. package/templates/.agents/skills/zaip-skill-meta-devtools-compliance-check/references/upstream.md +79 -0
  261. package/templates/.agents/skills/zaip-skill-meta-devtools-debug-access-token/SKILL.md +14 -0
  262. package/templates/.agents/skills/zaip-skill-meta-devtools-debug-access-token/agents/openai.yaml +4 -0
  263. package/templates/.agents/skills/zaip-skill-meta-devtools-debug-access-token/references/LICENSE +21 -0
  264. package/templates/.agents/skills/zaip-skill-meta-devtools-debug-access-token/references/upstream.md +144 -0
  265. package/templates/.agents/skills/zaip-skill-meta-devtools-debug-webhooks/SKILL.md +12 -0
  266. package/templates/.agents/skills/zaip-skill-meta-devtools-debug-webhooks/agents/openai.yaml +4 -0
  267. package/templates/.agents/skills/zaip-skill-meta-devtools-debug-webhooks/references/LICENSE +21 -0
  268. package/templates/.agents/skills/zaip-skill-meta-devtools-debug-webhooks/references/upstream.md +83 -0
  269. package/templates/.agents/skills/zaip-skill-meta-devtools-search-docs/SKILL.md +10 -0
  270. package/templates/.agents/skills/zaip-skill-meta-devtools-search-docs/agents/openai.yaml +4 -0
  271. package/templates/.agents/skills/zaip-skill-meta-devtools-search-docs/references/LICENSE +21 -0
  272. package/templates/.agents/skills/zaip-skill-meta-devtools-search-docs/references/setup.md +11 -0
  273. package/templates/.agents/skills/zaip-skill-meta-devtools-search-docs/references/upstream.md +55 -0
  274. package/templates/.agents/skills/zaip-skill-meta-devtools-webhook-setup/SKILL.md +12 -0
  275. package/templates/.agents/skills/zaip-skill-meta-devtools-webhook-setup/agents/openai.yaml +4 -0
  276. package/templates/.agents/skills/zaip-skill-meta-devtools-webhook-setup/references/LICENSE +21 -0
  277. package/templates/.agents/skills/zaip-skill-meta-devtools-webhook-setup/references/upstream.md +56 -0
  278. package/templates/.agents/skills/zaip-skill-sales-methodology/SKILL.md +12 -7
  279. package/templates/.agents/skills/zaip-skill-sqlite-read-model/SKILL.md +11 -4
  280. package/templates/.agents/skills/zaip-skill-tool-setup/SKILL.md +6 -4
  281. package/templates/.agents/skills/zaip-skill-tool-setup/references/codex-config.md +4 -2
  282. package/templates/.agents/skills/zaip-skill-tool-setup/references/secrets.md +1 -0
  283. package/templates/.agents/tools/catalog.yaml +6 -0
  284. package/templates/.agents/tools/cloud-runner-dns.mjs +28 -0
  285. package/templates/.agents/tools/cloud-runner-terraform.mjs +212 -0
  286. package/templates/.agents/tools/cloud-runner.integration.test.mjs +239 -0
  287. package/templates/.agents/tools/cloud-runner.mjs +786 -0
  288. package/templates/.agents/tools/cloud-runner.test.mjs +534 -0
  289. package/templates/.agents/tools/cloud-terraform-plan-policy.mjs +262 -0
  290. package/templates/.agents/tools/mcp/development/meta-devtools/README.md +14 -0
  291. package/templates/.agents/tools/mcp/development/meta-devtools/manifest.yaml +28 -0
  292. package/templates/.agents/tools/mcp/infra/cloudflare/manifest.yaml +2 -3
  293. package/templates/.agents/tools/mcp/infra/hostinger/manifest.yaml +1 -3
  294. package/templates/.agents/tools/mcp/marketing/meta-ads/README.md +15 -13
  295. package/templates/.agents/tools/mcp/marketing/meta-ads/manifest.yaml +15 -10
  296. package/templates/.agents/tools/profiles/development.yaml +3 -0
  297. package/templates/infra/terraform/.terraform.lock.hcl +42 -0
  298. package/templates/infra/terraform/README.md +31 -0
  299. package/templates/infra/terraform/backend.tf.json +13 -0
  300. package/templates/infra/terraform/deployment-inputs.example.yaml +22 -0
  301. package/templates/infra/terraform/fixtures/approved-targets.json +32 -0
  302. package/templates/infra/terraform/fixtures/plan-approved.json +67 -0
  303. package/templates/infra/terraform/main.tf +77 -0
  304. package/templates/infra/terraform/outputs.tf +20 -0
  305. package/templates/infra/terraform/terraform.tfvars.example +26 -0
  306. package/templates/infra/terraform/variables.tf +91 -0
  307. package/templates/infra/terraform/versions.tf +18 -0
  308. package/templates/scripts/validate-cloud-hostinger-contract.mjs +89 -0
  309. package/templates/scripts/validate-cloud-terraform-plan.mjs +1 -0
  310. package/templates/template-manifest.json +599 -167
  311. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-BwnJpl02.js +0 -3
  312. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-C09KmlSw.js +0 -68
  313. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-Dyo_wpL4.js +0 -2
  314. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-hPPfVGQv.css +0 -1
  315. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-stale-seed.ts +0 -50
@@ -0,0 +1,534 @@
1
+ import assert from "node:assert/strict";
2
+ import { spawnSync } from "node:child_process";
3
+ import { createHash } from "node:crypto";
4
+ import { relative, resolve } from "node:path";
5
+ import test from "node:test";
6
+ import { execute, run } from "./cloud-runner.mjs";
7
+
8
+ const root = resolve(import.meta.dirname, "../..");
9
+ const path = ".agents/config/autonomous-cloud-contract.json";
10
+ const digest = (value) => createHash("sha256").update(value).digest("hex");
11
+ const operation = (name, extra = {}) => ({
12
+ contract: path,
13
+ operation: name,
14
+ credentialsSource: "root",
15
+ ...extra,
16
+ });
17
+ const cf = (name) =>
18
+ operation(name, {
19
+ provider: "cloudflare",
20
+ accountId: "cf",
21
+ zoneId: "zone",
22
+ dnsRecord: "probe.example.com",
23
+ });
24
+ const tf = () => operation("terraform:plan", { terraformDirectory: "infra/terraform" });
25
+
26
+ // Every file is virtual. Tests never touch .env, SSH material, or real saved plans.
27
+ function fixture() {
28
+ const calls = [],
29
+ files = new Map();
30
+ const backend = {
31
+ type: "s3",
32
+ config: {
33
+ bucket: "approved-state",
34
+ key: "test/terraform.tfstate",
35
+ region: "us-east-1",
36
+ encrypt: true,
37
+ use_lockfile: true,
38
+ },
39
+ };
40
+ const contract = {
41
+ version: 1,
42
+ profile: "autonomous-cloud",
43
+ authorization: { standing: true, reference: "TASK-TEST" },
44
+ cloudflare: {
45
+ account_id: "cf",
46
+ zone_id: "zone",
47
+ zone_name: "example.com",
48
+ dns_records: ["api.example.com"],
49
+ direct_dns_records: {
50
+ "probe.example.com": {
51
+ name: "probe.example.com",
52
+ type: "A",
53
+ content: "198.51.100.7",
54
+ proxied: true,
55
+ ttl: 1,
56
+ },
57
+ },
58
+ allowed_operations: ["cloudflare:dns:read", "cloudflare:dns:create", "cloudflare:dns:edit"],
59
+ },
60
+ hostinger: {
61
+ account_id: "hs",
62
+ allowed_operations: [
63
+ "hostinger:vps:read",
64
+ "hostinger:ssh:read",
65
+ "hostinger:ssh:test",
66
+ "hostinger:ssh:configure",
67
+ ],
68
+ vps: {
69
+ edge: {
70
+ id: "101",
71
+ ssh_host: "198.51.100.7",
72
+ host_key_sha256: "SHA256:cJ6AyISHokEeHuTfufIqhhSS0gxHZRUMDHlKvXD4FHw",
73
+ ssh_user: "zaip",
74
+ private_key_path: ".local/test-key",
75
+ known_hosts_path: ".local/test-known",
76
+ },
77
+ application: { id: "102", ssh_host: "198.51.100.8" },
78
+ },
79
+ },
80
+ terraform: {
81
+ binary_path: ".local/test-terraform",
82
+ binary_sha256: digest("trusted-binary"),
83
+ working_directory: "infra/terraform",
84
+ allowed_operations: ["terraform:plan", "terraform:apply", "terraform:import"],
85
+ import_targets: { "hostinger_vps.edge[0]": "101" },
86
+ plan: {
87
+ backend,
88
+ path: ".local/cloud/plans/test.tfplan",
89
+ policy_json_path: ".local/cloud/plans/test.json",
90
+ policy_contract_path: ".agents/config/test-policy.json",
91
+ },
92
+ },
93
+ };
94
+ const env = {
95
+ ZAIP_CLOUD_PROFILE: "autonomous-cloud",
96
+ CLOUDFLARE_API_TOKEN: "cf-token",
97
+ HOSTINGER_API_TOKEN: "hs-token",
98
+ TF_VAR_cloudflare_account_id: "cf",
99
+ TF_VAR_cloudflare_zone_id: "zone",
100
+ TF_VAR_cloudflare_zone_name: "example.com",
101
+ ZAIP_HOSTINGER_ACCOUNT_ID: "hs",
102
+ TF_VAR_edge_vps_id: "101",
103
+ TF_VAR_application_vps_id: "102",
104
+ TF_VAR_edge_vps_ipv4: "198.51.100.7",
105
+ TF_VAR_application_vps_ipv4: "198.51.100.8",
106
+ ZAIP_EDGE_SSH_HOSTKEY_SHA256: "SHA256:cJ6AyISHokEeHuTfufIqhhSS0gxHZRUMDHlKvXD4FHw",
107
+ ZAIP_APPLICATION_SSH_HOSTKEY_SHA256: "SHA256:app",
108
+ ZAIP_CLOUD_SSH_PRIVATE_KEY_PATH: ".local/test-key",
109
+ AWS_ACCESS_KEY_ID: "state-key",
110
+ AWS_SECRET_ACCESS_KEY: "state-secret",
111
+ UNRELATED_SECRET: "never-pass",
112
+ };
113
+ const save = () => {
114
+ files.set(path, JSON.stringify(contract));
115
+ files.set(
116
+ ".env",
117
+ Object.entries(env)
118
+ .map(([key, value]) => `${key}=${value}`)
119
+ .join("\n"),
120
+ );
121
+ };
122
+ save();
123
+ files.set(".agents/config/autonomous-cloud-inputs.json", JSON.stringify(contract));
124
+ files.set(
125
+ "infra/terraform/backend.tf.json",
126
+ JSON.stringify({ terraform: { backend: { s3: backend.config } } }),
127
+ );
128
+ files.set("infra/terraform/.terraform.lock.hcl", "reviewed-lock");
129
+ files.set(".local/test-terraform", "trusted-binary");
130
+ files.set(
131
+ contract.terraform.plan.policy_contract_path,
132
+ JSON.stringify({
133
+ cloudflare: {
134
+ account_id: "cf",
135
+ zone_id: "zone",
136
+ zone_name: "example.com",
137
+ edge_ipv4: "198.51.100.7",
138
+ dns_records: { api: { type: "A", content: "198.51.100.7", proxied: true } },
139
+ },
140
+ hostinger: { edge: { id: "101" }, application: { id: "102", ipv4: "198.51.100.8" } },
141
+ }),
142
+ );
143
+ files.set(".local/test-key", "not-a-real-key");
144
+ files.set(".local/test-known", "not-a-real-host");
145
+ const state = {
146
+ values: {
147
+ root_module: {
148
+ resources: ["edge", "application"].map((role) => ({
149
+ address: `hostinger_vps.${role}[0]`,
150
+ type: "hostinger_vps",
151
+ mode: "managed",
152
+ values: {
153
+ id: contract.hostinger.vps[role].id,
154
+ ipv4_address: contract.hostinger.vps[role].ssh_host,
155
+ },
156
+ })),
157
+ },
158
+ },
159
+ };
160
+ let records = [],
161
+ planMade = false,
162
+ applied = false;
163
+ const key = (value) => relative(root, value).replaceAll("\\", "/");
164
+ const get = (value) => {
165
+ const name = key(value);
166
+ if (!files.has(name)) throw Object.assign(new Error("missing fixture"), { code: "ENOENT" });
167
+ return files.get(name);
168
+ };
169
+ const response = (body) => ({ ok: true, json: async () => body });
170
+ const deps = {
171
+ access: async (value) => {
172
+ get(value);
173
+ },
174
+ mkdir: async () => {},
175
+ realpath: async (value) => value,
176
+ readFile: async (value) => get(value),
177
+ writeFile: async (value, content) => {
178
+ calls.push({ write: key(value) });
179
+ files.set(key(value), content);
180
+ },
181
+ http: async (url, options) => {
182
+ calls.push({ url, method: options.method, body: options.body });
183
+ assert.equal(options.redirect, "error");
184
+ if (url.endsWith("/zones/zone"))
185
+ return response({
186
+ success: true,
187
+ result: { id: "zone", name: "example.com", account: { id: "cf" } },
188
+ });
189
+ const id = /virtual-machines\/(101|102)$/.exec(url)?.[1];
190
+ if (id)
191
+ return response({
192
+ id: Number(id),
193
+ ipv4: [{ address: id === "101" ? "198.51.100.7" : "198.51.100.8" }],
194
+ });
195
+ if (url.includes("dns_records?name=")) return response({ success: true, result: records });
196
+ if (url.endsWith("/dns_records") && options.method === "POST") {
197
+ records = [{ id: "dns-id", ...JSON.parse(options.body) }];
198
+ return response({ success: true, result: records[0] });
199
+ }
200
+ throw new Error(`Unexpected fixture HTTP route: ${url}`);
201
+ },
202
+ exec: async (file, args, options) => {
203
+ calls.push({ file, args, options });
204
+ if (file === "ssh-keygen")
205
+ return {
206
+ code: 0,
207
+ stdout: args.includes("-F")
208
+ ? "198.51.100.7 ssh-ed25519 AAAA"
209
+ : "256 SHA256:cJ6AyISHokEeHuTfufIqhhSS0gxHZRUMDHlKvXD4FHw host (ED25519)",
210
+ };
211
+ if (file === "ssh") return { code: 0, stdout: "Linux\n" };
212
+ if (file === process.execPath) {
213
+ assert.ok(planMade);
214
+ return { code: 0, stdout: "policy accepted" };
215
+ }
216
+ switch (args[0]) {
217
+ case "init":
218
+ files.set(
219
+ "infra/terraform/.terraform/terraform.tfstate",
220
+ JSON.stringify({ backend: { type: "s3", config: backend.config } }),
221
+ );
222
+ break;
223
+ case "fmt":
224
+ case "validate":
225
+ break;
226
+ case "plan":
227
+ planMade = true;
228
+ files.set(contract.terraform.plan.path, Buffer.from("reviewed-plan"));
229
+ break;
230
+ case "show":
231
+ assert.ok(planMade);
232
+ return {
233
+ code: 0,
234
+ stdout:
235
+ args.length === 2
236
+ ? (assert.ok(applied), JSON.stringify(state))
237
+ : JSON.stringify({ resource_changes: [] }),
238
+ };
239
+ case "apply":
240
+ assert.ok(planMade);
241
+ assert.equal(args.at(-1), resolve(root, contract.terraform.plan.path));
242
+ applied = true;
243
+ break;
244
+ case "import":
245
+ break;
246
+ default:
247
+ throw new Error(`Unexpected fixture command: ${args[0]}`);
248
+ }
249
+ return { code: 0, stdout: "" };
250
+ },
251
+ };
252
+ return {
253
+ deps,
254
+ contract,
255
+ env,
256
+ files,
257
+ calls,
258
+ save,
259
+ setRecords: (value) => {
260
+ records = value;
261
+ },
262
+ };
263
+ }
264
+
265
+ test("derive observes target identity and writes a complete secret-free contract", async () => {
266
+ const f = fixture();
267
+ const result = await run({ operation: "contract:derive", credentialsSource: "root" }, f.deps);
268
+ assert.equal(result.contract_path, path);
269
+ assert.equal(JSON.parse(f.files.get(path)).hostinger.vps.edge.id, "101");
270
+ assert.equal(f.calls.filter((call) => call.url).length, 3);
271
+ assert.ok(!f.files.get(path).includes("cf-token"));
272
+ });
273
+
274
+ test("DNS writes use exact names and read-after-write, rejecting ambiguity", async () => {
275
+ const f = fixture();
276
+ await run(cf("cloudflare:dns:create"), f.deps);
277
+ assert.deepEqual(
278
+ JSON.parse(f.calls.find((call) => call.method === "POST").body),
279
+ f.contract.cloudflare.direct_dns_records["probe.example.com"],
280
+ );
281
+ f.contract.cloudflare.direct_dns_records["probe.example.com"].name = "elsewhere.example.com";
282
+ f.save();
283
+ await assert.rejects(run(cf("cloudflare:dns:edit"), f.deps), /target_mismatch/);
284
+ f.setRecords([
285
+ { id: "one", name: "probe.example.com" },
286
+ { id: "two", name: "probe.example.com" },
287
+ ]);
288
+ await assert.rejects(run(cf("cloudflare:dns:read"), f.deps), /ambiguous_dns_record/);
289
+ });
290
+
291
+ test("SSH read needs no provider token and rejects additional unpinned keys", async () => {
292
+ const f = fixture();
293
+ delete f.env.HOSTINGER_API_TOKEN;
294
+ f.save();
295
+ const args = operation("hostinger:ssh:read", {
296
+ provider: "hostinger",
297
+ accountId: "hs",
298
+ vpsRole: "edge",
299
+ vpsId: "101",
300
+ hostKeySha256: "SHA256:cJ6AyISHokEeHuTfufIqhhSS0gxHZRUMDHlKvXD4FHw",
301
+ });
302
+ await run(args, f.deps);
303
+ const ssh = f.calls.find((call) => call.file === "ssh");
304
+ assert.equal(ssh.args.at(-1), "uname -s");
305
+ assert.equal(ssh.options.input, undefined);
306
+ assert.ok(ssh.args.includes("GlobalKnownHostsFile=none"));
307
+ assert.ok(ssh.args.includes("-F"));
308
+ const exec = f.deps.exec;
309
+ f.deps.exec = async (file, args, opts) =>
310
+ file === "ssh-keygen"
311
+ ? { code: 0, stdout: "198.51.100.7 ssh-ed25519 AAAA\n198.51.100.7 ssh-ed25519 BBBB" }
312
+ : exec(file, args, opts);
313
+ await assert.rejects(run(args, f.deps), /host_key_mismatch/);
314
+ });
315
+
316
+ test("first SSH connection writes only the key matching the preauthorized fingerprint", async () => {
317
+ const f = fixture();
318
+ f.files.delete(".local/test-known");
319
+ const exec = f.deps.exec;
320
+ f.deps.exec = async (file, args, opts) =>
321
+ file === "ssh-keyscan"
322
+ ? { code: 0, stdout: "198.51.100.7 ssh-ed25519 AAAA\n198.51.100.7 ssh-rsa BBBB" }
323
+ : exec(file, args, opts);
324
+ await run(
325
+ operation("hostinger:ssh:test", {
326
+ provider: "hostinger",
327
+ accountId: "hs",
328
+ vpsRole: "edge",
329
+ vpsId: "101",
330
+ hostKeySha256: f.contract.hostinger.vps.edge.host_key_sha256,
331
+ }),
332
+ f.deps,
333
+ );
334
+ assert.equal(f.files.get(".local/test-known"), "198.51.100.7 ssh-ed25519 AAAA\n");
335
+ });
336
+
337
+ test("creation rechecks catalog quote and aggregate budget before provisioning", async () => {
338
+ const f = fixture();
339
+ f.contract.authorization.max_cost = 50;
340
+ f.contract.authorization.currency = "USD";
341
+ const quote = {
342
+ catalog_item_id: "item",
343
+ price_id: "sku",
344
+ currency: "USD",
345
+ price_cents: 2000,
346
+ first_period_price_cents: 1800,
347
+ period: 1,
348
+ period_unit: "month",
349
+ };
350
+ for (const role of ["edge", "application"]) {
351
+ delete f.env[`TF_VAR_${role}_vps_id`];
352
+ f.contract.hostinger.vps[role] = { creation: { plan: "sku", quote } };
353
+ }
354
+ f.save();
355
+ f.files.set(".agents/config/autonomous-cloud-inputs.json", JSON.stringify(f.contract));
356
+ const http = f.deps.http;
357
+ f.deps.http = async (url, options) =>
358
+ url.endsWith("/virtual-machines")
359
+ ? { ok: true, json: async () => [] }
360
+ : url.includes("/billing/v1/catalog")
361
+ ? {
362
+ ok: true,
363
+ json: async () => [
364
+ {
365
+ id: "item",
366
+ prices: [
367
+ {
368
+ id: "sku",
369
+ currency: "USD",
370
+ price: 2000,
371
+ first_period_price: 1800,
372
+ period: 1,
373
+ period_unit: "month",
374
+ },
375
+ ],
376
+ },
377
+ ],
378
+ }
379
+ : http(url, options);
380
+ await run({ operation: "contract:derive", credentialsSource: "root" }, f.deps);
381
+ f.contract.authorization.max_cost = 39;
382
+ f.files.set(".agents/config/autonomous-cloud-inputs.json", JSON.stringify(f.contract));
383
+ await assert.rejects(
384
+ run({ operation: "contract:derive", credentialsSource: "root" }, f.deps),
385
+ /budget_exceeded/,
386
+ );
387
+ });
388
+
389
+ test("Terraform refuses changed binary and missing selected backend credential", async () => {
390
+ const f = fixture();
391
+ f.files.set(".local/test-terraform", "changed");
392
+ await assert.rejects(run(tf(), f.deps), /terraform_binary_mismatch/);
393
+ delete f.env.AWS_SECRET_ACCESS_KEY;
394
+ f.save();
395
+ await assert.rejects(run(tf(), f.deps), /backend_credential_unavailable/);
396
+ assert.ok(!f.calls.some((call) => call.args?.[0] === "init"));
397
+ });
398
+
399
+ test("Terraform checks actual backend, minimal env, exact receipt and observed resources", async () => {
400
+ const f = fixture();
401
+ const result = await run(tf(), f.deps);
402
+ assert.equal(result.plan_sha256, digest("reviewed-plan"));
403
+ const init = f.calls.find((call) => call.args?.[0] === "init");
404
+ assert.ok(init.args.includes("-lockfile=readonly"));
405
+ assert.equal(init.options.env.TF_VAR_cloudflare_zone_id, "zone");
406
+ assert.equal(init.options.env.AWS_SECRET_ACCESS_KEY, "state-secret");
407
+ assert.equal(init.options.env.UNRELATED_SECRET, undefined);
408
+ Object.assign(f.contract.terraform.plan, {
409
+ sha256: result.plan_sha256,
410
+ policy_result_sha256: result.policy_result_sha256,
411
+ });
412
+ f.save();
413
+ const args = operation("terraform:apply", {
414
+ planPath: f.contract.terraform.plan.path,
415
+ planSha256: result.plan_sha256,
416
+ policyResultSha256: result.policy_result_sha256,
417
+ });
418
+ assert.deepEqual((await run(args, f.deps)).targets, ["101", "102"]);
419
+ const changed = JSON.parse(f.files.get(f.contract.terraform.plan.policy_contract_path));
420
+ changed.cloudflare.dns_records.api.ttl = 60;
421
+ f.files.set(f.contract.terraform.plan.policy_contract_path, JSON.stringify(changed));
422
+ const count = f.calls.filter((call) => call.args?.[0] === "apply").length;
423
+ await assert.rejects(run(args, f.deps), /terraform_policy_failed/);
424
+ assert.equal(f.calls.filter((call) => call.args?.[0] === "apply").length, count);
425
+ });
426
+
427
+ test("a backend declaration cannot disguise initialized local state", async () => {
428
+ const f = fixture();
429
+ const exec = f.deps.exec;
430
+ f.deps.exec = async (file, args, opts) => {
431
+ const result = await exec(file, args, opts);
432
+ if (args[0] === "init")
433
+ f.files.set(
434
+ "infra/terraform/.terraform/terraform.tfstate",
435
+ JSON.stringify({ backend: { type: "local", config: {} } }),
436
+ );
437
+ return result;
438
+ };
439
+ await assert.rejects(run(tf(), f.deps), /backend_mismatch/);
440
+ assert.ok(!f.calls.some((call) => call.args?.[0] === "plan"));
441
+ });
442
+
443
+ test("R2 backend is scoped to the approved Cloudflare account and enables lockfiles", async () => {
444
+ const f = fixture();
445
+ const config = f.contract.terraform.plan.backend.config;
446
+ delete config.encrypt;
447
+ Object.assign(config, {
448
+ region: "auto",
449
+ endpoints: { s3: "https://cf.r2.cloudflarestorage.com" },
450
+ skip_credentials_validation: true,
451
+ skip_metadata_api_check: true,
452
+ skip_region_validation: true,
453
+ skip_requesting_account_id: true,
454
+ skip_s3_checksum: true,
455
+ use_path_style: true,
456
+ });
457
+ f.files.set(
458
+ "infra/terraform/backend.tf.json",
459
+ JSON.stringify({ terraform: { backend: { s3: config } } }),
460
+ );
461
+ f.save();
462
+ assert.ok((await run(tf(), f.deps)).plan_sha256);
463
+ config.endpoints.s3 = "https://foreign.r2.cloudflarestorage.com";
464
+ f.save();
465
+ await assert.rejects(run(tf(), f.deps), /invalid_backend_config/);
466
+ });
467
+
468
+ test("secondary policy cannot silently approve a different target set", async () => {
469
+ const f = fixture();
470
+ const policy = JSON.parse(f.files.get(f.contract.terraform.plan.policy_contract_path));
471
+ policy.hostinger.edge.id = "foreign";
472
+ f.files.set(f.contract.terraform.plan.policy_contract_path, JSON.stringify(policy));
473
+ await assert.rejects(run(tf(), f.deps), /policy_target_mismatch/);
474
+ assert.ok(!f.calls.some((call) => call.args?.[0] === "init"));
475
+ });
476
+
477
+ test("provider API logical errors stop before mutations", async () => {
478
+ const f = fixture();
479
+ f.deps.http = async () => ({ ok: true, json: async () => ({ success: false }) });
480
+ await assert.rejects(run(cf("cloudflare:dns:create"), f.deps), /provider_request_failed/);
481
+ assert.ok(!f.calls.some((call) => call.method === "POST"));
482
+ });
483
+
484
+ test("a lost DNS mutation response requires observation before a retry", async () => {
485
+ const f = fixture();
486
+ const http = f.deps.http;
487
+ f.deps.http = async (url, options) => {
488
+ const response = await http(url, options);
489
+ if (options.method === "POST") throw new Error("connection lost after server applied");
490
+ return response;
491
+ };
492
+ await assert.rejects(
493
+ run(cf("cloudflare:dns:create"), f.deps),
494
+ /remote_result_requires_reconciliation/,
495
+ );
496
+ assert.ok((await run(cf("cloudflare:dns:read"), f.deps)).targets.includes("dns-id"));
497
+ assert.equal(f.calls.filter((call) => call.method === "POST").length, 1);
498
+ });
499
+
500
+ test("real subprocess preserves large JSON and reports overflow and timeout", async () => {
501
+ const result = await execute(
502
+ process.execPath,
503
+ ["-e", "process.stdout.write(JSON.stringify({data:'x'.repeat(50000)}))"],
504
+ { maxOutput: 60_000 },
505
+ );
506
+ assert.equal(result.code, 0);
507
+ assert.equal(JSON.parse(result.stdout).data.length, 50_000);
508
+ const overflow = await execute(
509
+ process.execPath,
510
+ ["-e", "process.stdout.write('x'.repeat(50000))"],
511
+ { maxOutput: 100 },
512
+ );
513
+ assert.notEqual(overflow.code, 0);
514
+ assert.equal(overflow.overflow, true);
515
+ const timeout = await execute(process.execPath, ["-e", "setInterval(()=>{},1000)"], {
516
+ timeout: 100,
517
+ });
518
+ assert.notEqual(timeout.code, 0);
519
+ assert.equal(timeout.timedOut, true);
520
+ });
521
+
522
+ test("CLI rejects invalid and duplicate arguments with sanitized errors", () => {
523
+ for (const args of [
524
+ ["--operation", "invalid"],
525
+ ["--operation", "contract:derive", "--operation", "invalid"],
526
+ ]) {
527
+ const result = spawnSync(process.execPath, [".agents/tools/cloud-runner.mjs", ...args], {
528
+ cwd: root,
529
+ encoding: "utf8",
530
+ });
531
+ assert.notEqual(result.status, 0);
532
+ assert.deepEqual(JSON.parse(result.stderr), { ok: false, code: "invalid_arguments" });
533
+ }
534
+ });