@topogram/cli 0.3.64 → 0.3.65

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 (245) hide show
  1. package/package.json +1 -1
  2. package/src/adoption/plan/index.js +703 -0
  3. package/src/adoption/plan.js +12 -703
  4. package/src/agent-ops/query-builders/auth.js +375 -0
  5. package/src/agent-ops/query-builders/change-risk/change-plan.js +123 -0
  6. package/src/agent-ops/query-builders/change-risk/import-plan.js +49 -0
  7. package/src/agent-ops/query-builders/change-risk/maintained.js +286 -0
  8. package/src/agent-ops/query-builders/change-risk/review-packets.js +123 -0
  9. package/src/agent-ops/query-builders/change-risk/risk.js +189 -0
  10. package/src/agent-ops/query-builders/change-risk.js +25 -0
  11. package/src/agent-ops/query-builders/common.js +149 -0
  12. package/src/agent-ops/query-builders/maintained-risk.js +539 -0
  13. package/src/agent-ops/query-builders/maintained-shared.js +120 -0
  14. package/src/agent-ops/query-builders/multi-agent.js +547 -0
  15. package/src/agent-ops/query-builders/projection-impacts.js +514 -0
  16. package/src/agent-ops/query-builders/work-packets.js +417 -0
  17. package/src/agent-ops/query-builders/workflow-context-shared.js +300 -0
  18. package/src/agent-ops/query-builders/workflow-context.js +398 -0
  19. package/src/agent-ops/query-builders/workflow-presets-core.js +676 -0
  20. package/src/agent-ops/query-builders/workflow-presets.js +341 -0
  21. package/src/agent-ops/query-builders.d.ts +26 -26
  22. package/src/agent-ops/query-builders.js +42 -5021
  23. package/src/catalog/constants.js +10 -0
  24. package/src/catalog/copy.js +60 -0
  25. package/src/catalog/diagnostics.js +15 -0
  26. package/src/catalog/entries.js +42 -0
  27. package/src/catalog/files.js +67 -0
  28. package/src/catalog/provenance.js +122 -0
  29. package/src/catalog/source.js +150 -0
  30. package/src/catalog/validation.js +252 -0
  31. package/src/catalog.d.ts +2 -0
  32. package/src/catalog.js +18 -746
  33. package/src/cli/commands/catalog/check.js +31 -0
  34. package/src/cli/commands/catalog/copy.js +59 -0
  35. package/src/cli/commands/catalog/doctor.js +248 -0
  36. package/src/cli/commands/catalog/help.js +21 -0
  37. package/src/cli/commands/catalog/list.js +52 -0
  38. package/src/cli/commands/catalog/runner.js +92 -0
  39. package/src/cli/commands/catalog/shared.js +17 -0
  40. package/src/cli/commands/catalog/show.js +134 -0
  41. package/src/cli/commands/catalog.js +30 -615
  42. package/src/cli/commands/generator-policy/package-info.js +162 -0
  43. package/src/cli/commands/generator-policy/payloads.js +372 -0
  44. package/src/cli/commands/generator-policy/printers.js +159 -0
  45. package/src/cli/commands/generator-policy/runner.js +81 -0
  46. package/src/cli/commands/generator-policy/shared.js +39 -0
  47. package/src/cli/commands/generator-policy.js +15 -783
  48. package/src/cli/commands/import/adopt.js +170 -0
  49. package/src/cli/commands/import/check.js +91 -0
  50. package/src/cli/commands/import/diff.js +84 -0
  51. package/src/cli/commands/import/help.js +47 -0
  52. package/src/cli/commands/import/paths.js +277 -0
  53. package/src/cli/commands/import/plan.js +284 -0
  54. package/src/cli/commands/import/refresh.js +470 -0
  55. package/src/cli/commands/import/status-history.js +196 -0
  56. package/src/cli/commands/import/workspace.js +230 -0
  57. package/src/cli/commands/import.js +33 -1732
  58. package/src/cli/commands/package/constants.js +17 -0
  59. package/src/cli/commands/package/doctor.js +240 -0
  60. package/src/cli/commands/package/help.js +27 -0
  61. package/src/cli/commands/package/lockfile.js +135 -0
  62. package/src/cli/commands/package/npm.js +97 -0
  63. package/src/cli/commands/package/reporting.js +35 -0
  64. package/src/cli/commands/package/runner.js +33 -0
  65. package/src/cli/commands/package/shared.js +9 -0
  66. package/src/cli/commands/package/update-cli.js +252 -0
  67. package/src/cli/commands/package/versions.js +35 -0
  68. package/src/cli/commands/package.js +29 -813
  69. package/src/cli/commands/query/change-plan.js +68 -0
  70. package/src/cli/commands/query/definitions.js +202 -0
  71. package/src/cli/commands/query/import-adopt.js +121 -0
  72. package/src/cli/commands/query/runner/artifacts.js +102 -0
  73. package/src/cli/commands/query/runner/boundaries.js +211 -0
  74. package/src/cli/commands/query/runner/change.js +182 -0
  75. package/src/cli/commands/query/runner/import-adopt.js +111 -0
  76. package/src/cli/commands/query/runner/index.js +31 -0
  77. package/src/cli/commands/query/runner/output.js +12 -0
  78. package/src/cli/commands/query/runner/workflow.js +241 -0
  79. package/src/cli/commands/query/runner.js +3 -0
  80. package/src/cli/commands/query/workflow-context.js +5 -0
  81. package/src/cli/commands/query/workspace.js +274 -0
  82. package/src/cli/commands/query.js +9 -1300
  83. package/src/cli/commands/template/baseline.js +100 -0
  84. package/src/cli/commands/template/check.js +466 -0
  85. package/src/cli/commands/template/constants.js +8 -0
  86. package/src/cli/commands/template/diagnostics.js +26 -0
  87. package/src/cli/commands/template/help.js +28 -0
  88. package/src/cli/commands/template/lifecycle.js +404 -0
  89. package/src/cli/commands/template/list-show.js +287 -0
  90. package/src/cli/commands/template/policy.js +422 -0
  91. package/src/cli/commands/template/shared.js +127 -0
  92. package/src/cli/commands/template/updates.js +352 -0
  93. package/src/cli/commands/template.js +41 -2143
  94. package/src/generator/api/contracts.js +497 -0
  95. package/src/generator/api/metadata.js +221 -0
  96. package/src/generator/api/openapi.js +559 -0
  97. package/src/generator/api/schema.js +124 -0
  98. package/src/generator/api/types.d.ts +98 -0
  99. package/src/generator/api.js +3 -1195
  100. package/src/generator/context/shared/domain-sdlc.js +282 -0
  101. package/src/generator/context/shared/maintained-boundary.js +665 -0
  102. package/src/generator/context/shared/metrics.js +85 -0
  103. package/src/generator/context/shared/primitives.js +64 -0
  104. package/src/generator/context/shared/relationships.js +453 -0
  105. package/src/generator/context/shared/summaries.js +263 -0
  106. package/src/generator/context/shared/types.d.ts +207 -0
  107. package/src/generator/context/shared.d.ts +42 -0
  108. package/src/generator/context/shared.js +80 -1390
  109. package/src/generator/context/slice/core.js +397 -0
  110. package/src/generator/context/slice/sdlc.js +417 -0
  111. package/src/generator/context/slice/ui-packets.js +183 -0
  112. package/src/generator/context/slice.js +2 -859
  113. package/src/generator/registry/index.js +507 -0
  114. package/src/generator/registry.js +18 -504
  115. package/src/generator/runtime/environment/index.js +666 -0
  116. package/src/generator/runtime/environment.js +4 -666
  117. package/src/generator/runtime/runtime-check/index.js +554 -0
  118. package/src/generator/runtime/runtime-check.js +4 -554
  119. package/src/generator/runtime/shared/index.js +572 -0
  120. package/src/generator/runtime/shared.js +19 -570
  121. package/src/generator/shared.d.ts +2 -0
  122. package/src/generator/surfaces/shared.d.ts +3 -0
  123. package/src/generator/widget-conformance/behavior-report.js +258 -0
  124. package/src/generator/widget-conformance/checks.js +371 -0
  125. package/src/generator/widget-conformance/projection-context.js +200 -0
  126. package/src/generator/widget-conformance/report.js +166 -0
  127. package/src/generator/widget-conformance/types.d.ts +121 -0
  128. package/src/generator/widget-conformance.js +3 -824
  129. package/src/import/core/context.d.ts +3 -0
  130. package/src/import/core/contracts.d.ts +1 -0
  131. package/src/import/core/registry.d.ts +4 -0
  132. package/src/import/core/runner/candidates.js +217 -0
  133. package/src/import/core/runner/options.js +22 -0
  134. package/src/import/core/runner/reports.js +50 -0
  135. package/src/import/core/runner/run.js +79 -0
  136. package/src/import/core/runner/tracks.js +150 -0
  137. package/src/import/core/runner/ui-drafts.js +337 -0
  138. package/src/import/core/runner.js +3 -698
  139. package/src/import/core/shared/api-routes.js +221 -0
  140. package/src/import/core/shared/candidates.js +97 -0
  141. package/src/import/core/shared/files.js +177 -0
  142. package/src/import/core/shared/next-app.js +389 -0
  143. package/src/import/core/shared/types.d.ts +51 -0
  144. package/src/import/core/shared/ui-routes.js +230 -0
  145. package/src/import/core/shared.js +60 -861
  146. package/src/new-project/constants.js +128 -0
  147. package/src/new-project/create.js +83 -0
  148. package/src/new-project/json.js +28 -0
  149. package/src/new-project/metadata.js +96 -0
  150. package/src/new-project/package-spec.js +161 -0
  151. package/src/new-project/project-files.js +348 -0
  152. package/src/new-project/template-policy.js +269 -0
  153. package/src/new-project/template-resolution.js +368 -0
  154. package/src/new-project/template-snapshots.js +430 -0
  155. package/src/new-project/template-updates.js +512 -0
  156. package/src/new-project/types.d.ts +83 -0
  157. package/src/new-project.js +6 -2277
  158. package/src/parser.d.ts +87 -1
  159. package/src/parser.js +118 -0
  160. package/src/policy/review-boundaries.d.ts +15 -0
  161. package/src/project-config/index.js +564 -0
  162. package/src/project-config.js +19 -561
  163. package/src/resolver/enrich/acceptance-criterion.js +2 -0
  164. package/src/resolver/enrich/bug.js +2 -0
  165. package/src/resolver/enrich/pitch.js +2 -0
  166. package/src/resolver/enrich/requirement.js +2 -0
  167. package/src/resolver/enrich/task.js +2 -0
  168. package/src/resolver/index.js +19 -2089
  169. package/src/resolver/normalize.js +384 -1
  170. package/src/resolver/plans.js +168 -0
  171. package/src/resolver/projections-api.js +494 -0
  172. package/src/resolver/projections-db.js +133 -0
  173. package/src/resolver/projections-ui.js +317 -0
  174. package/src/resolver/shapes.js +251 -0
  175. package/src/resolver/shared.js +278 -0
  176. package/src/resolver/widgets.js +132 -0
  177. package/src/template-trust/constants.js +62 -0
  178. package/src/template-trust/content.js +258 -0
  179. package/src/template-trust/diff.js +92 -0
  180. package/src/template-trust/policy.js +61 -0
  181. package/src/template-trust/record.js +90 -0
  182. package/src/template-trust/status.js +182 -0
  183. package/src/template-trust.js +24 -687
  184. package/src/text-helpers.d.ts +1 -0
  185. package/src/topogram-types.d.ts +69 -0
  186. package/src/validator/common.js +488 -0
  187. package/src/validator/data-model.js +237 -0
  188. package/src/validator/docs.js +167 -0
  189. package/src/validator/expressions.js +146 -1
  190. package/src/validator/index.d.ts +23 -0
  191. package/src/validator/index.js +32 -3585
  192. package/src/validator/kinds.d.ts +41 -0
  193. package/src/validator/kinds.js +2 -0
  194. package/src/validator/model-helpers.js +46 -0
  195. package/src/validator/per-kind/acceptance-criterion.js +5 -0
  196. package/src/validator/per-kind/bug.js +6 -0
  197. package/src/validator/per-kind/domain.js +15 -2
  198. package/src/validator/per-kind/pitch.js +7 -0
  199. package/src/validator/per-kind/requirement.js +5 -0
  200. package/src/validator/per-kind/task.js +7 -0
  201. package/src/validator/per-kind/widget.js +14 -0
  202. package/src/validator/projections/api-http-async.js +410 -0
  203. package/src/validator/projections/api-http-authz.js +88 -0
  204. package/src/validator/projections/api-http-core.js +205 -0
  205. package/src/validator/projections/api-http-policies.js +339 -0
  206. package/src/validator/projections/api-http-responses.js +233 -0
  207. package/src/validator/projections/api-http.js +44 -0
  208. package/src/validator/projections/db.js +353 -0
  209. package/src/validator/projections/generator-defaults.js +45 -0
  210. package/src/validator/projections/helpers.js +87 -0
  211. package/src/validator/projections/ui-helpers.js +214 -0
  212. package/src/validator/projections/ui-navigation.js +344 -0
  213. package/src/validator/projections/ui-structure.js +364 -0
  214. package/src/validator/projections/ui-widgets.js +493 -0
  215. package/src/validator/projections/ui.js +46 -0
  216. package/src/validator/registry.js +48 -1
  217. package/src/validator/utils.d.ts +20 -0
  218. package/src/validator/utils.js +115 -12
  219. package/src/widget-behavior.d.ts +1 -0
  220. package/src/workflows/import-app/api/collect.js +221 -0
  221. package/src/workflows/import-app/api/openapi.js +257 -0
  222. package/src/workflows/import-app/api/routes.js +327 -0
  223. package/src/workflows/import-app/api/sources.js +22 -0
  224. package/src/workflows/import-app/api.js +2 -797
  225. package/src/workflows/reconcile/adoption-plan/build.js +208 -0
  226. package/src/workflows/reconcile/adoption-plan/dependencies.js +75 -0
  227. package/src/workflows/reconcile/adoption-plan/outputs.js +143 -0
  228. package/src/workflows/reconcile/adoption-plan/paths.js +58 -0
  229. package/src/workflows/reconcile/adoption-plan/projection-patches.js +177 -0
  230. package/src/workflows/reconcile/adoption-plan/reasons.js +107 -0
  231. package/src/workflows/reconcile/adoption-plan.js +30 -740
  232. package/src/workflows/reconcile/auth/closures.js +115 -0
  233. package/src/workflows/reconcile/auth/formatters.js +142 -0
  234. package/src/workflows/reconcile/auth/inference.js +330 -0
  235. package/src/workflows/reconcile/auth/roles.js +122 -0
  236. package/src/workflows/reconcile/auth.js +35 -690
  237. package/src/workflows/reconcile/bundle-core/index.js +600 -0
  238. package/src/workflows/reconcile/bundle-core.js +12 -598
  239. package/src/workflows/reconcile/canonical-surface.js +1 -1
  240. package/src/workflows/reconcile/impacts/adoption-plan.js +192 -0
  241. package/src/workflows/reconcile/impacts/indexes.js +101 -0
  242. package/src/workflows/reconcile/impacts/patches.js +252 -0
  243. package/src/workflows/reconcile/impacts/reports.js +80 -0
  244. package/src/workflows/reconcile/impacts.js +14 -623
  245. package/src/workspace-docs.d.ts +29 -0
@@ -0,0 +1,278 @@
1
+ import { blockEntries, getFieldValue, symbolValues, valueAsArray } from "../validator.js";
2
+
3
+ export function groupBy(items, keyFn) {
4
+ const grouped = {};
5
+ for (const item of items) {
6
+ const key = keyFn(item);
7
+ if (!Object.hasOwn(grouped, key)) {
8
+ grouped[key] = [];
9
+ }
10
+ grouped[key].push(item);
11
+ }
12
+ return grouped;
13
+ }
14
+
15
+ export function resolveReference(registry, id) {
16
+ return registry.get(id) || null;
17
+ }
18
+
19
+ export function toRef(target) {
20
+ if (!target) {
21
+ return null;
22
+ }
23
+
24
+ return {
25
+ id: target.id,
26
+ kind: target.kind
27
+ };
28
+ }
29
+
30
+ export function resolveReferenceList(registry, value) {
31
+ return symbolValues(value).map((id) => ({
32
+ id,
33
+ target: toRef(resolveReference(registry, id))
34
+ }));
35
+ }
36
+
37
+ export function resolveDomainTag(statement, registry) {
38
+ const domainField = statement.fields.find((field) => field.key === "domain");
39
+ if (!domainField || domainField.value.type !== "symbol") {
40
+ return null;
41
+ }
42
+ const id = domainField.value.value;
43
+ return {
44
+ id,
45
+ target: toRef(resolveReference(registry, id))
46
+ };
47
+ }
48
+
49
+ export function normalizeDomainScopeList(statement, key) {
50
+ const field = statement.fields.find((f) => f.key === key);
51
+ if (!field) return [];
52
+ const items = field.value.type === "list" || field.value.type === "sequence"
53
+ ? field.value.items
54
+ : [field.value];
55
+ return items
56
+ .map((item) => (item.type === "string" || item.type === "symbol" ? item.value : null))
57
+ .filter((value) => value !== null);
58
+ }
59
+
60
+ export function normalizeSequence(items) {
61
+ return items.map((item) => {
62
+ if (item.type === "symbol" || item.type === "string") {
63
+ return item.value;
64
+ }
65
+ if (item.type === "list") {
66
+ return item.items.map((nested) => nested.value);
67
+ }
68
+ return item.type;
69
+ });
70
+ }
71
+
72
+ export function normalizeFieldsBlock(statement, key = "fields") {
73
+ return blockEntries(getFieldValue(statement, key)).map((entry) => {
74
+ const [name, type, requiredness, ...rest] = entry.items;
75
+ let defaultValue = null;
76
+
77
+ for (let i = 0; i < rest.length - 1; i += 1) {
78
+ if (rest[i].type === "symbol" && rest[i].value === "default") {
79
+ defaultValue = rest[i + 1]?.value ?? null;
80
+ }
81
+ }
82
+
83
+ return {
84
+ name: name?.value ?? null,
85
+ fieldType: type?.value ?? null,
86
+ requiredness: requiredness?.value ?? null,
87
+ defaultValue,
88
+ raw: normalizeSequence(entry.items),
89
+ loc: entry.loc
90
+ };
91
+ });
92
+ }
93
+
94
+ export function normalizeGenericBlock(statement, key) {
95
+ return blockEntries(getFieldValue(statement, key)).map((entry) => ({
96
+ raw: normalizeSequence(entry.items),
97
+ loc: entry.loc
98
+ }));
99
+ }
100
+
101
+ export function tokenValue(token) {
102
+ return token?.value ?? null;
103
+ }
104
+
105
+ export function parseDefaultLiteral(token) {
106
+ if (!token) return null;
107
+ if (token.type === "list") {
108
+ return (token.items || []).map((item) => parseDefaultLiteral(item));
109
+ }
110
+ if (token.type === "string") {
111
+ return token.value ?? null;
112
+ }
113
+ if (token.type === "symbol") {
114
+ if (token.value === "true") return true;
115
+ if (token.value === "false") return false;
116
+ if (token.value === "null") return null;
117
+ if (/^-?\d+$/.test(token.value)) return Number.parseInt(token.value, 10);
118
+ if (/^-?\d+\.\d+$/.test(token.value)) return Number.parseFloat(token.value);
119
+ return token.value;
120
+ }
121
+ return token.value ?? null;
122
+ }
123
+
124
+ export function parseLiteralToken(token) {
125
+ const value = tokenValue(token);
126
+ if (value == null) {
127
+ return null;
128
+ }
129
+
130
+ if (value === "true") {
131
+ return { kind: "boolean", value: true };
132
+ }
133
+ if (value === "false") {
134
+ return { kind: "boolean", value: false };
135
+ }
136
+ if (value === "null") {
137
+ return { kind: "null", value: null };
138
+ }
139
+ if (/^-?\d+$/.test(value)) {
140
+ return { kind: "integer", value: Number.parseInt(value, 10) };
141
+ }
142
+ if (/^-?\d+\.\d+$/.test(value)) {
143
+ return { kind: "number", value: Number.parseFloat(value) };
144
+ }
145
+
146
+ return { kind: "symbol", value };
147
+ }
148
+
149
+ export function parseComparison(left, operator, right) {
150
+ if (!left || !operator || !right) {
151
+ return null;
152
+ }
153
+
154
+ return {
155
+ type: "comparison",
156
+ left: tokenValue(left),
157
+ operator,
158
+ right: parseLiteralToken(right)
159
+ };
160
+ }
161
+
162
+ export function parseInvariantEntry(entry) {
163
+ const tokens = entry.items;
164
+ const values = tokens.map((item) => item.value);
165
+ const [a, b, c, d, e, f, g] = tokens;
166
+
167
+ if (tokenValue(b) === "requires") {
168
+ return {
169
+ type: "requires",
170
+ field: tokenValue(a),
171
+ predicate: parseComparison(c, tokenValue(d), e),
172
+ raw: values,
173
+ loc: entry.loc
174
+ };
175
+ }
176
+
177
+ if (tokenValue(b) === "length") {
178
+ return {
179
+ type: "length_check",
180
+ field: tokenValue(a),
181
+ operator: tokenValue(c),
182
+ value: parseLiteralToken(d),
183
+ raw: values,
184
+ loc: entry.loc
185
+ };
186
+ }
187
+
188
+ if (tokenValue(b) === "format") {
189
+ return {
190
+ type: "format_check",
191
+ field: tokenValue(a),
192
+ operator: tokenValue(c),
193
+ format: tokenValue(d),
194
+ raw: values,
195
+ loc: entry.loc
196
+ };
197
+ }
198
+
199
+ if (tokenValue(d) === "implies") {
200
+ return {
201
+ type: "implication",
202
+ when: parseComparison(a, tokenValue(b), c),
203
+ then:
204
+ tokenValue(f) === "is"
205
+ ? {
206
+ type: "state_check",
207
+ field: tokenValue(e),
208
+ operator: "is",
209
+ value: parseLiteralToken(g)
210
+ }
211
+ : parseComparison(e, tokenValue(f), g),
212
+ raw: values,
213
+ loc: entry.loc
214
+ };
215
+ }
216
+
217
+ if (["==", "!=", "<", "<=", ">", ">="].includes(tokenValue(b))) {
218
+ return {
219
+ type: "comparison",
220
+ left: tokenValue(a),
221
+ operator: tokenValue(b),
222
+ right: parseLiteralToken(c),
223
+ raw: values,
224
+ loc: entry.loc
225
+ };
226
+ }
227
+
228
+ return {
229
+ type: "unknown",
230
+ raw: values,
231
+ loc: entry.loc
232
+ };
233
+ }
234
+
235
+ export function parseRuleExpression(value) {
236
+ const text = valueAsArray(value).map((item) => item.value).join(" ").trim();
237
+ const match = text.match(/^(.+?)\s*(==|!=|<=|>=|<|>)\s*(.+)$/);
238
+ if (!match) {
239
+ return {
240
+ type: "unknown",
241
+ raw: text
242
+ };
243
+ }
244
+
245
+ return {
246
+ type: "comparison",
247
+ left: match[1].trim(),
248
+ operator: match[2],
249
+ right: {
250
+ kind: "symbol",
251
+ value: match[3].trim()
252
+ },
253
+ raw: text
254
+ };
255
+ }
256
+
257
+ export function parseSymbolNode(value) {
258
+ return {
259
+ type: "symbol",
260
+ id: value
261
+ };
262
+ }
263
+
264
+ export function parseSymbolNodes(values) {
265
+ return values.map((value, index) => ({
266
+ ...parseSymbolNode(value),
267
+ order: index
268
+ }));
269
+ }
270
+
271
+ export function parseReferenceNodes(values) {
272
+ return values.map((entry, index) => ({
273
+ type: "reference",
274
+ id: entry.id,
275
+ target: entry.target || { id: entry.id, kind: null },
276
+ order: index
277
+ }));
278
+ }
@@ -0,0 +1,132 @@
1
+ import { blockEntries, getFieldValue, symbolValues } from "../validator.js";
2
+ import { normalizeSequence, parseDefaultLiteral, parseReferenceNodes, tokenValue } from "./shared.js";
3
+
4
+ export function normalizeWidgetProps(statement) {
5
+ return blockEntries(getFieldValue(statement, "props")).map((entry) => {
6
+ const [name, type, requiredness, ...rest] = entry.items;
7
+ let defaultValue = null;
8
+
9
+ for (let i = 0; i < rest.length - 1; i += 1) {
10
+ if (rest[i].type === "symbol" && rest[i].value === "default") {
11
+ defaultValue = parseDefaultLiteral(rest[i + 1]);
12
+ }
13
+ }
14
+
15
+ return {
16
+ name: name?.value ?? null,
17
+ fieldType: type?.value ?? null,
18
+ requiredness: requiredness?.value ?? null,
19
+ defaultValue,
20
+ raw: normalizeSequence(entry.items),
21
+ loc: entry.loc
22
+ };
23
+ });
24
+ }
25
+
26
+ export function normalizeWidgetEvents(statement, registry) {
27
+ return blockEntries(getFieldValue(statement, "events")).map((entry) => {
28
+ const [eventName, shapeRef] = entry.items;
29
+ const shapeId = tokenValue(shapeRef);
30
+ return {
31
+ id: tokenValue(eventName),
32
+ shape: shapeId
33
+ ? {
34
+ id: shapeId,
35
+ kind: registry.get(shapeId)?.kind || null
36
+ }
37
+ : null,
38
+ raw: normalizeSequence(entry.items),
39
+ loc: entry.loc
40
+ };
41
+ });
42
+ }
43
+
44
+ export function normalizeWidgetSlots(statement) {
45
+ return blockEntries(getFieldValue(statement, "slots")).map((entry) => ({
46
+ id: tokenValue(entry.items[0]),
47
+ description: tokenValue(entry.items[1]),
48
+ raw: normalizeSequence(entry.items),
49
+ loc: entry.loc
50
+ }));
51
+ }
52
+
53
+ export function normalizeBehaviorValue(token) {
54
+ if (!token) {
55
+ return null;
56
+ }
57
+ if (token.type === "list") {
58
+ return token.items.map((item) => normalizeBehaviorValue(item));
59
+ }
60
+ return parseDefaultLiteral(token);
61
+ }
62
+
63
+ export function normalizeWidgetBehaviors(statement) {
64
+ const structured = blockEntries(getFieldValue(statement, "behaviors")).map((entry) => {
65
+ const kind = tokenValue(entry.items[0]);
66
+ const directives = {};
67
+ for (let i = 1; i < entry.items.length; i += 2) {
68
+ const key = tokenValue(entry.items[i]);
69
+ if (!key) {
70
+ continue;
71
+ }
72
+ directives[key] = normalizeBehaviorValue(entry.items[i + 1]);
73
+ }
74
+ return {
75
+ kind,
76
+ directives,
77
+ source: "structured",
78
+ raw: normalizeSequence(entry.items),
79
+ loc: entry.loc
80
+ };
81
+ });
82
+
83
+ const structuredKinds = new Set(structured.map((entry) => entry.kind));
84
+ const shorthand = symbolValues(getFieldValue(statement, "behavior"))
85
+ .filter((kind) => !structuredKinds.has(kind))
86
+ .map((kind) => ({
87
+ kind,
88
+ directives: {},
89
+ source: "shorthand",
90
+ raw: [kind],
91
+ loc: null
92
+ }));
93
+
94
+ return [...structured, ...shorthand];
95
+ }
96
+
97
+ export function buildWidgetContract(statement) {
98
+ return {
99
+ type: "ui_widget_contract",
100
+ id: statement.id,
101
+ name: statement.name || statement.id,
102
+ description: statement.description || null,
103
+ category: statement.category || null,
104
+ version: statement.version || null,
105
+ status: statement.status || null,
106
+ props: (statement.props || []).map((prop) => ({
107
+ name: prop.name,
108
+ type: prop.fieldType,
109
+ requiredness: prop.requiredness,
110
+ defaultValue: prop.defaultValue ?? null
111
+ })),
112
+ events: (statement.events || []).map((event) => ({
113
+ id: event.id,
114
+ shape: event.shape || null
115
+ })),
116
+ slots: (statement.slots || []).map((slot) => ({
117
+ id: slot.id,
118
+ description: slot.description || null
119
+ })),
120
+ behavior: [...(statement.behavior || [])],
121
+ behaviors: (statement.behaviors || []).map((behavior) => ({
122
+ kind: behavior.kind,
123
+ directives: { ...(behavior.directives || {}) },
124
+ source: behavior.source || null
125
+ })),
126
+ patterns: [...(statement.patterns || [])],
127
+ regions: [...(statement.regions || [])],
128
+ approvals: [...(statement.approvals || [])],
129
+ lookups: parseReferenceNodes(statement.lookups || []),
130
+ dependencies: parseReferenceNodes(statement.dependencies || [])
131
+ };
132
+ }
@@ -0,0 +1,62 @@
1
+ // @ts-check
2
+
3
+ export const TEMPLATE_TRUST_FILE = ".topogram-template-trust.json";
4
+ export const TEMPLATE_TRUST_POLICY = "topogram-template-executable-implementation-v1";
5
+ export const IGNORED_IMPLEMENTATION_ENTRIES = new Set([".DS_Store", "node_modules", ".tmp"]);
6
+ export const MAX_TEXT_DIFF_BYTES = 256 * 1024;
7
+ export const TRUST_REVIEW_COMMANDS = "`topogram trust status`, `topogram trust diff`, and `topogram trust template`";
8
+
9
+ /**
10
+ * @param {string} value
11
+ * @returns {string}
12
+ */
13
+ export function normalizeRoot(value) {
14
+ return String(value || "").replace(/\\/g, "/");
15
+ }
16
+
17
+ /**
18
+ * @param {string} value
19
+ * @returns {string}
20
+ */
21
+ export function normalizeRelativePath(value) {
22
+ return value.replace(/\\/g, "/");
23
+ }
24
+
25
+ /**
26
+ * @param {string} relativePath
27
+ * @returns {string}
28
+ */
29
+ export function unsupportedImplementationSymlinkMessage(relativePath) {
30
+ return `Template implementation contains unsupported symlink '${relativePath}'. Implementation trust hashes real files under implementation/; symlinks can point outside the trusted root. Replace symlinks with real files under implementation/, then run ${TRUST_REVIEW_COMMANDS} after review.`;
31
+ }
32
+
33
+ /**
34
+ * @param {string} modulePath
35
+ * @returns {string}
36
+ */
37
+ export function implementationOutsideRootMessage(modulePath) {
38
+ return `Template implementation module '${modulePath}' must be under implementation/ for template-attached projects. Keep executable template code inside implementation/ so the trust record covers what topogram generate may load. Move the module back under implementation/, then run ${TRUST_REVIEW_COMMANDS} after review.`;
39
+ }
40
+
41
+ /**
42
+ * @param {string|string[]} issueOrIssues
43
+ * @returns {string}
44
+ */
45
+ export function templateTrustRecoveryGuidance(issueOrIssues) {
46
+ const issues = Array.isArray(issueOrIssues) ? issueOrIssues : [issueOrIssues];
47
+ const text = issues.join("\n");
48
+ if (issues.length > 0 && issues.every((issue) =>
49
+ issue.includes("topogram trust status") &&
50
+ issue.includes("topogram trust diff") &&
51
+ issue.includes("topogram trust template")
52
+ )) {
53
+ return "";
54
+ }
55
+ if (text.includes("unsupported symlink")) {
56
+ return `Replace symlinks with real files under implementation/, then run ${TRUST_REVIEW_COMMANDS} after review.`;
57
+ }
58
+ if (text.includes("must be under implementation/")) {
59
+ return `Keep executable template code under implementation/ so it can be hashed and trusted; move the module back under implementation/, then run ${TRUST_REVIEW_COMMANDS} after review.`;
60
+ }
61
+ return `Run \`topogram trust status\` and \`topogram trust diff\` to review implementation changes; after review, run \`topogram trust template\` to trust the current files.`;
62
+ }