@topogram/cli 0.3.64 → 0.3.66

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 (278) hide show
  1. package/package.json +1 -1
  2. package/src/adoption/plan/index.js +716 -0
  3. package/src/adoption/plan.js +12 -703
  4. package/src/adoption/reporting.js +1 -1
  5. package/src/agent-brief.js +7 -21
  6. package/src/agent-ops/query-builders/auth.js +375 -0
  7. package/src/agent-ops/query-builders/change-risk/change-plan.js +123 -0
  8. package/src/agent-ops/query-builders/change-risk/import-plan.js +49 -0
  9. package/src/agent-ops/query-builders/change-risk/maintained.js +286 -0
  10. package/src/agent-ops/query-builders/change-risk/review-packets.js +123 -0
  11. package/src/agent-ops/query-builders/change-risk/risk.js +189 -0
  12. package/src/agent-ops/query-builders/change-risk.js +25 -0
  13. package/src/agent-ops/query-builders/common.js +149 -0
  14. package/src/agent-ops/query-builders/maintained-risk.js +539 -0
  15. package/src/agent-ops/query-builders/maintained-shared.js +120 -0
  16. package/src/agent-ops/query-builders/multi-agent.js +547 -0
  17. package/src/agent-ops/query-builders/projection-impacts.js +514 -0
  18. package/src/agent-ops/query-builders/work-packets.js +417 -0
  19. package/src/agent-ops/query-builders/workflow-context-shared.js +300 -0
  20. package/src/agent-ops/query-builders/workflow-context.js +398 -0
  21. package/src/agent-ops/query-builders/workflow-presets-core.js +677 -0
  22. package/src/agent-ops/query-builders/workflow-presets.js +341 -0
  23. package/src/agent-ops/query-builders.d.ts +26 -26
  24. package/src/agent-ops/query-builders.js +42 -5021
  25. package/src/archive/jsonl.js +2 -2
  26. package/src/archive/resolver-bridge.js +1 -1
  27. package/src/archive/unarchive.js +2 -1
  28. package/src/catalog/constants.js +10 -0
  29. package/src/catalog/copy.js +65 -0
  30. package/src/catalog/diagnostics.js +15 -0
  31. package/src/catalog/entries.js +42 -0
  32. package/src/catalog/files.js +67 -0
  33. package/src/catalog/provenance.js +123 -0
  34. package/src/catalog/source.js +150 -0
  35. package/src/catalog/validation.js +252 -0
  36. package/src/catalog.d.ts +2 -0
  37. package/src/catalog.js +18 -746
  38. package/src/cli/command-parsers/project.js +3 -0
  39. package/src/cli/command-parsers/shared.js +1 -1
  40. package/src/cli/commands/agent.js +2 -2
  41. package/src/cli/commands/catalog/check.js +31 -0
  42. package/src/cli/commands/catalog/copy.js +59 -0
  43. package/src/cli/commands/catalog/doctor.js +248 -0
  44. package/src/cli/commands/catalog/help.js +21 -0
  45. package/src/cli/commands/catalog/list.js +52 -0
  46. package/src/cli/commands/catalog/runner.js +92 -0
  47. package/src/cli/commands/catalog/shared.js +17 -0
  48. package/src/cli/commands/catalog/show.js +134 -0
  49. package/src/cli/commands/catalog.js +30 -615
  50. package/src/cli/commands/check.js +3 -3
  51. package/src/cli/commands/doctor.js +2 -9
  52. package/src/cli/commands/generator-policy/package-info.js +162 -0
  53. package/src/cli/commands/generator-policy/payloads.js +372 -0
  54. package/src/cli/commands/generator-policy/printers.js +159 -0
  55. package/src/cli/commands/generator-policy/runner.js +81 -0
  56. package/src/cli/commands/generator-policy/shared.js +39 -0
  57. package/src/cli/commands/generator-policy.js +15 -783
  58. package/src/cli/commands/import/adopt.js +170 -0
  59. package/src/cli/commands/import/check.js +91 -0
  60. package/src/cli/commands/import/diff.js +84 -0
  61. package/src/cli/commands/import/help.js +47 -0
  62. package/src/cli/commands/import/paths.js +269 -0
  63. package/src/cli/commands/import/plan.js +292 -0
  64. package/src/cli/commands/import/refresh.js +471 -0
  65. package/src/cli/commands/import/status-history.js +196 -0
  66. package/src/cli/commands/import/workspace.js +233 -0
  67. package/src/cli/commands/import.js +33 -1732
  68. package/src/cli/commands/migrate.js +153 -0
  69. package/src/cli/commands/package/constants.js +17 -0
  70. package/src/cli/commands/package/doctor.js +240 -0
  71. package/src/cli/commands/package/help.js +27 -0
  72. package/src/cli/commands/package/lockfile.js +135 -0
  73. package/src/cli/commands/package/npm.js +97 -0
  74. package/src/cli/commands/package/reporting.js +35 -0
  75. package/src/cli/commands/package/runner.js +33 -0
  76. package/src/cli/commands/package/shared.js +9 -0
  77. package/src/cli/commands/package/update-cli.js +252 -0
  78. package/src/cli/commands/package/versions.js +35 -0
  79. package/src/cli/commands/package.js +29 -813
  80. package/src/cli/commands/query/change-plan.js +68 -0
  81. package/src/cli/commands/query/definitions.js +202 -0
  82. package/src/cli/commands/query/import-adopt.js +121 -0
  83. package/src/cli/commands/query/runner/artifacts.js +102 -0
  84. package/src/cli/commands/query/runner/boundaries.js +211 -0
  85. package/src/cli/commands/query/runner/change.js +182 -0
  86. package/src/cli/commands/query/runner/import-adopt.js +111 -0
  87. package/src/cli/commands/query/runner/index.js +31 -0
  88. package/src/cli/commands/query/runner/output.js +12 -0
  89. package/src/cli/commands/query/runner/workflow.js +241 -0
  90. package/src/cli/commands/query/runner.js +3 -0
  91. package/src/cli/commands/query/workflow-context.js +5 -0
  92. package/src/cli/commands/query/workspace.js +270 -0
  93. package/src/cli/commands/query.js +9 -1300
  94. package/src/cli/commands/source.js +3 -12
  95. package/src/cli/commands/template/baseline.js +100 -0
  96. package/src/cli/commands/template/check.js +467 -0
  97. package/src/cli/commands/template/constants.js +8 -0
  98. package/src/cli/commands/template/diagnostics.js +26 -0
  99. package/src/cli/commands/template/help.js +28 -0
  100. package/src/cli/commands/template/lifecycle.js +404 -0
  101. package/src/cli/commands/template/list-show.js +287 -0
  102. package/src/cli/commands/template/policy.js +422 -0
  103. package/src/cli/commands/template/shared.js +127 -0
  104. package/src/cli/commands/template/updates.js +352 -0
  105. package/src/cli/commands/template-runner.js +6 -6
  106. package/src/cli/commands/template.js +41 -2143
  107. package/src/cli/commands/trust.js +1 -1
  108. package/src/cli/commands/workflow.js +6 -1
  109. package/src/cli/dispatcher.js +6 -1
  110. package/src/cli/help.js +15 -14
  111. package/src/cli/migration-guidance.js +1 -1
  112. package/src/cli/output-safety.js +2 -1
  113. package/src/cli/path-normalization.js +3 -13
  114. package/src/generator/api/contracts.js +497 -0
  115. package/src/generator/api/metadata.js +221 -0
  116. package/src/generator/api/openapi.js +559 -0
  117. package/src/generator/api/schema.js +124 -0
  118. package/src/generator/api/types.d.ts +98 -0
  119. package/src/generator/api.js +3 -1195
  120. package/src/generator/context/domain-page.js +1 -1
  121. package/src/generator/context/shared/domain-sdlc.js +282 -0
  122. package/src/generator/context/shared/maintained-boundary.js +665 -0
  123. package/src/generator/context/shared/metrics.js +85 -0
  124. package/src/generator/context/shared/primitives.js +64 -0
  125. package/src/generator/context/shared/relationships.js +453 -0
  126. package/src/generator/context/shared/summaries.js +263 -0
  127. package/src/generator/context/shared/types.d.ts +207 -0
  128. package/src/generator/context/shared.d.ts +42 -0
  129. package/src/generator/context/shared.js +80 -1390
  130. package/src/generator/context/slice/core.js +397 -0
  131. package/src/generator/context/slice/sdlc.js +417 -0
  132. package/src/generator/context/slice/ui-packets.js +183 -0
  133. package/src/generator/context/slice.js +2 -859
  134. package/src/generator/context/task-mode.js +2 -2
  135. package/src/generator/registry/index.js +507 -0
  136. package/src/generator/registry.js +18 -504
  137. package/src/generator/runtime/environment/index.js +666 -0
  138. package/src/generator/runtime/environment.js +4 -666
  139. package/src/generator/runtime/runtime-check/index.js +554 -0
  140. package/src/generator/runtime/runtime-check.js +4 -554
  141. package/src/generator/runtime/shared/index.js +572 -0
  142. package/src/generator/runtime/shared.js +19 -570
  143. package/src/generator/sdlc/doc-page.js +1 -1
  144. package/src/generator/shared.d.ts +2 -0
  145. package/src/generator/surfaces/databases/lifecycle-shared.js +1 -1
  146. package/src/generator/surfaces/native/swiftui-templates/README.generated.md +1 -1
  147. package/src/generator/surfaces/shared.d.ts +3 -0
  148. package/src/generator/widget-conformance/behavior-report.js +258 -0
  149. package/src/generator/widget-conformance/checks.js +371 -0
  150. package/src/generator/widget-conformance/projection-context.js +200 -0
  151. package/src/generator/widget-conformance/report.js +166 -0
  152. package/src/generator/widget-conformance/types.d.ts +121 -0
  153. package/src/generator/widget-conformance.js +3 -824
  154. package/src/import/core/context.d.ts +3 -0
  155. package/src/import/core/context.js +5 -7
  156. package/src/import/core/contracts.d.ts +1 -0
  157. package/src/import/core/registry.d.ts +4 -0
  158. package/src/import/core/runner/candidates.js +337 -0
  159. package/src/import/core/runner/options.js +22 -0
  160. package/src/import/core/runner/reports.js +51 -0
  161. package/src/import/core/runner/run.js +79 -0
  162. package/src/import/core/runner/tracks.js +150 -0
  163. package/src/import/core/runner/ui-drafts.js +393 -0
  164. package/src/import/core/runner.js +3 -698
  165. package/src/import/core/shared/api-routes.js +221 -0
  166. package/src/import/core/shared/candidates.js +97 -0
  167. package/src/import/core/shared/files.js +177 -0
  168. package/src/import/core/shared/next-app.js +389 -0
  169. package/src/import/core/shared/types.d.ts +51 -0
  170. package/src/import/core/shared/ui-routes.js +230 -0
  171. package/src/import/core/shared.js +60 -861
  172. package/src/new-project/constants.js +128 -0
  173. package/src/new-project/create.js +90 -0
  174. package/src/new-project/json.js +28 -0
  175. package/src/new-project/metadata.js +96 -0
  176. package/src/new-project/package-spec.js +161 -0
  177. package/src/new-project/project-files.js +351 -0
  178. package/src/new-project/template-policy.js +269 -0
  179. package/src/new-project/template-resolution.js +370 -0
  180. package/src/new-project/template-snapshots.js +442 -0
  181. package/src/new-project/template-updates.js +512 -0
  182. package/src/new-project/types.d.ts +83 -0
  183. package/src/new-project.js +6 -2277
  184. package/src/parser.d.ts +87 -1
  185. package/src/parser.js +118 -0
  186. package/src/policy/review-boundaries.d.ts +15 -0
  187. package/src/project-config/index.js +591 -0
  188. package/src/project-config.js +19 -561
  189. package/src/resolver/enrich/acceptance-criterion.js +2 -0
  190. package/src/resolver/enrich/bug.js +2 -0
  191. package/src/resolver/enrich/pitch.js +2 -0
  192. package/src/resolver/enrich/requirement.js +2 -0
  193. package/src/resolver/enrich/task.js +2 -0
  194. package/src/resolver/index.js +19 -2089
  195. package/src/resolver/normalize.js +384 -1
  196. package/src/resolver/plans.js +168 -0
  197. package/src/resolver/projections-api.js +494 -0
  198. package/src/resolver/projections-db.js +133 -0
  199. package/src/resolver/projections-ui.js +317 -0
  200. package/src/resolver/shapes.js +251 -0
  201. package/src/resolver/shared.js +278 -0
  202. package/src/resolver/widgets.js +132 -0
  203. package/src/sdlc/adopt.js +6 -5
  204. package/src/sdlc/paths.js +3 -5
  205. package/src/sdlc/scaffold.js +2 -1
  206. package/src/template-trust/constants.js +62 -0
  207. package/src/template-trust/content.js +258 -0
  208. package/src/template-trust/diff.js +92 -0
  209. package/src/template-trust/policy.js +61 -0
  210. package/src/template-trust/record.js +90 -0
  211. package/src/template-trust/status.js +182 -0
  212. package/src/template-trust.js +24 -687
  213. package/src/text-helpers.d.ts +1 -0
  214. package/src/topogram-types.d.ts +69 -0
  215. package/src/validator/common.js +488 -0
  216. package/src/validator/data-model.js +237 -0
  217. package/src/validator/docs.js +167 -0
  218. package/src/validator/expressions.js +146 -1
  219. package/src/validator/index.d.ts +23 -0
  220. package/src/validator/index.js +32 -3585
  221. package/src/validator/kinds.d.ts +41 -0
  222. package/src/validator/kinds.js +2 -0
  223. package/src/validator/model-helpers.js +46 -0
  224. package/src/validator/per-kind/acceptance-criterion.js +5 -0
  225. package/src/validator/per-kind/bug.js +6 -0
  226. package/src/validator/per-kind/domain.js +15 -2
  227. package/src/validator/per-kind/pitch.js +7 -0
  228. package/src/validator/per-kind/requirement.js +5 -0
  229. package/src/validator/per-kind/task.js +7 -0
  230. package/src/validator/per-kind/widget.js +14 -0
  231. package/src/validator/projections/api-http-async.js +410 -0
  232. package/src/validator/projections/api-http-authz.js +88 -0
  233. package/src/validator/projections/api-http-core.js +205 -0
  234. package/src/validator/projections/api-http-policies.js +339 -0
  235. package/src/validator/projections/api-http-responses.js +233 -0
  236. package/src/validator/projections/api-http.js +44 -0
  237. package/src/validator/projections/db.js +353 -0
  238. package/src/validator/projections/generator-defaults.js +45 -0
  239. package/src/validator/projections/helpers.js +87 -0
  240. package/src/validator/projections/ui-helpers.js +214 -0
  241. package/src/validator/projections/ui-navigation.js +344 -0
  242. package/src/validator/projections/ui-structure.js +364 -0
  243. package/src/validator/projections/ui-widgets.js +493 -0
  244. package/src/validator/projections/ui.js +46 -0
  245. package/src/validator/registry.js +48 -1
  246. package/src/validator/utils.d.ts +20 -0
  247. package/src/validator/utils.js +115 -12
  248. package/src/widget-behavior.d.ts +1 -0
  249. package/src/workflows/import-app/api/collect.js +221 -0
  250. package/src/workflows/import-app/api/openapi.js +257 -0
  251. package/src/workflows/import-app/api/routes.js +327 -0
  252. package/src/workflows/import-app/api/sources.js +22 -0
  253. package/src/workflows/import-app/api.js +2 -797
  254. package/src/workflows/reconcile/adoption-plan/build.js +212 -0
  255. package/src/workflows/reconcile/adoption-plan/dependencies.js +75 -0
  256. package/src/workflows/reconcile/adoption-plan/outputs.js +153 -0
  257. package/src/workflows/reconcile/adoption-plan/paths.js +58 -0
  258. package/src/workflows/reconcile/adoption-plan/projection-patches.js +177 -0
  259. package/src/workflows/reconcile/adoption-plan/reasons.js +107 -0
  260. package/src/workflows/reconcile/adoption-plan.js +30 -740
  261. package/src/workflows/reconcile/auth/closures.js +115 -0
  262. package/src/workflows/reconcile/auth/formatters.js +142 -0
  263. package/src/workflows/reconcile/auth/inference.js +330 -0
  264. package/src/workflows/reconcile/auth/roles.js +122 -0
  265. package/src/workflows/reconcile/auth.js +35 -690
  266. package/src/workflows/reconcile/bundle-core/index.js +600 -0
  267. package/src/workflows/reconcile/bundle-core.js +12 -598
  268. package/src/workflows/reconcile/candidate-model.js +18 -2
  269. package/src/workflows/reconcile/canonical-surface.js +1 -1
  270. package/src/workflows/reconcile/impacts/adoption-plan.js +196 -0
  271. package/src/workflows/reconcile/impacts/indexes.js +105 -0
  272. package/src/workflows/reconcile/impacts/patches.js +252 -0
  273. package/src/workflows/reconcile/impacts/reports.js +80 -0
  274. package/src/workflows/reconcile/impacts.js +14 -623
  275. package/src/workflows/reconcile/renderers.js +41 -6
  276. package/src/workflows/shared.js +5 -11
  277. package/src/workspace-docs.d.ts +29 -0
  278. package/src/workspace-paths.js +328 -0
@@ -0,0 +1,364 @@
1
+ // @ts-check
2
+
3
+ import {
4
+ IDENTIFIER_PATTERN,
5
+ UI_APP_SHELL_KINDS,
6
+ UI_COLLECTION_PRESENTATIONS,
7
+ UI_DESIGN_ACCESSIBILITY_VALUES,
8
+ UI_DESIGN_ACTION_ROLES,
9
+ UI_DESIGN_COLOR_ROLES,
10
+ UI_DESIGN_DENSITIES,
11
+ UI_DESIGN_RADIUS_SCALES,
12
+ UI_DESIGN_TONES,
13
+ UI_DESIGN_TYPOGRAPHY_ROLES,
14
+ UI_NAVIGATION_PATTERNS,
15
+ UI_PATTERN_KINDS,
16
+ UI_REGION_KINDS,
17
+ UI_SCREEN_KINDS,
18
+ UI_STATE_KINDS,
19
+ UI_WINDOWING_MODES
20
+ } from "../kinds.js";
21
+ import {
22
+ blockSymbolItems,
23
+ getFieldValue,
24
+ pushError,
25
+ symbolValue,
26
+ symbolValues
27
+ } from "../utils.js";
28
+ import {
29
+ collectAvailableUiScreenIds,
30
+ collectProjectionUiScreens,
31
+ resolveProjectionUiScreenFieldNames,
32
+ SHARED_UI_SEMANTIC_BLOCKS
33
+ } from "./ui-helpers.js";
34
+ import {
35
+ parseUiDirectiveMap,
36
+ resolveCapabilityContractFields,
37
+ resolveCapabilityOutputShape
38
+ } from "./helpers.js";
39
+
40
+ /**
41
+ * @param {ValidationErrors} errors
42
+ * @param {TopogramStatement} statement
43
+ * @param {TopogramFieldMap} fieldMap
44
+ * @returns {void}
45
+ */
46
+ export function validateProjectionUiOwnership(errors, statement, fieldMap) {
47
+ if (statement.kind !== "projection") {
48
+ return;
49
+ }
50
+
51
+ const projectionType = symbolValue(getFieldValue(statement, "type"));
52
+ for (const key of SHARED_UI_SEMANTIC_BLOCKS) {
53
+ const field = fieldMap.get(key)?.[0];
54
+ if (!field || field.value.type !== "block") {
55
+ continue;
56
+ }
57
+ if (projectionType !== "ui_contract") {
58
+ pushError(
59
+ errors,
60
+ `Projection ${statement.id} ${key} belongs on shared UI projections; concrete UI projections may define screen_routes and surface hints only`,
61
+ field.loc
62
+ );
63
+ }
64
+ }
65
+
66
+ const routesField = fieldMap.get("screen_routes")?.[0];
67
+ if (routesField?.value.type === "block" && !["web_surface", "ios_surface"].includes(projectionType || "")) {
68
+ pushError(
69
+ errors,
70
+ `Projection ${statement.id} screen_routes belongs on concrete UI projections; shared UI projections own semantic screens and regions`,
71
+ routesField.loc
72
+ );
73
+ }
74
+ }
75
+
76
+ /**
77
+ * @param {ValidationErrors} errors
78
+ * @param {TopogramStatement} statement
79
+ * @param {TopogramFieldMap} fieldMap
80
+ * @param {TopogramRegistry} registry
81
+ * @returns {void}
82
+ */
83
+
84
+ export function validateProjectionUiScreens(errors, statement, fieldMap, registry) {
85
+ if (statement.kind !== "projection") {
86
+ return;
87
+ }
88
+
89
+ const screensField = fieldMap.get("screens")?.[0];
90
+ if (!screensField || screensField.value.type !== "block") {
91
+ return;
92
+ }
93
+
94
+ const realized = new Set(symbolValues(getFieldValue(statement, "realizes")));
95
+ const seenScreens = new Set();
96
+
97
+ for (const entry of screensField.value.entries) {
98
+ const tokens = blockSymbolItems(entry).map((item) => item.value);
99
+ const [keyword, screenId] = tokens;
100
+
101
+ if (keyword !== "screen") {
102
+ pushError(errors, `Projection ${statement.id} screens entries must start with 'screen'`, entry.loc);
103
+ continue;
104
+ }
105
+ if (!screenId) {
106
+ pushError(errors, `Projection ${statement.id} screens entries must include a screen id`, entry.loc);
107
+ continue;
108
+ }
109
+ if (!IDENTIFIER_PATTERN.test(screenId)) {
110
+ pushError(errors, `Projection ${statement.id} screens has invalid screen id '${screenId}'`, entry.loc);
111
+ }
112
+ if (seenScreens.has(screenId)) {
113
+ pushError(errors, `Projection ${statement.id} screens has duplicate screen id '${screenId}'`, entry.loc);
114
+ }
115
+ seenScreens.add(screenId);
116
+
117
+ const directives = parseUiDirectiveMap(tokens, 2, errors, statement, entry, `screens for '${screenId}'`);
118
+ const kind = directives.get("kind");
119
+ if (!kind) {
120
+ pushError(errors, `Projection ${statement.id} screens for '${screenId}' must include 'kind'`, entry.loc);
121
+ }
122
+ if (kind && !UI_SCREEN_KINDS.has(kind)) {
123
+ pushError(errors, `Projection ${statement.id} screens for '${screenId}' has invalid kind '${kind}'`, entry.loc);
124
+ }
125
+
126
+ for (const key of directives.keys()) {
127
+ if (!["kind", "title", "load", "item_shape", "view_shape", "input_shape", "submit", "detail_capability", "primary_action", "secondary_action", "destructive_action", "success_navigate", "success_refresh", "empty_title", "empty_body", "terminal_action", "loading_state", "error_state", "unauthorized_state", "not_found_state", "success_state"].includes(key)) {
128
+ pushError(errors, `Projection ${statement.id} screens for '${screenId}' has unknown directive '${key}'`, entry.loc);
129
+ }
130
+ }
131
+
132
+ for (const [key, expectedKind] of [
133
+ ["load", "capability"],
134
+ ["submit", "capability"],
135
+ ["detail_capability", "capability"],
136
+ ["primary_action", "capability"],
137
+ ["secondary_action", "capability"],
138
+ ["destructive_action", "capability"],
139
+ ["terminal_action", "capability"],
140
+ ["item_shape", "shape"],
141
+ ["view_shape", "shape"],
142
+ ["input_shape", "shape"]
143
+ ]) {
144
+ const targetId = directives.get(key);
145
+ if (!targetId) {
146
+ continue;
147
+ }
148
+ const target = registry.get(targetId);
149
+ if (!target) {
150
+ pushError(errors, `Projection ${statement.id} screens for '${screenId}' references missing ${expectedKind} '${targetId}' for '${key}'`, entry.loc);
151
+ continue;
152
+ }
153
+ if (target.kind !== expectedKind) {
154
+ pushError(errors, `Projection ${statement.id} screens for '${screenId}' must reference a ${expectedKind} for '${key}', found ${target.kind} '${target.id}'`, entry.loc);
155
+ }
156
+ if (expectedKind === "capability" && !realized.has(targetId)) {
157
+ pushError(errors, `Projection ${statement.id} screens for '${screenId}' capability '${targetId}' for '${key}' must also appear in 'realizes'`, entry.loc);
158
+ }
159
+ }
160
+
161
+ const successNavigate = directives.get("success_navigate");
162
+ const successRefresh = directives.get("success_refresh");
163
+ if (successNavigate && !IDENTIFIER_PATTERN.test(successNavigate)) {
164
+ pushError(errors, `Projection ${statement.id} screens for '${screenId}' has invalid target '${successNavigate}' for 'success_navigate'`, entry.loc);
165
+ }
166
+ if (successRefresh && !IDENTIFIER_PATTERN.test(successRefresh)) {
167
+ pushError(errors, `Projection ${statement.id} screens for '${screenId}' has invalid target '${successRefresh}' for 'success_refresh'`, entry.loc);
168
+ }
169
+
170
+ if (kind === "list" && !directives.get("load")) {
171
+ pushError(errors, `Projection ${statement.id} screens for '${screenId}' kind 'list' requires 'load'`, entry.loc);
172
+ }
173
+ if (kind === "detail") {
174
+ if (!directives.get("load")) {
175
+ pushError(errors, `Projection ${statement.id} screens for '${screenId}' kind 'detail' requires 'load'`, entry.loc);
176
+ }
177
+ if (!directives.get("view_shape")) {
178
+ pushError(errors, `Projection ${statement.id} screens for '${screenId}' kind 'detail' requires 'view_shape'`, entry.loc);
179
+ }
180
+ }
181
+ if (kind === "form") {
182
+ if (!directives.get("input_shape")) {
183
+ pushError(errors, `Projection ${statement.id} screens for '${screenId}' kind 'form' requires 'input_shape'`, entry.loc);
184
+ }
185
+ if (!directives.get("submit")) {
186
+ pushError(errors, `Projection ${statement.id} screens for '${screenId}' kind 'form' requires 'submit'`, entry.loc);
187
+ }
188
+ }
189
+ }
190
+
191
+ for (const entry of screensField.value.entries) {
192
+ const tokens = blockSymbolItems(entry).map((item) => item.value);
193
+ const screenId = tokens[1];
194
+ if (!screenId) {
195
+ continue;
196
+ }
197
+ const directives = parseUiDirectiveMap(tokens, 2, [], statement, entry, "");
198
+ for (const key of ["success_navigate", "success_refresh"]) {
199
+ const targetScreenId = directives.get(key);
200
+ if (targetScreenId && !seenScreens.has(targetScreenId)) {
201
+ pushError(errors, `Projection ${statement.id} screens for '${screenId}' references unknown screen '${targetScreenId}' for '${key}'`, entry.loc);
202
+ }
203
+ }
204
+ }
205
+ }
206
+
207
+ /**
208
+ * @param {ValidationErrors} errors
209
+ * @param {TopogramStatement} statement
210
+ * @param {TopogramFieldMap} fieldMap
211
+ * @returns {void}
212
+ */
213
+
214
+ export function validateProjectionUiAppShell(errors, statement, fieldMap) {
215
+ if (statement.kind !== "projection") {
216
+ return;
217
+ }
218
+
219
+ const shellField = fieldMap.get("app_shell")?.[0];
220
+ if (!shellField || shellField.value.type !== "block") {
221
+ return;
222
+ }
223
+
224
+ const seenKeys = new Set();
225
+ for (const entry of shellField.value.entries) {
226
+ const tokens = blockSymbolItems(entry).map((item) => item.value);
227
+ const [key, value, extra] = tokens;
228
+ if (!["brand", "shell", "primary_nav", "secondary_nav", "utility_nav", "footer", "global_search", "notifications", "account_menu", "workspace_switcher", "windowing"].includes(key || "")) {
229
+ pushError(errors, `Projection ${statement.id} app_shell has unknown key '${key}'`, entry.loc);
230
+ continue;
231
+ }
232
+ if (!value) {
233
+ pushError(errors, `Projection ${statement.id} app_shell is missing a value for '${key}'`, entry.loc);
234
+ continue;
235
+ }
236
+ if (extra) {
237
+ pushError(errors, `Projection ${statement.id} app_shell '${key}' accepts exactly one value`, entry.loc);
238
+ }
239
+ if (seenKeys.has(key)) {
240
+ pushError(errors, `Projection ${statement.id} app_shell has duplicate key '${key}'`, entry.loc);
241
+ }
242
+ seenKeys.add(key);
243
+
244
+ if (key === "shell" && !UI_APP_SHELL_KINDS.has(value)) {
245
+ pushError(errors, `Projection ${statement.id} app_shell has invalid shell '${value}'`, entry.loc);
246
+ }
247
+ if (["global_search", "notifications", "account_menu", "workspace_switcher"].includes(key) && !["true", "false"].includes(value)) {
248
+ pushError(errors, `Projection ${statement.id} app_shell '${key}' must be true or false`, entry.loc);
249
+ }
250
+ if (key === "windowing" && !UI_WINDOWING_MODES.has(value)) {
251
+ pushError(errors, `Projection ${statement.id} app_shell has invalid windowing '${value}'`, entry.loc);
252
+ }
253
+ }
254
+ }
255
+
256
+ /**
257
+ * @param {ValidationErrors} errors
258
+ * @param {TopogramStatement} statement
259
+ * @param {TopogramFieldMap} fieldMap
260
+ * @returns {void}
261
+ */
262
+
263
+ export function validateProjectionUiDesign(errors, statement, fieldMap) {
264
+ if (statement.kind !== "projection") {
265
+ return;
266
+ }
267
+
268
+ const designField = fieldMap.get("design_tokens")?.[0];
269
+ if (!designField || designField.value.type !== "block") {
270
+ return;
271
+ }
272
+
273
+ if (symbolValue(getFieldValue(statement, "type")) !== "ui_contract") {
274
+ pushError(errors, `Projection ${statement.id} design_tokens belongs on shared UI projections; concrete UI projections inherit semantic design intent through 'realizes'`, designField.loc);
275
+ }
276
+
277
+ for (const entry of designField.value.entries) {
278
+ const tokens = blockSymbolItems(entry).map((item) => item.value);
279
+ const [key, value, extra] = tokens;
280
+
281
+ if (key === "density") {
282
+ if (!UI_DESIGN_DENSITIES.has(value || "")) {
283
+ pushError(errors, `Projection ${statement.id} design_tokens density has invalid value '${value}'`, entry.loc);
284
+ }
285
+ if (tokens.length !== 2) {
286
+ pushError(errors, `Projection ${statement.id} design_tokens density accepts exactly one value`, entry.loc);
287
+ }
288
+ continue;
289
+ }
290
+
291
+ if (key === "tone") {
292
+ if (!UI_DESIGN_TONES.has(value || "")) {
293
+ pushError(errors, `Projection ${statement.id} design_tokens tone has invalid value '${value}'`, entry.loc);
294
+ }
295
+ if (tokens.length !== 2) {
296
+ pushError(errors, `Projection ${statement.id} design_tokens tone accepts exactly one value`, entry.loc);
297
+ }
298
+ continue;
299
+ }
300
+
301
+ if (key === "radius_scale") {
302
+ if (!UI_DESIGN_RADIUS_SCALES.has(value || "")) {
303
+ pushError(errors, `Projection ${statement.id} design_tokens radius_scale has invalid value '${value}'`, entry.loc);
304
+ }
305
+ if (tokens.length !== 2) {
306
+ pushError(errors, `Projection ${statement.id} design_tokens radius_scale accepts exactly one value`, entry.loc);
307
+ }
308
+ continue;
309
+ }
310
+
311
+ if (key === "color_role") {
312
+ if (!UI_DESIGN_COLOR_ROLES.has(value || "")) {
313
+ pushError(errors, `Projection ${statement.id} design_tokens color_role has invalid role '${value}'`, entry.loc);
314
+ }
315
+ if (tokens.length !== 3) {
316
+ pushError(errors, `Projection ${statement.id} design_tokens color_role must use 'color_role <role> <semantic-token>'`, entry.loc);
317
+ }
318
+ continue;
319
+ }
320
+
321
+ if (key === "typography_role") {
322
+ if (!UI_DESIGN_TYPOGRAPHY_ROLES.has(value || "")) {
323
+ pushError(errors, `Projection ${statement.id} design_tokens typography_role has invalid role '${value}'`, entry.loc);
324
+ }
325
+ if (tokens.length !== 3) {
326
+ pushError(errors, `Projection ${statement.id} design_tokens typography_role must use 'typography_role <role> <semantic-token>'`, entry.loc);
327
+ }
328
+ continue;
329
+ }
330
+
331
+ if (key === "action_role") {
332
+ if (!UI_DESIGN_ACTION_ROLES.has(value || "")) {
333
+ pushError(errors, `Projection ${statement.id} design_tokens action_role has invalid role '${value}'`, entry.loc);
334
+ }
335
+ if (tokens.length !== 3) {
336
+ pushError(errors, `Projection ${statement.id} design_tokens action_role must use 'action_role <role> <semantic-token>'`, entry.loc);
337
+ }
338
+ continue;
339
+ }
340
+
341
+ if (key === "accessibility") {
342
+ const values = UI_DESIGN_ACCESSIBILITY_VALUES[value];
343
+ if (tokens.length !== 3) {
344
+ pushError(errors, `Projection ${statement.id} design_tokens accessibility must use 'accessibility <setting> <value>'`, entry.loc);
345
+ }
346
+ if (!values) {
347
+ pushError(errors, `Projection ${statement.id} design_tokens accessibility has invalid setting '${value}'`, entry.loc);
348
+ } else if (!values.has(extra || "")) {
349
+ pushError(errors, `Projection ${statement.id} design_tokens accessibility '${value}' has invalid value '${extra}'`, entry.loc);
350
+ }
351
+ continue;
352
+ }
353
+
354
+ pushError(errors, `Projection ${statement.id} design_tokens has unknown key '${key}'`, entry.loc);
355
+ }
356
+ }
357
+
358
+ /**
359
+ * @param {ValidationErrors} errors
360
+ * @param {TopogramStatement} statement
361
+ * @param {TopogramFieldMap} fieldMap
362
+ * @param {TopogramRegistry} registry
363
+ * @returns {void}
364
+ */