@topogram/cli 0.3.63 → 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 (344) hide show
  1. package/package.json +1 -1
  2. package/src/adoption/plan/index.js +703 -0
  3. package/src/adoption/plan.d.ts +6 -0
  4. package/src/adoption/plan.js +12 -703
  5. package/src/adoption/reporting.d.ts +10 -0
  6. package/src/adoption/review-groups.d.ts +6 -0
  7. package/src/agent-brief.d.ts +3 -0
  8. package/src/agent-brief.js +495 -0
  9. package/src/agent-ops/query-builders/auth.js +375 -0
  10. package/src/agent-ops/query-builders/change-risk/change-plan.js +123 -0
  11. package/src/agent-ops/query-builders/change-risk/import-plan.js +49 -0
  12. package/src/agent-ops/query-builders/change-risk/maintained.js +286 -0
  13. package/src/agent-ops/query-builders/change-risk/review-packets.js +123 -0
  14. package/src/agent-ops/query-builders/change-risk/risk.js +189 -0
  15. package/src/agent-ops/query-builders/change-risk.js +25 -0
  16. package/src/agent-ops/query-builders/common.js +149 -0
  17. package/src/agent-ops/query-builders/maintained-risk.js +539 -0
  18. package/src/agent-ops/query-builders/maintained-shared.js +120 -0
  19. package/src/agent-ops/query-builders/multi-agent.js +547 -0
  20. package/src/agent-ops/query-builders/projection-impacts.js +514 -0
  21. package/src/agent-ops/query-builders/work-packets.js +417 -0
  22. package/src/agent-ops/query-builders/workflow-context-shared.js +300 -0
  23. package/src/agent-ops/query-builders/workflow-context.js +398 -0
  24. package/src/agent-ops/query-builders/workflow-presets-core.js +676 -0
  25. package/src/agent-ops/query-builders/workflow-presets.js +341 -0
  26. package/src/agent-ops/query-builders.d.ts +26 -0
  27. package/src/agent-ops/query-builders.js +42 -5021
  28. package/src/archive/archive.d.ts +2 -0
  29. package/src/archive/compact.d.ts +1 -0
  30. package/src/archive/unarchive.d.ts +1 -0
  31. package/src/catalog/constants.js +10 -0
  32. package/src/catalog/copy.js +60 -0
  33. package/src/catalog/diagnostics.js +15 -0
  34. package/src/catalog/entries.js +42 -0
  35. package/src/catalog/files.js +67 -0
  36. package/src/catalog/provenance.js +122 -0
  37. package/src/catalog/source.js +150 -0
  38. package/src/catalog/validation.js +252 -0
  39. package/src/catalog.d.ts +12 -0
  40. package/src/catalog.js +18 -750
  41. package/src/cli/catalog-alias.d.ts +1 -0
  42. package/src/cli/command-parser.js +38 -0
  43. package/src/cli/command-parsers/core.js +102 -0
  44. package/src/cli/command-parsers/generator.js +39 -0
  45. package/src/cli/command-parsers/import.js +44 -0
  46. package/src/cli/command-parsers/legacy-workflow.js +21 -0
  47. package/src/cli/command-parsers/project.js +47 -0
  48. package/src/cli/command-parsers/sdlc.js +47 -0
  49. package/src/cli/command-parsers/shared.js +51 -0
  50. package/src/cli/command-parsers/template.js +48 -0
  51. package/src/cli/commands/agent.js +47 -0
  52. package/src/cli/commands/catalog/check.js +31 -0
  53. package/src/cli/commands/catalog/copy.js +59 -0
  54. package/src/cli/commands/catalog/doctor.js +248 -0
  55. package/src/cli/commands/catalog/help.js +21 -0
  56. package/src/cli/commands/catalog/list.js +52 -0
  57. package/src/cli/commands/catalog/runner.js +92 -0
  58. package/src/cli/commands/catalog/shared.js +17 -0
  59. package/src/cli/commands/catalog/show.js +134 -0
  60. package/src/cli/commands/catalog.js +32 -0
  61. package/src/cli/commands/check.js +268 -0
  62. package/src/cli/commands/doctor.js +268 -0
  63. package/src/cli/commands/emit.js +149 -0
  64. package/src/cli/commands/generate.js +96 -0
  65. package/src/cli/commands/generator-policy/package-info.js +162 -0
  66. package/src/cli/commands/generator-policy/payloads.js +372 -0
  67. package/src/cli/commands/generator-policy/printers.js +159 -0
  68. package/src/cli/commands/generator-policy/runner.js +81 -0
  69. package/src/cli/commands/generator-policy/shared.js +39 -0
  70. package/src/cli/commands/generator-policy.js +17 -0
  71. package/src/cli/commands/generator.js +443 -0
  72. package/src/cli/commands/import/adopt.js +170 -0
  73. package/src/cli/commands/import/check.js +91 -0
  74. package/src/cli/commands/import/diff.js +84 -0
  75. package/src/cli/commands/import/help.js +47 -0
  76. package/src/cli/commands/import/paths.js +277 -0
  77. package/src/cli/commands/import/plan.js +284 -0
  78. package/src/cli/commands/import/refresh.js +470 -0
  79. package/src/cli/commands/import/status-history.js +196 -0
  80. package/src/cli/commands/import/workspace.js +230 -0
  81. package/src/cli/commands/import-runner.js +157 -0
  82. package/src/cli/commands/import.js +35 -0
  83. package/src/cli/commands/inspect.js +55 -0
  84. package/src/cli/commands/new.js +94 -0
  85. package/src/cli/commands/package/constants.js +17 -0
  86. package/src/cli/commands/package/doctor.js +240 -0
  87. package/src/cli/commands/package/help.js +27 -0
  88. package/src/cli/commands/package/lockfile.js +135 -0
  89. package/src/cli/commands/package/npm.js +97 -0
  90. package/src/cli/commands/package/reporting.js +35 -0
  91. package/src/cli/commands/package/runner.js +33 -0
  92. package/src/cli/commands/package/shared.js +9 -0
  93. package/src/cli/commands/package/update-cli.js +252 -0
  94. package/src/cli/commands/package/versions.js +35 -0
  95. package/src/cli/commands/package.js +31 -0
  96. package/src/cli/commands/query/change-plan.js +68 -0
  97. package/src/cli/commands/query/definitions.js +202 -0
  98. package/src/cli/commands/query/import-adopt.js +121 -0
  99. package/src/cli/commands/query/runner/artifacts.js +102 -0
  100. package/src/cli/commands/query/runner/boundaries.js +211 -0
  101. package/src/cli/commands/query/runner/change.js +182 -0
  102. package/src/cli/commands/query/runner/import-adopt.js +111 -0
  103. package/src/cli/commands/query/runner/index.js +31 -0
  104. package/src/cli/commands/query/runner/output.js +12 -0
  105. package/src/cli/commands/query/runner/workflow.js +241 -0
  106. package/src/cli/commands/query/runner.js +3 -0
  107. package/src/cli/commands/query/workflow-context.js +5 -0
  108. package/src/cli/commands/query/workspace.js +274 -0
  109. package/src/cli/commands/query.js +11 -0
  110. package/src/cli/commands/release-rollout.js +257 -0
  111. package/src/cli/commands/release-shared.js +528 -0
  112. package/src/cli/commands/release-status.js +429 -0
  113. package/src/cli/commands/release.js +107 -0
  114. package/src/cli/commands/sdlc.js +168 -0
  115. package/src/cli/commands/setup.js +76 -0
  116. package/src/cli/commands/source.js +291 -0
  117. package/src/cli/commands/template/baseline.js +100 -0
  118. package/src/cli/commands/template/check.js +466 -0
  119. package/src/cli/commands/template/constants.js +8 -0
  120. package/src/cli/commands/template/diagnostics.js +26 -0
  121. package/src/cli/commands/template/help.js +28 -0
  122. package/src/cli/commands/template/lifecycle.js +404 -0
  123. package/src/cli/commands/template/list-show.js +287 -0
  124. package/src/cli/commands/template/policy.js +422 -0
  125. package/src/cli/commands/template/shared.js +127 -0
  126. package/src/cli/commands/template/updates.js +352 -0
  127. package/src/cli/commands/template-runner.js +198 -0
  128. package/src/cli/commands/template.js +43 -0
  129. package/src/cli/commands/trust.js +219 -0
  130. package/src/cli/commands/version.js +40 -0
  131. package/src/cli/commands/widget.js +168 -0
  132. package/src/cli/commands/workflow.js +63 -0
  133. package/src/cli/dispatcher.js +392 -0
  134. package/src/cli/help-dispatch.js +188 -0
  135. package/src/cli/help.js +296 -0
  136. package/src/cli/migration-guidance.js +59 -0
  137. package/src/cli/options.js +96 -0
  138. package/src/cli/output-safety.js +107 -0
  139. package/src/cli/path-normalization.js +29 -0
  140. package/src/cli.js +47 -11711
  141. package/src/example-implementation.d.ts +2 -0
  142. package/src/format.d.ts +1 -0
  143. package/src/generator/api/contracts.js +497 -0
  144. package/src/generator/api/metadata.js +221 -0
  145. package/src/generator/api/openapi.js +559 -0
  146. package/src/generator/api/schema.js +124 -0
  147. package/src/generator/api/types.d.ts +98 -0
  148. package/src/generator/api.js +3 -1195
  149. package/src/generator/check.d.ts +1 -0
  150. package/src/generator/context/bundle.d.ts +1 -0
  151. package/src/generator/context/shared/domain-sdlc.js +282 -0
  152. package/src/generator/context/shared/maintained-boundary.js +665 -0
  153. package/src/generator/context/shared/metrics.js +85 -0
  154. package/src/generator/context/shared/primitives.js +64 -0
  155. package/src/generator/context/shared/relationships.js +453 -0
  156. package/src/generator/context/shared/summaries.js +263 -0
  157. package/src/generator/context/shared/types.d.ts +207 -0
  158. package/src/generator/context/shared.d.ts +44 -0
  159. package/src/generator/context/shared.js +80 -1390
  160. package/src/generator/context/slice/core.js +397 -0
  161. package/src/generator/context/slice/sdlc.js +417 -0
  162. package/src/generator/context/slice/ui-packets.js +183 -0
  163. package/src/generator/context/slice.js +2 -859
  164. package/src/generator/native/parity-bundle.js +2 -1
  165. package/src/generator/registry/index.js +507 -0
  166. package/src/generator/registry.js +18 -504
  167. package/src/generator/runtime/environment/index.js +666 -0
  168. package/src/generator/runtime/environment.js +4 -666
  169. package/src/generator/runtime/runtime-check/index.js +554 -0
  170. package/src/generator/runtime/runtime-check.js +4 -554
  171. package/src/generator/runtime/shared/index.js +572 -0
  172. package/src/generator/runtime/shared.js +19 -570
  173. package/src/generator/shared.d.ts +2 -0
  174. package/src/generator/surfaces/shared.d.ts +3 -0
  175. package/src/generator/surfaces/web/html-escape.js +22 -0
  176. package/src/generator/surfaces/web/react.js +10 -8
  177. package/src/generator/surfaces/web/sveltekit.js +7 -5
  178. package/src/generator/surfaces/web/vanilla.js +8 -4
  179. package/src/generator/widget-conformance/behavior-report.js +258 -0
  180. package/src/generator/widget-conformance/checks.js +371 -0
  181. package/src/generator/widget-conformance/projection-context.js +200 -0
  182. package/src/generator/widget-conformance/report.js +166 -0
  183. package/src/generator/widget-conformance/types.d.ts +121 -0
  184. package/src/generator/widget-conformance.js +3 -824
  185. package/src/generator.d.ts +2 -0
  186. package/src/github-client.js +520 -0
  187. package/src/import/core/context.d.ts +3 -0
  188. package/src/import/core/contracts.d.ts +1 -0
  189. package/src/import/core/registry.d.ts +4 -0
  190. package/src/import/core/runner/candidates.js +217 -0
  191. package/src/import/core/runner/options.js +22 -0
  192. package/src/import/core/runner/reports.js +50 -0
  193. package/src/import/core/runner/run.js +79 -0
  194. package/src/import/core/runner/tracks.js +150 -0
  195. package/src/import/core/runner/ui-drafts.js +337 -0
  196. package/src/import/core/runner.js +3 -698
  197. package/src/import/core/shared/api-routes.js +221 -0
  198. package/src/import/core/shared/candidates.js +97 -0
  199. package/src/import/core/shared/files.js +177 -0
  200. package/src/import/core/shared/next-app.js +389 -0
  201. package/src/import/core/shared/types.d.ts +51 -0
  202. package/src/import/core/shared/ui-routes.js +230 -0
  203. package/src/import/core/shared.js +67 -910
  204. package/src/import/extractors/api/flutter-dio.js +4 -8
  205. package/src/import/extractors/api/react-native-repository.js +4 -8
  206. package/src/import/index.d.ts +4 -0
  207. package/src/import/provenance.d.ts +4 -0
  208. package/src/new-project/constants.js +128 -0
  209. package/src/new-project/create.js +83 -0
  210. package/src/new-project/json.js +28 -0
  211. package/src/new-project/metadata.js +96 -0
  212. package/src/new-project/package-spec.js +161 -0
  213. package/src/new-project/project-files.js +348 -0
  214. package/src/new-project/template-policy.js +269 -0
  215. package/src/new-project/template-resolution.js +368 -0
  216. package/src/new-project/template-snapshots.js +430 -0
  217. package/src/new-project/template-updates.js +512 -0
  218. package/src/new-project/types.d.ts +83 -0
  219. package/src/new-project.js +6 -2188
  220. package/src/npm-safety.js +79 -0
  221. package/src/parser.d.ts +87 -0
  222. package/src/parser.js +118 -0
  223. package/src/path-helpers.d.ts +1 -0
  224. package/src/path-helpers.js +20 -0
  225. package/src/policy/review-boundaries.d.ts +15 -0
  226. package/src/project-config/index.js +564 -0
  227. package/src/project-config.js +19 -560
  228. package/src/reconcile/docs.d.ts +8 -0
  229. package/src/reconcile/journeys.d.ts +1 -0
  230. package/src/resolver/enrich/acceptance-criterion.js +2 -0
  231. package/src/resolver/enrich/bug.js +2 -0
  232. package/src/resolver/enrich/pitch.js +2 -0
  233. package/src/resolver/enrich/requirement.js +2 -0
  234. package/src/resolver/enrich/task.js +2 -0
  235. package/src/resolver/index.js +19 -2089
  236. package/src/resolver/normalize.js +384 -1
  237. package/src/resolver/plans.js +168 -0
  238. package/src/resolver/projections-api.js +494 -0
  239. package/src/resolver/projections-db.js +133 -0
  240. package/src/resolver/projections-ui.js +317 -0
  241. package/src/resolver/shapes.js +251 -0
  242. package/src/resolver/shared.js +278 -0
  243. package/src/resolver/widgets.js +132 -0
  244. package/src/resolver.d.ts +1 -0
  245. package/src/runtime-support.js +29 -0
  246. package/src/sdlc/adopt.d.ts +1 -0
  247. package/src/sdlc/check.d.ts +1 -0
  248. package/src/sdlc/explain.d.ts +1 -0
  249. package/src/sdlc/release.d.ts +1 -0
  250. package/src/sdlc/scaffold.d.ts +1 -0
  251. package/src/sdlc/transition.d.ts +1 -0
  252. package/src/template-trust/constants.js +62 -0
  253. package/src/template-trust/content.js +258 -0
  254. package/src/template-trust/diff.js +92 -0
  255. package/src/template-trust/policy.js +61 -0
  256. package/src/template-trust/record.js +90 -0
  257. package/src/template-trust/status.js +182 -0
  258. package/src/template-trust.js +24 -687
  259. package/src/text-helpers.d.ts +7 -0
  260. package/src/text-helpers.js +245 -0
  261. package/src/topogram-config.js +306 -0
  262. package/src/topogram-types.d.ts +69 -0
  263. package/src/validator/common.js +488 -0
  264. package/src/validator/data-model.js +237 -0
  265. package/src/validator/docs.js +167 -0
  266. package/src/validator/expressions.js +146 -1
  267. package/src/validator/index.d.ts +23 -0
  268. package/src/validator/index.js +32 -3585
  269. package/src/validator/kinds.d.ts +41 -0
  270. package/src/validator/kinds.js +2 -0
  271. package/src/validator/model-helpers.js +46 -0
  272. package/src/validator/per-kind/acceptance-criterion.js +5 -0
  273. package/src/validator/per-kind/bug.js +6 -0
  274. package/src/validator/per-kind/domain.js +15 -2
  275. package/src/validator/per-kind/pitch.js +7 -0
  276. package/src/validator/per-kind/requirement.js +5 -0
  277. package/src/validator/per-kind/task.js +7 -0
  278. package/src/validator/per-kind/widget.js +14 -0
  279. package/src/validator/projections/api-http-async.js +410 -0
  280. package/src/validator/projections/api-http-authz.js +88 -0
  281. package/src/validator/projections/api-http-core.js +205 -0
  282. package/src/validator/projections/api-http-policies.js +339 -0
  283. package/src/validator/projections/api-http-responses.js +233 -0
  284. package/src/validator/projections/api-http.js +44 -0
  285. package/src/validator/projections/db.js +353 -0
  286. package/src/validator/projections/generator-defaults.js +45 -0
  287. package/src/validator/projections/helpers.js +87 -0
  288. package/src/validator/projections/ui-helpers.js +214 -0
  289. package/src/validator/projections/ui-navigation.js +344 -0
  290. package/src/validator/projections/ui-structure.js +364 -0
  291. package/src/validator/projections/ui-widgets.js +493 -0
  292. package/src/validator/projections/ui.js +46 -0
  293. package/src/validator/registry.js +48 -1
  294. package/src/validator/utils.d.ts +20 -0
  295. package/src/validator/utils.js +115 -12
  296. package/src/validator.d.ts +2 -0
  297. package/src/widget-behavior.d.ts +1 -0
  298. package/src/workflows/adoption/index.js +26 -0
  299. package/src/workflows/docs-generate.js +262 -0
  300. package/src/workflows/docs-scan.js +703 -0
  301. package/src/workflows/docs.js +15 -0
  302. package/src/workflows/import-app/api/collect.js +221 -0
  303. package/src/workflows/import-app/api/openapi.js +257 -0
  304. package/src/workflows/import-app/api/routes.js +327 -0
  305. package/src/workflows/import-app/api/sources.js +22 -0
  306. package/src/workflows/import-app/api.js +4 -0
  307. package/src/workflows/import-app/db.js +538 -0
  308. package/src/workflows/import-app/index.js +30 -0
  309. package/src/workflows/import-app/shared.js +218 -0
  310. package/src/workflows/import-app/ui.js +443 -0
  311. package/src/workflows/import-app/workflow.js +159 -0
  312. package/src/workflows/reconcile/adoption-plan/build.js +208 -0
  313. package/src/workflows/reconcile/adoption-plan/dependencies.js +75 -0
  314. package/src/workflows/reconcile/adoption-plan/outputs.js +143 -0
  315. package/src/workflows/reconcile/adoption-plan/paths.js +58 -0
  316. package/src/workflows/reconcile/adoption-plan/projection-patches.js +177 -0
  317. package/src/workflows/reconcile/adoption-plan/reasons.js +107 -0
  318. package/src/workflows/reconcile/adoption-plan.js +32 -0
  319. package/src/workflows/reconcile/auth/closures.js +115 -0
  320. package/src/workflows/reconcile/auth/formatters.js +142 -0
  321. package/src/workflows/reconcile/auth/inference.js +330 -0
  322. package/src/workflows/reconcile/auth/roles.js +122 -0
  323. package/src/workflows/reconcile/auth.js +37 -0
  324. package/src/workflows/reconcile/bundle-core/index.js +600 -0
  325. package/src/workflows/reconcile/bundle-core.js +14 -0
  326. package/src/workflows/reconcile/bundle-shared.js +75 -0
  327. package/src/workflows/reconcile/candidate-model.js +477 -0
  328. package/src/workflows/reconcile/canonical-surface.js +264 -0
  329. package/src/workflows/reconcile/gap-report.js +333 -0
  330. package/src/workflows/reconcile/ids.js +6 -0
  331. package/src/workflows/reconcile/impacts/adoption-plan.js +192 -0
  332. package/src/workflows/reconcile/impacts/indexes.js +101 -0
  333. package/src/workflows/reconcile/impacts/patches.js +252 -0
  334. package/src/workflows/reconcile/impacts/reports.js +80 -0
  335. package/src/workflows/reconcile/impacts.js +16 -0
  336. package/src/workflows/reconcile/index.js +7 -0
  337. package/src/workflows/reconcile/renderers.js +461 -0
  338. package/src/workflows/reconcile/summary.js +90 -0
  339. package/src/workflows/reconcile/workflow.js +309 -0
  340. package/src/workflows/shared.js +189 -0
  341. package/src/workflows/types.d.ts +93 -0
  342. package/src/workflows.d.ts +1 -0
  343. package/src/workflows.js +10 -7652
  344. package/src/workspace-docs.d.ts +29 -0
@@ -0,0 +1,337 @@
1
+ // @ts-check
2
+
3
+ import { ensureTrailingNewline } from "../shared.js";
4
+ import {
5
+ capabilityHintsForScreen,
6
+ importedApiCapabilityIds,
7
+ inferredDataSourceForWidget,
8
+ uiWidgetCandidates
9
+ } from "./candidates.js";
10
+
11
+ /**
12
+ * @param {any[]} values
13
+ * @returns {string[]}
14
+ */
15
+ function uniqueSorted(values) {
16
+ return [...new Set((values || []).filter(Boolean).map(String))].sort();
17
+ }
18
+
19
+ /**
20
+ * @param {string} workspaceRoot
21
+ * @returns {string}
22
+ */
23
+ function projectionIdStem(workspaceRoot) {
24
+ const base = String(workspaceRoot || "").split(/[\\/]/).filter(Boolean).pop() || "imported_app";
25
+ return base
26
+ .toLowerCase()
27
+ .replace(/[^a-z0-9]+/g, "_")
28
+ .replace(/^_+|_+$/g, "") || "imported_app";
29
+ }
30
+
31
+ /**
32
+ * @param {any} widget
33
+ * @returns {string}
34
+ */
35
+ function widgetCandidateFileName(widget) {
36
+ return `${String(widget.id_hint || "widget")
37
+ .replace(/^component_/, "")
38
+ .replace(/_/g, "-")}.tg`;
39
+ }
40
+
41
+ /**
42
+ * @param {any} widget
43
+ * @returns {string}
44
+ */
45
+ function renderWidgetCandidate(widget) {
46
+ const evidenceCount = (widget.evidence || widget.provenance || []).length;
47
+ const missingDecisions = widget.missing_decisions || [
48
+ "confirm widget reuse boundary",
49
+ "confirm prop names and data source",
50
+ "confirm events and behavior"
51
+ ];
52
+ return `widget ${widget.id_hint} {
53
+ # Import metadata: confidence ${widget.confidence || "unknown"}; evidence ${evidenceCount}; inferred pattern ${widget.pattern || widget.inferred_pattern || "search_results"}; inferred region ${widget.region || widget.inferred_region || "results"}.
54
+ # Missing decisions: ${missingDecisions.join("; ")}.
55
+ name "${widget.label || widget.id_hint}"
56
+ description "Candidate reusable widget inferred from imported UI evidence. Review props, behavior, events, and reuse before adoption."
57
+ category collection
58
+ props {
59
+ ${widget.data_prop || "rows"} array required
60
+ }
61
+ patterns [${widget.pattern || "search_results"}]
62
+ regions [${widget.region || "results"}]
63
+ status proposed
64
+ }
65
+ `;
66
+ }
67
+
68
+ /**
69
+ * @param {any[]} widgetCandidates
70
+ * @param {Record<string, any>} allCandidates
71
+ * @returns {string[]}
72
+ */
73
+ function uiWidgetLinesForCandidates(widgetCandidates, allCandidates) {
74
+ return widgetCandidates
75
+ .filter((widget) => widget.screen_id && widget.region && widget.id_hint)
76
+ .map((widget) => {
77
+ const dataSource = inferredDataSourceForWidget(widget, allCandidates);
78
+ const dataBinding = dataSource
79
+ ? ` data ${widget.data_prop || "rows"} from ${dataSource}`
80
+ : "";
81
+ return ` screen ${widget.screen_id} region ${widget.region} widget ${widget.id_hint}${dataBinding}`;
82
+ });
83
+ }
84
+
85
+ /**
86
+ * @param {any} context
87
+ * @param {any} candidates
88
+ * @param {Record<string, any>} allCandidates
89
+ * @returns {Record<string, string>}
90
+ */
91
+ export function draftUiProjectionFiles(context, candidates, allCandidates = {}) {
92
+ const ui = candidates || { screens: [], routes: [], actions: [], stacks: [] };
93
+ /** @type {any[]} */
94
+ const screens = [...(ui.screens || [])].sort((a, b) => String(a.route_path || "").localeCompare(String(b.route_path || "")) || a.id_hint.localeCompare(b.id_hint));
95
+ /** @type {any[]} */
96
+ const uiRoutes = ui.routes || [];
97
+ /** @type {Map<string, string>} */
98
+ const routes = new Map(uiRoutes.map((route) => [route.screen_id, route.path]));
99
+ /** @type {any[]} */
100
+ const actions = ui.actions || [];
101
+ const widgetCandidates = [...uiWidgetCandidates(ui)].sort((a, b) => a.id_hint.localeCompare(b.id_hint));
102
+ const shell = actions.find((entry) => entry.kind === "ui_shell")?.shell_kind || "topbar";
103
+ const navigationPatterns = uniqueSorted(actions.filter((entry) => entry.kind === "navigation").map((entry) => entry.navigation_pattern));
104
+ const presentations = uniqueSorted(actions.filter((entry) => entry.kind === "ui_presentation").map((entry) => entry.presentation));
105
+ const capabilityHints = uniqueSorted([
106
+ ...screens.flatMap((screen) => capabilityHintsForScreen(screen)),
107
+ ...actions.map((entry) => entry.capability_hint).filter(Boolean),
108
+ ...importedApiCapabilityIds(allCandidates)
109
+ ]);
110
+ const stem = projectionIdStem(context.paths.workspaceRoot);
111
+ const defaultScreenId = screens.find((screen) => screen.screen_kind === "list")?.id_hint || screens[0]?.id_hint || null;
112
+
113
+ const uiScreensBlock = screens.length > 0
114
+ ? screens.map((screen) => {
115
+ const directives = [`kind ${screen.screen_kind || "flow"}`, `title "${screen.label || screen.id_hint}"`];
116
+ const screenCapabilityHints = capabilityHintsForScreen(screen);
117
+ if (screenCapabilityHints.length > 0) {
118
+ const loadHint = screenCapabilityHints.find((hint) => /^cap_(list|get)_/.test(hint));
119
+ const submitHint = screenCapabilityHints.find((hint) => /^cap_(create|update|sign_in|follow|delete)_/.test(hint));
120
+ if (loadHint && ["list", "detail", "job_status", "feed", "inbox", "dashboard", "analytics", "report"].includes(screen.screen_kind)) {
121
+ directives.push(`load ${loadHint}`);
122
+ }
123
+ if (submitHint && ["form", "wizard", "settings", "flow"].includes(screen.screen_kind)) {
124
+ directives.push(`submit ${submitHint}`);
125
+ }
126
+ }
127
+ return ` screen ${screen.id_hint} ${directives.join(" ")}`;
128
+ }).join("\n")
129
+ : " // No imported screens detected";
130
+
131
+ const collectionScreens = screens.filter((screen) => screen.screen_kind === "list");
132
+ const uiCollectionsLines = [];
133
+ for (const screen of collectionScreens) {
134
+ const screenPresentations = presentations.filter((presentation) =>
135
+ ["table", "data_grid", "cards", "board", "calendar", "gallery", "list"].includes(presentation)
136
+ );
137
+ const preferredView =
138
+ screenPresentations.find((presentation) => ["data_grid", "table", "cards", "list"].includes(presentation))
139
+ || "list";
140
+ uiCollectionsLines.push(` screen ${screen.id_hint} view ${preferredView}`);
141
+ if (presentations.includes("pull_to_refresh")) {
142
+ uiCollectionsLines.push(` screen ${screen.id_hint} refresh pull_to_refresh`);
143
+ }
144
+ if (presentations.includes("search")) {
145
+ uiCollectionsLines.push(` screen ${screen.id_hint} search query`);
146
+ }
147
+ }
148
+
149
+ const uiActionsLines = actions
150
+ .filter((entry) => entry.kind === "ui_action" && entry.screen_id && entry.capability_hint)
151
+ .map((entry) => ` screen ${entry.screen_id} action ${entry.capability_hint} prominence ${entry.prominence || "secondary"}`);
152
+
153
+ const uiNavigationLines = [];
154
+ if (defaultScreenId) {
155
+ if (navigationPatterns.includes("command_palette")) {
156
+ uiNavigationLines.push(` group workspace label "Workspace" placement primary pattern command_palette`);
157
+ } else {
158
+ uiNavigationLines.push(` group workspace label "Workspace" placement primary`);
159
+ }
160
+ }
161
+ for (const screen of screens) {
162
+ const directives = [
163
+ "group workspace",
164
+ `label "${screen.label || screen.id_hint}"`,
165
+ screen.id_hint === defaultScreenId ? "default true" : null,
166
+ screen.id_hint === defaultScreenId || screen.screen_kind === "list" ? "visible true" : "visible false"
167
+ ].filter(Boolean);
168
+ const matchedPattern =
169
+ navigationPatterns.find((pattern) =>
170
+ (pattern === "stack_navigation" && screen.screen_kind === "detail")
171
+ || (pattern === "segmented_control" && screen.screen_kind === "list")
172
+ || (pattern === "bottom_tabs" && screen.screen_kind === "list")
173
+ ) || null;
174
+ if (matchedPattern) {
175
+ directives.push(`pattern ${matchedPattern}`);
176
+ }
177
+ if (screen.screen_kind === "detail" && defaultScreenId && screen.id_hint !== defaultScreenId) {
178
+ directives.push(`breadcrumb ${defaultScreenId}`);
179
+ directives.push("sitemap exclude");
180
+ }
181
+ uiNavigationLines.push(` screen ${screen.id_hint} ${directives.join(" ")}`);
182
+ }
183
+
184
+ const uiScreenRegionLines = [];
185
+ for (const screen of screens) {
186
+ if (screen.screen_kind === "list") {
187
+ uiScreenRegionLines.push(` screen ${screen.id_hint} region toolbar pattern action_bar placement primary`);
188
+ const preferredPattern =
189
+ presentations.includes("data_grid") ? "data_grid_view"
190
+ : presentations.includes("table") ? "resource_table"
191
+ : presentations.includes("cards") ? "resource_cards"
192
+ : "search_results";
193
+ uiScreenRegionLines.push(` screen ${screen.id_hint} region results pattern ${preferredPattern} placement primary`);
194
+ }
195
+ if (screen.screen_kind === "detail") {
196
+ uiScreenRegionLines.push(` screen ${screen.id_hint} region summary pattern detail_panel placement primary`);
197
+ if (presentations.includes("inspector_pane")) {
198
+ uiScreenRegionLines.push(` screen ${screen.id_hint} region aside pattern inspector_pane placement supporting`);
199
+ }
200
+ }
201
+ }
202
+ const uiWidgetLines = uiWidgetLinesForCandidates(widgetCandidates, allCandidates);
203
+
204
+ const uiSharedDraft = `projection proj_ui_contract_imported_${stem} {
205
+ name "Imported UI Contract Draft"
206
+ description "Drafted from imported UI candidates. Review and adapt before adoption."
207
+
208
+ type ui_contract
209
+ realizes [
210
+ ${capabilityHints.length > 0 ? capabilityHints.map((hint) => ` ${hint}`).join(",\n") : " // add capability ids"}
211
+ ]
212
+ outputs [ui_contract]
213
+
214
+ app_shell {
215
+ brand "Imported ${stem.replace(/_/g, " ")}"
216
+ shell ${shell}
217
+ ${presentations.includes("search") ? " global_search true\n" : ""}${presentations.includes("multi_window") ? " windowing multi_window\n" : ""} }
218
+
219
+ design_tokens {
220
+ density comfortable
221
+ tone operational
222
+ radius_scale medium
223
+ color_role primary accent
224
+ color_role danger critical
225
+ typography_role body readable
226
+ typography_role heading prominent
227
+ action_role primary prominent
228
+ action_role destructive danger
229
+ accessibility contrast aa
230
+ accessibility focus visible
231
+ }
232
+
233
+ screens {
234
+ ${uiScreensBlock}
235
+ }
236
+
237
+ ${uiCollectionsLines.length > 0 ? ` collection_views {\n${uiCollectionsLines.join("\n")}\n }\n\n` : ""}${uiActionsLines.length > 0 ? ` screen_actions {\n${uiActionsLines.join("\n")}\n }\n\n` : ""} navigation {
238
+ ${uiNavigationLines.join("\n")}
239
+ }
240
+
241
+ ${uiScreenRegionLines.length > 0 ? ` screen_regions {\n${uiScreenRegionLines.join("\n")}\n }\n\n` : ""}${uiWidgetLines.length > 0 ? ` widget_bindings {\n${uiWidgetLines.join("\n")}\n }\n\n` : ""} status proposed
242
+ }
243
+ `;
244
+
245
+ const webCapHints = capabilityHints.length > 0 ? capabilityHints.join(",\n ") : "// add capability ids";
246
+ const uiRouteLines = screens
247
+ .filter((screen) => routes.has(screen.id_hint))
248
+ .map((screen) => ` screen ${screen.id_hint} path ${routes.get(screen.id_hint)}`);
249
+ const uiWebLines = [];
250
+ for (const screen of screens) {
251
+ if (!routes.has(screen.id_hint)) continue;
252
+ if (screen.id_hint === defaultScreenId) {
253
+ uiWebLines.push(` screen ${screen.id_hint} shell ${shell}`);
254
+ }
255
+ if (screen.screen_kind === "list") {
256
+ const preferredCollection =
257
+ presentations.includes("data_grid") ? "data_grid"
258
+ : presentations.includes("table") ? "table"
259
+ : presentations.includes("cards") ? "cards"
260
+ : "list";
261
+ uiWebLines.push(` screen ${screen.id_hint} collection ${preferredCollection}`);
262
+ if (presentations.includes("cards")) {
263
+ uiWebLines.push(` screen ${screen.id_hint} mobile_variant cards`);
264
+ }
265
+ }
266
+ if (screen.screen_kind === "detail" && presentations.includes("sheet")) {
267
+ uiWebLines.push(` screen ${screen.id_hint} present sheet`);
268
+ }
269
+ if (screen.screen_kind === "detail" && presentations.includes("popover")) {
270
+ uiWebLines.push(` screen ${screen.id_hint} present popover`);
271
+ }
272
+ }
273
+ for (const entry of actions.filter((action) => action.kind === "ui_action" && action.capability_hint)) {
274
+ const actionPresent =
275
+ presentations.includes("fab") ? "fab"
276
+ : presentations.includes("popover") ? "popover"
277
+ : "button";
278
+ uiWebLines.push(` action ${entry.capability_hint} present ${actionPresent}`);
279
+ }
280
+
281
+ const uiWebDraft = `projection proj_web_surface_imported_${stem} {
282
+ name "Imported Web Surface Draft"
283
+ description "Drafted from imported UI candidates. Review and adapt before adoption."
284
+
285
+ type web_surface
286
+ realizes [
287
+ proj_ui_contract_imported_${stem},
288
+ ${webCapHints}
289
+ ]
290
+ outputs [ui_contract, web_app]
291
+
292
+ screen_routes {
293
+ ${uiRouteLines.length > 0 ? uiRouteLines.join("\n") : " // add routes"}
294
+ }
295
+
296
+ ${uiWebLines.length > 0 ? ` web_hints {\n${uiWebLines.join("\n")}\n }\n\n` : ""} generator_defaults {
297
+ profile react
298
+ language typescript
299
+ styling css
300
+ }
301
+
302
+ status proposed
303
+ }
304
+ `;
305
+
306
+ const coverage = `# Imported UI Projection Drafts
307
+
308
+ - Draft UI contract projection: \`candidates/app/ui/drafts/proj-ui-contract.tg\`
309
+ - Draft web surface projection: \`candidates/app/ui/drafts/proj-web-surface.tg\`
310
+ - Draft widget candidates: ${widgetCandidates.length}
311
+ - Imported screens: ${screens.length}
312
+ - Imported routes: ${(ui.routes || []).length}
313
+ - Imported UI actions/presentations: ${actions.length}
314
+ - Imported navigation patterns: ${navigationPatterns.length ? navigationPatterns.join(", ") : "none"}
315
+ - Imported presentations: ${presentations.length ? presentations.join(", ") : "none"}
316
+
317
+ ## Review Notes
318
+
319
+ - These files are drafts, not adopted canonical projections.
320
+ - Capability ids come from imported hints and may need renaming or pruning.
321
+ - Widget candidates are suggested reusable contracts, not canonical ownership.
322
+ - Review widget props, events, behavior, regions, and patterns before adopting.
323
+ - Search and refresh directives are inferred heuristically.
324
+ - Navigation groups currently default to a single \`workspace\` group unless stronger grouping evidence exists.
325
+ `;
326
+
327
+ /** @type {Record<string, string>} */
328
+ const files = {
329
+ "candidates/app/ui/drafts/proj-ui-contract.tg": ensureTrailingNewline(uiSharedDraft),
330
+ "candidates/app/ui/drafts/proj-web-surface.tg": ensureTrailingNewline(uiWebDraft),
331
+ "candidates/app/ui/drafts/README.md": ensureTrailingNewline(coverage)
332
+ };
333
+ for (const widget of widgetCandidates) {
334
+ files[`candidates/app/ui/drafts/widgets/${widgetCandidateFileName(widget)}`] = ensureTrailingNewline(renderWidgetCandidate(widget));
335
+ }
336
+ return files;
337
+ }