@zaip-ai/cli 1.3.7 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -1
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +26 -0
- 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 +3 -1
- 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-install.d.ts +14 -0
- package/dist/services/stack-install.d.ts.map +1 -0
- package/dist/services/stack-install.js +176 -0
- package/dist/services/stack-install.js.map +1 -0
- package/dist/services/stack-node.d.ts +12 -0
- package/dist/services/stack-node.d.ts.map +1 -0
- package/dist/services/stack-node.js +150 -0
- package/dist/services/stack-node.js.map +1 -0
- package/dist/services/stack-package-manager.d.ts +12 -0
- package/dist/services/stack-package-manager.d.ts.map +1 -0
- package/dist/services/stack-package-manager.js +178 -0
- package/dist/services/stack-package-manager.js.map +1 -0
- package/dist/services/stack-plan.d.ts +35 -0
- package/dist/services/stack-plan.d.ts.map +1 -0
- package/dist/services/stack-plan.js +130 -0
- package/dist/services/stack-plan.js.map +1 -0
- 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 +4 -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 +214 -94
- 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--czwAlcH.js → DashboardHelpDialog-oZVlf-l5.js} +787 -723
- 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/{ProjectSettingsPage-BomxqCBU.css → ProjectSettingsPage-GgzpZ_PY.css} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-CAqYVin1.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/ProjectSettingsPage.tsx +15 -2
- package/templates/.agents/dashboard/apps/frontend/src/ProjectStackEditor.tsx +33 -6
- 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 +9 -8
- package/templates/.agents/dashboard/apps/frontend/src/project-settings-model.ts +15 -3
- package/templates/.agents/dashboard/apps/frontend/src/project-settings-page.css +0 -104
- package/templates/.agents/dashboard/apps/frontend/src/project-settings.test.ts +61 -0
- package/templates/.agents/dashboard/apps/frontend/src/project-stack-versions.css +117 -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 +477 -327
- 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 +243 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.ts +252 -41
- 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-server.mjs +142 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +231 -239
- 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/stack-dependencies.json +14 -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 +613 -173
- package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-B_Oj6Dlf.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-CblPpexd.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,88 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ReconciliationCommandTimeoutError,
|
|
3
|
+
type ReconciliationResult,
|
|
4
|
+
reconciliationCommandTimeoutMs,
|
|
5
|
+
} from "./server-workspace.js";
|
|
6
|
+
|
|
7
|
+
export function reconciliationNeedsRefresh(result: ReconciliationResult): boolean {
|
|
8
|
+
return result.reconciled_ids.length > 0 || result.blocked.length > 0;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type ReconciliationMode = "manual" | "host-terminal";
|
|
12
|
+
|
|
13
|
+
/** Include queue time in the HTTP deadline; the serialized job remains retryable. */
|
|
14
|
+
export async function waitForWorkReconciliation(
|
|
15
|
+
work: Promise<ReconciliationResult>,
|
|
16
|
+
onDeadline: () => void = () => undefined,
|
|
17
|
+
): Promise<ReconciliationResult> {
|
|
18
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
19
|
+
try {
|
|
20
|
+
return await Promise.race([
|
|
21
|
+
work,
|
|
22
|
+
new Promise<never>((_resolve, reject) => {
|
|
23
|
+
timer = setTimeout(() => {
|
|
24
|
+
onDeadline();
|
|
25
|
+
reject(new ReconciliationCommandTimeoutError());
|
|
26
|
+
}, reconciliationCommandTimeoutMs);
|
|
27
|
+
timer.unref();
|
|
28
|
+
}),
|
|
29
|
+
]);
|
|
30
|
+
} finally {
|
|
31
|
+
if (timer !== undefined) clearTimeout(timer);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Serialize canonical mutations from the button and the host recovery timer. */
|
|
36
|
+
export function createWorkReconciliation(input: {
|
|
37
|
+
reconcile: (mode: ReconciliationMode) => Promise<ReconciliationResult>;
|
|
38
|
+
refresh: () => Promise<void>;
|
|
39
|
+
}) {
|
|
40
|
+
let tail = Promise.resolve();
|
|
41
|
+
const pending = new Map<ReconciliationMode, Promise<ReconciliationResult>>();
|
|
42
|
+
const refresh = () => void input.refresh().catch(() => undefined);
|
|
43
|
+
return (mode: ReconciliationMode): Promise<ReconciliationResult> => {
|
|
44
|
+
const current = pending.get("manual") ?? pending.get(mode);
|
|
45
|
+
if (current !== undefined) return current;
|
|
46
|
+
const job = tail
|
|
47
|
+
.then(() => input.reconcile(mode))
|
|
48
|
+
.then(
|
|
49
|
+
(result) => {
|
|
50
|
+
if (result.reconciled_ids.length > 0 || result.blocked.length > 0) refresh();
|
|
51
|
+
return result;
|
|
52
|
+
},
|
|
53
|
+
(error: unknown) => {
|
|
54
|
+
// A failed command may already have persisted part of the graph.
|
|
55
|
+
refresh();
|
|
56
|
+
throw error;
|
|
57
|
+
},
|
|
58
|
+
)
|
|
59
|
+
.finally(() => pending.delete(mode));
|
|
60
|
+
pending.set(mode, job);
|
|
61
|
+
tail = job.then(
|
|
62
|
+
() => undefined,
|
|
63
|
+
() => undefined,
|
|
64
|
+
);
|
|
65
|
+
return job;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Recover missed host-stop callbacks without relying on an open browser tab. */
|
|
70
|
+
export function startHostTerminalReconciliation(reconcile: () => Promise<unknown>): () => void {
|
|
71
|
+
let stopped = false;
|
|
72
|
+
let timer: ReturnType<typeof setTimeout>;
|
|
73
|
+
const schedule = (delay: number) => {
|
|
74
|
+
timer = setTimeout(() => {
|
|
75
|
+
void reconcile()
|
|
76
|
+
.catch(() => undefined)
|
|
77
|
+
.finally(() => {
|
|
78
|
+
if (!stopped) schedule(30_000);
|
|
79
|
+
});
|
|
80
|
+
}, delay);
|
|
81
|
+
timer.unref();
|
|
82
|
+
};
|
|
83
|
+
schedule(1_000);
|
|
84
|
+
return () => {
|
|
85
|
+
stopped = true;
|
|
86
|
+
clearTimeout(timer);
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -68,19 +68,52 @@ export interface ReconciliationResult {
|
|
|
68
68
|
not_reconciled: ReconciliationItem[];
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
export const reconciliationCommandTimeoutMs = 170_000;
|
|
72
|
+
|
|
73
|
+
export class ReconciliationCommandTimeoutError extends Error {
|
|
74
|
+
constructor() {
|
|
75
|
+
super(
|
|
76
|
+
`Open-work reconciliation exceeded ${reconciliationCommandTimeoutMs}ms. Canonical records may contain partial changes; the dashboard projection is being refreshed.`,
|
|
77
|
+
);
|
|
78
|
+
this.name = "ReconciliationCommandTimeoutError";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
71
82
|
export async function reconcileOpenWork(
|
|
72
83
|
filesystem: WorkspaceFileSystem,
|
|
73
84
|
workspaceRoot: string,
|
|
85
|
+
options: { hostTerminalOnly?: boolean } = {},
|
|
74
86
|
): Promise<ReconciliationResult> {
|
|
75
87
|
if (!(await filesystem.exists(".agents/runtime/bin/zaip.mjs"))) {
|
|
76
|
-
|
|
88
|
+
throw new Error("ZAIP runtime is unavailable; open work could not be reconciled.");
|
|
77
89
|
}
|
|
78
90
|
const cliPath = resolve(workspaceRoot, ".agents", "runtime", "bin", "zaip.mjs");
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
91
|
+
let stdout: string;
|
|
92
|
+
try {
|
|
93
|
+
({ stdout } = await execFileAsync(
|
|
94
|
+
process.execPath,
|
|
95
|
+
[
|
|
96
|
+
cliPath,
|
|
97
|
+
"run",
|
|
98
|
+
"reconcile",
|
|
99
|
+
"--open",
|
|
100
|
+
"--json",
|
|
101
|
+
...(options.hostTerminalOnly ? ["--host-terminal-only"] : []),
|
|
102
|
+
],
|
|
103
|
+
{
|
|
104
|
+
cwd: workspaceRoot,
|
|
105
|
+
windowsHide: true,
|
|
106
|
+
maxBuffer: 10 * 1_024 * 1_024,
|
|
107
|
+
timeout: reconciliationCommandTimeoutMs,
|
|
108
|
+
killSignal: "SIGTERM",
|
|
109
|
+
},
|
|
110
|
+
));
|
|
111
|
+
} catch (error) {
|
|
112
|
+
if (typeof error === "object" && error !== null && "killed" in error && error.killed === true) {
|
|
113
|
+
throw new ReconciliationCommandTimeoutError();
|
|
114
|
+
}
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
84
117
|
return reconciliationResult(JSON.parse(stdout) as unknown);
|
|
85
118
|
}
|
|
86
119
|
|
|
@@ -94,6 +127,7 @@ export function reconciliationResult(value: unknown): ReconciliationResult {
|
|
|
94
127
|
};
|
|
95
128
|
const records =
|
|
96
129
|
typeof value === "object" && value !== null ? (value as Record<string, unknown>) : {};
|
|
130
|
+
const terminalStatuses = new Set(["completed", "delivered", "blocked", "cancelled", "failed"]);
|
|
97
131
|
const reconciliations = Array.isArray(records.reconciliations) ? records.reconciliations : [];
|
|
98
132
|
for (const candidate of reconciliations) {
|
|
99
133
|
if (typeof candidate !== "object" || candidate === null) continue;
|
|
@@ -107,7 +141,7 @@ export function reconciliationResult(value: unknown): ReconciliationResult {
|
|
|
107
141
|
const record = entity as Record<string, unknown>;
|
|
108
142
|
if (
|
|
109
143
|
item.status === "closed" &&
|
|
110
|
-
|
|
144
|
+
terminalStatuses.has(record.status as string) &&
|
|
111
145
|
typeof record.id === "string"
|
|
112
146
|
) {
|
|
113
147
|
reconciled.add(record.id);
|
|
@@ -119,12 +153,39 @@ export function reconciliationResult(value: unknown): ReconciliationResult {
|
|
|
119
153
|
}
|
|
120
154
|
}
|
|
121
155
|
}
|
|
156
|
+
// A terminal conversation/root can change canonical telemetry without a
|
|
157
|
+
// Task graph. It still requires a snapshot promotion so Cost Monitor does
|
|
158
|
+
// not keep serving the generation that preceded its Run closure.
|
|
159
|
+
const closedRuns = Array.isArray(records.runs) ? records.runs : [];
|
|
160
|
+
closedRuns.forEach((candidate) => {
|
|
161
|
+
if (typeof candidate !== "object" || candidate === null) return;
|
|
162
|
+
const runId = (candidate as { run?: { run_id?: unknown } }).run?.run_id;
|
|
163
|
+
if (typeof runId === "string") reconciled.add(runId);
|
|
164
|
+
});
|
|
122
165
|
const orphanedExecutions = Array.isArray(records.orphaned_executions)
|
|
123
166
|
? records.orphaned_executions
|
|
124
167
|
: [];
|
|
125
168
|
orphanedExecutions.forEach((id) => {
|
|
126
169
|
remember(blocked, id, "Execution orphaned after the reconciliation grace period.");
|
|
127
170
|
});
|
|
171
|
+
const orphanedInteractionExecutions = Array.isArray(records.orphaned_interaction_executions)
|
|
172
|
+
? records.orphaned_interaction_executions
|
|
173
|
+
: [];
|
|
174
|
+
orphanedInteractionExecutions.forEach((id) => {
|
|
175
|
+
remember(blocked, id, "Interaction Execution orphaned after the reconciliation grace period.");
|
|
176
|
+
});
|
|
177
|
+
// Orphan recovery can settle owners without returning a Run reconciliation.
|
|
178
|
+
// Surface every persisted owner, including macro-only `delivered` outcomes,
|
|
179
|
+
// so the button reports the changed entities and refreshes their snapshot.
|
|
180
|
+
for (const key of ["orphaned_owner_entities", "orphaned_execution_entities"]) {
|
|
181
|
+
for (const candidate of Array.isArray(records[key]) ? records[key] : []) {
|
|
182
|
+
if (typeof candidate !== "object" || candidate === null) continue;
|
|
183
|
+
const entity = candidate as Record<string, unknown>;
|
|
184
|
+
if (typeof entity.id !== "string" || !terminalStatuses.has(entity.status as string)) continue;
|
|
185
|
+
reconciled.add(entity.id);
|
|
186
|
+
if (entity.status === "blocked") remember(blocked, entity.id, entity.status_reason);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
128
189
|
const errors = Array.isArray(records.reconciliation_errors) ? records.reconciliation_errors : [];
|
|
129
190
|
errors.forEach((candidate) => {
|
|
130
191
|
if (typeof candidate !== "object" || candidate === null) return;
|
|
@@ -247,15 +247,21 @@ describe("dashboard backend", () => {
|
|
|
247
247
|
headers: { "x-zaip-session": "test-session" },
|
|
248
248
|
});
|
|
249
249
|
expect(response.status, await response.clone().text()).toBe(200);
|
|
250
|
-
await
|
|
251
|
-
|
|
252
|
-
|
|
250
|
+
const receipt = (await response.json()) as Record<string, unknown>;
|
|
251
|
+
expect(receipt).toMatchObject({ reconciliation: { reconciled_ids: ["TASK-RECONCILED"] } });
|
|
252
|
+
expect(Object.keys(receipt).sort()).toEqual([
|
|
253
|
+
"projection_refresh_completed",
|
|
254
|
+
"reconciliation",
|
|
255
|
+
"snapshot_state",
|
|
256
|
+
]);
|
|
253
257
|
expect(reconcile).toHaveBeenCalledOnce();
|
|
254
|
-
expect(reconcile).toHaveBeenCalledWith(canonicalFilesystem, workspaceRoot
|
|
258
|
+
expect(reconcile).toHaveBeenCalledWith(canonicalFilesystem, workspaceRoot, {
|
|
259
|
+
hostTerminalOnly: false,
|
|
260
|
+
});
|
|
255
261
|
expect(refresh).toHaveBeenCalledOnce();
|
|
256
262
|
const rejected = await app.request("/api/v2/reconcile-open-work", { method: "POST" });
|
|
257
263
|
expect(rejected.status).toBe(401);
|
|
258
|
-
}
|
|
264
|
+
});
|
|
259
265
|
it("rebuilds a stale immutable projection without reconciling lifecycle work", async () => {
|
|
260
266
|
const fixtureRoot = await mkdtemp(join(tmpdir(), "zaip-dashboard-stale-projection-"));
|
|
261
267
|
const taskIndexPath = join(
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
readProjectOverview,
|
|
35
35
|
readProjectSettings,
|
|
36
36
|
} from "./project-settings.js";
|
|
37
|
+
import { agentPortraitFiles, openWorkIds } from "./server-agent-assets.js";
|
|
37
38
|
import {
|
|
38
39
|
type BoardClassification,
|
|
39
40
|
boardFilters,
|
|
@@ -41,6 +42,7 @@ import {
|
|
|
41
42
|
boardStage,
|
|
42
43
|
classificationPage,
|
|
43
44
|
} from "./server-board.js";
|
|
45
|
+
import { registerBrowserLeaseRoute } from "./server-browser-lease.js";
|
|
44
46
|
import { registerDailyReadModelRoute } from "./server-daily-read-models-route.js";
|
|
45
47
|
import {
|
|
46
48
|
changeEntityPageRows,
|
|
@@ -64,11 +66,24 @@ import {
|
|
|
64
66
|
} from "./server-projections.js";
|
|
65
67
|
import { isAllowedDashboardAuthority } from "./server-request-authority.js";
|
|
66
68
|
import { refreshSqliteSnapshotInWorker } from "./server-snapshot-refresh.js";
|
|
69
|
+
import { readCommittedSnapshotRevision } from "./server-snapshot-revision.js";
|
|
70
|
+
import { startSnapshotSynchronization } from "./server-snapshot-synchronization.js";
|
|
67
71
|
import { buildSqliteTaskTrace } from "./server-sqlite-task-trace.js";
|
|
72
|
+
import { writeReadModelStartup, writeStartupPhase } from "./server-startup.js";
|
|
68
73
|
import { queryValues, selectedCurrency } from "./server-summary-helpers.js";
|
|
74
|
+
import {
|
|
75
|
+
createWorkReconciliation,
|
|
76
|
+
reconciliationNeedsRefresh,
|
|
77
|
+
startHostTerminalReconciliation,
|
|
78
|
+
waitForWorkReconciliation,
|
|
79
|
+
} from "./server-work-reconciliation.js";
|
|
80
|
+
|
|
81
|
+
export { reconciliationNeedsRefresh } from "./server-work-reconciliation.js";
|
|
82
|
+
|
|
69
83
|
import {
|
|
70
84
|
dashboardIdentity,
|
|
71
85
|
dashboardWorkspaceKey,
|
|
86
|
+
ReconciliationCommandTimeoutError,
|
|
72
87
|
type ReconciliationResult,
|
|
73
88
|
reconcileOpenWork,
|
|
74
89
|
} from "./server-workspace.js";
|
|
@@ -79,6 +94,7 @@ import {
|
|
|
79
94
|
} from "./sqlite-read-model.js";
|
|
80
95
|
|
|
81
96
|
export { manifestRun, mergeManifestRuns } from "./manifest-runs.js";
|
|
97
|
+
export { openWorkIds } from "./server-agent-assets.js";
|
|
82
98
|
export { projectionPeriodFilter } from "./server-period.js";
|
|
83
99
|
export { projectAllTimeTopTasks } from "./server-period-macro-metric.js";
|
|
84
100
|
export {
|
|
@@ -94,10 +110,6 @@ export {
|
|
|
94
110
|
validateSqliteReadModelSchema,
|
|
95
111
|
} from "./sqlite-read-model.js";
|
|
96
112
|
|
|
97
|
-
export function reconciliationNeedsRefresh(result: ReconciliationResult): boolean {
|
|
98
|
-
return result.reconciled_ids.length > 0 || result.blocked.length > 0;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
113
|
type OverviewMacroMetrics = NonNullable<
|
|
102
114
|
NonNullable<OperationsProjection["summary"]["overview_metrics"]>["macro_metrics"]
|
|
103
115
|
>;
|
|
@@ -108,47 +120,6 @@ const RUNTIME_KIND = "zaip-dashboard-sqlite-runtime";
|
|
|
108
120
|
const SESSION_COOKIE = "zaip-dashboard-sqlite-session";
|
|
109
121
|
const WORK_PRIORITY_PATH = ".agents/dashboard/work-priority.json";
|
|
110
122
|
const SNAPSHOT_CACHE_TTL_MS = 5_000;
|
|
111
|
-
const agentPortraitFiles: Record<string, string> = {
|
|
112
|
-
"agent-orchestrator": "1 - Dave - Product Owner.png",
|
|
113
|
-
"agent-builder": "2 - Rafa - Tech Lead.png",
|
|
114
|
-
"agent-task-executor": "3 - Leo - Software Engineer.png",
|
|
115
|
-
"agent-analyst": "4 - Bia - Product Manager.png",
|
|
116
|
-
"agent-finalizer": "5 - Gui - Quality Assurance Lead.png",
|
|
117
|
-
"agent-reviewer": "6 - Nanda - Principal Engineer.png",
|
|
118
|
-
"agent-integrator": "7 - Dani - Integration Engineer.png",
|
|
119
|
-
"agent-auditor": "8 - Ana - Quality Auditor.png",
|
|
120
|
-
"agent-text-summarizer": "9 - Lia - Technical Writer.png",
|
|
121
|
-
"agent-data-analyst": "10 - Gabi - Data Analyst.png",
|
|
122
|
-
"agent-refactoring-specialist": "11 - Tati - Refactoring Specialist.png",
|
|
123
|
-
"agent-frontend": "12 - Doug - Frontend Developer.png",
|
|
124
|
-
"agent-backend": "13 - Will - Backend Developer.png",
|
|
125
|
-
"agent-website-developer": "14 - Jonny - Website Developer.png",
|
|
126
|
-
"agent-designer": "15 - Manu - Product Designer.png",
|
|
127
|
-
"agent-cloud-engineer": "16 - Dan - Cloud Engineer.png",
|
|
128
|
-
"agent-security-auditor": "17 - Luis - Security Auditor.png",
|
|
129
|
-
"agent-marketing-analyst": "18 - Lucia - Marketing Analyst.png",
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
interface ActiveWorkItem {
|
|
133
|
-
kind: string;
|
|
134
|
-
id: string;
|
|
135
|
-
status: string | null;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/** Pure lifecycle helper retained for callers; it never reads a runtime projection. */
|
|
139
|
-
export function openWorkIds(items: readonly ActiveWorkItem[]): string[] {
|
|
140
|
-
const kinds = new Set(["prd", "spec", "change", "task", "execution"]);
|
|
141
|
-
const statuses = new Set(["active", "executing", "verifying", "running", "paused"]);
|
|
142
|
-
return items
|
|
143
|
-
.filter(
|
|
144
|
-
(item) =>
|
|
145
|
-
kinds.has(item.kind) &&
|
|
146
|
-
(statuses.has(item.status ?? "") || (item.kind === "task" && item.status === "planned")),
|
|
147
|
-
)
|
|
148
|
-
.map((item) => item.id)
|
|
149
|
-
.sort();
|
|
150
|
-
}
|
|
151
|
-
|
|
152
123
|
interface DashboardAppOptions {
|
|
153
124
|
syncAgentAdapters?: () => Promise<AgentAdapterSyncResult>;
|
|
154
125
|
filesystem?: WorkspaceFileSystem;
|
|
@@ -158,8 +129,12 @@ interface DashboardAppOptions {
|
|
|
158
129
|
reconcileOpenWork?: typeof reconcileOpenWork;
|
|
159
130
|
refreshReadModel?: () => Promise<void>;
|
|
160
131
|
snapshotState?: "current" | "updating";
|
|
132
|
+
/** Enable filesystem and day rollover synchronization for the serving process. */
|
|
133
|
+
watchSources?: boolean;
|
|
161
134
|
/** Test seam: health and reconciliation only require the asserted V2 layout. */
|
|
162
135
|
layout?: WorkspaceLayout;
|
|
136
|
+
/** Only the spawned local runtime may self-terminate for a missing browser lease. */
|
|
137
|
+
launcherOwned?: boolean;
|
|
163
138
|
}
|
|
164
139
|
|
|
165
140
|
class V2WorkspaceRequiredError extends Error {
|
|
@@ -650,14 +625,15 @@ export function createDashboardApp(
|
|
|
650
625
|
const app = new Hono();
|
|
651
626
|
const filesystem = options.filesystem ?? new WorkspaceFileSystem(workspaceRoot);
|
|
652
627
|
const isSqliteSnapshot = filesystem instanceof SqliteReadModelFileSystem;
|
|
653
|
-
//
|
|
654
|
-
|
|
655
|
-
// canonical filesystems remain deliberately uncached.
|
|
656
|
-
const sqliteLayout = isSqliteSnapshot ? requireV2Layout(filesystem) : null;
|
|
628
|
+
// Cache layout within a committed revision and reload after synchronization.
|
|
629
|
+
let sqliteLayout = isSqliteSnapshot ? requireV2Layout(filesystem) : null;
|
|
657
630
|
const readLayout = async () =>
|
|
658
631
|
options.layout ?? sqliteLayout ?? (await requireV2Layout(filesystem));
|
|
659
632
|
const snapshotReadOnly = options.snapshotReadOnly ?? isSqliteSnapshot;
|
|
660
|
-
|
|
633
|
+
// A stale seed is safe to serve only until this process promotes its own
|
|
634
|
+
// replacement. Keep the state mutable so health/ready stop advertising an
|
|
635
|
+
// update after the atomic handoff succeeds.
|
|
636
|
+
let snapshotState = options.snapshotState ?? "current";
|
|
661
637
|
const canonicalFilesystem = options.canonicalFilesystem ?? new WorkspaceFileSystem(workspaceRoot);
|
|
662
638
|
const reconcileOpen = options.reconcileOpenWork ?? reconcileOpenWork;
|
|
663
639
|
const refreshReadModel =
|
|
@@ -714,16 +690,48 @@ export function createDashboardApp(
|
|
|
714
690
|
aggregatePayloads.clear();
|
|
715
691
|
aggregateInFlight.clear();
|
|
716
692
|
};
|
|
693
|
+
let observedSnapshotRevision: string | null = null;
|
|
717
694
|
let projectionRefreshInFlight: Promise<void> | null = null;
|
|
695
|
+
let projectionRefreshRequested = false;
|
|
718
696
|
const rebuildProjection = async () => {
|
|
719
|
-
if (projectionRefreshInFlight !== null)
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
697
|
+
if (projectionRefreshInFlight !== null) {
|
|
698
|
+
projectionRefreshRequested = true;
|
|
699
|
+
return projectionRefreshInFlight;
|
|
700
|
+
}
|
|
701
|
+
snapshotState = "updating";
|
|
702
|
+
projectionRefreshInFlight = (async () => {
|
|
703
|
+
do {
|
|
704
|
+
projectionRefreshRequested = false;
|
|
705
|
+
await refreshReadModel();
|
|
706
|
+
if (isSqliteSnapshot) sqliteLayout = requireV2Layout(filesystem);
|
|
707
|
+
clearSnapshotCache();
|
|
708
|
+
} while (projectionRefreshRequested);
|
|
709
|
+
snapshotState = "current";
|
|
710
|
+
})().finally(() => {
|
|
711
|
+
projectionRefreshInFlight = null;
|
|
712
|
+
});
|
|
725
713
|
return projectionRefreshInFlight;
|
|
726
714
|
};
|
|
715
|
+
startSnapshotSynchronization({
|
|
716
|
+
workspaceRoot,
|
|
717
|
+
staleSeed: isSqliteSnapshot && snapshotState === "updating",
|
|
718
|
+
watchSources: isSqliteSnapshot && options.watchSources === true,
|
|
719
|
+
refresh: rebuildProjection,
|
|
720
|
+
});
|
|
721
|
+
const reconcileWork = createWorkReconciliation({
|
|
722
|
+
reconcile: (mode) =>
|
|
723
|
+
reconcileOpen(canonicalFilesystem, workspaceRoot, {
|
|
724
|
+
hostTerminalOnly: mode === "host-terminal",
|
|
725
|
+
}),
|
|
726
|
+
refresh: rebuildProjection,
|
|
727
|
+
});
|
|
728
|
+
if (
|
|
729
|
+
isSqliteSnapshot &&
|
|
730
|
+
options.watchSources === true &&
|
|
731
|
+
process.env.ZAIP_DASHBOARD_WATCH_SOURCES !== "0"
|
|
732
|
+
) {
|
|
733
|
+
startHostTerminalReconciliation(() => reconcileWork("host-terminal"));
|
|
734
|
+
}
|
|
727
735
|
const readSnapshot = (context: Context) => {
|
|
728
736
|
const key = snapshotKey(context);
|
|
729
737
|
const cached = cachedSnapshots.get(key);
|
|
@@ -785,6 +793,8 @@ export function createDashboardApp(
|
|
|
785
793
|
// available while the dashboard serves a read-only snapshot.
|
|
786
794
|
const reconcileWrite =
|
|
787
795
|
context.req.method === "POST" && context.req.path === `${API_PREFIX}/reconcile-open-work`;
|
|
796
|
+
const browserLeaseWrite =
|
|
797
|
+
context.req.method === "GET" && context.req.path === `${API_PREFIX}/browser-lease`;
|
|
788
798
|
const projectionRefreshWrite =
|
|
789
799
|
context.req.method === "POST" && context.req.path === `${API_PREFIX}/refresh-projection`;
|
|
790
800
|
if (
|
|
@@ -792,7 +802,8 @@ export function createDashboardApp(
|
|
|
792
802
|
context.req.method !== "HEAD" &&
|
|
793
803
|
!settingsWrite &&
|
|
794
804
|
!reconcileWrite &&
|
|
795
|
-
!projectionRefreshWrite
|
|
805
|
+
!projectionRefreshWrite &&
|
|
806
|
+
!browserLeaseWrite
|
|
796
807
|
) {
|
|
797
808
|
context.header(
|
|
798
809
|
"Allow",
|
|
@@ -824,15 +835,23 @@ export function createDashboardApp(
|
|
|
824
835
|
context.req.path.startsWith(`${API_PREFIX}/agent-catalog-assets/`)
|
|
825
836
|
? context.req.query("token")
|
|
826
837
|
: undefined;
|
|
838
|
+
const leaseToken = browserLeaseWrite ? context.req.query("token") : undefined;
|
|
839
|
+
// EventSource cannot carry the session header and localhost cookies span
|
|
840
|
+
// ports. Its query capability is therefore intentionally stricter than
|
|
841
|
+
// ordinary dashboard requests: an old tab must never lease a new runtime.
|
|
842
|
+
if (browserLeaseWrite && leaseToken !== sessionToken)
|
|
843
|
+
return context.json({ error: "Invalid local session" }, 401);
|
|
827
844
|
if (
|
|
828
845
|
headerSession !== sessionToken &&
|
|
829
846
|
cookieSession !== sessionToken &&
|
|
830
|
-
portraitToken !== sessionToken
|
|
847
|
+
portraitToken !== sessionToken &&
|
|
848
|
+
leaseToken !== sessionToken
|
|
831
849
|
) {
|
|
832
850
|
return context.json({ error: "Invalid local session" }, 401);
|
|
833
851
|
}
|
|
834
852
|
return next();
|
|
835
853
|
});
|
|
854
|
+
registerBrowserLeaseRoute(app, API_PREFIX, options.launcherOwned === true);
|
|
836
855
|
|
|
837
856
|
app.on(["GET", "HEAD"], `${API_PREFIX}/health`, async (context) => {
|
|
838
857
|
try {
|
|
@@ -871,6 +890,15 @@ export function createDashboardApp(
|
|
|
871
890
|
try {
|
|
872
891
|
const layout = await readLayout();
|
|
873
892
|
if (isSqliteSnapshot) {
|
|
893
|
+
const revision = readCommittedSnapshotRevision(workspaceRoot);
|
|
894
|
+
if (observedSnapshotRevision !== null && observedSnapshotRevision !== revision) {
|
|
895
|
+
// A worker may commit before its completion callback runs. Refresh
|
|
896
|
+
// the reader and its caches before advertising the new revision.
|
|
897
|
+
filesystem.refresh();
|
|
898
|
+
clearSnapshotCache();
|
|
899
|
+
sqliteLayout = requireV2Layout(filesystem);
|
|
900
|
+
}
|
|
901
|
+
observedSnapshotRevision = revision;
|
|
874
902
|
const metadata = filesystem.metadata();
|
|
875
903
|
return headOrJson(context, {
|
|
876
904
|
kind: RUNTIME_KIND,
|
|
@@ -884,6 +912,7 @@ export function createDashboardApp(
|
|
|
884
912
|
// /ready must never start a competing projection in the background.
|
|
885
913
|
day_count: metadata.daily_aggregate_count,
|
|
886
914
|
snapshot_state: snapshotState,
|
|
915
|
+
snapshot_revision: revision,
|
|
887
916
|
});
|
|
888
917
|
}
|
|
889
918
|
const projection = await buildFirstFoldQuickProjection(filesystem, layout, {
|
|
@@ -1220,23 +1249,32 @@ export function createDashboardApp(
|
|
|
1220
1249
|
app.post(`${API_PREFIX}/reconcile-open-work`, async (context) => {
|
|
1221
1250
|
try {
|
|
1222
1251
|
await readLayout();
|
|
1223
|
-
//
|
|
1224
|
-
//
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
// canonical data, so rebuilding the immutable SQLite snapshot only adds
|
|
1229
|
-
// seconds of redundant work before the dashboard can settle.
|
|
1230
|
-
if (reconciliationNeedsRefresh(reconciledIds)) {
|
|
1231
|
-
await rebuildProjection();
|
|
1232
|
-
}
|
|
1252
|
+
// Share the canonical mutation queue with missed host-stop recovery.
|
|
1253
|
+
// Projection rebuilds run in the background and publish their revision.
|
|
1254
|
+
const reconciledIds = await waitForWorkReconciliation(reconcileWork("manual"), () => {
|
|
1255
|
+
void rebuildProjection().catch(() => undefined);
|
|
1256
|
+
});
|
|
1233
1257
|
return context.json({
|
|
1234
|
-
...(await readSnapshot(context)),
|
|
1235
1258
|
reconciliation: reconciledIds,
|
|
1236
|
-
|
|
1259
|
+
snapshot_state: snapshotState,
|
|
1260
|
+
projection_refresh_completed:
|
|
1261
|
+
snapshotState === "current" && projectionRefreshInFlight === null,
|
|
1237
1262
|
});
|
|
1238
1263
|
} catch (error) {
|
|
1239
1264
|
if (error instanceof V2WorkspaceRequiredError) throw error;
|
|
1265
|
+
if (error instanceof ReconciliationCommandTimeoutError) {
|
|
1266
|
+
// SIGTERM can occur after the CLI persisted some records. Start an
|
|
1267
|
+
// atomic refresh without extending the request past the client's
|
|
1268
|
+
// deadline, and make that uncertainty explicit to the caller.
|
|
1269
|
+
return context.json(
|
|
1270
|
+
{
|
|
1271
|
+
error: error.message,
|
|
1272
|
+
reconciliation_may_be_partial: true,
|
|
1273
|
+
projection_refresh_started: true,
|
|
1274
|
+
},
|
|
1275
|
+
408,
|
|
1276
|
+
);
|
|
1277
|
+
}
|
|
1240
1278
|
return context.json({ error: error instanceof Error ? error.message : String(error) }, 400);
|
|
1241
1279
|
}
|
|
1242
1280
|
});
|
|
@@ -1314,7 +1352,18 @@ export function createDashboardApp(
|
|
|
1314
1352
|
);
|
|
1315
1353
|
return headOrJson(
|
|
1316
1354
|
context,
|
|
1317
|
-
|
|
1355
|
+
// The paged Cost adapter reads the lifecycle summary. That canonical
|
|
1356
|
+
// artifact is intentionally not copied into SQLite; use its current
|
|
1357
|
+
// filesystem alongside the immutable SQL facts rather than failing
|
|
1358
|
+
// a filtered page with a synthetic missing-file error.
|
|
1359
|
+
await buildManifestCostRunPage(
|
|
1360
|
+
isSqliteSnapshot ? canonicalFilesystem : filesystem,
|
|
1361
|
+
layout,
|
|
1362
|
+
context,
|
|
1363
|
+
{ from, to },
|
|
1364
|
+
offset,
|
|
1365
|
+
limit,
|
|
1366
|
+
),
|
|
1318
1367
|
200,
|
|
1319
1368
|
true,
|
|
1320
1369
|
);
|
|
@@ -1627,42 +1676,23 @@ export const app = new Proxy({} as Hono, {
|
|
|
1627
1676
|
},
|
|
1628
1677
|
});
|
|
1629
1678
|
|
|
1630
|
-
function startupPhase(phase: string): void {
|
|
1631
|
-
process.stderr.write(
|
|
1632
|
-
`${JSON.stringify({
|
|
1633
|
-
event: "dashboard_sqlite_startup_phase",
|
|
1634
|
-
phase,
|
|
1635
|
-
elapsed_ms: Math.round(performance.now() - moduleStartedAt),
|
|
1636
|
-
})}\n`,
|
|
1637
|
-
);
|
|
1638
|
-
}
|
|
1639
|
-
|
|
1640
1679
|
async function main(): Promise<void> {
|
|
1641
1680
|
const port = Number.parseInt(process.env.ZAIP_SERVER_PORT ?? "4317", 10);
|
|
1642
|
-
|
|
1681
|
+
writeStartupPhase(moduleStartedAt, "main_entered");
|
|
1643
1682
|
const startedAt = performance.now();
|
|
1644
|
-
const
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
process.stderr.write(
|
|
1649
|
-
`${JSON.stringify({
|
|
1650
|
-
event: "dashboard_sqlite_read_model",
|
|
1651
|
-
elapsed_ms: Math.round(performance.now() - startedAt),
|
|
1652
|
-
cache: readModel.cache,
|
|
1653
|
-
fingerprint_ms: readModel.fingerprint_ms,
|
|
1654
|
-
materialize_ms: readModel.materialize_ms,
|
|
1655
|
-
source_files: readModel.files,
|
|
1656
|
-
})}\n`,
|
|
1657
|
-
);
|
|
1658
|
-
startupPhase("read_model_ready");
|
|
1683
|
+
const startupOptions = { forceCanonical: false, preferExisting: true };
|
|
1684
|
+
const readModel = await rebuildSqliteReadModel(runtimeWorkspaceRoot, startupOptions);
|
|
1685
|
+
writeReadModelStartup(startedAt, readModel);
|
|
1686
|
+
writeStartupPhase(moduleStartedAt, "read_model_ready");
|
|
1659
1687
|
const runtimeApp = createDashboardApp(runtimeWorkspaceRoot, sessionToken, undefined, {
|
|
1660
1688
|
filesystem: new SqliteReadModelFileSystem(runtimeWorkspaceRoot),
|
|
1661
1689
|
snapshotState: readModel.cache === "stale_seed" ? "updating" : "current",
|
|
1690
|
+
watchSources: true,
|
|
1691
|
+
launcherOwned: true,
|
|
1662
1692
|
});
|
|
1663
|
-
|
|
1693
|
+
writeStartupPhase(moduleStartedAt, "runtime_app_ready");
|
|
1664
1694
|
serve({ fetch: runtimeApp.fetch, hostname: HOST, port }, ({ port: boundPort }) => {
|
|
1665
|
-
|
|
1695
|
+
writeStartupPhase(moduleStartedAt, "listening");
|
|
1666
1696
|
process.stdout.write(
|
|
1667
1697
|
`ZAIP-AIOS dashboard API: http://${HOST}:${boundPort}${API_PREFIX}/health\n`,
|
|
1668
1698
|
);
|