@zaip-ai/cli 1.0.8 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/services/adapters.d.ts +1 -1
- package/dist/services/adapters.js +1 -1
- package/dist/services/agent-adapters.js +3 -3
- package/dist/services/agent-adapters.js.map +1 -1
- package/dist/services/agent-adapters.test.js +7 -1
- package/dist/services/agent-adapters.test.js.map +1 -1
- package/dist/services/codex-pre-tool-hook-template.d.ts.map +1 -1
- package/dist/services/codex-pre-tool-hook-template.js +89 -7
- package/dist/services/codex-pre-tool-hook-template.js.map +1 -1
- package/dist/services/codex-rules.d.ts +1 -1
- package/dist/services/codex-rules.d.ts.map +1 -1
- package/dist/services/codex-rules.js +7 -0
- package/dist/services/codex-rules.js.map +1 -1
- package/dist/services/install-agents-template.d.ts.map +1 -1
- package/dist/services/install-agents-template.js +1 -0
- package/dist/services/install-agents-template.js.map +1 -1
- package/dist/services/logger.test.js +2 -2
- package/dist/services/runtime-template.test.js +31 -7
- package/dist/services/runtime-template.test.js.map +1 -1
- package/dist/services/template-manifest.d.ts.map +1 -1
- package/dist/services/template-manifest.js +12 -3
- package/dist/services/template-manifest.js.map +1 -1
- package/package.json +1 -1
- package/templates/.agents/architecture/software-architecture.md +131 -0
- package/templates/.agents/branding/brandbook.docx +0 -0
- package/templates/.agents/branding/brandbook.md +60 -0
- package/templates/.agents/config/agents/catalog.yaml +7 -7
- package/templates/.agents/config/clients/codex/agents/zaip-agent-backend.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 +1 -1
- package/templates/.agents/config/clients/codex/agents/zaip-agent-frontend.toml +8 -8
- package/templates/.agents/config/clients/codex/agents/zaip-agent-orchestrator.toml +1 -1
- package/templates/.agents/dashboard/.tmp-run-list.json +254 -0
- package/templates/.agents/dashboard/.zaip-managed.json +457 -173
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-Z60df2r-.js → CostCalculationGuidePage-ovxurkIk.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/DashboardHelpDialog-BgVgrfhQ.js +2310 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-Coc6pA-1.js → PricingSettingsDialog-vSvvOHQp.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-BomxqCBU.css +1 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-zH758vfs.js +3 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-DLn-Mz2M.js +1 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-CaKwQP43.css → TraceabilityWorkspace-DvvavDLY.css} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-DKwP1stV.js +68 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-PoJA2PI1.css +1 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-DFBuc_qp.js → icons-vendor-B_lDDHn1.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-B31GMG5O.css +1 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-CZQlsLV9.js +2 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-CCQOHdVI.js → react-vendor-B3TJrD4O.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-pC2_0J8x.js → traceability-7f1j5wx3.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/index.html +7 -7
- package/templates/.agents/dashboard/apps/frontend/package.json +1 -1
- package/templates/.agents/dashboard/apps/frontend/playwright.dom.config.ts +32 -0
- package/templates/.agents/dashboard/apps/frontend/src/App.tsx +199 -140
- package/templates/.agents/dashboard/apps/frontend/src/AppOverlays.tsx +0 -21
- package/templates/.agents/dashboard/apps/frontend/src/DashboardAlternateContent.tsx +20 -11
- package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsPage.tsx +14 -7
- package/templates/.agents/dashboard/apps/frontend/src/ProjectStackEditor.tsx +4 -2
- package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.dom.e2e.ts +56 -0
- package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.test.ts +21 -2
- package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.tsx +89 -19
- package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +19 -4
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +49 -3
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +29 -10
- package/templates/.agents/dashboard/apps/frontend/src/operations-period-render.test.ts +4 -4
- package/templates/.agents/dashboard/apps/frontend/src/overview-status-page.test.ts +4 -2
- package/templates/.agents/dashboard/apps/frontend/src/project-settings-page.css +36 -26
- package/templates/.agents/dashboard/apps/frontend/src/project-settings.test.ts +2 -2
- package/templates/.agents/dashboard/apps/frontend/src/snapshot-banner-semantics.test.ts +47 -6
- package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +59 -9
- package/templates/.agents/dashboard/apps/frontend/src/sqlite-page-export.test.ts +32 -0
- package/templates/.agents/dashboard/apps/frontend/src/sqlite-page-export.ts +21 -0
- package/templates/.agents/dashboard/apps/frontend/src/styles.css +19 -0
- package/templates/.agents/dashboard/apps/frontend/src/traceability-task-pagination.test.ts +32 -0
- package/templates/.agents/dashboard/apps/frontend/src/traceability-task-pagination.ts +36 -0
- package/templates/.agents/dashboard/apps/frontend/src/traceability-workspace.css +6 -2
- package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.test.ts +137 -23
- package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.ts +229 -35
- package/templates/.agents/dashboard/apps/frontend/src/use-app-effects.ts +61 -7
- package/templates/.agents/dashboard/apps/frontend/src/use-app-operations-pages.ts +3 -6
- package/templates/.agents/dashboard/apps/frontend/src/use-app-trace-documents.ts +7 -1
- package/templates/.agents/dashboard/apps/frontend/src/use-app-work-list-page.test.ts +163 -0
- package/templates/.agents/dashboard/apps/frontend/src/use-app-work-list-page.ts +136 -0
- package/templates/.agents/dashboard/apps/frontend/src/use-operations-detail-export.ts +76 -0
- package/templates/.agents/dashboard/apps/frontend/src/work-list-load-dedup.test.ts +23 -0
- package/templates/.agents/dashboard/apps/frontend/src/work-list-load-dedup.ts +27 -0
- package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.test.ts +39 -15
- package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.ts +3 -4
- package/templates/.agents/dashboard/apps/frontend/vite.config.ts +4 -1
- package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.test.ts +89 -19
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CompactLifecycleCostTable.tsx +31 -16
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostCharts.test.ts +43 -14
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostCharts.tsx +5 -5
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionPanel.tsx +60 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionTable.tsx +191 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.loading.test.ts +14 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.run-page.test.ts +18 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.tsx +18 -3
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostModelsAuditTable.tsx +1 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorContent.tsx +75 -44
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorLoadErrors.tsx +35 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.test.ts +162 -40
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +221 -79
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableLoading.test.ts +132 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableLoading.tsx +70 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +203 -155
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.tsx +164 -125
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-copy.ts +2 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-views.ts +3 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor.css +5 -2
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-page-range.ts +35 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/index.ts +2 -2
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/period-cost-groups.ts +2 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-compact-cost-page.ts +32 -9
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.test.ts +37 -2
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.ts +131 -9
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-run-page.ts +34 -17
- package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.test.ts +0 -24
- package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.test.ts +225 -424
- package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.ts +24 -15
- package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-terminal-day.test.ts +6 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/server/source-size-cost-server/build-cost-monitor-projection-agents.test.ts +31 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/server/source-size-cost-server/build-cost-summary-projection-duration.test.ts +414 -0
- package/templates/.agents/dashboard/modules/operations/package.json +1 -1
- package/templates/.agents/dashboard/modules/operations/src/contracts.ts +46 -26
- package/templates/.agents/dashboard/modules/operations/src/react/DeveloperAttributionPanel.test.ts +54 -0
- package/templates/.agents/dashboard/modules/operations/src/react/DeveloperAttributionPanel.tsx +247 -0
- package/templates/.agents/dashboard/modules/operations/src/react/EntityTables.tsx +31 -11
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsMainContent.tsx +39 -13
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.helpers.tsx +107 -2
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.macro-metrics.test.ts +55 -0
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.test.ts +23 -29
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +211 -184
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverviewTopPanel.tsx +127 -0
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +60 -51
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageNavigation.tsx +1 -4
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageOverview.tsx +3 -0
- package/templates/.agents/dashboard/modules/operations/src/react/PagedWorkList.test.tsx +43 -0
- package/templates/.agents/dashboard/modules/operations/src/react/PagedWorkList.tsx +181 -0
- package/templates/.agents/dashboard/modules/operations/src/react/PeriodSummaryTable.tsx +32 -10
- package/templates/.agents/dashboard/modules/operations/src/react/TaskDetailsDialog.tsx +9 -3
- package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkBoard.tsx +13 -5
- package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.test.ts +16 -6
- package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.tsx +14 -4
- package/templates/.agents/dashboard/modules/operations/src/react/conversation-rows.ts +1 -2
- package/templates/.agents/dashboard/modules/operations/src/react/developer-identities.test.ts +18 -0
- package/templates/.agents/dashboard/modules/operations/src/react/developer-identities.ts +30 -0
- package/templates/.agents/dashboard/modules/operations/src/react/execution-metrics.ts +1 -0
- package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +393 -4
- package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +484 -61
- package/templates/.agents/dashboard/modules/operations/src/react/export/export-layout.test.ts +23 -1
- package/templates/.agents/dashboard/modules/operations/src/react/export/xlsx-runtime-e2e.test.ts +248 -0
- package/templates/.agents/dashboard/modules/operations/src/react/index.ts +1 -0
- package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.test.ts +4 -4
- package/templates/.agents/dashboard/modules/operations/src/react/operation-duration.ts +6 -4
- package/templates/.agents/dashboard/modules/operations/src/react/operations-coverage-toast.test.ts +4 -3
- package/templates/.agents/dashboard/modules/operations/src/react/operations-date-filters.css +1 -1
- package/templates/.agents/dashboard/modules/operations/src/react/operations-global-filters.test.ts +4 -1
- package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +22 -12
- package/templates/.agents/dashboard/modules/operations/src/react/operations-overview.css +4 -0
- package/templates/.agents/dashboard/modules/operations/src/react/operations-overview.status-cards.test.ts +1 -1
- package/templates/.agents/dashboard/modules/operations/src/react/operations-page-contract.ts +53 -6
- package/templates/.agents/dashboard/modules/operations/src/react/operations-view-order.test.ts +2 -4
- package/templates/.agents/dashboard/modules/operations/src/react/period-summary.test.ts +82 -6
- package/templates/.agents/dashboard/modules/operations/src/react/period-summary.ts +1 -0
- package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.test.ts +2 -1
- package/templates/.agents/dashboard/modules/operations/src/react/work-board-model.ts +1 -1
- package/templates/.agents/dashboard/modules/operations/src/server/execution-relationship-counts.test.ts +19 -7
- package/templates/.agents/dashboard/modules/operations/src/server/execution-relationship-counts.ts +4 -1
- package/templates/.agents/dashboard/modules/operations/src/server/metric-coverage.ts +1 -0
- package/templates/.agents/dashboard/modules/operations/src/server/quick-daily-operations-projection.ts +11 -5
- 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/branding/src/index.ts +1 -1
- package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
- package/templates/.agents/dashboard/packages/contracts/src/index.ts +1 -0
- package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +533 -338
- package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +506 -311
- package/templates/.agents/dashboard/packages/local-runtime/gitignore.template +2 -0
- package/templates/.agents/dashboard/packages/local-runtime/package.json +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-dashboard.mjs +15 -7
- package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-runtime.mjs +44 -13
- package/templates/.agents/dashboard/packages/local-runtime/scripts/rebuild-sqlite-read-model.mjs +8 -3
- package/templates/.agents/dashboard/packages/local-runtime/scripts/source-size-runtime-scripts/sqlite-read-model-fixture.mjs +397 -0
- package/templates/.agents/dashboard/packages/local-runtime/scripts/test-sqlite-read-model.mjs +472 -145
- package/templates/.agents/dashboard/packages/local-runtime/scripts/test-unix-launchers.mjs +15 -3
- package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-sqlite-read-model.mjs +141 -33
- package/templates/.agents/dashboard/packages/local-runtime/server.mjs +533 -338
- package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.test.ts +6 -2
- package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.ts +3 -3
- package/templates/.agents/dashboard/packages/local-runtime/src/server-board.test.ts +89 -16
- package/templates/.agents/dashboard/packages/local-runtime/src/server-board.ts +33 -16
- package/templates/.agents/dashboard/packages/local-runtime/src/server-classification-page.test.ts +87 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-period-macro-metric.test.ts +44 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-period-macro-metric.ts +125 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-reconciliation-refresh.test.ts +66 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-request-authority.test.ts +61 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-request-authority.ts +18 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-run-projections.test.ts +42 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-refresh.ts +97 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot.test.ts +22 -5
- package/templates/.agents/dashboard/packages/local-runtime/src/server-sqlite-task-trace.ts +91 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-workspace.ts +7 -3
- package/templates/.agents/dashboard/packages/local-runtime/src/server.test-fixtures.ts +36 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +230 -132
- package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +224 -182
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-artifact-counts.ts +28 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.test.ts +63 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.ts +109 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-aggregates.ts +497 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-fast-page-parity.test-support.ts +65 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-page.test.ts +176 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-page.ts +119 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-projection.ts +41 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.test.ts +16 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.ts +29 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-cache.ts +355 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-persistence.ts +121 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-timing.ts +27 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-metric-contract.ts +16 -2
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-projection.ts +15 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.test.ts +223 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.ts +304 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-cache.test-support.ts +23 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-first-fold-types.ts +89 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider-fixture.ts +227 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider.test.ts +691 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.ts +81 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +1655 -567
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +2168 -1268
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-cache.ts +129 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-install.test.ts +26 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-install.ts +28 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-seed.test.ts +116 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.mjs +146 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.test.mjs +165 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-refresh.mjs +140 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +255 -289
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +94 -88
- package/templates/.agents/dashboard/packages/ui/package.json +1 -1
- package/templates/.agents/dashboard/packages/windows-launcher/Program.cs +5 -2
- package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
- package/templates/.agents/dashboard/tests/e2e/playwright.config.ts +4 -1
- package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-loading.spec.ts +142 -0
- package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-pagination.spec.ts +232 -0
- package/templates/.agents/dashboard/tests/e2e/specs/dashboard-performance-matrix.spec.ts +743 -0
- package/templates/.agents/dashboard/tests/e2e/specs/dashboard.spec.ts +189 -214
- package/templates/.agents/dashboard/zaip-dashboard-windows.exe +0 -0
- package/templates/.agents/design/.zaip-managed.json +3 -3
- package/templates/.agents/design/apps/catalog/package.json +1 -1
- package/templates/.agents/design/packages/local-runtime/package.json +1 -1
- package/templates/.agents/growth/estrategia-bootstrap-90-dias.md +169 -0
- package/templates/.agents/growth/strategy.md +27 -0
- package/templates/.agents/marketing/estrategia-marketing-zaip-90-dias.md +197 -0
- package/templates/.agents/marketing/strategy.md +29 -0
- package/templates/.agents/requirements/autonomous-assurance.md +6 -6
- 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 +3 -3
- package/templates/.agents/requirements/kanban-dashboard.md +10 -2
- package/templates/.agents/requirements/model-orchestration.md +1 -1
- package/templates/.agents/requirements/public-distribution.md +1 -1
- package/templates/.agents/requirements/software-architecture.md +1 -1
- package/templates/.agents/requirements/strategic-improvements.md +1 -1
- package/templates/.agents/requirements/work-lifecycle.md +4 -4
- package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
- package/templates/.agents/rules/dashboard-ui-consistency.md +14 -0
- package/templates/.agents/rules/frontend-lite.md +4 -4
- package/templates/.agents/rules/run-lifecycle-closure.md +4 -4
- package/templates/.agents/runtime/VERSION +1 -1
- package/templates/.agents/runtime/bin/zaip.mjs +1142 -1041
- package/templates/.agents/runtime/checksums.sha256 +6 -6
- package/templates/.agents/runtime/manifest.json +1 -1
- package/templates/.agents/runtime/pnpm-lock.sha256 +1 -1
- package/templates/.agents/runtime/provenance.json +5 -5
- package/templates/.agents/runtime/sbom.cdx.json +3 -3
- package/templates/.agents/sales/playbook.md +32 -0
- package/templates/.agents/sales/roteiro-comercial-zaip.md +252 -0
- package/templates/.agents/skills/criar-pasta-obsidian/scripts/generate-obsidian-vault.test.mjs +20 -16
- package/templates/.agents/skills/zaip-aios/SKILL.md +1 -1
- package/templates/.agents/skills/zaip-skill-agent-catalog/SKILL.md +22 -0
- package/templates/.agents/skills/zaip-skill-agent-catalog/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-author-skills/SKILL.md +3 -2
- package/templates/.agents/skills/zaip-skill-author-skills/scripts/audit-skill-catalog.mjs +49 -0
- package/templates/.agents/skills/zaip-skill-author-skills/scripts/author-skill-scripts.test.mjs +27 -0
- package/templates/.agents/skills/zaip-skill-author-skills/scripts/run-skill-tests.mjs +37 -0
- package/templates/.agents/skills/zaip-skill-backend/SKILL.md +1 -0
- package/templates/.agents/skills/zaip-skill-brand-governance/SKILL.md +9 -2
- package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-framework.md +39 -0
- package/templates/.agents/skills/zaip-skill-brand-governance/references/brandbook-standards.md +1 -1
- package/templates/.agents/skills/zaip-skill-change/SKILL.md +1 -1
- package/templates/.agents/skills/zaip-skill-change/references/observable-evidence.md +83 -0
- package/templates/.agents/skills/zaip-skill-dashboard-diagnostics/SKILL.md +22 -0
- package/templates/.agents/skills/zaip-skill-dashboard-diagnostics/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-enforce-architecture/SKILL.md +2 -0
- package/templates/.agents/skills/zaip-skill-execution/SKILL.md +1 -1
- package/templates/.agents/skills/zaip-skill-frontend/SKILL.md +4 -3
- package/templates/.agents/skills/zaip-skill-frontend/agents/openai.yaml +2 -2
- package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +10 -10
- package/templates/.agents/skills/zaip-skill-growth-strategy-revops/SKILL.md +6 -0
- package/templates/.agents/skills/zaip-skill-lifecycle-closure/SKILL.md +27 -0
- package/templates/.agents/skills/zaip-skill-lifecycle-closure/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-marketing/SKILL.md +6 -0
- package/templates/.agents/skills/zaip-skill-prd/SKILL.md +4 -0
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.mjs +111 -104
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-explicit-recovery.mjs +223 -0
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.mjs +55 -9
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.test.mjs +145 -14
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.mjs +19 -9
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.test.mjs +82 -5
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/source-size-telemetry/model-identity-reconciliation.mjs +77 -0
- package/templates/.agents/skills/zaip-skill-release-qualification/SKILL.md +20 -0
- package/templates/.agents/skills/zaip-skill-release-qualification/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-review/SKILL.md +5 -0
- package/templates/.agents/skills/zaip-skill-rules/SKILL.md +1 -1
- package/templates/.agents/skills/zaip-skill-sales-methodology/SKILL.md +6 -0
- package/templates/.agents/skills/zaip-skill-spec/SKILL.md +4 -0
- package/templates/.agents/skills/zaip-skill-sqlite-read-model/SKILL.md +22 -90
- package/templates/.agents/skills/zaip-skill-sqlite-read-model/scripts/ensure-node.mjs +28 -5
- package/templates/.agents/zaip-aios/INDEX.md +57 -22
- package/templates/.agents/zaip-aios/README.md +24 -13
- package/templates/.agents/zaip-aios/VERSION +1 -1
- package/templates/.agents/zaip-aios/guides/02-requirements.md +5 -0
- package/templates/.agents/zaip-aios/guides/06-execucao.md +13 -4
- package/templates/.agents/zaip-aios/guides/07-revisao-e-validacao.md +7 -0
- package/templates/.agents/zaip-aios/guides/10-seguranca.md +23 -0
- package/templates/.agents/zaip-aios/guides/11-observabilidade-e-custos.md +6 -6
- package/templates/.agents/zaip-aios/guides/13-boas-praticas.md +3 -0
- package/templates/.agents/zaip-aios/guides/16-lifecycle-e-reconciliacao.md +12 -3
- package/templates/.agents/zaip-aios/guides/17-como-o-custo-e-calculado.md +5 -5
- package/templates/.agents/zaip-aios/guides/18-catalogo-de-agentes.md +76 -0
- package/templates/.agents/zaip-aios/guides/19-assurance-e-autonomia.md +95 -0
- package/templates/.agents/zaip-aios/guides/20-instalacao-detalhada.md +366 -0
- package/templates/.agents/zaip-aios/guides/21-telemetria-monitor-custos.md +46 -0
- package/templates/.agents/zaip-aios/guides/22-fluxos-e-roteamento.md +74 -0
- package/templates/.agents/zaip-aios/guides/23-orquestracao-de-modelos.md +483 -0
- package/templates/.agents/zaip-aios/guides/24-calculo-de-custos-openai.md +85 -0
- package/templates/.agents/zaip-aios/guides/25-fontes-de-precos-openai.md +19 -0
- package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +111 -0
- package/templates/.agents/zaip-aios/guides/27-telemetria-git-native.md +172 -0
- package/templates/.agents/zaip-aios/guides/28-lifecycle-completo.md +149 -0
- package/templates/.agents/zaip-aios/guides/assets/diagrams/lifecycles-task-spec-prd.png +0 -0
- package/templates/.agents/zaip-aios/guides/assets/diagrams/prd-lifecycle.png +0 -0
- package/templates/.agents/zaip-aios/guides/assets/diagrams/spec-lifecycle.png +0 -0
- package/templates/.agents/zaip-aios/guides/assets/diagrams/task-lifecycle.png +0 -0
- package/templates/template-manifest.json +756 -235
- package/templates/.agents/dashboard/apps/frontend/dist/assets/DashboardHelpDialog-Cs6dzDmW.js +0 -1505
- package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-QE1k9yZB.css +0 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-_Pf5DA_A.js +0 -3
- package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-BVlz3DLZ.js +0 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-BZ5WdaMN.css +0 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-Cf9ctPVt.js +0 -68
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-8A4DcNXM.js +0 -2
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-DK_enB5Z.css +0 -1
- package/templates/.agents/dashboard/apps/frontend/src/use-idle-cost-prefetch.ts +0 -45
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { copyFile, mkdir, readdir, rename, rm, stat } from "node:fs/promises";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { DatabaseSync } from "node:sqlite";
|
|
5
|
+
|
|
6
|
+
export async function pruneSnapshotCache(directory: string, activePath: string): Promise<void> {
|
|
7
|
+
const entries = await readdir(directory, { withFileTypes: true }).catch(() => []);
|
|
8
|
+
const stale = await Promise.all(
|
|
9
|
+
entries
|
|
10
|
+
.filter(
|
|
11
|
+
(entry) =>
|
|
12
|
+
entry.isFile() &&
|
|
13
|
+
entry.name.endsWith(".sqlite") &&
|
|
14
|
+
resolve(directory, entry.name) !== activePath,
|
|
15
|
+
)
|
|
16
|
+
.map(async (entry) => ({
|
|
17
|
+
path: resolve(directory, entry.name),
|
|
18
|
+
mtime: (await stat(resolve(directory, entry.name))).mtimeMs,
|
|
19
|
+
})),
|
|
20
|
+
);
|
|
21
|
+
for (const entry of stale.sort((a, b) => b.mtime - a.mtime).slice(1))
|
|
22
|
+
await rm(entry.path, { force: true }).catch(() => {});
|
|
23
|
+
for (const entry of entries) {
|
|
24
|
+
if (!entry.isFile() || !entry.name.includes(".sqlite.") || !entry.name.includes(".tmp"))
|
|
25
|
+
continue;
|
|
26
|
+
const candidate = resolve(directory, entry.name);
|
|
27
|
+
if (Date.now() - (await stat(candidate)).mtimeMs > 60_000)
|
|
28
|
+
await rm(candidate, { force: true }).catch(() => {});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function readSnapshotFileCount(
|
|
33
|
+
path: string,
|
|
34
|
+
fingerprint: string,
|
|
35
|
+
schemaVersion: string,
|
|
36
|
+
hasRequiredPayloads: (database: DatabaseSync) => boolean,
|
|
37
|
+
): number | null {
|
|
38
|
+
try {
|
|
39
|
+
const database = new DatabaseSync(path, { readOnly: true });
|
|
40
|
+
const value = (key: string) =>
|
|
41
|
+
(
|
|
42
|
+
database.prepare("SELECT value FROM zaip_vw_read_model_metadata WHERE key = ?").get(key) as
|
|
43
|
+
| { value?: string }
|
|
44
|
+
| undefined
|
|
45
|
+
)?.value;
|
|
46
|
+
const files = Number(value("source_file_count") ?? 0);
|
|
47
|
+
const result =
|
|
48
|
+
value("source_fingerprint") === fingerprint &&
|
|
49
|
+
value("schema_version") === schemaVersion &&
|
|
50
|
+
hasRequiredPayloads(database)
|
|
51
|
+
? files
|
|
52
|
+
: null;
|
|
53
|
+
database.close();
|
|
54
|
+
return result;
|
|
55
|
+
} catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function mostRecentCompatibleSnapshot(
|
|
61
|
+
directory: string,
|
|
62
|
+
schemaVersion: string,
|
|
63
|
+
hasRequiredPayloads: (database: DatabaseSync) => boolean,
|
|
64
|
+
): Promise<{ path: string; files: number } | null> {
|
|
65
|
+
const entries = await readdir(directory, { withFileTypes: true }).catch(() => []);
|
|
66
|
+
const candidates = await Promise.all(
|
|
67
|
+
entries
|
|
68
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith(".sqlite"))
|
|
69
|
+
.map(async (entry) => ({
|
|
70
|
+
path: join(directory, entry.name),
|
|
71
|
+
mtime: (await stat(join(directory, entry.name))).mtimeMs,
|
|
72
|
+
})),
|
|
73
|
+
);
|
|
74
|
+
for (const candidate of candidates.sort((left, right) => right.mtime - left.mtime)) {
|
|
75
|
+
const files = readCompatibleSnapshotFileCount(
|
|
76
|
+
candidate.path,
|
|
77
|
+
schemaVersion,
|
|
78
|
+
hasRequiredPayloads,
|
|
79
|
+
);
|
|
80
|
+
if (files !== null) return { path: candidate.path, files };
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function readCompatibleSnapshotFileCount(
|
|
86
|
+
path: string,
|
|
87
|
+
schemaVersion: string,
|
|
88
|
+
hasRequiredPayloads: (database: DatabaseSync) => boolean,
|
|
89
|
+
): number | null {
|
|
90
|
+
try {
|
|
91
|
+
const database = new DatabaseSync(path, { readOnly: true });
|
|
92
|
+
const value = (key: string) =>
|
|
93
|
+
(
|
|
94
|
+
database.prepare("SELECT value FROM zaip_vw_read_model_metadata WHERE key = ?").get(key) as
|
|
95
|
+
| { value?: string }
|
|
96
|
+
| undefined
|
|
97
|
+
)?.value;
|
|
98
|
+
const files = Number(value("source_file_count") ?? 0);
|
|
99
|
+
const result =
|
|
100
|
+
value("schema_version") === schemaVersion && hasRequiredPayloads(database) ? files : null;
|
|
101
|
+
database.close();
|
|
102
|
+
return result;
|
|
103
|
+
} catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function installLegacyViewAliases(database: DatabaseSync): void {
|
|
109
|
+
const views = database
|
|
110
|
+
.prepare("SELECT name FROM sqlite_master WHERE type = 'view' AND name LIKE 'zaip_vw_%'")
|
|
111
|
+
.all() as Array<{ name: string }>;
|
|
112
|
+
for (const { name } of views) {
|
|
113
|
+
const alias = name.slice("zaip_vw_".length);
|
|
114
|
+
const quoted = (identifier: string) => `"${identifier.replaceAll('"', '""')}"`;
|
|
115
|
+
database.exec(`CREATE TEMP VIEW ${quoted(alias)} AS SELECT * FROM main.${quoted(name)}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export async function materializeSnapshot(source: string, destination: string): Promise<void> {
|
|
120
|
+
await mkdir(dirname(destination), { recursive: true });
|
|
121
|
+
const temporaryPath = `${destination}.${process.pid}.${randomUUID()}.tmp`;
|
|
122
|
+
await copyFile(source, temporaryPath);
|
|
123
|
+
try {
|
|
124
|
+
await rename(temporaryPath, destination);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
await rm(temporaryPath, { force: true });
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
}
|
package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-install.test.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
5
|
+
import { activateStagedSqliteSnapshot } from "./sqlite-snapshot-install.js";
|
|
6
|
+
|
|
7
|
+
const temporaryDirectories: string[] = [];
|
|
8
|
+
|
|
9
|
+
afterEach(async () => {
|
|
10
|
+
await Promise.all(
|
|
11
|
+
temporaryDirectories.splice(0).map((directory) => rm(directory, { recursive: true })),
|
|
12
|
+
);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe("SQLite snapshot handoff", () => {
|
|
16
|
+
it("renames the validated stage synchronously during the close/reopen handoff", async () => {
|
|
17
|
+
const directory = await mkdtemp(join(tmpdir(), "zaip-snapshot-install-"));
|
|
18
|
+
temporaryDirectories.push(directory);
|
|
19
|
+
const staged = join(directory, "next.sqlite");
|
|
20
|
+
const destination = join(directory, "read-model.sqlite");
|
|
21
|
+
await writeFile(staged, "next-generation");
|
|
22
|
+
|
|
23
|
+
expect(activateStagedSqliteSnapshot(staged, destination)).toBeUndefined();
|
|
24
|
+
await expect(readFile(destination, "utf8")).resolves.toBe("next-generation");
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { renameSync } from "node:fs";
|
|
2
|
+
import { copyFile, mkdir, rm } from "node:fs/promises";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
|
|
5
|
+
export async function stageSqliteSnapshot(
|
|
6
|
+
source: string,
|
|
7
|
+
destination: string,
|
|
8
|
+
validate: (path: string) => unknown,
|
|
9
|
+
) {
|
|
10
|
+
await mkdir(dirname(destination), { recursive: true });
|
|
11
|
+
const staged = `${destination}.${process.pid}.refresh.tmp`;
|
|
12
|
+
await copyFile(source, staged);
|
|
13
|
+
try {
|
|
14
|
+
validate(staged);
|
|
15
|
+
return staged;
|
|
16
|
+
} catch (error) {
|
|
17
|
+
await rm(staged, { force: true });
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Called after the old connection is closed. Keep the handoff in this tick so
|
|
24
|
+
* no request can observe a closed SQLite handle between close and replacement.
|
|
25
|
+
*/
|
|
26
|
+
export function activateStagedSqliteSnapshot(staged: string, destination: string) {
|
|
27
|
+
renameSync(staged, destination);
|
|
28
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { copyFile, mkdir, mkdtemp, readdir, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { DatabaseSync } from "node:sqlite";
|
|
5
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
6
|
+
import { hasRequiredFirstFoldPayloads } from "./sqlite-first-fold-persistence.js";
|
|
7
|
+
import { rebuildSqliteReadModel, SqliteReadModelFileSystem } from "./sqlite-read-model.js";
|
|
8
|
+
|
|
9
|
+
const roots: string[] = [];
|
|
10
|
+
|
|
11
|
+
afterEach(async () => {
|
|
12
|
+
await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe("SQLite snapshot seed publication", () => {
|
|
16
|
+
it("skips a newer incomplete seed and materializes the prior complete cache", async () => {
|
|
17
|
+
const root = await mkdtemp(join(tmpdir(), "zaip-snapshot-seed-"));
|
|
18
|
+
roots.push(root);
|
|
19
|
+
const task = join(root, ".agents", "records", "tasks", "task.md");
|
|
20
|
+
await mkdir(join(root, ".agents", "records", "tasks"), { recursive: true });
|
|
21
|
+
await mkdir(join(root, ".agents", "config"), { recursive: true });
|
|
22
|
+
await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n");
|
|
23
|
+
await writeFile(task, "# original\n");
|
|
24
|
+
await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({ cache: "rebuilt" });
|
|
25
|
+
const cacheDirectory = join(root, ".local", "dashboard-sqlite", "cache");
|
|
26
|
+
const completeName = (await readdir(cacheDirectory)).find((name) => name.endsWith(".sqlite"));
|
|
27
|
+
expect(completeName).toBeDefined();
|
|
28
|
+
if (completeName === undefined) throw new Error("Expected a complete SQLite seed");
|
|
29
|
+
const incomplete = join(cacheDirectory, "v67-ff5-incomplete-newest.sqlite");
|
|
30
|
+
await copyFile(join(cacheDirectory, completeName), incomplete);
|
|
31
|
+
const incompleteDatabase = new DatabaseSync(incomplete);
|
|
32
|
+
incompleteDatabase
|
|
33
|
+
.prepare("DELETE FROM zaip_aios_activities WHERE payload_type='first_fold_all_time_cache'")
|
|
34
|
+
.run();
|
|
35
|
+
incompleteDatabase.close();
|
|
36
|
+
await writeFile(task, "# changed canonically\n");
|
|
37
|
+
const previousPath = process.env.ZAIP_SQLITE_DB_PATH;
|
|
38
|
+
const previousSeed = process.env.ZAIP_SQLITE_PREFER_LAST_VALID_SEED;
|
|
39
|
+
try {
|
|
40
|
+
process.env.ZAIP_SQLITE_DB_PATH = join(root, ".local", "dashboard-sqlite", "next.sqlite");
|
|
41
|
+
process.env.ZAIP_SQLITE_PREFER_LAST_VALID_SEED = "1";
|
|
42
|
+
await expect(rebuildSqliteReadModel(root)).resolves.toMatchObject({
|
|
43
|
+
cache: "stale_seed",
|
|
44
|
+
files: 2,
|
|
45
|
+
});
|
|
46
|
+
const served = new SqliteReadModelFileSystem(root);
|
|
47
|
+
try {
|
|
48
|
+
expect(served.firstFoldAllTime()).toBeDefined();
|
|
49
|
+
expect(served.firstFoldBoardAllTime()).toBeDefined();
|
|
50
|
+
} finally {
|
|
51
|
+
served.close();
|
|
52
|
+
}
|
|
53
|
+
} finally {
|
|
54
|
+
if (previousPath === undefined) delete process.env.ZAIP_SQLITE_DB_PATH;
|
|
55
|
+
else process.env.ZAIP_SQLITE_DB_PATH = previousPath;
|
|
56
|
+
if (previousSeed === undefined) delete process.env.ZAIP_SQLITE_PREFER_LAST_VALID_SEED;
|
|
57
|
+
else process.env.ZAIP_SQLITE_PREFER_LAST_VALID_SEED = previousSeed;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("rejects a seed whose board payload is truncated below canonical work", async () => {
|
|
62
|
+
const root = await mkdtemp(join(tmpdir(), "zaip-snapshot-truncated-"));
|
|
63
|
+
roots.push(root);
|
|
64
|
+
await mkdir(join(root, ".agents", "records", "tasks"), { recursive: true });
|
|
65
|
+
await mkdir(join(root, ".agents", "config"), { recursive: true });
|
|
66
|
+
await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n");
|
|
67
|
+
await writeFile(
|
|
68
|
+
join(root, ".agents", "records", "tasks", "task.md"),
|
|
69
|
+
"---\nid: TASK-SEED-POPULATION\ntitle: Seed population\nstatus: ready\nrisk: standard\ncreated_at: 2026-08-01T12:00:00.000Z\n---\n# Seed population\n",
|
|
70
|
+
);
|
|
71
|
+
await rebuildSqliteReadModel(root);
|
|
72
|
+
const seed = join(
|
|
73
|
+
root,
|
|
74
|
+
".local",
|
|
75
|
+
"dashboard-sqlite",
|
|
76
|
+
"cache",
|
|
77
|
+
(await readdir(join(root, ".local", "dashboard-sqlite", "cache"))).find((name) =>
|
|
78
|
+
name.endsWith(".sqlite"),
|
|
79
|
+
) ?? "missing.sqlite",
|
|
80
|
+
);
|
|
81
|
+
const database = new DatabaseSync(seed);
|
|
82
|
+
try {
|
|
83
|
+
database
|
|
84
|
+
.prepare(
|
|
85
|
+
"UPDATE zaip_aios_activities SET payload_json=json_set(payload_json, '$.pages.task', json('[]')) WHERE payload_type='first_fold_all_time_board_cache'",
|
|
86
|
+
)
|
|
87
|
+
.run();
|
|
88
|
+
expect(hasRequiredFirstFoldPayloads(database)).toBe(false);
|
|
89
|
+
} finally {
|
|
90
|
+
database.close();
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("accepts a complete monthly payload when historical work was recorded on rebuild day", async () => {
|
|
95
|
+
const root = await mkdtemp(join(tmpdir(), "zaip-snapshot-monthly-day-"));
|
|
96
|
+
roots.push(root);
|
|
97
|
+
await mkdir(join(root, ".agents", "records", "tasks"), { recursive: true });
|
|
98
|
+
await mkdir(join(root, ".agents", "config"), { recursive: true });
|
|
99
|
+
await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n");
|
|
100
|
+
await writeFile(
|
|
101
|
+
join(root, ".agents", "records", "tasks", "historical-task.md"),
|
|
102
|
+
"---\nid: TASK-SEED-HISTORICAL\ntitle: Historical seed task\nstatus: ready\nrisk: standard\ncreated_at: 2026-07-01T12:00:00.000Z\n---\n# Historical seed task\n",
|
|
103
|
+
);
|
|
104
|
+
await rebuildSqliteReadModel(root);
|
|
105
|
+
const cacheDirectory = join(root, ".local", "dashboard-sqlite", "cache");
|
|
106
|
+
const seedName = (await readdir(cacheDirectory)).find((name) => name.endsWith(".sqlite"));
|
|
107
|
+
expect(seedName).toBeDefined();
|
|
108
|
+
if (seedName === undefined) throw new Error("Expected a complete SQLite seed");
|
|
109
|
+
const database = new DatabaseSync(join(cacheDirectory, seedName), { readOnly: true });
|
|
110
|
+
try {
|
|
111
|
+
expect(hasRequiredFirstFoldPayloads(database)).toBe(true);
|
|
112
|
+
} finally {
|
|
113
|
+
database.close();
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
});
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { createServer as createHttpServer } from "node:http";
|
|
2
|
+
|
|
3
|
+
export async function createDashboardLaunchPage({ port, host, runtimeKind, healthPath, delay }) {
|
|
4
|
+
let redirectUrl = null;
|
|
5
|
+
let failure = null;
|
|
6
|
+
let progress = {
|
|
7
|
+
percent: 4,
|
|
8
|
+
phase: "Iniciando o launcher local",
|
|
9
|
+
detail: "Abrindo a página de preparação.",
|
|
10
|
+
};
|
|
11
|
+
const connections = new Set();
|
|
12
|
+
let resolveRedirectObserved;
|
|
13
|
+
const redirectObserved = new Promise((resolveObserved) => {
|
|
14
|
+
resolveRedirectObserved = resolveObserved;
|
|
15
|
+
});
|
|
16
|
+
let resolveFailureObserved;
|
|
17
|
+
const failureObserved = new Promise((resolveObserved) => {
|
|
18
|
+
resolveFailureObserved = resolveObserved;
|
|
19
|
+
});
|
|
20
|
+
const server = createHttpServer((request, response) => {
|
|
21
|
+
response.setHeader("Cache-Control", "no-store");
|
|
22
|
+
if (request.url?.startsWith("/api/v2/ready")) {
|
|
23
|
+
if (redirectUrl !== null) resolveRedirectObserved(true);
|
|
24
|
+
if (failure !== null) resolveFailureObserved(true);
|
|
25
|
+
response.writeHead(failure === null ? 200 : 503, {
|
|
26
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
27
|
+
});
|
|
28
|
+
response.end(JSON.stringify({ target: redirectUrl, failure }));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (request.url?.startsWith("/api/v2/progress")) {
|
|
32
|
+
if (failure !== null) resolveFailureObserved(true);
|
|
33
|
+
response.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
34
|
+
response.end(JSON.stringify({ ...progress, failure }));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (request.url?.startsWith(healthPath)) {
|
|
38
|
+
response.writeHead(503, { "Content-Type": "application/json; charset=utf-8" });
|
|
39
|
+
response.end(JSON.stringify({ kind: "zaip-dashboard-launcher", status: "starting" }));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
response.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
43
|
+
response.end(`<!doctype html>
|
|
44
|
+
<html lang="pt-BR">
|
|
45
|
+
<head>
|
|
46
|
+
<meta charset="utf-8">
|
|
47
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
48
|
+
<title>Dashboard Zaip AIOS</title>
|
|
49
|
+
<style>
|
|
50
|
+
:root{color-scheme:dark;font-family:Inter,system-ui,sans-serif;background:#010610;color:#f1f5f9}
|
|
51
|
+
*{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}
|
|
52
|
+
.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;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)}.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}
|
|
53
|
+
</style>
|
|
54
|
+
</head>
|
|
55
|
+
<body>
|
|
56
|
+
<main class="launch-overlay" aria-label="Preparando dashboard">
|
|
57
|
+
<section class="progress" aria-live="polite" role="status"><strong id="phase">Iniciando o launcher local</strong><span id="detail">Abrindo a página de preparação.</span><div class="track" id="track" aria-label="Preparação em andamento"><div class="bar" id="bar"></div></div><span class="handoff" id="handoff">O dashboard está pronto. Abrindo a tela principal automaticamente…</span><span class="failure" id="failure" role="alert"></span></section>
|
|
58
|
+
</main>
|
|
59
|
+
<script>
|
|
60
|
+
let handoffTarget=null,progressRequestInFlight=false,terminalFailure=false;
|
|
61
|
+
function showHandoff(target){handoffTarget=target;document.getElementById("handoff").style.display="block";document.getElementById("phase").textContent="Dashboard pronto";document.getElementById("detail").textContent="Concluindo a abertura da tela principal."}
|
|
62
|
+
function showFailure(next){terminalFailure=true;clearInterval(progressPoll);document.getElementById("phase").textContent=next.phase;document.getElementById("detail").textContent="A preparação não foi concluída. Consulte a mensagem abaixo para agir.";document.getElementById("bar").style.width="100%";document.getElementById("handoff").style.display="none";document.getElementById("failure").textContent=next.detail;document.getElementById("failure").style.display="block";document.querySelector(".progress").classList.add("terminal-failure")}
|
|
63
|
+
async function updateProgress(){if(progressRequestInFlight||terminalFailure)return terminalFailure;progressRequestInFlight=true;try{const r=await fetch("/api/v2/progress",{cache:"no-store",signal:AbortSignal.timeout(1000)});const p=await r.json();if(terminalFailure)return true;if(p.failure){showFailure(p.failure);return true}if(!handoffTarget){document.getElementById("phase").textContent=p.phase;document.getElementById("detail").textContent=p.detail};if(!terminalFailure)document.getElementById("bar").style.width=Math.max(4,Math.min(100,Number(p.percent)||4))+"%"}catch{}finally{progressRequestInFlight=false}return terminalFailure}
|
|
64
|
+
const progressPoll=setInterval(updateProgress,250);
|
|
65
|
+
async function waitForDashboard(){try{if(await updateProgress())return;const ready=await fetch("/api/v2/ready",{cache:"no-store",signal:AbortSignal.timeout(1000)});const next=await ready.json();if(next.failure){showFailure(next.failure);return}if(next.target){showHandoff(next.target);clearInterval(progressPoll);setTimeout(()=>location.replace(next.target),0);return}const response=await fetch("${healthPath}",{cache:"no-store",signal:AbortSignal.timeout(1000)});const payload=await response.json();if(response.ok&&payload.kind==="${runtimeKind}"){clearInterval(progressPoll);location.reload();return}}catch{}setTimeout(waitForDashboard,250)}
|
|
66
|
+
updateProgress();setTimeout(waitForDashboard,100)
|
|
67
|
+
setTimeout(()=>{if(handoffTarget)showHandoff(handoffTarget)},4000)
|
|
68
|
+
</script>
|
|
69
|
+
</body>
|
|
70
|
+
</html>`);
|
|
71
|
+
});
|
|
72
|
+
server.on("connection", (connection) => {
|
|
73
|
+
connections.add(connection);
|
|
74
|
+
connection.once("close", () => connections.delete(connection));
|
|
75
|
+
});
|
|
76
|
+
await new Promise((resolveListen, rejectListen) => {
|
|
77
|
+
server.once("error", rejectListen);
|
|
78
|
+
server.listen({ host, port }, resolveListen);
|
|
79
|
+
});
|
|
80
|
+
server.unref();
|
|
81
|
+
const address = server.address();
|
|
82
|
+
const listeningPort = typeof address === "object" && address !== null ? address.port : port;
|
|
83
|
+
return {
|
|
84
|
+
port: listeningPort,
|
|
85
|
+
redirect: (target) => {
|
|
86
|
+
redirectUrl = target;
|
|
87
|
+
},
|
|
88
|
+
setProgress: (next) => {
|
|
89
|
+
progress = {
|
|
90
|
+
...progress,
|
|
91
|
+
...next,
|
|
92
|
+
percent: Math.max(progress.percent, next.percent ?? progress.percent),
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
setFailure: (next) => {
|
|
96
|
+
failure = { phase: next.phase, detail: next.detail };
|
|
97
|
+
progress = {
|
|
98
|
+
...progress,
|
|
99
|
+
...next,
|
|
100
|
+
percent: Math.max(progress.percent, next.percent ?? progress.percent),
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
waitForRedirect: async (timeoutMs = 1_500) =>
|
|
104
|
+
Promise.race([redirectObserved, delay(timeoutMs).then(() => false)]),
|
|
105
|
+
closeAfterHandoffGrace: (graceMs = 12_000) => {
|
|
106
|
+
const timer = setTimeout(() => {
|
|
107
|
+
void server.close();
|
|
108
|
+
server.closeAllConnections?.();
|
|
109
|
+
for (const connection of connections) connection.destroy();
|
|
110
|
+
}, graceMs);
|
|
111
|
+
timer.unref?.();
|
|
112
|
+
},
|
|
113
|
+
closeAfterFailureObservation: (graceMs = 12_000) => {
|
|
114
|
+
server.ref();
|
|
115
|
+
return Promise.race([failureObserved, delay(graceMs)]).then(
|
|
116
|
+
() =>
|
|
117
|
+
new Promise((resolveClosed) => {
|
|
118
|
+
setTimeout(() => {
|
|
119
|
+
server.closeAllConnections?.();
|
|
120
|
+
for (const connection of connections) connection.destroy();
|
|
121
|
+
void server.close(() => resolveClosed());
|
|
122
|
+
}, 250);
|
|
123
|
+
}),
|
|
124
|
+
);
|
|
125
|
+
},
|
|
126
|
+
close: ({ forceAfterMs = 750 } = {}) =>
|
|
127
|
+
new Promise((resolveClose, rejectClose) => {
|
|
128
|
+
if (!server.listening) {
|
|
129
|
+
resolveClose();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
let forceTimer = null;
|
|
133
|
+
const finish = (error) => {
|
|
134
|
+
if (forceTimer !== null) clearTimeout(forceTimer);
|
|
135
|
+
if (error) rejectClose(error);
|
|
136
|
+
else resolveClose();
|
|
137
|
+
};
|
|
138
|
+
server.close(finish);
|
|
139
|
+
forceTimer = setTimeout(() => {
|
|
140
|
+
server.closeAllConnections?.();
|
|
141
|
+
for (const connection of connections) connection.destroy();
|
|
142
|
+
}, forceAfterMs);
|
|
143
|
+
forceTimer.unref?.();
|
|
144
|
+
}),
|
|
145
|
+
};
|
|
146
|
+
}
|
package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.test.mjs
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { connect } from "node:net";
|
|
2
|
+
import { chromium } from "@playwright/test";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
import { host, startDashboardLaunchPage } from "./start-dashboard.mjs";
|
|
5
|
+
|
|
6
|
+
describe("dashboard launch page", () => {
|
|
7
|
+
it("serves an accessible active progress overlay and an automatic handoff while the runtime starts", async () => {
|
|
8
|
+
const launchPage = await startDashboardLaunchPage(0);
|
|
9
|
+
try {
|
|
10
|
+
const page = await fetch(`http://${host}:${launchPage.port}/?token=temporary`);
|
|
11
|
+
const health = await fetch(`http://${host}:${launchPage.port}/api/v2/health`);
|
|
12
|
+
|
|
13
|
+
expect(page.status).toBe(200);
|
|
14
|
+
const html = await page.text();
|
|
15
|
+
expect(html).toContain('class="launch-overlay"');
|
|
16
|
+
expect(html).toContain("position:fixed;inset:0;width:100vw;height:100vh");
|
|
17
|
+
expect(html).toContain("display:grid;place-items:center");
|
|
18
|
+
expect(html).toContain('aria-live="polite" role="status"');
|
|
19
|
+
expect(html).toContain('aria-label="Preparação em andamento"');
|
|
20
|
+
expect(html).toContain("animation:launch-activity 1.35s ease-in-out infinite");
|
|
21
|
+
expect(html).toContain("@media (prefers-reduced-motion:reduce)");
|
|
22
|
+
expect(html).toContain("O dashboard está pronto. Abrindo a tela principal automaticamente…");
|
|
23
|
+
expect(html).not.toContain("abra o dashboard agora");
|
|
24
|
+
expect(html).not.toContain('id="handoff-link"');
|
|
25
|
+
expect(html).toContain("function showHandoff(target)");
|
|
26
|
+
const progress = await fetch(`http://${host}:${launchPage.port}/api/v2/progress`);
|
|
27
|
+
await expect(progress.json()).resolves.toMatchObject({
|
|
28
|
+
phase: "Iniciando o launcher local",
|
|
29
|
+
percent: expect.any(Number),
|
|
30
|
+
});
|
|
31
|
+
expect(health.status).toBe(503);
|
|
32
|
+
await expect(health.json()).resolves.toEqual({
|
|
33
|
+
kind: "zaip-dashboard-launcher",
|
|
34
|
+
status: "starting",
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
launchPage.redirect("http://127.0.0.1:4317/?token=reused-session");
|
|
38
|
+
const ready = await fetch(`http://${host}:${launchPage.port}/api/v2/ready`);
|
|
39
|
+
await expect(ready.json()).resolves.toEqual({
|
|
40
|
+
target: "http://127.0.0.1:4317/?token=reused-session",
|
|
41
|
+
failure: null,
|
|
42
|
+
});
|
|
43
|
+
await expect(launchPage.waitForRedirect(10)).resolves.toBe(true);
|
|
44
|
+
} finally {
|
|
45
|
+
await launchPage.close();
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("keeps the handoff hidden until a real handoff target exists while progress polling continues", async () => {
|
|
50
|
+
const launchPage = await startDashboardLaunchPage(0);
|
|
51
|
+
const browser = await chromium.launch();
|
|
52
|
+
try {
|
|
53
|
+
const page = await browser.newPage();
|
|
54
|
+
await page.route("**/api/v2/ready", (route) =>
|
|
55
|
+
route.fulfill({ contentType: "application/json", body: JSON.stringify({ target: null }) }),
|
|
56
|
+
);
|
|
57
|
+
await page.route("**/api/v2/health", () => new Promise(() => {}));
|
|
58
|
+
await page.goto(`http://${host}:${launchPage.port}/?token=temporary`);
|
|
59
|
+
|
|
60
|
+
await expect
|
|
61
|
+
.poll(() =>
|
|
62
|
+
page.locator("#handoff").evaluate((element) => getComputedStyle(element).display),
|
|
63
|
+
)
|
|
64
|
+
.toBe("none");
|
|
65
|
+
launchPage.setProgress({ percent: 64, phase: "Atualizando progresso independente" });
|
|
66
|
+
await expect
|
|
67
|
+
.poll(() => page.locator("#phase").textContent())
|
|
68
|
+
.toBe("Atualizando progresso independente");
|
|
69
|
+
|
|
70
|
+
await page.evaluate(() => window.showHandoff("http://127.0.0.1:4417/?token=ready"));
|
|
71
|
+
await expect
|
|
72
|
+
.poll(() =>
|
|
73
|
+
page.locator("#handoff").evaluate((element) => getComputedStyle(element).display),
|
|
74
|
+
)
|
|
75
|
+
.toBe("block");
|
|
76
|
+
} finally {
|
|
77
|
+
await browser.close();
|
|
78
|
+
await launchPage.close();
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("publishes a durable preparation failure without returning a false ready target", async () => {
|
|
83
|
+
const launchPage = await startDashboardLaunchPage(0);
|
|
84
|
+
const browser = await chromium.launch();
|
|
85
|
+
try {
|
|
86
|
+
launchPage.setFailure({
|
|
87
|
+
percent: 100,
|
|
88
|
+
phase: "Não foi possível preparar o dashboard",
|
|
89
|
+
detail: "A verificação local falhou.",
|
|
90
|
+
});
|
|
91
|
+
const ready = await fetch(`http://${host}:${launchPage.port}/api/v2/ready`);
|
|
92
|
+
expect(ready.status).toBe(503);
|
|
93
|
+
await expect(ready.json()).resolves.toEqual({
|
|
94
|
+
target: null,
|
|
95
|
+
failure: {
|
|
96
|
+
phase: "Não foi possível preparar o dashboard",
|
|
97
|
+
detail: "A verificação local falhou.",
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const page = await browser.newPage();
|
|
102
|
+
await page.goto(`http://${host}:${launchPage.port}/?token=temporary`);
|
|
103
|
+
await expect
|
|
104
|
+
.poll(() => page.locator("#failure").textContent())
|
|
105
|
+
.toBe("A verificação local falhou.");
|
|
106
|
+
await expect
|
|
107
|
+
.poll(() =>
|
|
108
|
+
page.locator("#failure").evaluate((element) => getComputedStyle(element).display),
|
|
109
|
+
)
|
|
110
|
+
.toBe("block");
|
|
111
|
+
await expect
|
|
112
|
+
.poll(() =>
|
|
113
|
+
page.locator("#handoff").evaluate((element) => getComputedStyle(element).display),
|
|
114
|
+
)
|
|
115
|
+
.toBe("none");
|
|
116
|
+
await expect
|
|
117
|
+
.poll(() => page.locator("#phase").textContent())
|
|
118
|
+
.toBe("Não foi possível preparar o dashboard");
|
|
119
|
+
await expect
|
|
120
|
+
.poll(() => page.locator("#detail").textContent())
|
|
121
|
+
.toBe("A preparação não foi concluída. Consulte a mensagem abaixo para agir.");
|
|
122
|
+
await expect
|
|
123
|
+
.poll(() =>
|
|
124
|
+
page
|
|
125
|
+
.locator(".progress")
|
|
126
|
+
.evaluate((element) => element.classList.contains("terminal-failure")),
|
|
127
|
+
)
|
|
128
|
+
.toBe(true);
|
|
129
|
+
await expect
|
|
130
|
+
.poll(() =>
|
|
131
|
+
page
|
|
132
|
+
.locator("#track")
|
|
133
|
+
.evaluate((element) => getComputedStyle(element, "::after").animationName),
|
|
134
|
+
)
|
|
135
|
+
.toBe("none");
|
|
136
|
+
await expect
|
|
137
|
+
.poll(() => page.locator("#bar").evaluate((element) => getComputedStyle(element).width))
|
|
138
|
+
.not.toBe("4px");
|
|
139
|
+
|
|
140
|
+
await launchPage.closeAfterFailureObservation(0);
|
|
141
|
+
await expect
|
|
142
|
+
.poll(() => page.locator("#failure").textContent())
|
|
143
|
+
.toBe("A verificação local falhou.");
|
|
144
|
+
} finally {
|
|
145
|
+
await browser.close();
|
|
146
|
+
await launchPage.close();
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("bounds launch-page shutdown when a browser connection never finishes polling", async () => {
|
|
151
|
+
const launchPage = await startDashboardLaunchPage(0);
|
|
152
|
+
const connection = connect({ host, port: launchPage.port });
|
|
153
|
+
await new Promise((resolveConnected, rejectConnected) => {
|
|
154
|
+
connection.once("connect", resolveConnected);
|
|
155
|
+
connection.once("error", rejectConnected);
|
|
156
|
+
});
|
|
157
|
+
const closed = new Promise((resolveClosed) => connection.once("close", resolveClosed));
|
|
158
|
+
const startedAt = Date.now();
|
|
159
|
+
await launchPage.close({ forceAfterMs: 20 });
|
|
160
|
+
await closed;
|
|
161
|
+
|
|
162
|
+
expect(Date.now() - startedAt).toBeLessThan(500);
|
|
163
|
+
expect(connection.destroyed).toBe(true);
|
|
164
|
+
});
|
|
165
|
+
});
|