@zaip-ai/cli 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/services/agent-adapters.js +1 -1
- package/dist/services/agent-adapters.js.map +1 -1
- package/dist/services/agent-adapters.test.js +2 -1
- package/dist/services/agent-adapters.test.js.map +1 -1
- package/dist/services/codex-pre-tool-hook-template.d.ts.map +1 -1
- package/dist/services/codex-pre-tool-hook-template.js +89 -7
- package/dist/services/codex-pre-tool-hook-template.js.map +1 -1
- package/dist/services/codex-rules.d.ts +1 -1
- package/dist/services/codex-rules.d.ts.map +1 -1
- package/dist/services/codex-rules.js +7 -0
- package/dist/services/codex-rules.js.map +1 -1
- package/dist/services/install-agents-template.d.ts.map +1 -1
- package/dist/services/install-agents-template.js +1 -0
- package/dist/services/install-agents-template.js.map +1 -1
- package/dist/services/runtime-template.test.js +31 -7
- package/dist/services/runtime-template.test.js.map +1 -1
- package/dist/services/template-manifest.d.ts.map +1 -1
- package/dist/services/template-manifest.js +7 -3
- package/dist/services/template-manifest.js.map +1 -1
- package/package.json +1 -1
- package/templates/.agents/config/agents/catalog.yaml +7 -7
- package/templates/.agents/config/clients/codex/agents/zaip-agent-backend.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-designer.toml +2 -2
- package/templates/.agents/config/clients/codex/agents/zaip-agent-frontend.toml +8 -8
- package/templates/.agents/dashboard/.zaip-managed.json +373 -205
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-DxR_pgSV.js → CostCalculationGuidePage-ovxurkIk.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-4jZLTWE_.js → DashboardHelpDialog-BgVgrfhQ.js} +240 -86
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-CKcsqb-r.js → PricingSettingsDialog-vSvvOHQp.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{ProjectSettingsPage-DmmJD2Th.js → ProjectSettingsPage-zH758vfs.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-DLn-Mz2M.js +1 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-CaKwQP43.css → TraceabilityWorkspace-DvvavDLY.css} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-DKwP1stV.js +68 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-PoJA2PI1.css +1 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-C0fj2uU9.js → icons-vendor-B_lDDHn1.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-B31GMG5O.css +1 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-CZQlsLV9.js +2 -0
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-BEsJ-FYH.js → react-vendor-B3TJrD4O.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-B6y6Gw12.js → traceability-7f1j5wx3.js} +1 -1
- package/templates/.agents/dashboard/apps/frontend/dist/index.html +7 -7
- package/templates/.agents/dashboard/apps/frontend/playwright.dom.config.ts +32 -0
- package/templates/.agents/dashboard/apps/frontend/src/App.tsx +132 -245
- package/templates/.agents/dashboard/apps/frontend/src/AppOverlays.tsx +0 -21
- package/templates/.agents/dashboard/apps/frontend/src/DashboardAlternateContent.tsx +9 -0
- package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.dom.e2e.ts +56 -0
- package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.test.ts +18 -1
- package/templates/.agents/dashboard/apps/frontend/src/TraceabilityWorkspace.tsx +75 -8
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.test.ts +25 -1
- package/templates/.agents/dashboard/apps/frontend/src/dashboard-api.ts +7 -9
- package/templates/.agents/dashboard/apps/frontend/src/operations-period-render.test.ts +4 -4
- package/templates/.agents/dashboard/apps/frontend/src/overview-status-page.test.ts +1 -1
- package/templates/.agents/dashboard/apps/frontend/src/snapshot-banner-semantics.test.ts +7 -0
- package/templates/.agents/dashboard/apps/frontend/src/snapshot-coherence.test.ts +20 -8
- package/templates/.agents/dashboard/apps/frontend/src/sqlite-page-export.test.ts +32 -0
- package/templates/.agents/dashboard/apps/frontend/src/sqlite-page-export.ts +21 -0
- package/templates/.agents/dashboard/apps/frontend/src/styles.css +19 -0
- package/templates/.agents/dashboard/apps/frontend/src/traceability-task-pagination.test.ts +32 -0
- package/templates/.agents/dashboard/apps/frontend/src/traceability-task-pagination.ts +36 -0
- package/templates/.agents/dashboard/apps/frontend/src/traceability-workspace.css +6 -2
- package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.test.ts +48 -0
- package/templates/.agents/dashboard/apps/frontend/src/use-app-cost-loaders.ts +31 -27
- package/templates/.agents/dashboard/apps/frontend/src/use-app-trace-documents.ts +7 -1
- package/templates/.agents/dashboard/apps/frontend/src/use-app-work-list-page.test.ts +163 -0
- package/templates/.agents/dashboard/apps/frontend/src/use-app-work-list-page.ts +136 -0
- package/templates/.agents/dashboard/apps/frontend/src/use-operations-detail-export.ts +76 -0
- package/templates/.agents/dashboard/apps/frontend/src/work-list-load-dedup.test.ts +23 -0
- package/templates/.agents/dashboard/apps/frontend/src/work-list-load-dedup.ts +27 -0
- package/templates/.agents/dashboard/apps/frontend/src/work-list-pagination.test.ts +38 -14
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionPanel.tsx +60 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostDeveloperAttributionTable.tsx +191 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.loading.test.ts +14 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.run-page.test.ts +18 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.tsx +18 -3
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorContent.tsx +8 -2
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorLoadErrors.tsx +35 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.test.ts +47 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostMonitorPage.tsx +50 -58
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableLoading.test.ts +132 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTableLoading.tsx +70 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +128 -138
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.tsx +17 -67
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-copy.ts +2 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-views.ts +3 -1
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-page-range.ts +35 -0
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-compact-cost-page.ts +16 -4
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.test.ts +37 -2
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-group-page.ts +44 -8
- package/templates/.agents/dashboard/modules/cost-monitor/src/react/use-cost-run-page.ts +6 -1
- package/templates/.agents/dashboard/modules/operations/src/contracts.ts +20 -3
- package/templates/.agents/dashboard/modules/operations/src/react/DeveloperAttributionPanel.test.ts +54 -0
- package/templates/.agents/dashboard/modules/operations/src/react/DeveloperAttributionPanel.tsx +247 -0
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsMainContent.tsx +39 -13
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.helpers.tsx +107 -2
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.macro-metrics.test.ts +55 -0
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.test.ts +20 -28
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +162 -165
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverviewTopPanel.tsx +127 -0
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +13 -46
- package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageOverview.tsx +3 -0
- package/templates/.agents/dashboard/modules/operations/src/react/PagedWorkList.test.tsx +43 -0
- package/templates/.agents/dashboard/modules/operations/src/react/PagedWorkList.tsx +181 -0
- package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.test.ts +4 -2
- package/templates/.agents/dashboard/modules/operations/src/react/UnifiedWorkList.tsx +13 -0
- package/templates/.agents/dashboard/modules/operations/src/react/developer-identities.test.ts +18 -0
- package/templates/.agents/dashboard/modules/operations/src/react/developer-identities.ts +30 -0
- package/templates/.agents/dashboard/modules/operations/src/react/execution-metrics.ts +1 -0
- package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.test.ts +8 -0
- package/templates/.agents/dashboard/modules/operations/src/react/export/ExcelExportAction.tsx +3 -0
- package/templates/.agents/dashboard/modules/operations/src/react/export/export-layout.test.ts +14 -5
- package/templates/.agents/dashboard/modules/operations/src/react/index.ts +1 -0
- package/templates/.agents/dashboard/modules/operations/src/react/operations-coverage-toast.test.ts +4 -3
- package/templates/.agents/dashboard/modules/operations/src/react/operations-date-filters.css +1 -1
- package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +21 -11
- package/templates/.agents/dashboard/modules/operations/src/react/operations-overview.css +4 -0
- package/templates/.agents/dashboard/modules/operations/src/react/operations-page-contract.ts +8 -1
- package/templates/.agents/dashboard/modules/operations/src/react/operations-view-order.test.ts +1 -0
- package/templates/.agents/dashboard/modules/operations/src/react/period-summary.ts +1 -0
- package/templates/.agents/dashboard/modules/operations/src/server/metric-coverage.ts +1 -0
- package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +527 -335
- package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +501 -309
- package/templates/.agents/dashboard/packages/local-runtime/gitignore.template +2 -0
- package/templates/.agents/dashboard/packages/local-runtime/scripts/rebuild-sqlite-read-model.mjs +3 -1
- package/templates/.agents/dashboard/packages/local-runtime/scripts/test-sqlite-read-model.mjs +3 -3
- package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-sqlite-read-model.mjs +25 -15
- package/templates/.agents/dashboard/packages/local-runtime/server.mjs +527 -335
- package/templates/.agents/dashboard/packages/local-runtime/src/server-board.test.ts +34 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-board.ts +15 -8
- package/templates/.agents/dashboard/packages/local-runtime/src/server-classification-page.test.ts +87 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-period-macro-metric.test.ts +44 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-period-macro-metric.ts +125 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-reconciliation-refresh.test.ts +66 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-request-authority.test.ts +61 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-request-authority.ts +18 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-run-projections.test.ts +42 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot-refresh.ts +97 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server-snapshot.test.ts +3 -1
- package/templates/.agents/dashboard/packages/local-runtime/src/server-sqlite-task-trace.ts +91 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server.test-fixtures.ts +36 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +98 -123
- package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +111 -135
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-artifact-counts.ts +28 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.test.ts +63 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-agent-page.ts +109 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-aggregates.ts +497 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-fast-page-parity.test-support.ts +65 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-page.test.ts +176 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-page.ts +119 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-group-projection.ts +41 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.test.ts +16 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.ts +29 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-cache.ts +355 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-persistence.ts +121 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-first-fold-timing.ts +27 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-projection.ts +15 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.test.ts +223 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.ts +304 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-cache.test-support.ts +23 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-first-fold-types.ts +89 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider-fixture.ts +227 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-multi-provider.test.ts +691 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-source-fingerprint.ts +81 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.test.ts +440 -863
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model.ts +1120 -1086
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-cache.ts +129 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-install.test.ts +26 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-install.ts +28 -0
- package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-snapshot-seed.test.ts +116 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.mjs +146 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-launch-page.test.mjs +165 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-refresh.mjs +140 -0
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.mjs +188 -299
- package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +51 -70
- package/templates/.agents/dashboard/packages/windows-launcher/Program.cs +5 -2
- package/templates/.agents/dashboard/tests/e2e/playwright.config.ts +4 -1
- package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-loading.spec.ts +142 -0
- package/templates/.agents/dashboard/tests/e2e/specs/cost-monitor-pagination.spec.ts +232 -0
- package/templates/.agents/dashboard/tests/e2e/specs/dashboard-performance-matrix.spec.ts +743 -0
- package/templates/.agents/dashboard/tests/e2e/specs/dashboard.spec.ts +183 -210
- package/templates/.agents/dashboard/zaip-dashboard-windows.exe +0 -0
- package/templates/.agents/requirements/autonomous-assurance.md +6 -6
- package/templates/.agents/requirements/comparative-audit.md +1 -1
- package/templates/.agents/requirements/context-engine.md +1 -1
- package/templates/.agents/requirements/cost-observability.md +1 -1
- package/templates/.agents/requirements/dashboard-launch.md +1 -1
- package/templates/.agents/requirements/data-export.md +1 -1
- package/templates/.agents/requirements/design-system.md +1 -1
- package/templates/.agents/requirements/execution-engine.md +3 -3
- package/templates/.agents/requirements/kanban-dashboard.md +10 -2
- package/templates/.agents/requirements/model-orchestration.md +1 -1
- package/templates/.agents/requirements/public-distribution.md +1 -1
- package/templates/.agents/requirements/software-architecture.md +1 -1
- package/templates/.agents/requirements/strategic-improvements.md +1 -1
- package/templates/.agents/requirements/work-lifecycle.md +4 -4
- package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
- package/templates/.agents/rules/dashboard-ui-consistency.md +14 -0
- package/templates/.agents/rules/frontend-lite.md +4 -4
- package/templates/.agents/rules/run-lifecycle-closure.md +4 -4
- package/templates/.agents/runtime/bin/zaip.mjs +1137 -1037
- package/templates/.agents/runtime/checksums.sha256 +2 -2
- package/templates/.agents/runtime/provenance.json +2 -2
- package/templates/.agents/skills/criar-pasta-obsidian/scripts/generate-obsidian-vault.test.mjs +20 -16
- package/templates/.agents/skills/zaip-skill-agent-catalog/SKILL.md +22 -0
- package/templates/.agents/skills/zaip-skill-agent-catalog/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-author-skills/SKILL.md +3 -2
- package/templates/.agents/skills/zaip-skill-author-skills/scripts/audit-skill-catalog.mjs +49 -0
- package/templates/.agents/skills/zaip-skill-author-skills/scripts/author-skill-scripts.test.mjs +27 -0
- package/templates/.agents/skills/zaip-skill-author-skills/scripts/run-skill-tests.mjs +37 -0
- package/templates/.agents/skills/zaip-skill-backend/SKILL.md +1 -0
- package/templates/.agents/skills/zaip-skill-change/SKILL.md +1 -1
- package/templates/.agents/skills/zaip-skill-change/references/observable-evidence.md +83 -0
- package/templates/.agents/skills/zaip-skill-dashboard-diagnostics/SKILL.md +22 -0
- package/templates/.agents/skills/zaip-skill-dashboard-diagnostics/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-execution/SKILL.md +1 -1
- package/templates/.agents/skills/zaip-skill-frontend/SKILL.md +4 -3
- package/templates/.agents/skills/zaip-skill-frontend/agents/openai.yaml +2 -2
- package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +10 -10
- package/templates/.agents/skills/zaip-skill-lifecycle-closure/SKILL.md +27 -0
- package/templates/.agents/skills/zaip-skill-lifecycle-closure/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-prd/SKILL.md +4 -0
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-local-telemetry.mjs +72 -22
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-explicit-recovery.mjs +223 -0
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.mjs +42 -1
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-lib.test.mjs +101 -0
- package/templates/.agents/skills/zaip-skill-reconcile-telemetry/scripts/reconcile-telemetry-remeasurement.test.mjs +53 -0
- package/templates/.agents/skills/zaip-skill-release-qualification/SKILL.md +20 -0
- package/templates/.agents/skills/zaip-skill-release-qualification/agents/openai.yaml +4 -0
- package/templates/.agents/skills/zaip-skill-review/SKILL.md +5 -0
- package/templates/.agents/skills/zaip-skill-rules/SKILL.md +1 -1
- package/templates/.agents/skills/zaip-skill-spec/SKILL.md +4 -0
- package/templates/.agents/skills/zaip-skill-sqlite-read-model/SKILL.md +22 -90
- package/templates/.agents/zaip-aios/INDEX.md +57 -32
- package/templates/.agents/zaip-aios/README.md +22 -12
- package/templates/.agents/zaip-aios/guides/02-requirements.md +5 -0
- package/templates/.agents/zaip-aios/guides/06-execucao.md +13 -4
- package/templates/.agents/zaip-aios/guides/07-revisao-e-validacao.md +7 -0
- package/templates/.agents/zaip-aios/guides/10-seguranca.md +23 -0
- package/templates/.agents/zaip-aios/guides/11-observabilidade-e-custos.md +6 -6
- package/templates/.agents/zaip-aios/guides/13-boas-praticas.md +3 -0
- package/templates/.agents/zaip-aios/guides/16-lifecycle-e-reconciliacao.md +12 -3
- package/templates/.agents/zaip-aios/guides/17-como-o-custo-e-calculado.md +5 -5
- package/templates/.agents/zaip-aios/guides/19-assurance-e-autonomia.md +23 -0
- package/templates/.agents/zaip-aios/guides/20-instalacao-detalhada.md +44 -8
- package/templates/.agents/zaip-aios/guides/21-telemetria-monitor-custos.md +8 -14
- package/templates/.agents/zaip-aios/guides/22-fluxos-e-roteamento.md +5 -0
- package/templates/.agents/zaip-aios/guides/23-orquestracao-de-modelos.md +6 -6
- package/templates/.agents/zaip-aios/guides/24-calculo-de-custos-openai.md +8 -8
- package/templates/.agents/zaip-aios/guides/25-fontes-de-precos-openai.md +3 -2
- package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +77 -10
- package/templates/.agents/zaip-aios/guides/27-telemetria-git-native.md +8 -3
- package/templates/.agents/zaip-aios/guides/28-lifecycle-completo.md +5 -0
- package/templates/template-manifest.json +555 -170
- package/templates/.agents/dashboard/apps/frontend/dist/assets/TraceabilityWorkspace-BwtitWa_.js +0 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-BZ5WdaMN.css +0 -1
- package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-N5Csr0RP.js +0 -68
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-C4aIB1PV.js +0 -2
- package/templates/.agents/dashboard/apps/frontend/dist/assets/index-DK_enB5Z.css +0 -1
- package/templates/.agents/dashboard/apps/frontend/src/use-idle-cost-prefetch.ts +0 -45
- package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs.metafile.json +0 -7333
package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-operations-work-list.test.ts
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { DatabaseSync } from "node:sqlite";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import {
|
|
4
|
+
attachOperationsWorkListDevelopers,
|
|
5
|
+
operationsWorkListPayloadPage,
|
|
6
|
+
operationsWorkListSql,
|
|
7
|
+
} from "./sqlite-operations-work-list.js";
|
|
8
|
+
|
|
9
|
+
function page(input: Parameters<typeof operationsWorkListSql>[0]) {
|
|
10
|
+
const database = new DatabaseSync(":memory:");
|
|
11
|
+
database.exec(`
|
|
12
|
+
CREATE TABLE canonical_work_items (entity_kind TEXT, id TEXT, stage TEXT, risk TEXT, spec_id TEXT, change_id TEXT, occurred_day_sp TEXT);
|
|
13
|
+
CREATE TABLE canonical_changes (id TEXT, source_type TEXT, task_ids_json TEXT, created_at TEXT);
|
|
14
|
+
CREATE TABLE operations_work_kanban (entity_kind TEXT, id TEXT, title TEXT, status TEXT, risk TEXT, occurred_at TEXT, occurred_day_sp TEXT);
|
|
15
|
+
INSERT INTO canonical_work_items VALUES
|
|
16
|
+
('task','TASK-PRD','executing','standard','SPEC-1','CHG-PRD','2026-08-01'),
|
|
17
|
+
('task','TASK-SPEC','ready','standard','SPEC-1',NULL,'2026-08-02'),
|
|
18
|
+
('task','TASK-STANDALONE','executing','standard',NULL,NULL,'2026-08-03'),
|
|
19
|
+
('task','TASK-ORIGIN-SPEC','ready','standard',NULL,'CHG-SPEC','2026-08-03'),
|
|
20
|
+
('prd','PRD-1','definition','standard',NULL,NULL,'2026-08-04'),
|
|
21
|
+
('spec','SPEC-1','planning','standard',NULL,NULL,'2026-08-05');
|
|
22
|
+
INSERT INTO operations_work_kanban SELECT entity_kind,id,id,'active',risk,occurred_day_sp || 'T00:00:00Z',occurred_day_sp FROM canonical_work_items;
|
|
23
|
+
INSERT INTO canonical_changes VALUES
|
|
24
|
+
('CHG-PRD','prd','["TASK-PRD"]','2026-08-04T00:00:00Z'),
|
|
25
|
+
('CHG-SPEC','spec','["TASK-ORIGIN-SPEC"]','2026-08-04T00:00:00Z'),
|
|
26
|
+
('CHG-NEWER','spec','["TASK-PRD"]','2026-08-05T00:00:00Z');
|
|
27
|
+
`);
|
|
28
|
+
const sql = operationsWorkListSql(input);
|
|
29
|
+
const rows = database
|
|
30
|
+
.prepare(`${sql.select} FROM ${sql.source}${sql.where} ORDER BY work.id`)
|
|
31
|
+
.all(...sql.values) as Array<Record<string, unknown>>;
|
|
32
|
+
database.close();
|
|
33
|
+
return rows;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe("operations work list SQL", () => {
|
|
37
|
+
it("matches Kanban task kind and Change-origin precedence", () => {
|
|
38
|
+
expect(page({ kind: "all-tasks" }).map((row) => row.id)).toEqual([
|
|
39
|
+
"TASK-ORIGIN-SPEC",
|
|
40
|
+
"TASK-PRD",
|
|
41
|
+
"TASK-SPEC",
|
|
42
|
+
"TASK-STANDALONE",
|
|
43
|
+
]);
|
|
44
|
+
expect(page({ kind: "task" }).map((row) => row.id)).toEqual([
|
|
45
|
+
"TASK-ORIGIN-SPEC",
|
|
46
|
+
"TASK-PRD",
|
|
47
|
+
"TASK-SPEC",
|
|
48
|
+
]);
|
|
49
|
+
expect(page({ kind: "standalone-task" }).map((row) => row.id)).toEqual(["TASK-STANDALONE"]);
|
|
50
|
+
expect(page({ origin: "prd" }).map((row) => row.id)).toEqual(["TASK-PRD"]);
|
|
51
|
+
expect(page({ origin: "spec" }).map((row) => row.id)).toEqual([
|
|
52
|
+
"TASK-ORIGIN-SPEC",
|
|
53
|
+
"TASK-SPEC",
|
|
54
|
+
]);
|
|
55
|
+
expect(page({ origin: "task" }).map((row) => row.id)).toEqual(["TASK-STANDALONE"]);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("filters the public WorkStage, independent of lifecycle status", () => {
|
|
59
|
+
expect(page({ status: "executing", kind: "all" }).map((row) => row.id)).toEqual([
|
|
60
|
+
"TASK-PRD",
|
|
61
|
+
"TASK-STANDALONE",
|
|
62
|
+
]);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("paginates complete all-time payloads with public kinds and filters", () => {
|
|
66
|
+
const payload = {
|
|
67
|
+
pages: {
|
|
68
|
+
task: [
|
|
69
|
+
{
|
|
70
|
+
id: "TASK-LINKED",
|
|
71
|
+
title: "Linked task",
|
|
72
|
+
stage: "executing",
|
|
73
|
+
risk: "standard",
|
|
74
|
+
origin: "spec",
|
|
75
|
+
spec_id: "SPEC-1",
|
|
76
|
+
occurred_at: "2026-08-03T00:00:00Z",
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: "TASK-STANDALONE",
|
|
80
|
+
title: "Standalone task",
|
|
81
|
+
stage: "ready",
|
|
82
|
+
risk: "lite",
|
|
83
|
+
origin: "task",
|
|
84
|
+
spec_id: null,
|
|
85
|
+
occurred_at: "2026-08-02T00:00:00Z",
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
spec: [
|
|
89
|
+
{
|
|
90
|
+
id: "SPEC-1",
|
|
91
|
+
title: "Specification",
|
|
92
|
+
stage: "planning",
|
|
93
|
+
risk: "standard",
|
|
94
|
+
occurred_at: "2026-08-04T00:00:00Z",
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
prd: [
|
|
98
|
+
{
|
|
99
|
+
id: "PRD-1",
|
|
100
|
+
title: "Product requirement",
|
|
101
|
+
stage: "definition",
|
|
102
|
+
risk: "critical",
|
|
103
|
+
occurred_at: "2026-08-05T00:00:00Z",
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
expect(operationsWorkListPayloadPage({ kind: "all", limit: 2 }, payload)).toMatchObject({
|
|
109
|
+
total_count: 4,
|
|
110
|
+
has_more: true,
|
|
111
|
+
rows: [
|
|
112
|
+
{ id: "PRD-1", kind: "prd" },
|
|
113
|
+
{ id: "SPEC-1", kind: "spec" },
|
|
114
|
+
],
|
|
115
|
+
});
|
|
116
|
+
expect(
|
|
117
|
+
operationsWorkListPayloadPage({ kind: "all", offset: 2, limit: 2 }, payload)?.rows.map(
|
|
118
|
+
(row) => row.id,
|
|
119
|
+
),
|
|
120
|
+
).toEqual(["TASK-LINKED", "TASK-STANDALONE"]);
|
|
121
|
+
expect(
|
|
122
|
+
operationsWorkListPayloadPage({ kind: "task", status: "executing", origin: "spec" }, payload)
|
|
123
|
+
?.rows,
|
|
124
|
+
).toMatchObject([{ id: "TASK-LINKED", kind: "task" }]);
|
|
125
|
+
expect(
|
|
126
|
+
operationsWorkListPayloadPage({ kind: "standalone-task", risk: "lite" }, payload)?.rows,
|
|
127
|
+
).toMatchObject([{ id: "TASK-STANDALONE", kind: "standalone-task" }]);
|
|
128
|
+
expect(
|
|
129
|
+
operationsWorkListPayloadPage({ kind: "all-tasks" }, payload)?.rows.map((row) => row.id),
|
|
130
|
+
).toEqual(["TASK-LINKED", "TASK-STANDALONE"]);
|
|
131
|
+
expect(
|
|
132
|
+
operationsWorkListPayloadPage({ kind: "prd", query: "product" }, payload)?.rows,
|
|
133
|
+
).toMatchObject([{ id: "PRD-1", kind: "prd" }]);
|
|
134
|
+
expect(operationsWorkListPayloadPage({ kind: "all" }, {})).toBeNull();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("accepts the validated default-month payload but never applies all-time data to a range", () => {
|
|
138
|
+
const month = {
|
|
139
|
+
from_day: "2026-08-01",
|
|
140
|
+
to_day: "2026-08-31",
|
|
141
|
+
pages: { task: [], spec: [], prd: [] },
|
|
142
|
+
};
|
|
143
|
+
expect(
|
|
144
|
+
operationsWorkListPayloadPage({ from: "2026-08-01", to: "2026-08-31" }, month),
|
|
145
|
+
).toMatchObject({
|
|
146
|
+
total_count: 0,
|
|
147
|
+
});
|
|
148
|
+
expect(
|
|
149
|
+
operationsWorkListPayloadPage(
|
|
150
|
+
{ from: "2026-08-01", to: "2026-08-31" },
|
|
151
|
+
{ pages: month.pages },
|
|
152
|
+
),
|
|
153
|
+
).toBeNull();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("retains more than 200 rows for exports and later pages", () => {
|
|
157
|
+
const task = Array.from({ length: 205 }, (_, index) => ({
|
|
158
|
+
id: `TASK-${String(index).padStart(3, "0")}`,
|
|
159
|
+
title: "Complete population",
|
|
160
|
+
stage: "ready",
|
|
161
|
+
risk: "standard",
|
|
162
|
+
origin: "spec",
|
|
163
|
+
occurred_at: `2026-08-${String((index % 28) + 1).padStart(2, "0")}T00:00:00Z`,
|
|
164
|
+
}));
|
|
165
|
+
const payload = { pages: { task, spec: [], prd: [] } };
|
|
166
|
+
const firstPage = operationsWorkListPayloadPage({ kind: "task", limit: 100 }, payload);
|
|
167
|
+
expect(firstPage).toMatchObject({
|
|
168
|
+
total_count: 205,
|
|
169
|
+
has_more: true,
|
|
170
|
+
});
|
|
171
|
+
expect(firstPage?.rows).toHaveLength(100);
|
|
172
|
+
expect(firstPage?.rows.map((row) => row.id)).toContain("TASK-195");
|
|
173
|
+
expect(
|
|
174
|
+
operationsWorkListPayloadPage({ kind: "task", offset: 200, limit: 100 }, payload),
|
|
175
|
+
).toMatchObject({ total_count: 205, has_more: false, rows: expect.any(Array) });
|
|
176
|
+
expect(
|
|
177
|
+
operationsWorkListPayloadPage({ kind: "task", offset: 200, limit: 100 }, payload)?.rows,
|
|
178
|
+
).toHaveLength(5);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("projects each page's factual developer identities in one period-bounded set", () => {
|
|
182
|
+
const database = new DatabaseSync(":memory:");
|
|
183
|
+
database.exec(`
|
|
184
|
+
CREATE TABLE zaip_aios_activities (
|
|
185
|
+
payload_type TEXT, task_id TEXT, spec_id TEXT, prd_id TEXT,
|
|
186
|
+
developer_account_id TEXT, developer_login TEXT, occurred_day_sp TEXT
|
|
187
|
+
);
|
|
188
|
+
INSERT INTO zaip_aios_activities VALUES
|
|
189
|
+
(NULL, 'TASK-1', NULL, NULL, '2', 'alpha', '2026-08-10'),
|
|
190
|
+
(NULL, 'TASK-1', NULL, NULL, '2', 'beta', '2026-08-10'),
|
|
191
|
+
(NULL, 'TASK-1', NULL, NULL, '10', NULL, '2026-08-10'),
|
|
192
|
+
(NULL, 'TASK-1', NULL, NULL, 'outside-period', 'ignored', '2026-08-09'),
|
|
193
|
+
(NULL, NULL, 'SPEC-1', NULL, '7', 'spec-dev', '2026-08-10'),
|
|
194
|
+
(NULL, NULL, NULL, 'PRD-NOT-ON-PAGE', '99', 'not-selected', '2026-08-10');
|
|
195
|
+
`);
|
|
196
|
+
const rows = attachOperationsWorkListDevelopers(
|
|
197
|
+
database,
|
|
198
|
+
[
|
|
199
|
+
{ id: "TASK-1", kind: "task" },
|
|
200
|
+
{ id: "SPEC-1", entity_kind: "spec" },
|
|
201
|
+
{ id: "TASK-WITHOUT-RUN", kind: "standalone-task" },
|
|
202
|
+
],
|
|
203
|
+
{ from: "2026-08-10", to: "2026-08-10" },
|
|
204
|
+
);
|
|
205
|
+
expect(rows).toEqual([
|
|
206
|
+
{
|
|
207
|
+
id: "TASK-1",
|
|
208
|
+
kind: "task",
|
|
209
|
+
developers: [
|
|
210
|
+
{ account_id: "10", login_snapshot: null },
|
|
211
|
+
{ account_id: "2", login_snapshot: "beta" },
|
|
212
|
+
],
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
id: "SPEC-1",
|
|
216
|
+
entity_kind: "spec",
|
|
217
|
+
developers: [{ account_id: "7", login_snapshot: "spec-dev" }],
|
|
218
|
+
},
|
|
219
|
+
{ id: "TASK-WITHOUT-RUN", kind: "standalone-task", developers: [] },
|
|
220
|
+
]);
|
|
221
|
+
database.close();
|
|
222
|
+
});
|
|
223
|
+
});
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import type { DatabaseSync } from "node:sqlite";
|
|
2
|
+
|
|
3
|
+
export type OperationsWorkListQuery = {
|
|
4
|
+
from?: string | null;
|
|
5
|
+
to?: string | null;
|
|
6
|
+
query?: string;
|
|
7
|
+
status?: string;
|
|
8
|
+
risk?: string;
|
|
9
|
+
origin?: string;
|
|
10
|
+
kind?: "all" | "all-tasks" | "task" | "standalone-task" | "prd" | "spec";
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type WorkRow = Record<string, unknown>;
|
|
14
|
+
type WorkPagesPayload = { pages: { task: WorkRow[]; spec: WorkRow[]; prd: WorkRow[] } };
|
|
15
|
+
|
|
16
|
+
export type OperationsWorkListDeveloper = {
|
|
17
|
+
account_id: string;
|
|
18
|
+
login_snapshot: string | null;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type OperationsWorkListPayloadPage = {
|
|
22
|
+
offset: number;
|
|
23
|
+
limit: number;
|
|
24
|
+
total_count: number;
|
|
25
|
+
has_more: boolean;
|
|
26
|
+
rows: WorkRow[];
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function isWorkPagesPayload(value: unknown): value is WorkPagesPayload {
|
|
30
|
+
if (value === null || typeof value !== "object") return false;
|
|
31
|
+
const pages = (value as { pages?: unknown }).pages;
|
|
32
|
+
if (pages === null || typeof pages !== "object") return false;
|
|
33
|
+
return ["task", "spec", "prd"].every((kind) =>
|
|
34
|
+
Array.isArray((pages as Record<string, unknown>)[kind]),
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function publicKind(row: WorkRow, sourceKind: "task" | "spec" | "prd") {
|
|
39
|
+
if (sourceKind !== "task") return sourceKind;
|
|
40
|
+
if (row.kind === "task" || row.kind === "standalone-task") return row.kind;
|
|
41
|
+
return (typeof row.spec_id === "string" && row.spec_id.length > 0) ||
|
|
42
|
+
row.origin === "spec" ||
|
|
43
|
+
row.origin === "prd"
|
|
44
|
+
? "task"
|
|
45
|
+
: "standalone-task";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function matchesPayloadFilter(row: WorkRow, kind: string, input: OperationsWorkListQuery): boolean {
|
|
49
|
+
if (input.kind && input.kind !== "all") {
|
|
50
|
+
const matchesKind =
|
|
51
|
+
input.kind === "all-tasks"
|
|
52
|
+
? kind === "task" || kind === "standalone-task"
|
|
53
|
+
: kind === input.kind;
|
|
54
|
+
if (!matchesKind) return false;
|
|
55
|
+
}
|
|
56
|
+
if (input.query) {
|
|
57
|
+
const query = input.query.toLowerCase();
|
|
58
|
+
if (
|
|
59
|
+
!String(row.id ?? "")
|
|
60
|
+
.toLowerCase()
|
|
61
|
+
.includes(query) &&
|
|
62
|
+
!String(row.title ?? "")
|
|
63
|
+
.toLowerCase()
|
|
64
|
+
.includes(query)
|
|
65
|
+
)
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
if (input.status && row.stage !== input.status) return false;
|
|
69
|
+
if (input.risk && row.risk !== input.risk) return false;
|
|
70
|
+
// SQL only permits origin filters for Tasks. If an older payload lacks the
|
|
71
|
+
// persisted origin, preserve factual parity by falling back to SQL instead.
|
|
72
|
+
if (input.origin && (kind === "prd" || kind === "spec" || typeof row.origin !== "string"))
|
|
73
|
+
return false;
|
|
74
|
+
if (input.origin && row.origin !== input.origin) return false;
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Paginates already-materialized Board pages. Returning null deliberately
|
|
80
|
+
* delegates to SQL when a payload is absent or not rich enough for a filter.
|
|
81
|
+
*/
|
|
82
|
+
export function operationsWorkListPayloadPage(
|
|
83
|
+
input: OperationsWorkListQuery & { offset?: number; limit?: number },
|
|
84
|
+
payload: unknown,
|
|
85
|
+
): OperationsWorkListPayloadPage | null {
|
|
86
|
+
if (!isWorkPagesPayload(payload)) return null;
|
|
87
|
+
if (input.from || input.to) {
|
|
88
|
+
// Monthly payload eligibility is established by readFirstFoldMonthlyQuick;
|
|
89
|
+
// all-time payload callers do not provide a temporal filter.
|
|
90
|
+
const hasRange = typeof (payload as { from_day?: unknown }).from_day === "string";
|
|
91
|
+
if (!hasRange) return null;
|
|
92
|
+
}
|
|
93
|
+
const rows = (["task", "spec", "prd"] as const)
|
|
94
|
+
.flatMap((sourceKind) =>
|
|
95
|
+
payload.pages[sourceKind].map(
|
|
96
|
+
(row): WorkRow => ({ ...row, kind: publicKind(row, sourceKind) }),
|
|
97
|
+
),
|
|
98
|
+
)
|
|
99
|
+
.filter((row) => matchesPayloadFilter(row, String(row.kind), input))
|
|
100
|
+
.sort(
|
|
101
|
+
(left, right) =>
|
|
102
|
+
String(right.occurred_at ?? "").localeCompare(String(left.occurred_at ?? "")) ||
|
|
103
|
+
String(right.id ?? "").localeCompare(String(left.id ?? "")),
|
|
104
|
+
);
|
|
105
|
+
const limit = Math.min(200, Math.max(1, input.limit ?? 50));
|
|
106
|
+
const offset = Math.max(0, input.offset ?? 0);
|
|
107
|
+
const page = rows.slice(offset, offset + limit);
|
|
108
|
+
return {
|
|
109
|
+
offset,
|
|
110
|
+
limit,
|
|
111
|
+
total_count: rows.length,
|
|
112
|
+
has_more: offset + page.length < rows.length,
|
|
113
|
+
rows: page,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const linkedToSpec = "canonical.spec_id IS NOT NULL";
|
|
118
|
+
const changeId = `(COALESCE(canonical.change_id, (SELECT change.id FROM canonical_changes change, json_each(change.task_ids_json) task WHERE task.value = canonical.id ORDER BY change.created_at DESC, change.id DESC LIMIT 1)))`;
|
|
119
|
+
const changeOrigin = `(SELECT change.source_type FROM canonical_changes change WHERE change.id=${changeId})`;
|
|
120
|
+
const linkedTask = `(${linkedToSpec} OR COALESCE(${changeOrigin} IN ('spec', 'prd'), 0))`;
|
|
121
|
+
|
|
122
|
+
/** Builds count/page SQL for the canonical, server-paginated Operations List. */
|
|
123
|
+
export function operationsWorkListSql(input: OperationsWorkListQuery) {
|
|
124
|
+
const clauses: string[] = [];
|
|
125
|
+
const values: Array<string | number> = [];
|
|
126
|
+
if (input.from) {
|
|
127
|
+
clauses.push("canonical.occurred_day_sp >= ?");
|
|
128
|
+
values.push(input.from.slice(0, 10));
|
|
129
|
+
}
|
|
130
|
+
if (input.to) {
|
|
131
|
+
clauses.push("canonical.occurred_day_sp <= ?");
|
|
132
|
+
values.push(input.to.slice(0, 10));
|
|
133
|
+
}
|
|
134
|
+
if (input.query) {
|
|
135
|
+
clauses.push("(work.id LIKE ? OR work.title LIKE ?)");
|
|
136
|
+
values.push(`%${input.query}%`, `%${input.query}%`);
|
|
137
|
+
}
|
|
138
|
+
if (input.status) {
|
|
139
|
+
clauses.push("canonical.stage = ?");
|
|
140
|
+
values.push(input.status);
|
|
141
|
+
}
|
|
142
|
+
if (input.risk) {
|
|
143
|
+
clauses.push("canonical.risk = ?");
|
|
144
|
+
values.push(input.risk);
|
|
145
|
+
}
|
|
146
|
+
if (input.origin) {
|
|
147
|
+
clauses.push("canonical.entity_kind = 'task'");
|
|
148
|
+
const fallback =
|
|
149
|
+
input.origin === "spec"
|
|
150
|
+
? linkedToSpec
|
|
151
|
+
: input.origin === "task"
|
|
152
|
+
? `NOT ${linkedToSpec}`
|
|
153
|
+
: "0";
|
|
154
|
+
clauses.push(`(${changeOrigin} = ? OR (${changeOrigin} IS NULL AND ${fallback}))`);
|
|
155
|
+
values.push(input.origin);
|
|
156
|
+
}
|
|
157
|
+
if (input.kind === "prd" || input.kind === "spec") {
|
|
158
|
+
clauses.push("canonical.entity_kind = ?");
|
|
159
|
+
values.push(input.kind);
|
|
160
|
+
} else if (
|
|
161
|
+
input.kind === "all-tasks" ||
|
|
162
|
+
input.kind === "task" ||
|
|
163
|
+
input.kind === "standalone-task"
|
|
164
|
+
) {
|
|
165
|
+
clauses.push("canonical.entity_kind = 'task'");
|
|
166
|
+
if (input.kind !== "all-tasks")
|
|
167
|
+
clauses.push(input.kind === "task" ? linkedTask : `NOT ${linkedTask}`);
|
|
168
|
+
}
|
|
169
|
+
const source =
|
|
170
|
+
"operations_work_kanban work JOIN canonical_work_items canonical ON canonical.entity_kind=work.entity_kind AND canonical.id=work.id";
|
|
171
|
+
return {
|
|
172
|
+
source,
|
|
173
|
+
where: clauses.length === 0 ? "" : ` WHERE ${clauses.join(" AND ")}`,
|
|
174
|
+
values,
|
|
175
|
+
select: `SELECT work.*, canonical.stage, canonical.spec_id,
|
|
176
|
+
${changeId} AS change_id, ${changeOrigin} AS origin,
|
|
177
|
+
CASE WHEN canonical.entity_kind='task' THEN CASE WHEN ${linkedTask} THEN 'task' ELSE 'standalone-task' END ELSE canonical.entity_kind END AS kind`,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function operationsWorkListSqlPage(
|
|
182
|
+
database: DatabaseSync,
|
|
183
|
+
input: OperationsWorkListQuery & { offset?: number; limit?: number },
|
|
184
|
+
): OperationsWorkListPayloadPage {
|
|
185
|
+
const page = operationsWorkListSql(input);
|
|
186
|
+
const limit = Math.min(200, Math.max(1, input.limit ?? 50));
|
|
187
|
+
const offset = Math.max(0, input.offset ?? 0);
|
|
188
|
+
const total_count = Number(
|
|
189
|
+
(
|
|
190
|
+
database
|
|
191
|
+
.prepare(`SELECT COUNT(*) AS count FROM ${page.source}${page.where}`)
|
|
192
|
+
.get(...page.values) as {
|
|
193
|
+
count: number;
|
|
194
|
+
}
|
|
195
|
+
).count,
|
|
196
|
+
);
|
|
197
|
+
const rows = database
|
|
198
|
+
.prepare(
|
|
199
|
+
`${page.select} FROM ${page.source}${page.where} ORDER BY work.occurred_at DESC, work.id DESC LIMIT ? OFFSET ?`,
|
|
200
|
+
)
|
|
201
|
+
.all(...page.values, limit, offset) as WorkRow[];
|
|
202
|
+
return { offset, limit, total_count, has_more: offset + rows.length < total_count, rows };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function workEntityKind(row: WorkRow): "task" | "spec" | "prd" | null {
|
|
206
|
+
const kind = row.entity_kind ?? row.kind;
|
|
207
|
+
if (kind === "task" || kind === "standalone-task") return "task";
|
|
208
|
+
if (kind === "spec" || kind === "prd") return kind;
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** Adds factual developer identities for only the Work List page IDs. */
|
|
213
|
+
export function attachOperationsWorkListDevelopers(
|
|
214
|
+
database: DatabaseSync,
|
|
215
|
+
rows: readonly WorkRow[],
|
|
216
|
+
input: Pick<OperationsWorkListQuery, "from" | "to">,
|
|
217
|
+
): WorkRow[] {
|
|
218
|
+
const pageItems = rows.flatMap((row) => {
|
|
219
|
+
const entityKind = workEntityKind(row);
|
|
220
|
+
const id = typeof row.id === "string" && row.id.length > 0 ? row.id : null;
|
|
221
|
+
return entityKind && id ? [{ entityKind, id }] : [];
|
|
222
|
+
});
|
|
223
|
+
if (pageItems.length === 0) return rows.map((row) => ({ ...row, developers: [] }));
|
|
224
|
+
|
|
225
|
+
const values = pageItems.flatMap(({ entityKind, id }) => [entityKind, id]);
|
|
226
|
+
const from = input.from?.slice(0, 10) ?? null;
|
|
227
|
+
const to = input.to?.slice(0, 10) ?? null;
|
|
228
|
+
const identities = database
|
|
229
|
+
.prepare(
|
|
230
|
+
`WITH page_items(entity_kind, id) AS (VALUES ${pageItems.map(() => "(?, ?)").join(", ")}),
|
|
231
|
+
identified_developers AS (
|
|
232
|
+
SELECT page_items.entity_kind, page_items.id,
|
|
233
|
+
CAST(activity.developer_account_id AS TEXT) AS account_id,
|
|
234
|
+
MAX(NULLIF(TRIM(activity.developer_login), '')) AS login_snapshot
|
|
235
|
+
FROM page_items
|
|
236
|
+
JOIN zaip_aios_activities activity
|
|
237
|
+
ON activity.payload_type IS NULL
|
|
238
|
+
AND activity.developer_account_id IS NOT NULL
|
|
239
|
+
AND TRIM(activity.developer_account_id) <> ''
|
|
240
|
+
AND (
|
|
241
|
+
(page_items.entity_kind='task' AND activity.task_id=page_items.id)
|
|
242
|
+
OR (page_items.entity_kind='spec' AND activity.spec_id=page_items.id)
|
|
243
|
+
OR (page_items.entity_kind='prd' AND activity.prd_id=page_items.id)
|
|
244
|
+
)
|
|
245
|
+
WHERE (? IS NULL OR activity.occurred_day_sp >= ?)
|
|
246
|
+
AND (? IS NULL OR activity.occurred_day_sp <= ?)
|
|
247
|
+
GROUP BY page_items.entity_kind, page_items.id, CAST(activity.developer_account_id AS TEXT)
|
|
248
|
+
)
|
|
249
|
+
SELECT entity_kind, id, account_id, login_snapshot
|
|
250
|
+
FROM identified_developers
|
|
251
|
+
ORDER BY entity_kind, id, account_id COLLATE BINARY`,
|
|
252
|
+
)
|
|
253
|
+
.all(...values, from, from, to, to) as Array<{
|
|
254
|
+
entity_kind: "task" | "spec" | "prd";
|
|
255
|
+
id: string;
|
|
256
|
+
account_id: string;
|
|
257
|
+
login_snapshot: string | null;
|
|
258
|
+
}>;
|
|
259
|
+
const developersByItem = new Map<string, OperationsWorkListDeveloper[]>();
|
|
260
|
+
for (const identity of identities) {
|
|
261
|
+
const key = `${identity.entity_kind}:${identity.id}`;
|
|
262
|
+
const developers = developersByItem.get(key) ?? [];
|
|
263
|
+
developers.push({ account_id: identity.account_id, login_snapshot: identity.login_snapshot });
|
|
264
|
+
developersByItem.set(key, developers);
|
|
265
|
+
}
|
|
266
|
+
return rows.map((row) => {
|
|
267
|
+
const entityKind = workEntityKind(row);
|
|
268
|
+
const id = typeof row.id === "string" ? row.id : "";
|
|
269
|
+
return {
|
|
270
|
+
...row,
|
|
271
|
+
developers: entityKind ? (developersByItem.get(`${entityKind}:${id}`) ?? []) : [],
|
|
272
|
+
};
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** One physical expansion used only while materializing first-fold payloads. */
|
|
277
|
+
export function operationsWorkListSqlRows(database: DatabaseSync): WorkRow[] {
|
|
278
|
+
const physical = database
|
|
279
|
+
.prepare(
|
|
280
|
+
"SELECT 1 FROM sqlite_master WHERE type='table' AND name='operations_work_projection' LIMIT 1",
|
|
281
|
+
)
|
|
282
|
+
.get();
|
|
283
|
+
if (physical !== undefined)
|
|
284
|
+
return database
|
|
285
|
+
.prepare("SELECT * FROM operations_work_projection ORDER BY occurred_at DESC, id DESC")
|
|
286
|
+
.all() as WorkRow[];
|
|
287
|
+
const page = operationsWorkListSql({ kind: "all" });
|
|
288
|
+
return database
|
|
289
|
+
.prepare(
|
|
290
|
+
`${page.select} FROM ${page.source}${page.where} ORDER BY work.occurred_at DESC, work.id DESC`,
|
|
291
|
+
)
|
|
292
|
+
.all(...page.values) as WorkRow[];
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export function operationsWorkRowsInRange(
|
|
296
|
+
rows: readonly WorkRow[],
|
|
297
|
+
from: string,
|
|
298
|
+
to: string,
|
|
299
|
+
): WorkRow[] {
|
|
300
|
+
return rows.filter((row) => {
|
|
301
|
+
const day = typeof row.occurred_day_sp === "string" ? row.occurred_day_sp : "";
|
|
302
|
+
return day >= from && day <= to;
|
|
303
|
+
});
|
|
304
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { DatabaseSync } from "node:sqlite";
|
|
3
|
+
import { expect } from "vitest";
|
|
4
|
+
|
|
5
|
+
export function expectPersistedFirstFoldCaches(root: string, allTime: unknown, board: unknown) {
|
|
6
|
+
const database = new DatabaseSync(resolve(root, ".local/dashboard-sqlite/read-model.sqlite"), {
|
|
7
|
+
readOnly: true,
|
|
8
|
+
});
|
|
9
|
+
try {
|
|
10
|
+
const read = (payloadType: string) =>
|
|
11
|
+
database
|
|
12
|
+
.prepare("SELECT payload_json FROM zaip_aios_activities WHERE payload_type=?")
|
|
13
|
+
.get(payloadType) as { payload_json: string } | undefined;
|
|
14
|
+
const persistedAllTime = read("first_fold_all_time_cache");
|
|
15
|
+
const persistedBoard = read("first_fold_all_time_board_cache");
|
|
16
|
+
expect(persistedAllTime).toBeDefined();
|
|
17
|
+
expect(persistedBoard).toBeDefined();
|
|
18
|
+
expect(JSON.parse(persistedAllTime!.payload_json)).toEqual(allTime);
|
|
19
|
+
expect(JSON.parse(persistedBoard!.payload_json)).toEqual(board);
|
|
20
|
+
} finally {
|
|
21
|
+
database.close();
|
|
22
|
+
}
|
|
23
|
+
}
|
package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-first-fold-types.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { SqliteFirstFoldAggregate, SqliteSummaryKind } from "./sqlite-read-model.js";
|
|
2
|
+
|
|
3
|
+
export type SqliteFirstFoldAllTime = {
|
|
4
|
+
aggregate: SqliteFirstFoldAggregate & {
|
|
5
|
+
start_day: string | null;
|
|
6
|
+
end_day: string | null;
|
|
7
|
+
task_count: number;
|
|
8
|
+
completed_task_count: number;
|
|
9
|
+
spec_count: number;
|
|
10
|
+
completed_spec_count: number;
|
|
11
|
+
prd_count: number;
|
|
12
|
+
completed_prd_count: number;
|
|
13
|
+
total_cost_usd: number | null;
|
|
14
|
+
latest_task_created_at: string | null;
|
|
15
|
+
};
|
|
16
|
+
task_status_counts: Record<string, number>;
|
|
17
|
+
task_risk_counts: Record<string, number>;
|
|
18
|
+
task_metrics: {
|
|
19
|
+
average_duration_ms_per_task: number | null;
|
|
20
|
+
average_tokens_per_task: number | null;
|
|
21
|
+
average_cost_usd_per_task: number | null;
|
|
22
|
+
average_cost_brl_per_task: number | null;
|
|
23
|
+
latest_task_created_at: string | null;
|
|
24
|
+
};
|
|
25
|
+
top_tasks: Array<{
|
|
26
|
+
rank: number;
|
|
27
|
+
task_id: string;
|
|
28
|
+
title: string;
|
|
29
|
+
status: string | null;
|
|
30
|
+
risk: string | null;
|
|
31
|
+
total_run_count: number;
|
|
32
|
+
llm_call_count: number | null;
|
|
33
|
+
total_duration_ms: number;
|
|
34
|
+
total_tokens: number | null;
|
|
35
|
+
total_cost_usd: number | null;
|
|
36
|
+
total_cost_brl: number | null;
|
|
37
|
+
duration_share: number;
|
|
38
|
+
}>;
|
|
39
|
+
macro_metrics: Record<
|
|
40
|
+
"specs" | "prds",
|
|
41
|
+
{
|
|
42
|
+
status_counts: Record<string, number>;
|
|
43
|
+
classification_counts: Record<string, number>;
|
|
44
|
+
entity_count: number;
|
|
45
|
+
total_run_count: number;
|
|
46
|
+
total_duration_ms: number | null;
|
|
47
|
+
total_tokens: number | null;
|
|
48
|
+
total_cost_usd: number | null;
|
|
49
|
+
total_cost_brl: number | null;
|
|
50
|
+
average_duration_ms: number | null;
|
|
51
|
+
average_tokens: number | null;
|
|
52
|
+
average_cost_usd: number | null;
|
|
53
|
+
average_cost_brl: number | null;
|
|
54
|
+
latest_created_at: string | null;
|
|
55
|
+
top_entities: Array<{
|
|
56
|
+
rank: number;
|
|
57
|
+
entity_id: string;
|
|
58
|
+
title: string;
|
|
59
|
+
status: string | null;
|
|
60
|
+
total_run_count: number;
|
|
61
|
+
llm_call_count: number | null;
|
|
62
|
+
total_duration_ms: number | null;
|
|
63
|
+
total_tokens: number | null;
|
|
64
|
+
total_cost_usd: number | null;
|
|
65
|
+
total_cost_brl: number | null;
|
|
66
|
+
duration_share: number;
|
|
67
|
+
}>;
|
|
68
|
+
}
|
|
69
|
+
>;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export type SqliteFirstFoldMonthlyQuick = {
|
|
73
|
+
from_day: string;
|
|
74
|
+
to_day: string;
|
|
75
|
+
source_latest_day: string | null;
|
|
76
|
+
aggregate: SqliteFirstFoldAggregate;
|
|
77
|
+
pages: Record<SqliteSummaryKind, Array<Record<string, unknown>>>;
|
|
78
|
+
top_tasks: Array<{
|
|
79
|
+
task_id: string;
|
|
80
|
+
total_tokens: number | null;
|
|
81
|
+
cost_brl: number | null;
|
|
82
|
+
run_count: number;
|
|
83
|
+
duration_ms: number;
|
|
84
|
+
}>;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export type SqliteFirstFoldAllTimeBoard = {
|
|
88
|
+
pages: Record<SqliteSummaryKind, Array<Record<string, unknown>>>;
|
|
89
|
+
};
|