@sdd-method/author-cli 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +17 -0
  3. package/README.md +6 -2
  4. package/dist/author-bin.js +8 -0
  5. package/dist/author-program.js +99 -0
  6. package/dist/lib/adr-origin.js +59 -0
  7. package/dist/lib/agent-harness.js +37 -0
  8. package/dist/lib/api-surface/__fixtures__/serverless-repo/serverless/serverless.yml +18 -0
  9. package/dist/lib/api-surface/analyzers/library.js +95 -0
  10. package/dist/lib/api-surface/analyzers/serverless.js +336 -0
  11. package/dist/lib/api-surface/analyzers/spring.js +237 -0
  12. package/dist/lib/api-surface/analyzers/terraform.js +109 -0
  13. package/dist/lib/api-surface/detect.js +25 -0
  14. package/dist/lib/api-surface/emit.js +109 -0
  15. package/dist/lib/api-surface/file-set.js +43 -0
  16. package/dist/lib/api-surface/index.js +134 -0
  17. package/dist/lib/api-surface/types.js +17 -0
  18. package/dist/lib/briefing/index.js +13 -0
  19. package/dist/lib/briefing/render.js +132 -0
  20. package/dist/lib/briefing/variables.js +92 -0
  21. package/dist/lib/catalogue/application-archetype/vocabulary.js +177 -0
  22. package/dist/lib/catalogue/archetype/maps/android.yaml +66 -0
  23. package/dist/lib/catalogue/archetype/maps/swiftui.yaml +58 -0
  24. package/dist/lib/catalogue/archetype/maps/uikit.yaml +48 -0
  25. package/dist/lib/catalogue/archetype/maps/web-generic.yaml +86 -0
  26. package/dist/lib/catalogue/archetype/openui-archetype-vocabulary.yaml +46 -0
  27. package/dist/lib/catalogue/archetype/resolver.js +103 -0
  28. package/dist/lib/catalogue/archetype/wireframe.js +418 -0
  29. package/dist/lib/catalogue/baseline-check.js +151 -0
  30. package/dist/lib/catalogue/build.js +1502 -0
  31. package/dist/lib/catalogue/builders/adr-supersedes.js +103 -0
  32. package/dist/lib/catalogue/builders/adrs.js +222 -0
  33. package/dist/lib/catalogue/builders/application-conformance-coverage.js +47 -0
  34. package/dist/lib/catalogue/builders/application-data-plane-bindings.js +115 -0
  35. package/dist/lib/catalogue/builders/c4-components.js +229 -0
  36. package/dist/lib/catalogue/builders/c4-containers.js +240 -0
  37. package/dist/lib/catalogue/builders/c4-entity-rollups.js +87 -0
  38. package/dist/lib/catalogue/builders/c4-external-systems.js +194 -0
  39. package/dist/lib/catalogue/builders/c4-l1-candidates.js +107 -0
  40. package/dist/lib/catalogue/builders/c4-systems.js +98 -0
  41. package/dist/lib/catalogue/builders/capabilities.js +488 -0
  42. package/dist/lib/catalogue/builders/capability-domain-model.js +74 -0
  43. package/dist/lib/catalogue/builders/capability-edges.js +256 -0
  44. package/dist/lib/catalogue/builders/capability-spec-walker.js +99 -0
  45. package/dist/lib/catalogue/builders/capability-spec.js +348 -0
  46. package/dist/lib/catalogue/builders/container-dependency.js +183 -0
  47. package/dist/lib/catalogue/builders/contracts.js +402 -0
  48. package/dist/lib/catalogue/builders/data-items.js +344 -0
  49. package/dist/lib/catalogue/builders/data-store-mapping.js +113 -0
  50. package/dist/lib/catalogue/builders/domain-models.js +175 -0
  51. package/dist/lib/catalogue/builders/domains.js +119 -0
  52. package/dist/lib/catalogue/builders/edge-label-merge.js +19 -0
  53. package/dist/lib/catalogue/builders/entities-manifest.js +160 -0
  54. package/dist/lib/catalogue/builders/entities-mermaid.js +189 -0
  55. package/dist/lib/catalogue/builders/entity-persistence.js +102 -0
  56. package/dist/lib/catalogue/builders/entity-slug.js +47 -0
  57. package/dist/lib/catalogue/builders/event-catalog-walker.js +186 -0
  58. package/dist/lib/catalogue/builders/event-edges.js +327 -0
  59. package/dist/lib/catalogue/builders/events.js +168 -0
  60. package/dist/lib/catalogue/builders/evidence-class.js +43 -0
  61. package/dist/lib/catalogue/builders/evidence-target-repo.js +67 -0
  62. package/dist/lib/catalogue/builders/external-system-exemption.js +120 -0
  63. package/dist/lib/catalogue/builders/feature-contract.js +77 -0
  64. package/dist/lib/catalogue/builders/feature-domain-model.js +50 -0
  65. package/dist/lib/catalogue/builders/feature-grounding-walker.js +254 -0
  66. package/dist/lib/catalogue/builders/feature-grounding.js +391 -0
  67. package/dist/lib/catalogue/builders/feature-groups.js +63 -0
  68. package/dist/lib/catalogue/builders/feature-subscription-channels.js +228 -0
  69. package/dist/lib/catalogue/builders/feature-tree-walker.js +295 -0
  70. package/dist/lib/catalogue/builders/features.js +300 -0
  71. package/dist/lib/catalogue/builders/glossary-xref.js +378 -0
  72. package/dist/lib/catalogue/builders/glossary.js +204 -0
  73. package/dist/lib/catalogue/builders/implementations.js +214 -0
  74. package/dist/lib/catalogue/builders/index.js +64 -0
  75. package/dist/lib/catalogue/builders/integration-components.js +344 -0
  76. package/dist/lib/catalogue/builders/integrations.js +181 -0
  77. package/dist/lib/catalogue/builders/persona-c4system.js +149 -0
  78. package/dist/lib/catalogue/builders/persona-container.js +133 -0
  79. package/dist/lib/catalogue/builders/persona-journey-edges.js +133 -0
  80. package/dist/lib/catalogue/builders/personas.js +152 -0
  81. package/dist/lib/catalogue/builders/product-edges.js +106 -0
  82. package/dist/lib/catalogue/builders/product-platform-dependencies.js +405 -0
  83. package/dist/lib/catalogue/builders/products.js +162 -0
  84. package/dist/lib/catalogue/builders/quality-scores.js +635 -0
  85. package/dist/lib/catalogue/builders/repo-capability-exemption.js +61 -0
  86. package/dist/lib/catalogue/builders/repo-dependency.js +127 -0
  87. package/dist/lib/catalogue/builders/repo-edges.js +340 -0
  88. package/dist/lib/catalogue/builders/repositories.js +458 -0
  89. package/dist/lib/catalogue/builders/scaffolds.js +197 -0
  90. package/dist/lib/catalogue/builders/screen-tree.js +222 -0
  91. package/dist/lib/catalogue/builders/screens.js +396 -0
  92. package/dist/lib/catalogue/builders/service-capability-exemption.js +63 -0
  93. package/dist/lib/catalogue/builders/service-contract-consumes.js +186 -0
  94. package/dist/lib/catalogue/builders/service-contract.js +74 -0
  95. package/dist/lib/catalogue/builders/service-entity-tables.js +187 -0
  96. package/dist/lib/catalogue/builders/services.js +232 -0
  97. package/dist/lib/catalogue/builders/system-external-dependency.js +115 -0
  98. package/dist/lib/catalogue/builders/user-journeys.js +253 -0
  99. package/dist/lib/catalogue/canonical-schema.yaml +4117 -0
  100. package/dist/lib/catalogue/cli-version.js +10 -0
  101. package/dist/lib/catalogue/contract-id.js +49 -0
  102. package/dist/lib/catalogue/coverage-predicates.js +603 -0
  103. package/dist/lib/catalogue/coverage-render.js +552 -0
  104. package/dist/lib/catalogue/coverage-run.js +115 -0
  105. package/dist/lib/catalogue/csv-reader.js +97 -0
  106. package/dist/lib/catalogue/csv-writer.js +96 -0
  107. package/dist/lib/catalogue/data-plane-coherence.js +77 -0
  108. package/dist/lib/catalogue/ddl-generator.js +233 -0
  109. package/dist/lib/catalogue/dedupe-keyed-tables.js +0 -0
  110. package/dist/lib/catalogue/engine-validator.js +239 -0
  111. package/dist/lib/catalogue/ext-id.js +76 -0
  112. package/dist/lib/catalogue/feature-grounding-aliases-loader.js +65 -0
  113. package/dist/lib/catalogue/feature-repo-zero-resolution-summary.js +31 -0
  114. package/dist/lib/catalogue/finding-identity.js +183 -0
  115. package/dist/lib/catalogue/findings.js +46 -0
  116. package/dist/lib/catalogue/fk-validator.js +136 -0
  117. package/dist/lib/catalogue/freshness.js +70 -0
  118. package/dist/lib/catalogue/gate-checks.js +338 -0
  119. package/dist/lib/catalogue/graph-projection.js +346 -0
  120. package/dist/lib/catalogue/impact-run.js +228 -0
  121. package/dist/lib/catalogue/manifest-loader.js +435 -0
  122. package/dist/lib/catalogue/platform-scope.js +7 -0
  123. package/dist/lib/catalogue/population-checks.js +87 -0
  124. package/dist/lib/catalogue/relationship-semantics.js +66 -0
  125. package/dist/lib/catalogue/reverse-product-quality.js +99 -0
  126. package/dist/lib/catalogue/rubric-coverage-map.yaml +871 -0
  127. package/dist/lib/catalogue/runway-vocabulary-loader.js +56 -0
  128. package/dist/lib/catalogue/scaffold-delta.js +261 -0
  129. package/dist/lib/catalogue/schema-compat.js +52 -0
  130. package/dist/lib/catalogue/schema-loader.js +87 -0
  131. package/dist/lib/catalogue/scores-coverage.js +573 -0
  132. package/dist/lib/catalogue/screen-validation-loader.js +89 -0
  133. package/dist/lib/catalogue/service-architecture-parser.js +193 -0
  134. package/dist/lib/catalogue/service-contract-aliases-loader.js +109 -0
  135. package/dist/lib/catalogue/staleness-verdicts.js +345 -0
  136. package/dist/lib/catalogue/traceability-loader.js +350 -0
  137. package/dist/lib/catalogue/validate.js +200 -0
  138. package/dist/lib/catalogue/version.js +18 -0
  139. package/dist/lib/conformance/binding.js +70 -0
  140. package/dist/lib/conformance/finding.js +69 -0
  141. package/dist/lib/conformance/index.js +578 -0
  142. package/dist/lib/context-pull/index.js +191 -0
  143. package/dist/lib/context-pull/resolve.js +70 -0
  144. package/dist/lib/context-pull/retired-mcp-setup.js +7 -0
  145. package/dist/lib/contracts-availability/index.js +267 -0
  146. package/dist/lib/generate-briefing/index.js +77 -0
  147. package/dist/lib/list/discover.js +100 -0
  148. package/dist/lib/list/format.js +84 -0
  149. package/dist/lib/list/index.js +16 -0
  150. package/dist/lib/lock-file.js +437 -0
  151. package/dist/lib/pack/log.js +18 -0
  152. package/dist/lib/pack/schema.js +121 -0
  153. package/dist/lib/pack/seed.js +182 -0
  154. package/dist/lib/pack/validate.js +49 -0
  155. package/dist/lib/package-version.js +92 -0
  156. package/dist/lib/plan/index.js +69 -0
  157. package/dist/lib/plan/read-sdd.js +102 -0
  158. package/dist/lib/plan/render-template.js +84 -0
  159. package/dist/lib/repo-kind.js +129 -0
  160. package/dist/lib/scaffold/domain.js +234 -0
  161. package/dist/lib/scaffold/registry.js +136 -0
  162. package/dist/lib/scripts.js +7 -0
  163. package/dist/lib/sdd-index/repo-config.js +245 -0
  164. package/dist/lib/sdd-reader.js +91 -0
  165. package/dist/lib/snapshot/advance.js +454 -0
  166. package/dist/lib/snapshot/diff.js +190 -0
  167. package/dist/lib/snapshot/fold.js +208 -0
  168. package/dist/lib/snapshot/land.js +178 -0
  169. package/dist/lib/snapshot/manifest.js +206 -0
  170. package/dist/lib/snapshot/targets.js +169 -0
  171. package/dist/lib/snapshot/verify.js +91 -0
  172. package/dist/lib/sync/briefing-merge.js +106 -0
  173. package/dist/lib/sync/bundle-cache.js +109 -0
  174. package/dist/lib/sync/yaml-block-merge.js +120 -0
  175. package/dist/lib/validate/aggregate.js +51 -0
  176. package/dist/lib/validate/bundle-coherence.js +74 -0
  177. package/dist/lib/validate/dispatch.js +243 -0
  178. package/dist/lib/validate/index.js +110 -0
  179. package/dist/lib/validate/plan.js +54 -0
  180. package/dist/lib/validate/runner.js +85 -0
  181. package/dist/lib/validate/yaml-parse.js +112 -0
  182. package/dist/maintain-version.json +4 -0
  183. package/dist/verbs/api-surface.js +71 -0
  184. package/dist/verbs/catalogue-check.js +28 -0
  185. package/dist/verbs/catalogue-verify.js +114 -0
  186. package/dist/verbs/conformance.js +34 -0
  187. package/dist/verbs/context.js +39 -0
  188. package/dist/verbs/contracts.js +34 -0
  189. package/dist/verbs/generate-briefing.js +29 -0
  190. package/dist/verbs/list.js +45 -0
  191. package/dist/verbs/pack-validate.js +17 -0
  192. package/dist/verbs/path-option.js +25 -0
  193. package/dist/verbs/plan.js +42 -0
  194. package/dist/verbs/render.js +87 -0
  195. package/dist/verbs/scaffold.js +83 -0
  196. package/dist/verbs/snapshot.js +134 -0
  197. package/dist/verbs/validate.js +48 -0
  198. package/dist/verify-program.js +122 -0
  199. package/dist/verify-version.json +4 -0
  200. package/package.json +32 -4
  201. package/scripts/validate-app-dependencies.sh +664 -0
  202. package/scripts/validate-app-docs.sh +199 -0
  203. package/scripts/validate-integration-docs.sh +505 -0
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Application-archetype vocabulary resolution (M-ADR 0191 §4.2).
3
+ *
4
+ * The `application_archetype` manifest trait is a *classification* over a
5
+ * tiered vocabulary. This module resolves a declared value against the union
6
+ * of:
7
+ * - the **method tier** — `unclassified` only, built into sdd-cli (mirrors
8
+ * how the ADR 0173/0176 method-tier scaffold archetypes are built in);
9
+ * - the **reference-architecture / adopter bundle tiers** — seedless
10
+ * vocabulary files (`application-archetypes.yaml`) shipped in consumed
11
+ * bundles and extracted to the local bundle cache
12
+ * (`.sdd/bundle-cache/<bundle>@<version>/`);
13
+ * - an optional **adopter-local** extension file at
14
+ * `.sdd/application-archetypes.yaml` in the SDD repo.
15
+ *
16
+ * This deliberately does NOT reuse the ADR 0176 scaffold registry resolver
17
+ * (`scaffold/registry.ts`): that resolver is seed-oriented and drops any
18
+ * entry with no `seeds[]`, whereas a classification archetype is seedless by
19
+ * design. It DOES share the same bundle-cache distribution substrate — this
20
+ * is a distinct data type over a shared substrate, not a second distribution
21
+ * mechanism (M-ADR 0191 §6).
22
+ */
23
+ import { readFile, readdir } from "node:fs/promises";
24
+ import { join } from "node:path";
25
+ import { parse as parseYaml } from "yaml";
26
+ import { BUNDLE_CACHE_REL, VOCAB_FILE } from "../../sync/bundle-cache.js";
27
+ /** The sentinel that lives in the method tier — the back-compat default. */
28
+ export const UNCLASSIFIED = "unclassified";
29
+ export { VOCAB_FILE };
30
+ /** Adopter-local extension file, relative to the SDD repo root. */
31
+ export const ADOPTER_VOCAB_REL = join(".sdd", VOCAB_FILE);
32
+ const VALID_PRESENCE = new Set([
33
+ "required",
34
+ "typical",
35
+ "optional",
36
+ "absent-by-shape",
37
+ ]);
38
+ /** The built-in method tier (M-ADR 0191 §4.2 — `unclassified` only). */
39
+ const METHOD_TIER = [
40
+ {
41
+ id: UNCLASSIFIED,
42
+ tier: "method",
43
+ shape: "the back-compat default; a product that has not declared a shape",
44
+ source: "method",
45
+ },
46
+ ];
47
+ function parseVocabFile(raw, source) {
48
+ let parsed;
49
+ try {
50
+ parsed = parseYaml(raw);
51
+ }
52
+ catch {
53
+ return []; // malformed vocab — skip rather than break the build
54
+ }
55
+ if (parsed === null || typeof parsed !== "object")
56
+ return [];
57
+ if (!Array.isArray(parsed.archetypes))
58
+ return [];
59
+ const tier = typeof parsed.tier === "string" ? parsed.tier : "unknown";
60
+ const out = [];
61
+ for (const a of parsed.archetypes) {
62
+ if (a === null || typeof a !== "object")
63
+ continue;
64
+ const rec = a;
65
+ const id = typeof rec.id === "string" ? rec.id : undefined;
66
+ if (!id)
67
+ continue;
68
+ const expectedBindings = parseExpectedBindings(rec.expected_bindings);
69
+ const conformanceExpectations = parseStringList(rec.conformance);
70
+ out.push({
71
+ id,
72
+ tier,
73
+ source,
74
+ ...(typeof rec.layer === "string" && { layer: rec.layer }),
75
+ ...(typeof rec.shape === "string" && { shape: rec.shape }),
76
+ ...(expectedBindings.length > 0 && { expectedBindings }),
77
+ ...(conformanceExpectations.length > 0 && { conformanceExpectations }),
78
+ });
79
+ }
80
+ return out;
81
+ }
82
+ /** Parse an archetype's `expected_bindings:` list, dropping malformed entries
83
+ * (an unknown presence or a missing pattern is skipped, not fatal). */
84
+ function parseExpectedBindings(raw) {
85
+ if (!Array.isArray(raw))
86
+ return [];
87
+ const out = [];
88
+ for (const e of raw) {
89
+ if (e === null || typeof e !== "object")
90
+ continue;
91
+ const rec = e;
92
+ const pattern = typeof rec.pattern === "string" ? rec.pattern : undefined;
93
+ const presence = typeof rec.presence === "string" ? rec.presence : undefined;
94
+ if (!pattern || !presence || !VALID_PRESENCE.has(presence))
95
+ continue;
96
+ out.push({ pattern, presence: presence });
97
+ }
98
+ return out;
99
+ }
100
+ /** Parse a `conformance:` list of opaque string tags, dropping non-strings. */
101
+ function parseStringList(raw) {
102
+ if (!Array.isArray(raw))
103
+ return [];
104
+ return raw.filter((v) => typeof v === "string" && v.trim() !== "");
105
+ }
106
+ /** readdir(withFileTypes) that yields [] on any error, sorted by name. */
107
+ async function readDirSafe(dir) {
108
+ try {
109
+ const entries = await readdir(dir, { withFileTypes: true });
110
+ return entries.sort((a, b) => a.name.localeCompare(b.name));
111
+ }
112
+ catch {
113
+ return [];
114
+ }
115
+ }
116
+ /** Find every application-archetypes.yaml within a cached bundle (root + nested). */
117
+ async function findVocabFiles(dir, depth = 0) {
118
+ const found = [];
119
+ for (const e of await readDirSafe(dir)) {
120
+ if (e.isFile() && e.name === VOCAB_FILE) {
121
+ found.push(join(dir, e.name));
122
+ }
123
+ else if (e.isDirectory() && depth < 4) {
124
+ found.push(...(await findVocabFiles(join(dir, e.name), depth + 1)));
125
+ }
126
+ }
127
+ return found;
128
+ }
129
+ /**
130
+ * Discover the active vocabulary for an SDD repo: method tier ∪ every bundle
131
+ * vocab file in the bundle cache ∪ the adopter-local extension file.
132
+ */
133
+ export async function discoverVocabulary(targetRepo) {
134
+ const terms = [...METHOD_TIER];
135
+ // Bundle tiers (RA + adopter bundles both land in the cache).
136
+ const cacheRoot = join(targetRepo, BUNDLE_CACHE_REL);
137
+ for (const e of await readDirSafe(cacheRoot)) {
138
+ if (!e.isDirectory())
139
+ continue;
140
+ const bundleCacheDir = join(cacheRoot, e.name);
141
+ const at = e.name.lastIndexOf("@");
142
+ const bundleName = at > 0 ? e.name.slice(0, at) : e.name;
143
+ for (const vocabPath of await findVocabFiles(bundleCacheDir)) {
144
+ let raw;
145
+ try {
146
+ raw = await readFile(vocabPath, "utf8");
147
+ }
148
+ catch {
149
+ continue;
150
+ }
151
+ terms.push(...parseVocabFile(raw, bundleName));
152
+ }
153
+ }
154
+ // Adopter-local extension.
155
+ try {
156
+ const raw = await readFile(join(targetRepo, ADOPTER_VOCAB_REL), "utf8");
157
+ terms.push(...parseVocabFile(raw, "adopter-local"));
158
+ }
159
+ catch {
160
+ // absent — fine
161
+ }
162
+ return { terms, ids: new Set(terms.map((t) => t.id)) };
163
+ }
164
+ /**
165
+ * Resolve a declared archetype value against a vocabulary. `undefined`
166
+ * defaults to `unclassified` (always resolved). A declared value that is not
167
+ * in the vocabulary is unresolved (the caller emits an error finding).
168
+ */
169
+ export function resolveArchetype(declared, vocab) {
170
+ const value = declared ?? UNCLASSIFIED;
171
+ return {
172
+ value,
173
+ resolved: vocab.ids.has(value),
174
+ unclassified: value === UNCLASSIFIED,
175
+ };
176
+ }
177
+ //# sourceMappingURL=vocabulary.js.map
@@ -0,0 +1,66 @@
1
+ # Default archetype map — android (ADR 0169 §4.2). Method-owned.
2
+ #
3
+ # Android View + Material toolkit. These names are industry-standard (Google/AndroidX/Material)
4
+ # and identical across every Android app — never an adopter's bespoke vocabulary.
5
+ # Resolution order (ADR 0169 §4.3): adopter overlay override -> by_token -> by_suffix_heuristic -> default.
6
+ # Selected per screen by `platform: android` frontmatter.
7
+
8
+ map_version: "1.0.0"
9
+ platform: android
10
+
11
+ # Material/AndroidX vendor prefixes, stripped before token lookup.
12
+ strip_prefixes: [Material, Appcompat, AppCompat, Androidx]
13
+
14
+ by_token:
15
+ ConstraintLayout: stack
16
+ FrameLayout: stack
17
+ LinearLayout: stack
18
+ RelativeLayout: stack
19
+ CoordinatorLayout: scaffold
20
+ NestedScrollView: scroll
21
+ ScrollView: scroll
22
+ RecyclerView: list
23
+ ListView: list
24
+ GridLayout: grid
25
+ GridView: grid
26
+ ViewPager: paged-panes
27
+ ViewPager2: paged-panes
28
+ TabLayout: tab-strip
29
+ BottomNavigationView: tab-bar
30
+ NavigationView: sidebar
31
+ NavigationRailView: sidebar
32
+ Toolbar: app-bar
33
+ AppBarLayout: app-bar
34
+ ActionBar: app-bar
35
+ CollapsingToolbarLayout: app-bar
36
+ Button: button
37
+ MaterialButton: button
38
+ ImageButton: button
39
+ FloatingActionButton: fab
40
+ ExtendedFloatingActionButton: fab
41
+ Chip: tab
42
+ ChipGroup: button-group
43
+ ToggleButton: segmented-control
44
+ TextView: text
45
+ EditText: text
46
+ MaterialTextView: text
47
+ ImageView: image
48
+ ImageFilterView: image
49
+ CardView: card
50
+ MaterialCardView: card
51
+ Snackbar: banner
52
+ BottomSheetDialog: sheet
53
+ AlertDialog: modal
54
+ DialogFragment: modal
55
+
56
+ by_suffix_heuristic:
57
+ Layout: stack
58
+ View: panel
59
+ Button: button
60
+ Bar: app-bar
61
+ Dialog: modal
62
+ Card: card
63
+ Text: text
64
+ Image: image
65
+
66
+ default: panel
@@ -0,0 +1,58 @@
1
+ # Default archetype map — swiftui (ADR 0169 §4.2). Method-owned.
2
+ #
3
+ # Apple SwiftUI toolkit. Industry-standard Apple names, identical across every SwiftUI app —
4
+ # never an adopter's bespoke vocabulary.
5
+ # Resolution order (ADR 0169 §4.3): adopter overlay override -> by_token -> by_suffix_heuristic -> default.
6
+ # Selected per screen by `platform: swiftui` frontmatter.
7
+
8
+ map_version: "1.0.0"
9
+ platform: swiftui
10
+
11
+ strip_prefixes: []
12
+
13
+ by_token:
14
+ VStack: stack
15
+ HStack: row
16
+ ZStack: stack
17
+ LazyVStack: stack
18
+ LazyHStack: row
19
+ Grid: grid
20
+ LazyVGrid: grid
21
+ LazyHGrid: grid
22
+ ScrollView: scroll
23
+ List: list
24
+ Section: panel
25
+ ForEach: list-item # repeated child marker; rendered as a list-item row
26
+ Form: list
27
+ NavigationView: nav-bar
28
+ NavigationStack: nav-bar
29
+ NavigationSplitView: sidebar
30
+ NavigationLink: button
31
+ TabView: tab-bar
32
+ Button: button
33
+ Menu: list
34
+ Toolbar: app-bar
35
+ ToolbarItem: button
36
+ Text: text
37
+ Label: text
38
+ TextField: text
39
+ SecureField: text
40
+ Image: image
41
+ AsyncImage: image
42
+ Spacer: text # decorative; flagged by screen-styling-primitive-as-structure
43
+ Divider: text # decorative; flagged by screen-styling-primitive-as-structure
44
+ GroupBox: card
45
+ Sheet: sheet
46
+ Alert: modal
47
+ Picker: segmented-control
48
+
49
+ by_suffix_heuristic:
50
+ Stack: stack
51
+ View: panel
52
+ Button: button
53
+ Link: button
54
+ Field: text
55
+ Image: image
56
+ Text: text
57
+
58
+ default: panel
@@ -0,0 +1,48 @@
1
+ # Default archetype map — uikit (ADR 0169 §4.2). Method-owned.
2
+ #
3
+ # Apple UIKit toolkit. Industry-standard Apple names (UI- prefixed), identical across every
4
+ # UIKit app — never an adopter's bespoke vocabulary.
5
+ # Resolution order (ADR 0169 §4.3): adopter overlay override -> by_token -> by_suffix_heuristic -> default.
6
+ # Selected per screen by `platform: uikit` frontmatter.
7
+
8
+ map_version: "1.0.0"
9
+ platform: uikit
10
+
11
+ # The `UI` vendor prefix is stripped, so the `by_token` keys are unprefixed.
12
+ strip_prefixes: [UI, NS]
13
+
14
+ by_token:
15
+ View: panel
16
+ StackView: stack
17
+ ScrollView: scroll
18
+ TableView: list
19
+ TableViewCell: list-item
20
+ CollectionView: grid
21
+ CollectionViewCell: card
22
+ NavigationBar: nav-bar
23
+ NavigationController: nav-bar
24
+ TabBar: tab-bar
25
+ TabBarController: tab-bar
26
+ Toolbar: app-bar
27
+ BarButtonItem: button
28
+ Button: button
29
+ Label: text
30
+ TextField: text
31
+ TextView: text
32
+ ImageView: image
33
+ PageViewController: paged-panes
34
+ SegmentedControl: segmented-control
35
+ ActivityIndicatorView: text
36
+ AlertController: modal
37
+ Stack: stack
38
+
39
+ by_suffix_heuristic:
40
+ View: panel
41
+ Controller: panel
42
+ Button: button
43
+ Bar: app-bar
44
+ Label: text
45
+ Field: text
46
+ Image: image
47
+
48
+ default: panel
@@ -0,0 +1,86 @@
1
+ # Default archetype map — web-generic (ADR 0169 §4.2). Method-owned.
2
+ #
3
+ # Keys off component NAMES (which the builder already parses), not design-system source.
4
+ # Vendor-standard / common-DS tokens ONLY — never an adopter's bespoke vocabulary.
5
+ # Resolution order (ADR 0169 §4.3): adopter overlay override -> by_token -> by_suffix_heuristic -> default.
6
+ # Selected per screen by `platform: web-generic` (or web) frontmatter.
7
+
8
+ map_version: "1.0.0"
9
+ platform: web-generic
10
+
11
+ # Stripped (case-insensitive) before token lookup, so `MuiButton`/`ChButton` -> `Button`.
12
+ strip_prefixes: [Mui, Ch, Ds, Ui, App, Base, Core, V]
13
+
14
+ by_token:
15
+ Container: grid
16
+ Grid: grid
17
+ Row: row
18
+ Col: col
19
+ Column: col
20
+ Stack: stack
21
+ Flex: row
22
+ Scroll: scroll
23
+ ScrollArea: scroll
24
+ Tabs: tab-strip
25
+ Tab: tab
26
+ TabPanel: pane
27
+ Table: table
28
+ DataGrid: table
29
+ List: list
30
+ ListItem: list-item
31
+ Menu: list
32
+ Card: card
33
+ Panel: panel
34
+ Dialog: modal
35
+ Modal: modal
36
+ Popup: modal
37
+ Popover: modal
38
+ Drawer: sidebar
39
+ SidePanel: sidebar
40
+ Sidebar: sidebar
41
+ Nav: nav-bar
42
+ Navbar: nav-bar
43
+ AppBar: app-bar
44
+ Header: app-bar
45
+ Toolbar: app-bar
46
+ Alert: banner
47
+ Banner: banner
48
+ Toast: banner
49
+ Snackbar: banner
50
+ Sheet: sheet
51
+ BottomSheet: sheet
52
+ Btn: button
53
+ Button: button
54
+ IconButton: button
55
+ Fab: fab
56
+ ButtonGroup: button-group
57
+ SegmentedControl: segmented-control
58
+ Stat: text
59
+ StatCard: card
60
+ KpiBar: kpi-bar
61
+ Text: text
62
+ Typography: text
63
+ Label: text
64
+ Heading: text
65
+ Image: image
66
+ Img: image
67
+ Avatar: image
68
+ Icon: image
69
+
70
+ # Applied when no token matches. First matching suffix wins.
71
+ by_suffix_heuristic:
72
+ Button: button
73
+ Bar: app-bar
74
+ List: list
75
+ Grid: grid
76
+ Card: card
77
+ Panel: panel
78
+ Dialog: modal
79
+ Modal: modal
80
+ Layout: stack
81
+ Container: grid
82
+ Text: text
83
+ Image: image
84
+ Icon: image
85
+
86
+ default: panel
@@ -0,0 +1,46 @@
1
+ # OpenUI Archetype Vocabulary — method-owned (ADR 0169 §4.1)
2
+ #
3
+ # A closed, platform-tagged superset of visual archetypes. An archetype assigns a
4
+ # component a VISUAL SHAPE + slots/orientation — never geometry or styling (stays inside
5
+ # the compose-only boundary, ADR 0166 §3). Default archetype maps
6
+ # (archetype-maps/*.yaml) resolve adopter component NAMES to entries here; the
7
+ # render-screen-wireframe skill lowers a resolved tree to SVG using `render`.
8
+ #
9
+ # `is_container` feeds ADR 0168 §4.1 isContainer when a resolved map is present.
10
+
11
+ vocabulary_version: "1.0.0"
12
+
13
+ archetypes:
14
+
15
+ # --- structural containers -------------------------------------------------
16
+ scaffold: { is_container: true, render: { slots: [header, main, footer], orientation: vertical } }
17
+ app-bar: { is_container: true, render: { shape: bar, position: top } }
18
+ nav-bar: { is_container: true, render: { shape: bar, position: top } }
19
+ tab-bar: { is_container: true, render: { shape: bar, position: bottom } }
20
+ sidebar: { is_container: true, render: { shape: rail, position: left } }
21
+ stack: { is_container: true, render: { orientation: vertical } }
22
+ row: { is_container: true, render: { orientation: horizontal } }
23
+ col: { is_container: true, render: { orientation: vertical } }
24
+ grid: { is_container: true, render: { shape: grid } }
25
+ scroll: { is_container: true, render: { orientation: vertical, scroll: true } }
26
+ list: { is_container: true, render: { orientation: vertical, repeat: true } }
27
+ table: { is_container: true, render: { shape: grid, header_row: true } }
28
+ card: { is_container: true, render: { shape: card } }
29
+ panel: { is_container: true, render: { shape: panel } } # opaque fallback
30
+ paged-panes: { is_container: true, render: { shape: paged, active_first: true } }
31
+ pane: { is_container: true, render: { shape: panel } }
32
+ tab-strip: { is_container: true, render: { orientation: horizontal, shape: chips } }
33
+ button-group: { is_container: true, render: { orientation: horizontal } }
34
+ segmented-control: { is_container: true, render: { orientation: horizontal, shape: chips } }
35
+ kpi-bar: { is_container: true, render: { orientation: horizontal, shape: chips } }
36
+ modal: { is_container: true, render: { shape: floating, overlay: true } }
37
+ sheet: { is_container: true, render: { shape: floating, position: bottom } }
38
+ banner: { is_container: true, render: { shape: bar } }
39
+
40
+ # --- leaves ----------------------------------------------------------------
41
+ tab: { is_container: false, render: { shape: chip } }
42
+ list-item: { is_container: false, render: { shape: row } }
43
+ button: { is_container: false, render: { shape: button } }
44
+ fab: { is_container: false, render: { shape: circle, position: bottom-right } }
45
+ text: { is_container: false, render: { shape: text } }
46
+ image: { is_container: false, render: { shape: image } }
@@ -0,0 +1,103 @@
1
+ // OpenUI archetype resolver (per ADR 0169).
2
+ //
3
+ // Binds an adopter component NAME to a visual ARCHETYPE via a method-shipped
4
+ // platform default map plus an optional adopter overlay. The binding is what
5
+ // makes a shape-blind openui-lang block renderable as a wireframe, and it
6
+ // supplies the container/leaf classification the ADR 0168 `screen-root-is-leaf`
7
+ // check consumes (isContainerArchetype).
8
+ //
9
+ // Resolution order (ADR 0169 §4.3): adopter override -> default by_token (after
10
+ // stripping a vendor prefix) -> by_suffix_heuristic -> default (panel).
11
+ //
12
+ // The vocabulary + the four default maps are method-owned reference data,
13
+ // VENDORED from sdd-method (docs/method/methods/guides/openui-archetype-*.yaml /
14
+ // archetype-maps/) — the same vendoring relationship as canonical-schema.yaml.
15
+ // They use vendor-standard names only; never an adopter's bespoke vocabulary.
16
+ // copy-yaml-assets.mjs copies them next to the compiled JS at build time.
17
+ import { readFileSync } from "node:fs";
18
+ import { fileURLToPath } from "node:url";
19
+ import { dirname, join } from "node:path";
20
+ import { parse as parseYaml } from "yaml";
21
+ const __dirname = dirname(fileURLToPath(import.meta.url));
22
+ const PLATFORMS = new Set(["web-generic", "android", "swiftui", "uikit"]);
23
+ const FALLBACK_ARCHETYPE = "panel";
24
+ // Loaded once, cached. Reference data is immutable at runtime.
25
+ let vocabularyCache;
26
+ const mapCache = new Map();
27
+ function loadVocabulary() {
28
+ if (vocabularyCache === undefined) {
29
+ const raw = readFileSync(join(__dirname, "openui-archetype-vocabulary.yaml"), "utf-8");
30
+ const parsed = parseYaml(raw);
31
+ vocabularyCache = { archetypes: parsed?.archetypes ?? {} };
32
+ }
33
+ return vocabularyCache;
34
+ }
35
+ function loadMap(platform) {
36
+ let m = mapCache.get(platform);
37
+ if (m === undefined) {
38
+ const raw = readFileSync(join(__dirname, "maps", `${platform}.yaml`), "utf-8");
39
+ m = parseYaml(raw) ?? {};
40
+ mapCache.set(platform, m);
41
+ }
42
+ return m;
43
+ }
44
+ /** True when `platform` has a method-shipped default map. */
45
+ export function isKnownPlatform(platform) {
46
+ return platform !== undefined && PLATFORMS.has(platform);
47
+ }
48
+ function stripPrefix(name, prefixes) {
49
+ for (const p of prefixes ?? []) {
50
+ if (name.length > p.length && name.startsWith(p))
51
+ return name.slice(p.length);
52
+ }
53
+ return name;
54
+ }
55
+ /**
56
+ * Resolve a component name to a visual archetype for a platform, honouring an
57
+ * optional adopter overlay. Always resolves (panel fallback) — never throws.
58
+ */
59
+ export function resolveArchetype(name, platform, overlay) {
60
+ const override = overlay?.overrides?.[name];
61
+ if (override !== undefined)
62
+ return { archetype: override, provenance: "override" };
63
+ const map = loadMap(platform);
64
+ const token = stripPrefix(name, map.strip_prefixes);
65
+ const byToken = map.by_token?.[token] ?? map.by_token?.[name];
66
+ if (byToken !== undefined)
67
+ return { archetype: byToken, provenance: "default" };
68
+ // First suffix the name ends with wins.
69
+ for (const [suffix, archetype] of Object.entries(map.by_suffix_heuristic ?? {})) {
70
+ if (name.endsWith(suffix))
71
+ return { archetype, provenance: "heuristic" };
72
+ }
73
+ return { archetype: map.default ?? FALLBACK_ARCHETYPE, provenance: "fallback" };
74
+ }
75
+ /**
76
+ * Whether a component classifies as a container archetype for a platform.
77
+ * Used by ADR 0168 §4.1 isContainer to refine the appears-with-children
78
+ * heuristic. Returns undefined when the platform has no map (caller falls back
79
+ * to the heuristic) so an absent map never mis-classifies a known container.
80
+ */
81
+ export function isContainerArchetype(name, platform, overlay) {
82
+ if (!isKnownPlatform(platform))
83
+ return undefined;
84
+ const { archetype } = resolveArchetype(name, platform, overlay);
85
+ return loadVocabulary().archetypes[archetype]?.is_container === true;
86
+ }
87
+ /**
88
+ * The vendor name prefixes the platform's default map strips (e.g. `UI`/`NS` for
89
+ * uikit, `Mui`/`Ch`/… for web-generic). The renderer combines these with the
90
+ * adopter overlay's `strip_prefixes` to humanise component names into labels.
91
+ * Returns `[]` for an unknown platform.
92
+ */
93
+ export function mapStripPrefixes(platform) {
94
+ if (!isKnownPlatform(platform))
95
+ return [];
96
+ return loadMap(platform).strip_prefixes ?? [];
97
+ }
98
+ /** Vocabulary metadata for an archetype: container flag + render hints. */
99
+ export function archetypeInfo(archetype) {
100
+ const entry = loadVocabulary().archetypes[archetype];
101
+ return { isContainer: entry?.is_container === true, render: entry?.render ?? {} };
102
+ }
103
+ //# sourceMappingURL=resolver.js.map