@zaip-ai/cli 4.9.0 → 5.1.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.
Files changed (213) hide show
  1. package/dist/services/adapter-hook-sources.d.ts +3 -0
  2. package/dist/services/adapter-hook-sources.d.ts.map +1 -1
  3. package/dist/services/adapter-hook-sources.js +3 -0
  4. package/dist/services/adapter-hook-sources.js.map +1 -1
  5. package/dist/services/adapters.d.ts +1 -1
  6. package/dist/services/adapters.d.ts.map +1 -1
  7. package/dist/services/adapters.js +5 -2
  8. package/dist/services/adapters.js.map +1 -1
  9. package/dist/services/adapters.test.js +1 -1
  10. package/dist/services/adapters.test.js.map +1 -1
  11. package/dist/services/codex-conversation-lifecycle-hook.d.ts.map +1 -1
  12. package/dist/services/codex-conversation-lifecycle-hook.js +16 -6
  13. package/dist/services/codex-conversation-lifecycle-hook.js.map +1 -1
  14. package/dist/services/codex-hook-activation.d.ts +1 -1
  15. package/dist/services/codex-hook-activation.d.ts.map +1 -1
  16. package/dist/services/codex-hook-activation.js +116 -10
  17. package/dist/services/codex-hook-activation.js.map +1 -1
  18. package/dist/services/codex-pre-tool-cli-capture-template.d.ts +2 -0
  19. package/dist/services/codex-pre-tool-cli-capture-template.d.ts.map +1 -0
  20. package/dist/services/codex-pre-tool-cli-capture-template.js +104 -0
  21. package/dist/services/codex-pre-tool-cli-capture-template.js.map +1 -0
  22. package/dist/services/codex-pre-tool-cloud-template.d.ts +2 -0
  23. package/dist/services/codex-pre-tool-cloud-template.d.ts.map +1 -0
  24. package/dist/services/codex-pre-tool-cloud-template.js +190 -0
  25. package/dist/services/codex-pre-tool-cloud-template.js.map +1 -0
  26. package/dist/services/codex-pre-tool-dependencies.test-support.d.ts +2 -0
  27. package/dist/services/codex-pre-tool-dependencies.test-support.d.ts.map +1 -0
  28. package/dist/services/codex-pre-tool-dependencies.test-support.js +9 -0
  29. package/dist/services/codex-pre-tool-dependencies.test-support.js.map +1 -0
  30. package/dist/services/codex-pre-tool-hook-fixture.test-support.d.ts +5 -0
  31. package/dist/services/codex-pre-tool-hook-fixture.test-support.d.ts.map +1 -0
  32. package/dist/services/codex-pre-tool-hook-fixture.test-support.js +19 -0
  33. package/dist/services/codex-pre-tool-hook-fixture.test-support.js.map +1 -0
  34. package/dist/services/codex-pre-tool-hook-template-bootstrap.test.d.ts +2 -0
  35. package/dist/services/codex-pre-tool-hook-template-bootstrap.test.d.ts.map +1 -0
  36. package/dist/services/codex-pre-tool-hook-template-bootstrap.test.js +107 -0
  37. package/dist/services/codex-pre-tool-hook-template-bootstrap.test.js.map +1 -0
  38. package/dist/services/codex-pre-tool-hook-template.d.ts.map +1 -1
  39. package/dist/services/codex-pre-tool-hook-template.js +96 -210
  40. package/dist/services/codex-pre-tool-hook-template.js.map +1 -1
  41. package/dist/services/codex-pre-tool-hook-template.test.js +32 -80
  42. package/dist/services/codex-pre-tool-hook-template.test.js.map +1 -1
  43. package/dist/services/codex-pre-tool-host-context-template.d.ts +2 -0
  44. package/dist/services/codex-pre-tool-host-context-template.d.ts.map +1 -0
  45. package/dist/services/codex-pre-tool-host-context-template.js +139 -0
  46. package/dist/services/codex-pre-tool-host-context-template.js.map +1 -0
  47. package/dist/services/codex-pre-tool-support-template.d.ts.map +1 -1
  48. package/dist/services/codex-pre-tool-support-template.js +61 -101
  49. package/dist/services/codex-pre-tool-support-template.js.map +1 -1
  50. package/dist/services/codex-subagent-hook-template.d.ts +1 -1
  51. package/dist/services/codex-subagent-hook-template.d.ts.map +1 -1
  52. package/dist/services/codex-subagent-hook-template.js +13 -2
  53. package/dist/services/codex-subagent-hook-template.js.map +1 -1
  54. package/dist/services/codex-validation-runtime-template.d.ts.map +1 -1
  55. package/dist/services/codex-validation-runtime-template.js +10 -4
  56. package/dist/services/codex-validation-runtime-template.js.map +1 -1
  57. package/dist/services/runtime-template-test-support.d.ts +1 -0
  58. package/dist/services/runtime-template-test-support.d.ts.map +1 -1
  59. package/dist/services/runtime-template-test-support.js +23 -2
  60. package/dist/services/runtime-template-test-support.js.map +1 -1
  61. package/dist/services/runtime-template.test.js +4 -23
  62. package/dist/services/runtime-template.test.js.map +1 -1
  63. package/package.json +1 -1
  64. package/templates/.agents/README-ENG.md +58 -7
  65. package/templates/.agents/README.md +46 -10
  66. package/templates/.agents/config/agents/discovery.json +1 -1
  67. package/templates/.agents/dashboard/.zaip-managed.json +174 -86
  68. package/templates/.agents/dashboard/apps/frontend/dist/assets/{CostCalculationGuidePage-BW7Vy1cp.js → CostCalculationGuidePage-uR-asJv_.js} +1 -1
  69. package/templates/.agents/dashboard/apps/frontend/dist/assets/{DashboardHelpDialog-Cp_hEVd8.js → DashboardHelpDialog-CngnpoLL.js} +87 -13
  70. package/templates/.agents/dashboard/apps/frontend/dist/assets/{PricingSettingsDialog-Prcs-ydy.js → PricingSettingsDialog-Bszw3ekd.js} +1 -1
  71. package/templates/.agents/dashboard/apps/frontend/dist/assets/{ProjectSettingsPage-Cu40wAFF.js → ProjectSettingsPage-IJ1znG4w.js} +1 -1
  72. package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-Bh3YBd3C.js → TraceabilityWorkspace-CsBpHqq_.js} +1 -1
  73. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-B0Jwz_rk.js +68 -0
  74. package/templates/.agents/dashboard/apps/frontend/dist/assets/{dashboard-localization-CF7B1Hjn.js → dashboard-localization-D41g5rdo.js} +58 -7
  75. package/templates/.agents/dashboard/apps/frontend/dist/assets/{icons-vendor-DOhy6D2-.js → icons-vendor-CjGGux6h.js} +1 -1
  76. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-Bedlm0f7.js +2 -0
  77. package/templates/.agents/dashboard/apps/frontend/dist/assets/{react-vendor-CkPC-yMz.js → react-vendor-B9jZSAKf.js} +1 -1
  78. package/templates/.agents/dashboard/apps/frontend/dist/assets/{traceability-BEdGoIDm.js → traceability-DFpwb0TN.js} +1 -1
  79. package/templates/.agents/dashboard/apps/frontend/dist/index.html +5 -5
  80. package/templates/.agents/dashboard/apps/frontend/package.json +2 -2
  81. package/templates/.agents/dashboard/apps/frontend/src/AppDashboardContent.tsx +3 -0
  82. package/templates/.agents/dashboard/apps/frontend/src/AppOverlays.tsx +16 -7
  83. package/templates/.agents/dashboard/apps/frontend/src/__tests__/app-composition-support.ts +1 -0
  84. package/templates/.agents/dashboard/apps/frontend/src/cost-period-refresh.test.ts +1 -1
  85. package/templates/.agents/dashboard/apps/frontend/src/operations-period-render.test.ts +2 -0
  86. package/templates/.agents/dashboard/apps/frontend/src/use-app-trace-documents.navigation.test.tsx +125 -0
  87. package/templates/.agents/dashboard/apps/frontend/src/use-app-trace-documents.ts +67 -9
  88. package/templates/.agents/dashboard/apps/frontend/src/use-dashboard-app-model.tsx +15 -15
  89. package/templates/.agents/dashboard/apps/frontend/src/use-dashboard-locale.ts +18 -0
  90. package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
  91. package/templates/.agents/dashboard/modules/cost-monitor/src/contracts.ts +10 -3
  92. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostFilters.run-page.test.ts +5 -1
  93. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostGroupsTable.period-values.test.tsx +2 -2
  94. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables-keeps-legacy-codex-identity-fields-blank.test.ts +5 -5
  95. package/templates/.agents/dashboard/modules/cost-monitor/src/react/CostTables.test.ts +36 -43
  96. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-monitor-loaders.ts +1 -0
  97. package/templates/.agents/dashboard/modules/cost-monitor/src/react/cost-table-formatters.ts +6 -4
  98. package/templates/.agents/dashboard/modules/cost-monitor/src/server/aggregate.ts +2 -2
  99. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-monitor-projection.ts +1 -1
  100. package/templates/.agents/dashboard/modules/cost-monitor/src/server/build-cost-summary-projection.ts +11 -25
  101. package/templates/.agents/dashboard/modules/cost-monitor/src/server/cost-summary-defaults.ts +26 -0
  102. package/templates/.agents/dashboard/modules/operations/package.json +1 -1
  103. package/templates/.agents/dashboard/modules/operations/src/contracts.ts +11 -16
  104. package/templates/.agents/dashboard/modules/operations/src/planning-contracts.ts +14 -0
  105. package/templates/.agents/dashboard/modules/operations/src/react/DecisionTable.tsx +65 -0
  106. package/templates/.agents/dashboard/modules/operations/src/react/EntityTables.tsx +5 -71
  107. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverview.tsx +4 -39
  108. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverviewTopPanel.navigation.test.tsx +150 -0
  109. package/templates/.agents/dashboard/modules/operations/src/react/OperationsOverviewTopPanel.tsx +7 -3
  110. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPage.tsx +14 -43
  111. package/templates/.agents/dashboard/modules/operations/src/react/OperationsPageOverview.tsx +3 -0
  112. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-contract.ts +51 -0
  113. package/templates/.agents/dashboard/modules/operations/src/react/operations-overview-period-filter.test.ts +12 -3
  114. package/templates/.agents/dashboard/modules/operations/src/react/operations-page-contract.ts +1 -0
  115. package/templates/.agents/dashboard/modules/operations/src/react/use-operations-default-range.ts +16 -0
  116. package/templates/.agents/dashboard/modules/operations/src/react/use-operations-filter-sync.ts +66 -0
  117. package/templates/.agents/dashboard/modules/traceability/package.json +1 -1
  118. package/templates/.agents/dashboard/packages/branding/package.json +1 -1
  119. package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
  120. package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
  121. package/templates/.agents/dashboard/packages/local-runtime/dashboard-build-fingerprint.mjs +87 -0
  122. package/templates/.agents/dashboard/packages/local-runtime/dashboard-build-fingerprint.test.mjs +48 -0
  123. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +193 -191
  124. package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +169 -169
  125. package/templates/.agents/dashboard/packages/local-runtime/package.json +1 -1
  126. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-frontend.mjs +29 -0
  127. package/templates/.agents/dashboard/packages/local-runtime/scripts/build-sqlite-runtime.mjs +5 -0
  128. package/templates/.agents/dashboard/packages/local-runtime/server.mjs +193 -191
  129. package/templates/.agents/dashboard/packages/local-runtime/src/active-capture-failure.test.ts +38 -0
  130. package/templates/.agents/dashboard/packages/local-runtime/src/active-capture-failure.ts +35 -0
  131. package/templates/.agents/dashboard/packages/local-runtime/src/active-codex-telemetry.test.ts +53 -2
  132. package/templates/.agents/dashboard/packages/local-runtime/src/active-codex-telemetry.ts +18 -1
  133. package/templates/.agents/dashboard/packages/local-runtime/src/manifest-runs.ts +8 -2
  134. package/templates/.agents/dashboard/packages/local-runtime/src/server-capture-projection-order.test.ts +118 -0
  135. package/templates/.agents/dashboard/packages/local-runtime/src/server-cost-run-search.test.ts +90 -0
  136. package/templates/.agents/dashboard/packages/local-runtime/src/server-cost-run-search.ts +86 -0
  137. package/templates/.agents/dashboard/packages/local-runtime/src/server-operations-routes.ts +8 -1
  138. package/templates/.agents/dashboard/packages/local-runtime/src/server-projection-loaders.ts +13 -0
  139. package/templates/.agents/dashboard/packages/local-runtime/src/server-projections.ts +30 -74
  140. package/templates/.agents/dashboard/packages/local-runtime/src/server-route-handlers.ts +42 -0
  141. package/templates/.agents/dashboard/packages/local-runtime/src/server-routes.test.ts +60 -0
  142. package/templates/.agents/dashboard/packages/local-runtime/src/server-run-projections.test.ts +12 -2
  143. package/templates/.agents/dashboard/packages/local-runtime/src/server-telemetry-command.test.ts +29 -4
  144. package/templates/.agents/dashboard/packages/local-runtime/src/server-telemetry-refresh.ts +7 -0
  145. package/templates/.agents/dashboard/packages/local-runtime/src/server.test.ts +51 -54
  146. package/templates/.agents/dashboard/packages/local-runtime/src/server.ts +28 -45
  147. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-filter-matrix.test.ts +5 -0
  148. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.test.ts +49 -0
  149. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-cost-invocation-page.ts +44 -1
  150. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-cached-cost-page.ts +11 -10
  151. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-query-summary.ts +1 -1
  152. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-work-item-index.test.ts +18 -1
  153. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-build.mjs +12 -5
  154. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard-paths.mjs +8 -0
  155. package/templates/.agents/dashboard/packages/local-runtime/start-dashboard.test.mjs +1 -0
  156. package/templates/.agents/dashboard/packages/ui/package.json +1 -1
  157. package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
  158. package/templates/.agents/dashboard/tests/e2e/qualify-top-five-trace.mjs +53 -0
  159. package/templates/.agents/dashboard/tests/e2e/verify-top-five-served.mjs +78 -0
  160. package/templates/.agents/design/.zaip-managed.json +14 -6
  161. package/templates/.agents/design/apps/catalog/dist/assets/index-BGxXxXTo.js +72 -0
  162. package/templates/.agents/design/apps/catalog/dist/index.html +1 -1
  163. package/templates/.agents/design/apps/catalog/package.json +1 -1
  164. package/templates/.agents/design/apps/catalog/src/components/TopEntitiesSpecimen.tsx +45 -0
  165. package/templates/.agents/design/apps/catalog/src/pages/ComponentsPage.tsx +3 -1
  166. package/templates/.agents/design/apps/catalog/src/stories/Components.stories.tsx +2 -0
  167. package/templates/.agents/design/packages/local-runtime/package.json +1 -1
  168. package/templates/.agents/requirements/autonomous-assurance.md +11 -2
  169. package/templates/.agents/requirements/cloud-hostinger-autonomy.md +1 -1
  170. package/templates/.agents/requirements/comparative-audit.md +1 -1
  171. package/templates/.agents/requirements/context-engine.md +1 -1
  172. package/templates/.agents/requirements/cost-observability.md +1 -1
  173. package/templates/.agents/requirements/dashboard-launch.md +1 -1
  174. package/templates/.agents/requirements/data-export.md +1 -1
  175. package/templates/.agents/requirements/design-system.md +1 -1
  176. package/templates/.agents/requirements/execution-engine.md +1 -1
  177. package/templates/.agents/requirements/kanban-dashboard.md +1 -1
  178. package/templates/.agents/requirements/model-orchestration.md +1 -1
  179. package/templates/.agents/requirements/public-distribution.md +1 -1
  180. package/templates/.agents/requirements/software-architecture.md +1 -1
  181. package/templates/.agents/requirements/strategic-improvements.md +1 -1
  182. package/templates/.agents/requirements/work-lifecycle.md +2 -1
  183. package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
  184. package/templates/.agents/rules/run-lifecycle-closure.md +2 -1
  185. package/templates/.agents/rules/workflow.md +1 -0
  186. package/templates/.agents/runtime/VERSION +1 -1
  187. package/templates/.agents/runtime/bin/zaip.mjs +1178 -764
  188. package/templates/.agents/runtime/checksums.sha256 +6 -6
  189. package/templates/.agents/runtime/manifest.json +1 -1
  190. package/templates/.agents/runtime/pnpm-lock.sha256 +1 -1
  191. package/templates/.agents/runtime/provenance.json +5 -5
  192. package/templates/.agents/runtime/sbom.cdx.json +59 -59
  193. package/templates/.agents/skills/zaip-skill-execution/SKILL.md +1 -1
  194. package/templates/.agents/skills/zaip-skill-execution/references/controlled-release-recovery.md +14 -0
  195. package/templates/.agents/skills/zaip-skill-execution/references/runtime-governance.md +1 -1
  196. package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +5 -1
  197. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/deploy-contract-cli.test.mjs +53 -0
  198. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/deploy-contract.mjs +12 -0
  199. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/deploy-contract.test.mjs +26 -32
  200. package/templates/.agents/skills/zaip-skill-maintenance-enter/SKILL.md +23 -0
  201. package/templates/.agents/skills/zaip-skill-maintenance-enter/agents/openai.yaml +4 -0
  202. package/templates/.agents/skills/zaip-skill-maintenance-enter/scripts/maintenance.mjs +213 -0
  203. package/templates/.agents/skills/zaip-skill-maintenance-enter/scripts/maintenance.test.mjs +207 -0
  204. package/templates/.agents/skills/zaip-skill-maintenance-exit/SKILL.md +21 -0
  205. package/templates/.agents/skills/zaip-skill-maintenance-exit/agents/openai.yaml +4 -0
  206. package/templates/.agents/skills/zaip-skill-release-qualification/SKILL.md +2 -0
  207. package/templates/.agents/skills/zaip-skill-release-qualification/references/local-preparation.md +37 -8
  208. package/templates/.agents/zaip-aios/VERSION +1 -1
  209. package/templates/.agents/zaip-aios/guides/10-seguranca.md +2 -2
  210. package/templates/.agents/zaip-aios/guides/26-qualidade-e-release.md +38 -0
  211. package/templates/template-manifest.json +259 -135
  212. package/templates/.agents/dashboard/apps/frontend/dist/assets/cost-monitor-Co2Jiuzh.js +0 -68
  213. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-qVSJnJ0_.js +0 -2
@@ -35,12 +35,12 @@ export function AppOverlays({
35
35
  documentDetail,
36
36
  helpOpen,
37
37
  loadingArea,
38
- operations,
39
38
  reconciliationResult,
40
39
  refreshDialog,
41
40
  showTrace,
42
41
  trace,
43
42
  traceLink,
43
+ traceMacroLoading,
44
44
  traceLoadingTaskId,
45
45
  closeDocument,
46
46
  onCloseHelp,
@@ -65,8 +65,14 @@ export function AppOverlays({
65
65
  trace: TaskTrace | null;
66
66
  traceLink:
67
67
  | { kind: "change"; row: ChangeProjection }
68
- | { kind: "macro"; label: "PRD" | "SPEC"; row: MacroProjection }
68
+ | {
69
+ kind: "macro";
70
+ label: "PRD" | "SPEC";
71
+ row: MacroProjection;
72
+ projection: OperationsProjection;
73
+ }
69
74
  | null;
75
+ traceMacroLoading: { label: "PRD" | "SPEC"; id: string } | null;
70
76
  traceLoadingTaskId: string | null;
71
77
  closeDocument: () => void;
72
78
  onCloseHelp: () => void;
@@ -112,9 +118,9 @@ export function AppOverlays({
112
118
  onOpenTrace(taskId);
113
119
  }}
114
120
  row={traceLink.row}
115
- runs={operations.runs}
116
- specs={operations.specs}
117
- tasks={operations.tasks}
121
+ runs={traceLink.projection.runs}
122
+ specs={traceLink.projection.specs}
123
+ tasks={traceLink.projection.tasks}
118
124
  />
119
125
  ) : null}
120
126
  {documentDetail ? (
@@ -190,8 +196,11 @@ export function AppOverlays({
190
196
  onDismiss={onDismissReconciliation}
191
197
  />
192
198
  ) : null}
193
- {loadingArea !== null && refreshDialog === null ? (
194
- <DashboardLoadingNotice area={loadingArea} locale={costLocale} />
199
+ {(loadingArea !== null || traceMacroLoading !== null) && refreshDialog === null ? (
200
+ <DashboardLoadingNotice
201
+ area={traceMacroLoading === null ? (loadingArea ?? "operations") : "operations"}
202
+ locale={costLocale}
203
+ />
195
204
  ) : null}
196
205
  </>
197
206
  );
@@ -3,6 +3,7 @@ import { readFileSync } from "node:fs";
3
3
  export function readAppCompositionSource(): string {
4
4
  return [
5
5
  "use-dashboard-app-model.tsx",
6
+ "use-dashboard-locale.ts",
6
7
  "AppDashboardContent.tsx",
7
8
  "use-app-work-board.ts",
8
9
  "dashboard-cost-facts.ts",
@@ -73,7 +73,7 @@ describe("Cost period refresh", () => {
73
73
  expect(activeCostReload).toContain(
74
74
  "[costs?.currency, currency, failedArea, loadCostSummary, operations]",
75
75
  );
76
- expect(app).toContain("}, [api, currency, operationsPeriod]);");
76
+ expect(app).toContain("}, [api, currency, operationsPeriod, currencyRef]);");
77
77
  expect(app).toContain("costsLoadedRef.current = false;");
78
78
  });
79
79
 
@@ -37,6 +37,7 @@ function renderPeriod(preset: "today" | "yesterday", loading = false) {
37
37
  onDateChange: vi.fn(),
38
38
  onLocaleChange: vi.fn(),
39
39
  onOpenDocument: vi.fn(),
40
+ onOpenMacro: vi.fn(),
40
41
  onOpenTask: vi.fn(async () => false),
41
42
  onPriorityChange: vi.fn(async () => undefined),
42
43
  onRefresh: vi.fn(),
@@ -92,6 +93,7 @@ describe("App-owned Operations period render", () => {
92
93
  onDateChange: vi.fn(),
93
94
  onLocaleChange: vi.fn(),
94
95
  onOpenDocument: vi.fn(),
96
+ onOpenMacro: vi.fn(),
95
97
  onOpenTask: vi.fn(async () => false),
96
98
  onPriorityChange: vi.fn(async () => undefined),
97
99
  onRefresh: vi.fn(),
@@ -0,0 +1,125 @@
1
+ import { createRequire } from "node:module";
2
+ import { fileURLToPath } from "node:url";
3
+ import { describe, expect, it } from "vitest";
4
+
5
+ const browserRequire = createRequire(
6
+ fileURLToPath(new URL("../../../tests/e2e/package.json", import.meta.url)),
7
+ );
8
+ const { chromium, expect: browserExpect } = browserRequire("@playwright/test");
9
+
10
+ describe("macro trace navigation from a compact overview", () => {
11
+ it("hydrates exact macro details, keeps linked rows, and ignores stale macro and Task requests", async () => {
12
+ const esbuild = browserRequire("esbuild");
13
+ const harness = await esbuild.build({
14
+ bundle: true,
15
+ format: "iife",
16
+ logLevel: "silent",
17
+ platform: "browser",
18
+ write: false,
19
+ stdin: {
20
+ contents: `
21
+ import React, { useState } from "react";
22
+ import { createRoot } from "react-dom/client";
23
+ import { useAppTraceDocuments } from "./use-app-trace-documents.js";
24
+
25
+ const pending = [];
26
+ window.__macroTraceProbe = { pending };
27
+ const api = {
28
+ operations: (_period, _scope, signal) => new Promise((resolve) => {
29
+ pending.push({ resolve, signal });
30
+ }),
31
+ taskTrace: async (id) => ({ task_id: id, task_title: id }),
32
+ prd: async (id) => ({ id, title: id, body: "Full document", artifact_path: "prds/one.md" }),
33
+ };
34
+ function Harness() {
35
+ const [error, setError] = useState(null);
36
+ const [, setFailedArea] = useState(null);
37
+ const [, setLoadingArea] = useState(null);
38
+ const state = useAppTraceDocuments({
39
+ api,
40
+ operations: { prds: [], specs: [], tasks: [], runs: [], changes: [] },
41
+ isOperationsDetailLoaded: () => false,
42
+ setError,
43
+ setFailedArea,
44
+ setLoadingArea,
45
+ });
46
+ return <>
47
+ <button onClick={() => void state.openTraceMacro("SPEC", "SPEC-TARGET")}>Open SPEC</button>
48
+ <button onClick={() => void state.openTraceMacro("PRD", "PRD-TARGET")}>Open PRD</button>
49
+ <button onClick={() => void state.openTrace("TASK-TARGET")}>Open Task</button>
50
+ <button onClick={() => void state.openDocument("prd", "PRD-TARGET")}>Read PRD</button>
51
+ <output id="state">{JSON.stringify({
52
+ macro: state.traceLink?.kind === "macro" ? state.traceLink.row.id : null,
53
+ kind: state.traceLink?.kind === "macro" ? state.traceLink.row.kind : null,
54
+ linkedTaskIds: state.traceLink?.kind === "macro"
55
+ ? state.traceLink.projection.tasks.map((row) => row.id) : [],
56
+ loading: state.traceMacroLoading?.id ?? null,
57
+ task: state.trace?.task_id ?? null,
58
+ document: state.documentDetail?.preview.id ?? null,
59
+ error,
60
+ })}</output>
61
+ </>;
62
+ }
63
+ createRoot(document.getElementById("root")).render(<Harness />);
64
+ `,
65
+ loader: "tsx",
66
+ resolveDir: fileURLToPath(new URL(".", import.meta.url)),
67
+ sourcefile: "macro-trace-navigation-harness.tsx",
68
+ },
69
+ });
70
+ const browser = await chromium.launch({ headless: true });
71
+ try {
72
+ const page = await browser.newPage();
73
+ const pageErrors: string[] = [];
74
+ page.on("pageerror", (error: Error) => pageErrors.push(error.message));
75
+ await page.setContent('<div id="root"></div>');
76
+ await page.addScriptTag({ content: harness.outputFiles[0].text });
77
+ const state = () => page.locator("#state");
78
+ const resolve = (index: number, prds: unknown[], specs: unknown[]) =>
79
+ page.evaluate(
80
+ ({ index, prds, specs }: { index: number; prds: unknown[]; specs: unknown[] }) => {
81
+ const request = (
82
+ window as typeof window & {
83
+ __macroTraceProbe: { pending: Array<{ resolve: (value: unknown) => void }> };
84
+ }
85
+ ).__macroTraceProbe.pending[index];
86
+ if (!request) throw new Error(`Missing pending macro request ${index}`);
87
+ request.resolve({
88
+ prds,
89
+ specs,
90
+ tasks: [{ id: "TASK-LINKED" }],
91
+ runs: [],
92
+ });
93
+ },
94
+ { index, prds, specs },
95
+ );
96
+
97
+ await page.getByRole("button", { name: "Open SPEC" }).click();
98
+ await browserExpect(state()).toContainText('"loading":"SPEC-TARGET"');
99
+ await page.getByRole("button", { name: "Open PRD" }).click();
100
+ await browserExpect(state()).toContainText('"loading":"PRD-TARGET"');
101
+ await resolve(0, [], [{ id: "SPEC-TARGET", kind: "spec" }]);
102
+ await browserExpect(state()).toContainText('"macro":null');
103
+ await resolve(1, [{ id: "PRD-TARGET", kind: "prd" }], []);
104
+ await browserExpect(state()).toContainText('"macro":"PRD-TARGET"');
105
+ await browserExpect(state()).toContainText('"linkedTaskIds":["TASK-LINKED"]');
106
+ await page.getByRole("button", { name: "Read PRD" }).click();
107
+ await browserExpect(state()).toContainText('"document":"PRD-TARGET"');
108
+
109
+ await page.getByRole("button", { name: "Open SPEC" }).click();
110
+ await page.getByRole("button", { name: "Open Task" }).click();
111
+ await browserExpect(state()).toContainText('"task":"TASK-TARGET"');
112
+ await resolve(2, [], [{ id: "SPEC-TARGET", kind: "spec" }]);
113
+ await browserExpect(state()).toContainText('"macro":null');
114
+
115
+ await page.getByRole("button", { name: "Open PRD" }).click();
116
+ await resolve(3, [{ id: "PRD-OTHER", kind: "prd" }], []);
117
+ await browserExpect(state()).toContainText('"error":"PRD PRD-TARGET not found"');
118
+ await browserExpect(state()).toContainText('"loading":null');
119
+ expect(pageErrors).toEqual([]);
120
+ await page.close();
121
+ } finally {
122
+ await browser.close();
123
+ }
124
+ }, 60_000);
125
+ });
@@ -13,12 +13,14 @@ import type { DashboardApiClient } from "./dashboard-api.js";
13
13
  export function useAppTraceDocuments({
14
14
  api,
15
15
  operations,
16
+ isOperationsDetailLoaded,
16
17
  setError,
17
18
  setFailedArea,
18
19
  setLoadingArea,
19
20
  }: {
20
21
  api: DashboardApiClient;
21
22
  operations: OperationsProjection | null;
23
+ isOperationsDetailLoaded: () => boolean;
22
24
  setError: Dispatch<SetStateAction<string | null>>;
23
25
  setFailedArea: Dispatch<SetStateAction<LoadingArea | null>>;
24
26
  setLoadingArea: Dispatch<SetStateAction<LoadingArea | null>>;
@@ -34,16 +36,31 @@ export function useAppTraceDocuments({
34
36
  } | null>(null);
35
37
  const [traceLink, setTraceLink] = useState<
36
38
  | { kind: "change"; row: ChangeProjection }
37
- | { kind: "macro"; label: "PRD" | "SPEC"; row: MacroProjection }
39
+ | {
40
+ kind: "macro";
41
+ label: "PRD" | "SPEC";
42
+ row: MacroProjection;
43
+ projection: OperationsProjection;
44
+ }
38
45
  | null
39
46
  >(null);
40
47
  const documentRequestId = useRef(0);
41
48
  const traceRequestId = useRef(0);
49
+ const macroRequestId = useRef(0);
50
+ const macroAbortController = useRef<AbortController | null>(null);
51
+ const [traceMacroLoading, setTraceMacroLoading] = useState<{
52
+ label: "PRD" | "SPEC";
53
+ id: string;
54
+ } | null>(null);
42
55
  const traceAbortController = useRef<AbortController | null>(null);
43
56
  const [traceLoadingTaskId, setTraceLoadingTaskId] = useState<string | null>(null);
44
57
  const [selectedTraceTaskId, setSelectedTraceTaskId] = useState("");
45
58
 
46
59
  async function openTrace(taskId: string) {
60
+ macroRequestId.current += 1;
61
+ macroAbortController.current?.abort();
62
+ setTraceMacroLoading(null);
63
+ setTraceLink(null);
47
64
  const requestId = ++traceRequestId.current;
48
65
  traceAbortController.current?.abort();
49
66
  const controller = new AbortController();
@@ -92,18 +109,58 @@ export function useAppTraceDocuments({
92
109
  setTraceLink({ kind: "change", row });
93
110
  }
94
111
 
95
- function openTraceMacro(label: "PRD" | "SPEC", id: string) {
96
- const rows = label === "PRD" ? operations?.prds : operations?.specs;
97
- const row = rows?.find((macro) => macro.id === id);
98
- if (row === undefined) return;
112
+ async function openTraceMacro(label: "PRD" | "SPEC", id: string) {
113
+ const requestId = ++macroRequestId.current;
114
+ macroAbortController.current?.abort();
115
+ macroAbortController.current = null;
116
+ traceRequestId.current += 1;
117
+ traceAbortController.current?.abort();
118
+ traceAbortController.current = null;
119
+ setTraceLoadingTaskId(null);
120
+ setLoadingArea((current) => (current === "traceability" ? null : current));
121
+ setError(null);
122
+ setFailedArea(null);
99
123
  setTrace(null);
100
- setTraceLink({ kind: "macro", label, row });
124
+ setTraceLink(null);
125
+ const rows = label === "PRD" ? operations?.prds : operations?.specs;
126
+ const existing = rows?.find((macro) => macro.id === id && macro.kind === label.toLowerCase());
127
+ if (existing && operations && isOperationsDetailLoaded()) {
128
+ setTraceMacroLoading(null);
129
+ setTraceLink({ kind: "macro", label, row: existing, projection: operations });
130
+ return;
131
+ }
132
+ const controller = new AbortController();
133
+ macroAbortController.current = controller;
134
+ setTraceMacroLoading({ label, id });
135
+ try {
136
+ // The compact first fold has ranking IDs but omits macro and linked Task rows.
137
+ // Hydrate only after the user requests this traceability dialog.
138
+ const projection = await api.operations(undefined, "detail", controller.signal);
139
+ if (requestId !== macroRequestId.current || controller.signal.aborted) return;
140
+ const row = (label === "PRD" ? projection.prds : projection.specs).find(
141
+ (macro) => macro.id === id && macro.kind === label.toLowerCase(),
142
+ );
143
+ if (!row) throw new Error(`${label} ${id} not found`);
144
+ setTraceLink({ kind: "macro", label, row, projection });
145
+ } catch (cause) {
146
+ if (requestId !== macroRequestId.current || controller.signal.aborted) return;
147
+ setError(cause instanceof Error ? cause.message : String(cause));
148
+ } finally {
149
+ if (requestId === macroRequestId.current) {
150
+ if (macroAbortController.current === controller) macroAbortController.current = null;
151
+ setTraceMacroLoading(null);
152
+ }
153
+ }
101
154
  }
102
155
 
103
156
  async function openDocument(kind: "prd" | "spec", id: string) {
104
- const preview = (kind === "prd" ? operations?.prds : operations?.specs)?.find(
105
- (macro) => macro.id === id,
106
- );
157
+ const preview =
158
+ (kind === "prd" ? operations?.prds : operations?.specs)?.find((macro) => macro.id === id) ??
159
+ (traceLink?.kind === "macro"
160
+ ? (kind === "prd" ? traceLink.projection.prds : traceLink.projection.specs).find(
161
+ (macro) => macro.id === id,
162
+ )
163
+ : undefined);
107
164
  if (!preview) return;
108
165
  const requestId = ++documentRequestId.current;
109
166
  const label = kind === "prd" ? "PRD" : "SPEC";
@@ -143,6 +200,7 @@ export function useAppTraceDocuments({
143
200
  setTraceTasks,
144
201
  trace,
145
202
  traceLink,
203
+ traceMacroLoading,
146
204
  traceLoadingTaskId,
147
205
  traceTasks,
148
206
  };
@@ -62,6 +62,7 @@ import { useAppTraceDocuments } from "./use-app-trace-documents.js";
62
62
  import { useAppTraceTaskPagination } from "./use-app-trace-task-pagination.js";
63
63
  import { useAppWorkBoard } from "./use-app-work-board.js";
64
64
  import { useAppWorkListPage } from "./use-app-work-list-page.js";
65
+ import { useDashboardLocale } from "./use-dashboard-locale.js";
65
66
  import { useOperationsDetailExport } from "./use-operations-detail-export.js";
66
67
  import { useSnapshotNotice } from "./use-snapshot-notice.js";
67
68
  import "./loading-feedback.css";
@@ -103,18 +104,8 @@ export function useDashboardAppModel() {
103
104
  useState<OverviewClassificationPages>({});
104
105
  const [costs, setCosts] = useState<CostMonitorProjection | null>(null);
105
106
  const [displayedCosts, setDisplayedCosts] = useState<CostMonitorProjection | null>(null);
106
- const [costLocale, setCostLocale] = useState<CostLocale>(savedLocale);
107
- const [currency, setCurrency] = useState<CostCurrency>(() =>
108
- window.localStorage.getItem(currencyKey) === "USD" ? "USD" : "BRL",
109
- );
110
- const currencyRef = useRef(currency);
111
- currencyRef.current = currency;
112
- // Language is the global selector's source of truth for the paired display
113
- // currency, so Operations and Cost Monitor cannot diverge.
114
- const changeDashboardLocale = useCallback((next: CostLocale) => {
115
- setCostLocale(next);
116
- setCurrency(next === "en-US" ? "USD" : "BRL");
117
- }, []);
107
+ const { costLocale, currency, setCurrency, currencyRef, changeDashboardLocale } =
108
+ useDashboardLocale();
118
109
  const [operationsPeriod, setOperationsPeriod] = useState(() => defaultOperationsPeriod);
119
110
  // All Time may update its displayed factual range without changing the
120
111
  // unbounded request identity. Keep the refresh callback stable for that
@@ -174,6 +165,7 @@ export function useDashboardAppModel() {
174
165
  cancelled = true;
175
166
  };
176
167
  }, [api, applyDashboardIdentity]);
168
+ const operationsDetailLoadedRef = useRef(false);
177
169
  const {
178
170
  closeDocument,
179
171
  documentDetail,
@@ -181,6 +173,7 @@ export function useDashboardAppModel() {
181
173
  openTrace,
182
174
  openTraceChange,
183
175
  openTraceMacro,
176
+ traceMacroLoading,
184
177
  selectedTraceTaskId,
185
178
  setSelectedTraceTaskId,
186
179
  setTrace,
@@ -191,7 +184,14 @@ export function useDashboardAppModel() {
191
184
  traceLink,
192
185
  traceLoadingTaskId,
193
186
  traceTasks,
194
- } = useAppTraceDocuments({ api, operations, setError, setFailedArea, setLoadingArea });
187
+ } = useAppTraceDocuments({
188
+ api,
189
+ operations,
190
+ isOperationsDetailLoaded: () => operationsDetailLoadedRef.current,
191
+ setError,
192
+ setFailedArea,
193
+ setLoadingArea,
194
+ });
195
195
  const { loadMoreTraceTasks, traceTasksHasMore, traceTasksLoading } = useAppTraceTaskPagination(
196
196
  api,
197
197
  traceTasks,
@@ -205,7 +205,6 @@ export function useDashboardAppModel() {
205
205
  const costSummaryRequestVersion = useRef(0);
206
206
  const costSummaryAbortRef = useRef<AbortController | null>(null);
207
207
  const costsLoadedRef = useRef(false);
208
- const operationsDetailLoadedRef = useRef(false);
209
208
  const operationsDetailCancelRef = useRef<(() => void) | null>(null);
210
209
  const operationsDetailAbortRef = useRef<AbortController | null>(null);
211
210
  const operationsPageAbortRef = useRef<AbortController | null>(null);
@@ -571,7 +570,7 @@ export function useDashboardAppModel() {
571
570
  setLoadingArea((current) => (current === "costs" ? null : current));
572
571
  if (costSummaryAbortRef.current === controller) costSummaryAbortRef.current = null;
573
572
  }
574
- }, [api, currency, operationsPeriod]);
573
+ }, [api, currency, operationsPeriod, currencyRef]);
575
574
 
576
575
  // The global language selector can request USD while Operations is active.
577
576
  // Acquire its coherent Cost Monitor snapshot here instead of requiring a
@@ -695,6 +694,7 @@ export function useDashboardAppModel() {
695
694
  openTraceChange,
696
695
  openTraceMacro,
697
696
  selectedTraceTaskId,
697
+ traceMacroLoading,
698
698
  trace,
699
699
  traceLoadingTaskId,
700
700
  traceTasksHasMore,
@@ -0,0 +1,18 @@
1
+ import type { CostCurrency, CostLocale } from "@zaip-ai/dashboard-cost-monitor/react";
2
+ import { useCallback, useRef, useState } from "react";
3
+ import { currencyKey, savedLocale } from "./app-preferences.js";
4
+ export function useDashboardLocale() {
5
+ const [costLocale, setCostLocale] = useState<CostLocale>(savedLocale);
6
+ const [currency, setCurrency] = useState<CostCurrency>(() =>
7
+ window.localStorage.getItem(currencyKey) === "USD" ? "USD" : "BRL",
8
+ );
9
+ const currencyRef = useRef(currency);
10
+ currencyRef.current = currency;
11
+ // Language is the global selector's source of truth for the paired display
12
+ // currency, so Operations and Cost Monitor cannot diverge.
13
+ const changeDashboardLocale = useCallback((next: CostLocale) => {
14
+ setCostLocale(next);
15
+ setCurrency(next === "en-US" ? "USD" : "BRL");
16
+ }, []);
17
+ return { costLocale, currency, setCurrency, currencyRef, changeDashboardLocale };
18
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zaip-ai/dashboard-cost-monitor",
3
- "version": "4.9.0",
3
+ "version": "5.1.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -69,7 +69,7 @@ export interface CostRunRow {
69
69
  run_id: string;
70
70
  /** Lifecycle Execution that owns this Run, retained for the Executions tab period filter. */
71
71
  execution_id: string | null;
72
- conversation_id: string;
72
+ conversation_id: string | null;
73
73
  task_id: string | null;
74
74
  task_title: string;
75
75
  task_status: string;
@@ -81,7 +81,14 @@ export interface CostRunRow {
81
81
  parent_run_id: string | null;
82
82
  run_role: "intake" | "orchestrator" | "subagent";
83
83
  run_kind: "run" | "subrun";
84
- run_purpose: "intake" | "orchestration" | "execution" | "review" | "audit" | "finalization";
84
+ run_purpose:
85
+ | "observation"
86
+ | "intake"
87
+ | "orchestration"
88
+ | "execution"
89
+ | "review"
90
+ | "audit"
91
+ | "finalization";
85
92
  requires_finalizer: boolean;
86
93
  client: string;
87
94
  agent: string;
@@ -95,7 +102,7 @@ export interface CostRunRow {
95
102
  call_count: number | null;
96
103
  status: string;
97
104
  phase: string;
98
- origin: "conversation" | "task" | "spec" | "prd";
105
+ origin: "observation" | "conversation" | "task" | "spec" | "prd";
99
106
  work_type: "new" | "rework";
100
107
  started_at: string;
101
108
  finished_at: string | null;
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { loadCostMonitorRunPage } from "./CostFilters.js";
2
+ import { emptyCostFilters, loadCostMonitorRunPage } from "./CostFilters.js";
3
3
 
4
4
  describe("Cost Monitor invocation page loading", () => {
5
5
  it("uses a ten-row default for the remote invocation page", async () => {
@@ -7,6 +7,7 @@ describe("Cost Monitor invocation page loading", () => {
7
7
  await loadCostMonitorRunPage({
8
8
  currency: "BRL",
9
9
  offset: 0,
10
+ filters: { ...emptyCostFilters, query: "target title" },
10
11
  fetcher: async (url) => {
11
12
  calls.push(String(url));
12
13
  return new Response(JSON.stringify({ runs: [] }), { status: 200 });
@@ -14,5 +15,8 @@ describe("Cost Monitor invocation page loading", () => {
14
15
  });
15
16
 
16
17
  expect(new URL(calls[0]!, "http://dashboard.local").searchParams.get("limit")).toBe("10");
18
+ expect(new URL(calls[0]!, "http://dashboard.local").searchParams.get("query")).toBe(
19
+ "target title",
20
+ );
17
21
  });
18
22
  });
@@ -22,7 +22,7 @@ const unavailableGroup = {
22
22
  } as const;
23
23
 
24
24
  describe("period group values", () => {
25
- it("discloses presentation zero without changing null sorting", () => {
25
+ it("preserves unavailable tokens alongside disclosed presentation zeros and null sorting", () => {
26
26
  const table = CostGroupsTable({
27
27
  rows: [unavailableGroup],
28
28
  currency: "BRL",
@@ -53,7 +53,7 @@ describe("period group values", () => {
53
53
  );
54
54
  expect([duration.props.children, tokens.props.children, cost.props.children]).toEqual([
55
55
  "0",
56
- "0",
56
+ "—",
57
57
  formatAuditableCurrency(0, "BRL", "pt-BR"),
58
58
  ]);
59
59
  expect(
@@ -179,7 +179,7 @@ describe("grouped cost availability", () => {
179
179
  ).toBe("0");
180
180
  expect(
181
181
  columns.find((column) => column.key === "cost")?.render?.({ ...model, estimated_brl: null }),
182
- ).toBe("0");
182
+ ).toBe("—");
183
183
  expect(
184
184
  columns
185
185
  .find((column) => column.key === "tokens")
@@ -324,14 +324,14 @@ describe("grouped cost availability", () => {
324
324
  expect(column(key)?.description).toContain("projeção SQLite/API");
325
325
  expect(column(key)?.hidden).not.toBe(true);
326
326
  }
327
- expect(column("duration")?.render?.(unavailableRun)).toBe("0");
328
- expect(column("inputTokens")?.render?.(unavailableRun)).toBe("0");
327
+ expect(column("duration")?.render?.(unavailableRun)).toBe("—");
328
+ expect(column("inputTokens")?.render?.(unavailableRun)).toBe("—");
329
329
  expect(column("inputRate")?.render?.(unavailableRun)).toBe("0,00");
330
330
  expect(column("contextMultiplier")?.render?.(unavailableRun)).toBe("0");
331
331
  expect(column("inputCost")?.render?.(unavailableRun)).toContain("0,00");
332
332
  expect(column("fxRate")?.render?.(unavailableRun)).toBe("R$ 0,00");
333
- expect(column("recordedBrl")?.render?.(unavailableRun)).toBe("0");
334
- expect(column("cost")?.render?.(unavailableRun)).toBe("0");
333
+ expect(column("recordedBrl")?.render?.(unavailableRun)).toBe("—");
334
+ expect(column("cost")?.render?.(unavailableRun)).toBe("—");
335
335
  });
336
336
  it("provides a clear scroll label for the detailed Runs table", () => {
337
337
  expect(costRunsScrollLabel("pt-BR")).toBe(