@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
package/templates/.agents/dashboard/packages/local-runtime/src/active-codex-telemetry.test.ts
CHANGED
|
@@ -26,6 +26,37 @@ describe("active Codex telemetry capture", () => {
|
|
|
26
26
|
});
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
+
it("does not execute a CLI against historical running entries in a stale worktree", async () => {
|
|
30
|
+
const root = await runtimeFixture("process.exitCode = 8;\n");
|
|
31
|
+
await writeFile(
|
|
32
|
+
join(root, ".agents/records/lifecycle/active-work.json"),
|
|
33
|
+
JSON.stringify({
|
|
34
|
+
schema_version: 1,
|
|
35
|
+
items: [{ kind: "run", status: "running", updated_at: "2026-09-01T00:00:00Z" }],
|
|
36
|
+
}),
|
|
37
|
+
);
|
|
38
|
+
await expect(captureActiveCodexTelemetry(root)).resolves.toMatchObject({
|
|
39
|
+
skipped_reason: "no_recent_active_runs",
|
|
40
|
+
captured_runs: 0,
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
it("still captures a recently active worktree Run", async () => {
|
|
44
|
+
const root = await runtimeFixture(
|
|
45
|
+
"process.stdout.write(JSON.stringify({telemetry:{captured:[{captured:true}]}}));\n",
|
|
46
|
+
);
|
|
47
|
+
await writeFile(
|
|
48
|
+
join(root, ".agents/records/lifecycle/active-work.json"),
|
|
49
|
+
JSON.stringify({
|
|
50
|
+
schema_version: 1,
|
|
51
|
+
items: [{ kind: "run", status: "running", updated_at: new Date().toISOString() }],
|
|
52
|
+
}),
|
|
53
|
+
);
|
|
54
|
+
await expect(captureActiveCodexTelemetry(root)).resolves.toMatchObject({
|
|
55
|
+
captured_runs: 1,
|
|
56
|
+
skipped_reason: null,
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
29
60
|
it("returns a typed manifest condition when the lifecycle has not been initialized", async () => {
|
|
30
61
|
const root = await runtimeFixture(
|
|
31
62
|
"process.stderr.write('Lifecycle manifest is not initialized'); process.exitCode = 1;\n",
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
|
-
import {
|
|
2
|
+
import { readFile, stat } from "node:fs/promises";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
3
4
|
import { promisify } from "node:util";
|
|
4
5
|
import { WorkspaceFileSystem } from "@zaip-ai/core";
|
|
5
6
|
import { lifecycleManifestState } from "./server-lifecycle-diagnostics.js";
|
|
7
|
+
import { dashboardCanonicalSourceRoots } from "./sqlite-read-model-source-fingerprint.js";
|
|
6
8
|
|
|
7
9
|
const execFileAsync = promisify(execFile);
|
|
8
10
|
|
|
@@ -15,6 +17,7 @@ export type ActiveCodexTelemetryCapture = {
|
|
|
15
17
|
| "manifest_uninitialized"
|
|
16
18
|
| "manifest_invalid"
|
|
17
19
|
| "no_active_runs"
|
|
20
|
+
| "no_recent_active_runs"
|
|
18
21
|
| "no_new_segments"
|
|
19
22
|
| null;
|
|
20
23
|
last_capture_at: string;
|
|
@@ -39,6 +42,16 @@ export async function captureActiveCodexTelemetry(
|
|
|
39
42
|
skipped_reason: manifestState === "missing" ? "manifest_uninitialized" : "manifest_invalid",
|
|
40
43
|
last_capture_at: new Date().toISOString(),
|
|
41
44
|
};
|
|
45
|
+
const activeRuns = await recentActiveRuns(workspaceRoot);
|
|
46
|
+
if (activeRuns !== null && activeRuns.recent === 0) {
|
|
47
|
+
return {
|
|
48
|
+
captured_runs: 0,
|
|
49
|
+
captured_segments: 0,
|
|
50
|
+
manifest_state: "initialized",
|
|
51
|
+
skipped_reason: activeRuns.stale > 0 ? "no_recent_active_runs" : "no_active_runs",
|
|
52
|
+
last_capture_at: new Date().toISOString(),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
42
55
|
const cliPath = resolve(workspaceRoot, ".agents", "runtime", "bin", "zaip.mjs");
|
|
43
56
|
try {
|
|
44
57
|
const outcome = await execFileAsync(
|
|
@@ -79,6 +92,66 @@ export async function captureActiveCodexTelemetry(
|
|
|
79
92
|
}
|
|
80
93
|
}
|
|
81
94
|
|
|
95
|
+
/** A stale lifecycle index is not proof of a live Codex invocation. */
|
|
96
|
+
async function recentActiveRuns(
|
|
97
|
+
workspaceRoot: string,
|
|
98
|
+
): Promise<{ recent: number; stale: number } | null> {
|
|
99
|
+
const path = join(workspaceRoot, ".agents", "records", "lifecycle", "active-work.json");
|
|
100
|
+
const metadata = await stat(path).catch((error: NodeJS.ErrnoException) => {
|
|
101
|
+
if (error.code === "ENOENT") return null;
|
|
102
|
+
throw error;
|
|
103
|
+
});
|
|
104
|
+
if (metadata === null) return null;
|
|
105
|
+
if (metadata.size > 8 * 1024 * 1024) throw new Error("Active-work index exceeds capture limit");
|
|
106
|
+
const parsed: unknown = JSON.parse(await readFile(path, "utf8"));
|
|
107
|
+
if (
|
|
108
|
+
typeof parsed !== "object" ||
|
|
109
|
+
parsed === null ||
|
|
110
|
+
!Array.isArray((parsed as { items?: unknown }).items)
|
|
111
|
+
)
|
|
112
|
+
throw new Error("Invalid active-work index for telemetry capture");
|
|
113
|
+
const cutoff = Date.now() - 72 * 60 * 60 * 1_000;
|
|
114
|
+
const runs = (parsed as { items: unknown[] }).items.filter(
|
|
115
|
+
(item) =>
|
|
116
|
+
typeof item === "object" &&
|
|
117
|
+
item !== null &&
|
|
118
|
+
(item as { kind?: unknown }).kind === "run" &&
|
|
119
|
+
(item as { status?: unknown }).status === "running",
|
|
120
|
+
);
|
|
121
|
+
const recent = runs.filter((item) => {
|
|
122
|
+
const updated = (item as { updated_at?: unknown }).updated_at;
|
|
123
|
+
return (
|
|
124
|
+
typeof updated === "string" &&
|
|
125
|
+
Number.isFinite(Date.parse(updated)) &&
|
|
126
|
+
Date.parse(updated) >= cutoff
|
|
127
|
+
);
|
|
128
|
+
}).length;
|
|
129
|
+
return { recent, stale: runs.length - recent };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Capture each canonical checkout before refreshing the combined SQLite view. */
|
|
133
|
+
export async function captureRepositoryActiveCodexTelemetry(
|
|
134
|
+
workspaceRoot: string,
|
|
135
|
+
): Promise<ActiveCodexTelemetryCapture> {
|
|
136
|
+
const roots = await dashboardCanonicalSourceRoots(workspaceRoot);
|
|
137
|
+
const results = await Promise.all(roots.map((root) => captureActiveCodexTelemetry(root)));
|
|
138
|
+
const primary = results[0];
|
|
139
|
+
if (primary === undefined) throw new Error("No dashboard workspace was discovered");
|
|
140
|
+
const capturedRuns = results.reduce((count, result) => count + result.captured_runs, 0);
|
|
141
|
+
return {
|
|
142
|
+
captured_runs: capturedRuns,
|
|
143
|
+
captured_segments: capturedRuns === 0 ? 0 : null,
|
|
144
|
+
manifest_state: primary.manifest_state,
|
|
145
|
+
skipped_reason:
|
|
146
|
+
capturedRuns > 0
|
|
147
|
+
? null
|
|
148
|
+
: results.some((result) => result.skipped_reason === "no_new_segments")
|
|
149
|
+
? "no_new_segments"
|
|
150
|
+
: primary.skipped_reason,
|
|
151
|
+
last_capture_at: new Date().toISOString(),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
82
155
|
function parseJsonResult(stdout: string): unknown {
|
|
83
156
|
if (!stdout.trim()) throw new Error("Active telemetry capture returned no JSON result");
|
|
84
157
|
try {
|
package/templates/.agents/dashboard/packages/local-runtime/src/agent-catalog-settings.test.ts
CHANGED
|
@@ -30,9 +30,9 @@ describe("agent catalog settings", () => {
|
|
|
30
30
|
const settings = await readAgentCatalogSettings(new WorkspaceFileSystem(workspaceRoot));
|
|
31
31
|
|
|
32
32
|
expect(settings).toMatchObject({
|
|
33
|
-
default_model: "gpt-
|
|
33
|
+
default_model: "gpt-6-sol",
|
|
34
34
|
default_reasoning_effort: "medium",
|
|
35
|
-
allowed_models: ["gpt-
|
|
35
|
+
allowed_models: ["gpt-6-luna", "gpt-6-sol", "gpt-6-astra"],
|
|
36
36
|
allowed_reasoning_efforts: ["low", "medium", "high", "xhigh"],
|
|
37
37
|
});
|
|
38
38
|
});
|
|
@@ -47,17 +47,17 @@ describe("agent catalog settings", () => {
|
|
|
47
47
|
]),
|
|
48
48
|
).toEqual(
|
|
49
49
|
expect.arrayContaining([
|
|
50
|
-
["agent-orchestrator", "gpt-
|
|
51
|
-
["agent-builder", "gpt-
|
|
52
|
-
["agent-task-executor", "gpt-
|
|
53
|
-
["agent-analyst", "gpt-
|
|
54
|
-
["agent-finalizer", "gpt-
|
|
55
|
-
["agent-reviewer", "gpt-
|
|
56
|
-
["agent-integrator", "gpt-
|
|
57
|
-
["agent-auditor", "gpt-
|
|
58
|
-
["agent-text-summarizer", "gpt-
|
|
59
|
-
["agent-data-analyst", "gpt-
|
|
60
|
-
["agent-refactoring-specialist", "gpt-
|
|
50
|
+
["agent-orchestrator", "gpt-6-sol", "medium"],
|
|
51
|
+
["agent-builder", "gpt-6-sol", "medium"],
|
|
52
|
+
["agent-task-executor", "gpt-6-sol", "medium"],
|
|
53
|
+
["agent-analyst", "gpt-6-sol", "medium"],
|
|
54
|
+
["agent-finalizer", "gpt-6-sol", "medium"],
|
|
55
|
+
["agent-reviewer", "gpt-6-sol", "medium"],
|
|
56
|
+
["agent-integrator", "gpt-6-sol", "high"],
|
|
57
|
+
["agent-auditor", "gpt-6-sol", "high"],
|
|
58
|
+
["agent-text-summarizer", "gpt-6-sol", "medium"],
|
|
59
|
+
["agent-data-analyst", "gpt-6-sol", "medium"],
|
|
60
|
+
["agent-refactoring-specialist", "gpt-6-sol", "medium"],
|
|
61
61
|
]),
|
|
62
62
|
);
|
|
63
63
|
expect(current.agents.some((agent) => agent.model.preferred[0] === "policy-selected")).toBe(
|
|
@@ -73,7 +73,7 @@ describe("agent catalog settings", () => {
|
|
|
73
73
|
...agent,
|
|
74
74
|
model: {
|
|
75
75
|
...agent.model,
|
|
76
|
-
preferred: ["gpt-
|
|
76
|
+
preferred: ["gpt-6-sol"],
|
|
77
77
|
reasoning_effort: "high" as const,
|
|
78
78
|
},
|
|
79
79
|
}
|
|
@@ -201,7 +201,7 @@ describe("agent catalog settings", () => {
|
|
|
201
201
|
const target = current.agents[0];
|
|
202
202
|
if (target === undefined) throw new Error("Catalog must contain an agent");
|
|
203
203
|
const options = {
|
|
204
|
-
allowed_models: ["gpt-
|
|
204
|
+
allowed_models: ["gpt-6-sol"],
|
|
205
205
|
allowed_reasoning_efforts: ["low", "medium", "high", "xhigh"],
|
|
206
206
|
};
|
|
207
207
|
|
|
@@ -269,10 +269,10 @@ describe("project settings persistence", () => {
|
|
|
269
269
|
...current,
|
|
270
270
|
model_orchestration: {
|
|
271
271
|
mode: "auto",
|
|
272
|
-
default_model: "gpt-
|
|
272
|
+
default_model: "gpt-6-sol",
|
|
273
273
|
default_effort: "medium",
|
|
274
274
|
default_velocity: "standard",
|
|
275
|
-
allowed_models: ["gpt-
|
|
275
|
+
allowed_models: ["gpt-6-luna", "gpt-6-sol"],
|
|
276
276
|
allowed_efforts: ["low", "medium", "high", "xhigh"],
|
|
277
277
|
max_auto_effort: "xhigh",
|
|
278
278
|
automatic_sources: ["spec", "prd"],
|
|
@@ -545,7 +545,7 @@ export function renderSoftwareArchitecture(config: ProjectConfig): string {
|
|
|
545
545
|
"",
|
|
546
546
|
]);
|
|
547
547
|
const executionDetails =
|
|
548
|
-
config.execution && config.execution
|
|
548
|
+
config.execution && "autonomous" in config.execution
|
|
549
549
|
? [
|
|
550
550
|
`- **Runtime:** ${config.execution.runtime}`,
|
|
551
551
|
`- **Provider:** ${markdownCell(config.execution.autonomous.provider)}`,
|
|
@@ -31,7 +31,7 @@ describe("dashboard identity endpoint", () => {
|
|
|
31
31
|
|
|
32
32
|
expect(response.status, await response.clone().text()).toBe(200);
|
|
33
33
|
await expect(response.json()).resolves.toEqual({
|
|
34
|
-
title: "Dashboard
|
|
34
|
+
title: "Dashboard ZAIP AIOS",
|
|
35
35
|
repository_name: "",
|
|
36
36
|
});
|
|
37
37
|
expect(refreshReadModel).not.toHaveBeenCalled();
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
3
3
|
|
|
4
|
-
const watchers: Array<{ path: string; listener: () => void }> = [];
|
|
4
|
+
const watchers: Array<{ path: string; listener: () => void; close: ReturnType<typeof vi.fn> }> = [];
|
|
5
5
|
|
|
6
6
|
vi.mock("node:fs", () => ({
|
|
7
7
|
watch: vi.fn((path: string, _options: unknown, listener: () => void) => {
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const close = vi.fn();
|
|
9
|
+
watchers.push({ path, listener, close });
|
|
10
|
+
return { unref: vi.fn(), close };
|
|
10
11
|
}),
|
|
11
12
|
}));
|
|
12
13
|
|
|
@@ -19,6 +20,27 @@ afterEach(() => {
|
|
|
19
20
|
});
|
|
20
21
|
|
|
21
22
|
describe("snapshot source synchronization", () => {
|
|
23
|
+
it("observes newly registered checkout records and stops observing removed checkouts", async () => {
|
|
24
|
+
vi.useFakeTimers();
|
|
25
|
+
let roots = ["C:/main", "C:/codex/worktree"];
|
|
26
|
+
const refresh = vi.fn(async () => undefined);
|
|
27
|
+
startSnapshotSynchronization({
|
|
28
|
+
workspaceRoot: roots[0]!,
|
|
29
|
+
discoverSourceRoots: async () => roots,
|
|
30
|
+
staleSeed: false,
|
|
31
|
+
watchSources: true,
|
|
32
|
+
refresh,
|
|
33
|
+
});
|
|
34
|
+
await vi.advanceTimersByTimeAsync(1);
|
|
35
|
+
const sibling = watchers.find(({ path }) => path === join(roots[1]!, ".agents", "records"));
|
|
36
|
+
expect(sibling).toBeDefined();
|
|
37
|
+
sibling?.listener();
|
|
38
|
+
await vi.advanceTimersByTimeAsync(300);
|
|
39
|
+
expect(refresh).toHaveBeenCalled();
|
|
40
|
+
roots = [roots[0]!];
|
|
41
|
+
await vi.advanceTimersByTimeAsync(60_000);
|
|
42
|
+
expect(sibling?.close).toHaveBeenCalledOnce();
|
|
43
|
+
});
|
|
22
44
|
it("reports capture failure separately while refreshing canonical data", async () => {
|
|
23
45
|
vi.useFakeTimers();
|
|
24
46
|
const error = new Error("capture timed out");
|
package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-synchronization.ts
CHANGED
|
@@ -4,6 +4,8 @@ import type { ActiveCodexTelemetryCapture } from "./active-codex-telemetry.js";
|
|
|
4
4
|
|
|
5
5
|
export function startSnapshotSynchronization(input: {
|
|
6
6
|
workspaceRoot: string;
|
|
7
|
+
/** Same registered repository sources used by the SQLite fingerprint. */
|
|
8
|
+
discoverSourceRoots?: () => Promise<readonly string[]>;
|
|
7
9
|
staleSeed: boolean;
|
|
8
10
|
watchSources: boolean;
|
|
9
11
|
refresh: () => Promise<void>;
|
|
@@ -27,25 +29,58 @@ export function startSnapshotSynchronization(input: {
|
|
|
27
29
|
}, 300);
|
|
28
30
|
pendingRefresh.unref();
|
|
29
31
|
};
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
const watchers = new Map<string, ReturnType<typeof watch>>();
|
|
33
|
+
const syncWatchers = (roots: readonly string[]) => {
|
|
34
|
+
const wanted = new Set(
|
|
35
|
+
roots.flatMap((root) =>
|
|
36
|
+
["data", "records", "config"].map((kind) => join(root, ".agents", kind)),
|
|
37
|
+
),
|
|
38
|
+
);
|
|
39
|
+
for (const [path, watcher] of watchers) {
|
|
40
|
+
if (!wanted.has(path)) {
|
|
41
|
+
watcher.close();
|
|
42
|
+
watchers.delete(path);
|
|
43
|
+
scheduleRefresh();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
for (const path of wanted) {
|
|
47
|
+
if (watchers.has(path)) continue;
|
|
48
|
+
try {
|
|
49
|
+
const watcher = watch(path, { recursive: true }, scheduleRefresh);
|
|
50
|
+
watcher.unref();
|
|
51
|
+
watchers.set(path, watcher);
|
|
52
|
+
} catch {
|
|
53
|
+
// The periodic fingerprint remains the fallback on unsupported filesystems.
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
syncWatchers([input.workspaceRoot]);
|
|
58
|
+
const discover = async () => {
|
|
59
|
+
if (input.discoverSourceRoots === undefined) return;
|
|
35
60
|
try {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// Reuse-triggered refresh remains the portable fallback.
|
|
61
|
+
syncWatchers(await input.discoverSourceRoots());
|
|
62
|
+
} catch (error) {
|
|
63
|
+
input.onRefreshFailure?.({ trigger: "source_change", error });
|
|
40
64
|
}
|
|
41
|
-
}
|
|
65
|
+
};
|
|
66
|
+
void discover();
|
|
67
|
+
let captureInFlight = false;
|
|
42
68
|
const captureAndRefresh = () => {
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
69
|
+
if (captureInFlight) return;
|
|
70
|
+
captureInFlight = true;
|
|
71
|
+
void (async () => {
|
|
72
|
+
try {
|
|
73
|
+
await discover();
|
|
74
|
+
if (input.captureActiveTelemetry !== undefined) {
|
|
75
|
+
input.onCaptureSuccess?.(await input.captureActiveTelemetry());
|
|
76
|
+
}
|
|
77
|
+
} catch (error) {
|
|
78
|
+
input.onCaptureFailure?.(error);
|
|
79
|
+
} finally {
|
|
80
|
+
scheduleRefresh();
|
|
81
|
+
captureInFlight = false;
|
|
82
|
+
}
|
|
83
|
+
})();
|
|
49
84
|
};
|
|
50
85
|
// Run at most once a minute. File watchers only project canonical changes;
|
|
51
86
|
// they never launch telemetry or lifecycle work.
|
|
@@ -514,7 +514,7 @@ describe("dashboard backend snapshot", () => {
|
|
|
514
514
|
});
|
|
515
515
|
await expect(response.json()).resolves.toMatchObject({
|
|
516
516
|
dashboard: {
|
|
517
|
-
title: "Dashboard
|
|
517
|
+
title: "Dashboard ZAIP AIOS",
|
|
518
518
|
repository_name: "",
|
|
519
519
|
},
|
|
520
520
|
operations: { readonly: true, summary: { source_latest_at: "2026-07-14T00:00:05.000Z" } },
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import type { Context } from "hono";
|
|
3
|
+
|
|
4
|
+
export const DASHBOARD_LOOPBACK_HOST = "127.0.0.1";
|
|
5
|
+
|
|
6
|
+
export function isAllowedOrigin(origin: string): boolean {
|
|
7
|
+
try {
|
|
8
|
+
const parsed = new URL(origin);
|
|
9
|
+
return (
|
|
10
|
+
parsed.protocol === "http:" &&
|
|
11
|
+
(parsed.hostname === DASHBOARD_LOOPBACK_HOST || parsed.hostname === "localhost")
|
|
12
|
+
);
|
|
13
|
+
} catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function isSafeUiPath(pathname: string): boolean {
|
|
19
|
+
try {
|
|
20
|
+
const decoded = decodeURIComponent(pathname).replaceAll("\\", "/");
|
|
21
|
+
return !decoded.includes("\0") && !decoded.split("/").some((segment) => segment === "..");
|
|
22
|
+
} catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function defaultSessionToken(): string {
|
|
28
|
+
return process.env.ZAIP_UI_TOKEN ?? randomBytes(24).toString("base64url");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function shouldBootstrapBrowserSession(context: Context): boolean {
|
|
32
|
+
if (context.req.method !== "GET" && context.req.method !== "HEAD") return false;
|
|
33
|
+
if (context.req.path !== "/" && context.req.path !== "/index.html") return false;
|
|
34
|
+
const origin = context.req.header("origin");
|
|
35
|
+
if (origin !== undefined && !isAllowedOrigin(origin)) return false;
|
|
36
|
+
return context.req.header("sec-fetch-site") !== "cross-site";
|
|
37
|
+
}
|
|
@@ -11,7 +11,7 @@ export async function dashboardIdentity(
|
|
|
11
11
|
filesystem: WorkspaceFileSystem,
|
|
12
12
|
workspaceRoot: string,
|
|
13
13
|
): Promise<{ title: string; repository_name: string }> {
|
|
14
|
-
let title = process.env.ZAIP_DASHBOARD_TITLE?.trim() || "Dashboard
|
|
14
|
+
let title = process.env.ZAIP_DASHBOARD_TITLE?.trim() || "Dashboard ZAIP AIOS";
|
|
15
15
|
let repositorySetting = "auto";
|
|
16
16
|
try {
|
|
17
17
|
if (await filesystem.exists(DASHBOARD_CONFIG_PATH)) {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomBytes } from "node:crypto";
|
|
2
1
|
import { readFile } from "node:fs/promises";
|
|
3
2
|
import { basename, resolve } from "node:path";
|
|
4
3
|
import { serve } from "@hono/node-server";
|
|
@@ -9,7 +8,7 @@ import { type Context, Hono } from "hono";
|
|
|
9
8
|
import { getCookie, setCookie } from "hono/cookie";
|
|
10
9
|
import {
|
|
11
10
|
type ActiveCodexTelemetryCapture,
|
|
12
|
-
|
|
11
|
+
captureRepositoryActiveCodexTelemetry,
|
|
13
12
|
} from "./active-codex-telemetry.js";
|
|
14
13
|
import { runAgentAdapterSync } from "./agent-adapter-sync.js";
|
|
15
14
|
import {
|
|
@@ -44,10 +43,18 @@ import { startSnapshotSynchronization } from "./server-snapshot-synchronization.
|
|
|
44
43
|
import { writeReadModelStartup, writeStartupPhase } from "./server-startup.js";
|
|
45
44
|
import { selectedCurrency } from "./server-summary-helpers.js";
|
|
46
45
|
import { registerTraceRoutes } from "./server-trace-routes.js";
|
|
46
|
+
import {
|
|
47
|
+
defaultSessionToken,
|
|
48
|
+
DASHBOARD_LOOPBACK_HOST as HOST,
|
|
49
|
+
isAllowedOrigin,
|
|
50
|
+
isSafeUiPath,
|
|
51
|
+
shouldBootstrapBrowserSession,
|
|
52
|
+
} from "./server-ui-security.js";
|
|
47
53
|
import {
|
|
48
54
|
createWorkReconciliation,
|
|
49
55
|
waitForWorkReconciliation,
|
|
50
56
|
} from "./server-work-reconciliation.js";
|
|
57
|
+
import { dashboardCanonicalSourceRoots } from "./sqlite-read-model-source-fingerprint.js";
|
|
51
58
|
|
|
52
59
|
export { reconciliationNeedsRefresh } from "./server-work-reconciliation.js";
|
|
53
60
|
|
|
@@ -76,7 +83,6 @@ export {
|
|
|
76
83
|
validateSqliteReadModelSchema,
|
|
77
84
|
} from "./sqlite-read-model.js";
|
|
78
85
|
|
|
79
|
-
const HOST = "127.0.0.1";
|
|
80
86
|
const RUNTIME_KIND = "zaip-dashboard-sqlite-runtime";
|
|
81
87
|
const SESSION_COOKIE = "zaip-dashboard-sqlite-session";
|
|
82
88
|
|
|
@@ -98,35 +104,6 @@ interface DashboardAppOptions {
|
|
|
98
104
|
launcherOwned?: boolean;
|
|
99
105
|
}
|
|
100
106
|
|
|
101
|
-
function isAllowedOrigin(origin: string): boolean {
|
|
102
|
-
try {
|
|
103
|
-
const parsed = new URL(origin);
|
|
104
|
-
return (
|
|
105
|
-
parsed.protocol === "http:" && (parsed.hostname === HOST || parsed.hostname === "localhost")
|
|
106
|
-
);
|
|
107
|
-
} catch {
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
function isSafeUiPath(pathname: string): boolean {
|
|
112
|
-
try {
|
|
113
|
-
const decoded = decodeURIComponent(pathname).replaceAll("\\", "/");
|
|
114
|
-
return !decoded.includes("\0") && !decoded.split("/").some((segment) => segment === "..");
|
|
115
|
-
} catch {
|
|
116
|
-
return false;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
function defaultSessionToken(): string {
|
|
120
|
-
return process.env.ZAIP_UI_TOKEN ?? randomBytes(24).toString("base64url");
|
|
121
|
-
}
|
|
122
|
-
function shouldBootstrapBrowserSession(context: Context): boolean {
|
|
123
|
-
if (context.req.method !== "GET" && context.req.method !== "HEAD") return false;
|
|
124
|
-
if (context.req.path !== "/" && context.req.path !== "/index.html") return false;
|
|
125
|
-
const origin = context.req.header("origin");
|
|
126
|
-
if (origin !== undefined && !isAllowedOrigin(origin)) return false;
|
|
127
|
-
return context.req.header("sec-fetch-site") !== "cross-site";
|
|
128
|
-
}
|
|
129
|
-
|
|
130
107
|
/**
|
|
131
108
|
* Keep the entity/macro details on the snapshot filesystem, while making the
|
|
132
109
|
* first-fold counters and token/cost facts come from SQL.
|
|
@@ -262,11 +239,12 @@ export function createDashboardApp(
|
|
|
262
239
|
};
|
|
263
240
|
startSnapshotSynchronization({
|
|
264
241
|
workspaceRoot,
|
|
242
|
+
discoverSourceRoots: () => dashboardCanonicalSourceRoots(workspaceRoot),
|
|
265
243
|
staleSeed: isSqliteSnapshot && snapshotState === "updating",
|
|
266
244
|
watchSources: isSqliteSnapshot && options.watchSources === true,
|
|
267
245
|
refresh: rebuildProjection,
|
|
268
246
|
...(isSqliteSnapshot && options.watchSources === true
|
|
269
|
-
? { captureActiveTelemetry: () =>
|
|
247
|
+
? { captureActiveTelemetry: () => captureRepositoryActiveCodexTelemetry(workspaceRoot) }
|
|
270
248
|
: {}),
|
|
271
249
|
onRefreshFailure: projectionRefreshDiagnostics.record,
|
|
272
250
|
onCaptureSuccess: (result) => {
|
|
@@ -30,24 +30,27 @@ import {
|
|
|
30
30
|
validateSqliteReadModelSchema,
|
|
31
31
|
} from "./sqlite-read-model-schema.js";
|
|
32
32
|
import { sourceFingerprint } from "./sqlite-read-model-source-fingerprint.js";
|
|
33
|
+
import {
|
|
34
|
+
rebuildFingerprintOptions,
|
|
35
|
+
type SqliteRebuildOptions,
|
|
36
|
+
} from "./sqlite-rebuild-fingerprint-options.js";
|
|
33
37
|
import type { SqliteRebuildResult } from "./sqlite-rebuild-result.js";
|
|
34
38
|
import { readSnapshotFileCount } from "./sqlite-snapshot-cache.js";
|
|
35
39
|
import { deriveCanonicalWorkStages } from "./sqlite-work-stages.js";
|
|
36
40
|
export async function rebuildSqliteReadModel(
|
|
37
41
|
workspaceRoot: string,
|
|
38
|
-
options:
|
|
42
|
+
options: SqliteRebuildOptions = {},
|
|
39
43
|
): Promise<SqliteRebuildResult> {
|
|
40
44
|
const path = sqliteReadModelPath(workspaceRoot);
|
|
41
|
-
//
|
|
42
|
-
// avoids advertising every launch as stale while preserving the stale seed
|
|
43
|
-
// path for a changed source or an incompatible database.
|
|
45
|
+
// Reuse only when schema and canonical fingerprint still match; otherwise rebuild.
|
|
44
46
|
if (options.preferExisting && !options.forceCanonical) {
|
|
45
47
|
try {
|
|
46
48
|
validateSqliteReadModelSchema(path);
|
|
47
49
|
const fingerprintStartedAt = performance.now();
|
|
48
|
-
const sourceSnapshot = await sourceFingerprint(
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
const sourceSnapshot = await sourceFingerprint(
|
|
51
|
+
workspaceRoot,
|
|
52
|
+
rebuildFingerprintOptions(path, options),
|
|
53
|
+
);
|
|
51
54
|
const fingerprint = `${sourceSnapshot.fingerprint}\ncurrent_day=${saoPauloDay(new Date().toISOString())}`;
|
|
52
55
|
const database = new DatabaseSync(path, { readOnly: true });
|
|
53
56
|
try {
|
|
@@ -108,9 +111,7 @@ export async function rebuildSqliteReadModel(
|
|
|
108
111
|
reportLaunchProgress("source_fingerprint_started", 8, "Inventariando fontes canônicas.");
|
|
109
112
|
let sourceSnapshot = await sourceFingerprint(
|
|
110
113
|
workspaceRoot,
|
|
111
|
-
options
|
|
112
|
-
? { verifyContent: true }
|
|
113
|
-
: { previous: persistedSourceCheckpoint(path) },
|
|
114
|
+
rebuildFingerprintOptions(path, options),
|
|
114
115
|
);
|
|
115
116
|
let refresh = {
|
|
116
117
|
reused_sources: sourceSnapshot.reusedFiles,
|
|
@@ -157,9 +158,7 @@ export async function rebuildSqliteReadModel(
|
|
|
157
158
|
// Capture canonical inputs only after acquiring exclusive writer ownership.
|
|
158
159
|
sourceSnapshot = await sourceFingerprint(
|
|
159
160
|
workspaceRoot,
|
|
160
|
-
options
|
|
161
|
-
? { verifyContent: true }
|
|
162
|
-
: { previous: persistedSourceCheckpoint(path) },
|
|
161
|
+
rebuildFingerprintOptions(path, options),
|
|
163
162
|
);
|
|
164
163
|
refresh = {
|
|
165
164
|
reused_sources: sourceSnapshot.reusedFiles,
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
1
2
|
import { mkdir, mkdtemp, rename, rm, stat, utimes, writeFile } from "node:fs/promises";
|
|
2
|
-
import { join, resolve } from "node:path";
|
|
3
|
+
import { basename, join, resolve } from "node:path";
|
|
3
4
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
4
5
|
import {
|
|
6
|
+
isCodexManagedWorktreeRoot,
|
|
5
7
|
type SqliteReadModelSourceCandidate,
|
|
6
8
|
sourceFingerprint,
|
|
7
9
|
} from "./sqlite-read-model-source-fingerprint.js";
|
|
@@ -26,6 +28,74 @@ afterEach(async () => {
|
|
|
26
28
|
});
|
|
27
29
|
|
|
28
30
|
describe("persistent source fingerprint checkpoints", () => {
|
|
31
|
+
it("includes direct Codex checkouts but not nested Task workspaces", () => {
|
|
32
|
+
expect(isCodexManagedWorktreeRoot("C:\\Users\\david\\.codex\\worktrees\\v38-readiness")).toBe(
|
|
33
|
+
true,
|
|
34
|
+
);
|
|
35
|
+
expect(isCodexManagedWorktreeRoot("/home/david/.codex/worktrees/v38-readiness")).toBe(true);
|
|
36
|
+
expect(isCodexManagedWorktreeRoot("C:\\Users\\david\\.codex\\worktrees\\v38\\zaip-aios")).toBe(
|
|
37
|
+
true,
|
|
38
|
+
);
|
|
39
|
+
expect(isCodexManagedWorktreeRoot("/home/david/.codex/worktrees/v38/zaip-aios")).toBe(true);
|
|
40
|
+
expect(
|
|
41
|
+
isCodexManagedWorktreeRoot(
|
|
42
|
+
"C:\\Users\\david\\.codex\\worktrees\\v38\\zaip-aios\\.local\\task-workspaces\\tree",
|
|
43
|
+
),
|
|
44
|
+
).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
it("aggregates registered roots by canonical ID and chooses the newest record, not checkout mtime", async () => {
|
|
47
|
+
const { root, path } = await fixture();
|
|
48
|
+
const sibling = await mkdtemp(
|
|
49
|
+
join(resolve(import.meta.dirname, "../../../../..", ".local/sqlite/tests"), "worktree-"),
|
|
50
|
+
);
|
|
51
|
+
roots.push(sibling);
|
|
52
|
+
const siblingPath = join(sibling, ".agents/records/tasks/task.md");
|
|
53
|
+
await mkdir(join(sibling, ".agents/records/tasks"), { recursive: true });
|
|
54
|
+
await writeFile(path, "---\nid: TASK-1\nupdated_at: 2026-09-17T12:00:00Z\n---\nold\n");
|
|
55
|
+
await writeFile(siblingPath, "---\nid: TASK-1\nupdated_at: 2026-09-23T12:00:00Z\n---\nnew\n");
|
|
56
|
+
await utimes(path, new Date("2026-09-24"), new Date("2026-09-24"));
|
|
57
|
+
const snapshot = await sourceFingerprint(root, { sourceRoots: [root, sibling] });
|
|
58
|
+
expect(snapshot.candidates).toHaveLength(1);
|
|
59
|
+
expect(snapshot.candidates[0]?.path).toBe(siblingPath);
|
|
60
|
+
await writeFile(
|
|
61
|
+
join(sibling, ".agents/records/tasks/another.md"),
|
|
62
|
+
"---\nid: TASK-2\nupdated_at: 2026-09-23T12:00:00Z\n---\n",
|
|
63
|
+
);
|
|
64
|
+
const expanded = await sourceFingerprint(root, { sourceRoots: [root, sibling] });
|
|
65
|
+
expect(expanded.candidates.map((candidate) => candidate.source)).toEqual([
|
|
66
|
+
".agents/records/tasks/another.md",
|
|
67
|
+
".agents/records/tasks/task.md",
|
|
68
|
+
]);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("automatically discovers a registered Codex worktree and includes its canonical Task", async () => {
|
|
72
|
+
const { root } = await fixture();
|
|
73
|
+
execFileSync("git", ["init", "-q", root]);
|
|
74
|
+
execFileSync("git", ["-C", root, "add", ".agents/records/tasks/task.md"]);
|
|
75
|
+
execFileSync("git", [
|
|
76
|
+
"-C",
|
|
77
|
+
root,
|
|
78
|
+
"-c",
|
|
79
|
+
"user.name=Test",
|
|
80
|
+
"-c",
|
|
81
|
+
"user.email=test@example.invalid",
|
|
82
|
+
"commit",
|
|
83
|
+
"-qm",
|
|
84
|
+
"base",
|
|
85
|
+
]);
|
|
86
|
+
const candidate = join(root, ".codex", "worktrees", "candidate", basename(root));
|
|
87
|
+
await mkdir(resolve(candidate, ".."), { recursive: true });
|
|
88
|
+
execFileSync("git", ["-C", root, "worktree", "add", "-q", "-b", "candidate", candidate]);
|
|
89
|
+
await writeFile(
|
|
90
|
+
join(candidate, ".agents/records/tasks/new.md"),
|
|
91
|
+
"---\nid: TASK-NEW\ncreated_at: 2026-09-23T12:00:00Z\n---\n",
|
|
92
|
+
);
|
|
93
|
+
const discovered = await sourceFingerprint(root);
|
|
94
|
+
expect(discovered.candidates.map((item) => item.source)).toContain(
|
|
95
|
+
".agents/records/tasks/new.md",
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
|
|
29
99
|
it("includes current data records, retains legacy records, and excludes generated projections", async () => {
|
|
30
100
|
const { root } = await fixture();
|
|
31
101
|
await mkdir(join(root, ".agents/data/runs/2026/09"), { recursive: true });
|