@zaip-ai/cli 3.7.0 → 4.0.0
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 +5 -5
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +6 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/services/adapters.d.ts +1 -1
- package/dist/services/adapters.d.ts.map +1 -1
- package/dist/services/adapters.js +22 -4
- package/dist/services/adapters.js.map +1 -1
- package/dist/services/adapters.test.js +24 -0
- package/dist/services/adapters.test.js.map +1 -1
- package/dist/services/agent-adapters.js +1 -1
- package/dist/services/agent-adapters.js.map +1 -1
- package/dist/services/backup-gitignore.d.ts +9 -0
- package/dist/services/backup-gitignore.d.ts.map +1 -0
- package/dist/services/backup-gitignore.js +66 -0
- package/dist/services/backup-gitignore.js.map +1 -0
- package/dist/services/backup-gitignore.test.d.ts +2 -0
- package/dist/services/backup-gitignore.test.d.ts.map +1 -0
- package/dist/services/backup-gitignore.test.js +27 -0
- package/dist/services/backup-gitignore.test.js.map +1 -0
- package/dist/services/codex-conversation-lifecycle-hook.d.ts.map +1 -1
- package/dist/services/codex-conversation-lifecycle-hook.js +15 -7
- package/dist/services/codex-conversation-lifecycle-hook.js.map +1 -1
- package/dist/services/install-agents-template.d.ts.map +1 -1
- package/dist/services/install-agents-template.js +43 -127
- package/dist/services/install-agents-template.js.map +1 -1
- package/dist/services/install-template-policy.d.ts.map +1 -1
- package/dist/services/install-template-policy.js +2 -0
- package/dist/services/install-template-policy.js.map +1 -1
- package/dist/services/legacy-records-migration.d.ts +15 -0
- package/dist/services/legacy-records-migration.d.ts.map +1 -0
- package/dist/services/legacy-records-migration.js +109 -0
- package/dist/services/legacy-records-migration.js.map +1 -0
- package/dist/services/local-state-migration.d.ts +8 -1
- package/dist/services/local-state-migration.d.ts.map +1 -1
- package/dist/services/local-state-migration.js +67 -32
- package/dist/services/local-state-migration.js.map +1 -1
- package/dist/services/logger.d.ts.map +1 -1
- package/dist/services/logger.js +2 -0
- package/dist/services/logger.js.map +1 -1
- package/dist/services/project-model-migration.d.ts +3 -0
- package/dist/services/project-model-migration.d.ts.map +1 -0
- package/dist/services/project-model-migration.js +163 -0
- package/dist/services/project-model-migration.js.map +1 -0
- package/dist/services/project-model-migration.test.d.ts +2 -0
- package/dist/services/project-model-migration.test.d.ts.map +1 -0
- package/dist/services/project-model-migration.test.js +62 -0
- package/dist/services/project-model-migration.test.js.map +1 -0
- package/dist/services/sqlite-bootstrap.d.ts.map +1 -1
- package/dist/services/sqlite-bootstrap.js +9 -1
- package/dist/services/sqlite-bootstrap.js.map +1 -1
- package/dist/services/template-manifest.d.ts.map +1 -1
- package/dist/services/template-manifest.js +2 -0
- package/dist/services/template-manifest.js.map +1 -1
- package/dist/services/transactional-files.d.ts +1 -0
- package/dist/services/transactional-files.d.ts.map +1 -1
- package/dist/services/transactional-files.js +3 -0
- package/dist/services/transactional-files.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/README-ENG.md +90 -34
- package/templates/.agents/README.md +59 -32
- package/templates/.agents/config/agents/catalog.yaml +23 -23
- package/templates/.agents/config/agents/discovery.json +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-analyst.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-auditor.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-backend.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-brand-strategist.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-builder.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-cloud-engineer.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-data-analyst.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-designer.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-finalizer.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-frontend.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-general-operations.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-governance-compliance.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-growth-strategist.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-integrator.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-marketing-analyst.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-orchestrator.toml +3 -3
- package/templates/.agents/config/clients/codex/agents/zaip-agent-refactoring-specialist.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-reviewer.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-sales-specialist.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-security-auditor.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-task-executor.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-website-developer.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-writer.toml +2 -2
- package/templates/.agents/config/clients.yaml +1 -1
- package/templates/.agents/config/pricing/models.json +57 -1
- package/templates/.agents/config/project.yaml +21 -7
- package/templates/.agents/dashboard/.zaip-managed.json +195 -115
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-C5NgEcVh.js → CostCalculationGuidePage-f4ZGJRg3.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-BDQR0U4a.js → DashboardHelpDialog-DlN5EMmD.js} +249 -136
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-CGYcJ5EB.js → PricingSettingsDialog-v9zGRTlk.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-BRdoeTWk.js +3 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-Ckxk_izu.js → TraceabilityWorkspace-B_5u4Xnp.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{cost-monitor-BsMfGfQi.css → cost-monitor-C2AFYBu_.css} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-D7PrDZy9.js +68 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{dashboard-localization-jvdDfNKs.js → dashboard-localization-CF7B1Hjn.js} +90 -34
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-x8xxL9yW.js → icons-vendor-Cv3WBFIF.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-C4rLXrz_.js +2 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-CNOXIJHN.js → react-vendor-mHgsmxb6.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-CcpbpT1s.js → traceability-B0CPyEVq.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/index.html +6 -6
- package/templates/.agents/dashboard/apps/frontend/package.json +1 -1
- package/templates/.agents/dashboard/apps/frontend/src/AppDashboardContent.tsx +11 -1
- package/templates/.agents/dashboard/apps/frontend/src/AppLoadingBoundary.tsx +3 -2
- package/templates/.agents/dashboard/apps/frontend/src/AppLoadingPanels.tsx +1 -1
- package/templates/.agents/dashboard/apps/frontend/src/AppOverlays.tsx +1 -1
- package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsPage.tsx +9 -13
- package/templates/.agents/dashboard/apps/frontend/src/cost-monitor-population.test.tsx +4 -2
- package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +9 -5
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-api-settings.ts +3 -2
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +2 -2
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-identity.test.ts +3 -3
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-identity.ts +1 -1
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-localization.test.ts +2 -1
- package/templates/.agents/dashboard/apps/frontend/src/operations-period-render.test.ts +40 -3
- package/templates/.agents/dashboard/apps/frontend/src/project-settings-model.ts +12 -1
- package/templates/.agents/dashboard/apps/frontend/src/project-settings.test.ts +19 -0
- package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +1 -1
- package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.test.ts +3 -1
- package/templates/.agents/dashboard/apps/frontend/src/use-dashboard-app-model.tsx +14 -23
- package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.test.ts +3 -3
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.tsx +2 -3
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionTable.tsx +2 -6
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostGroupsTable.period-values.test.tsx +66 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostGroupsTable.tsx +29 -34
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorContent.tsx +2 -2
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.embedded.test.ts +11 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +1 -13
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostPeriodAverageCards.test.tsx +23 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostPeriodAverageCards.tsx +2 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableDisplay.ts +6 -11
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables-keeps-legacy-codex-identity-fields-blank.test.ts +6 -6
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +10 -12
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-group-page-totals.ts +23 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-group-period-values.tsx +34 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-embedded.css +0 -7
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-table-formatters.ts +4 -9
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-table-presentation.ts +2 -3
- package/templates/.agents/dashboard/modules/operations/package.json +1 -1
- package/templates/.agents/dashboard/modules/operations/src/react/DeveloperAttributionPanel.tsx +2 -12
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.helpers.tsx +2 -2
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.test.ts +1 -6
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +34 -36
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverviewCharts.tsx +12 -3
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverviewTopPanel.tsx +12 -14
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +4 -4
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageOverview.tsx +23 -4
- package/templates/.agents/dashboard/modules/operations/src/react/OverviewCostKpi.tsx +30 -2
- package/templates/.agents/dashboard/modules/operations/src/react/TaskDetailsDialog.tsx +2 -13
- package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkBoard.priority.test.ts +8 -1
- package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkBoard.tsx +8 -16
- package/templates/.agents/dashboard/modules/operations/src/react/WorkColumnState.tsx +34 -0
- package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.test.ts +1 -1
- package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.ts +1 -1
- package/templates/.agents/dashboard/modules/operations/src/react/operations-average-unmeasured.test.ts +10 -0
- package/templates/.agents/dashboard/modules/operations/src/react/operations-content-visibility.ts +3 -0
- package/templates/.agents/dashboard/modules/operations/src/react/operations-coverage-toast.test.ts +4 -3
- package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +12 -1
- package/templates/.agents/dashboard/modules/operations/src/react/operations-page-contract.ts +1 -0
- package/templates/.agents/dashboard/modules/operations/src/react/operations-skeleton.css +80 -0
- package/templates/.agents/dashboard/modules/operations/src/react/operations.css +2 -11
- package/templates/.agents/dashboard/modules/operations/src/react/overview-cost-card.test.tsx +36 -0
- package/templates/.agents/dashboard/modules/operations/src/react/overview-metric-format.test.ts +11 -0
- package/templates/.agents/dashboard/modules/operations/src/react/overview-metric-format.ts +28 -3
- package/templates/.agents/dashboard/modules/operations/src/react/overview-metric-stats.ts +44 -0
- package/templates/.agents/dashboard/modules/operations/src/react/work-card-label.ts +5 -0
- package/templates/.agents/dashboard/modules/operations/src/react/work-column-state.ts +11 -0
- package/templates/.agents/dashboard/modules/operations/src/react/work-item-filter.ts +13 -0
- package/templates/.agents/dashboard/modules/traceability/package.json +1 -1
- package/templates/.agents/dashboard/packages/branding/package.json +1 -1
- package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
- package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +173 -173
- package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +120 -120
- package/templates/.agents/dashboard/packages/local-runtime/package.json +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/server.mjs +173 -173
- package/templates/.agents/dashboard/packages/local-runtime/src/active-codex-telemetry.test.ts +31 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/active-codex-telemetry.ts +74 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/agent-catalog-settings.test.ts +15 -15
- package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.test.ts +2 -2
- package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.ts +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/server-identity.test.ts +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-synchronization.test.ts +25 -3
- package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-synchronization.ts +51 -16
- package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot.test.ts +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/server-ui-security.ts +37 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-workspace.ts +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +11 -33
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-rebuild.ts +12 -13
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.test.ts +71 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.ts +141 -25
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-worktree-sources.test.ts +60 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-rebuild-fingerprint-options.ts +13 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.mjs +26 -2
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.test.mjs +5 -0
- package/templates/.agents/dashboard/packages/ui/package.json +1 -1
- package/templates/.agents/dashboard/packages/ui/src/DashboardHeader.test.mjs +5 -0
- package/templates/.agents/dashboard/packages/ui/src/DashboardHeader.tsx +4 -4
- package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
- package/templates/.agents/dashboard/tests/e2e/playwright.config.ts +4 -0
- package/templates/.agents/dashboard/tests/e2e/specs/dashboard-performance-matrix.spec.ts +15 -23
- package/templates/.agents/dashboard/tests/e2e/specs/dashboard.spec.ts +1 -1
- package/templates/.agents/dashboard/tests/e2e/specs/performance-matrix-types.ts +15 -0
- package/templates/.agents/dashboard/tests/e2e/specs/performance-observability.ts +30 -0
- package/templates/.agents/dashboard/tests/e2e/specs/performance-work-row-identity.ts +6 -0
- package/templates/.agents/design/.zaip-managed.json +13 -9
- package/templates/.agents/design/apps/catalog/dist/assets/index-DkpQYoyC.js +72 -0
- package/templates/.agents/design/apps/catalog/dist/index.html +1 -1
- package/templates/.agents/design/apps/catalog/package.json +1 -1
- package/templates/.agents/design/apps/catalog/src/components/CostPopulationSpecimen.test.tsx +8 -4
- package/templates/.agents/design/apps/catalog/src/components/CostPopulationSpecimen.tsx +10 -3
- package/templates/.agents/design/apps/catalog/src/components/DashboardFiltersSpecimen.tsx +0 -15
- package/templates/.agents/design/apps/catalog/src/pages/ComponentsPage.tsx +3 -3
- package/templates/.agents/design/apps/catalog/src/stories/DashboardFilters.stories.tsx +0 -1
- package/templates/.agents/design/packages/local-runtime/package.json +1 -1
- package/templates/.agents/requirements/autonomous-assurance.md +1 -1
- package/templates/.agents/requirements/cloud-hostinger-autonomy.md +1 -1
- 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 +1 -1
- 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 +6 -6
- 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 +2 -2
- package/templates/.agents/rules/workflow.md +1 -1
- package/templates/.agents/runtime/VERSION +1 -1
- package/templates/.agents/runtime/bin/zaip.mjs +73 -64
- package/templates/.agents/runtime/checksums.sha256 +5 -5
- package/templates/.agents/runtime/manifest.json +1 -1
- package/templates/.agents/runtime/provenance.json +4 -4
- package/templates/.agents/runtime/sbom.cdx.json +1 -1
- package/templates/.agents/skills/zaip-skill-adapters/SKILL.md +1 -1
- package/templates/.agents/skills/zaip-skill-executar-fila-pronta/SKILL.md +7 -7
- package/templates/.agents/skills/zaip-skill-executar-fila-pronta/scripts/ready-queue-fence.mjs +32 -7
- package/templates/.agents/skills/zaip-skill-executar-fila-pronta/scripts/ready-queue-fence.test.mjs +134 -1
- package/templates/.agents/skills/zaip-skill-executar-fila-pronta/scripts/ready-queue-lease.mjs +57 -0
- package/templates/.agents/skills/zaip-skill-executar-fila-pronta/scripts/scheduled-ready-queue-contract.test.mjs +9 -6
- package/templates/.agents/skills/zaip-skill-execution/SKILL.md +1 -1
- package/templates/.agents/skills/zaip-skill-execution/references/runtime-governance.md +2 -2
- package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +5 -5
- package/templates/.agents/skills/zaip-skill-github-deploy/agents/openai.yaml +2 -2
- package/templates/.agents/skills/zaip-skill-github-deploy/references/deployment-workflow.md +5 -3
- package/templates/.agents/skills/zaip-skill-github-deploy/scripts/github-deploy-contract.test.mjs +40 -5
- package/templates/.agents/skills/zaip-skill-instalar-agendamento/SKILL.md +2 -2
- package/templates/.agents/skills/zaip-skill-release-qualification/SKILL.md +6 -0
- package/templates/.agents/skills/zaip-skill-release-qualification/references/local-preparation.md +54 -6
- package/templates/.agents/zaip-aios/README.md +4 -4
- package/templates/.agents/zaip-aios/VERSION +1 -1
- package/templates/.agents/zaip-aios/guides/01-primeiros-passos.md +4 -3
- package/templates/.agents/zaip-aios/guides/03-tasks.md +5 -4
- package/templates/.agents/zaip-aios/guides/04-specs.md +4 -1
- package/templates/.agents/zaip-aios/guides/05-prds.md +7 -3
- package/templates/.agents/zaip-aios/guides/06-execucao.md +9 -4
- package/templates/.agents/zaip-aios/guides/09-agentes-e-squads.md +9 -5
- package/templates/.agents/zaip-aios/guides/11-observabilidade-e-custos.md +10 -2
- package/templates/.agents/zaip-aios/guides/12-instalacao-e-upgrade.md +10 -5
- package/templates/.agents/zaip-aios/guides/13-boas-praticas.md +12 -1
- package/templates/.agents/zaip-aios/guides/14-troubleshooting.md +3 -1
- package/templates/.agents/zaip-aios/guides/16-lifecycle-e-reconciliacao.md +12 -7
- package/templates/.agents/zaip-aios/guides/17-como-o-custo-e-calculado.md +1 -1
- package/templates/.agents/zaip-aios/guides/18-catalogo-de-agentes.md +5 -1
- package/templates/.agents/zaip-aios/guides/19-assurance-e-autonomia.md +19 -15
- package/templates/.agents/zaip-aios/guides/20-instalacao-detalhada.md +13 -9
- package/templates/.agents/zaip-aios/guides/21-telemetria-monitor-custos.md +4 -3
- package/templates/.agents/zaip-aios/guides/22-fluxos-e-roteamento.md +9 -7
- package/templates/.agents/zaip-aios/guides/23-orquestracao-de-modelos.md +40 -25
- package/templates/.agents/zaip-aios/guides/24-calculo-de-custos-openai.md +8 -8
- package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +14 -5
- package/templates/.agents/zaip-aios/guides/27-telemetria-git-native.md +6 -0
- package/templates/.agents/zaip-aios/guides/28-lifecycle-completo.md +129 -11
- package/templates/template-manifest.json +310 -218
- package/templates/tsconfig.base.json +22 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-OulA4CoX.js +0 -3
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-j3aUYH5G.js +0 -68
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-CqfSgtk9.js +0 -2
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
1
2
|
import { createHash } from "node:crypto";
|
|
2
3
|
import { readdir, readFile, stat } from "node:fs/promises";
|
|
3
4
|
import { join, relative, resolve } from "node:path";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
|
|
7
|
+
const execFileAsync = promisify(execFile);
|
|
4
8
|
|
|
5
9
|
const textExtensions = new Set([".json", ".jsonl", ".md", ".yaml", ".yml", ".txt"]);
|
|
6
10
|
|
|
@@ -45,8 +49,141 @@ export type SqliteReadModelSourceCheckpoint = Omit<SqliteReadModelSourceCandidat
|
|
|
45
49
|
type FingerprintOptions = {
|
|
46
50
|
previous?: ReadonlyMap<string, SqliteReadModelSourceCheckpoint>;
|
|
47
51
|
verifyContent?: boolean;
|
|
52
|
+
/** Explicit roots allow deterministic testing without a Git checkout. */
|
|
53
|
+
sourceRoots?: readonly string[] | undefined;
|
|
48
54
|
};
|
|
49
55
|
|
|
56
|
+
export async function dashboardCanonicalSourceRoots(workspaceRoot: string): Promise<string[]> {
|
|
57
|
+
const primary = resolve(workspaceRoot);
|
|
58
|
+
const gitRoot = await execFileAsync("git", ["rev-parse", "--show-toplevel"], {
|
|
59
|
+
cwd: primary,
|
|
60
|
+
encoding: "utf8",
|
|
61
|
+
windowsHide: true,
|
|
62
|
+
timeout: 5_000,
|
|
63
|
+
}).catch(() => ({ stdout: "" }));
|
|
64
|
+
if (resolve(gitRoot.stdout.trim()).toLowerCase() !== primary.toLowerCase()) return [primary];
|
|
65
|
+
const output = await execFileAsync("git", ["worktree", "list", "--porcelain"], {
|
|
66
|
+
cwd: primary,
|
|
67
|
+
encoding: "utf8",
|
|
68
|
+
windowsHide: true,
|
|
69
|
+
timeout: 15_000,
|
|
70
|
+
}).catch(() => ({ stdout: "" }));
|
|
71
|
+
// Git supplies only worktrees registered to this repository. Ignore unrelated
|
|
72
|
+
// sibling folders and ordinary task workspaces; they are not Codex worktrees.
|
|
73
|
+
const registeredRoots = output.stdout
|
|
74
|
+
.split(/\r?\n/u)
|
|
75
|
+
.filter((line) => line.startsWith("worktree "))
|
|
76
|
+
.map((line) => resolve(line.slice(9).trim()));
|
|
77
|
+
const codexRoots = registeredRoots.filter(isCodexManagedWorktreeRoot);
|
|
78
|
+
// The first registered checkout is the repository's main worktree and may
|
|
79
|
+
// contain canonical history absent from a Codex worktree's branch.
|
|
80
|
+
return [...new Set([primary, ...registeredRoots.slice(0, 1), ...codexRoots])];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function isCodexManagedWorktreeRoot(root: string): boolean {
|
|
84
|
+
// Internal Task workspaces can sit below a managed checkout but are not
|
|
85
|
+
// separate Codex checkouts. Avoid re-scanning that nested copy on every
|
|
86
|
+
// dashboard refresh.
|
|
87
|
+
return /[\\/]\.codex[\\/]worktrees(?:[\\/][^\\/]+){1,2}$/iu.test(root);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function canonicalRevision(content: string, source: string): [string, number, number] {
|
|
91
|
+
if (source.endsWith(".jsonl")) {
|
|
92
|
+
const dates = [...content.matchAll(/"occurred_at"\s*:\s*"([^"]+)"/gu)];
|
|
93
|
+
return [
|
|
94
|
+
dates.reduce((latest, match) => ((match[1] ?? "") > latest ? (match[1] ?? "") : latest), ""),
|
|
95
|
+
dates.length,
|
|
96
|
+
content.length,
|
|
97
|
+
];
|
|
98
|
+
}
|
|
99
|
+
const updated = /^updated_at:\s*([^\r\n]+)/mu.exec(content)?.[1]?.trim() ?? "";
|
|
100
|
+
const created = /^created_at:\s*([^\r\n]+)/mu.exec(content)?.[1]?.trim() ?? "";
|
|
101
|
+
const revision = Number(/^revision:\s*(\d+)/mu.exec(content)?.[1] ?? 0);
|
|
102
|
+
return [updated || created, revision, content.length];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function selectCanonicalSources(
|
|
106
|
+
roots: readonly string[],
|
|
107
|
+
): Promise<Array<{ path: string; source: string }>> {
|
|
108
|
+
const locations = new Map<string, string[]>();
|
|
109
|
+
for (const [index, root] of roots.entries()) {
|
|
110
|
+
const directories =
|
|
111
|
+
index === 0
|
|
112
|
+
? [
|
|
113
|
+
".agents/config",
|
|
114
|
+
...[
|
|
115
|
+
"tasks",
|
|
116
|
+
"specs",
|
|
117
|
+
"prds",
|
|
118
|
+
"runs",
|
|
119
|
+
"executions",
|
|
120
|
+
"changes",
|
|
121
|
+
"lifecycle/historical-developer-attribution",
|
|
122
|
+
].flatMap((kind) => [`.agents/data/${kind}`, `.agents/records/${kind}`]),
|
|
123
|
+
]
|
|
124
|
+
: [
|
|
125
|
+
"tasks",
|
|
126
|
+
"specs",
|
|
127
|
+
"prds",
|
|
128
|
+
"runs",
|
|
129
|
+
"executions",
|
|
130
|
+
"changes",
|
|
131
|
+
"lifecycle/historical-developer-attribution",
|
|
132
|
+
].map((kind) => `.agents/records/${kind}`);
|
|
133
|
+
const paths = (
|
|
134
|
+
await Promise.all(directories.map((directory) => listFiles(resolve(root, directory))))
|
|
135
|
+
).flat();
|
|
136
|
+
for (const path of paths) {
|
|
137
|
+
const source = relative(root, path).replaceAll("\\", "/");
|
|
138
|
+
if (
|
|
139
|
+
!textExtensions.has(path.slice(path.lastIndexOf(".")).toLowerCase()) ||
|
|
140
|
+
!isDashboardCanonicalSource(source)
|
|
141
|
+
)
|
|
142
|
+
continue;
|
|
143
|
+
const peers = locations.get(source) ?? [];
|
|
144
|
+
peers.push(path);
|
|
145
|
+
locations.set(source, peers);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const selected: Array<{ path: string; source: string }> = [];
|
|
149
|
+
const entries = [...locations.entries()];
|
|
150
|
+
for (let offset = 0; offset < entries.length; offset += 32) {
|
|
151
|
+
selected.push(
|
|
152
|
+
...(await Promise.all(
|
|
153
|
+
entries.slice(offset, offset + 32).map(async ([source, paths]) => {
|
|
154
|
+
const firstPath = paths[0];
|
|
155
|
+
if (firstPath === undefined) throw new Error(`No canonical source for ${source}`);
|
|
156
|
+
if (paths.length === 1) return { source, path: firstPath };
|
|
157
|
+
// Worktree checkout mtimes do not represent canonical record recency.
|
|
158
|
+
// Compare embedded revision timestamps and prefer the first registered
|
|
159
|
+
// source on an exact tie, so repeated scans remain deterministic.
|
|
160
|
+
const revisions = await Promise.all(
|
|
161
|
+
paths.map(async (path) => canonicalRevision(await readFile(path, "utf8"), source)),
|
|
162
|
+
);
|
|
163
|
+
let winner = 0;
|
|
164
|
+
for (let index = 1; index < paths.length; index += 1) {
|
|
165
|
+
const left = revisions[index];
|
|
166
|
+
const right = revisions[winner];
|
|
167
|
+
if (left === undefined || right === undefined)
|
|
168
|
+
throw new Error(`Incomplete canonical revisions for ${source}`);
|
|
169
|
+
if (
|
|
170
|
+
left[0] > right[0] ||
|
|
171
|
+
(left[0] === right[0] &&
|
|
172
|
+
(left[1] > right[1] || (left[1] === right[1] && left[2] > right[2])))
|
|
173
|
+
)
|
|
174
|
+
winner = index;
|
|
175
|
+
}
|
|
176
|
+
const selectedPath = paths[winner];
|
|
177
|
+
if (selectedPath === undefined)
|
|
178
|
+
throw new Error(`No selected canonical source for ${source}`);
|
|
179
|
+
return { source, path: selectedPath };
|
|
180
|
+
}),
|
|
181
|
+
)),
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
return selected.sort((left, right) => left.source.localeCompare(right.source));
|
|
185
|
+
}
|
|
186
|
+
|
|
50
187
|
export async function sourceFingerprint(
|
|
51
188
|
workspaceRoot: string,
|
|
52
189
|
options: FingerprintOptions = {},
|
|
@@ -56,29 +193,9 @@ export async function sourceFingerprint(
|
|
|
56
193
|
hashedFiles: number;
|
|
57
194
|
reusedFiles: number;
|
|
58
195
|
}> {
|
|
59
|
-
const candidates = (
|
|
60
|
-
await
|
|
61
|
-
|
|
62
|
-
".agents/config",
|
|
63
|
-
...[
|
|
64
|
-
"tasks",
|
|
65
|
-
"specs",
|
|
66
|
-
"prds",
|
|
67
|
-
"runs",
|
|
68
|
-
"executions",
|
|
69
|
-
"changes",
|
|
70
|
-
"lifecycle/historical-developer-attribution",
|
|
71
|
-
].flatMap((kind) => [`.agents/data/${kind}`, `.agents/records/${kind}`]),
|
|
72
|
-
].map((root) => listFiles(resolve(workspaceRoot, root))),
|
|
73
|
-
)
|
|
74
|
-
)
|
|
75
|
-
.flat()
|
|
76
|
-
.filter(
|
|
77
|
-
(path) =>
|
|
78
|
-
textExtensions.has(path.slice(path.lastIndexOf(".")).toLowerCase()) &&
|
|
79
|
-
isDashboardCanonicalSource(relative(workspaceRoot, path).replaceAll("\\", "/")),
|
|
80
|
-
)
|
|
81
|
-
.sort();
|
|
196
|
+
const candidates = await selectCanonicalSources(
|
|
197
|
+
options.sourceRoots ?? (await dashboardCanonicalSourceRoots(workspaceRoot)),
|
|
198
|
+
);
|
|
82
199
|
const candidatesWithMetadata: SqliteReadModelSourceCandidate[] = [];
|
|
83
200
|
let hashedFiles = 0;
|
|
84
201
|
let reusedFiles = 0;
|
|
@@ -91,8 +208,7 @@ export async function sourceFingerprint(
|
|
|
91
208
|
candidatesWithMetadata.push(
|
|
92
209
|
...(
|
|
93
210
|
await Promise.all(
|
|
94
|
-
candidates.slice(offset, offset + 32).map(async (candidate) => {
|
|
95
|
-
const source = relative(workspaceRoot, candidate).replaceAll("\\", "/");
|
|
211
|
+
candidates.slice(offset, offset + 32).map(async ({ path: candidate, source }) => {
|
|
96
212
|
try {
|
|
97
213
|
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
98
214
|
const metadata = await stat(candidate);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { DatabaseSync } from "node:sqlite";
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import { rebuildSqliteReadModel } from "./sqlite-read-model.js";
|
|
6
|
+
|
|
7
|
+
const tempRoot = join(
|
|
8
|
+
resolve(import.meta.dirname, "../../../../../.."),
|
|
9
|
+
".tmp",
|
|
10
|
+
"sqlite-read-model-tests",
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
describe("SQLite worktree source aggregation", () => {
|
|
14
|
+
it("materializes recent worktree Tasks once and refreshes when a sibling changes", async () => {
|
|
15
|
+
await mkdir(tempRoot, { recursive: true });
|
|
16
|
+
const root = await mkdtemp(join(tempRoot, "fixture-"));
|
|
17
|
+
const sibling = await mkdtemp(join(tempRoot, "fixture-"));
|
|
18
|
+
try {
|
|
19
|
+
await mkdir(join(root, ".agents/config"), { recursive: true });
|
|
20
|
+
await mkdir(join(root, ".agents/records/tasks"), { recursive: true });
|
|
21
|
+
await mkdir(join(sibling, ".agents/records/tasks"), { recursive: true });
|
|
22
|
+
await writeFile(join(root, ".agents/config/project.yaml"), "zaip:\n enabled: true\n");
|
|
23
|
+
const oldRecord =
|
|
24
|
+
"---\nid: TASK-DUPLICATE\ntitle: Old\nstatus: executing\ncreated_at: 2026-09-17T10:00:00Z\nupdated_at: 2026-09-17T10:00:00Z\n---\n";
|
|
25
|
+
const newRecord = oldRecord.replace("Old", "Recent").replaceAll("2026-09-17", "2026-09-23");
|
|
26
|
+
await writeFile(join(root, ".agents/records/tasks/TASK-DUPLICATE.md"), oldRecord);
|
|
27
|
+
await writeFile(join(sibling, ".agents/records/tasks/TASK-DUPLICATE.md"), newRecord);
|
|
28
|
+
await writeFile(
|
|
29
|
+
join(sibling, ".agents/records/tasks/TASK-NEW.md"),
|
|
30
|
+
newRecord.replaceAll("TASK-DUPLICATE", "TASK-NEW"),
|
|
31
|
+
);
|
|
32
|
+
const options = { sourceRoots: [root, sibling] };
|
|
33
|
+
await rebuildSqliteReadModel(root, options);
|
|
34
|
+
const database = new DatabaseSync(join(root, ".local/sqlite/zaip-aios-dashboard.sqlite"), {
|
|
35
|
+
readOnly: true,
|
|
36
|
+
});
|
|
37
|
+
try {
|
|
38
|
+
expect(
|
|
39
|
+
database.prepare("SELECT count(*) AS n FROM zaip_vw_task_summary").get(),
|
|
40
|
+
).toMatchObject({ n: 2 });
|
|
41
|
+
expect(
|
|
42
|
+
database
|
|
43
|
+
.prepare("SELECT task_count FROM zaip_vw_daily_aggregates WHERE day=?")
|
|
44
|
+
.get("2026-09-23"),
|
|
45
|
+
).toMatchObject({ task_count: 2 });
|
|
46
|
+
} finally {
|
|
47
|
+
database.close();
|
|
48
|
+
}
|
|
49
|
+
await writeFile(
|
|
50
|
+
join(sibling, ".agents/records/tasks/TASK-THIRD.md"),
|
|
51
|
+
newRecord.replaceAll("TASK-DUPLICATE", "TASK-THIRD"),
|
|
52
|
+
);
|
|
53
|
+
const refreshed = await rebuildSqliteReadModel(root, options);
|
|
54
|
+
expect(refreshed.refresh.added_sources).toBe(1);
|
|
55
|
+
} finally {
|
|
56
|
+
await rm(root, { recursive: true, force: true });
|
|
57
|
+
await rm(sibling, { recursive: true, force: true });
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-rebuild-fingerprint-options.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { persistedSourceCheckpoint } from "./sqlite-read-model-schema.js";
|
|
2
|
+
|
|
3
|
+
export interface SqliteRebuildOptions {
|
|
4
|
+
forceCanonical?: boolean;
|
|
5
|
+
preferExisting?: boolean;
|
|
6
|
+
sourceRoots?: readonly string[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function rebuildFingerprintOptions(path: string, options: SqliteRebuildOptions) {
|
|
10
|
+
return options.forceCanonical
|
|
11
|
+
? { verifyContent: true, sourceRoots: options.sourceRoots }
|
|
12
|
+
: { previous: persistedSourceCheckpoint(path), sourceRoots: options.sourceRoots };
|
|
13
|
+
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
1
2
|
import { createServer as createHttpServer } from "node:http";
|
|
2
3
|
import { basename } from "node:path";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
3
7
|
|
|
4
8
|
const escapeHtml = (text) =>
|
|
5
9
|
String(text).replace(
|
|
@@ -8,6 +12,21 @@ const escapeHtml = (text) =>
|
|
|
8
12
|
({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[character],
|
|
9
13
|
);
|
|
10
14
|
|
|
15
|
+
async function githubRepository(workspaceRoot) {
|
|
16
|
+
if (!workspaceRoot) return null;
|
|
17
|
+
try {
|
|
18
|
+
const { stdout } = await execFileAsync(
|
|
19
|
+
"git",
|
|
20
|
+
["-C", workspaceRoot, "remote", "get-url", "origin"],
|
|
21
|
+
{ encoding: "utf8", windowsHide: true, timeout: 1500 },
|
|
22
|
+
);
|
|
23
|
+
const match = stdout.trim().match(/github\.com(?::|\/)([^/\s]+)\/([^/\s]+?)(?:\.git)?$/i);
|
|
24
|
+
return match ? `${match[1]}/${match[2]}` : null;
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
11
30
|
export async function createDashboardLaunchPage({
|
|
12
31
|
port,
|
|
13
32
|
host,
|
|
@@ -16,6 +35,10 @@ export async function createDashboardLaunchPage({
|
|
|
16
35
|
delay,
|
|
17
36
|
workspaceRoot = "",
|
|
18
37
|
}) {
|
|
38
|
+
const repository = await githubRepository(workspaceRoot);
|
|
39
|
+
const repositoryBadge = repository
|
|
40
|
+
? `<a class="repository-badge" href="https://github.com/${escapeHtml(repository)}" target="_blank" rel="noopener noreferrer" aria-label="Repositório GitHub ${escapeHtml(repository)}"><svg aria-hidden="true" viewBox="0 0 16 16" fill="currentColor"><path d="M8 0a8 8 0 0 0-2.53 15.59c.4.07.55-.17.55-.39v-1.5c-2.23.49-2.7-.95-2.7-.95-.36-.93-.89-1.18-.89-1.18-.73-.5.05-.49.05-.49.8.06 1.23.82 1.23.82.71 1.22 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.9-3.64-3.95 0-.87.31-1.58.82-2.14-.08-.2-.36-1.01.08-2.11 0 0 .67-.21 2.2.82a7.67 7.67 0 0 1 4 0c1.53-1.03 2.2-.82 2.2-.82.44 1.1.16 1.91.08 2.11.51.56.82 1.27.82 2.14 0 3.06-1.87 3.75-3.65 3.95.28.24.53.71.53 1.44v2.27c0 .22.14.47.55.39A8 8 0 0 0 8 0Z"/></svg>${escapeHtml(repository)}</a>`
|
|
41
|
+
: "";
|
|
19
42
|
let redirectUrl = null;
|
|
20
43
|
let failure = null;
|
|
21
44
|
let progress = {
|
|
@@ -86,17 +109,18 @@ export async function createDashboardLaunchPage({
|
|
|
86
109
|
<head>
|
|
87
110
|
<meta charset="utf-8">
|
|
88
111
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
89
|
-
<title>Dashboard
|
|
112
|
+
<title>Dashboard ZAIP AIOS</title>
|
|
90
113
|
<style>
|
|
91
114
|
:root{color-scheme:dark;font-family:Inter,system-ui,sans-serif;background:#010610;color:#f1f5f9}
|
|
92
115
|
*{box-sizing:border-box}body{margin:0;background:#010610}.launch-overlay{position:fixed;inset:0;width:100vw;height:100vh;display:grid;place-items:center;padding:clamp(18px,5vw,72px);background:radial-gradient(circle at 50% 35%,rgba(0,176,240,.11),transparent 42%),#010610}
|
|
93
116
|
.progress{width:min(100%,760px);padding:clamp(24px,4vw,42px);border:1px solid rgba(125,211,252,.2);border-radius:20px;background:rgba(3,9,22,.94);box-shadow:0 24px 80px rgba(0,0,0,.45);backdrop-filter:blur(10px)}.progress strong,.progress span:not(.handoff):not(.failure){display:block}.progress strong{font-size:clamp(1.05rem,2vw,1.35rem)}.progress span{color:#b6c6db;font-size:clamp(.88rem,1.5vw,1rem);margin-top:7px}.track{position:relative;height:9px;margin-top:20px;border-radius:999px;background:#172033;overflow:hidden}.track::after{content:"";position:absolute;z-index:2;inset:0;background:linear-gradient(90deg,transparent 0%,rgba(224,242,254,.14) 35%,rgba(224,242,254,.8) 50%,rgba(224,242,254,.14) 65%,transparent 100%);transform:translateX(-100%);animation:launch-activity 1.35s ease-in-out infinite;pointer-events:none}.progress.terminal-failure .track::after{animation:none;transform:none;background:rgba(254,202,202,.2)}.progress.terminal-failure .bar{background:#f87171}.bar{position:relative;z-index:1;height:100%;width:4%;border-radius:inherit;background:linear-gradient(90deg,#38bdf8,#818cf8);transition:width .35s ease}@keyframes launch-activity{to{transform:translateX(100%)}}@media (prefers-reduced-motion:reduce){.track::after{animation:none;transform:none;background:linear-gradient(90deg,transparent 0%,rgba(224,242,254,.2) 50%,transparent 100%)}}.handoff,.failure{display:none;margin-top:16px;color:#dbeafe}.failure{color:#fecaca}
|
|
94
117
|
.activity{min-height:1.3em}.steps{display:grid;gap:7px;max-height:12.5rem;overflow:auto;margin:18px 0 0;padding:0;list-style:none}.steps li{position:relative;padding-left:20px;color:#94a3b8;font-size:.82rem}.steps li::before{content:"";position:absolute;left:1px;top:.4em;width:8px;height:8px;border-radius:50%;background:#475569}.steps li[data-state="active"]{color:#dbeafe}.steps li[data-state="active"]::before{background:#38bdf8;box-shadow:0 0 0 4px rgba(56,189,248,.16)}.progress.terminal-failure .steps li[data-state="active"]::before{background:#f87171}@media (prefers-reduced-motion:reduce){.bar{transition:none}}
|
|
118
|
+
.launch-heading{margin-bottom:18px}.launch-heading h1{margin:0;font-size:clamp(1.2rem,2.4vw,1.55rem)}.workspace-identity{display:flex;flex-wrap:wrap;align-items:center;gap:10px}.repository-badge{display:inline-flex;align-items:center;gap:7px;max-width:100%;padding:6px 10px;border-radius:999px;background:#f8fafc;color:#0f172a;font-size:.78rem;font-weight:700;text-decoration:none;overflow-wrap:anywhere}.repository-badge svg{width:15px;height:15px;flex:none}.repository-badge:focus-visible{outline:2px solid #7dd3fc;outline-offset:3px}
|
|
95
119
|
</style>
|
|
96
120
|
</head>
|
|
97
121
|
<body>
|
|
98
122
|
<main class="launch-overlay" aria-label="Preparando dashboard" aria-busy="true">
|
|
99
|
-
<section class="progress" aria-live="polite" role="status"><div aria-label="Workspace" style="margin-bottom:20px;overflow-wrap:anywhere"><strong>${escapeHtml(basename(workspaceRoot))}</strong><span>${escapeHtml(workspaceRoot)}</span></div><strong id="phase">Iniciando o launcher local</strong><span id="detail">Abrindo a página de preparação.</span><span class="activity" id="activity" aria-hidden="true">Atividade em andamento.</span><div class="track" id="track" role="progressbar" aria-label="Preparação em andamento" aria-valuemin="0" aria-valuemax="100" aria-valuenow="4" aria-valuetext="Iniciando o launcher local"><div class="bar" id="bar"></div></div><ol class="steps" id="steps" aria-label="Etapas de preparação"><li data-state="active">Iniciando o launcher local</li></ol><span class="handoff" id="handoff">O dashboard está pronto. Abrindo a tela principal automaticamente…</span><span class="failure" id="failure" role="alert"></span></section>
|
|
123
|
+
<section class="progress" aria-live="polite" role="status"><div class="launch-heading"><h1>Dashboard ZAIP AIOS</h1></div><div aria-label="Workspace" style="margin-bottom:20px;overflow-wrap:anywhere"><div class="workspace-identity"><strong>${escapeHtml(basename(workspaceRoot))}</strong>${repositoryBadge}</div><span>${escapeHtml(workspaceRoot)}</span></div><strong id="phase">Iniciando o launcher local</strong><span id="detail">Abrindo a página de preparação.</span><span class="activity" id="activity" aria-hidden="true">Atividade em andamento.</span><div class="track" id="track" role="progressbar" aria-label="Preparação em andamento" aria-valuemin="0" aria-valuemax="100" aria-valuenow="4" aria-valuetext="Iniciando o launcher local"><div class="bar" id="bar"></div></div><ol class="steps" id="steps" aria-label="Etapas de preparação"><li data-state="active">Iniciando o launcher local</li></ol><span class="handoff" id="handoff">O dashboard está pronto. Abrindo a tela principal automaticamente…</span><span class="failure" id="failure" role="alert"></span></section>
|
|
100
124
|
</main>
|
|
101
125
|
<script>
|
|
102
126
|
let handoffTarget=null,progressRequestInFlight=false,terminalFailure=false,lastProgressPercent=4,compilationStartedAt=null,compilationDetail="",compilationTicker=null,activeStepKey="",activeStepStartedAt=Date.now();
|
package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.test.mjs
CHANGED
|
@@ -12,6 +12,9 @@ describe("dashboard launch page", () => {
|
|
|
12
12
|
|
|
13
13
|
expect(page.status).toBe(200);
|
|
14
14
|
const html = await page.text();
|
|
15
|
+
expect(html).toContain("<h1>Dashboard ZAIP AIOS</h1>");
|
|
16
|
+
expect(html).toContain('class="repository-badge"');
|
|
17
|
+
expect(html).toContain("zaip-ai/zaip-aios</a>");
|
|
15
18
|
expect(html).toContain('class="launch-overlay"');
|
|
16
19
|
expect(html).toContain("position:fixed;inset:0;width:100vw;height:100vh");
|
|
17
20
|
expect(html).toContain("display:grid;place-items:center");
|
|
@@ -69,6 +72,8 @@ describe("dashboard launch page", () => {
|
|
|
69
72
|
);
|
|
70
73
|
await page.route("**/api/v2/health", () => new Promise(() => {}));
|
|
71
74
|
await page.goto(`http://${host}:${launchPage.port}/?token=temporary`);
|
|
75
|
+
if (process.env.ZAIP_LAUNCH_SCREENSHOT_PATH)
|
|
76
|
+
await page.screenshot({ path: process.env.ZAIP_LAUNCH_SCREENSHOT_PATH });
|
|
72
77
|
|
|
73
78
|
await expect
|
|
74
79
|
.poll(() =>
|
|
@@ -2,6 +2,7 @@ import { readFileSync } from "node:fs";
|
|
|
2
2
|
import { describe, expect, it } from "vitest";
|
|
3
3
|
|
|
4
4
|
const styles = readFileSync(new URL("ui.css", import.meta.url), "utf8");
|
|
5
|
+
const headerSource = readFileSync(new URL("DashboardHeader.tsx", import.meta.url), "utf8");
|
|
5
6
|
|
|
6
7
|
describe("DashboardHeader", () => {
|
|
7
8
|
it("optically balances the repository badge horizontal spacing", () => {
|
|
@@ -9,6 +10,10 @@ describe("DashboardHeader", () => {
|
|
|
9
10
|
expect(rule).toContain("padding-block: 0.3rem");
|
|
10
11
|
expect(rule).toContain("padding-inline: 0.6rem 0.72rem");
|
|
11
12
|
});
|
|
13
|
+
it("labels the timestamp as telemetry rather than overall snapshot freshness", () => {
|
|
14
|
+
expect(headerSource).toContain('updated: "Última telemetria"');
|
|
15
|
+
expect(headerSource).toContain('waiting: "Sem telemetria medida"');
|
|
16
|
+
});
|
|
12
17
|
});
|
|
13
18
|
|
|
14
19
|
function cssRule(source, selector) {
|
|
@@ -38,8 +38,8 @@ export function DashboardHeader({
|
|
|
38
38
|
refresh: "Atualizar",
|
|
39
39
|
refreshing: "Atualizando…",
|
|
40
40
|
settings: "Configurações",
|
|
41
|
-
updated: "
|
|
42
|
-
waiting: "
|
|
41
|
+
updated: "Última telemetria",
|
|
42
|
+
waiting: "Sem telemetria medida",
|
|
43
43
|
}
|
|
44
44
|
: {
|
|
45
45
|
filters: "Filters",
|
|
@@ -47,8 +47,8 @@ export function DashboardHeader({
|
|
|
47
47
|
refresh: "Refresh",
|
|
48
48
|
refreshing: "Refreshing…",
|
|
49
49
|
settings: "Settings",
|
|
50
|
-
updated: "
|
|
51
|
-
waiting: "
|
|
50
|
+
updated: "Last telemetry",
|
|
51
|
+
waiting: "No measured telemetry",
|
|
52
52
|
};
|
|
53
53
|
const updatedLabel =
|
|
54
54
|
lastUpdatedAt === null
|
|
@@ -42,6 +42,10 @@ export default defineConfig({
|
|
|
42
42
|
// Match the Windows launcher: first paint uses the latest validated
|
|
43
43
|
// immutable seed while canonical refresh work stays off the served path.
|
|
44
44
|
ZAIP_SQLITE_PREFER_LAST_VALID_SEED: "1",
|
|
45
|
+
// Browser qualification reads a fixed Git candidate. Live host capture
|
|
46
|
+
// would mutate its canonical records during the clean-worktree gate.
|
|
47
|
+
// Source-watch/capture behavior has separate runtime tests.
|
|
48
|
+
ZAIP_DASHBOARD_WATCH_SOURCES: "0",
|
|
45
49
|
// Keep pre-bind progress observable if the web-server health gate times out.
|
|
46
50
|
ZAIP_DASHBOARD_LAUNCH_PROGRESS: "1",
|
|
47
51
|
},
|
|
@@ -1,24 +1,13 @@
|
|
|
1
1
|
import { expect, type Locator, type Page, test } from "@playwright/test";
|
|
2
2
|
import { exportRowIdentity } from "./export-row-identity.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
request_count: number;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
type SqlitePage = {
|
|
13
|
-
offset: number;
|
|
14
|
-
limit: number;
|
|
15
|
-
total_count: number;
|
|
16
|
-
has_more: boolean;
|
|
17
|
-
rows: readonly Record<string, unknown>[];
|
|
18
|
-
};
|
|
3
|
+
import type { Metric, SqlitePage } from "./performance-matrix-types.js";
|
|
4
|
+
import {
|
|
5
|
+
assertPerformanceWarnings,
|
|
6
|
+
observePerformanceWarnings,
|
|
7
|
+
} from "./performance-observability.js";
|
|
8
|
+
import { workRowIdentities } from "./performance-work-row-identity.js";
|
|
19
9
|
|
|
20
10
|
type PeriodQuery = { from: string | null; to: string | null };
|
|
21
|
-
|
|
22
11
|
const costViews = [
|
|
23
12
|
["Diário", "daily", "cost_monitor_daily"],
|
|
24
13
|
["Mensal", "monthly", "cost_monitor_monthly"],
|
|
@@ -91,11 +80,12 @@ test("measures Cost, Operation and Traceability surfaces without full snapshot h
|
|
|
91
80
|
page.on("requestfinished", finishApiRequest);
|
|
92
81
|
page.on("requestfailed", finishApiRequest);
|
|
93
82
|
page.on("response", (response) => {
|
|
83
|
+
const startedAt = requestStartedAt.get(response.request());
|
|
84
|
+
const elapsed = startedAt === undefined ? undefined : performance.now() - startedAt;
|
|
94
85
|
if (process.env.ZAIP_E2E_LOG_TIMINGS === "1") {
|
|
95
|
-
|
|
96
|
-
if (startedAt !== undefined) {
|
|
86
|
+
if (elapsed !== undefined) {
|
|
97
87
|
console.log(
|
|
98
|
-
`DASHBOARD_API_TIMING ${Math.round(
|
|
88
|
+
`DASHBOARD_API_TIMING ${Math.round(elapsed)}ms ${response.status()} ${response.url()}`,
|
|
99
89
|
);
|
|
100
90
|
}
|
|
101
91
|
}
|
|
@@ -115,6 +105,7 @@ test("measures Cost, Operation and Traceability surfaces without full snapshot h
|
|
|
115
105
|
}
|
|
116
106
|
});
|
|
117
107
|
page.on("pageerror", (error) => pageErrors.push(error.message));
|
|
108
|
+
const performanceWarnings = observePerformanceWarnings(page, requestStartedAt);
|
|
118
109
|
|
|
119
110
|
await installExportSink(page);
|
|
120
111
|
await openDashboard(page);
|
|
@@ -156,6 +147,7 @@ test("measures Cost, Operation and Traceability surfaces without full snapshot h
|
|
|
156
147
|
await verifyCompleteWorkListExport(page);
|
|
157
148
|
|
|
158
149
|
expect(pageErrors).toEqual([]);
|
|
150
|
+
assertPerformanceWarnings(performanceWarnings);
|
|
159
151
|
expect(apiFailures).toEqual([]);
|
|
160
152
|
expect(idleSnapshots).toEqual([]);
|
|
161
153
|
console.log(`DASHBOARD_PERFORMANCE_MATRIX ${JSON.stringify(metrics)}`);
|
|
@@ -359,7 +351,7 @@ async function assertWorkListPagination(
|
|
|
359
351
|
const totalText = await pager.locator("output").textContent();
|
|
360
352
|
const total = Number(totalText?.match(/de\s+(\d+)/)?.[1] ?? 0);
|
|
361
353
|
if (total > 10) {
|
|
362
|
-
const firstPageRows = await
|
|
354
|
+
const firstPageRows = await workRowIdentities(rows);
|
|
363
355
|
const next = pager.getByRole("button", { name: "Próxima" });
|
|
364
356
|
await expect(next).toBeEnabled();
|
|
365
357
|
await assertNoFullscreenOverlay(page);
|
|
@@ -369,7 +361,7 @@ async function assertWorkListPagination(
|
|
|
369
361
|
await expect(pager.locator("output")).toContainText("11–", { timeout: 10_000 });
|
|
370
362
|
await expect(rows).toHaveCount(Math.min(10, total - 10), { timeout: 10_000 });
|
|
371
363
|
await expect(surface).not.toHaveAttribute("aria-busy", "true", { timeout: 10_000 });
|
|
372
|
-
expect(await
|
|
364
|
+
expect(await workRowIdentities(rows)).not.toEqual(firstPageRows);
|
|
373
365
|
// Filter hydration must not reset an already loaded page after navigation.
|
|
374
366
|
await waitForApiQuiet(matchesSelection);
|
|
375
367
|
await expect(pager.locator("output")).toContainText("11–", { timeout: 10_000 });
|
|
@@ -381,7 +373,7 @@ async function assertWorkListPagination(
|
|
|
381
373
|
await expect(pager.locator("output")).toContainText("1–", { timeout: 10_000 });
|
|
382
374
|
await expect(rows).toHaveCount(Math.min(10, total), { timeout: 10_000 });
|
|
383
375
|
await expect(surface).not.toHaveAttribute("aria-busy", "true", { timeout: 10_000 });
|
|
384
|
-
expect(await
|
|
376
|
+
expect(await workRowIdentities(rows)).toEqual(firstPageRows);
|
|
385
377
|
await assertNoFullscreenOverlay(page);
|
|
386
378
|
}
|
|
387
379
|
}
|
|
@@ -173,7 +173,7 @@ test("renders the modern read-only dashboard and meets accessibility gates", asy
|
|
|
173
173
|
// Identity is loaded independently; both the initial title and the title
|
|
174
174
|
// with the observed repository identify the same accessible navigation.
|
|
175
175
|
await expect(
|
|
176
|
-
page.getByRole("navigation", { name: /^Dashboard
|
|
176
|
+
page.getByRole("navigation", { name: /^Dashboard ZAIP AIOS(?: .+)? menu$/ }),
|
|
177
177
|
).toBeVisible();
|
|
178
178
|
const capabilityNav = page.getByRole("navigation", { name: "Áreas do dashboard" });
|
|
179
179
|
const globalControls = page.locator(".dashboard-global-controls");
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type Metric = {
|
|
2
|
+
surface: string;
|
|
3
|
+
period: "this-month" | "all";
|
|
4
|
+
ttfv_ms: number;
|
|
5
|
+
settled_ms: number;
|
|
6
|
+
request_count: number;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type SqlitePage = {
|
|
10
|
+
offset: number;
|
|
11
|
+
limit: number;
|
|
12
|
+
total_count: number;
|
|
13
|
+
has_more: boolean;
|
|
14
|
+
rows: readonly Record<string, unknown>[];
|
|
15
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { expect, type Page, type Request } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
export function observePerformanceWarnings(page: Page, requestStartedAt: WeakMap<Request, number>) {
|
|
4
|
+
const reactKeyWarnings: string[] = [];
|
|
5
|
+
const healthAndReadyTimings: number[] = [];
|
|
6
|
+
page.on("response", (response) => {
|
|
7
|
+
const startedAt = requestStartedAt.get(response.request());
|
|
8
|
+
if (startedAt === undefined) return;
|
|
9
|
+
if (["/api/v2/health", "/api/v2/ready"].includes(new URL(response.url()).pathname)) {
|
|
10
|
+
healthAndReadyTimings.push(performance.now() - startedAt);
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
page.on("console", (message) => {
|
|
14
|
+
if (message.type() === "warning" && /unique "key"|unique key/i.test(message.text())) {
|
|
15
|
+
reactKeyWarnings.push(message.text());
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
return { healthAndReadyTimings, reactKeyWarnings };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function assertPerformanceWarnings(
|
|
22
|
+
observations: ReturnType<typeof observePerformanceWarnings>,
|
|
23
|
+
) {
|
|
24
|
+
expect(observations.reactKeyWarnings).toEqual([]);
|
|
25
|
+
expect(observations.healthAndReadyTimings.length).toBeGreaterThan(0);
|
|
26
|
+
expect(
|
|
27
|
+
Math.max(...observations.healthAndReadyTimings),
|
|
28
|
+
"health and ready remain responsive under load",
|
|
29
|
+
).toBeLessThan(10_000);
|
|
30
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Locator } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
/** Live telemetry can change metrics while a paginated row keeps the same identity. */
|
|
4
|
+
export function workRowIdentities(rows: Locator): Promise<string[]> {
|
|
5
|
+
return rows.locator(".operations-work-list-identity small").allTextContents();
|
|
6
|
+
}
|