@zaip-ai/cli 1.3.0 → 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/agent-adapters.js +1 -1
- package/dist/services/agent-adapters.js.map +1 -1
- package/dist/services/agent-adapters.test.js +2 -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/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 +7 -3
- package/dist/services/template-manifest.js.map +1 -1
- package/package.json +1 -1
- 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-frontend.toml +8 -8
- package/templates/.agents/dashboard/.zaip-managed.json +373 -205
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-DxR_pgSV.js → CostCalculationGuidePage-ovxurkIk.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-4jZLTWE_.js → DashboardHelpDialog-BgVgrfhQ.js} +240 -86
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-CKcsqb-r.js → PricingSettingsDialog-vSvvOHQp.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{ProjectSettingsPage-DmmJD2Th.js → ProjectSettingsPage-zH758vfs.js} +1 -1
- 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-C0fj2uU9.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-BEsJ-FYH.js → react-vendor-B3TJrD4O.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-B6y6Gw12.js → traceability-7f1j5wx3.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/index.html +7 -7
- package/templates/.agents/dashboard/apps/frontend/playwright.dom.config.ts +32 -0
- package/templates/.agents/dashboard/apps/frontend/src/App.tsx +132 -245
- package/templates/.agents/dashboard/apps/frontend/src/AppOverlays.tsx +0 -21
- package/templates/.agents/dashboard/apps/frontend/src/DashboardAlternateContent.tsx +9 -0
- package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.dom.e2e.ts +56 -0
- package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.test.ts +18 -1
- package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.tsx +75 -8
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +25 -1
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +7 -9
- 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 +1 -1
- package/templates/.agents/dashboard/apps/frontend/src/snapshot-banner-semantics.test.ts +7 -0
- package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +20 -8
- 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 +48 -0
- package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.ts +31 -27
- 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 +38 -14
- 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/CostMonitorContent.tsx +8 -2
- 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 +47 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +50 -58
- 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 +128 -138
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.tsx +17 -67
- 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-page-range.ts +35 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-compact-cost-page.ts +16 -4
- 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 +44 -8
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-run-page.ts +6 -1
- package/templates/.agents/dashboard/modules/operations/src/contracts.ts +20 -3
- 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/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 +20 -28
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +162 -165
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverviewTopPanel.tsx +127 -0
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +13 -46
- 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/UnifiedWorkList.test.ts +4 -2
- package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.tsx +13 -0
- 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 +8 -0
- package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +3 -0
- package/templates/.agents/dashboard/modules/operations/src/react/export/export-layout.test.ts +14 -5
- package/templates/.agents/dashboard/modules/operations/src/react/index.ts +1 -0
- package/templates/.agents/dashboard/modules/operations/src/react/operations-coverage-toast.test.ts +4 -3
- package/templates/.agents/dashboard/modules/operations/src/react/operations-date-filters.css +1 -1
- package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +21 -11
- package/templates/.agents/dashboard/modules/operations/src/react/operations-overview.css +4 -0
- package/templates/.agents/dashboard/modules/operations/src/react/operations-page-contract.ts +8 -1
- package/templates/.agents/dashboard/modules/operations/src/react/operations-view-order.test.ts +1 -0
- package/templates/.agents/dashboard/modules/operations/src/react/period-summary.ts +1 -0
- package/templates/.agents/dashboard/modules/operations/src/server/metric-coverage.ts +1 -0
- package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +527 -335
- package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +501 -309
- package/templates/.agents/dashboard/packages/local-runtime/gitignore.template +2 -0
- package/templates/.agents/dashboard/packages/local-runtime/scripts/rebuild-sqlite-read-model.mjs +3 -1
- package/templates/.agents/dashboard/packages/local-runtime/scripts/test-sqlite-read-model.mjs +3 -3
- package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-sqlite-read-model.mjs +25 -15
- package/templates/.agents/dashboard/packages/local-runtime/server.mjs +527 -335
- package/templates/.agents/dashboard/packages/local-runtime/src/server-board.test.ts +34 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-board.ts +15 -8
- 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 +3 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/server-sqlite-task-trace.ts +91 -0
- 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 +98 -123
- package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +111 -135
- 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-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 +440 -863
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +1120 -1086
- 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 +188 -299
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +51 -70
- package/templates/.agents/dashboard/packages/windows-launcher/Program.cs +5 -2
- 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 +183 -210
- package/templates/.agents/dashboard/zaip-dashboard-windows.exe +0 -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/bin/zaip.mjs +1137 -1037
- package/templates/.agents/runtime/checksums.sha256 +2 -2
- package/templates/.agents/runtime/provenance.json +2 -2
- package/templates/.agents/skills/criar-pasta-obsidian/scripts/generate-obsidian-vault.test.mjs +20 -16
- 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-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-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-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-prd/SKILL.md +4 -0
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.mjs +72 -22
- 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 +42 -1
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.test.mjs +101 -0
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.test.mjs +53 -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-spec/SKILL.md +4 -0
- package/templates/.agents/skills/zaip-skill-sqlite-read-model/SKILL.md +22 -90
- package/templates/.agents/zaip-aios/INDEX.md +57 -32
- package/templates/.agents/zaip-aios/README.md +22 -12
- 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/19-assurance-e-autonomia.md +23 -0
- package/templates/.agents/zaip-aios/guides/20-instalacao-detalhada.md +44 -8
- package/templates/.agents/zaip-aios/guides/21-telemetria-monitor-custos.md +8 -14
- package/templates/.agents/zaip-aios/guides/22-fluxos-e-roteamento.md +5 -0
- package/templates/.agents/zaip-aios/guides/23-orquestracao-de-modelos.md +6 -6
- package/templates/.agents/zaip-aios/guides/24-calculo-de-custos-openai.md +8 -8
- package/templates/.agents/zaip-aios/guides/25-fontes-de-precos-openai.md +3 -2
- package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +77 -10
- package/templates/.agents/zaip-aios/guides/27-telemetria-git-native.md +8 -3
- package/templates/.agents/zaip-aios/guides/28-lifecycle-completo.md +5 -0
- package/templates/template-manifest.json +555 -170
- package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-BwtitWa_.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-N5Csr0RP.js +0 -68
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-C4aIB1PV.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
- package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs.metafile.json +0 -7333
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { queryInvocationManifestPeriod } from "@zaip-ai/costs";
|
|
3
3
|
import { describe, expect, it } from "vitest";
|
|
4
|
-
import {
|
|
5
|
-
activeCostPeriodData,
|
|
6
|
-
costPeriodDateRange,
|
|
7
|
-
defaultCostPeriod,
|
|
8
|
-
emptyCostFilters,
|
|
9
|
-
loadCostMonitorPeriod,
|
|
10
|
-
shouldFetchCostPeriod,
|
|
11
|
-
} from "./CostFilters.js";
|
|
12
4
|
import { displayModelName, isModelAuditRow, sumModelDurationMs } from "./CostModelsAuditTable.js";
|
|
13
5
|
import {
|
|
14
6
|
agentRunModelPresentation,
|
|
7
|
+
type CostDeveloperAttributionRow,
|
|
8
|
+
CostDeveloperAttributionTable,
|
|
15
9
|
CostGroupsTable,
|
|
16
10
|
CostRunsTable,
|
|
17
11
|
contextUpliftUsd,
|
|
@@ -29,7 +23,6 @@ import {
|
|
|
29
23
|
formatCostPeriodLabel,
|
|
30
24
|
formatDateTime,
|
|
31
25
|
formatDurationCoverage,
|
|
32
|
-
formatMultiplierPair,
|
|
33
26
|
formatRate,
|
|
34
27
|
formatReasoningEffort,
|
|
35
28
|
formatServiceTier,
|
|
@@ -207,6 +200,112 @@ describe("runtime availability", () => {
|
|
|
207
200
|
});
|
|
208
201
|
});
|
|
209
202
|
describe("grouped cost availability", () => {
|
|
203
|
+
it("uses the requested Cost Monitor developer metric columns without Operations source or coverage", () => {
|
|
204
|
+
const table = CostDeveloperAttributionTable({
|
|
205
|
+
locale: "pt-BR",
|
|
206
|
+
rows: [
|
|
207
|
+
{
|
|
208
|
+
account_id: "42",
|
|
209
|
+
login_snapshot: "dev-42",
|
|
210
|
+
prd_count: 1,
|
|
211
|
+
spec_count: 2,
|
|
212
|
+
task_count: 3,
|
|
213
|
+
run_count: 4,
|
|
214
|
+
test_count: null,
|
|
215
|
+
evidence_count: null,
|
|
216
|
+
total_duration_ms: 60_000,
|
|
217
|
+
total_tokens: 50,
|
|
218
|
+
total_cost_brl: 1.5,
|
|
219
|
+
duration_covered_runs: 4,
|
|
220
|
+
token_covered_runs: 4,
|
|
221
|
+
brl_covered_runs: 4,
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
});
|
|
225
|
+
const columns = table.props.columns as Array<{
|
|
226
|
+
key: string;
|
|
227
|
+
label: string;
|
|
228
|
+
render: (row: CostDeveloperAttributionRow) => unknown;
|
|
229
|
+
}>;
|
|
230
|
+
const unavailable = {
|
|
231
|
+
account_id: "unknown",
|
|
232
|
+
login_snapshot: null,
|
|
233
|
+
prd_count: 0,
|
|
234
|
+
spec_count: 0,
|
|
235
|
+
task_count: 0,
|
|
236
|
+
run_count: 0,
|
|
237
|
+
test_count: null,
|
|
238
|
+
evidence_count: null,
|
|
239
|
+
total_duration_ms: null,
|
|
240
|
+
total_tokens: null,
|
|
241
|
+
total_cost_brl: null,
|
|
242
|
+
duration_covered_runs: 0,
|
|
243
|
+
token_covered_runs: 0,
|
|
244
|
+
brl_covered_runs: 0,
|
|
245
|
+
} satisfies CostDeveloperAttributionRow;
|
|
246
|
+
expect(columns.map((column) => [column.key, column.label])).toEqual([
|
|
247
|
+
["developer", "Desenvolvedor"],
|
|
248
|
+
["prds", "PRDs"],
|
|
249
|
+
["specs", "SPECs"],
|
|
250
|
+
["tasks", "Tarefas"],
|
|
251
|
+
["runs", "Runs"],
|
|
252
|
+
["tests", "Testes"],
|
|
253
|
+
["evidences", "Evidências"],
|
|
254
|
+
["duration", "Tempo"],
|
|
255
|
+
["tokens", "Tokens"],
|
|
256
|
+
["cost", "Custos"],
|
|
257
|
+
]);
|
|
258
|
+
expect(columns.find((column) => column.key === "tests")?.render(unavailable)).toBe("—");
|
|
259
|
+
expect(columns.find((column) => column.key === "evidences")?.render(unavailable)).toBe("—");
|
|
260
|
+
expect(columns.find((column) => column.key === "duration")?.render(unavailable)).toBe(
|
|
261
|
+
"Indisponível",
|
|
262
|
+
);
|
|
263
|
+
});
|
|
264
|
+
it("marks incomplete aggregates in place without adding source or coverage columns", () => {
|
|
265
|
+
const partial = {
|
|
266
|
+
account_id: "42",
|
|
267
|
+
login_snapshot: "dev-42",
|
|
268
|
+
prd_count: 1,
|
|
269
|
+
spec_count: 2,
|
|
270
|
+
task_count: 3,
|
|
271
|
+
run_count: 4,
|
|
272
|
+
test_count: null,
|
|
273
|
+
evidence_count: null,
|
|
274
|
+
total_duration_ms: 60_000,
|
|
275
|
+
total_tokens: 50,
|
|
276
|
+
total_cost_brl: 1.5,
|
|
277
|
+
duration_covered_runs: 3,
|
|
278
|
+
token_covered_runs: 2,
|
|
279
|
+
brl_covered_runs: 2,
|
|
280
|
+
} satisfies CostDeveloperAttributionRow;
|
|
281
|
+
const table = CostDeveloperAttributionTable({ locale: "pt-BR", rows: [partial] });
|
|
282
|
+
const columns = table.props.columns as Array<{
|
|
283
|
+
key: string;
|
|
284
|
+
render: (
|
|
285
|
+
row: CostDeveloperAttributionRow,
|
|
286
|
+
) => { props?: { children?: unknown[]; title?: string } } | string;
|
|
287
|
+
}>;
|
|
288
|
+
for (const key of ["duration", "tokens", "cost"]) {
|
|
289
|
+
const rendered = columns.find((column) => column.key === key)?.render(partial);
|
|
290
|
+
expect(rendered).toMatchObject({
|
|
291
|
+
props: {
|
|
292
|
+
title: expect.stringContaining("Valor parcial"),
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
const children = (rendered as { props: { children: unknown[] } }).props.children;
|
|
296
|
+
expect(children[0]).toMatchObject({
|
|
297
|
+
props: { "aria-hidden": "true", children: expect.any(String) },
|
|
298
|
+
});
|
|
299
|
+
expect(children[1]).toMatchObject({
|
|
300
|
+
props: { children: expect.stringContaining("Valor parcial") },
|
|
301
|
+
});
|
|
302
|
+
expect(
|
|
303
|
+
(rendered as { props: { "aria-label"?: string } }).props["aria-label"],
|
|
304
|
+
).toBeUndefined();
|
|
305
|
+
}
|
|
306
|
+
expect(columns.map((column) => column.key)).not.toContain("coverage");
|
|
307
|
+
expect(columns.map((column) => column.key)).not.toContain("source");
|
|
308
|
+
});
|
|
210
309
|
it("uses deduplicated root and child invocation effort in the Run drilldown footer", () => {
|
|
211
310
|
const root = {
|
|
212
311
|
run_id: "RUN-ROOT",
|
|
@@ -290,22 +389,28 @@ describe("grouped cost availability", () => {
|
|
|
290
389
|
expect(column("tokens")?.sortValue?.(unavailableGroup)).toBeNull();
|
|
291
390
|
expect(column("cost")?.sortValue?.(unavailableGroup)).toBeNull();
|
|
292
391
|
const totalSummary = "Total geral — Tempo: Indisponível; Tokens: 0; BRL: R$ 0,00";
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
).toBe("Total geral");
|
|
298
|
-
expect(
|
|
299
|
-
|
|
300
|
-
).toBe(totalSummary);
|
|
301
|
-
expect(
|
|
302
|
-
(column("tokens")!.footer as { props: { "aria-label": string } }).props["aria-label"],
|
|
303
|
-
).toBe(totalSummary);
|
|
304
|
-
expect(
|
|
305
|
-
(column("cost")!.footer as { props: { "aria-label": string } }).props["aria-label"],
|
|
306
|
-
).toBe(totalSummary);
|
|
392
|
+
const footerLabel = (key: string) => {
|
|
393
|
+
const footer = column(key)?.footer as { props?: { "aria-label"?: string } } | undefined;
|
|
394
|
+
return footer?.props?.["aria-label"];
|
|
395
|
+
};
|
|
396
|
+
expect(footerLabel("latestStartedAt")).toBe("Total geral");
|
|
397
|
+
expect(footerLabel("duration")).toBe(totalSummary);
|
|
398
|
+
expect(footerLabel("tokens")).toBe(totalSummary);
|
|
399
|
+
expect(footerLabel("cost")).toBe(totalSummary);
|
|
307
400
|
expect(column("coverage")).toBeUndefined();
|
|
308
401
|
});
|
|
402
|
+
it("keeps the empty state until loading settles for local cost-group pages", () => {
|
|
403
|
+
const loadingTable = CostGroupsTable({
|
|
404
|
+
rows: [],
|
|
405
|
+
currency: "BRL",
|
|
406
|
+
locale: "pt-BR",
|
|
407
|
+
loading: true,
|
|
408
|
+
});
|
|
409
|
+
const emptyTable = CostGroupsTable({ rows: [], currency: "BRL", locale: "pt-BR" });
|
|
410
|
+
|
|
411
|
+
expect(loadingTable.props.emptyMessage).toBe("Carregando…");
|
|
412
|
+
expect(emptyTable.props.emptyMessage).toBe("Nenhum dado disponível.");
|
|
413
|
+
});
|
|
309
414
|
it("uses supplied pre-pagination totals for daily footer metrics", () => {
|
|
310
415
|
const table = CostGroupsTable({
|
|
311
416
|
rows: [{ ...unavailableGroup, total_tokens: 5, estimated_brl: 2, estimated_usd: 1 }],
|
|
@@ -622,121 +727,6 @@ describe("grouped cost availability", () => {
|
|
|
622
727
|
expect(pager.props.pagination.onRetry).toEqual(expect.any(Function));
|
|
623
728
|
});
|
|
624
729
|
});
|
|
625
|
-
describe("period-driven Cost Monitor loading", () => {
|
|
626
|
-
it("drops a stale in-memory Cost period response when refresh replaces its base snapshot", () => {
|
|
627
|
-
const stale = { runs: [{ run_id: "RUN-OBSERVED", duration_ms: 31 * 3_600_000 }] } as never;
|
|
628
|
-
const refreshed = { runs: [{ run_id: "RUN-PROJECTED", duration_ms: 413_659_026 }] } as never;
|
|
629
|
-
expect(activeCostPeriodData(refreshed, stale, stale)).toBe(refreshed);
|
|
630
|
-
expect(activeCostPeriodData(refreshed, refreshed, refreshed)).toBe(refreshed);
|
|
631
|
-
});
|
|
632
|
-
it("does not issue a second Cost request after an embedded default atomic snapshot", () => {
|
|
633
|
-
const filters = {
|
|
634
|
-
query: "",
|
|
635
|
-
provider: "",
|
|
636
|
-
phase: "",
|
|
637
|
-
origin: "",
|
|
638
|
-
workType: "",
|
|
639
|
-
agent: "",
|
|
640
|
-
model: "",
|
|
641
|
-
status: "",
|
|
642
|
-
priority: "",
|
|
643
|
-
risk: "",
|
|
644
|
-
};
|
|
645
|
-
expect(shouldFetchCostPeriod({ filters, period: "month", snapshotBacked: true })).toBe(false);
|
|
646
|
-
expect(shouldFetchCostPeriod({ filters, period: "all", snapshotBacked: true })).toBe(true);
|
|
647
|
-
expect(shouldFetchCostPeriod({ filters, period: "7", snapshotBacked: true })).toBe(true);
|
|
648
|
-
expect(
|
|
649
|
-
shouldFetchCostPeriod({
|
|
650
|
-
filters: { ...filters, phase: "execution" },
|
|
651
|
-
period: "month",
|
|
652
|
-
snapshotBacked: true,
|
|
653
|
-
}),
|
|
654
|
-
).toBe(true);
|
|
655
|
-
});
|
|
656
|
-
it("uses the current month for the default period and keeps All Time explicit", async () => {
|
|
657
|
-
expect(defaultCostPeriod).toBe("month");
|
|
658
|
-
expect(costPeriodDateRange("all", new Date("2026-08-01T03:30:00.000Z"))).toBeUndefined();
|
|
659
|
-
expect(costPeriodDateRange("month", new Date("2026-08-01T03:30:00.000Z"))).toEqual({
|
|
660
|
-
from: "2026-08-01",
|
|
661
|
-
to: "2026-08-01",
|
|
662
|
-
});
|
|
663
|
-
// Selecting standalone All Time still removes the prior month bounds.
|
|
664
|
-
expect(costPeriodDateRange("all", new Date("2026-08-01T03:30:00.000Z"))).toBeUndefined();
|
|
665
|
-
const calls: string[] = [];
|
|
666
|
-
await loadCostMonitorPeriod({
|
|
667
|
-
currency: "BRL",
|
|
668
|
-
fetcher: async (url) => {
|
|
669
|
-
calls.push(String(url));
|
|
670
|
-
return new Response(JSON.stringify({ runs: [] }), { status: 200 });
|
|
671
|
-
},
|
|
672
|
-
});
|
|
673
|
-
expect(calls).toEqual(["/api/v2/cost-monitor?currency=BRL&scope=summary"]);
|
|
674
|
-
});
|
|
675
|
-
it("derives an inclusive current-month range without inspecting materialized Runs", () => {
|
|
676
|
-
expect(costPeriodDateRange("month", new Date("2026-07-26T15:00:00.000Z"))).toEqual({
|
|
677
|
-
from: "2026-07-01",
|
|
678
|
-
to: "2026-07-26",
|
|
679
|
-
});
|
|
680
|
-
expect(costPeriodDateRange("7", new Date("2026-07-26T15:00:00.000Z"))).toEqual({
|
|
681
|
-
from: "2026-07-20",
|
|
682
|
-
to: "2026-07-26",
|
|
683
|
-
});
|
|
684
|
-
});
|
|
685
|
-
it("requests the selected range from the local runtime and forwards cancellation", async () => {
|
|
686
|
-
const calls: Array<{ url: string; signal: AbortSignal | null | undefined }> = [];
|
|
687
|
-
const controller = new AbortController();
|
|
688
|
-
const projection = { runs: [] };
|
|
689
|
-
const loaded = await loadCostMonitorPeriod({
|
|
690
|
-
currency: "BRL",
|
|
691
|
-
from: "2026-07-01",
|
|
692
|
-
to: "2026-07-26",
|
|
693
|
-
filters: {
|
|
694
|
-
query: "TASK-1",
|
|
695
|
-
provider: "openai",
|
|
696
|
-
phase: "execution",
|
|
697
|
-
origin: "spec",
|
|
698
|
-
workType: "rework",
|
|
699
|
-
agent: "zaip-agent-builder",
|
|
700
|
-
model: "gpt-5.6-terra",
|
|
701
|
-
status: "completed",
|
|
702
|
-
priority: "high",
|
|
703
|
-
risk: "standard",
|
|
704
|
-
},
|
|
705
|
-
signal: controller.signal,
|
|
706
|
-
fetcher: async (url, init) => {
|
|
707
|
-
calls.push({ url: String(url), signal: init?.signal });
|
|
708
|
-
return new Response(JSON.stringify(projection), {
|
|
709
|
-
headers: { "content-type": "application/json" },
|
|
710
|
-
status: 200,
|
|
711
|
-
});
|
|
712
|
-
},
|
|
713
|
-
});
|
|
714
|
-
expect(loaded).toEqual(projection);
|
|
715
|
-
expect(calls).toEqual([
|
|
716
|
-
{
|
|
717
|
-
url:
|
|
718
|
-
"/api/v2/cost-monitor?currency=BRL&scope=summary&from=2026-07-01&to=2026-07-26" +
|
|
719
|
-
"&provider=openai&phase=execution&agent=zaip-agent-builder" +
|
|
720
|
-
"&model=gpt-5.6-terra&status=completed",
|
|
721
|
-
signal: controller.signal,
|
|
722
|
-
},
|
|
723
|
-
]);
|
|
724
|
-
});
|
|
725
|
-
it("never leaves period/filter hydration scope-less or on detail", async () => {
|
|
726
|
-
const calls: string[] = [];
|
|
727
|
-
await loadCostMonitorPeriod({
|
|
728
|
-
currency: "USD",
|
|
729
|
-
filters: { ...emptyCostFilters, provider: "openai", model: "gpt-5.6-terra" },
|
|
730
|
-
fetcher: async (url) => {
|
|
731
|
-
calls.push(String(url));
|
|
732
|
-
return new Response(JSON.stringify({ runs: [] }), { status: 200 });
|
|
733
|
-
},
|
|
734
|
-
});
|
|
735
|
-
const request = new URL(calls[0]!, "http://dashboard.local");
|
|
736
|
-
expect(request.searchParams.get("scope")).toBe("summary");
|
|
737
|
-
expect(request.searchParams.get("scope")).not.toBe("detail");
|
|
738
|
-
});
|
|
739
|
-
});
|
|
740
730
|
describe("manifest-first invocation query", () => {
|
|
741
731
|
it("opens only intersecting monthly manifests and candidate chunks", async () => {
|
|
742
732
|
const inRange = signedSummary({
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
} from "@zaip-ai/dashboard-ui";
|
|
7
7
|
import type { CostGroupRow, CostRunRow, DurationCoverage } from "../contracts.js";
|
|
8
8
|
import { MoreVerticalIcon } from "./CostTableIcons.js";
|
|
9
|
+
import { type CostRunPagination, CostRunServerPagination } from "./CostTableLoading.js";
|
|
9
10
|
import type { CostCurrency, CostLocale } from "./cost-monitor-copy.js";
|
|
10
11
|
import {
|
|
11
12
|
agentRunModelPresentation,
|
|
@@ -30,6 +31,10 @@ import {
|
|
|
30
31
|
} from "./cost-table-presentation.js";
|
|
31
32
|
import type { CostGroupTotals } from "./use-cost-group-page.js";
|
|
32
33
|
|
|
34
|
+
export {
|
|
35
|
+
type CostDeveloperAttributionRow,
|
|
36
|
+
CostDeveloperAttributionTable,
|
|
37
|
+
} from "./CostDeveloperAttributionTable.js";
|
|
33
38
|
export { CostModelsAuditTable } from "./CostModelsAuditTable.js";
|
|
34
39
|
|
|
35
40
|
export {
|
|
@@ -269,16 +274,7 @@ export function CostRunsTable({
|
|
|
269
274
|
currency: CostCurrency;
|
|
270
275
|
locale: CostLocale;
|
|
271
276
|
compact?: boolean;
|
|
272
|
-
pagination?:
|
|
273
|
-
offset: number;
|
|
274
|
-
limit: number;
|
|
275
|
-
total: number | null;
|
|
276
|
-
has_more: boolean;
|
|
277
|
-
loading: boolean;
|
|
278
|
-
error: string | null;
|
|
279
|
-
onChange: (offset: number) => void;
|
|
280
|
-
onRetry: () => void;
|
|
281
|
-
};
|
|
277
|
+
pagination?: CostRunPagination;
|
|
282
278
|
}) {
|
|
283
279
|
const footerLabel = costRunsFooterLabel(locale, pagination !== undefined);
|
|
284
280
|
const total = (key: keyof CostRunRow) => sumNumbers(rows.map((row) => row[key]));
|
|
@@ -599,63 +595,6 @@ function inclusiveTokenTotal(
|
|
|
599
595
|
: row.total_tokens;
|
|
600
596
|
}
|
|
601
597
|
|
|
602
|
-
function CostRunServerPagination({
|
|
603
|
-
locale,
|
|
604
|
-
pagination,
|
|
605
|
-
}: {
|
|
606
|
-
locale: CostLocale;
|
|
607
|
-
pagination: NonNullable<Parameters<typeof CostRunsTable>[0]["pagination"]>;
|
|
608
|
-
}) {
|
|
609
|
-
const first = pagination.total === 0 ? 0 : pagination.offset + 1;
|
|
610
|
-
const last =
|
|
611
|
-
pagination.total === null
|
|
612
|
-
? pagination.offset + pagination.limit
|
|
613
|
-
: Math.min(pagination.offset + pagination.limit, pagination.total);
|
|
614
|
-
const previous = Math.max(0, pagination.offset - pagination.limit);
|
|
615
|
-
const next = pagination.offset + pagination.limit;
|
|
616
|
-
return (
|
|
617
|
-
<nav
|
|
618
|
-
aria-label={locale === "pt-BR" ? "Paginação das invocações" : "Invocation pagination"}
|
|
619
|
-
className="ui-table-pagination"
|
|
620
|
-
>
|
|
621
|
-
<button
|
|
622
|
-
disabled={pagination.loading || pagination.offset === 0}
|
|
623
|
-
onClick={() => pagination.onChange(previous)}
|
|
624
|
-
type="button"
|
|
625
|
-
>
|
|
626
|
-
{locale === "pt-BR" ? "Anterior" : "Previous"}
|
|
627
|
-
</button>
|
|
628
|
-
<span aria-live="polite">
|
|
629
|
-
{pagination.loading
|
|
630
|
-
? locale === "pt-BR"
|
|
631
|
-
? "Carregando invocações…"
|
|
632
|
-
: "Loading invocations…"
|
|
633
|
-
: pagination.total === null
|
|
634
|
-
? `${first}–${last}${pagination.has_more ? "+" : ""}`
|
|
635
|
-
: `${first}–${last} ${locale === "pt-BR" ? "de" : "of"} ${pagination.total}`}
|
|
636
|
-
</span>
|
|
637
|
-
<button
|
|
638
|
-
disabled={
|
|
639
|
-
pagination.loading ||
|
|
640
|
-
(!pagination.has_more && (pagination.total === null || next >= pagination.total))
|
|
641
|
-
}
|
|
642
|
-
onClick={() => pagination.onChange(next)}
|
|
643
|
-
type="button"
|
|
644
|
-
>
|
|
645
|
-
{locale === "pt-BR" ? "Próxima" : "Next"}
|
|
646
|
-
</button>
|
|
647
|
-
{pagination.error ? (
|
|
648
|
-
<span role="status">
|
|
649
|
-
{pagination.error}{" "}
|
|
650
|
-
<button onClick={pagination.onRetry} type="button">
|
|
651
|
-
{locale === "pt-BR" ? "Tentar novamente" : "Retry"}
|
|
652
|
-
</button>
|
|
653
|
-
</span>
|
|
654
|
-
) : null}
|
|
655
|
-
</nav>
|
|
656
|
-
);
|
|
657
|
-
}
|
|
658
|
-
|
|
659
598
|
function costPeriodHeading(period: "daily" | "monthly" | "annual", locale: CostLocale): string {
|
|
660
599
|
if (locale === "en-US") {
|
|
661
600
|
return period === "daily" ? "Day" : period === "monthly" ? "Month" : "Year";
|
|
@@ -675,6 +614,7 @@ export function CostGroupsTable({
|
|
|
675
614
|
dateHeading,
|
|
676
615
|
labelHeading,
|
|
677
616
|
totals: suppliedTotals,
|
|
617
|
+
loading = false,
|
|
678
618
|
}: {
|
|
679
619
|
rows: readonly CostGroupRow[];
|
|
680
620
|
currency: CostCurrency;
|
|
@@ -687,6 +627,7 @@ export function CostGroupsTable({
|
|
|
687
627
|
dateHeading?: string;
|
|
688
628
|
labelHeading?: string;
|
|
689
629
|
totals?: CostGroupTotals;
|
|
630
|
+
loading?: boolean;
|
|
690
631
|
}) {
|
|
691
632
|
const pageTotals = {
|
|
692
633
|
runs: rows.reduce((sum, row) => sum + row.run_count, 0),
|
|
@@ -926,6 +867,15 @@ export function CostGroupsTable({
|
|
|
926
867
|
: { key: "label", direction: "desc" }
|
|
927
868
|
}
|
|
928
869
|
locale={locale}
|
|
870
|
+
emptyMessage={
|
|
871
|
+
loading
|
|
872
|
+
? locale === "pt-BR"
|
|
873
|
+
? "Carregando…"
|
|
874
|
+
: "Loading…"
|
|
875
|
+
: locale === "pt-BR"
|
|
876
|
+
? "Nenhum dado disponível."
|
|
877
|
+
: "No data available."
|
|
878
|
+
}
|
|
929
879
|
pageSize={100}
|
|
930
880
|
rowKey={(row) => row.key}
|
|
931
881
|
onRowClick={onOpenTrace === undefined ? undefined : (row) => onOpenTrace(row.key)}
|
|
@@ -37,6 +37,7 @@ export const costCopy = {
|
|
|
37
37
|
daily: "Diário",
|
|
38
38
|
monthly: "Mensal",
|
|
39
39
|
annual: "Anual",
|
|
40
|
+
developers: "Desenvolvedores",
|
|
40
41
|
},
|
|
41
42
|
},
|
|
42
43
|
"en-US": {
|
|
@@ -73,6 +74,7 @@ export const costCopy = {
|
|
|
73
74
|
daily: "Daily",
|
|
74
75
|
monthly: "Monthly",
|
|
75
76
|
annual: "Annual",
|
|
77
|
+
developers: "Developers",
|
|
76
78
|
},
|
|
77
79
|
},
|
|
78
80
|
} as const;
|
|
@@ -11,7 +11,8 @@ export type CostView =
|
|
|
11
11
|
| "models"
|
|
12
12
|
| "daily"
|
|
13
13
|
| "monthly"
|
|
14
|
-
| "annual"
|
|
14
|
+
| "annual"
|
|
15
|
+
| "developers";
|
|
15
16
|
|
|
16
17
|
export const DEFAULT_COST_VIEW: CostView = "daily";
|
|
17
18
|
|
|
@@ -19,6 +20,7 @@ export const COST_VIEW_ORDER: readonly CostView[] = [
|
|
|
19
20
|
"daily",
|
|
20
21
|
"monthly",
|
|
21
22
|
"annual",
|
|
23
|
+
"developers",
|
|
22
24
|
"overview",
|
|
23
25
|
"executions",
|
|
24
26
|
"agentCalls",
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type CostPeriod, defaultCostPeriod } from "./CostFilters.js";
|
|
2
|
+
|
|
3
|
+
export type CostPageDateRange = { from: string; to: string };
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Embedded pages use the host's all-time atomic snapshot until an explicit
|
|
7
|
+
* period, date range, or local Cost filter narrows the population.
|
|
8
|
+
*/
|
|
9
|
+
export function resolveCostGroupPageRange({
|
|
10
|
+
embedded,
|
|
11
|
+
globalDateRange,
|
|
12
|
+
hasLocalCostFilters,
|
|
13
|
+
period,
|
|
14
|
+
runPageRange,
|
|
15
|
+
}: {
|
|
16
|
+
embedded: boolean;
|
|
17
|
+
globalDateRange: { start: string; end: string } | undefined;
|
|
18
|
+
hasLocalCostFilters: boolean;
|
|
19
|
+
period: CostPeriod;
|
|
20
|
+
runPageRange: CostPageDateRange | undefined;
|
|
21
|
+
}): CostPageDateRange | undefined {
|
|
22
|
+
if (
|
|
23
|
+
embedded &&
|
|
24
|
+
globalDateRange === undefined &&
|
|
25
|
+
period === defaultCostPeriod &&
|
|
26
|
+
!hasLocalCostFilters
|
|
27
|
+
)
|
|
28
|
+
return undefined;
|
|
29
|
+
return runPageRange;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Compact lifecycle tables share the same embedded snapshot contract. */
|
|
33
|
+
export function resolveCompactCostPageRange(args: Parameters<typeof resolveCostGroupPageRange>[0]) {
|
|
34
|
+
return resolveCostGroupPageRange(args);
|
|
35
|
+
}
|
|
@@ -28,15 +28,26 @@ export function compactReadModelKind(view: CostView): CompactReadModelKind | nul
|
|
|
28
28
|
: null;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/** A page fallback is valid only for the same compact table surface. */
|
|
32
|
+
export function isSameCompactCostSurface(resolvedKey: string | null, requestKey: string): boolean {
|
|
33
|
+
if (resolvedKey === null) return false;
|
|
34
|
+
return (
|
|
35
|
+
resolvedKey.slice(0, resolvedKey.lastIndexOf("\u0000")) ===
|
|
36
|
+
requestKey.slice(0, requestKey.lastIndexOf("\u0000"))
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
31
40
|
export function useCompactCostPage({
|
|
32
41
|
view,
|
|
33
42
|
load,
|
|
43
|
+
limit = 50,
|
|
34
44
|
range,
|
|
35
45
|
query,
|
|
36
46
|
filters,
|
|
37
47
|
}: {
|
|
38
48
|
view: CostView;
|
|
39
49
|
load: LoadCompactCostPage | undefined;
|
|
50
|
+
limit?: number;
|
|
40
51
|
range: { from: string; to: string } | undefined;
|
|
41
52
|
query: string | undefined;
|
|
42
53
|
filters: CostFilterState;
|
|
@@ -54,10 +65,10 @@ export function useCompactCostPage({
|
|
|
54
65
|
const rangeFrom = range?.from;
|
|
55
66
|
const rangeTo = range?.to;
|
|
56
67
|
const filterKey = Object.values(filters).join("\u0000");
|
|
57
|
-
const paginationKey = `${view}\u0000${query ?? ""}\u0000${rangeFrom ?? ""}\u0000${rangeTo ?? ""}\u0000${filterKey}`;
|
|
68
|
+
const paginationKey = `${view}\u0000${limit}\u0000${query ?? ""}\u0000${rangeFrom ?? ""}\u0000${rangeTo ?? ""}\u0000${filterKey}`;
|
|
58
69
|
const requestKey = `${paginationKey}\u0000${offset}`;
|
|
59
|
-
const requestInputRef = useRef({ filters, query, rangeFrom, rangeTo });
|
|
60
|
-
requestInputRef.current = { filters, query, rangeFrom, rangeTo };
|
|
70
|
+
const requestInputRef = useRef({ filters, limit, query, rangeFrom, rangeTo });
|
|
71
|
+
requestInputRef.current = { filters, limit, query, rangeFrom, rangeTo };
|
|
61
72
|
useEffect(() => {
|
|
62
73
|
void paginationKey;
|
|
63
74
|
setOffset(0);
|
|
@@ -81,7 +92,7 @@ export function useCompactCostPage({
|
|
|
81
92
|
void loadPage({
|
|
82
93
|
kind,
|
|
83
94
|
offset,
|
|
84
|
-
limit:
|
|
95
|
+
limit: requestInput.limit,
|
|
85
96
|
...(requestInput.rangeFrom === undefined || requestInput.rangeTo === undefined
|
|
86
97
|
? {}
|
|
87
98
|
: { from: requestInput.rangeFrom, to: requestInput.rangeTo }),
|
|
@@ -112,6 +123,7 @@ export function useCompactCostPage({
|
|
|
112
123
|
// A response for another tab, range, filter, or offset must never occupy
|
|
113
124
|
// this view while the next request is in flight.
|
|
114
125
|
compactPage: resolvedKey === requestKey ? page : null,
|
|
126
|
+
staleCompactPage: isSameCompactCostSurface(resolvedKey, requestKey) ? page : null,
|
|
115
127
|
compactPageLoading: loading,
|
|
116
128
|
compactPageError: error,
|
|
117
129
|
retryCompactPage: () => setAttempt((value) => value + 1),
|
package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.test.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
1
2
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import {
|
|
3
|
+
import { isSameCompactCostSurface } from "./use-compact-cost-page.js";
|
|
4
|
+
import { isCurrentCostGroupPage, isSameCostGroupSurface } from "./use-cost-group-page.js";
|
|
3
5
|
|
|
4
|
-
describe("
|
|
6
|
+
describe("useCostGroupPage loading lifecycle", () => {
|
|
5
7
|
it("masks a resolved monthly page while the annual request is pending", () => {
|
|
6
8
|
const monthly = "monthly\u0000\u0000\u0000\u0000\u00000";
|
|
7
9
|
const annual = "annual\u0000\u0000\u0000\u0000\u00000";
|
|
@@ -9,4 +11,37 @@ describe("Cost group page request identity", () => {
|
|
|
9
11
|
expect(isCurrentCostGroupPage(monthly, annual)).toBe(false);
|
|
10
12
|
expect(isCurrentCostGroupPage(annual, annual)).toBe(true);
|
|
11
13
|
});
|
|
14
|
+
|
|
15
|
+
it("never reuses rows from another tab while its slow request is pending", () => {
|
|
16
|
+
const daily = "daily\u000010\u00002026-08-01\u00002026-08-25\u0000\u00000";
|
|
17
|
+
const models = "models\u000010\u00002026-08-01\u00002026-08-25\u0000\u00000";
|
|
18
|
+
const executions = "executions\u000010\u0000\u00002026-08-01\u00002026-08-25\u0000\u00000";
|
|
19
|
+
const tasks = "tasks\u000010\u0000\u00002026-08-01\u00002026-08-25\u0000\u00000";
|
|
20
|
+
|
|
21
|
+
expect(isSameCostGroupSurface(daily, models)).toBe(false);
|
|
22
|
+
expect(isSameCompactCostSurface(executions, tasks)).toBe(false);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("keeps previous rows only while the next page of the same tab is pending", () => {
|
|
26
|
+
const firstPage = "daily\u000010\u00002026-08-01\u00002026-08-25\u0000\u00000";
|
|
27
|
+
const secondPage = "daily\u000010\u00002026-08-01\u00002026-08-25\u0000\u000010";
|
|
28
|
+
|
|
29
|
+
expect(isSameCostGroupSurface(firstPage, secondPage)).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("invalidates an aborted request before clearing an inactive group view", () => {
|
|
33
|
+
const source = readFileSync(new URL("./use-cost-group-page.ts", import.meta.url), "utf8");
|
|
34
|
+
|
|
35
|
+
expect(source).toContain("const current = ++generation.current;");
|
|
36
|
+
expect(source).toContain("if (!active || !loader.current)");
|
|
37
|
+
expect(source).toContain("setLoading(false);");
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("handles loader failures instead of leaving a rejected promise", () => {
|
|
41
|
+
const source = readFileSync(new URL("./use-cost-group-page.ts", import.meta.url), "utf8");
|
|
42
|
+
|
|
43
|
+
expect(source).toContain(".catch((cause: unknown) => {");
|
|
44
|
+
expect(source).toContain("setError(cause instanceof Error ? cause.message : String(cause));");
|
|
45
|
+
expect(source).toContain("retry: () => setAttempt");
|
|
46
|
+
});
|
|
12
47
|
});
|