@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,5 @@
|
|
|
1
1
|
import { costInvocationProjectionSelect } from "./sqlite-cost-invocation-projection.js";
|
|
2
|
+
import { specRootElapsedViewSql } from "./sqlite-spec-root-elapsed-view.js";
|
|
2
3
|
export const baseViewSql = `
|
|
3
4
|
CREATE INDEX zaip_activities_agent_run ON zaip_aios_activities(activity_source_kind, agent_run_id, occurred_day_sp, occurred_at DESC);
|
|
4
5
|
CREATE INDEX zaip_activities_relationships ON zaip_aios_activities(task_id, spec_id, prd_id, execution_id, conversation_id);
|
|
@@ -55,6 +56,7 @@ export const baseViewSql = `
|
|
|
55
56
|
WHERE allocation.spec_id=a.spec_id AND allocation.run_id=a.run_id
|
|
56
57
|
)
|
|
57
58
|
UNION ALL SELECT * FROM shared_creation_allocations;
|
|
59
|
+
${specRootElapsedViewSql}
|
|
58
60
|
CREATE VIEW attributed_token_active AS
|
|
59
61
|
SELECT f.activity_row_id, f.occurred_day_sp, f.attributed_token_active_ms,
|
|
60
62
|
a.run_id, a.execution_id, a.task_id, a.spec_id, a.prd_id, a.conversation_id,
|
|
@@ -214,11 +216,11 @@ export const baseViewSql = `
|
|
|
214
216
|
SELECT day, interval_group, MIN(start_ms) AS start_ms, MAX(end_ms) AS end_ms
|
|
215
217
|
FROM cost_monitor_grouped_intervals GROUP BY day, interval_group
|
|
216
218
|
), cost_monitor_daily_duration AS (
|
|
217
|
-
--
|
|
218
|
-
--
|
|
219
|
-
--
|
|
220
|
-
SELECT
|
|
221
|
-
FROM
|
|
219
|
+
-- Cost daily duration is factual elapsed time from source intervals.
|
|
220
|
+
-- The union removes root/subrun overlap; token-active allocation
|
|
221
|
+
-- remains a distinct Operations and attribution measure.
|
|
222
|
+
SELECT day, ROUND(SUM(end_ms - start_ms)) AS total_duration
|
|
223
|
+
FROM cost_monitor_merged_intervals GROUP BY day
|
|
222
224
|
), cost_monitor_duration_coverage AS (
|
|
223
225
|
SELECT day, COUNT(DISTINCT activity_id) AS eligible_runs,
|
|
224
226
|
COUNT(DISTINCT activity_id) AS known_runs
|
|
@@ -267,7 +269,7 @@ export const baseViewSql = `
|
|
|
267
269
|
i.total_root_run_duration,
|
|
268
270
|
i.total_sub_run_duration,
|
|
269
271
|
o.total_duration AS operations_total_duration,
|
|
270
|
-
|
|
272
|
+
dcm.total_duration AS cost_monitor_total_duration,
|
|
271
273
|
coverage.eligible_runs AS cost_monitor_duration_eligible_runs,
|
|
272
274
|
coverage.known_runs AS cost_monitor_duration_known_runs,
|
|
273
275
|
o.total_duration AS total_duration,
|
|
@@ -305,7 +307,7 @@ export const baseViewSql = `
|
|
|
305
307
|
-- population rather than Operations' broader Run/activity totals.
|
|
306
308
|
CREATE VIEW cost_monitor_overview AS SELECT period_kind, period_key, cost_monitor_invocation_count AS total_run_count, cost_monitor_invocation_count AS invocation_count, llm_call_count, source_event_count, cost_monitor_total_duration, total_tokens, total_cost_usd, total_cost_brl FROM overview;
|
|
307
309
|
CREATE VIEW task_summary AS SELECT t.id, t.title, t.status, t.risk, t.occurred_at, t.occurred_day_sp, COUNT(i.run_id) AS invocation_count, SUM(i.llm_call_count) AS llm_call_count, SUM(i.duration_ms) AS total_duration, SUM(i.total_tokens) AS total_tokens, SUM(i.cost_usd) AS total_cost_usd, SUM(i.cost_brl) AS total_cost_brl FROM tasks t LEFT JOIN activities i ON i.task_id = t.id GROUP BY t.id, t.title, t.status, t.risk, t.occurred_at, t.occurred_day_sp;
|
|
308
|
-
CREATE VIEW spec_summary AS SELECT s.id, s.title, s.status, s.risk, s.occurred_at, s.occurred_day_sp, COUNT(i.run_id) AS invocation_count, SUM(i.llm_call_count) AS llm_call_count,
|
|
310
|
+
CREATE VIEW spec_summary AS SELECT s.id, s.title, s.status, s.risk, s.occurred_at, s.occurred_day_sp, COUNT(i.run_id) AS invocation_count, SUM(i.llm_call_count) AS llm_call_count, elapsed.total_duration_ms AS total_duration, SUM(i.total_tokens) AS total_tokens, SUM(i.cost_usd) AS total_cost_usd, SUM(i.cost_brl) AS total_cost_brl FROM specs s LEFT JOIN macro_spec_activities i ON i.spec_id = s.id LEFT JOIN spec_root_elapsed elapsed ON elapsed.spec_id=s.id GROUP BY s.id, s.title, s.status, s.risk, s.occurred_at, s.occurred_day_sp;
|
|
309
311
|
CREATE VIEW prd_summary AS SELECT p.id, p.title, p.status, p.risk, p.occurred_at, p.occurred_day_sp, COUNT(i.run_id) AS invocation_count, SUM(i.llm_call_count) AS llm_call_count, SUM(i.duration_ms) AS total_duration, SUM(i.total_tokens) AS total_tokens, SUM(i.cost_usd) AS total_cost_usd, SUM(i.cost_brl) AS total_cost_brl FROM prds p LEFT JOIN activities i ON i.prd_id = p.id GROUP BY p.id, p.title, p.status, p.risk, p.occurred_at, p.occurred_day_sp;
|
|
310
312
|
CREATE VIEW cost_monitor_group_daily AS SELECT * FROM cost_monitor_group_daily_cache;
|
|
311
313
|
CREATE VIEW vw_overview AS SELECT * FROM overview;
|
package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-schema-dashboard-views.ts
CHANGED
|
@@ -51,7 +51,9 @@ export const dashboardViewSql = ` CREATE VIEW vw_operations_work_list AS
|
|
|
51
51
|
FROM entity_activity GROUP BY entity_kind, entity_id
|
|
52
52
|
), durations AS (
|
|
53
53
|
SELECT entity_kind, entity_id, ROUND(SUM(duration_ms)) AS total_duration
|
|
54
|
-
FROM entity_activity GROUP BY entity_kind, entity_id
|
|
54
|
+
FROM entity_activity WHERE entity_kind <> 'spec' GROUP BY entity_kind, entity_id
|
|
55
|
+
UNION ALL
|
|
56
|
+
SELECT 'spec', spec_id, total_duration_ms FROM spec_root_elapsed
|
|
55
57
|
)
|
|
56
58
|
SELECT w.entity_kind, w.id, w.title, w.status, w.risk, w.occurred_at, w.occurred_day_sp,
|
|
57
59
|
f.invocation_count, f.llm_call_count, d.total_duration,
|
|
@@ -231,7 +233,6 @@ export const dashboardViewSql = ` CREATE VIEW vw_operations_work_list AS
|
|
|
231
233
|
WITH usage AS (
|
|
232
234
|
SELECT spec_id,
|
|
233
235
|
COUNT(*) AS total_run_count,
|
|
234
|
-
ROUND(SUM(duration_ms)) AS total_duration_ms,
|
|
235
236
|
SUM(total_tokens) AS total_tokens,
|
|
236
237
|
SUM(cost_usd) AS total_cost_usd,
|
|
237
238
|
SUM(cost_brl) AS total_cost_brl
|
|
@@ -239,16 +240,17 @@ export const dashboardViewSql = ` CREATE VIEW vw_operations_work_list AS
|
|
|
239
240
|
)
|
|
240
241
|
SELECT COUNT(*) AS entity_count,
|
|
241
242
|
SUM(usage.total_run_count) AS total_run_count,
|
|
242
|
-
SUM(
|
|
243
|
+
SUM(elapsed.total_duration_ms) AS total_duration_ms,
|
|
243
244
|
SUM(usage.total_tokens) AS total_tokens,
|
|
244
245
|
SUM(usage.total_cost_usd) AS total_cost_usd,
|
|
245
246
|
SUM(usage.total_cost_brl) AS total_cost_brl,
|
|
246
|
-
CASE WHEN COUNT(*)=0 THEN NULL ELSE SUM(
|
|
247
|
+
CASE WHEN COUNT(*)=0 THEN NULL ELSE SUM(elapsed.total_duration_ms)/COUNT(*) END AS average_duration_ms,
|
|
247
248
|
CASE WHEN COUNT(*)=0 THEN NULL ELSE SUM(usage.total_tokens)/COUNT(*) END AS average_tokens,
|
|
248
249
|
CASE WHEN COUNT(*)=0 THEN NULL ELSE SUM(usage.total_cost_usd)/COUNT(*) END AS average_cost_usd,
|
|
249
250
|
CASE WHEN COUNT(*)=0 THEN NULL ELSE SUM(usage.total_cost_brl)/COUNT(*) END AS average_cost_brl,
|
|
250
251
|
MAX(s.occurred_at) AS latest_created_at
|
|
251
|
-
FROM spec_summary s LEFT JOIN usage ON usage.spec_id=s.id
|
|
252
|
+
FROM spec_summary s LEFT JOIN usage ON usage.spec_id=s.id
|
|
253
|
+
LEFT JOIN spec_root_elapsed elapsed ON elapsed.spec_id=s.id;
|
|
252
254
|
CREATE VIEW vw_first_fold_prd_metrics_all_time AS
|
|
253
255
|
WITH usage AS (
|
|
254
256
|
SELECT prd_id,
|
|
@@ -276,16 +278,16 @@ export const dashboardViewSql = ` CREATE VIEW vw_operations_work_list AS
|
|
|
276
278
|
SELECT spec_id,
|
|
277
279
|
COUNT(*) AS total_run_count,
|
|
278
280
|
SUM(llm_call_count) AS llm_call_count,
|
|
279
|
-
ROUND(SUM(duration_ms)) AS total_duration_ms,
|
|
280
281
|
SUM(total_tokens) AS total_tokens,
|
|
281
282
|
SUM(cost_usd) AS total_cost_usd,
|
|
282
283
|
SUM(cost_brl) AS total_cost_brl
|
|
283
284
|
FROM macro_spec_activities GROUP BY spec_id
|
|
284
285
|
), ranked AS (
|
|
285
286
|
SELECT s.id AS entity_id, s.title, s.status, usage.total_run_count, usage.llm_call_count,
|
|
286
|
-
|
|
287
|
-
ROW_NUMBER() OVER (ORDER BY
|
|
287
|
+
elapsed.total_duration_ms, usage.total_tokens, usage.total_cost_usd, usage.total_cost_brl,
|
|
288
|
+
ROW_NUMBER() OVER (ORDER BY elapsed.total_duration_ms IS NOT NULL DESC, elapsed.total_duration_ms DESC, usage.total_run_count DESC, s.id) AS rank
|
|
288
289
|
FROM spec_summary s LEFT JOIN usage ON usage.spec_id=s.id
|
|
290
|
+
LEFT JOIN spec_root_elapsed elapsed ON elapsed.spec_id=s.id
|
|
289
291
|
), total AS (SELECT SUM(total_duration_ms) AS total_duration_ms FROM ranked)
|
|
290
292
|
SELECT ranked.rank, ranked.entity_id, ranked.title, ranked.status,
|
|
291
293
|
COALESCE(ranked.total_run_count,0) AS total_run_count, ranked.llm_call_count,
|
package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-spec-root-elapsed-view.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPEC elapsed time is the union of factual root Run intervals within each
|
|
3
|
+
* SPEC. A root and its children must not both contribute elapsed time. A Run
|
|
4
|
+
* linked to two SPECs remains visible in each; the cross-SPEC sum is therefore
|
|
5
|
+
* a sum of entity durations, not a global wall-clock total.
|
|
6
|
+
*/
|
|
7
|
+
export const specRootElapsedViewSql = `
|
|
8
|
+
CREATE VIEW spec_root_elapsed AS
|
|
9
|
+
WITH roots AS (
|
|
10
|
+
SELECT spec_id, run_id,
|
|
11
|
+
MAX(source_duration_ms) AS source_duration_ms,
|
|
12
|
+
MIN(source_started_at) AS source_started_at,
|
|
13
|
+
MAX(source_finished_at) AS source_finished_at
|
|
14
|
+
FROM macro_spec_activities
|
|
15
|
+
WHERE spec_id IS NOT NULL AND run_role='root'
|
|
16
|
+
GROUP BY spec_id, run_id
|
|
17
|
+
), source_intervals AS (
|
|
18
|
+
SELECT spec_id,
|
|
19
|
+
(julianday(source_started_at) - 2440587.5) * 86400000.0 AS start_ms,
|
|
20
|
+
(julianday(source_finished_at) - 2440587.5) * 86400000.0 AS end_ms
|
|
21
|
+
FROM roots
|
|
22
|
+
WHERE source_started_at IS NOT NULL AND source_finished_at IS NOT NULL
|
|
23
|
+
AND julianday(source_finished_at) > julianday(source_started_at)
|
|
24
|
+
), ordered AS (
|
|
25
|
+
SELECT spec_id, start_ms, end_ms,
|
|
26
|
+
MAX(end_ms) OVER (
|
|
27
|
+
PARTITION BY spec_id ORDER BY start_ms, end_ms
|
|
28
|
+
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
|
|
29
|
+
) AS prior_end_ms
|
|
30
|
+
FROM source_intervals
|
|
31
|
+
), grouped AS (
|
|
32
|
+
SELECT spec_id, start_ms, end_ms,
|
|
33
|
+
SUM(CASE WHEN prior_end_ms IS NULL OR start_ms > prior_end_ms THEN 1 ELSE 0 END)
|
|
34
|
+
OVER (PARTITION BY spec_id ORDER BY start_ms, end_ms) AS interval_group
|
|
35
|
+
FROM ordered
|
|
36
|
+
), merged AS (
|
|
37
|
+
SELECT spec_id, interval_group, MIN(start_ms) AS start_ms, MAX(end_ms) AS end_ms
|
|
38
|
+
FROM grouped GROUP BY spec_id, interval_group
|
|
39
|
+
), source_totals AS (
|
|
40
|
+
SELECT spec_id, SUM(end_ms - start_ms) AS duration_ms
|
|
41
|
+
FROM merged GROUP BY spec_id
|
|
42
|
+
), fallback_totals AS (
|
|
43
|
+
-- A terminal factual duration without source boundaries remains
|
|
44
|
+
-- available, but cannot be unioned against another Run interval.
|
|
45
|
+
SELECT spec_id, SUM(source_duration_ms) AS duration_ms
|
|
46
|
+
FROM roots
|
|
47
|
+
WHERE source_duration_ms IS NOT NULL
|
|
48
|
+
AND NOT (
|
|
49
|
+
source_started_at IS NOT NULL AND source_finished_at IS NOT NULL
|
|
50
|
+
AND julianday(source_finished_at) > julianday(source_started_at)
|
|
51
|
+
)
|
|
52
|
+
GROUP BY spec_id
|
|
53
|
+
), known_specs AS (
|
|
54
|
+
SELECT spec_id FROM source_totals UNION SELECT spec_id FROM fallback_totals
|
|
55
|
+
)
|
|
56
|
+
SELECT known_specs.spec_id,
|
|
57
|
+
ROUND(COALESCE(source_totals.duration_ms, 0) + COALESCE(fallback_totals.duration_ms, 0)) AS total_duration_ms
|
|
58
|
+
FROM known_specs
|
|
59
|
+
LEFT JOIN source_totals USING(spec_id)
|
|
60
|
+
LEFT JOIN fallback_totals USING(spec_id);
|
|
61
|
+
`;
|
package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-spec-root-elapsed.test.ts
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { DatabaseSync } from "node:sqlite";
|
|
4
|
+
import { afterEach, expect, it } from "vitest";
|
|
5
|
+
import { rebuildSqliteReadModel, SqliteReadModelFileSystem } from "./sqlite-read-model.js";
|
|
6
|
+
|
|
7
|
+
const roots: string[] = [];
|
|
8
|
+
afterEach(async () => {
|
|
9
|
+
await Promise.all(
|
|
10
|
+
roots
|
|
11
|
+
.splice(0)
|
|
12
|
+
.map((root) =>
|
|
13
|
+
import("node:fs/promises").then(({ rm }) => rm(root, { recursive: true, force: true })),
|
|
14
|
+
),
|
|
15
|
+
);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("shows a 21-hour source-observed SPEC root and splits Cost elapsed without child double counting", async () => {
|
|
19
|
+
const temp = resolve(import.meta.dirname, "../../../../../..", ".tmp", "sqlite-read-model-tests");
|
|
20
|
+
await mkdir(temp, { recursive: true });
|
|
21
|
+
const root = await mkdtemp(join(temp, "spec-elapsed-"));
|
|
22
|
+
roots.push(root);
|
|
23
|
+
const records = join(root, ".agents", "records");
|
|
24
|
+
await mkdir(join(records, "runs", "2026", "09"), { recursive: true });
|
|
25
|
+
await mkdir(join(records, "specs", "2026", "09"), { recursive: true });
|
|
26
|
+
await mkdir(join(root, ".agents", "config"), { recursive: true });
|
|
27
|
+
await writeFile(join(root, ".agents", "config", "project.yaml"), "zaip:\n enabled: true\n");
|
|
28
|
+
for (const id of ["SPEC-ROOT", "SPEC-CHILD"])
|
|
29
|
+
await writeFile(
|
|
30
|
+
join(records, "specs", "2026", "09", `${id}.md`),
|
|
31
|
+
`---\nid: ${id}\ntitle: ${id}\nstatus: active\nrisk: standard\ncreated_at: 2026-09-30T22:00:00.000Z\n---\n# ${id}\n`,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const sourceStart = "2026-09-30T22:41:41.072Z";
|
|
35
|
+
const sourceEnd = "2026-10-01T19:55:46.569Z";
|
|
36
|
+
const run = (id: string, specId: string, start: string, end: string, parent: string | null) => {
|
|
37
|
+
const invocation = `AINV-${id}`;
|
|
38
|
+
return [
|
|
39
|
+
{
|
|
40
|
+
schema_version: 2,
|
|
41
|
+
event_id: `${id}:1`,
|
|
42
|
+
run_id: id,
|
|
43
|
+
sequence: 1,
|
|
44
|
+
occurred_at: start,
|
|
45
|
+
type: "run.started",
|
|
46
|
+
attribution_status: "attributed",
|
|
47
|
+
phase: "execution",
|
|
48
|
+
run_role: parent === null ? "orchestrator" : "subagent",
|
|
49
|
+
run_purpose: "execution",
|
|
50
|
+
requires_finalizer: false,
|
|
51
|
+
execution_kind: "delivery",
|
|
52
|
+
execution_eligibility: ["delivery"],
|
|
53
|
+
entrypoint: "spec",
|
|
54
|
+
work_type: "new",
|
|
55
|
+
storage_mode: "tracked_sanitized",
|
|
56
|
+
client: "codex",
|
|
57
|
+
agent: "agent",
|
|
58
|
+
agent_name: "agent",
|
|
59
|
+
provider: "openai",
|
|
60
|
+
model: "gpt-6-sol",
|
|
61
|
+
reasoning_effort: null,
|
|
62
|
+
client_thread_id: `thread-${id}`,
|
|
63
|
+
client_turn_id: `turn-${id}`,
|
|
64
|
+
conversation_id: "CONV-SPEC",
|
|
65
|
+
execution_id: "EXEC-SPEC",
|
|
66
|
+
task_id: null,
|
|
67
|
+
spec_id: specId,
|
|
68
|
+
prd_id: null,
|
|
69
|
+
change_id: null,
|
|
70
|
+
parent_run_id: parent,
|
|
71
|
+
continuation_of_run_id: null,
|
|
72
|
+
retry_of_run_id: null,
|
|
73
|
+
agent_invocation_id: invocation,
|
|
74
|
+
root_agent_invocation_id: parent === null ? invocation : "AINV-RUN-ROOT",
|
|
75
|
+
parent_agent_invocation_id: parent === null ? null : "AINV-RUN-ROOT",
|
|
76
|
+
invocation_kind: parent === null ? "orchestrator" : "delegated",
|
|
77
|
+
delegation_depth: parent === null ? 0 : 1,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
schema_version: 2,
|
|
81
|
+
event_id: `${id}:2`,
|
|
82
|
+
run_id: id,
|
|
83
|
+
sequence: 2,
|
|
84
|
+
occurred_at: end,
|
|
85
|
+
type: "usage.recorded",
|
|
86
|
+
phase: "execution",
|
|
87
|
+
activity_kind: "model_usage",
|
|
88
|
+
classification_source: "explicit",
|
|
89
|
+
tokens: {
|
|
90
|
+
input: 100,
|
|
91
|
+
cached_input: 0,
|
|
92
|
+
output: 20,
|
|
93
|
+
reasoning: 0,
|
|
94
|
+
total: 120,
|
|
95
|
+
source: "provider_reported",
|
|
96
|
+
},
|
|
97
|
+
cost: { usd: 1, brl: 5, fx_rate: 5 },
|
|
98
|
+
provider: "openai",
|
|
99
|
+
model: "gpt-6-sol",
|
|
100
|
+
source_segment_key: id,
|
|
101
|
+
model_call_id: `MCALL-${id}`,
|
|
102
|
+
runtime: { reasoning_effort: null, service_tier: null },
|
|
103
|
+
supersedes_event_id: null,
|
|
104
|
+
source_occurred_at: end,
|
|
105
|
+
source_started_at: start,
|
|
106
|
+
source_finished_at: end,
|
|
107
|
+
duration_ms: null,
|
|
108
|
+
duration_provenance: null,
|
|
109
|
+
},
|
|
110
|
+
];
|
|
111
|
+
};
|
|
112
|
+
for (const [id, specId, start, end, parent] of [
|
|
113
|
+
["RUN-ROOT", "SPEC-ROOT", sourceStart, sourceEnd, null],
|
|
114
|
+
["RUN-OVERLAP", "SPEC-ROOT", "2026-10-01T04:30:00.000Z", "2026-10-01T05:30:00.000Z", null],
|
|
115
|
+
["RUN-CHILD", "SPEC-CHILD", "2026-10-01T04:00:00.000Z", "2026-10-01T05:00:00.000Z", "RUN-ROOT"],
|
|
116
|
+
["RUN-UNKNOWN", "SPEC-CHILD", "2026-10-02T12:00:00.000Z", "2026-10-02T12:00:00.000Z", null],
|
|
117
|
+
] as const)
|
|
118
|
+
await writeFile(
|
|
119
|
+
join(records, "runs", "2026", "09", `${id}.jsonl`),
|
|
120
|
+
`${run(id, specId, start, end, parent)
|
|
121
|
+
.map((event) => JSON.stringify(event))
|
|
122
|
+
.join("\n")}\n`,
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
await rebuildSqliteReadModel(root);
|
|
126
|
+
const db = new DatabaseSync(resolve(root, ".local/sqlite/zaip-aios-dashboard.sqlite"), {
|
|
127
|
+
readOnly: true,
|
|
128
|
+
});
|
|
129
|
+
const observed = Date.parse(sourceEnd) - Date.parse(sourceStart);
|
|
130
|
+
expect(observed).toBe(76_445_497);
|
|
131
|
+
expect(
|
|
132
|
+
db.prepare("SELECT source_duration_ms FROM zaip_aios_activities WHERE run_id='RUN-ROOT'").get(),
|
|
133
|
+
).toEqual({ source_duration_ms: observed });
|
|
134
|
+
expect(
|
|
135
|
+
db
|
|
136
|
+
.prepare("SELECT spec_id, total_duration_ms FROM zaip_vw_spec_root_elapsed ORDER BY spec_id")
|
|
137
|
+
.all(),
|
|
138
|
+
).toEqual([{ spec_id: "SPEC-ROOT", total_duration_ms: observed }]);
|
|
139
|
+
expect(
|
|
140
|
+
db
|
|
141
|
+
.prepare(
|
|
142
|
+
"SELECT entity_id, total_duration_ms FROM zaip_vw_first_fold_top_specs_all_time ORDER BY rank LIMIT 1",
|
|
143
|
+
)
|
|
144
|
+
.get(),
|
|
145
|
+
).toEqual({ entity_id: "SPEC-ROOT", total_duration_ms: observed });
|
|
146
|
+
expect(
|
|
147
|
+
db.prepare("SELECT total_duration_ms FROM zaip_vw_first_fold_spec_metrics_all_time").get(),
|
|
148
|
+
).toEqual({ total_duration_ms: observed });
|
|
149
|
+
expect(
|
|
150
|
+
db
|
|
151
|
+
.prepare("SELECT period_key, total_duration FROM zaip_vw_cost_daily ORDER BY period_key")
|
|
152
|
+
.all(),
|
|
153
|
+
).toEqual([
|
|
154
|
+
{ period_key: "2026-09-30", total_duration: 15_498_928 },
|
|
155
|
+
{ period_key: "2026-10-01", total_duration: 60_946_569 },
|
|
156
|
+
{ period_key: "2026-10-02", total_duration: null },
|
|
157
|
+
]);
|
|
158
|
+
db.close();
|
|
159
|
+
const filesystem = new SqliteReadModelFileSystem(root);
|
|
160
|
+
const allTimeCost = filesystem.costMonitorSummaryAggregate({ from: null, to: null });
|
|
161
|
+
expect(allTimeCost.cost_monitor_daily_duration).toMatchObject({
|
|
162
|
+
"2026-09-30": { known_sum: 15_498_928 },
|
|
163
|
+
"2026-10-01": { known_sum: 60_946_569 },
|
|
164
|
+
"2026-10-02": { known_sum: 0, known_runs: 0, eligible_runs: 1 },
|
|
165
|
+
});
|
|
166
|
+
expect(allTimeCost.daily_rows).toContainEqual(
|
|
167
|
+
expect.objectContaining({ key: "2026-10-02", total_duration: null }),
|
|
168
|
+
);
|
|
169
|
+
const unknownFiltered = filesystem.costMonitorSummaryAggregate({
|
|
170
|
+
from: "2026-10-02",
|
|
171
|
+
to: "2026-10-02",
|
|
172
|
+
specs: ["SPEC-CHILD"],
|
|
173
|
+
});
|
|
174
|
+
expect(unknownFiltered.cost_monitor_daily_duration).toMatchObject({
|
|
175
|
+
"2026-10-02": { known_sum: 0, known_runs: 0, eligible_runs: 1 },
|
|
176
|
+
});
|
|
177
|
+
expect(unknownFiltered.daily_rows).toContainEqual(
|
|
178
|
+
expect.objectContaining({ key: "2026-10-02", total_duration: null }),
|
|
179
|
+
);
|
|
180
|
+
const secondDayCost = filesystem.costMonitorSummaryAggregate({
|
|
181
|
+
from: "2026-10-01",
|
|
182
|
+
to: "2026-10-01",
|
|
183
|
+
});
|
|
184
|
+
expect(secondDayCost.cost_monitor_daily_duration).toMatchObject({
|
|
185
|
+
"2026-10-01": { known_sum: 60_946_569 },
|
|
186
|
+
});
|
|
187
|
+
expect(secondDayCost.cost_monitor_daily_duration).not.toHaveProperty("2026-09-30");
|
|
188
|
+
const filteredCost = filesystem.costMonitorSummaryAggregate({
|
|
189
|
+
from: "2026-10-01",
|
|
190
|
+
to: "2026-10-01",
|
|
191
|
+
specs: ["SPEC-ROOT"],
|
|
192
|
+
});
|
|
193
|
+
expect(filteredCost.cost_monitor_daily_duration).toMatchObject({
|
|
194
|
+
"2026-10-01": { known_sum: 60_946_569 },
|
|
195
|
+
});
|
|
196
|
+
const unknownDay = { from: "2026-10-02", to: "2026-10-02" };
|
|
197
|
+
expect(
|
|
198
|
+
filesystem.costMonitorSummaryAggregate(unknownDay).cost_monitor_daily_duration,
|
|
199
|
+
).toMatchObject({
|
|
200
|
+
"2026-10-02": { known_sum: 0, eligible_runs: 1, known_runs: 0 },
|
|
201
|
+
});
|
|
202
|
+
expect(
|
|
203
|
+
filesystem.costMonitorSummaryAggregate({ ...unknownDay, specs: ["SPEC-CHILD"] })
|
|
204
|
+
.cost_monitor_daily_duration,
|
|
205
|
+
).toMatchObject({ "2026-10-02": { known_sum: 0, eligible_runs: 1, known_runs: 0 } });
|
|
206
|
+
expect(filesystem.summaryPage("spec", { from: null, to: null }, 0, 10).rows).toContainEqual(
|
|
207
|
+
expect.objectContaining({ id: "SPEC-ROOT", total_duration: observed }),
|
|
208
|
+
);
|
|
209
|
+
filesystem.close();
|
|
210
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { DatabaseSync } from "node:sqlite";
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
import { SqliteReadModelFileSystem } from "./sqlite-read-model-filesystem.js";
|
|
6
|
+
import { rebuildSqliteReadModel } from "./sqlite-read-model-rebuild.js";
|
|
7
|
+
import { validateSqliteReadModelSchema } from "./sqlite-read-model-schema.js";
|
|
8
|
+
import * as fingerprints from "./sqlite-read-model-source-fingerprint.js";
|
|
9
|
+
|
|
10
|
+
const roots: string[] = [];
|
|
11
|
+
const source = ".agents/records/tasks/TASK-STARTUP.md";
|
|
12
|
+
const record = (title: string) =>
|
|
13
|
+
`---\nid: TASK-STARTUP\ntitle: ${title}\nstatus: executing\ncreated_at: 2026-09-29T12:00:00Z\n---\n`;
|
|
14
|
+
async function fixture() {
|
|
15
|
+
const parent = resolve(import.meta.dirname, "../../../../..", ".local/sqlite/tests");
|
|
16
|
+
await mkdir(parent, { recursive: true });
|
|
17
|
+
const root = await mkdtemp(join(parent, "startup-seed-"));
|
|
18
|
+
roots.push(root);
|
|
19
|
+
await mkdir(join(root, ".agents/records/tasks"), { recursive: true });
|
|
20
|
+
await writeFile(join(root, source), record("Before"));
|
|
21
|
+
return root;
|
|
22
|
+
}
|
|
23
|
+
afterEach(async () => {
|
|
24
|
+
vi.restoreAllMocks();
|
|
25
|
+
await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
|
|
26
|
+
});
|
|
27
|
+
describe("validated startup generation", () => {
|
|
28
|
+
it("serves a seed without traversing sources, then canonical refresh observes the changed record", async () => {
|
|
29
|
+
const root = await fixture();
|
|
30
|
+
await rebuildSqliteReadModel(root);
|
|
31
|
+
await writeFile(join(root, source), record("After"));
|
|
32
|
+
const fingerprint = vi.spyOn(fingerprints, "sourceFingerprint");
|
|
33
|
+
const sql = vi.spyOn(DatabaseSync.prototype, "prepare");
|
|
34
|
+
const result = await rebuildSqliteReadModel(root, {
|
|
35
|
+
preferExisting: true,
|
|
36
|
+
sourceRoots: ["invalid-startup-root"],
|
|
37
|
+
});
|
|
38
|
+
expect(result).toMatchObject({ cache: "stale_seed", fingerprint_ms: 0, materialize_ms: 0 });
|
|
39
|
+
expect(fingerprint).not.toHaveBeenCalled();
|
|
40
|
+
expect(sql).toHaveBeenCalledWith("PRAGMA quick_check");
|
|
41
|
+
expect(sql).not.toHaveBeenCalledWith("PRAGMA integrity_check");
|
|
42
|
+
const reader = new SqliteReadModelFileSystem(root);
|
|
43
|
+
try {
|
|
44
|
+
expect(await reader.readText(source)).toContain("title: Before");
|
|
45
|
+
await rebuildSqliteReadModel(root);
|
|
46
|
+
expect(sql).toHaveBeenCalledWith("PRAGMA integrity_check");
|
|
47
|
+
reader.refresh();
|
|
48
|
+
expect(await reader.readText(source)).toContain("title: After");
|
|
49
|
+
} finally {
|
|
50
|
+
reader.close();
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it.each([
|
|
55
|
+
"old-schema",
|
|
56
|
+
"missing-index",
|
|
57
|
+
"missing-payload",
|
|
58
|
+
])("rebuilds %s rather than serving incomplete seed", async (damage) => {
|
|
59
|
+
const root = await fixture();
|
|
60
|
+
const first = await rebuildSqliteReadModel(root);
|
|
61
|
+
const database = new DatabaseSync(first.path);
|
|
62
|
+
try {
|
|
63
|
+
if (damage === "old-schema")
|
|
64
|
+
database.exec(
|
|
65
|
+
"UPDATE zaip_aios_activities SET payload_json=json_set(payload_json,'$.value','0') WHERE payload_type='metadata' AND json_extract(payload_json,'$.key')='schema_version'",
|
|
66
|
+
);
|
|
67
|
+
else if (damage === "missing-index")
|
|
68
|
+
database.exec("DROP INDEX zaip_activities_work_item_identity");
|
|
69
|
+
else
|
|
70
|
+
database.exec(
|
|
71
|
+
"DELETE FROM zaip_aios_activities WHERE payload_type='first_fold_all_time_board_cache'",
|
|
72
|
+
);
|
|
73
|
+
} finally {
|
|
74
|
+
database.close();
|
|
75
|
+
}
|
|
76
|
+
expect((await rebuildSqliteReadModel(root, { preferExisting: true })).cache).toBe("rebuilt");
|
|
77
|
+
expect(() => validateSqliteReadModelSchema(first.path)).not.toThrow();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("rejects corrupt bytes and never serves them as a validated seed", async () => {
|
|
81
|
+
const root = await fixture();
|
|
82
|
+
const first = await rebuildSqliteReadModel(root);
|
|
83
|
+
await writeFile(first.path, "corrupt SQLite bytes");
|
|
84
|
+
expect(() => validateSqliteReadModelSchema(first.path, { integrity: "quick" })).toThrow();
|
|
85
|
+
await expect(rebuildSqliteReadModel(root, { preferExisting: true })).rejects.toThrow();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { appendFileSync, mkdirSync } from "node:fs";
|
|
2
|
-
import {
|
|
2
|
+
import { createDashboardDiagnostics, sanitizeDiagnostic } from "./dashboard-diagnostics.mjs";
|
|
3
|
+
import { launcherLogPath, sessionDirectory, workspaceRoot } from "./start-dashboard-paths.mjs";
|
|
4
|
+
export const launcherDiagnostics = createDashboardDiagnostics(workspaceRoot, "launcher");
|
|
5
|
+
process.env.ZAIP_DASHBOARD_LAUNCH_ID = launcherDiagnostics.correlationId;
|
|
3
6
|
export function appendLauncherLog(message) {
|
|
7
|
+
launcherDiagnostics.log("launcher_message", { message });
|
|
4
8
|
try {
|
|
5
9
|
mkdirSync(sessionDirectory, { recursive: true });
|
|
6
10
|
appendFileSync(
|
|
7
11
|
launcherLogPath,
|
|
8
|
-
`[${new Date().toISOString()}] ${stripTerminalControlCodes(message)}\n`,
|
|
12
|
+
`[${new Date().toISOString()}] ${stripTerminalControlCodes(sanitizeDiagnostic(message))}\n`,
|
|
9
13
|
"utf8",
|
|
10
14
|
);
|
|
11
15
|
} catch {
|
|
@@ -55,12 +55,18 @@ export async function startDashboardServer({
|
|
|
55
55
|
ZAIP_SQLITE_PREFER_LAST_VALID_SEED: "0",
|
|
56
56
|
ZAIP_SQLITE_DB_PATH: dbPath,
|
|
57
57
|
},
|
|
58
|
-
stdio: ["ignore", "
|
|
58
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
59
59
|
windowsHide: true,
|
|
60
60
|
});
|
|
61
61
|
onChildStarted(child);
|
|
62
|
+
appendLog(`Runtime spawned: pid=${child.pid} port=${port} attempt=${attempt}`);
|
|
63
|
+
child.stdout?.setEncoding("utf8");
|
|
64
|
+
child.stdout?.on("data", (chunk) =>
|
|
65
|
+
appendLog(`runtime stdout: ${String(chunk).slice(0, 16000)}`),
|
|
66
|
+
);
|
|
62
67
|
child.stderr?.setEncoding("utf8");
|
|
63
68
|
child.stderr?.on("data", (chunk) => {
|
|
69
|
+
appendLog(`runtime stderr: ${String(chunk).slice(0, 16000)}`);
|
|
64
70
|
stderr = `${stderr}${chunk}`.slice(-4_000);
|
|
65
71
|
startupTelemetryBuffer = `${startupTelemetryBuffer}${String(chunk)}`;
|
|
66
72
|
const lines = startupTelemetryBuffer.split("\n");
|
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
dashboardUrl,
|
|
4
4
|
findAvailablePortWithFallback,
|
|
5
5
|
openBrowser,
|
|
6
|
-
preferredPort,
|
|
7
6
|
} from "./start-dashboard-navigation.mjs";
|
|
8
7
|
|
|
9
8
|
export {
|
|
@@ -23,6 +22,7 @@ import {
|
|
|
23
22
|
import {
|
|
24
23
|
appendLauncherLog,
|
|
25
24
|
formatLauncherError,
|
|
25
|
+
launcherDiagnostics,
|
|
26
26
|
stripTerminalControlCodes,
|
|
27
27
|
} from "./start-dashboard-logging.mjs";
|
|
28
28
|
import {
|
|
@@ -36,7 +36,6 @@ import {
|
|
|
36
36
|
lockHeartbeatFloorMs,
|
|
37
37
|
lockPath,
|
|
38
38
|
lockTimeoutMs,
|
|
39
|
-
maxPortAttempts,
|
|
40
39
|
maxPortHistory,
|
|
41
40
|
maxServerStartAttempts,
|
|
42
41
|
nodeCompileCacheDirectory,
|
|
@@ -494,6 +493,7 @@ async function startDashboardServer(
|
|
|
494
493
|
});
|
|
495
494
|
}
|
|
496
495
|
async function main() {
|
|
496
|
+
launcherDiagnostics.log("launcher_entered");
|
|
497
497
|
let ownedChild = null;
|
|
498
498
|
let currentSession = null;
|
|
499
499
|
let launchPage = null;
|
|
@@ -741,9 +741,8 @@ async function waitForDashboard(port, child) {
|
|
|
741
741
|
await delay(100);
|
|
742
742
|
}
|
|
743
743
|
}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
}
|
|
744
|
+
const delay = (milliseconds) =>
|
|
745
|
+
new Promise((resolveDelay) => setTimeout(resolveDelay, milliseconds));
|
|
747
746
|
const isMain = process.argv[1]
|
|
748
747
|
? resolve(process.argv[1]) === fileURLToPath(import.meta.url)
|
|
749
748
|
: false;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
|
+
import { createElement } from "react";
|
|
3
|
+
import { renderToStaticMarkup } from "react-dom/server";
|
|
2
4
|
import { describe, expect, it } from "vitest";
|
|
5
|
+
import { DashboardHeader } from "./DashboardHeader.tsx";
|
|
3
6
|
|
|
4
7
|
const styles = readFileSync(new URL("ui.css", import.meta.url), "utf8");
|
|
5
|
-
const headerSource = readFileSync(new URL("DashboardHeader.tsx", import.meta.url), "utf8");
|
|
6
8
|
|
|
7
9
|
describe("DashboardHeader", () => {
|
|
8
10
|
it("optically balances the repository badge horizontal spacing", () => {
|
|
@@ -10,12 +12,39 @@ describe("DashboardHeader", () => {
|
|
|
10
12
|
expect(rule).toContain("padding-block: 0.3rem");
|
|
11
13
|
expect(rule).toContain("padding-inline: 0.6rem 0.72rem");
|
|
12
14
|
});
|
|
13
|
-
it("
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
it.each(["pt-BR", "en-US"])("shows only snapshot freshness in %s", (locale) => {
|
|
16
|
+
const telemetry = "2026-09-29T11:32:27Z";
|
|
17
|
+
const snapshot = "2026-09-29T12:59:35Z";
|
|
18
|
+
const markup = renderHeader({ locale, lastUpdatedAt: telemetry, snapshotUpdatedAt: snapshot });
|
|
19
|
+
const formatted = new Intl.DateTimeFormat(locale, { dateStyle: "short", timeStyle: "medium" });
|
|
20
|
+
expect(markup.match(/<small>/g)).toHaveLength(1);
|
|
21
|
+
expect(markup).toContain(locale === "pt-BR" ? "Última Atualização" : "Last Updated");
|
|
22
|
+
expect(markup).toContain(formatted.format(new Date(snapshot)));
|
|
23
|
+
expect(markup).not.toContain(formatted.format(new Date(telemetry)));
|
|
24
|
+
});
|
|
25
|
+
it("keeps an unavailable snapshot explicit even when telemetry exists", () => {
|
|
26
|
+
const markup = renderHeader({ lastUpdatedAt: "2026-09-29T11:32:27Z" });
|
|
27
|
+
expect(markup.match(/<small>/g)).toHaveLength(1);
|
|
28
|
+
expect(markup).toContain("Atualização indisponível");
|
|
29
|
+
expect(markup).not.toContain("11:32:27");
|
|
16
30
|
});
|
|
17
31
|
});
|
|
18
32
|
|
|
33
|
+
function renderHeader(props) {
|
|
34
|
+
return renderToStaticMarkup(
|
|
35
|
+
createElement(DashboardHeader, {
|
|
36
|
+
filters: null,
|
|
37
|
+
lastUpdatedAt: null,
|
|
38
|
+
loading: false,
|
|
39
|
+
locale: "pt-BR",
|
|
40
|
+
onLocaleChange() {},
|
|
41
|
+
onRefresh() {},
|
|
42
|
+
title: "Dashboard ZAIP AIOS",
|
|
43
|
+
...props,
|
|
44
|
+
}),
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
19
48
|
function cssRule(source, selector) {
|
|
20
49
|
const match = [...source.matchAll(/([^{}]+)\{([^}]*)\}/g)].find((candidate) =>
|
|
21
50
|
candidate[1]?.split(",").some((item) => item.trim() === selector),
|
|
@@ -7,7 +7,7 @@ const zaipLogoUrl = new URL("../../../../config/src/logo_novo_azul.png", import.
|
|
|
7
7
|
export function DashboardHeader({
|
|
8
8
|
filters,
|
|
9
9
|
filtersActive = false,
|
|
10
|
-
|
|
10
|
+
snapshotUpdatedAt = null,
|
|
11
11
|
loading,
|
|
12
12
|
locale,
|
|
13
13
|
onLocaleChange,
|
|
@@ -19,6 +19,7 @@ export function DashboardHeader({
|
|
|
19
19
|
filters: ReactNode;
|
|
20
20
|
filtersActive?: boolean;
|
|
21
21
|
lastUpdatedAt: string | null;
|
|
22
|
+
snapshotUpdatedAt?: string | null;
|
|
22
23
|
loading: boolean;
|
|
23
24
|
locale: DashboardHeaderLocale;
|
|
24
25
|
onLocaleChange: (locale: DashboardHeaderLocale) => void;
|
|
@@ -38,8 +39,8 @@ export function DashboardHeader({
|
|
|
38
39
|
refresh: "Atualizar",
|
|
39
40
|
refreshing: "Atualizando…",
|
|
40
41
|
settings: "Configurações",
|
|
41
|
-
updated: "Última
|
|
42
|
-
waiting: "
|
|
42
|
+
updated: "Última Atualização",
|
|
43
|
+
waiting: "Atualização indisponível",
|
|
43
44
|
}
|
|
44
45
|
: {
|
|
45
46
|
filters: "Filters",
|
|
@@ -47,13 +48,13 @@ export function DashboardHeader({
|
|
|
47
48
|
refresh: "Refresh",
|
|
48
49
|
refreshing: "Refreshing…",
|
|
49
50
|
settings: "Settings",
|
|
50
|
-
updated: "Last
|
|
51
|
-
waiting: "
|
|
51
|
+
updated: "Last Updated",
|
|
52
|
+
waiting: "Update unavailable",
|
|
52
53
|
};
|
|
53
54
|
const updatedLabel =
|
|
54
|
-
|
|
55
|
+
snapshotUpdatedAt === null
|
|
55
56
|
? copy.waiting
|
|
56
|
-
: `${copy.updated} ${new Intl.DateTimeFormat(locale, { dateStyle: "short", timeStyle: "medium" }).format(new Date(
|
|
57
|
+
: `${copy.updated} ${new Intl.DateTimeFormat(locale, { dateStyle: "short", timeStyle: "medium" }).format(new Date(snapshotUpdatedAt))}`;
|
|
57
58
|
const changeLocale = (next: DashboardHeaderLocale) => {
|
|
58
59
|
onLocaleChange(next);
|
|
59
60
|
setLocaleOpen(false);
|