@zaip-ai/cli 3.4.0 → 3.5.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 (119) hide show
  1. package/dist/services/adapters.d.ts +1 -1
  2. package/dist/services/adapters.js +1 -1
  3. package/package.json +1 -1
  4. package/templates/.agents/config/agents/discovery.json +1 -1
  5. package/templates/.agents/dashboard/.zaip-managed.json +54 -38
  6. package/templates/.agents/dashboard/apps/frontend/dist/assets/{ProjectSettingsPage-B9GWkEyN.css → ProjectSettingsPage-CQMhvzvJ.css} +1 -1
  7. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-D46WWIKr.js +3 -0
  8. package/templates/.agents/dashboard/apps/frontend/dist/assets/{TraceabilityWorkspace-CqK3Psfy.js → TraceabilityWorkspace-BKBpJyLh.js} +1 -1
  9. package/templates/.agents/dashboard/apps/frontend/dist/assets/{index-Cl5EWx8R.js → index-Bas2TVju.js} +2 -2
  10. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-CxrG_wRI.css +1 -0
  11. package/templates/.agents/dashboard/apps/frontend/dist/index.html +2 -2
  12. package/templates/.agents/dashboard/apps/frontend/package.json +1 -1
  13. package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsCard.tsx +5 -0
  14. package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsField.tsx +21 -0
  15. package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsPage.dom.test.ts +12 -1
  16. package/templates/.agents/dashboard/apps/frontend/src/ProjectSettingsPage.tsx +16 -28
  17. package/templates/.agents/dashboard/apps/frontend/src/ProjectStackEditor.tsx +25 -4
  18. package/templates/.agents/dashboard/apps/frontend/src/WorkspaceStatus.test.tsx +26 -8
  19. package/templates/.agents/dashboard/apps/frontend/src/WorkspaceStatus.tsx +9 -28
  20. package/templates/.agents/dashboard/apps/frontend/src/project-settings-copy.ts +13 -4
  21. package/templates/.agents/dashboard/apps/frontend/src/project-settings-model.ts +25 -1
  22. package/templates/.agents/dashboard/apps/frontend/src/project-settings-workspace.css +28 -0
  23. package/templates/.agents/dashboard/apps/frontend/src/project-settings.test.ts +39 -0
  24. package/templates/.agents/dashboard/apps/frontend/src/workspace-status.css +1 -14
  25. package/templates/.agents/dashboard/modules/cost-monitor/package.json +1 -1
  26. package/templates/.agents/dashboard/modules/operations/package.json +1 -1
  27. package/templates/.agents/dashboard/modules/traceability/package.json +1 -1
  28. package/templates/.agents/dashboard/packages/branding/package.json +1 -1
  29. package/templates/.agents/dashboard/packages/contracts/package.json +1 -1
  30. package/templates/.agents/dashboard/packages/data-export/package.json +1 -1
  31. package/templates/.agents/dashboard/packages/local-runtime/dist/server.cjs +2 -2
  32. package/templates/.agents/dashboard/packages/local-runtime/dist/sqlite-read-model.cjs +73 -73
  33. package/templates/.agents/dashboard/packages/local-runtime/package.json +1 -1
  34. package/templates/.agents/dashboard/packages/local-runtime/scripts/validate-sqlite-read-model.mjs +38 -6
  35. package/templates/.agents/dashboard/packages/local-runtime/server.mjs +2 -2
  36. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.test.ts +2 -3
  37. package/templates/.agents/dashboard/packages/local-runtime/src/project-settings.ts +1 -1
  38. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-pricing-provenance.test.ts +39 -0
  39. package/templates/.agents/dashboard/packages/local-runtime/src/sqlite-read-model-canonical.ts +2 -2
  40. package/templates/.agents/dashboard/packages/ui/package.json +1 -1
  41. package/templates/.agents/dashboard/tests/e2e/package.json +1 -1
  42. package/templates/.agents/design/.zaip-managed.json +78 -50
  43. package/templates/.agents/design/apps/catalog/dist/assets/index-D1JaPXfV.css +1 -0
  44. package/templates/.agents/design/apps/catalog/dist/assets/index-D2miO4-O.js +72 -0
  45. package/templates/.agents/design/apps/catalog/dist/assets/index-mvD5mwcC.js +72 -0
  46. package/templates/.agents/design/apps/catalog/dist/index.html +2 -2
  47. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{CatalogShell-CvaciY0C.js → CatalogShell-BJ8b4xZr.js} +1 -1
  48. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{Color-6AOWCN3U-DwBV1A1Y.js → Color-6AOWCN3U-CQLHzznn.js} +1 -1
  49. package/templates/.agents/design/apps/catalog/dist/storybook/assets/Components.stories-kxWwSKin.js +146 -0
  50. package/templates/.agents/design/apps/catalog/dist/storybook/assets/DashboardFilters.stories-Chm_dXV7.js +9 -0
  51. package/templates/.agents/design/apps/catalog/dist/storybook/assets/DashboardFiltersSpecimen-9CaCbGIZ.js +1 -0
  52. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{DesignSystem.stories-2OCgtT0I.js → DesignSystem.stories-ED52wFjY.js} +1 -1
  53. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{DocsRenderer-JROSPFPF-CODg0rSl.js → DocsRenderer-JROSPFPF-BcLgM80v.js} +4 -4
  54. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{Primitives-BmeKjJW4.js → Primitives-DV6Bpudf.js} +1 -1
  55. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{WithTooltip-7X4HQR7L-C5MI-3uZ.js → WithTooltip-7X4HQR7L-BKNiAz_E.js} +1 -1
  56. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{WorkspaceStatus.stories-Tb_iQqVK.js → WorkspaceStatus.stories-BL19HGOo.js} +2 -2
  57. package/templates/.agents/design/apps/catalog/dist/storybook/assets/WorkspaceStatusSpecimen-DQnSS6s9.js +1 -0
  58. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{chunk-DRQKCCAG-KSn75jcy.js → chunk-DRQKCCAG-DZBcXL-p.js} +1 -1
  59. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{chunk-W22LQPXL-C4LS1Thf.js → chunk-W22LQPXL-CF3y2mfo.js} +1 -1
  60. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{components-DV1BRgMY.js → components-BVjxMRGq.js} +5 -5
  61. package/templates/.agents/design/apps/catalog/dist/storybook/assets/formatter-L2YTDE3Q-Do9sjqiW.js +1 -0
  62. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{iframe-CBbPFx5G.js → iframe-CTWGZcEe.js} +4 -4
  63. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{react-18-C9IPGXtb.js → react-18-B9_a4mHb.js} +1 -1
  64. package/templates/.agents/design/apps/catalog/dist/storybook/assets/react-NrUxok8K.js +1 -0
  65. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{syntaxhighlighter-YFXUGROL-ZgDQjyWI.js → syntaxhighlighter-YFXUGROL-F_p8E2xc.js} +1 -1
  66. package/templates/.agents/design/apps/catalog/dist/storybook/assets/{theming-Cx9-gH6l.js → theming-fbSD9ZLF.js} +1 -1
  67. package/templates/.agents/design/apps/catalog/dist/storybook/iframe.html +1 -1
  68. package/templates/.agents/design/apps/catalog/dist/storybook/index.json +1 -1
  69. package/templates/.agents/design/apps/catalog/dist/storybook/sb-addons/a11y-2/manager-bundle.js +3 -3
  70. package/templates/.agents/design/apps/catalog/dist/storybook/sb-addons/docs-1/manager-bundle.js +4 -4
  71. package/templates/.agents/design/apps/catalog/dist/storybook/sb-addons/storybook-core-server-presets-0/common-manager-bundle.js +60 -60
  72. package/templates/.agents/design/apps/catalog/package.json +1 -1
  73. package/templates/.agents/design/apps/catalog/src/components/StackVersionFieldSpecimen.tsx +70 -0
  74. package/templates/.agents/design/apps/catalog/src/components/WorkspaceStatusSpecimen.tsx +23 -7
  75. package/templates/.agents/design/apps/catalog/src/pages/ComponentsPage.tsx +20 -6
  76. package/templates/.agents/design/apps/catalog/src/stories/Components.stories.tsx +14 -0
  77. package/templates/.agents/design/apps/catalog/src/stories/WorkspaceStatus.stories.tsx +5 -2
  78. package/templates/.agents/design/apps/catalog/src/styles/components.css +1 -1
  79. package/templates/.agents/design/apps/catalog/src/styles/stack-version-field.css +17 -0
  80. package/templates/.agents/design/packages/local-runtime/package.json +1 -1
  81. package/templates/.agents/requirements/autonomous-assurance.md +1 -1
  82. package/templates/.agents/requirements/cloud-hostinger-autonomy.md +1 -1
  83. package/templates/.agents/requirements/comparative-audit.md +1 -1
  84. package/templates/.agents/requirements/context-engine.md +1 -1
  85. package/templates/.agents/requirements/cost-observability.md +1 -1
  86. package/templates/.agents/requirements/dashboard-launch.md +1 -1
  87. package/templates/.agents/requirements/data-export.md +1 -1
  88. package/templates/.agents/requirements/design-system.md +1 -1
  89. package/templates/.agents/requirements/execution-engine.md +1 -1
  90. package/templates/.agents/requirements/kanban-dashboard.md +1 -1
  91. package/templates/.agents/requirements/model-orchestration.md +1 -1
  92. package/templates/.agents/requirements/public-distribution.md +1 -1
  93. package/templates/.agents/requirements/software-architecture.md +1 -1
  94. package/templates/.agents/requirements/strategic-improvements.md +1 -1
  95. package/templates/.agents/requirements/work-lifecycle.md +1 -1
  96. package/templates/.agents/requirements/zaip-strategic-95.md +1 -1
  97. package/templates/.agents/rules/workflow.md +1 -1
  98. package/templates/.agents/runtime/VERSION +1 -1
  99. package/templates/.agents/runtime/bin/zaip.mjs +9 -9
  100. package/templates/.agents/runtime/checksums.sha256 +5 -5
  101. package/templates/.agents/runtime/manifest.json +1 -1
  102. package/templates/.agents/runtime/provenance.json +4 -4
  103. package/templates/.agents/runtime/sbom.cdx.json +1 -1
  104. package/templates/.agents/skills/zaip-skill-github-deploy/SKILL.md +5 -4
  105. package/templates/.agents/skills/zaip-skill-github-deploy/agents/openai.yaml +1 -1
  106. package/templates/.agents/skills/zaip-skill-github-deploy/references/deployment-workflow.md +7 -7
  107. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/consumer-release-preparation.mjs +1 -2
  108. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/consumer-release-preparation.test.mjs +9 -1
  109. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/github-deploy-contract.test.mjs +23 -0
  110. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/preflight.mjs +2 -6
  111. package/templates/.agents/skills/zaip-skill-github-deploy/scripts/preflight.test.mjs +15 -1
  112. package/templates/.agents/zaip-aios/VERSION +1 -1
  113. package/templates/template-manifest.json +169 -125
  114. package/templates/.agents/dashboard/apps/frontend/dist/assets/ProjectSettingsPage-DVCPPV75.js +0 -3
  115. package/templates/.agents/dashboard/apps/frontend/dist/assets/index-Cwylbh_N.css +0 -1
  116. package/templates/.agents/design/apps/catalog/dist/storybook/assets/Components.stories-3dqK5g3e.js +0 -142
  117. package/templates/.agents/design/apps/catalog/dist/storybook/assets/WorkspaceStatusSpecimen-CD54pw0-.js +0 -1
  118. package/templates/.agents/design/apps/catalog/dist/storybook/assets/formatter-L2YTDE3Q-BU_68im1.js +0 -1
  119. package/templates/.agents/design/apps/catalog/dist/storybook/assets/react-CEv2qkJT.js +0 -1
@@ -1,10 +1,12 @@
1
- import { type FormEvent, type ReactNode, useCallback, useEffect, useState } from "react";
1
+ import { type FormEvent, useCallback, useEffect, useState } from "react";
2
2
  import type {
3
3
  DashboardApiClient,
4
4
  ProjectConfigSettings,
5
5
  ProjectOverview,
6
6
  } from "./dashboard-api.js";
7
7
  import { StackComponentEditor, StackVersions } from "./ProjectStackEditor.js";
8
+ import { ProjectSettingsCard as SettingsCard } from "./ProjectSettingsCard.js";
9
+ import { ProjectSettingsField as Field } from "./ProjectSettingsField.js";
8
10
  import {
9
11
  type InstallationDimensionStatus,
10
12
  projectInstallationStatus,
@@ -25,7 +27,9 @@ import {
25
27
  } from "./project-settings-model.js";
26
28
  import "./project-settings-page.css";
27
29
  import "./project-stack-versions.css";
30
+ import "./project-settings-workspace.css";
28
31
  import { AutonomySettings } from "./AutonomySettings.js";
32
+ import { useRuntimeStatus } from "./use-runtime-status.js";
29
33
 
30
34
  export function ProjectSettingsPage({
31
35
  api,
@@ -46,6 +50,7 @@ export function ProjectSettingsPage({
46
50
  const [error, setError] = useState<string | null>(null);
47
51
  const [notice, setNotice] = useState<string | null>(null);
48
52
  const [installationToastVisible, setInstallationToastVisible] = useState(false);
53
+ const runtime = useRuntimeStatus();
49
54
  const installation = overview === null ? null : projectInstallationStatus(overview);
50
55
 
51
56
  const loadProjectSettings = useCallback(async () => {
@@ -219,6 +224,16 @@ export function ProjectSettingsPage({
219
224
 
220
225
  <div className="project-settings-grid">
221
226
  <SettingsCard className="is-wide project-identity-card" title={text.identity}>
227
+ <Field
228
+ className="project-settings-workspace-field"
229
+ hint={text.workspacePathHint}
230
+ label={text.workspacePath}
231
+ >
232
+ <code className="project-settings-workspace-path">
233
+ {runtime.status?.workspace ??
234
+ (runtime.unavailable ? text.workspacePathUnavailable : text.workspacePathLoading)}
235
+ </code>
236
+ </Field>
222
237
  <Field label="Schema">
223
238
  <input readOnly value={config.schema_version} />
224
239
  </Field>
@@ -599,33 +614,6 @@ function installationStateLabel(state: InstallationDimensionStatus["state"], loc
599
614
  return text.unknown;
600
615
  }
601
616
 
602
- function SettingsCard({
603
- children,
604
- className = "",
605
- title,
606
- }: {
607
- children: ReactNode;
608
- className?: string;
609
- title: string;
610
- }) {
611
- return (
612
- <section className={`project-settings-card ${className}`}>
613
- <h2>{title}</h2>
614
- <div className="project-settings-fields">{children}</div>
615
- </section>
616
- );
617
- }
618
-
619
- function Field({ children, hint, label }: { children: ReactNode; hint?: string; label: string }) {
620
- return (
621
- <div className="project-settings-field">
622
- <span>{label}</span>
623
- {children}
624
- {hint ? <small>{hint}</small> : null}
625
- </div>
626
- );
627
- }
628
-
629
617
  function Toggle({
630
618
  checked,
631
619
  hint,
@@ -1,5 +1,6 @@
1
1
  import type { ProjectOverview } from "./dashboard-api.js";
2
2
  import {
3
+ acceptsDescriptiveVersion,
3
4
  type StackComponentId,
4
5
  type StackComponentsDraft,
5
6
  stackComponentDefinitions,
@@ -74,7 +75,9 @@ export function StackComponentEditor({
74
75
  <div className="project-stack-table-head" aria-hidden="true">
75
76
  <span>Item</span>
76
77
  <span>{locale === "pt-BR" ? "Tecnologia" : "Technology"}</span>
77
- <span>{locale === "pt-BR" ? "Versão exata" : "Exact version"}</span>
78
+ <span>
79
+ {locale === "pt-BR" ? "Versão atual / referência" : "Current version / reference"}
80
+ </span>
78
81
  <span>
79
82
  {locale === "pt-BR" ? "Pacote / imagem / serviço" : "Package / image / service"}
80
83
  </span>
@@ -92,9 +95,27 @@ export function StackComponentEditor({
92
95
  onChange={(event) => update(definition.id, "name", event.target.value)}
93
96
  />
94
97
  <input
95
- aria-label={`${componentLabels[definition.id].pt}: versão exata`}
96
- inputMode="decimal"
97
- placeholder="x.y.z"
98
+ aria-label={`${componentLabels[definition.id].pt}: ${
99
+ acceptsDescriptiveVersion(definition.id)
100
+ ? "versão atual ou referência"
101
+ : "versão exata"
102
+ }`}
103
+ className={
104
+ acceptsDescriptiveVersion(definition.id) ? "is-reference-value" : undefined
105
+ }
106
+ inputMode={acceptsDescriptiveVersion(definition.id) ? "text" : "decimal"}
107
+ placeholder={
108
+ acceptsDescriptiveVersion(definition.id)
109
+ ? locale === "pt-BR"
110
+ ? "Serviço em nuvem"
111
+ : "Cloud service"
112
+ : "x.y.z"
113
+ }
114
+ title={
115
+ acceptsDescriptiveVersion(definition.id)
116
+ ? components[definition.id].version
117
+ : undefined
118
+ }
98
119
  value={components[definition.id].version}
99
120
  onChange={(event) => update(definition.id, "version", event.target.value)}
100
121
  />
@@ -4,30 +4,48 @@ import { describe, expect, it } from "vitest";
4
4
  import { WorkspaceStatus } from "./WorkspaceStatus.js";
5
5
 
6
6
  describe("workspace diagnostics", () => {
7
+ it("does not render a global workspace banner when the runtime is healthy", () => {
8
+ const html = renderToStaticMarkup(
9
+ createElement(WorkspaceStatus, {
10
+ status: {
11
+ workspace: "C:/projects/zaip-growth",
12
+ workspace_name: "zaip-growth",
13
+ workspaceKey: "growth",
14
+ status: "ok",
15
+ lifecycle_manifest_state: "initialized",
16
+ },
17
+ }),
18
+ );
19
+ expect(html).toBe("");
20
+ });
21
+
7
22
  it.each([
8
- "initialized",
9
23
  "missing",
10
24
  "invalid",
11
- ] as const)("identifies the served path with %s lifecycle", (state) => {
25
+ ] as const)("keeps the %s lifecycle warning without exposing the served path", (state) => {
12
26
  const html = renderToStaticMarkup(
13
27
  createElement(WorkspaceStatus, {
14
28
  status: {
15
29
  workspace: "C:/projects/zaip-growth",
16
30
  workspace_name: "zaip-growth",
17
31
  workspaceKey: "growth",
18
- status: state === "initialized" ? "ok" : "degraded",
32
+ status: "degraded",
19
33
  lifecycle_manifest_state: state,
20
34
  },
21
35
  }),
22
36
  );
23
- expect(html).toContain("C:/projects/zaip-growth");
37
+ expect(html).not.toContain("C:/projects/zaip-growth");
38
+ expect(html).not.toContain("zaip-growth");
24
39
  if (state === "missing") expect(html).toContain("Lifecycle não inicializado");
25
40
  if (state === "invalid") expect(html).toContain("Manifesto do lifecycle inválido");
26
- if (state !== "initialized") expect(html).toContain("manifest rebuild --confirm-full-scan");
41
+ expect(html).toContain("manifest rebuild --confirm-full-scan");
27
42
  });
43
+
28
44
  it("keeps unknown health explicit", () => {
29
- expect(
30
- renderToStaticMarkup(createElement(WorkspaceStatus, { status: null, unavailable: true })),
31
- ).toContain("Workspace indisponível");
45
+ const html = renderToStaticMarkup(
46
+ createElement(WorkspaceStatus, { status: null, unavailable: true }),
47
+ );
48
+ expect(html).toContain("Não foi possível consultar a saúde do Dashboard");
49
+ expect(html).not.toContain("Workspace indisponível");
32
50
  });
33
51
  });
@@ -1,4 +1,3 @@
1
- import { useLayoutEffect, useRef } from "react";
2
1
  import type { DashboardRuntimeStatus } from "./dashboard-runtime-status.js";
3
2
  import "./workspace-status.css";
4
3
 
@@ -10,32 +9,10 @@ export function WorkspaceStatus({
10
9
  unavailable?: boolean;
11
10
  }) {
12
11
  const manifest = status?.lifecycle_manifest_state;
13
- const banner = useRef<HTMLElement>(null);
14
- useLayoutEffect(() => {
15
- const element = banner.current;
16
- if (!element) return;
17
- const update = () =>
18
- document.documentElement.style.setProperty(
19
- "--dashboard-workspace-height",
20
- `${element.getBoundingClientRect().height}px`,
21
- );
22
- update();
23
- const observer = new ResizeObserver(update);
24
- observer.observe(element);
25
- return () => {
26
- observer.disconnect();
27
- document.documentElement.style.removeProperty("--dashboard-workspace-height");
28
- };
29
- }, []);
12
+ if (manifest === "initialized" && status?.status === "ok" && !unavailable) return null;
13
+
30
14
  return (
31
- <aside ref={banner} className="workspace-status" aria-label="Workspace do Dashboard">
32
- <div className="workspace-status__identity">
33
- <strong>{status?.workspace_name ?? "Dashboard"}</strong>
34
- <span>
35
- {status?.workspace ??
36
- (unavailable ? "Workspace indisponível" : "Identificando workspace…")}
37
- </span>
38
- </div>
15
+ <aside className="workspace-status" aria-label="Saúde do Dashboard">
39
16
  {manifest === "missing" || manifest === "invalid" ? (
40
17
  <div className="workspace-status__warning" role="alert">
41
18
  <strong>
@@ -43,7 +20,7 @@ export function WorkspaceStatus({
43
20
  ? "Lifecycle não inicializado"
44
21
  : "Manifesto do lifecycle inválido"}
45
22
  </strong>
46
- <p>Os dados deste workspace estão indisponíveis. Na pasta indicada, execute:</p>
23
+ <p>Os dados deste workspace estão indisponíveis. Na pasta do projeto, execute:</p>
47
24
  <code>node .agents/runtime/bin/zaip.mjs manifest rebuild --confirm-full-scan</code>
48
25
  </div>
49
26
  ) : status?.status === "degraded" || unavailable ? (
@@ -52,7 +29,11 @@ export function WorkspaceStatus({
52
29
  ? "Não foi possível consultar a saúde do Dashboard. Tentando novamente…"
53
30
  : "Dashboard degradado: a atualização dos dados ou da telemetria requer atenção."}
54
31
  </p>
55
- ) : null}
32
+ ) : (
33
+ <p className="workspace-status__warning" role="status">
34
+ Identificando a saúde do Dashboard…
35
+ </p>
36
+ )}
56
37
  </aside>
57
38
  );
58
39
  }
@@ -15,6 +15,10 @@ export const projectSettingsCopy = {
15
15
  framework: "Framework ZAIP-AIOS",
16
16
  frameworkHint: "Ativa ou desativa o framework para este projeto.",
17
17
  identity: "Identidade do projeto",
18
+ workspacePath: "Caminho do projeto",
19
+ workspacePathHint: "Pasta local usada por esta instância do Dashboard.",
20
+ workspacePathLoading: "Identificando caminho…",
21
+ workspacePathUnavailable: "Caminho indisponível",
18
22
  stack: "Stack e linguagens",
19
23
  execution: "Execução",
20
24
  assurance: "Assurance",
@@ -57,8 +61,9 @@ export const projectSettingsCopy = {
57
61
  available: "Criado",
58
62
  artifactUnavailable: "Ainda não criado",
59
63
  componentGuide:
60
- "Preencha cada responsabilidade separadamente. A versão fica sem prefixos (^, ~, >=) e a referência identifica o pacote, imagem ou serviço.",
61
- versionHint: "Versão exata: 22.16.0 ou 17.6. Deixe vazio para serviços sem versão fixada.",
64
+ "Preencha cada responsabilidade separadamente. Use a versão exata do software e, para serviços em nuvem ou hospedagem, informe Serviço em nuvem.",
65
+ versionHint:
66
+ "Software: 22.16.0 ou 17.6, sem prefixos (^, ~, >=). Serviço gerenciado: Serviço em nuvem. Hospedagem: Serviço em nuvem.",
62
67
  referenceHint:
63
68
  "Ex.: npm:hono, docker:node:22.16.0-bookworm-slim, service:supabase ou provider:cloudflare-pages.",
64
69
  overrides: "Opções avançadas (JSON)",
@@ -103,6 +108,10 @@ export const projectSettingsCopy = {
103
108
  framework: "ZAIP-AIOS framework",
104
109
  frameworkHint: "Enable or disable the framework for this project.",
105
110
  identity: "Project identity",
111
+ workspacePath: "Project path",
112
+ workspacePathHint: "Local folder used by this Dashboard instance.",
113
+ workspacePathLoading: "Identifying path…",
114
+ workspacePathUnavailable: "Path unavailable",
106
115
  stack: "Stack and languages",
107
116
  execution: "Execution",
108
117
  assurance: "Assurance",
@@ -145,9 +154,9 @@ export const projectSettingsCopy = {
145
154
  available: "Created",
146
155
  artifactUnavailable: "Not created yet",
147
156
  componentGuide:
148
- "Fill each responsibility separately. Versions have no prefixes (^, ~, >=), and the reference identifies the package, image, or service.",
157
+ "Fill each responsibility separately. Use an exact software version and, for cloud services or hosting, enter Cloud service.",
149
158
  versionHint:
150
- "Exact version: 22.16.0 or 17.6. Leave blank for services without a pinned version.",
159
+ "Software: 22.16.0 or 17.6, without prefixes (^, ~, >=). Managed service: Cloud service. Hosting: Cloud service.",
151
160
  referenceHint:
152
161
  "E.g. npm:hono, docker:node:22.16.0-bookworm-slim, service:supabase, or provider:cloudflare-pages.",
153
162
  overrides: "Advanced options (JSON)",
@@ -34,6 +34,18 @@ export type StackComponentId = (typeof stackComponentDefinitions)[number]["id"];
34
34
  export type StackComponentDraft = { name: string; version: string; reference: string };
35
35
  export type StackComponentsDraft = Record<StackComponentId, StackComponentDraft>;
36
36
 
37
+ const descriptiveVersionComponentIds = new Set<StackComponentId>([
38
+ "database",
39
+ "auth_storage",
40
+ "backend_hosting",
41
+ "frontend_hosting",
42
+ "site_hosting",
43
+ ]);
44
+
45
+ export function acceptsDescriptiveVersion(id: StackComponentId): boolean {
46
+ return descriptiveVersionComponentIds.has(id);
47
+ }
48
+
37
49
  export function projectSettingsDraft(config: ProjectConfigSettings): {
38
50
  components: StackComponentsDraft;
39
51
  otherOverrides: string;
@@ -110,11 +122,23 @@ export function buildProjectSettingsPayload(
110
122
  } = parsed;
111
123
  for (const definition of stackComponentDefinitions) {
112
124
  const version = components[definition.id].version.trim();
113
- if (version !== "" && !/^\d+\.\d+(?:\.\d+)?(?:[-+][0-9A-Za-z.-]+)?$/.test(version)) {
125
+ if (
126
+ version !== "" &&
127
+ !acceptsDescriptiveVersion(definition.id) &&
128
+ !/^\d+\.\d+(?:\.\d+)?(?:[-+][0-9A-Za-z.-]+)?$/.test(version)
129
+ ) {
114
130
  throw new Error(
115
131
  `A versão de ${components[definition.id].name || definition.defaultName} deve ser exata, como 22.16.0 ou 17.6, sem ^, ~, >= ou latest.`,
116
132
  );
117
133
  }
134
+ if (
135
+ acceptsDescriptiveVersion(definition.id) &&
136
+ (version.length > 120 || /[\r\n]/.test(version))
137
+ ) {
138
+ throw new Error(
139
+ `A referência de ${components[definition.id].name || definition.defaultName} deve ter uma única linha com até 120 caracteres.`,
140
+ );
141
+ }
118
142
  }
119
143
  const normalized = Object.fromEntries(
120
144
  stackComponentDefinitions.map((definition) => [
@@ -0,0 +1,28 @@
1
+ .project-settings-workspace-path {
2
+ display: block;
3
+ min-width: 0;
4
+ padding: 10px 12px;
5
+ border: 1px solid #cbd7e5;
6
+ border-radius: 12px;
7
+ background: #f8fafc;
8
+ overflow-wrap: anywhere;
9
+ color: #0f172a;
10
+ }
11
+
12
+ .project-settings-workspace-field {
13
+ grid-column: 1 / -1;
14
+ }
15
+
16
+ .project-stack-row input.is-reference-value {
17
+ border-color: #9edcf2;
18
+ background-color: #effaff;
19
+ color: #075985;
20
+ font-weight: 650;
21
+ -webkit-text-fill-color: #075985;
22
+ }
23
+
24
+ .project-stack-row input.is-reference-value:hover,
25
+ .project-stack-row input.is-reference-value:focus-visible {
26
+ border-color: #00b0f0;
27
+ background-color: #f5fcff;
28
+ }
@@ -111,6 +111,45 @@ describe("project settings form mapping", () => {
111
111
  ).toThrow("deve ser exata");
112
112
  });
113
113
 
114
+ it("accepts descriptive references only for managed services and hosting", () => {
115
+ const components = projectSettingsDraft(config).components;
116
+ const payload = buildProjectSettingsPayload(
117
+ config,
118
+ {
119
+ ...components,
120
+ database: { ...components.database, version: "Serviço em nuvem" },
121
+ auth_storage: { ...components.auth_storage, version: "Serviço em nuvem" },
122
+ backend_hosting: {
123
+ ...components.backend_hosting,
124
+ version: "Serviço em nuvem",
125
+ },
126
+ frontend_hosting: { ...components.frontend_hosting, version: "Serviço em nuvem" },
127
+ site_hosting: { ...components.site_hosting, version: "Serviço em nuvem" },
128
+ },
129
+ "{}",
130
+ );
131
+
132
+ expect(payload.stack.overrides.components).toMatchObject({
133
+ database: { version: "Serviço em nuvem" },
134
+ auth_storage: { version: "Serviço em nuvem" },
135
+ backend_hosting: {
136
+ version: "Serviço em nuvem",
137
+ },
138
+ frontend_hosting: { version: "Serviço em nuvem" },
139
+ site_hosting: { version: "Serviço em nuvem" },
140
+ });
141
+ expect(() =>
142
+ buildProjectSettingsPayload(
143
+ config,
144
+ {
145
+ ...components,
146
+ backend_api: { ...components.backend_api, version: "Serviço em nuvem" },
147
+ },
148
+ "{}",
149
+ ),
150
+ ).toThrow("deve ser exata");
151
+ });
152
+
114
153
  it("keeps observability and on-demand testing tools editable with pinned-or-empty versions", () => {
115
154
  const configured = {
116
155
  ...config,
@@ -8,21 +8,8 @@
8
8
  border-bottom: 1px solid var(--border, rgba(255, 255, 255, 0.12));
9
9
  font-size: 12px;
10
10
  }
11
- .dashboard-header {
12
- top: var(--dashboard-workspace-height, 0px);
13
- }
14
- .workspace-status__identity {
15
- display: flex;
16
- flex-wrap: wrap;
17
- gap: 4px 16px;
18
- align-items: baseline;
19
- }
20
- .workspace-status__identity span {
21
- overflow-wrap: anywhere;
22
- min-width: 0;
23
- }
24
11
  .workspace-status__warning {
25
- margin: 8px 0;
12
+ margin: 0;
26
13
  color: var(--error-text, #fecaca);
27
14
  }
28
15
  .workspace-status__warning p {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zaip-ai/dashboard-cost-monitor",
3
- "version": "3.4.0",
3
+ "version": "3.5.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zaip-ai/dashboard-operations",
3
- "version": "3.4.0",
3
+ "version": "3.5.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zaip-ai/dashboard-traceability",
3
- "version": "3.4.0",
3
+ "version": "3.5.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zaip-ai/dashboard-branding",
3
- "version": "3.4.0",
3
+ "version": "3.5.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zaip-ai/dashboard-contracts",
3
- "version": "3.4.0",
3
+ "version": "3.5.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zaip-ai/dashboard-data-export",
3
- "version": "3.4.0",
3
+ "version": "3.5.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {