@zaip-ai/cli 4.5.0 → 4.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/commands/init.js +1 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/services/adapters.d.ts +1 -1
- package/dist/services/adapters.d.ts.map +1 -1
- package/dist/services/adapters.js +6 -6
- package/dist/services/adapters.js.map +1 -1
- package/dist/services/codex-config-overlay.d.ts.map +1 -1
- package/dist/services/codex-config-overlay.js +27 -10
- package/dist/services/codex-config-overlay.js.map +1 -1
- package/dist/services/codex-native-tool-authority-template.d.ts.map +1 -1
- package/dist/services/codex-native-tool-authority-template.js +188 -9
- package/dist/services/codex-native-tool-authority-template.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 +50 -128
- package/dist/services/codex-pre-tool-hook-template.js.map +1 -1
- package/dist/services/codex-pre-tool-hook-template.test.js +4 -0
- package/dist/services/codex-pre-tool-hook-template.test.js.map +1 -1
- package/dist/services/codex-pre-tool-support-template.d.ts.map +1 -1
- package/dist/services/codex-pre-tool-support-template.js +1 -4
- package/dist/services/codex-pre-tool-support-template.js.map +1 -1
- package/dist/services/codex-stale-git-lock-template.d.ts +2 -0
- package/dist/services/codex-stale-git-lock-template.d.ts.map +1 -0
- package/dist/services/codex-stale-git-lock-template.js +64 -0
- package/dist/services/codex-stale-git-lock-template.js.map +1 -0
- package/dist/services/global-codex-config-migration.test.js +1 -4
- package/dist/services/global-codex-config-migration.test.js.map +1 -1
- package/dist/services/global-codex-config.d.ts.map +1 -1
- package/dist/services/global-codex-config.js +2 -1
- package/dist/services/global-codex-config.js.map +1 -1
- package/dist/services/global-codex-config.test.js +3 -1
- package/dist/services/global-codex-config.test.js.map +1 -1
- package/dist/services/hook-readiness.d.ts.map +1 -1
- package/dist/services/hook-readiness.js.map +1 -1
- package/dist/services/install-agents-template.js +2 -2
- package/dist/services/install-agents-template.js.map +1 -1
- package/dist/services/install-template-policy.d.ts.map +1 -1
- package/dist/services/install-template-policy.js +2 -0
- package/dist/services/install-template-policy.js.map +1 -1
- package/dist/services/logger.d.ts +1 -1
- package/dist/services/logger.d.ts.map +1 -1
- package/dist/services/logger.js +2 -1
- package/dist/services/logger.js.map +1 -1
- package/dist/services/logger.test.js +77 -0
- package/dist/services/logger.test.js.map +1 -1
- package/dist/services/runtime-template-integrity.test.d.ts +2 -0
- package/dist/services/runtime-template-integrity.test.d.ts.map +1 -0
- package/dist/services/runtime-template-integrity.test.js +26 -0
- package/dist/services/runtime-template-integrity.test.js.map +1 -0
- package/dist/services/runtime-template-test-support.d.ts +3 -0
- package/dist/services/runtime-template-test-support.d.ts.map +1 -0
- package/dist/services/runtime-template-test-support.js +32 -0
- package/dist/services/runtime-template-test-support.js.map +1 -0
- package/dist/services/runtime-template.test.js +37 -48
- package/dist/services/runtime-template.test.js.map +1 -1
- package/package.json +1 -1
- package/templates/.agents/README.md +8 -0
- package/templates/.agents/config/agents/discovery.json +1 -1
- package/templates/.agents/config/deploy-policy.json +5 -0
- package/templates/.agents/dashboard/.zaip-managed.json +235 -83
- package/templates/.agents/dashboard/README.md +2 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-f4ZGJRg3.js → CostCalculationGuidePage-OUjdwEcM.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-CkQ_y8kg.js → DashboardHelpDialog-Cei1ChjE.js} +99 -10
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-v9zGRTlk.js → PricingSettingsDialog-_woNCrTT.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{ProjectSettingsPage-doIMhei7.js → ProjectSettingsPage-B2_7MVOP.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-C_4ftjyB.js → TraceabilityWorkspace-C_jCsSZe.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-C8zQDBT7.js +68 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-Cv3WBFIF.js → icons-vendor-iMPXot7Y.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-DZhppOIk.css +1 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-DiCwz0sr.js +2 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-mHgsmxb6.js → react-vendor-721Re3Ss.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-B0CPyEVq.js → traceability-BjdTkWS0.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/index.html +6 -6
- package/templates/.agents/dashboard/apps/frontend/package.json +1 -1
- package/templates/.agents/dashboard/apps/frontend/src/AppOverlays.tsx +6 -34
- package/templates/.agents/dashboard/apps/frontend/src/ReconciliationFeedback.dom.test.ts +130 -0
- package/templates/.agents/dashboard/apps/frontend/src/ReconciliationFeedback.tsx +226 -0
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-api-sqlite-view.ts +45 -0
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +15 -0
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +17 -46
- package/templates/.agents/dashboard/apps/frontend/src/reconciliation-feedback-fixtures.ts +23 -0
- package/templates/.agents/dashboard/apps/frontend/src/reconciliation-feedback-model.test.ts +69 -0
- package/templates/.agents/dashboard/apps/frontend/src/reconciliation-feedback-model.ts +59 -0
- package/templates/.agents/dashboard/apps/frontend/src/reconciliation-feedback.css +131 -0
- package/templates/.agents/dashboard/apps/frontend/src/styles.css +0 -32
- package/templates/.agents/dashboard/apps/frontend/src/use-dashboard-app-model.tsx +2 -2
- package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.test.ts +2 -2
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +1 -1
- package/templates/.agents/dashboard/modules/operations/package.json +1 -1
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.macro-metrics.test.ts +7 -2
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +6 -6
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +1 -4
- package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkBoard.navigation.test.ts +236 -0
- package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkBoard.tsx +1 -24
- package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +3 -2
- package/templates/.agents/dashboard/modules/operations/src/react/overview-duration-hint.ts +14 -0
- package/templates/.agents/dashboard/modules/traceability/package.json +1 -1
- package/templates/.agents/dashboard/packages/branding/package.json +1 -1
- package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
- package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/DIAGNOSTICS.md +42 -0
- package/templates/.agents/dashboard/packages/local-runtime/dashboard-diagnostics.d.mts +10 -0
- package/templates/.agents/dashboard/packages/local-runtime/dashboard-diagnostics.mjs +101 -0
- package/templates/.agents/dashboard/packages/local-runtime/dashboard-diagnostics.test.mjs +58 -0
- package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +318 -236
- package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +285 -205
- package/templates/.agents/dashboard/packages/local-runtime/package.json +1 -1
- package/templates/.agents/dashboard/packages/local-runtime/scripts/test-sqlite-dashboard-startup.mjs +233 -0
- package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-provider-nonzero.mjs +45 -0
- package/templates/.agents/dashboard/packages/local-runtime/scripts/verify-dashboard-executable-startup.mjs +107 -0
- package/templates/.agents/dashboard/packages/local-runtime/scripts/verify-dashboard-reconciliation-executable.mjs +271 -0
- package/templates/.agents/dashboard/packages/local-runtime/server.mjs +318 -236
- package/templates/.agents/dashboard/packages/local-runtime/src/active-codex-telemetry.test.ts +78 -12
- package/templates/.agents/dashboard/packages/local-runtime/src/active-codex-telemetry.ts +36 -56
- package/templates/.agents/dashboard/packages/local-runtime/src/canonical-source-revision-cache.test.ts +125 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/canonical-source-revision-cache.ts +168 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/dashboard-diagnostics.test.ts +57 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-agent-catalog-routes.ts +76 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-dual-reads-manifest-summaries-without-losing.test.ts +5 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-reconciliation-diagnostics.test.ts +118 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-reconciliation-result.test.ts +35 -6
- package/templates/.agents/dashboard/packages/local-runtime/src/server-reconciliation-route.ts +105 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-synchronization.test.ts +64 -9
- package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-synchronization.ts +19 -27
- package/templates/.agents/dashboard/packages/local-runtime/src/server-telemetry-command.test.ts +111 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-telemetry-refresh.test.ts +59 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-telemetry-refresh.ts +44 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-work-reconciliation.test.ts +20 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-work-reconciliation.ts +12 -7
- package/templates/.agents/dashboard/packages/local-runtime/src/server-workspace.ts +48 -6
- package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +2 -2
- package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +126 -134
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.ts +14 -2
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-summary-elapsed.ts +107 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-dashboard-startup.test.ts +163 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-dashboard-startup.ts +78 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-header-timestamp.test.ts +31 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-provider-nonzero.test.ts +271 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-provider-visibility.ts +32 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-operations-duration.ts +58 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-provider-dimension.ts +12 -3
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-summary.ts +41 -54
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-view-page.ts +9 -58
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-canonical.ts +7 -7
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-counts-every-root-execution-day-returns.test.ts +5 -5
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider.test.ts +4 -4
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-rebuild.ts +9 -35
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-schema.ts +13 -9
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.ts +43 -45
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +5 -9
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +5 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-schema-base-views.ts +9 -7
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-schema-dashboard-views.ts +10 -8
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-spec-root-elapsed-view.ts +61 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-spec-root-elapsed.test.ts +210 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-startup-seed.test.ts +87 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-logging.mjs +6 -2
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-server.mjs +7 -1
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +4 -5
- package/templates/.agents/dashboard/packages/ui/package.json +1 -1
- package/templates/.agents/dashboard/packages/ui/src/DashboardHeader.test.mjs +33 -4
- package/templates/.agents/dashboard/packages/ui/src/DashboardHeader.tsx +8 -7
- package/templates/.agents/dashboard/packages/windows-launcher/Program.cs +46 -3
- package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
- package/templates/.agents/dashboard/tests/e2e/qualify-kanban-popup.mjs +56 -0
- package/templates/.agents/dashboard/tests/e2e/specs/dashboard-update-label.spec.ts +49 -0
- package/templates/.agents/design/.zaip-managed.json +17 -5
- package/templates/.agents/design/apps/catalog/dist/assets/index-D3uhpycC.js +72 -0
- package/templates/.agents/design/apps/catalog/dist/index.html +1 -1
- package/templates/.agents/design/apps/catalog/package.json +1 -1
- package/templates/.agents/design/apps/catalog/src/pages/ComponentsPage.tsx +13 -1
- package/templates/.agents/design/apps/catalog/src/specimens/ReconciliationSpecimen.stories.tsx +6 -0
- package/templates/.agents/design/apps/catalog/src/specimens/ReconciliationSpecimen.tsx +101 -0
- package/templates/.agents/design/packages/local-runtime/package.json +1 -1
- package/templates/.agents/requirements/autonomous-assurance.md +1 -1
- package/templates/.agents/requirements/cloud-hostinger-autonomy.md +1 -1
- package/templates/.agents/requirements/comparative-audit.md +1 -1
- package/templates/.agents/requirements/context-engine.md +1 -1
- package/templates/.agents/requirements/cost-observability.md +1 -1
- package/templates/.agents/requirements/dashboard-launch.md +1 -1
- package/templates/.agents/requirements/data-export.md +1 -1
- package/templates/.agents/requirements/design-system.md +1 -1
- package/templates/.agents/requirements/execution-engine.md +1 -1
- package/templates/.agents/requirements/kanban-dashboard.md +1 -1
- package/templates/.agents/requirements/model-orchestration.md +21 -6
- package/templates/.agents/requirements/public-distribution.md +4 -4
- package/templates/.agents/requirements/software-architecture.md +1 -1
- package/templates/.agents/requirements/strategic-improvements.md +1 -1
- package/templates/.agents/requirements/work-lifecycle.md +1 -1
- package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
- package/templates/.agents/rules/core.md +3 -1
- package/templates/.agents/rules/workflow.md +3 -2
- package/templates/.agents/runtime/VERSION +1 -1
- package/templates/.agents/runtime/bin/zaip.mjs +368 -199
- package/templates/.agents/runtime/checksums.sha256 +5 -5
- package/templates/.agents/runtime/manifest.json +1 -1
- package/templates/.agents/runtime/provenance.json +4 -4
- package/templates/.agents/runtime/sbom.cdx.json +1 -1
- package/templates/.agents/skills/zaip-skill-config/SKILL.md +25 -3
- package/templates/.agents/skills/zaip-skill-execution/SKILL.md +4 -0
- package/templates/.agents/skills/zaip-skill-execution/references/autonomous-continuation.md +4 -0
- package/templates/.agents/skills/zaip-skill-execution/references/candidate-workflow.md +1 -1
- package/templates/.agents/skills/zaip-skill-execution/references/runtime-governance.md +2 -2
- package/templates/.agents/skills/zaip-skill-general-operations/SKILL.md +1 -0
- package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +38 -48
- package/templates/.agents/skills/zaip-skill-github-deploy/agents/openai.yaml +2 -2
- package/templates/.agents/skills/zaip-skill-github-deploy/references/deployment-workflow.md +67 -99
- package/templates/.agents/skills/zaip-skill-github-deploy/references/release-identity.md +33 -30
- package/templates/.agents/skills/zaip-skill-github-deploy/scripts/deploy-contract.mjs +307 -0
- package/templates/.agents/skills/zaip-skill-github-deploy/scripts/deploy-contract.test.mjs +337 -0
- package/templates/.agents/skills/zaip-skill-github-deploy/scripts/github-deploy-contract.test.mjs +41 -28
- package/templates/.agents/skills/zaip-skill-github-deploy/scripts/guarded-commits.mjs +212 -0
- package/templates/.agents/skills/zaip-skill-lifecycle-closure/SKILL.md +4 -0
- package/templates/.agents/skills/zaip-skill-prd/SKILL.md +4 -0
- package/templates/.agents/skills/zaip-skill-release-qualification/SKILL.md +46 -68
- package/templates/.agents/skills/zaip-skill-release-qualification/references/local-preparation.md +100 -44
- package/templates/.agents/skills/zaip-skill-send-email/SKILL.md +15 -0
- package/templates/.agents/skills/zaip-skill-send-email/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-setup/SKILL.md +5 -2
- package/templates/.agents/skills/zaip-skill-spec/SKILL.md +4 -0
- package/templates/.agents/skills/zaip-skill-task/SKILL.md +4 -0
- package/templates/.agents/skills/zaip-skill-testing-strategy/SKILL.md +19 -0
- package/templates/.agents/skills/zaip-skill-tool-setup/SKILL.md +2 -0
- package/templates/.agents/skills/zaip-skill-use-connectors/SKILL.md +15 -0
- package/templates/.agents/skills/zaip-skill-use-connectors/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-use-connectors/scripts/connector-guidance.test.mjs +29 -0
- package/templates/.agents/skills/zaip-skill-use-connectors/scripts/verify-connector-lock.mjs +30 -0
- package/templates/.agents/tools/cloud-runner.integration.test.mjs +3 -0
- package/templates/.agents/zaip-aios/VERSION +1 -1
- package/templates/.agents/zaip-aios/guides/03-tasks.md +6 -0
- package/templates/.agents/zaip-aios/guides/04-specs.md +6 -0
- package/templates/.agents/zaip-aios/guides/05-prds.md +4 -0
- package/templates/.agents/zaip-aios/guides/06-execucao.md +6 -0
- package/templates/.agents/zaip-aios/guides/16-lifecycle-e-reconciliacao.md +6 -0
- package/templates/.agents/zaip-aios/guides/19-assurance-e-autonomia.md +4 -0
- package/templates/.agents/zaip-aios/guides/22-fluxos-e-roteamento.md +6 -0
- package/templates/.agents/zaip-aios/guides/23-orquestracao-de-modelos.md +36 -4
- package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +15 -4
- package/templates/.agents/zaip-aios/guides/28-lifecycle-completo.md +8 -0
- package/templates/template-manifest.json +354 -150
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-D7PrDZy9.js +0 -68
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-OBJXZOwe.css +0 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-Rbmpz4UO.js +0 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { basename, resolve } from "node:path";
|
|
3
3
|
import { serve } from "@hono/node-server";
|
|
4
4
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
@@ -6,24 +6,20 @@ import { WorkspaceFileSystem, type WorkspaceLayout } from "@zaip-ai/core";
|
|
|
6
6
|
import { fxRateSchema, PricingRepository, pricingCatalogSchema } from "@zaip-ai/costs";
|
|
7
7
|
import { type Context, Hono } from "hono";
|
|
8
8
|
import { getCookie, setCookie } from "hono/cookie";
|
|
9
|
+
import { createDashboardDiagnostics } from "../dashboard-diagnostics.mjs";
|
|
9
10
|
import {
|
|
10
11
|
type ActiveCodexTelemetryCapture,
|
|
11
12
|
captureRepositoryActiveCodexTelemetry,
|
|
12
13
|
} from "./active-codex-telemetry.js";
|
|
13
14
|
import { runAgentAdapterSync } from "./agent-adapter-sync.js";
|
|
14
|
-
import {
|
|
15
|
-
type AgentAdapterSyncResult,
|
|
16
|
-
AgentCatalogUpdateError,
|
|
17
|
-
persistAgentCatalogUpdate,
|
|
18
|
-
readAgentCatalogSettings,
|
|
19
|
-
} from "./agent-catalog-settings.js";
|
|
15
|
+
import type { AgentAdapterSyncResult } from "./agent-catalog-settings.js";
|
|
20
16
|
import {
|
|
21
17
|
persistProjectSettings,
|
|
22
18
|
readProjectOverview,
|
|
23
19
|
readProjectSettings,
|
|
24
20
|
} from "./project-settings.js";
|
|
25
21
|
import { createProjectionRefreshDiagnostics } from "./projection-refresh-diagnostics.js";
|
|
26
|
-
import {
|
|
22
|
+
import { registerAgentCatalogRoutes } from "./server-agent-catalog-routes.js";
|
|
27
23
|
import { registerBrowserLeaseRoute } from "./server-browser-lease.js";
|
|
28
24
|
import { registerCostsRoutes } from "./server-costs-routes.js";
|
|
29
25
|
import {
|
|
@@ -36,12 +32,17 @@ import { lifecycleManifestState } from "./server-lifecycle-diagnostics.js";
|
|
|
36
32
|
import { registerOperationsRoutes } from "./server-operations-routes.js";
|
|
37
33
|
import { projectionPeriodFilter } from "./server-period.js";
|
|
38
34
|
import { buildFirstFoldQuickProjection, dashboardSnapshot } from "./server-read-projections.js";
|
|
35
|
+
import {
|
|
36
|
+
createLoggedWorkReconciliation,
|
|
37
|
+
registerReconciliationRoute,
|
|
38
|
+
} from "./server-reconciliation-route.js";
|
|
39
39
|
import { isAllowedDashboardAuthority } from "./server-request-authority.js";
|
|
40
40
|
import { refreshSqliteSnapshotInWorker } from "./server-snapshot-refresh.js";
|
|
41
41
|
import { readCommittedSnapshotRevision } from "./server-snapshot-revision.js";
|
|
42
42
|
import { startSnapshotSynchronization } from "./server-snapshot-synchronization.js";
|
|
43
43
|
import { writeReadModelStartup, writeStartupPhase } from "./server-startup.js";
|
|
44
44
|
import { selectedCurrency } from "./server-summary-helpers.js";
|
|
45
|
+
import { createTelemetryProjectionRefresh } from "./server-telemetry-refresh.js";
|
|
45
46
|
import { registerTraceRoutes } from "./server-trace-routes.js";
|
|
46
47
|
import {
|
|
47
48
|
defaultSessionToken,
|
|
@@ -50,20 +51,11 @@ import {
|
|
|
50
51
|
isSafeUiPath,
|
|
51
52
|
shouldBootstrapBrowserSession,
|
|
52
53
|
} from "./server-ui-security.js";
|
|
53
|
-
import {
|
|
54
|
-
createWorkReconciliation,
|
|
55
|
-
waitForWorkReconciliation,
|
|
56
|
-
} from "./server-work-reconciliation.js";
|
|
57
54
|
import { dashboardCanonicalSourceRoots } from "./sqlite-read-model-source-fingerprint.js";
|
|
58
55
|
|
|
59
56
|
export { reconciliationNeedsRefresh } from "./server-work-reconciliation.js";
|
|
60
57
|
|
|
61
|
-
import {
|
|
62
|
-
dashboardIdentity,
|
|
63
|
-
dashboardWorkspaceKey,
|
|
64
|
-
ReconciliationCommandTimeoutError,
|
|
65
|
-
reconcileOpenWork,
|
|
66
|
-
} from "./server-workspace.js";
|
|
58
|
+
import { dashboardIdentity, dashboardWorkspaceKey, reconcileOpenWork } from "./server-workspace.js";
|
|
67
59
|
import { rebuildSqliteReadModel, SqliteReadModelFileSystem } from "./sqlite-read-model.js";
|
|
68
60
|
|
|
69
61
|
export { manifestRun, mergeManifestRuns } from "./manifest-runs.js";
|
|
@@ -95,6 +87,7 @@ interface DashboardAppOptions {
|
|
|
95
87
|
snapshotReadOnly?: boolean;
|
|
96
88
|
reconcileOpenWork?: typeof reconcileOpenWork;
|
|
97
89
|
refreshReadModel?: () => Promise<void>;
|
|
90
|
+
captureTelemetry?: () => Promise<ActiveCodexTelemetryCapture>;
|
|
98
91
|
snapshotState?: "current" | "updating";
|
|
99
92
|
/** Enable filesystem and day rollover synchronization for the serving process. */
|
|
100
93
|
watchSources?: boolean;
|
|
@@ -123,6 +116,8 @@ export function createDashboardApp(
|
|
|
123
116
|
options: DashboardAppOptions = {},
|
|
124
117
|
): Hono {
|
|
125
118
|
const app = new Hono();
|
|
119
|
+
const diagnostics = createDashboardDiagnostics(workspaceRoot, "runtime");
|
|
120
|
+
diagnostics.log("runtime_app_started", { snapshot_read_only: options.snapshotReadOnly });
|
|
126
121
|
const filesystem = options.filesystem ?? new WorkspaceFileSystem(workspaceRoot);
|
|
127
122
|
const isSqliteSnapshot = filesystem instanceof SqliteReadModelFileSystem;
|
|
128
123
|
// Cache layout within a committed revision and reload after synchronization.
|
|
@@ -145,7 +140,6 @@ export function createDashboardApp(
|
|
|
145
140
|
const workspace = resolve(workspaceRoot);
|
|
146
141
|
const workspaceName = basename(workspace);
|
|
147
142
|
const syncAgentAdapters = options.syncAgentAdapters ?? (() => runAgentAdapterSync(workspaceRoot));
|
|
148
|
-
let catalogWriteTail = Promise.resolve();
|
|
149
143
|
type DashboardSnapshot = Awaited<ReturnType<typeof dashboardSnapshot>>;
|
|
150
144
|
const snapshotInFlight = new Map<string, Promise<DashboardSnapshot>>();
|
|
151
145
|
const cachedSnapshots = new Map<string, { snapshot: DashboardSnapshot; cachedAt: number }>();
|
|
@@ -198,12 +192,17 @@ export function createDashboardApp(
|
|
|
198
192
|
let activeCapture: ActiveCodexTelemetryCapture | null = null;
|
|
199
193
|
let projectionRefreshInFlight: Promise<void> | null = null;
|
|
200
194
|
let projectionRefreshRequested = false;
|
|
201
|
-
const
|
|
195
|
+
const associatedRefreshJobs = new Set<string>();
|
|
196
|
+
const rebuildProjection = async (associatedJobId: string | null = null) => {
|
|
197
|
+
if (associatedJobId !== null) associatedRefreshJobs.add(associatedJobId);
|
|
202
198
|
if (projectionRefreshInFlight !== null) {
|
|
203
199
|
projectionRefreshRequested = true;
|
|
204
200
|
return projectionRefreshInFlight;
|
|
205
201
|
}
|
|
206
202
|
snapshotState = "updating";
|
|
203
|
+
const refresh_id = randomUUID();
|
|
204
|
+
const job_id = associatedJobId;
|
|
205
|
+
diagnostics.log("projection_refresh_started", { refresh_id, job_id });
|
|
207
206
|
projectionRefreshInFlight = (async () => {
|
|
208
207
|
let passes = 0;
|
|
209
208
|
do {
|
|
@@ -217,36 +216,57 @@ export function createDashboardApp(
|
|
|
217
216
|
} while (projectionRefreshRequested && passes < 2);
|
|
218
217
|
snapshotState = "current";
|
|
219
218
|
projectionRefreshDiagnostics.clear();
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
219
|
+
diagnostics.log("projection_refresh_completed", {
|
|
220
|
+
refresh_id,
|
|
221
|
+
job_id: [...associatedRefreshJobs][0] ?? job_id,
|
|
222
|
+
job_ids: [...associatedRefreshJobs],
|
|
223
|
+
projection_updated_at: isSqliteSnapshot ? filesystem.projectionUpdatedAt() : null,
|
|
224
|
+
latest_token_collected_at: isSqliteSnapshot ? filesystem.latestTokenCollectedAt() : null,
|
|
225
|
+
});
|
|
226
|
+
if (!projectionRefreshRequested) associatedRefreshJobs.clear();
|
|
227
|
+
})()
|
|
228
|
+
.catch((error: unknown) => {
|
|
229
|
+
// A failed promotion is still an older snapshot; leave its readiness
|
|
230
|
+
// explicit and retain evidence instead of silently swallowing failure.
|
|
231
|
+
projectionRefreshDiagnostics.record({ trigger: "source_change", error });
|
|
232
|
+
diagnostics.log("projection_refresh_failed", {
|
|
233
|
+
refresh_id,
|
|
234
|
+
job_id: [...associatedRefreshJobs][0] ?? job_id,
|
|
235
|
+
job_ids: [...associatedRefreshJobs],
|
|
236
|
+
error,
|
|
237
|
+
});
|
|
238
|
+
associatedRefreshJobs.clear();
|
|
239
|
+
throw error;
|
|
240
|
+
})
|
|
241
|
+
.finally(() => {
|
|
242
|
+
projectionRefreshInFlight = null;
|
|
243
|
+
// Preserve a source change that arrived during the bounded catch-up.
|
|
244
|
+
// It starts after the committed generation becomes observable, rather
|
|
245
|
+
// than extending the current `updating` state without bound.
|
|
246
|
+
if (projectionRefreshRequested) {
|
|
247
|
+
projectionRefreshRequested = false;
|
|
248
|
+
// Yield a real event-loop turn with `current` exposed before starting
|
|
249
|
+
// another rebuild. `/ready` can then advertise the committed SQLite
|
|
250
|
+
// generation and open tabs can read it coherently.
|
|
251
|
+
const followUp = setTimeout(() => {
|
|
252
|
+
void rebuildProjection().catch((error: unknown) =>
|
|
253
|
+
projectionRefreshDiagnostics.record({ trigger: "source_change", error }),
|
|
254
|
+
);
|
|
255
|
+
}, 250);
|
|
256
|
+
followUp.unref();
|
|
257
|
+
}
|
|
258
|
+
});
|
|
238
259
|
return projectionRefreshInFlight;
|
|
239
260
|
};
|
|
240
|
-
|
|
241
|
-
workspaceRoot,
|
|
242
|
-
discoverSourceRoots: () => dashboardCanonicalSourceRoots(workspaceRoot),
|
|
243
|
-
staleSeed: isSqliteSnapshot && snapshotState === "updating",
|
|
244
|
-
watchSources: isSqliteSnapshot && options.watchSources === true,
|
|
261
|
+
const telemetryRefresh = createTelemetryProjectionRefresh({
|
|
245
262
|
refresh: rebuildProjection,
|
|
246
|
-
...(
|
|
247
|
-
? {
|
|
248
|
-
:
|
|
249
|
-
|
|
263
|
+
...(options.captureTelemetry !== undefined
|
|
264
|
+
? { capture: options.captureTelemetry }
|
|
265
|
+
: isSqliteSnapshot &&
|
|
266
|
+
options.watchSources === true &&
|
|
267
|
+
process.env.ZAIP_DASHBOARD_WATCH_SOURCES !== "0"
|
|
268
|
+
? { capture: () => captureRepositoryActiveCodexTelemetry(workspaceRoot) }
|
|
269
|
+
: {}),
|
|
250
270
|
onCaptureSuccess: (result) => {
|
|
251
271
|
activeCapture = result;
|
|
252
272
|
activeCaptureFailure = null;
|
|
@@ -259,12 +279,29 @@ export function createDashboardApp(
|
|
|
259
279
|
};
|
|
260
280
|
},
|
|
261
281
|
});
|
|
262
|
-
const
|
|
263
|
-
|
|
282
|
+
const visibleSnapshotState = () =>
|
|
283
|
+
telemetryRefresh.pending || activeCaptureFailure !== null ? "updating" : snapshotState;
|
|
284
|
+
startSnapshotSynchronization({
|
|
285
|
+
workspaceRoot,
|
|
286
|
+
discoverSourceRoots: () => dashboardCanonicalSourceRoots(workspaceRoot),
|
|
287
|
+
staleSeed: isSqliteSnapshot && snapshotState === "updating",
|
|
288
|
+
watchSources: isSqliteSnapshot && options.watchSources === true,
|
|
289
|
+
refresh: rebuildProjection,
|
|
290
|
+
synchronizeTelemetry: telemetryRefresh.refresh,
|
|
291
|
+
onRefreshFailure: projectionRefreshDiagnostics.record,
|
|
292
|
+
});
|
|
293
|
+
const reconcileWork = createLoggedWorkReconciliation({
|
|
294
|
+
diagnostics,
|
|
295
|
+
reconcile: (mode, jobId) =>
|
|
264
296
|
reconcileOpen(canonicalFilesystem, workspaceRoot, {
|
|
265
297
|
hostTerminalOnly: mode === "host-terminal",
|
|
298
|
+
jobId,
|
|
266
299
|
}),
|
|
267
|
-
|
|
300
|
+
snapshotTimes: () => ({
|
|
301
|
+
projection_updated_at: isSqliteSnapshot ? filesystem.projectionUpdatedAt() : null,
|
|
302
|
+
latest_token_collected_at: isSqliteSnapshot ? filesystem.latestTokenCollectedAt() : null,
|
|
303
|
+
}),
|
|
304
|
+
refresh: (jobId) => rebuildProjection(jobId),
|
|
268
305
|
});
|
|
269
306
|
// Terminal usage is persisted by the host/CLI lifecycle boundary. The
|
|
270
307
|
// source synchronizer above projects those records, but the Dashboard must
|
|
@@ -331,7 +368,9 @@ export function createDashboardApp(
|
|
|
331
368
|
const browserLeaseWrite =
|
|
332
369
|
context.req.method === "GET" && context.req.path === `${API_PREFIX}/browser-lease`;
|
|
333
370
|
const projectionRefreshWrite =
|
|
334
|
-
context.req.method === "POST" &&
|
|
371
|
+
context.req.method === "POST" &&
|
|
372
|
+
(context.req.path === `${API_PREFIX}/refresh-projection` ||
|
|
373
|
+
context.req.path === `${API_PREFIX}/capture-telemetry`);
|
|
335
374
|
if (
|
|
336
375
|
context.req.method !== "GET" &&
|
|
337
376
|
context.req.method !== "HEAD" &&
|
|
@@ -350,7 +389,8 @@ export function createDashboardApp(
|
|
|
350
389
|
? "GET, HEAD, PUT"
|
|
351
390
|
: context.req.path === `${API_PREFIX}/reconcile-open-work`
|
|
352
391
|
? "POST"
|
|
353
|
-
: context.req.path === `${API_PREFIX}/refresh-projection`
|
|
392
|
+
: context.req.path === `${API_PREFIX}/refresh-projection` ||
|
|
393
|
+
context.req.path === `${API_PREFIX}/capture-telemetry`
|
|
354
394
|
? "POST"
|
|
355
395
|
: "GET, HEAD",
|
|
356
396
|
);
|
|
@@ -408,7 +448,7 @@ export function createDashboardApp(
|
|
|
408
448
|
lifecycle_manifest_state: manifestState,
|
|
409
449
|
read_only: true,
|
|
410
450
|
storage: isSqliteSnapshot ? filesystem.metadata() : { storage_mode: "filesystem" },
|
|
411
|
-
snapshot_state:
|
|
451
|
+
snapshot_state: visibleSnapshotState(),
|
|
412
452
|
projection_refresh_failure: projectionRefreshDiagnostics.failure,
|
|
413
453
|
active_capture_failure: activeCaptureFailure,
|
|
414
454
|
active_capture: activeCapture,
|
|
@@ -468,11 +508,13 @@ export function createDashboardApp(
|
|
|
468
508
|
// monthly Operations projection was materialized during rebuild;
|
|
469
509
|
// /ready must never start a competing projection in the background.
|
|
470
510
|
day_count: metadata.daily_aggregate_count,
|
|
471
|
-
snapshot_state:
|
|
511
|
+
snapshot_state: visibleSnapshotState(),
|
|
472
512
|
projection_refresh_failure: projectionRefreshDiagnostics.failure,
|
|
473
513
|
active_capture_failure: activeCaptureFailure,
|
|
474
514
|
active_capture: activeCapture,
|
|
475
515
|
snapshot_revision: revision,
|
|
516
|
+
projection_updated_at: filesystem.projectionUpdatedAt(),
|
|
517
|
+
latest_token_collected_at: filesystem.latestTokenCollectedAt(),
|
|
476
518
|
});
|
|
477
519
|
}
|
|
478
520
|
const projection = await buildFirstFoldQuickProjection(filesystem, layout, {
|
|
@@ -518,48 +560,43 @@ export function createDashboardApp(
|
|
|
518
560
|
readAggregate,
|
|
519
561
|
clearSnapshotCache,
|
|
520
562
|
});
|
|
521
|
-
app
|
|
563
|
+
registerReconciliationRoute(app, {
|
|
564
|
+
readLayout,
|
|
565
|
+
diagnostics,
|
|
566
|
+
reconcileWork,
|
|
567
|
+
refresh: (jobId) => rebuildProjection(jobId),
|
|
568
|
+
snapshotState: visibleSnapshotState,
|
|
569
|
+
refreshCompleted: () =>
|
|
570
|
+
visibleSnapshotState() === "current" && projectionRefreshInFlight === null,
|
|
571
|
+
});
|
|
572
|
+
app.post(`${API_PREFIX}/refresh-projection`, async (context) => {
|
|
522
573
|
try {
|
|
523
574
|
await readLayout();
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
const reconciledIds = await waitForWorkReconciliation(reconcileWork("manual"), () => {
|
|
527
|
-
void rebuildProjection().catch(() => undefined);
|
|
528
|
-
});
|
|
529
|
-
return context.json({
|
|
530
|
-
reconciliation: reconciledIds,
|
|
531
|
-
snapshot_state: snapshotState,
|
|
532
|
-
projection_refresh_completed:
|
|
533
|
-
snapshotState === "current" && projectionRefreshInFlight === null,
|
|
534
|
-
});
|
|
535
|
-
} catch (error) {
|
|
536
|
-
if (error instanceof V2WorkspaceRequiredError) throw error;
|
|
537
|
-
if (error instanceof ReconciliationCommandTimeoutError) {
|
|
538
|
-
// SIGTERM can occur after the CLI persisted some records. Start an
|
|
539
|
-
// atomic refresh without extending the request past the client's
|
|
540
|
-
// deadline, and make that uncertainty explicit to the caller.
|
|
575
|
+
await telemetryRefresh.refresh(true);
|
|
576
|
+
if (activeCaptureFailure !== null)
|
|
541
577
|
return context.json(
|
|
542
578
|
{
|
|
543
|
-
error:
|
|
544
|
-
|
|
545
|
-
|
|
579
|
+
error: "Telemetry capture is unavailable",
|
|
580
|
+
snapshot_state: visibleSnapshotState(),
|
|
581
|
+
active_capture_failure: activeCaptureFailure,
|
|
546
582
|
},
|
|
547
|
-
|
|
583
|
+
503,
|
|
548
584
|
);
|
|
549
|
-
}
|
|
550
|
-
return context.json({ error: error instanceof Error ? error.message : String(error) }, 400);
|
|
551
|
-
}
|
|
552
|
-
});
|
|
553
|
-
app.post(`${API_PREFIX}/refresh-projection`, async (context) => {
|
|
554
|
-
try {
|
|
555
|
-
await readLayout();
|
|
556
|
-
await rebuildProjection();
|
|
557
585
|
return context.json(await readSnapshot(context));
|
|
558
586
|
} catch (error) {
|
|
559
587
|
if (error instanceof V2WorkspaceRequiredError) throw error;
|
|
560
588
|
return context.json({ error: error instanceof Error ? error.message : String(error) }, 400);
|
|
561
589
|
}
|
|
562
590
|
});
|
|
591
|
+
app.post(`${API_PREFIX}/capture-telemetry`, async (context) => {
|
|
592
|
+
await readLayout();
|
|
593
|
+
void telemetryRefresh
|
|
594
|
+
.refresh()
|
|
595
|
+
.catch((error: unknown) =>
|
|
596
|
+
projectionRefreshDiagnostics.record({ trigger: "source_change", error }),
|
|
597
|
+
);
|
|
598
|
+
return context.json({ snapshot_state: visibleSnapshotState() }, 202);
|
|
599
|
+
});
|
|
563
600
|
registerCostsRoutes(app, {
|
|
564
601
|
filesystem,
|
|
565
602
|
canonicalFilesystem,
|
|
@@ -599,56 +636,11 @@ export function createDashboardApp(
|
|
|
599
636
|
clearSnapshotCache();
|
|
600
637
|
return context.json(rate);
|
|
601
638
|
});
|
|
602
|
-
app
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
context,
|
|
608
|
-
{ error: error instanceof Error ? error.message : String(error) },
|
|
609
|
-
400,
|
|
610
|
-
);
|
|
611
|
-
}
|
|
612
|
-
});
|
|
613
|
-
app.get(`${API_PREFIX}/agent-catalog-assets/:agentId`, async (context) => {
|
|
614
|
-
const portrait = agentPortraitFiles[context.req.param("agentId")];
|
|
615
|
-
if (portrait === undefined) return context.json({ error: "Agent portrait not found" }, 404);
|
|
616
|
-
try {
|
|
617
|
-
return context.body(
|
|
618
|
-
await readFile(resolve(workspaceRoot, ".agents/config/src", portrait)),
|
|
619
|
-
200,
|
|
620
|
-
{ "cache-control": "no-store", "content-type": "image/png" },
|
|
621
|
-
);
|
|
622
|
-
} catch (error) {
|
|
623
|
-
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
|
624
|
-
return context.json({ error: "Agent portrait not found" }, 404);
|
|
625
|
-
}
|
|
626
|
-
return context.json({ error: "Agent portrait could not be read" }, 500);
|
|
627
|
-
}
|
|
628
|
-
});
|
|
629
|
-
app.put(`${API_PREFIX}/agent-catalog`, async (context) => {
|
|
630
|
-
const update = async () => {
|
|
631
|
-
try {
|
|
632
|
-
const persisted = await persistAgentCatalogUpdate(
|
|
633
|
-
filesystem,
|
|
634
|
-
await context.req.json(),
|
|
635
|
-
syncAgentAdapters,
|
|
636
|
-
);
|
|
637
|
-
clearSnapshotCache();
|
|
638
|
-
return context.json(persisted);
|
|
639
|
-
} catch (error) {
|
|
640
|
-
if (error instanceof AgentCatalogUpdateError) {
|
|
641
|
-
return context.json({ error: error.message }, error.status);
|
|
642
|
-
}
|
|
643
|
-
return context.json({ error: "Agent catalog update failed" }, 500);
|
|
644
|
-
}
|
|
645
|
-
};
|
|
646
|
-
const result = catalogWriteTail.then(update, update);
|
|
647
|
-
catalogWriteTail = result.then(
|
|
648
|
-
() => undefined,
|
|
649
|
-
() => undefined,
|
|
650
|
-
);
|
|
651
|
-
return result;
|
|
639
|
+
registerAgentCatalogRoutes(app, {
|
|
640
|
+
filesystem,
|
|
641
|
+
workspaceRoot,
|
|
642
|
+
syncAgentAdapters,
|
|
643
|
+
clearSnapshotCache,
|
|
652
644
|
});
|
|
653
645
|
app.on(["GET", "HEAD"], `${API_PREFIX}/project-settings`, async (context) => {
|
|
654
646
|
try {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { providerVisibleMetricsSql } from "./sqlite-provider-visibility.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Date-only Cost pages can use immutable, indexed activity facts. Any
|
|
3
5
|
* additional filter deliberately falls back to the canonical SQL path, whose
|
|
@@ -181,8 +183,18 @@ export function readDateOnlyCostDimensionPage(
|
|
|
181
183
|
dimension === "model"
|
|
182
184
|
? "COALESCE(task_population.task_count,0) AS task_count,0 AS prd_count,0 AS spec_count,0 AS validation_count,0 AS evidence_count"
|
|
183
185
|
: "COALESCE(task_population.task_count,0) task_count";
|
|
186
|
+
const aggregatedRows = `${cte}, aggregated_rows AS (
|
|
187
|
+
SELECT keys.key,keys.key AS label,COALESCE(population.invocation_count,0) invocation_count,
|
|
188
|
+
${rowProductivity},population.total_duration,population.source_event_count,
|
|
189
|
+
financial.total_tokens,financial.total_cost_usd,financial.total_cost_brl
|
|
190
|
+
FROM keys LEFT JOIN population USING(key) LEFT JOIN task_population USING(key)
|
|
191
|
+
LEFT JOIN financial USING(key)
|
|
192
|
+
), visible_rows AS (SELECT * FROM aggregated_rows${
|
|
193
|
+
dimension === "provider" ? ` WHERE ${providerVisibleMetricsSql}` : ""
|
|
194
|
+
})`;
|
|
184
195
|
const total_count = Number(
|
|
185
|
-
database.prepare(`${
|
|
196
|
+
database.prepare(`${aggregatedRows} SELECT COUNT(*) AS count FROM visible_rows`).get(...args)
|
|
197
|
+
?.count ?? 0,
|
|
186
198
|
);
|
|
187
199
|
const totals =
|
|
188
200
|
database
|
|
@@ -192,7 +204,7 @@ export function readDateOnlyCostDimensionPage(
|
|
|
192
204
|
.get(...args) ?? {};
|
|
193
205
|
const rows = database
|
|
194
206
|
.prepare(
|
|
195
|
-
`${
|
|
207
|
+
`${aggregatedRows} SELECT * FROM visible_rows ORDER BY total_cost_brl DESC,key LIMIT ? OFFSET ?`,
|
|
196
208
|
)
|
|
197
209
|
.all(...args, limit, offset);
|
|
198
210
|
if (dimension === "model") {
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { SqliteQueryContext } from "./sqlite-query-context.js";
|
|
2
|
+
|
|
3
|
+
type DailyElapsed = { known_sum: number; eligible_runs: number; known_runs: number };
|
|
4
|
+
|
|
5
|
+
export function costSummaryElapsedByDay(
|
|
6
|
+
database: SqliteQueryContext["database"],
|
|
7
|
+
from: string | null,
|
|
8
|
+
to: string | null,
|
|
9
|
+
): Map<string, DailyElapsed> {
|
|
10
|
+
const rows = database
|
|
11
|
+
.prepare(`SELECT day, cost_monitor_total_duration AS duration_ms,
|
|
12
|
+
cost_monitor_duration_eligible_runs AS eligible_runs,
|
|
13
|
+
cost_monitor_duration_known_runs AS known_runs
|
|
14
|
+
FROM zaip_vw_daily_aggregates
|
|
15
|
+
WHERE (? IS NULL OR day >= ?) AND (? IS NULL OR day <= ?)`)
|
|
16
|
+
.all(from, from, to, to) as Array<Record<string, unknown>>;
|
|
17
|
+
const result = new Map<string, DailyElapsed>();
|
|
18
|
+
for (const row of rows) {
|
|
19
|
+
const eligible = Number(row.eligible_runs ?? 0);
|
|
20
|
+
if (typeof row.duration_ms !== "number" && eligible === 0) continue;
|
|
21
|
+
result.set(String(row.day), {
|
|
22
|
+
known_sum: typeof row.duration_ms === "number" ? row.duration_ms : 0,
|
|
23
|
+
eligible_runs: eligible,
|
|
24
|
+
known_runs: Number(row.known_runs ?? 0),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Apply dimension filters before unioning observed source intervals by local day. */
|
|
31
|
+
export function filteredCostSummaryElapsedByDay(
|
|
32
|
+
database: SqliteQueryContext["database"],
|
|
33
|
+
from: string | null,
|
|
34
|
+
to: string | null,
|
|
35
|
+
dimensionClauses: readonly string[],
|
|
36
|
+
dimensionValues: readonly (string | number | null)[],
|
|
37
|
+
): Map<string, DailyElapsed> {
|
|
38
|
+
const rows = database
|
|
39
|
+
.prepare(`SELECT a.activity_row_id AS id, a.source_started_at AS started_at,
|
|
40
|
+
a.source_finished_at AS finished_at, a.source_occurred_at AS source_at,
|
|
41
|
+
a.occurred_at AS occurred_at
|
|
42
|
+
FROM activities a
|
|
43
|
+
WHERE (a.total_tokens IS NOT NULL OR a.cost_usd IS NOT NULL OR a.cost_brl IS NOT NULL)
|
|
44
|
+
${dimensionClauses.map((clause) => `AND ${clause}`).join("\n")}`)
|
|
45
|
+
.all(...dimensionValues) as Array<{
|
|
46
|
+
id: number;
|
|
47
|
+
started_at: string | null;
|
|
48
|
+
finished_at: string | null;
|
|
49
|
+
source_at: string | null;
|
|
50
|
+
occurred_at: string | null;
|
|
51
|
+
}>;
|
|
52
|
+
const threeHours = 3 * 60 * 60 * 1000;
|
|
53
|
+
const localDay = (ms: number) => new Date(ms - threeHours).toISOString().slice(0, 10);
|
|
54
|
+
const inRange = (day: string) => (from === null || day >= from) && (to === null || day <= to);
|
|
55
|
+
const byDay = new Map<
|
|
56
|
+
string,
|
|
57
|
+
{ intervals: Array<[number, number]>; eligible: Set<number>; known: Set<number> }
|
|
58
|
+
>();
|
|
59
|
+
const bucket = (day: string) => {
|
|
60
|
+
let value = byDay.get(day);
|
|
61
|
+
if (value === undefined) {
|
|
62
|
+
value = { intervals: [], eligible: new Set(), known: new Set() };
|
|
63
|
+
byDay.set(day, value);
|
|
64
|
+
}
|
|
65
|
+
return value;
|
|
66
|
+
};
|
|
67
|
+
for (const row of rows) {
|
|
68
|
+
const start = row.started_at === null ? Number.NaN : Date.parse(row.started_at);
|
|
69
|
+
const end = row.finished_at === null ? Number.NaN : Date.parse(row.finished_at);
|
|
70
|
+
if (Number.isFinite(start) && Number.isFinite(end) && end > start) {
|
|
71
|
+
for (let segmentStart = start; segmentStart < end; ) {
|
|
72
|
+
const day = localDay(segmentStart);
|
|
73
|
+
const segmentEnd = Math.min(end, Date.parse(`${day}T03:00:00.000Z`) + 86_400_000);
|
|
74
|
+
if (inRange(day)) {
|
|
75
|
+
const value = bucket(day);
|
|
76
|
+
value.intervals.push([segmentStart, segmentEnd]);
|
|
77
|
+
value.eligible.add(row.id);
|
|
78
|
+
value.known.add(row.id);
|
|
79
|
+
}
|
|
80
|
+
segmentStart = segmentEnd;
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
const occurred = row.started_at ?? row.source_at ?? row.occurred_at;
|
|
84
|
+
if (occurred === null) continue;
|
|
85
|
+
const occurredMs = Date.parse(occurred);
|
|
86
|
+
if (!Number.isFinite(occurredMs)) continue;
|
|
87
|
+
const day = localDay(occurredMs);
|
|
88
|
+
if (inRange(day)) bucket(day).eligible.add(row.id);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const result = new Map<string, DailyElapsed>();
|
|
92
|
+
for (const [day, value] of byDay) {
|
|
93
|
+
const sorted = value.intervals.sort((a, b) => a[0] - b[0]);
|
|
94
|
+
let total = 0;
|
|
95
|
+
let mergedEnd = Number.NEGATIVE_INFINITY;
|
|
96
|
+
for (const [start, end] of sorted) {
|
|
97
|
+
total += Math.max(0, end - Math.max(start, mergedEnd));
|
|
98
|
+
mergedEnd = Math.max(mergedEnd, end);
|
|
99
|
+
}
|
|
100
|
+
result.set(day, {
|
|
101
|
+
known_sum: Math.round(total),
|
|
102
|
+
eligible_runs: value.eligible.size,
|
|
103
|
+
known_runs: value.known.size,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|