@zaip-ai/cli 1.3.8 → 1.4.2
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.
- package/README.md +58 -3
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +17 -6
- package/dist/commands/init.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/services/adapters.js +4 -4
- package/dist/services/adapters.js.map +1 -1
- package/dist/services/codex-config-template.d.ts +2 -2
- package/dist/services/codex-config-template.d.ts.map +1 -1
- package/dist/services/codex-config-template.js +3 -3
- package/dist/services/codex-config-template.js.map +1 -1
- package/dist/services/codex-rules.d.ts +1 -1
- package/dist/services/codex-rules.d.ts.map +1 -1
- package/dist/services/codex-rules.js +9 -24
- package/dist/services/codex-rules.js.map +1 -1
- package/dist/services/delivery-git-preflight.d.ts +23 -0
- package/dist/services/delivery-git-preflight.d.ts.map +1 -0
- package/dist/services/delivery-git-preflight.js +69 -0
- package/dist/services/delivery-git-preflight.js.map +1 -0
- package/dist/services/doctor.d.ts.map +1 -1
- package/dist/services/doctor.js +13 -1
- package/dist/services/doctor.js.map +1 -1
- package/dist/services/install-agents-template.d.ts.map +1 -1
- package/dist/services/install-agents-template.js +22 -28
- package/dist/services/install-agents-template.js.map +1 -1
- package/dist/services/install-profile.d.ts +8 -0
- package/dist/services/install-profile.d.ts.map +1 -0
- package/dist/services/install-profile.js +56 -0
- package/dist/services/install-profile.js.map +1 -0
- package/dist/services/logger.d.ts.map +1 -1
- package/dist/services/logger.js +6 -5
- package/dist/services/logger.js.map +1 -1
- package/dist/services/stack-git.d.ts +9 -0
- package/dist/services/stack-git.d.ts.map +1 -0
- package/dist/services/stack-git.js +188 -0
- package/dist/services/stack-git.js.map +1 -0
- package/dist/services/stack-plan.d.ts +3 -1
- package/dist/services/stack-plan.d.ts.map +1 -1
- package/dist/services/stack-plan.js +15 -1
- package/dist/services/stack-plan.js.map +1 -1
- package/dist/services/stack-terraform.d.ts +13 -0
- package/dist/services/stack-terraform.d.ts.map +1 -0
- package/dist/services/stack-terraform.js +274 -0
- package/dist/services/stack-terraform.js.map +1 -0
- package/dist/services/template-manifest.d.ts.map +1 -1
- package/dist/services/template-manifest.js +14 -1
- package/dist/services/template-manifest.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/templates/.agents/.env.example +34 -0
- package/templates/{README.md → .agents/README.md} +124 -60
- package/templates/.agents/config/agents/catalog.yaml +23 -23
- package/templates/.agents/config/clients/codex/agents/zaip-agent-analyst.toml +1 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-auditor.toml +1 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-backend.toml +5 -4
- package/templates/.agents/config/clients/codex/agents/zaip-agent-brand-strategist.toml +1 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-builder.toml +1 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-cloud-engineer.toml +10 -7
- package/templates/.agents/config/clients/codex/agents/zaip-agent-data-analyst.toml +1 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-designer.toml +1 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-finalizer.toml +1 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-frontend.toml +5 -4
- package/templates/.agents/config/clients/codex/agents/zaip-agent-general-operations.toml +1 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-governance-compliance.toml +1 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-growth-strategist.toml +1 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-integrator.toml +1 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-marketing-analyst.toml +5 -4
- package/templates/.agents/config/clients/codex/agents/zaip-agent-orchestrator.toml +1 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-refactoring-specialist.toml +1 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-reviewer.toml +1 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-sales-specialist.toml +1 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-security-auditor.toml +1 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-task-executor.toml +1 -0
- package/templates/.agents/config/clients/codex/agents/zaip-agent-website-developer.toml +5 -4
- package/templates/.agents/config/clients/codex/agents/zaip-agent-writer.toml +1 -0
- package/templates/.agents/config/pricing/models.json +25 -1
- package/templates/.agents/config/project.yaml +2 -0
- package/templates/.agents/dashboard/.zaip-managed.json +208 -88
- package/templates/.agents/dashboard/DATA-DICTIONARY.md +1 -1
- package/templates/.agents/dashboard/README.md +58 -19
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-DwVZOmMV.js → CostCalculationGuidePage-snUCQYTC.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-VcLx9iOO.js → DashboardHelpDialog-oZVlf-l5.js} +72 -8
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-CyjMXkm8.js → PricingSettingsDialog-BPtVUGgs.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-3Awyaovx.js +3 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-DFZwIXSC.js → TraceabilityWorkspace-BYjVOHI_.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-DbaLbU2q.js +68 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-DXBOtWNI.js → icons-vendor-TPUT2IUt.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-Cmlx8OYH.css +1 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-ZJFXmK7m.js +2 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-DaNXQPyk.js → react-vendor-Ct48XHGL.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-I4AKqVDX.js → traceability-BDe4_Ubl.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/index.html +6 -6
- package/templates/.agents/dashboard/apps/frontend/src/App.tsx +73 -67
- package/templates/.agents/dashboard/apps/frontend/src/AppLoadingBoundary.tsx +35 -7
- package/templates/.agents/dashboard/apps/frontend/src/AppWorkBoard.ts +55 -0
- package/templates/.agents/dashboard/apps/frontend/src/ProjectStackEditor.tsx +11 -0
- package/templates/.agents/dashboard/apps/frontend/src/app-loading-boundary.css +98 -0
- package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +5 -5
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-api-reconciliation.ts +33 -0
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +75 -0
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +7 -8
- package/templates/.agents/dashboard/apps/frontend/src/project-settings-model.ts +14 -2
- package/templates/.agents/dashboard/apps/frontend/src/project-settings.test.ts +35 -0
- package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +78 -2
- package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.test.ts +28 -0
- package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.ts +8 -5
- package/templates/.agents/dashboard/apps/frontend/src/use-app-effects.ts +180 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/contracts.ts +7 -4
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorContent.tsx +13 -7
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +14 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableDisplay.ts +211 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +152 -157
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.tsx +155 -142
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/InvocationManifestQuery.test.ts +145 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/period-cost-groups.ts +7 -5
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-compact-cost-page.ts +4 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.ts +4 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-run-page.ts +4 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.ts +4 -4
- package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +79 -1
- package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +105 -11
- package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +482 -332
- package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +430 -285
- package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-runtime.mjs +14 -2
- package/templates/.agents/dashboard/packages/local-runtime/scripts/rebuild-sqlite-read-model.mjs +6 -26
- package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-sqlite-read-model.mjs +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/scripts/verify-persistent-launch.mjs +268 -0
- package/templates/.agents/dashboard/packages/local-runtime/server.mjs +482 -332
- package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.test.ts +90 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.ts +112 -22
- package/templates/.agents/dashboard/packages/local-runtime/src/server-agent-assets.ts +39 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-browser-lease.ts +33 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-reconciliation-refresh.test.ts +148 -11
- package/templates/.agents/dashboard/packages/local-runtime/src/server-reconciliation-result.test.ts +68 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-refresh.test.ts +19 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-refresh.ts +39 -43
- package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-revision.test.ts +42 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-revision.ts +26 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-synchronization.ts +34 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-startup.ts +30 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-work-reconciliation.test.ts +89 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-work-reconciliation.ts +88 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-workspace.ts +68 -7
- package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +11 -5
- package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +129 -99
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-agent-productivity.test.ts +111 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-agent-productivity.ts +140 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.test.ts +127 -4
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.ts +145 -5
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-aggregates.ts +156 -23
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-projection.ts +18 -9
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-projection.ts +52 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-persistence.ts +35 -13
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-force-canonical.test.ts +56 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-incremental-cache.test.ts +29 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-incremental-cache.ts +136 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-incremental-refresh.test.ts +251 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-projection.ts +22 -7
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-cache.test-support.ts +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-canonical-parsing.ts +42 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-canonical.ts +793 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider-duration.test.ts +270 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider-fixture.ts +3 -2
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider.test.ts +18 -4
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.test.ts +87 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.ts +105 -16
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +131 -59
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +1000 -1115
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-cache.ts +13 -92
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-claims.test.mjs +79 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.mjs +27 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-lifecycle.mjs +6 -6
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-prerequisites.mjs +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-refresh.mjs +2 -10
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-runtime-selection.mjs +36 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-runtime-selection.test.mjs +63 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-server.mjs +142 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +262 -267
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +18 -29
- package/templates/.agents/dashboard/packages/windows-launcher/Program.cs +6 -0
- package/templates/.agents/dashboard/zaip-dashboard-windows.exe +0 -0
- package/templates/.agents/requirements/autonomous-assurance.md +1 -1
- package/templates/.agents/requirements/cloud-hostinger-autonomy.md +47 -0
- package/templates/.agents/requirements/comparative-audit.md +1 -1
- package/templates/.agents/requirements/context-engine.md +1 -1
- package/templates/.agents/requirements/cost-observability.md +1 -1
- package/templates/.agents/requirements/dashboard-launch.md +2 -2
- package/templates/.agents/requirements/data-export.md +1 -1
- package/templates/.agents/requirements/design-system.md +1 -1
- package/templates/.agents/requirements/execution-engine.md +1 -1
- package/templates/.agents/requirements/kanban-dashboard.md +1 -1
- package/templates/.agents/requirements/model-orchestration.md +1 -1
- package/templates/.agents/requirements/public-distribution.md +1 -1
- package/templates/.agents/requirements/software-architecture.md +1 -1
- package/templates/.agents/requirements/strategic-improvements.md +1 -1
- package/templates/.agents/requirements/work-lifecycle.md +1 -1
- package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
- package/templates/.agents/rules/autonomy-decision.md +1 -1
- package/templates/.agents/rules/cloud-hostinger-autonomy.md +21 -0
- package/templates/.agents/rules/core.md +5 -4
- package/templates/.agents/rules/local-sqlite-storage.md +18 -0
- package/templates/.agents/rules/meta-mcp.md +21 -0
- package/templates/.agents/rules/workflow.md +1 -0
- package/templates/.agents/runtime/bin/zaip.mjs +305 -137
- package/templates/.agents/runtime/checksums.sha256 +2 -2
- package/templates/.agents/runtime/provenance.json +2 -2
- package/templates/.agents/skills/zaip-skill-api-to-mcp/SKILL.md +4 -0
- package/templates/.agents/skills/zaip-skill-brand-governance/SKILL.md +25 -9
- package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-framework.md +2 -2
- package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-standards.md +2 -2
- package/templates/.agents/skills/zaip-skill-change/references/observable-evidence.md +15 -0
- package/templates/.agents/skills/zaip-skill-dashboard-sqlite/SKILL.md +13 -5
- package/templates/.agents/skills/zaip-skill-data-analyst/SKILL.md +10 -5
- package/templates/.agents/skills/zaip-skill-execution/SKILL.md +5 -4
- package/templates/.agents/skills/zaip-skill-frontend-launcher/SKILL.md +4 -3
- package/templates/.agents/skills/zaip-skill-frontend-launcher/references/launcher-contract.md +5 -3
- package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +5 -5
- package/templates/.agents/skills/zaip-skill-github-deploy/scripts/preflight.mjs +78 -13
- package/templates/.agents/skills/zaip-skill-github-deploy/scripts/preflight.test.mjs +59 -0
- package/templates/.agents/skills/zaip-skill-github-deploy/scripts/yaml-parser.mjs +157 -0
- package/templates/.agents/skills/zaip-skill-growth-strategy-revops/SKILL.md +11 -6
- package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/SKILL.md +17 -0
- package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/agents/openai.yaml +7 -0
- package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/references/autonomous-cloud-inputs.example.json +41 -0
- package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/references/autonomous-runner.md +84 -0
- package/templates/.agents/skills/zaip-skill-hostinger-cloudflare-terraform/references/operational-contract.md +19 -0
- package/templates/.agents/skills/zaip-skill-local-credentials/SKILL.md +43 -0
- package/templates/.agents/skills/zaip-skill-local-credentials/agents/openai.yaml +6 -0
- package/templates/.agents/skills/zaip-skill-local-credentials/references/dotenv-resolution.md +47 -0
- package/templates/.agents/skills/zaip-skill-marketing/SKILL.md +8 -3
- package/templates/.agents/skills/zaip-skill-meta-ads/SKILL.md +16 -0
- package/templates/.agents/skills/zaip-skill-meta-ads/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-meta-ads/references/setup.md +3 -0
- package/templates/.agents/skills/zaip-skill-meta-ads-setup/SKILL.md +24 -0
- package/templates/.agents/skills/zaip-skill-meta-ads-setup/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-meta-ads-setup/references/diagnostics.md +13 -0
- package/templates/.agents/skills/zaip-skill-meta-ads-setup/references/official-sources.md +10 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-api-health/SKILL.md +12 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-api-health/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-api-health/references/LICENSE +21 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-api-health/references/upstream.md +77 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-api-integration/SKILL.md +12 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-api-integration/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-api-integration/references/LICENSE +21 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-api-integration/references/upstream.md +126 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-app-health-check/SKILL.md +12 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-app-health-check/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-app-health-check/references/LICENSE +21 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-app-health-check/references/upstream.md +67 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-app-review-prep/SKILL.md +12 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-app-review-prep/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-app-review-prep/references/LICENSE +21 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-app-review-prep/references/upstream.md +69 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-compliance-check/SKILL.md +12 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-compliance-check/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-compliance-check/references/LICENSE +21 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-compliance-check/references/upstream.md +79 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-debug-access-token/SKILL.md +14 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-debug-access-token/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-debug-access-token/references/LICENSE +21 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-debug-access-token/references/upstream.md +144 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-debug-webhooks/SKILL.md +12 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-debug-webhooks/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-debug-webhooks/references/LICENSE +21 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-debug-webhooks/references/upstream.md +83 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-search-docs/SKILL.md +10 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-search-docs/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-search-docs/references/LICENSE +21 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-search-docs/references/setup.md +11 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-search-docs/references/upstream.md +55 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-webhook-setup/SKILL.md +12 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-webhook-setup/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-webhook-setup/references/LICENSE +21 -0
- package/templates/.agents/skills/zaip-skill-meta-devtools-webhook-setup/references/upstream.md +56 -0
- package/templates/.agents/skills/zaip-skill-sales-methodology/SKILL.md +12 -7
- package/templates/.agents/skills/zaip-skill-sqlite-read-model/SKILL.md +11 -4
- package/templates/.agents/skills/zaip-skill-tool-setup/SKILL.md +6 -4
- package/templates/.agents/skills/zaip-skill-tool-setup/references/codex-config.md +4 -2
- package/templates/.agents/skills/zaip-skill-tool-setup/references/secrets.md +1 -0
- package/templates/.agents/tools/catalog.yaml +6 -0
- package/templates/.agents/tools/cloud-runner-dns.mjs +28 -0
- package/templates/.agents/tools/cloud-runner-terraform.mjs +212 -0
- package/templates/.agents/tools/cloud-runner.integration.test.mjs +239 -0
- package/templates/.agents/tools/cloud-runner.mjs +786 -0
- package/templates/.agents/tools/cloud-runner.test.mjs +534 -0
- package/templates/.agents/tools/cloud-terraform-plan-policy.mjs +262 -0
- package/templates/.agents/tools/mcp/development/meta-devtools/README.md +14 -0
- package/templates/.agents/tools/mcp/development/meta-devtools/manifest.yaml +28 -0
- package/templates/.agents/tools/mcp/infra/cloudflare/manifest.yaml +2 -3
- package/templates/.agents/tools/mcp/infra/hostinger/manifest.yaml +1 -3
- package/templates/.agents/tools/mcp/marketing/meta-ads/README.md +15 -13
- package/templates/.agents/tools/mcp/marketing/meta-ads/manifest.yaml +15 -10
- package/templates/.agents/tools/profiles/development.yaml +3 -0
- package/templates/infra/terraform/.terraform.lock.hcl +42 -0
- package/templates/infra/terraform/README.md +31 -0
- package/templates/infra/terraform/backend.tf.json +13 -0
- package/templates/infra/terraform/deployment-inputs.example.yaml +22 -0
- package/templates/infra/terraform/fixtures/approved-targets.json +32 -0
- package/templates/infra/terraform/fixtures/plan-approved.json +67 -0
- package/templates/infra/terraform/main.tf +77 -0
- package/templates/infra/terraform/outputs.tf +20 -0
- package/templates/infra/terraform/terraform.tfvars.example +26 -0
- package/templates/infra/terraform/variables.tf +91 -0
- package/templates/infra/terraform/versions.tf +18 -0
- package/templates/scripts/validate-cloud-hostinger-contract.mjs +89 -0
- package/templates/scripts/validate-cloud-terraform-plan.mjs +1 -0
- package/templates/template-manifest.json +607 -167
- package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-BwnJpl02.js +0 -3
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-C09KmlSw.js +0 -68
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-Dyo_wpL4.js +0 -2
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-hPPfVGQv.css +0 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-stale-seed.ts +0 -50
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const fields = ["name", "type", "content", "proxied", "ttl", "comment"];
|
|
2
|
+
|
|
3
|
+
export function dnsInventory(scope) {
|
|
4
|
+
return new Set(
|
|
5
|
+
Array.isArray(scope.dns_records) ? scope.dns_records : Object.keys(scope.dns_records ?? {}),
|
|
6
|
+
);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function dnsBody(record, fail) {
|
|
10
|
+
if (!record || typeof record !== "object") fail("invalid_contract");
|
|
11
|
+
const body = {};
|
|
12
|
+
for (const key of fields) if (record[key] !== undefined) body[key] = record[key];
|
|
13
|
+
if (
|
|
14
|
+
typeof body.name !== "string" ||
|
|
15
|
+
typeof body.type !== "string" ||
|
|
16
|
+
typeof body.content !== "string"
|
|
17
|
+
)
|
|
18
|
+
fail("invalid_contract");
|
|
19
|
+
return body;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function sameDns(actual, expected) {
|
|
23
|
+
return fields.every((key) => expected[key] === undefined || actual[key] === expected[key]);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function authHeaders(token) {
|
|
27
|
+
return { Authorization: `Bearer ${token}`, "Content-Type": "application/json" };
|
|
28
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/** Executes the contract-bound Terraform operations used by cloud-runner. */
|
|
2
|
+
export async function runTerraform(args, contract, credentials, toolkit) {
|
|
3
|
+
const { deps, root, dirname, exact, fail, insideRoot, nonempty, requireString, result, sha256 } =
|
|
4
|
+
toolkit;
|
|
5
|
+
const scope = contract.terraform;
|
|
6
|
+
if (
|
|
7
|
+
!scope ||
|
|
8
|
+
!new Set(["terraform:plan", "terraform:apply", "terraform:import"]).has(args.operation) ||
|
|
9
|
+
!scope.allowed_operations?.includes(args.operation)
|
|
10
|
+
)
|
|
11
|
+
fail("operation_not_allowed");
|
|
12
|
+
exact(
|
|
13
|
+
args,
|
|
14
|
+
args.operation === "terraform:plan"
|
|
15
|
+
? ["contract", "operation", "credentials-source", "terraform-directory"]
|
|
16
|
+
: args.operation === "terraform:apply"
|
|
17
|
+
? [
|
|
18
|
+
"contract",
|
|
19
|
+
"operation",
|
|
20
|
+
"credentials-source",
|
|
21
|
+
"plan-path",
|
|
22
|
+
"plan-sha256",
|
|
23
|
+
"policy-result-sha256",
|
|
24
|
+
]
|
|
25
|
+
: ["contract", "operation", "credentials-source", "resource-address", "resource-id"],
|
|
26
|
+
);
|
|
27
|
+
if (
|
|
28
|
+
!credentials.cloudflare ||
|
|
29
|
+
!credentials.hostinger ||
|
|
30
|
+
scope.working_directory !== "infra/terraform"
|
|
31
|
+
)
|
|
32
|
+
fail("credential_unavailable");
|
|
33
|
+
const cwd = insideRoot(scope.working_directory);
|
|
34
|
+
const env = terraformEnvironment(credentials.values, { nonempty, fail });
|
|
35
|
+
const binary = insideRoot(requireString(scope, "binary_path"));
|
|
36
|
+
if (sha256(await deps.readFile(binary)) !== scope.binary_sha256)
|
|
37
|
+
fail("terraform_binary_mismatch");
|
|
38
|
+
await toolkit.preflight(contract, credentials, deps);
|
|
39
|
+
const plan = toolkit.validPlan(scope.plan, contract.cloudflare.account_id);
|
|
40
|
+
await toolkit.verifyPolicyTargets(contract, deps);
|
|
41
|
+
await toolkit.verifyBackendSource(plan, cwd, deps);
|
|
42
|
+
const execOptions = { cwd, env, timeout: 900_000, maxOutput: 32_000_000 };
|
|
43
|
+
if (
|
|
44
|
+
(await deps.exec(binary, ["init", "-input=false", "-lockfile=readonly"], execOptions)).code !==
|
|
45
|
+
0
|
|
46
|
+
)
|
|
47
|
+
fail("terraform_init_failed");
|
|
48
|
+
await toolkit.verifyBackend(plan, cwd, deps);
|
|
49
|
+
if (args.operation === "terraform:plan")
|
|
50
|
+
return planTerraform(args, contract, plan, binary, execOptions, {
|
|
51
|
+
deps,
|
|
52
|
+
root,
|
|
53
|
+
dirname,
|
|
54
|
+
fail,
|
|
55
|
+
insideRoot,
|
|
56
|
+
result,
|
|
57
|
+
sha256,
|
|
58
|
+
receipt: toolkit.receipt,
|
|
59
|
+
});
|
|
60
|
+
if (args.operation === "terraform:apply")
|
|
61
|
+
return applyTerraform(args, contract, credentials, plan, binary, cwd, execOptions, toolkit);
|
|
62
|
+
exact(args, ["contract", "operation", "credentials-source", "resource-address", "resource-id"]);
|
|
63
|
+
if (scope.import_targets?.[args.resourceAddress] !== args.resourceId) fail("target_mismatch");
|
|
64
|
+
if (
|
|
65
|
+
(
|
|
66
|
+
await deps.exec(
|
|
67
|
+
binary,
|
|
68
|
+
["import", "-input=false", args.resourceAddress, args.resourceId],
|
|
69
|
+
execOptions,
|
|
70
|
+
)
|
|
71
|
+
).code !== 0
|
|
72
|
+
)
|
|
73
|
+
fail("remote_result_requires_reconciliation");
|
|
74
|
+
return result(args.operation, "terraform", [args.resourceAddress, args.resourceId]);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function planTerraform(args, contract, plan, binary, execOptions, toolkit) {
|
|
78
|
+
const { deps, root, dirname, fail, insideRoot, result, sha256, receipt } = toolkit;
|
|
79
|
+
if (args.terraformDirectory !== "infra/terraform") fail("target_mismatch");
|
|
80
|
+
const planPath = insideRoot(plan.path),
|
|
81
|
+
policyPath = insideRoot(plan.policy_json_path);
|
|
82
|
+
await deps.mkdir(dirname(planPath), { recursive: true });
|
|
83
|
+
for (const argv of [
|
|
84
|
+
["fmt", "-check"],
|
|
85
|
+
["validate"],
|
|
86
|
+
["plan", "-input=false", "-out", planPath],
|
|
87
|
+
["show", "-json", planPath],
|
|
88
|
+
]) {
|
|
89
|
+
const response = await deps.exec(binary, argv, execOptions);
|
|
90
|
+
if (response.code !== 0) fail("terraform_failed");
|
|
91
|
+
if (argv[0] === "show") await deps.writeFile(policyPath, response.stdout ?? "");
|
|
92
|
+
}
|
|
93
|
+
const policy = await policyCheck(plan, root, deps);
|
|
94
|
+
if (policy.code !== 0) fail("terraform_policy_failed");
|
|
95
|
+
return {
|
|
96
|
+
...result(args.operation, "terraform", plan.targets ?? []),
|
|
97
|
+
plan_sha256: sha256(await deps.readFile(planPath)),
|
|
98
|
+
policy_result_sha256: await receipt(contract, policy.stdout ?? "", deps),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function applyTerraform(
|
|
103
|
+
args,
|
|
104
|
+
contract,
|
|
105
|
+
credentials,
|
|
106
|
+
plan,
|
|
107
|
+
binary,
|
|
108
|
+
cwd,
|
|
109
|
+
execOptions,
|
|
110
|
+
toolkit,
|
|
111
|
+
) {
|
|
112
|
+
const {
|
|
113
|
+
deps,
|
|
114
|
+
root,
|
|
115
|
+
fail,
|
|
116
|
+
exact,
|
|
117
|
+
insideRoot,
|
|
118
|
+
result,
|
|
119
|
+
sha256,
|
|
120
|
+
receipt,
|
|
121
|
+
verifyBackend,
|
|
122
|
+
observeState,
|
|
123
|
+
} = toolkit;
|
|
124
|
+
exact(args, [
|
|
125
|
+
"contract",
|
|
126
|
+
"operation",
|
|
127
|
+
"credentials-source",
|
|
128
|
+
"plan-path",
|
|
129
|
+
"plan-sha256",
|
|
130
|
+
"policy-result-sha256",
|
|
131
|
+
]);
|
|
132
|
+
const planPath = insideRoot(plan.path);
|
|
133
|
+
if (
|
|
134
|
+
args.planPath !== plan.path ||
|
|
135
|
+
args.planSha256 !== plan.sha256 ||
|
|
136
|
+
args.policyResultSha256 !== plan.policy_result_sha256 ||
|
|
137
|
+
sha256(await deps.readFile(planPath)) !== args.planSha256
|
|
138
|
+
)
|
|
139
|
+
fail("target_mismatch");
|
|
140
|
+
const show = await deps.exec(binary, ["show", "-json", planPath], execOptions);
|
|
141
|
+
if (show.code !== 0) fail("terraform_failed");
|
|
142
|
+
await deps.writeFile(insideRoot(plan.policy_json_path), show.stdout ?? "");
|
|
143
|
+
const policy = await policyCheck(plan, root, deps);
|
|
144
|
+
if (
|
|
145
|
+
policy.code !== 0 ||
|
|
146
|
+
(await receipt(contract, policy.stdout ?? "", deps)) !== args.policyResultSha256
|
|
147
|
+
)
|
|
148
|
+
fail("terraform_policy_failed");
|
|
149
|
+
if ((await deps.exec(binary, ["apply", "-input=false", planPath], execOptions)).code !== 0)
|
|
150
|
+
fail("remote_result_requires_reconciliation");
|
|
151
|
+
await verifyBackend(plan, cwd, deps);
|
|
152
|
+
const state = await deps.exec(binary, ["show", "-json"], execOptions);
|
|
153
|
+
if (state.code !== 0) fail("read_after_write_failed");
|
|
154
|
+
const observed = await observeState(JSON.parse(state.stdout), contract, credentials, deps);
|
|
155
|
+
if (observed.bindings.length) {
|
|
156
|
+
for (const binding of observed.bindings)
|
|
157
|
+
Object.assign(contract.hostinger.vps[binding.role], {
|
|
158
|
+
id: binding.id,
|
|
159
|
+
ssh_host: binding.ipv4,
|
|
160
|
+
});
|
|
161
|
+
delete contract.terraform.plan.sha256;
|
|
162
|
+
delete contract.terraform.plan.policy_result_sha256;
|
|
163
|
+
await deps.writeFile(insideRoot(args.contract), `${JSON.stringify(contract, null, 2)}\n`, {
|
|
164
|
+
mode: 0o600,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
...result(args.operation, "terraform", observed.targets),
|
|
169
|
+
bindings: observed.bindings,
|
|
170
|
+
validation: "provider-read-after-write; application health requires separate checks",
|
|
171
|
+
plan_sha256: args.planSha256,
|
|
172
|
+
policy_result_sha256: args.policyResultSha256,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function terraformEnvironment(values, { nonempty, fail }) {
|
|
177
|
+
if (!nonempty(values.AWS_ACCESS_KEY_ID) || !nonempty(values.AWS_SECRET_ACCESS_KEY))
|
|
178
|
+
fail("backend_credential_unavailable");
|
|
179
|
+
const allowed = [
|
|
180
|
+
"CLOUDFLARE_API_TOKEN",
|
|
181
|
+
"HOSTINGER_API_TOKEN",
|
|
182
|
+
"TF_VAR_cloudflare_account_id",
|
|
183
|
+
"TF_VAR_cloudflare_zone_id",
|
|
184
|
+
"TF_VAR_cloudflare_zone_name",
|
|
185
|
+
"TF_VAR_edge_vps_ipv4",
|
|
186
|
+
"TF_VAR_application_vps_ipv4",
|
|
187
|
+
"AWS_ACCESS_KEY_ID",
|
|
188
|
+
"AWS_SECRET_ACCESS_KEY",
|
|
189
|
+
"AWS_SESSION_TOKEN",
|
|
190
|
+
"AWS_REGION",
|
|
191
|
+
];
|
|
192
|
+
return {
|
|
193
|
+
...Object.fromEntries(
|
|
194
|
+
allowed.filter((key) => nonempty(values[key])).map((key) => [key, values[key]]),
|
|
195
|
+
),
|
|
196
|
+
AWS_EC2_METADATA_DISABLED: "true",
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function policyCheck(plan, root, deps) {
|
|
201
|
+
return deps.exec(
|
|
202
|
+
process.execPath,
|
|
203
|
+
[
|
|
204
|
+
".agents/tools/cloud-terraform-plan-policy.mjs",
|
|
205
|
+
"--plan",
|
|
206
|
+
plan.policy_json_path,
|
|
207
|
+
"--contract",
|
|
208
|
+
plan.policy_contract_path,
|
|
209
|
+
],
|
|
210
|
+
{ cwd: root, env: {} },
|
|
211
|
+
);
|
|
212
|
+
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import {
|
|
4
|
+
copyFile,
|
|
5
|
+
link,
|
|
6
|
+
mkdir,
|
|
7
|
+
mkdtemp,
|
|
8
|
+
readFile,
|
|
9
|
+
realpath,
|
|
10
|
+
rm,
|
|
11
|
+
writeFile,
|
|
12
|
+
} from "node:fs/promises";
|
|
13
|
+
import { createServer } from "node:http";
|
|
14
|
+
import { tmpdir } from "node:os";
|
|
15
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
16
|
+
import test from "node:test";
|
|
17
|
+
import { pathToFileURL } from "node:url";
|
|
18
|
+
|
|
19
|
+
test("real filesystem, local HTTP providers and stateful child CLI complete plan/apply without real accounts", async (t) => {
|
|
20
|
+
const temporaryRoot = await realpath(tmpdir());
|
|
21
|
+
const workspace = await mkdtemp(join(temporaryRoot, "zaip-cloud-e2e-"));
|
|
22
|
+
t.after(async () => {
|
|
23
|
+
assert.equal(dirname(await realpath(workspace)), temporaryRoot);
|
|
24
|
+
assert.ok(basename(workspace).startsWith("zaip-cloud-e2e-"));
|
|
25
|
+
await rm(workspace, { recursive: true, force: true });
|
|
26
|
+
});
|
|
27
|
+
const put = async (name, content) => {
|
|
28
|
+
const path = join(workspace, name);
|
|
29
|
+
await mkdir(dirname(path), { recursive: true });
|
|
30
|
+
await writeFile(path, typeof content === "string" ? content : JSON.stringify(content));
|
|
31
|
+
};
|
|
32
|
+
await put(".agents/tools/.keep", "");
|
|
33
|
+
await copyFile(
|
|
34
|
+
resolve(import.meta.dirname, "cloud-runner.mjs"),
|
|
35
|
+
join(workspace, ".agents/tools/cloud-runner.mjs"),
|
|
36
|
+
);
|
|
37
|
+
await copyFile(
|
|
38
|
+
resolve(import.meta.dirname, "cloud-terraform-plan-policy.mjs"),
|
|
39
|
+
join(workspace, ".agents/tools/cloud-terraform-plan-policy.mjs"),
|
|
40
|
+
);
|
|
41
|
+
await put("scripts/.keep", "");
|
|
42
|
+
await copyFile(
|
|
43
|
+
resolve(import.meta.dirname, "../../scripts/validate-cloud-terraform-plan.mjs"),
|
|
44
|
+
join(workspace, "scripts/validate-cloud-terraform-plan.mjs"),
|
|
45
|
+
);
|
|
46
|
+
await mkdir(join(workspace, ".local"), { recursive: true });
|
|
47
|
+
const binary = join(
|
|
48
|
+
workspace,
|
|
49
|
+
".local",
|
|
50
|
+
process.platform === "win32" ? "terraform.exe" : "terraform",
|
|
51
|
+
);
|
|
52
|
+
try {
|
|
53
|
+
await link(process.execPath, binary);
|
|
54
|
+
} catch {
|
|
55
|
+
await copyFile(process.execPath, binary);
|
|
56
|
+
}
|
|
57
|
+
const hash = createHash("sha256")
|
|
58
|
+
.update(await readFile(binary))
|
|
59
|
+
.digest("hex");
|
|
60
|
+
const config = {
|
|
61
|
+
bucket: "approved-state",
|
|
62
|
+
key: "test/state",
|
|
63
|
+
region: "us-east-1",
|
|
64
|
+
encrypt: true,
|
|
65
|
+
use_lockfile: true,
|
|
66
|
+
};
|
|
67
|
+
const policy = {
|
|
68
|
+
cloudflare: {
|
|
69
|
+
account_id: "cf",
|
|
70
|
+
zone_id: "zone",
|
|
71
|
+
zone_name: "example.com",
|
|
72
|
+
edge_ipv4: "198.51.100.7",
|
|
73
|
+
dns_records: {},
|
|
74
|
+
},
|
|
75
|
+
hostinger: {
|
|
76
|
+
edge: {
|
|
77
|
+
id: "101",
|
|
78
|
+
plan: "sku",
|
|
79
|
+
data_center_id: 1,
|
|
80
|
+
template_id: 2,
|
|
81
|
+
hostname: "edge",
|
|
82
|
+
ssh_key_ids: [],
|
|
83
|
+
},
|
|
84
|
+
application: {
|
|
85
|
+
id: "102",
|
|
86
|
+
plan: "sku",
|
|
87
|
+
data_center_id: 1,
|
|
88
|
+
template_id: 2,
|
|
89
|
+
hostname: "app",
|
|
90
|
+
ssh_key_ids: [],
|
|
91
|
+
ipv4: "198.51.100.8",
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
const contract = {
|
|
96
|
+
version: 1,
|
|
97
|
+
profile: "autonomous-cloud",
|
|
98
|
+
authorization: { standing: true, reference: "TASK-TEST" },
|
|
99
|
+
cloudflare: { account_id: "cf", zone_id: "zone", zone_name: "example.com", dns_records: [] },
|
|
100
|
+
hostinger: {
|
|
101
|
+
account_id: "hs",
|
|
102
|
+
vps: {
|
|
103
|
+
edge: { id: "101", ssh_host: "198.51.100.7" },
|
|
104
|
+
application: { id: "102", ssh_host: "198.51.100.8" },
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
terraform: {
|
|
108
|
+
binary_path: ".local/" + basename(binary),
|
|
109
|
+
binary_sha256: hash,
|
|
110
|
+
working_directory: "infra/terraform",
|
|
111
|
+
allowed_operations: ["terraform:plan", "terraform:apply"],
|
|
112
|
+
plan: {
|
|
113
|
+
backend: { type: "s3", config },
|
|
114
|
+
path: ".local/cloud/plans/approved.tfplan",
|
|
115
|
+
policy_json_path: ".local/cloud/plans/approved.json",
|
|
116
|
+
policy_contract_path: ".agents/config/policy.json",
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
const contractPath = ".agents/config/autonomous-cloud-contract.json";
|
|
121
|
+
await put(contractPath, contract);
|
|
122
|
+
await put(".agents/config/policy.json", policy);
|
|
123
|
+
await put(
|
|
124
|
+
".env",
|
|
125
|
+
"CLOUDFLARE_API_TOKEN=fake-cf\nHOSTINGER_API_TOKEN=fake-hs\nAWS_ACCESS_KEY_ID=fake-state-key\nAWS_SECRET_ACCESS_KEY=fake-state-secret\nUNRELATED_SECRET=never-forward\n",
|
|
126
|
+
);
|
|
127
|
+
await put("infra/terraform/backend.tf.json", { terraform: { backend: { s3: config } } });
|
|
128
|
+
await put("infra/terraform/.terraform.lock.hcl", "fixture-provider-lock");
|
|
129
|
+
const values = ["edge", "application"].map((role) => ({
|
|
130
|
+
address: `hostinger_vps.${role}[0]`,
|
|
131
|
+
type: "hostinger_vps",
|
|
132
|
+
mode: "managed",
|
|
133
|
+
values: { ...policy.hostinger[role], ipv4_address: contract.hostinger.vps[role].ssh_host },
|
|
134
|
+
}));
|
|
135
|
+
for (const resource of values) delete resource.values.ipv4;
|
|
136
|
+
await put("infra/terraform/expected-plan.json", {
|
|
137
|
+
resource_changes: values.map((resource) => ({
|
|
138
|
+
address: resource.address,
|
|
139
|
+
type: resource.type,
|
|
140
|
+
change: { actions: ["no-op"], before: resource.values, after: resource.values },
|
|
141
|
+
})),
|
|
142
|
+
});
|
|
143
|
+
await put("infra/terraform/expected-state.json", {
|
|
144
|
+
values: { root_module: { resources: values } },
|
|
145
|
+
});
|
|
146
|
+
await put(
|
|
147
|
+
"infra/terraform/fake.cjs",
|
|
148
|
+
`const fs=require('node:fs');const assert=require('node:assert/strict');module.exports=(op)=>{
|
|
149
|
+
assert.equal(process.env.UNRELATED_SECRET,undefined);assert.equal(process.env.AWS_EC2_METADATA_DISABLED,'true');
|
|
150
|
+
let state=fs.existsSync('.fake-state.json')?JSON.parse(fs.readFileSync('.fake-state.json')):{};
|
|
151
|
+
if(op==='init'){state.initialized=true;fs.mkdirSync('.terraform',{recursive:true});const b=JSON.parse(fs.readFileSync('backend.tf.json')).terraform.backend.s3;fs.writeFileSync('.terraform/terraform.tfstate',JSON.stringify({backend:{type:'s3',config:b}}));}
|
|
152
|
+
else {assert.ok(state.initialized);if(op==='plan'){state.planned=true;fs.writeFileSync(process.argv[process.argv.indexOf('-out')+1],'reviewed-plan');}
|
|
153
|
+
if(op==='show'){assert.ok(state.planned);const saved=process.argv.length>3;if(!saved)assert.ok(state.applied);process.stdout.write(fs.readFileSync(saved?'expected-plan.json':'expected-state.json'));}
|
|
154
|
+
if(op==='apply'){assert.ok(state.planned);assert.equal(fs.readFileSync(process.argv.at(-1),'utf8'),'reviewed-plan');state.applied=true;}}
|
|
155
|
+
state.calls=[...(state.calls||[]),op];fs.writeFileSync('.fake-state.json',JSON.stringify(state));};`,
|
|
156
|
+
);
|
|
157
|
+
for (const op of ["init", "fmt", "validate", "plan", "show", "apply"])
|
|
158
|
+
await put(`infra/terraform/${op}`, `require('./fake.cjs')('${op}');`);
|
|
159
|
+
const requests = [];
|
|
160
|
+
const server = createServer((req, res) => {
|
|
161
|
+
requests.push(req.url);
|
|
162
|
+
res.setHeader("Content-Type", "application/json");
|
|
163
|
+
if (req.method !== "GET") {
|
|
164
|
+
res.statusCode = 405;
|
|
165
|
+
return res.end("{}");
|
|
166
|
+
}
|
|
167
|
+
if (req.url === "/client/v4/zones/zone")
|
|
168
|
+
return res.end(
|
|
169
|
+
JSON.stringify({
|
|
170
|
+
success: true,
|
|
171
|
+
result: { id: "zone", name: "example.com", account: { id: "cf" } },
|
|
172
|
+
}),
|
|
173
|
+
);
|
|
174
|
+
const id = /virtual-machines\/(101|102)$/.exec(req.url)?.[1];
|
|
175
|
+
if (id)
|
|
176
|
+
return res.end(
|
|
177
|
+
JSON.stringify({
|
|
178
|
+
id: Number(id),
|
|
179
|
+
ipv4: [{ address: id === "101" ? "198.51.100.7" : "198.51.100.8" }],
|
|
180
|
+
}),
|
|
181
|
+
);
|
|
182
|
+
res.statusCode = 404;
|
|
183
|
+
res.end("{}");
|
|
184
|
+
});
|
|
185
|
+
await new Promise((done) => server.listen(0, "127.0.0.1", done));
|
|
186
|
+
t.after(() => new Promise((done) => server.close(done)));
|
|
187
|
+
const endpoint = `http://127.0.0.1:${server.address().port}`;
|
|
188
|
+
const deps = { http: (url, options) => fetch(endpoint + new URL(url).pathname, options) };
|
|
189
|
+
const { run } = await import(
|
|
190
|
+
pathToFileURL(join(workspace, ".agents/tools/cloud-runner.mjs")).href
|
|
191
|
+
);
|
|
192
|
+
const planned = await run(
|
|
193
|
+
{
|
|
194
|
+
contract: contractPath,
|
|
195
|
+
operation: "terraform:plan",
|
|
196
|
+
credentialsSource: "root",
|
|
197
|
+
terraformDirectory: "infra/terraform",
|
|
198
|
+
},
|
|
199
|
+
deps,
|
|
200
|
+
);
|
|
201
|
+
Object.assign(contract.terraform.plan, {
|
|
202
|
+
sha256: planned.plan_sha256,
|
|
203
|
+
policy_result_sha256: planned.policy_result_sha256,
|
|
204
|
+
});
|
|
205
|
+
await put(contractPath, contract);
|
|
206
|
+
const args = {
|
|
207
|
+
contract: contractPath,
|
|
208
|
+
operation: "terraform:apply",
|
|
209
|
+
credentialsSource: "root",
|
|
210
|
+
planPath: contract.terraform.plan.path,
|
|
211
|
+
planSha256: planned.plan_sha256,
|
|
212
|
+
policyResultSha256: planned.policy_result_sha256,
|
|
213
|
+
};
|
|
214
|
+
const result = await run(args, deps);
|
|
215
|
+
assert.deepEqual(result.targets, ["101", "102"]);
|
|
216
|
+
const recorded = JSON.parse(
|
|
217
|
+
await readFile(join(workspace, "infra/terraform/.fake-state.json"), "utf8"),
|
|
218
|
+
);
|
|
219
|
+
assert.deepEqual(recorded.calls, [
|
|
220
|
+
"init",
|
|
221
|
+
"fmt",
|
|
222
|
+
"validate",
|
|
223
|
+
"plan",
|
|
224
|
+
"show",
|
|
225
|
+
"init",
|
|
226
|
+
"show",
|
|
227
|
+
"apply",
|
|
228
|
+
"show",
|
|
229
|
+
]);
|
|
230
|
+
assert.equal(requests.length, 8);
|
|
231
|
+
await put(contract.terraform.plan.path, "tampered");
|
|
232
|
+
await assert.rejects(run(args, deps), /target_mismatch/);
|
|
233
|
+
assert.equal(
|
|
234
|
+
JSON.parse(
|
|
235
|
+
await readFile(join(workspace, "infra/terraform/.fake-state.json"), "utf8"),
|
|
236
|
+
).calls.filter((op) => op === "apply").length,
|
|
237
|
+
1,
|
|
238
|
+
);
|
|
239
|
+
});
|