@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { createHash, randomBytes } from "node:crypto";
|
|
3
|
-
import { appendFileSync,
|
|
3
|
+
import { appendFileSync, mkdirSync } from "node:fs";
|
|
4
4
|
import {
|
|
5
5
|
access,
|
|
6
6
|
mkdir,
|
|
@@ -12,18 +12,20 @@ import {
|
|
|
12
12
|
utimes,
|
|
13
13
|
writeFile,
|
|
14
14
|
} from "node:fs/promises";
|
|
15
|
-
import { createServer as createHttpServer } from "node:http";
|
|
16
15
|
import { createServer } from "node:net";
|
|
17
16
|
import { tmpdir } from "node:os";
|
|
18
17
|
import { dirname, join, relative, resolve, win32 } from "node:path";
|
|
19
18
|
import process from "node:process";
|
|
20
19
|
import { fileURLToPath } from "node:url";
|
|
21
20
|
import { collectPreviousDashboardSessions } from "./start-dashboard-history.mjs";
|
|
21
|
+
import { createDashboardLaunchPage } from "./start-dashboard-launch-page.mjs";
|
|
22
22
|
import {
|
|
23
|
+
isProcessAlive,
|
|
23
24
|
stopOwnedDashboardProcess,
|
|
24
25
|
stopProcessTree,
|
|
25
26
|
teardownWarning,
|
|
26
27
|
} from "./start-dashboard-processes.mjs";
|
|
28
|
+
import { refreshIsRunning, startSeedRefresh } from "./start-dashboard-refresh.mjs";
|
|
27
29
|
|
|
28
30
|
export {
|
|
29
31
|
isAncestorProcess,
|
|
@@ -38,7 +40,10 @@ export const maxPortAttempts = 25;
|
|
|
38
40
|
export const runtimeKind = "zaip-dashboard-sqlite-runtime";
|
|
39
41
|
const packageRoot = dirname(fileURLToPath(import.meta.url));
|
|
40
42
|
export const workspaceRoot = resolve(packageRoot, "../../../..");
|
|
41
|
-
export const workspaceKey = createHash("sha256")
|
|
43
|
+
export const workspaceKey = createHash("sha256")
|
|
44
|
+
.update(`${workspaceRoot}:dashboard-sqlite`)
|
|
45
|
+
.digest("hex")
|
|
46
|
+
.slice(0, 16);
|
|
42
47
|
export const sessionDirectory = join(tmpdir(), "zaip-aios", `dashboard-sqlite-${workspaceKey}`);
|
|
43
48
|
export const sessionPath = join(sessionDirectory, "dashboard-sqlite-session.json");
|
|
44
49
|
export const portRegistryPath = join(sessionDirectory, "dashboard-sqlite-ports.json");
|
|
@@ -46,20 +51,15 @@ export const lockPath = join(sessionDirectory, "dashboard-sqlite-launcher.lock")
|
|
|
46
51
|
export const launcherLogPath = join(sessionDirectory, "dashboard-sqlite-launcher.log");
|
|
47
52
|
const frontendRoot = resolve(workspaceRoot, ".agents/dashboard/apps/frontend/dist");
|
|
48
53
|
const sqliteReadModelDirectory = resolve(workspaceRoot, ".local", "dashboard-sqlite");
|
|
49
|
-
// Keep the immutable seed cache
|
|
50
|
-
// generations and the isolated background refresher must never derive a
|
|
51
|
-
// different cache directory from their temporary SQLite path.
|
|
54
|
+
// Keep the immutable seed cache durable and independent of temporary SQLite generations.
|
|
52
55
|
const sqliteSnapshotCacheDirectory = join(sqliteReadModelDirectory, "cache");
|
|
53
|
-
// Node's bytecode cache is disposable
|
|
54
|
-
// data. Keep it beside the private SQLite generations so fresh-port semantics
|
|
55
|
-
// and canonical sources remain unchanged.
|
|
56
|
+
// Node's bytecode cache is disposable acceleration beside private SQLite generations.
|
|
56
57
|
const nodeCompileCacheDirectory = join(sqliteReadModelDirectory, "node-compile-cache");
|
|
57
58
|
const installedServer = resolve(packageRoot, "server.mjs");
|
|
58
59
|
const sourceServer = resolve(packageRoot, "dist/server.cjs");
|
|
59
60
|
const healthPath = "/api/v2/health";
|
|
60
|
-
// Fresh-generation probe marker: changes the immutable source fingerprint only.
|
|
61
61
|
// Keep the preparation lock through a full build so concurrent clicks coalesce safely.
|
|
62
|
-
const lockTimeoutMs =
|
|
62
|
+
const lockTimeoutMs = 210_000;
|
|
63
63
|
const staleLockMs = 30_000;
|
|
64
64
|
const lockHeartbeatFloorMs = 10;
|
|
65
65
|
// A cold immutable seed can legitimately take ~176 s on a busy Windows
|
|
@@ -259,6 +259,10 @@ export async function findReusableDashboardSession({
|
|
|
259
259
|
const port = matches.find((candidate) => candidate !== null);
|
|
260
260
|
return port === undefined ? null : { ...session, port };
|
|
261
261
|
}
|
|
262
|
+
|
|
263
|
+
async function backgroundRefreshIsRunning() {
|
|
264
|
+
return refreshIsRunning(join(sessionDirectory, "dashboard-sqlite-refresh.json"), isProcessAlive);
|
|
265
|
+
}
|
|
262
266
|
async function latestModifiedAt(paths) {
|
|
263
267
|
let latest = 0;
|
|
264
268
|
for (const path of paths) {
|
|
@@ -283,9 +287,18 @@ async function runSqliteBuild(target) {
|
|
|
283
287
|
const command = process.execPath;
|
|
284
288
|
const args = frontend
|
|
285
289
|
? [resolve(workspaceRoot, "node_modules/vite/bin/vite.js"), "build"]
|
|
286
|
-
: [
|
|
290
|
+
: [
|
|
291
|
+
resolve(
|
|
292
|
+
workspaceRoot,
|
|
293
|
+
".agents/dashboard/packages/local-runtime/scripts/build-sqlite-runtime.mjs",
|
|
294
|
+
),
|
|
295
|
+
];
|
|
287
296
|
const output = await new Promise((resolveBuild, rejectBuild) => {
|
|
288
|
-
const child = spawn(command, args, {
|
|
297
|
+
const child = spawn(command, args, {
|
|
298
|
+
cwd: frontend ? resolve(workspaceRoot, ".agents/dashboard/apps/frontend") : packageRoot,
|
|
299
|
+
windowsHide: true,
|
|
300
|
+
stdio: "pipe",
|
|
301
|
+
});
|
|
289
302
|
let outputText = "";
|
|
290
303
|
const appendOutput = (chunk) => {
|
|
291
304
|
outputText = `${outputText}${chunk}`.slice(-8_000);
|
|
@@ -299,7 +312,9 @@ async function runSqliteBuild(target) {
|
|
|
299
312
|
if (code === 0) resolveBuild();
|
|
300
313
|
else
|
|
301
314
|
rejectBuild(
|
|
302
|
-
new Error(
|
|
315
|
+
new Error(
|
|
316
|
+
`SQLite dashboard ${target} build failed (${code}): ${formatLauncherError(outputText)}`,
|
|
317
|
+
),
|
|
303
318
|
);
|
|
304
319
|
});
|
|
305
320
|
});
|
|
@@ -331,6 +346,7 @@ export async function withLauncherLock(
|
|
|
331
346
|
path = lockPath,
|
|
332
347
|
timeoutMs = lockTimeoutMs,
|
|
333
348
|
staleAfterMs = staleLockMs,
|
|
349
|
+
onWait = () => {},
|
|
334
350
|
} = {},
|
|
335
351
|
) {
|
|
336
352
|
await mkdir(directory, { recursive: true });
|
|
@@ -357,6 +373,7 @@ export async function withLauncherLock(
|
|
|
357
373
|
await rm(path, { recursive: true, force: true });
|
|
358
374
|
continue;
|
|
359
375
|
}
|
|
376
|
+
onWait();
|
|
360
377
|
await delay(100);
|
|
361
378
|
}
|
|
362
379
|
}
|
|
@@ -424,7 +441,12 @@ export function browserLaunchCommands(
|
|
|
424
441
|
],
|
|
425
442
|
];
|
|
426
443
|
}
|
|
427
|
-
return
|
|
444
|
+
return platform === "darwin"
|
|
445
|
+
? [["open", [target]]]
|
|
446
|
+
: [
|
|
447
|
+
["xdg-open", [target]],
|
|
448
|
+
["gio", ["open", target]],
|
|
449
|
+
];
|
|
428
450
|
}
|
|
429
451
|
export async function openBrowser(target, spawnImpl = spawn) {
|
|
430
452
|
if (process.env.ZAIP_UI_NO_BROWSER === "1") return true;
|
|
@@ -455,126 +477,8 @@ export async function openBrowser(target, spawnImpl = spawn) {
|
|
|
455
477
|
appendLauncherLog(`Could not dispatch the dashboard URL to the default browser: ${target}`);
|
|
456
478
|
return false;
|
|
457
479
|
}
|
|
458
|
-
export
|
|
459
|
-
|
|
460
|
-
let progress = {
|
|
461
|
-
percent: 4,
|
|
462
|
-
phase: "Iniciando o launcher local",
|
|
463
|
-
detail: "Abrindo a página de preparação.",
|
|
464
|
-
};
|
|
465
|
-
const connections = new Set();
|
|
466
|
-
let resolveRedirectObserved;
|
|
467
|
-
const redirectObserved = new Promise((resolveObserved) => {
|
|
468
|
-
resolveRedirectObserved = resolveObserved;
|
|
469
|
-
});
|
|
470
|
-
const server = createHttpServer((request, response) => {
|
|
471
|
-
response.setHeader("Cache-Control", "no-store");
|
|
472
|
-
if (request.url?.startsWith("/api/v2/ready")) {
|
|
473
|
-
if (redirectUrl !== null) resolveRedirectObserved(true);
|
|
474
|
-
response.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
475
|
-
response.end(JSON.stringify({ target: redirectUrl }));
|
|
476
|
-
return;
|
|
477
|
-
}
|
|
478
|
-
if (request.url?.startsWith("/api/v2/progress")) {
|
|
479
|
-
response.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
480
|
-
response.end(JSON.stringify(progress));
|
|
481
|
-
return;
|
|
482
|
-
}
|
|
483
|
-
if (request.url?.startsWith(healthPath)) {
|
|
484
|
-
response.writeHead(503, { "Content-Type": "application/json; charset=utf-8" });
|
|
485
|
-
response.end(JSON.stringify({ kind: "zaip-dashboard-launcher", status: "starting" }));
|
|
486
|
-
return;
|
|
487
|
-
}
|
|
488
|
-
response.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
489
|
-
response.end(`<!doctype html>
|
|
490
|
-
<html lang="pt-BR">
|
|
491
|
-
<head>
|
|
492
|
-
<meta charset="utf-8">
|
|
493
|
-
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
494
|
-
<title>Dashboard Zaip AIOS</title>
|
|
495
|
-
<style>
|
|
496
|
-
:root{color-scheme:dark;font-family:Inter,system-ui,sans-serif;background:#010610;color:#f1f5f9}
|
|
497
|
-
*{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}
|
|
498
|
-
.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{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{height:9px;margin-top:20px;border-radius:999px;background:#172033;overflow:hidden}.bar{height:100%;width:4%;border-radius:inherit;background:linear-gradient(90deg,#38bdf8,#818cf8);transition:width .35s ease}.handoff{display:none;margin-top:16px;color:#dbeafe}.handoff a{color:#7dd3fc;font-weight:700}
|
|
499
|
-
</style>
|
|
500
|
-
</head>
|
|
501
|
-
<body>
|
|
502
|
-
<main class="launch-overlay" aria-label="Preparando dashboard">
|
|
503
|
-
<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"><div class="bar" id="bar"></div></div><span class="handoff" id="handoff">O dashboard está pronto. Se ele não abrir automaticamente, <a id="handoff-link" href="#">abra o dashboard agora</a>.</span></section>
|
|
504
|
-
</main>
|
|
505
|
-
<script>
|
|
506
|
-
let handoffTarget=null;
|
|
507
|
-
function showHandoff(target){handoffTarget=target;const box=document.getElementById("handoff");const link=document.getElementById("handoff-link");link.href=target;box.style.display="block";document.getElementById("phase").textContent="Dashboard pronto";document.getElementById("detail").textContent="Concluindo a abertura da tela principal."}
|
|
508
|
-
async function updateProgress(){try{const r=await fetch("/api/v2/progress",{cache:"no-store"});const p=await r.json();if(!handoffTarget){document.getElementById("phase").textContent=p.phase;document.getElementById("detail").textContent=p.detail};document.getElementById("bar").style.width=Math.max(4,Math.min(100,Number(p.percent)||4))+"%"}catch{}}
|
|
509
|
-
async function waitForDashboard(){
|
|
510
|
-
try{
|
|
511
|
-
await updateProgress();
|
|
512
|
-
const ready=await fetch("/api/v2/ready",{cache:"no-store"});
|
|
513
|
-
const next=await ready.json();
|
|
514
|
-
if(next.target){showHandoff(next.target);setTimeout(()=>location.replace(next.target),0);return}
|
|
515
|
-
const response=await fetch("${healthPath}",{cache:"no-store"});
|
|
516
|
-
const payload=await response.json();
|
|
517
|
-
if(response.ok&&payload.kind==="${runtimeKind}"){location.reload();return}
|
|
518
|
-
}catch{}
|
|
519
|
-
setTimeout(waitForDashboard,250)
|
|
520
|
-
}
|
|
521
|
-
updateProgress();setTimeout(waitForDashboard,100)
|
|
522
|
-
// A browser extension or a failed navigation must never leave a silent
|
|
523
|
-
// skeleton. The visible link remains actionable while the temporary
|
|
524
|
-
// launcher server keeps serving this page through the handoff grace.
|
|
525
|
-
setTimeout(()=>{if(handoffTarget)showHandoff(handoffTarget)},4000)
|
|
526
|
-
</script>
|
|
527
|
-
</body>
|
|
528
|
-
</html>`);
|
|
529
|
-
});
|
|
530
|
-
server.on("connection", (connection) => {
|
|
531
|
-
connections.add(connection);
|
|
532
|
-
connection.once("close", () => connections.delete(connection));
|
|
533
|
-
});
|
|
534
|
-
await new Promise((resolveListen, rejectListen) => {
|
|
535
|
-
server.once("error", rejectListen);
|
|
536
|
-
server.listen({ host, port }, resolveListen);
|
|
537
|
-
});
|
|
538
|
-
server.unref();
|
|
539
|
-
const address = server.address();
|
|
540
|
-
const listeningPort = typeof address === "object" && address !== null ? address.port : port;
|
|
541
|
-
return {
|
|
542
|
-
port: listeningPort,
|
|
543
|
-
redirect: (target) => {
|
|
544
|
-
redirectUrl = target;
|
|
545
|
-
},
|
|
546
|
-
setProgress: (next) => {
|
|
547
|
-
progress = { ...progress, ...next, percent: Math.max(progress.percent, next.percent ?? progress.percent) };
|
|
548
|
-
},
|
|
549
|
-
waitForRedirect: async (timeoutMs = 1_500) =>
|
|
550
|
-
Promise.race([redirectObserved, delay(timeoutMs).then(() => false)]),
|
|
551
|
-
closeAfterHandoffGrace: (graceMs = 12_000) => {
|
|
552
|
-
const timer = setTimeout(() => {
|
|
553
|
-
void server.close();
|
|
554
|
-
server.closeAllConnections?.();
|
|
555
|
-
for (const connection of connections) connection.destroy();
|
|
556
|
-
}, graceMs);
|
|
557
|
-
timer.unref?.();
|
|
558
|
-
},
|
|
559
|
-
close: ({ forceAfterMs = 750 } = {}) =>
|
|
560
|
-
new Promise((resolveClose, rejectClose) => {
|
|
561
|
-
let forceTimer = null;
|
|
562
|
-
const finish = (error) => {
|
|
563
|
-
if (forceTimer !== null) clearTimeout(forceTimer);
|
|
564
|
-
if (error) rejectClose(error);
|
|
565
|
-
else resolveClose();
|
|
566
|
-
};
|
|
567
|
-
server.close(finish);
|
|
568
|
-
// The preparation page polls while redirecting. A browser keep-alive
|
|
569
|
-
// or an interrupted polling request must not keep this transient
|
|
570
|
-
// server alive indefinitely after its handoff was issued.
|
|
571
|
-
forceTimer = setTimeout(() => {
|
|
572
|
-
server.closeAllConnections?.();
|
|
573
|
-
for (const connection of connections) connection.destroy();
|
|
574
|
-
}, forceAfterMs);
|
|
575
|
-
forceTimer.unref?.();
|
|
576
|
-
}),
|
|
577
|
-
};
|
|
480
|
+
export function startDashboardLaunchPage(port) {
|
|
481
|
+
return createDashboardLaunchPage({ port, host, runtimeKind, healthPath, delay });
|
|
578
482
|
}
|
|
579
483
|
async function redirectLaunchPage(launchPage, target) {
|
|
580
484
|
launchPage.redirect(target);
|
|
@@ -628,7 +532,13 @@ export async function previousDashboardSessions({
|
|
|
628
532
|
workspaceKey,
|
|
629
533
|
});
|
|
630
534
|
}
|
|
631
|
-
async function startDashboardServer(
|
|
535
|
+
async function startDashboardServer(
|
|
536
|
+
serverPath,
|
|
537
|
+
token,
|
|
538
|
+
excludedPorts,
|
|
539
|
+
initialPort = null,
|
|
540
|
+
onProgress = () => {},
|
|
541
|
+
) {
|
|
632
542
|
const failures = [];
|
|
633
543
|
for (let attempt = 1; attempt <= maxServerStartAttempts; attempt += 1) {
|
|
634
544
|
const port =
|
|
@@ -677,15 +587,31 @@ async function startDashboardServer(serverPath, token, excludedPorts, initialPor
|
|
|
677
587
|
onProgress({
|
|
678
588
|
percent: event.percent,
|
|
679
589
|
phase: "Configurando o banco SQLite local",
|
|
680
|
-
detail:
|
|
590
|
+
detail:
|
|
591
|
+
"Esta é a instalação/atualização da cópia local descartável; nenhum servidor externo é instalado.",
|
|
681
592
|
});
|
|
682
593
|
if (event?.event === "dashboard_sqlite_startup_phase" && event.phase === "main_entered")
|
|
683
|
-
onProgress({
|
|
594
|
+
onProgress({
|
|
595
|
+
percent: 50,
|
|
596
|
+
phase: "Lendo os registros do projeto",
|
|
597
|
+
detail: "Preparando o read model SQLite local.",
|
|
598
|
+
});
|
|
684
599
|
if (event?.event === "dashboard_sqlite_read_model") snapshotCache = event.cache;
|
|
685
600
|
if (event?.event === "dashboard_sqlite_read_model")
|
|
686
|
-
onProgress({
|
|
601
|
+
onProgress({
|
|
602
|
+
percent: 82,
|
|
603
|
+
phase: "Banco local pronto",
|
|
604
|
+
detail:
|
|
605
|
+
event.cache === "rebuilt"
|
|
606
|
+
? "O read model SQLite foi reconstruído para os dados atuais."
|
|
607
|
+
: "Uma cópia local do read model foi preparada.",
|
|
608
|
+
});
|
|
687
609
|
if (event?.event === "dashboard_sqlite_startup_phase" && event.phase === "listening")
|
|
688
|
-
onProgress({
|
|
610
|
+
onProgress({
|
|
611
|
+
percent: 88,
|
|
612
|
+
phase: "Iniciando a interface",
|
|
613
|
+
detail: "Verificando saúde e disponibilidade dos dados.",
|
|
614
|
+
});
|
|
689
615
|
} catch {
|
|
690
616
|
// Only structured startup telemetry affects the user-facing progress.
|
|
691
617
|
}
|
|
@@ -707,10 +633,15 @@ async function startDashboardServer(serverPath, token, excludedPorts, initialPor
|
|
|
707
633
|
await removeGeneratedReadModel(dbPath);
|
|
708
634
|
const detail = stripTerminalControlCodes(stderr)
|
|
709
635
|
.split("\n")
|
|
710
|
-
.filter(
|
|
636
|
+
.filter(
|
|
637
|
+
(line) =>
|
|
638
|
+
!line.includes("ExperimentalWarning") && !line.includes("node --trace-warnings"),
|
|
639
|
+
)
|
|
711
640
|
.join("\n")
|
|
712
641
|
.trim();
|
|
713
|
-
failures.push(
|
|
642
|
+
failures.push(
|
|
643
|
+
`porta ${port}: ${error.message}${detail ? ` — ${formatLauncherError(detail, 600)}` : ""}`,
|
|
644
|
+
);
|
|
714
645
|
appendLauncherLog(
|
|
715
646
|
`Dashboard start attempt ${attempt} failed on port ${port}: ${error.message}`,
|
|
716
647
|
);
|
|
@@ -744,59 +675,29 @@ async function removeGeneratedReadModel(candidate) {
|
|
|
744
675
|
if (attempt < 20) await delay(250);
|
|
745
676
|
}
|
|
746
677
|
}
|
|
747
|
-
appendLauncherLog(
|
|
678
|
+
appendLauncherLog(
|
|
679
|
+
`Could not remove closed SQLite read model after retries: ${resolvedCandidate}`,
|
|
680
|
+
);
|
|
748
681
|
return false;
|
|
749
682
|
}
|
|
750
|
-
function refreshSnapshotSeedInBackground() {
|
|
751
|
-
const refreshPath = resolve(sqliteReadModelDirectory, `refresh-${process.pid}-${randomBytes(4).toString("hex")}.sqlite`);
|
|
683
|
+
async function refreshSnapshotSeedInBackground() {
|
|
752
684
|
const refreshStatusPath = join(sessionDirectory, "dashboard-sqlite-refresh.json");
|
|
753
685
|
const refreshLogPath = join(sessionDirectory, "dashboard-sqlite-refresh.log");
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
let worker;
|
|
757
|
-
try {
|
|
758
|
-
worker = spawn(process.execPath, [resolve(packageRoot, "scripts/rebuild-sqlite-read-model.mjs")], {
|
|
759
|
-
cwd: workspaceRoot,
|
|
760
|
-
env: {
|
|
761
|
-
...process.env,
|
|
762
|
-
ZAIP_SQLITE_DB_PATH: refreshPath,
|
|
763
|
-
ZAIP_SQLITE_PREFER_LAST_VALID_SEED: "0",
|
|
764
|
-
ZAIP_DASHBOARD_LAUNCH_PROGRESS: "0",
|
|
765
|
-
ZAIP_SQLITE_REFRESH_CLEANUP: "1",
|
|
766
|
-
ZAIP_SQLITE_CACHE_DIR: sqliteSnapshotCacheDirectory,
|
|
767
|
-
},
|
|
768
|
-
// A detached worker keeps its own append-only evidence file. Pipes can
|
|
769
|
-
// disappear with a fast launcher exit and silently abort the refresh.
|
|
770
|
-
stdio: ["ignore", refreshLogDescriptor, refreshLogDescriptor],
|
|
771
|
-
detached: true,
|
|
772
|
-
windowsHide: true,
|
|
773
|
-
});
|
|
774
|
-
} finally {
|
|
775
|
-
closeSync(refreshLogDescriptor);
|
|
776
|
-
}
|
|
777
|
-
void writeJsonAtomic(refreshStatusPath, {
|
|
778
|
-
status: "running",
|
|
779
|
-
pid: worker.pid ?? null,
|
|
780
|
-
path: refreshPath,
|
|
686
|
+
return startSeedRefresh({
|
|
687
|
+
appendLog: appendLauncherLog,
|
|
781
688
|
cacheDirectory: sqliteSnapshotCacheDirectory,
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
exitCode: code ?? null,
|
|
794
|
-
logPath: refreshLogPath,
|
|
795
|
-
finishedAt: new Date().toISOString(),
|
|
796
|
-
}).catch(() => {});
|
|
689
|
+
isRunning: backgroundRefreshIsRunning,
|
|
690
|
+
isProcessAlive,
|
|
691
|
+
lockPath: join(sessionDirectory, "dashboard-sqlite-refresh.lock"),
|
|
692
|
+
packageRoot,
|
|
693
|
+
randomBytes,
|
|
694
|
+
refreshLogPath,
|
|
695
|
+
refreshStatusPath,
|
|
696
|
+
sqliteDirectory: sqliteReadModelDirectory,
|
|
697
|
+
stopProcessTree,
|
|
698
|
+
workspaceRoot,
|
|
699
|
+
writeJsonAtomic,
|
|
797
700
|
});
|
|
798
|
-
worker.unref();
|
|
799
|
-
appendLauncherLog(`Started background SQLite seed refresh at ${refreshPath}; cache ${sqliteSnapshotCacheDirectory}; worker log ${refreshLogPath}.`);
|
|
800
701
|
}
|
|
801
702
|
async function writeLauncherStatus(status, message = "") {
|
|
802
703
|
const path = process.env.ZAIP_LAUNCH_STATUS;
|
|
@@ -806,7 +707,15 @@ async function writeLauncherStatus(status, message = "") {
|
|
|
806
707
|
await rename(temporaryPath, path);
|
|
807
708
|
}
|
|
808
709
|
function phaseTiming(phase, startedAt, details = {}) {
|
|
809
|
-
appendLauncherLog(
|
|
710
|
+
appendLauncherLog(
|
|
711
|
+
JSON.stringify({
|
|
712
|
+
event: "dashboard_sqlite_phase",
|
|
713
|
+
phase,
|
|
714
|
+
elapsed_ms: Date.now() - startedAt,
|
|
715
|
+
launcher_pid: process.pid,
|
|
716
|
+
...details,
|
|
717
|
+
}),
|
|
718
|
+
);
|
|
810
719
|
}
|
|
811
720
|
async function main() {
|
|
812
721
|
let ownedChild = null;
|
|
@@ -827,7 +736,8 @@ async function main() {
|
|
|
827
736
|
launchPage.setProgress({
|
|
828
737
|
percent: 10,
|
|
829
738
|
phase: "Validando pré-requisitos locais",
|
|
830
|
-
detail:
|
|
739
|
+
detail:
|
|
740
|
+
"Verificando Node.js 22 e o suporte a node:sqlite; isto não instala um banco de dados.",
|
|
831
741
|
});
|
|
832
742
|
await assertDashboardPrerequisites();
|
|
833
743
|
launchPage.setProgress({
|
|
@@ -835,110 +745,162 @@ async function main() {
|
|
|
835
745
|
phase: "Preparando a sessão do dashboard",
|
|
836
746
|
detail: "Coordenando esta abertura local com segurança.",
|
|
837
747
|
});
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
phase: "Verificando os artefatos do dashboard",
|
|
844
|
-
detail: "Usando o build existente quando ele já está atualizado.",
|
|
845
|
-
});
|
|
846
|
-
const buildSignature = await ensureFreshDashboardBuild();
|
|
847
|
-
phaseTiming("build_complete", buildStartedAt, { build_signature: buildSignature });
|
|
848
|
-
// A second deliberate click must use the already healthy compatible
|
|
849
|
-
// runtime. Build signature makes this safe across dashboard updates;
|
|
850
|
-
// an incompatible session continues through a replacement handoff.
|
|
851
|
-
const reusable = await findReusableDashboardSession({
|
|
852
|
-
expectedBuildSignature: buildSignature,
|
|
853
|
-
expectedSnapshotState: "current",
|
|
854
|
-
});
|
|
855
|
-
if (reusable !== null) {
|
|
856
|
-
appendLauncherLog(`Reused healthy compatible dashboard session on port ${reusable.port}, PID ${reusable.serverPid ?? "unknown"}.`);
|
|
857
|
-
await redirectLaunchPage(launchPage, dashboardUrl(reusable.port, reusable.token));
|
|
858
|
-
launchPage = null;
|
|
859
|
-
await writeLauncherStatus("ok");
|
|
860
|
-
return;
|
|
861
|
-
}
|
|
862
|
-
const previousSessions = await previousDashboardSessions();
|
|
863
|
-
const excludedPorts = new Set([
|
|
864
|
-
...previousSessions.map((session) => session.port),
|
|
865
|
-
launchPort,
|
|
866
|
-
]);
|
|
867
|
-
const serverPath = await assertRuntimeReady();
|
|
868
|
-
const readyStartedAt = Date.now();
|
|
869
|
-
launchPage.setProgress({
|
|
870
|
-
percent: 42,
|
|
871
|
-
phase: "Abrindo o banco local descartável",
|
|
872
|
-
detail: "Criando uma cópia privada do read model SQLite para esta sessão.",
|
|
873
|
-
});
|
|
874
|
-
const { child, port, dbPath, snapshotCache } = await startDashboardServer(
|
|
875
|
-
serverPath,
|
|
876
|
-
token,
|
|
877
|
-
excludedPorts,
|
|
878
|
-
null,
|
|
879
|
-
(progress) => launchPage?.setProgress(progress),
|
|
880
|
-
);
|
|
881
|
-
phaseTiming("server_ready", readyStartedAt, { server_pid: child.pid, port, db_path: dbPath });
|
|
882
|
-
ownedChild = child;
|
|
883
|
-
try {
|
|
748
|
+
let reportedLockWait = false;
|
|
749
|
+
await withLauncherLock(
|
|
750
|
+
async () => {
|
|
751
|
+
phaseTiming("lock_acquired", launchStartedAt);
|
|
752
|
+
const buildStartedAt = Date.now();
|
|
884
753
|
launchPage.setProgress({
|
|
885
|
-
percent:
|
|
886
|
-
phase:
|
|
887
|
-
detail:
|
|
888
|
-
? "Os dados canônicos estão sendo atualizados em segundo plano para a próxima abertura."
|
|
889
|
-
: "Validando saúde e dados iniciais antes de abrir a tela principal.",
|
|
754
|
+
percent: 28,
|
|
755
|
+
phase: "Verificando os artefatos do dashboard",
|
|
756
|
+
detail: "Usando o build existente quando ele já está atualizado.",
|
|
890
757
|
});
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
token
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
const status = await stopOwnedDashboard(previous);
|
|
919
|
-
await recordPortStatus(previous, status);
|
|
920
|
-
if (status === "closed") await removeGeneratedReadModel(previous.dbPath);
|
|
921
|
-
if (teardownWarning(status))
|
|
922
|
-
warnings.push(`não foi possível fechar a porta anterior ${previous.port}`);
|
|
923
|
-
else if (status === "skipped_unowned")
|
|
758
|
+
const buildSignature = await ensureFreshDashboardBuild();
|
|
759
|
+
phaseTiming("build_complete", buildStartedAt, { build_signature: buildSignature });
|
|
760
|
+
// A second deliberate click must use the already healthy compatible
|
|
761
|
+
// runtime. Build signature makes this safe across dashboard updates;
|
|
762
|
+
// an incompatible session continues through a replacement handoff.
|
|
763
|
+
const reusable = await findReusableDashboardSession({
|
|
764
|
+
expectedBuildSignature: buildSignature,
|
|
765
|
+
expectedSnapshotState: "current",
|
|
766
|
+
});
|
|
767
|
+
if (reusable !== null) {
|
|
768
|
+
appendLauncherLog(
|
|
769
|
+
`Reused healthy compatible dashboard session on port ${reusable.port}, PID ${reusable.serverPid ?? "unknown"}.`,
|
|
770
|
+
);
|
|
771
|
+
await redirectLaunchPage(launchPage, dashboardUrl(reusable.port, reusable.token));
|
|
772
|
+
launchPage = null;
|
|
773
|
+
await writeLauncherStatus("ok");
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
// A stale seed is still a valid read-only dashboard while its one
|
|
777
|
+
// canonical refresh runs. Reuse it instead of turning repeated clicks
|
|
778
|
+
// into competing full SQLite rebuilds and private server generations.
|
|
779
|
+
if (await backgroundRefreshIsRunning()) {
|
|
780
|
+
const updating = await findReusableDashboardSession({
|
|
781
|
+
expectedBuildSignature: buildSignature,
|
|
782
|
+
expectedSnapshotState: "updating",
|
|
783
|
+
});
|
|
784
|
+
if (updating !== null) {
|
|
924
785
|
appendLauncherLog(
|
|
925
|
-
`
|
|
786
|
+
`Reused updating dashboard session on port ${updating.port}; canonical seed refresh is already running.`,
|
|
926
787
|
);
|
|
788
|
+
await redirectLaunchPage(launchPage, dashboardUrl(updating.port, updating.token, true));
|
|
789
|
+
launchPage = null;
|
|
790
|
+
await writeLauncherStatus("ok");
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
927
793
|
}
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
794
|
+
const previousSessions = await previousDashboardSessions();
|
|
795
|
+
const excludedPorts = new Set([
|
|
796
|
+
...previousSessions.map((session) => session.port),
|
|
797
|
+
launchPort,
|
|
798
|
+
]);
|
|
799
|
+
const serverPath = await assertRuntimeReady();
|
|
800
|
+
const readyStartedAt = Date.now();
|
|
801
|
+
launchPage.setProgress({
|
|
802
|
+
percent: 42,
|
|
803
|
+
phase: "Abrindo o banco local descartável",
|
|
804
|
+
detail: "Criando uma cópia privada do read model SQLite para esta sessão.",
|
|
805
|
+
});
|
|
806
|
+
const { child, port, dbPath, snapshotCache } = await startDashboardServer(
|
|
807
|
+
serverPath,
|
|
808
|
+
token,
|
|
809
|
+
excludedPorts,
|
|
810
|
+
null,
|
|
811
|
+
(progress) => launchPage?.setProgress(progress),
|
|
812
|
+
);
|
|
813
|
+
phaseTiming("server_ready", readyStartedAt, {
|
|
814
|
+
server_pid: child.pid,
|
|
815
|
+
port,
|
|
816
|
+
db_path: dbPath,
|
|
817
|
+
});
|
|
818
|
+
ownedChild = child;
|
|
819
|
+
try {
|
|
820
|
+
launchPage.setProgress({
|
|
821
|
+
percent: 92,
|
|
822
|
+
phase:
|
|
823
|
+
snapshotCache === "stale_seed"
|
|
824
|
+
? "Abrindo snapshot local validado"
|
|
825
|
+
: "Dashboard pronto",
|
|
826
|
+
detail:
|
|
827
|
+
snapshotCache === "stale_seed"
|
|
828
|
+
? "Os dados canônicos estão sendo atualizados em segundo plano para a próxima abertura."
|
|
829
|
+
: "Validando saúde e dados iniciais antes de abrir a tela principal.",
|
|
830
|
+
});
|
|
831
|
+
if (snapshotCache === "stale_seed") await delay(350);
|
|
832
|
+
await redirectLaunchPage(
|
|
833
|
+
launchPage,
|
|
834
|
+
dashboardUrl(port, token, snapshotCache === "stale_seed"),
|
|
931
835
|
);
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
836
|
+
phaseTiming("handoff_complete", launchStartedAt, { server_pid: child.pid, port });
|
|
837
|
+
launchPage = null;
|
|
838
|
+
if (snapshotCache === "stale_seed") await refreshSnapshotSeedInBackground();
|
|
839
|
+
currentSession = {
|
|
840
|
+
kind: runtimeKind,
|
|
841
|
+
workspace: workspaceRoot,
|
|
842
|
+
workspaceKey,
|
|
843
|
+
rootPid: process.pid,
|
|
844
|
+
serverPid: child.pid,
|
|
845
|
+
port,
|
|
846
|
+
token,
|
|
847
|
+
dbPath,
|
|
848
|
+
buildSignature,
|
|
849
|
+
generationId: `${process.pid}-${child.pid}-${port}-${randomBytes(6).toString("hex")}`,
|
|
850
|
+
// Never pin subsequent clicks to a stale seed. A completed
|
|
851
|
+
// background refresh is consumed by a fresh handoff on the next
|
|
852
|
+
// click, then the old updating generation is retired below.
|
|
853
|
+
snapshotState: snapshotCache === "stale_seed" ? "updating" : "current",
|
|
854
|
+
createdAt: new Date().toISOString(),
|
|
855
|
+
};
|
|
856
|
+
await writeDashboardSession(currentSession);
|
|
857
|
+
await recordPortStatus(currentSession, "active");
|
|
858
|
+
const warnings = [];
|
|
859
|
+
for (const previous of previousSessions) {
|
|
860
|
+
const status = await stopOwnedDashboard(previous);
|
|
861
|
+
await recordPortStatus(previous, status);
|
|
862
|
+
if (status === "closed") await removeGeneratedReadModel(previous.dbPath);
|
|
863
|
+
if (teardownWarning(status))
|
|
864
|
+
warnings.push(`não foi possível fechar a porta anterior ${previous.port}`);
|
|
865
|
+
else if (status === "skipped_unowned")
|
|
866
|
+
appendLauncherLog(
|
|
867
|
+
`Skipped teardown of port ${previous.port}: registered server PID does not own its live listener.`,
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
if (warnings.length > 0)
|
|
871
|
+
appendLauncherLog(
|
|
872
|
+
`Dashboard launched on port ${port}; prior-port cleanup: ${warnings.join("; ")}`,
|
|
873
|
+
);
|
|
874
|
+
await writeLauncherStatus("ok");
|
|
875
|
+
} catch (error) {
|
|
876
|
+
await stopProcessTree(child.pid);
|
|
877
|
+
if (currentSession !== null) await recordPortStatus(currentSession, "failed");
|
|
878
|
+
await clearOwnedDashboardSession();
|
|
879
|
+
throw error;
|
|
880
|
+
}
|
|
881
|
+
},
|
|
882
|
+
{
|
|
883
|
+
onWait: () => {
|
|
884
|
+
if (reportedLockWait) return;
|
|
885
|
+
reportedLockWait = true;
|
|
886
|
+
launchPage?.setProgress({
|
|
887
|
+
percent: 22,
|
|
888
|
+
phase: "Aguardando outra abertura do dashboard",
|
|
889
|
+
detail: "A outra sessão está concluindo o carregamento local antes desta continuar.",
|
|
890
|
+
});
|
|
891
|
+
},
|
|
892
|
+
},
|
|
893
|
+
);
|
|
940
894
|
} catch (error) {
|
|
941
|
-
if (launchPage !== null)
|
|
895
|
+
if (launchPage !== null) {
|
|
896
|
+
launchPage.setFailure({
|
|
897
|
+
percent: 100,
|
|
898
|
+
phase: "Não foi possível preparar o dashboard",
|
|
899
|
+
detail: formatLauncherError(error instanceof Error ? error.message : String(error), 900),
|
|
900
|
+
});
|
|
901
|
+
launchPage.closeAfterFailureObservation();
|
|
902
|
+
launchPage = null;
|
|
903
|
+
}
|
|
942
904
|
throw error;
|
|
943
905
|
}
|
|
944
906
|
if (ownedChild === null) return;
|
|
@@ -1000,7 +962,11 @@ async function waitForDashboard(port, child) {
|
|
|
1000
962
|
}
|
|
1001
963
|
await delay(100);
|
|
1002
964
|
}
|
|
1003
|
-
|
|
965
|
+
// A cold read-model timeout is not a port collision. Retrying would start
|
|
966
|
+
// up to four more full builds and exceed the launcher deadline.
|
|
967
|
+
const timedOut = new Error(`Timed out waiting for ${dashboardHealthUrl(port)}`);
|
|
968
|
+
timedOut.retryable = false;
|
|
969
|
+
throw timedOut;
|
|
1004
970
|
}
|
|
1005
971
|
function exists(path) {
|
|
1006
972
|
return access(path).then(
|