@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,84 @@
1
+ import { access, readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ /**
4
+ * Where a synced baseline carries the pilot-kickoff template: methods/templates/ since the method's
5
+ * methods/ subdivision, then the flat methods/ path older baselines still hold. Reading only the old
6
+ * path left `plan --pilot` failing in every SDD synced after the move.
7
+ */
8
+ export const PILOT_TEMPLATE_REL_PATHS = [
9
+ "docs/method/methods/templates/pilot-kickoff-template.md",
10
+ "docs/method/methods/pilot-kickoff-template.md",
11
+ ];
12
+ /** The first pilot-kickoff template present under the SDD root, or undefined. */
13
+ export async function resolvePilotTemplate(sddRoot) {
14
+ for (const rel of PILOT_TEMPLATE_REL_PATHS) {
15
+ const p = join(sddRoot, rel);
16
+ try {
17
+ await access(p);
18
+ return p;
19
+ }
20
+ catch {
21
+ // try the next location
22
+ }
23
+ }
24
+ return undefined;
25
+ }
26
+ const VAR_PATTERN = /\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/g;
27
+ export async function renderPilotKickoff(inputs) {
28
+ const { snapshot } = inputs;
29
+ const templatePath = await resolvePilotTemplate(snapshot.sddRoot);
30
+ if (templatePath === undefined)
31
+ throw new Error(`no pilot-kickoff template under ${snapshot.sddRoot}`);
32
+ const template = await readFile(templatePath, "utf8");
33
+ const vars = buildVars(inputs);
34
+ return template.replace(VAR_PATTERN, (match, name) => {
35
+ if (!(name in vars)) {
36
+ // Leave unknown placeholders intact so the human can see what wasn't
37
+ // prefilled and fill it themselves, rather than silently blanking.
38
+ return match;
39
+ }
40
+ return vars[name] ?? "";
41
+ });
42
+ }
43
+ function buildVars(inputs) {
44
+ const { snapshot, platformCliVersionHint, today } = inputs;
45
+ const { repoConfig } = snapshot;
46
+ const inlineList = (items, sep = ", ") => items.length === 0 ? "_(none declared — fill in)_" : items.join(sep);
47
+ const bulletList = (items) => items.length === 0 ? "- _(none declared — fill in)_" : items.map((i) => `- ${i}`).join("\n");
48
+ return {
49
+ service_name: snapshot.service,
50
+ capability: snapshot.capability,
51
+ capability_display: toTitleCase(snapshot.capability.replace(/-/g, " ")),
52
+ domain: snapshot.domain,
53
+ domain_display: toTitleCase(snapshot.domain),
54
+ service_type: repoConfig.serviceType ?? "_(not declared — fill in)_",
55
+ today,
56
+ platform_cli_version_hint: platformCliVersionHint,
57
+ capability_spec_path: snapshot.capabilitySpecPath,
58
+ capability_spec_present: snapshot.capabilitySpecPresent ? "present" : "**MISSING — author before kickoff**",
59
+ capability_spec_state: snapshot.capabilitySpecPresent
60
+ ? "Exists; run `/validate-intent-quality` before kickoff"
61
+ : "**MISSING** — author before kickoff",
62
+ traceability_manifest_path: snapshot.traceabilityManifestPath,
63
+ traceability_manifest_present: snapshot.traceabilityManifestPresent ? "present" : "**MISSING — author before kickoff**",
64
+ traceability_manifest_state: snapshot.traceabilityManifestPresent
65
+ ? "Exists; confirm `status:` before kickoff"
66
+ : "**MISSING** — author before kickoff",
67
+ feature_spec_count: String(snapshot.featureSpecCount),
68
+ feature_spec_paths_inline: inlineList(snapshot.featureSpecRelativePaths),
69
+ feature_spec_paths_list: bulletList(snapshot.featureSpecRelativePaths),
70
+ aggregate_count: String(repoConfig.aggregates.length),
71
+ aggregate_list_inline: inlineList(repoConfig.aggregates),
72
+ internal_dependencies_inline: repoConfig.internalDependencies.length === 0
73
+ ? "_(none — zero internal mocking required)_"
74
+ : repoConfig.internalDependencies.join(", "),
75
+ openapi_count: String(repoConfig.contracts.openapi.length),
76
+ proto_count: String(repoConfig.contracts.proto.length),
77
+ avro_count: String(repoConfig.contracts.avro.length),
78
+ spicedb_count: String(repoConfig.contracts.spicedb.length),
79
+ };
80
+ }
81
+ function toTitleCase(s) {
82
+ return s.replace(/\b\w/g, (c) => c.toUpperCase());
83
+ }
84
+ //# sourceMappingURL=render-template.js.map
@@ -0,0 +1,129 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ /**
4
+ * Forward-base bundles set `.sdd-repo-kind` and qualify as the base
5
+ * layer that additive extensions can compose on top of (per ADR 0135).
6
+ * The legacy self-contained `reverse-baseline` is retained as a
7
+ * forward base for compat with adopters who haven't migrated to the
8
+ * `reverse-extension-baseline` additive shape yet.
9
+ */
10
+ const FORWARD_BASE_BUNDLES = new Set([
11
+ "platform-baseline",
12
+ "app-baseline",
13
+ "integration-baseline",
14
+ "reverse-baseline",
15
+ ]);
16
+ export const REPO_KIND_FILE = ".sdd-repo-kind";
17
+ /**
18
+ * Legacy marker filename from the pre-rebrand era. Read-only fallback during
19
+ * the rebrand transition: `readRepoKind` accepts either filename; `sync`
20
+ * auto-migrates legacy → canonical. New writes always use `REPO_KIND_FILE`.
21
+ * Drop after one minor-version overlap.
22
+ */
23
+ export const LEGACY_REPO_KIND_FILE = ".iteraitive-repo-kind";
24
+ const PROFILE_BY_REPO_KIND = {
25
+ "platform-product": "platform",
26
+ "application-product": "application",
27
+ "integration-product": "integration",
28
+ "reverse-corpus": "reverse",
29
+ };
30
+ const REPO_KIND_BY_PROFILE = {
31
+ platform: "platform-product",
32
+ application: "application-product",
33
+ integration: "integration-product",
34
+ reverse: "reverse-corpus",
35
+ };
36
+ /**
37
+ * Forward-base bundles map 1:1 to a profile. Additive bundles
38
+ * (`reverse-extension-baseline`) have no profile of their own — they
39
+ * compose on top of whatever forward base is already locked.
40
+ */
41
+ const PROFILE_BY_BUNDLE_NAME = {
42
+ "platform-baseline": "platform",
43
+ "app-baseline": "application",
44
+ "integration-baseline": "integration",
45
+ "reverse-baseline": "reverse",
46
+ };
47
+ const BUNDLE_NAME_BY_PROFILE = {
48
+ platform: "platform-baseline",
49
+ application: "app-baseline",
50
+ integration: "integration-baseline",
51
+ reverse: "reverse-baseline",
52
+ };
53
+ export function profileFromRepoKind(kind) {
54
+ return PROFILE_BY_REPO_KIND[kind];
55
+ }
56
+ export function repoKindFromProfile(profile) {
57
+ return REPO_KIND_BY_PROFILE[profile];
58
+ }
59
+ /**
60
+ * Returns the profile a bundle authoritatively claims, or null for
61
+ * additive bundles that don't claim a profile of their own. Accepts
62
+ * arbitrary strings (adopter pack names per ADR 0151) and returns null
63
+ * for any name not in the closed sdd-method bundle set.
64
+ */
65
+ export function profileFromBundleName(name) {
66
+ if (!isBundleName(name))
67
+ return null;
68
+ return PROFILE_BY_BUNDLE_NAME[name] ?? null;
69
+ }
70
+ export function bundleNameFromProfile(profile) {
71
+ return BUNDLE_NAME_BY_PROFILE[profile];
72
+ }
73
+ /**
74
+ * Forward-base bundles set `.sdd-repo-kind` and qualify as the base
75
+ * layer that additive extensions compose on top of. Additive bundles
76
+ * (sdd-method's `reverse-extension-baseline` and ADR 0151 adopter
77
+ * packs) return false. Accepts arbitrary strings; unknown names return
78
+ * false.
79
+ */
80
+ export function isForwardBase(name) {
81
+ if (!isBundleName(name))
82
+ return false;
83
+ return FORWARD_BASE_BUNDLES.has(name);
84
+ }
85
+ /**
86
+ * Maps repo-kind → forward-base bundle name. Used when migrating a
87
+ * legacy v1 lock file (which doesn't record bundle name) to v2.
88
+ */
89
+ export function bundleNameFromRepoKind(kind) {
90
+ return BUNDLE_NAME_BY_PROFILE[PROFILE_BY_REPO_KIND[kind]];
91
+ }
92
+ export function isRepoKind(value) {
93
+ return value in PROFILE_BY_REPO_KIND;
94
+ }
95
+ const ALL_BUNDLE_NAMES = new Set([
96
+ "platform-baseline",
97
+ "app-baseline",
98
+ "integration-baseline",
99
+ "reverse-baseline",
100
+ "reverse-extension-baseline",
101
+ ]);
102
+ export function isBundleName(value) {
103
+ return ALL_BUNDLE_NAMES.has(value);
104
+ }
105
+ export async function readRepoKind(repoRoot) {
106
+ // Canonical first; fall back to legacy marker during the rebrand transition.
107
+ for (const filename of [REPO_KIND_FILE, LEGACY_REPO_KIND_FILE]) {
108
+ const path = join(repoRoot, filename);
109
+ let raw;
110
+ try {
111
+ raw = await readFile(path, "utf8");
112
+ }
113
+ catch (err) {
114
+ if (err.code === "ENOENT")
115
+ continue;
116
+ throw err;
117
+ }
118
+ const value = raw.trim();
119
+ if (!isRepoKind(value)) {
120
+ throw new Error(`Unrecognised ${filename} value: ${JSON.stringify(value)} at ${path}`);
121
+ }
122
+ return value;
123
+ }
124
+ return null;
125
+ }
126
+ export async function writeRepoKind(repoRoot, kind) {
127
+ await writeFile(join(repoRoot, REPO_KIND_FILE), `${kind}\n`, "utf8");
128
+ }
129
+ //# sourceMappingURL=repo-kind.js.map
@@ -0,0 +1,234 @@
1
+ import { access, copyFile, mkdir, readdir, writeFile } from "node:fs/promises";
2
+ import { dirname, join, relative } from "node:path";
3
+ /**
4
+ * Domain scaffolding (ADR 0173). Writes the invariant domain shape into a
5
+ * platform-root SDD, optionally seeded from a domain archetype. The generic
6
+ * shape is method-owned and domain-agnostic; archetypes overlay starter content.
7
+ *
8
+ * Only the `integration` archetype is built in (the method tier — the method
9
+ * owns that vocabulary via ADR 0171/0172). Reference-architecture and adopter
10
+ * archetypes are resolved from a consumed registry (not in this prototype).
11
+ */
12
+ export const METHOD_DOMAIN_ARCHETYPES = ["integration"];
13
+ export function isMethodDomainArchetype(value) {
14
+ return METHOD_DOMAIN_ARCHETYPES.includes(value);
15
+ }
16
+ export async function scaffoldDomain(input) {
17
+ const base = join(input.targetRepo, "docs", "domains", input.name);
18
+ const filesWritten = [];
19
+ const write = async (rel, content) => {
20
+ await writeFileAt(join(base, rel), content);
21
+ filesWritten.push(join("docs", "domains", input.name, rel));
22
+ };
23
+ const writeIfMissing = async (rel, content) => {
24
+ if (await fileExists(join(base, rel)))
25
+ return;
26
+ await write(rel, content);
27
+ };
28
+ // Registry archetype (ADR 0176 §4.4): copy seed files from the bundle
29
+ // cache FIRST — copy-and-own; the generic shape then fills only the
30
+ // gaps the seed didn't provide.
31
+ if (input.registryArchetype) {
32
+ const copied = await copyRegistrySeeds(input.registryArchetype, base);
33
+ for (const rel of copied) {
34
+ filesWritten.push(join("docs", "domains", input.name, rel));
35
+ }
36
+ }
37
+ await writeIfMissing("README.md", renderDomainReadme(input));
38
+ await writeIfMissing("architecture/glossary.md", renderDomainGlossary(input));
39
+ await writeIfMissing("architecture/data-model.mermaid.md", renderDomainDataModel(input));
40
+ await writeIfMissing("architecture/diagrams/.gitkeep", "");
41
+ await writeIfMissing("architecture/adr/.gitkeep", "");
42
+ await writeIfMissing("design/.gitkeep", "");
43
+ await writeIfMissing("product/.gitkeep", "");
44
+ if (input.withContracts) {
45
+ await writeIfMissing("contracts/.gitkeep", "");
46
+ }
47
+ // Archetype overlay (method tier).
48
+ if (input.archetype === "integration") {
49
+ await write("architecture/interaction-patterns.md", renderIntegrationArchetype());
50
+ }
51
+ return { filesWritten };
52
+ }
53
+ /**
54
+ * Copy a registry archetype's seed files from the bundle cache into the
55
+ * domain directory, stripping the seed prefix: a seed prefix
56
+ * `core-b2b-saas/domains/identity/` maps its files onto the domain root.
57
+ * Returns the relative paths written (relative to the domain dir).
58
+ */
59
+ async function copyRegistrySeeds(archetype, domainDir) {
60
+ const written = [];
61
+ for (const seedPrefix of archetype.seeds) {
62
+ const seedRoot = join(archetype.bundleCacheDir, seedPrefix);
63
+ const files = await walkFiles(seedRoot);
64
+ for (const abs of files) {
65
+ const rel = relative(seedRoot, abs);
66
+ const dst = join(domainDir, rel);
67
+ await mkdir(dirname(dst), { recursive: true });
68
+ await copyFile(abs, dst);
69
+ written.push(rel);
70
+ }
71
+ }
72
+ if (written.length === 0) {
73
+ throw new Error(`Archetype '${archetype.id}' (bundle ${archetype.bundleName}) has no seed files in the cache — re-sync the bundle.`);
74
+ }
75
+ return written;
76
+ }
77
+ async function walkFiles(root) {
78
+ const out = [];
79
+ let entries;
80
+ try {
81
+ entries = await readdir(root, { withFileTypes: true });
82
+ }
83
+ catch {
84
+ return out;
85
+ }
86
+ for (const e of entries) {
87
+ const child = join(root, e.name);
88
+ if (e.isDirectory()) {
89
+ out.push(...(await walkFiles(child)));
90
+ }
91
+ else if (e.isFile()) {
92
+ out.push(child);
93
+ }
94
+ }
95
+ return out;
96
+ }
97
+ async function fileExists(path) {
98
+ try {
99
+ await access(path);
100
+ return true;
101
+ }
102
+ catch {
103
+ return false;
104
+ }
105
+ }
106
+ function titleize(slug) {
107
+ return slug
108
+ .split("-")
109
+ .filter((p) => p.length > 0)
110
+ .map((p) => p[0].toUpperCase() + p.slice(1))
111
+ .join(" ");
112
+ }
113
+ function renderDomainReadme(input) {
114
+ const title = titleize(input.name);
115
+ const intro = input.archetype === "integration"
116
+ ? "Provider-specific integrations that bridge external systems to the platform via canonical contracts. Each integration is a separate `integration-product` SDD that registers into this domain (ADR 0136)."
117
+ : `TODO: one-paragraph description of the ${title} domain — the capability slice it owns and its boundary.`;
118
+ return ([
119
+ `# ${title} Domain`,
120
+ "",
121
+ `> ${intro}`,
122
+ "",
123
+ "## Architecture",
124
+ "",
125
+ "- [Glossary](architecture/glossary.md) — domain vocabulary",
126
+ "- [Data Model](architecture/data-model.mermaid.md) — entity-relationship diagram",
127
+ "- [ADRs](architecture/adr/) — domain-specific architecture decisions",
128
+ "- [Diagrams](architecture/diagrams/) — C4 and other diagrams",
129
+ ...(input.archetype === "integration"
130
+ ? [
131
+ "- [Interaction Patterns](architecture/interaction-patterns.md) — ingestion / invocation patterns (sdd-method#0171/#0172)",
132
+ ]
133
+ : []),
134
+ "",
135
+ "## Product",
136
+ "",
137
+ "- [Capability Specs](product/) — domain capabilities",
138
+ "",
139
+ "## Design",
140
+ "",
141
+ "- [Design](design/) — feature/design grounding",
142
+ ...(input.withContracts
143
+ ? ["", "## Contracts", "", "- [Contracts](contracts/) — contracts this domain exposes"]
144
+ : []),
145
+ "",
146
+ ].join("\n"));
147
+ }
148
+ function renderDomainGlossary(input) {
149
+ const title = titleize(input.name);
150
+ if (input.archetype === "integration") {
151
+ return ([
152
+ `# ${title} Domain Glossary`,
153
+ "",
154
+ "> Vocabulary for this domain. Interaction-pattern terms below are anchored in",
155
+ "> Enterprise Integration Patterns (sdd-method#0172).",
156
+ "",
157
+ "| Term | Definition |",
158
+ "|------|------------|",
159
+ "| Provider | An external system this platform integrates with. |",
160
+ "| Ingestion pattern | How an integration acquires data (event-stream-consume / webhook / socket-listen / poll). |",
161
+ "| Invocation pattern | How an integration invokes a provider (request-response / async-request / publish). |",
162
+ "| CanonicalEvent | The normalised event an integration translates provider data into. |",
163
+ "",
164
+ ].join("\n"));
165
+ }
166
+ return ([
167
+ `# ${title} Domain Glossary`,
168
+ "",
169
+ "> Owned vocabulary for this domain. One row per term the domain defines.",
170
+ "",
171
+ "| Term | Definition |",
172
+ "|------|------------|",
173
+ "| TODO | TODO — define the domain's core terms. |",
174
+ "",
175
+ ].join("\n"));
176
+ }
177
+ function renderDomainDataModel(input) {
178
+ const title = titleize(input.name);
179
+ return ([
180
+ `# ${title} Domain — Data Model`,
181
+ "",
182
+ "> Entity-relationship diagram for this domain (ADR 0142 — first-class catalogue entity).",
183
+ "",
184
+ "```mermaid",
185
+ "erDiagram",
186
+ " %% TODO: model this domain's entities and relationships",
187
+ " ENTITY {",
188
+ " string id",
189
+ " }",
190
+ "```",
191
+ "",
192
+ ].join("\n"));
193
+ }
194
+ function renderIntegrationArchetype() {
195
+ return ([
196
+ "# Integration Interaction Patterns",
197
+ "",
198
+ "> Seeded by the `integration` domain archetype (sdd-method#0173). The interaction",
199
+ "> pattern is the adopter-agnostic, EIP-anchored data-flow axis (sdd-method#0171),",
200
+ "> orthogonal to provider category (`profileType`, sdd-method#0137).",
201
+ "",
202
+ "## Ingestion (inbound)",
203
+ "",
204
+ "| Pattern | Meaning |",
205
+ "|---------|---------|",
206
+ "| `event-stream-consume` | Subscribe to / drain a provider-hosted broker, stream or feed. |",
207
+ "| `webhook` | Expose an endpoint the provider pushes events to. |",
208
+ "| `socket-listen` | Accept connection-oriented sessions and read framed data. |",
209
+ "| `poll` | Request the provider on a schedule. |",
210
+ "",
211
+ "## Invocation (outbound)",
212
+ "",
213
+ "| Pattern | Meaning |",
214
+ "|---------|---------|",
215
+ "| `request-response` | Synchronous call-and-wait. |",
216
+ "| `async-request` | Submit; result returns later via a separate channel, correlated. |",
217
+ "| `publish` | Fire-and-forget write to a broker. |",
218
+ "",
219
+ "## Adopter framework roles",
220
+ "",
221
+ "If your platform runs an integration/component framework, map its component roles",
222
+ "onto these patterns **here** (sdd-method#0171 §9.5) — the method stays role-name-neutral.",
223
+ "",
224
+ "| Your role | Ingestion / Invocation pattern |",
225
+ "|-----------|-------------------------------|",
226
+ "| TODO | TODO |",
227
+ "",
228
+ ].join("\n"));
229
+ }
230
+ async function writeFileAt(path, content) {
231
+ await mkdir(dirname(path), { recursive: true });
232
+ await writeFile(path, content, "utf8");
233
+ }
234
+ //# sourceMappingURL=domain.js.map
@@ -0,0 +1,136 @@
1
+ import { readFile, readdir } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { parse as parseYaml } from "yaml";
4
+ import { BUNDLE_CACHE_REL, REGISTRY_FILE } from "../sync/bundle-cache.js";
5
+ /**
6
+ * Scan the bundle cache for registries and return every archetype found.
7
+ * Bundles without any registry.yaml are skipped silently (vendor packs
8
+ * etc.). A registry may sit at the bundle's payload root or nested
9
+ * (multi-bundle producer repos keep one registry per bundle subtree,
10
+ * e.g. a vertical overlay's `verticals/fleet/registry.yaml`) — all are
11
+ * read; seed paths stay payload-root-relative regardless of where the
12
+ * declaring registry sits.
13
+ */
14
+ export async function discoverArchetypes(targetRepo) {
15
+ const cacheRoot = join(targetRepo, BUNDLE_CACHE_REL);
16
+ let entries;
17
+ try {
18
+ entries = await readdir(cacheRoot, { withFileTypes: true });
19
+ }
20
+ catch {
21
+ return [];
22
+ }
23
+ const out = [];
24
+ for (const e of entries) {
25
+ if (!e.isDirectory())
26
+ continue;
27
+ const bundleCacheDir = join(cacheRoot, e.name);
28
+ const at = e.name.lastIndexOf("@");
29
+ const bundleName = at > 0 ? e.name.slice(0, at) : e.name;
30
+ for (const registryPath of await findRegistryFiles(bundleCacheDir)) {
31
+ let raw;
32
+ try {
33
+ raw = await readFile(registryPath, "utf8");
34
+ }
35
+ catch {
36
+ continue;
37
+ }
38
+ let parsed;
39
+ try {
40
+ parsed = parseYaml(raw);
41
+ }
42
+ catch {
43
+ continue; // malformed registry — skip rather than break scaffold
44
+ }
45
+ if (parsed === null || typeof parsed !== "object")
46
+ continue;
47
+ if (!Array.isArray(parsed.archetypes))
48
+ continue;
49
+ const tier = typeof parsed.tier === "string" ? parsed.tier : "unknown";
50
+ for (const a of parsed.archetypes) {
51
+ if (a === null || typeof a !== "object")
52
+ continue;
53
+ const rec = a;
54
+ const id = typeof rec.id === "string" ? rec.id : undefined;
55
+ const seeds = Array.isArray(rec.seeds)
56
+ ? rec.seeds.filter((s) => typeof s === "string")
57
+ : [];
58
+ if (!id || seeds.length === 0)
59
+ continue;
60
+ out.push({
61
+ id,
62
+ tier,
63
+ seeds,
64
+ bundleName,
65
+ bundleCacheDir,
66
+ ...(typeof rec.layer === "string" && { layer: rec.layer }),
67
+ ...(typeof rec.domain_name === "string" && { domainName: rec.domain_name }),
68
+ ...(typeof rec.status === "string" && { status: rec.status }),
69
+ ...(typeof rec.notes === "string" && { notes: rec.notes }),
70
+ });
71
+ }
72
+ }
73
+ }
74
+ return out;
75
+ }
76
+ /** Depth cap for nested-registry discovery — bundle payloads are shallow. */
77
+ const REGISTRY_SCAN_MAX_DEPTH = 4;
78
+ /**
79
+ * Find every registry.yaml within a cached bundle (root + nested),
80
+ * depth-capped. Returns absolute paths in a stable (sorted) order.
81
+ */
82
+ async function findRegistryFiles(dir, depth = 0) {
83
+ let entries;
84
+ try {
85
+ entries = await readdir(dir, { withFileTypes: true });
86
+ }
87
+ catch {
88
+ return [];
89
+ }
90
+ const found = [];
91
+ for (const e of entries.sort((a, b) => a.name.localeCompare(b.name))) {
92
+ if (e.isFile() && e.name === REGISTRY_FILE) {
93
+ found.push(join(dir, e.name));
94
+ }
95
+ else if (e.isDirectory() && depth < REGISTRY_SCAN_MAX_DEPTH) {
96
+ found.push(...(await findRegistryFiles(join(dir, e.name), depth + 1)));
97
+ }
98
+ }
99
+ return found;
100
+ }
101
+ /**
102
+ * Resolve an archetype reference against the cache. Accepts bare ids
103
+ * (`core/identity`) and bundle-qualified ids
104
+ * (`ref-arch-core-b2b-saas:core/identity`).
105
+ */
106
+ export async function resolveArchetype(targetRepo, reference) {
107
+ const available = await discoverArchetypes(targetRepo);
108
+ let bundleFilter;
109
+ let id = reference;
110
+ const colon = reference.indexOf(":");
111
+ if (colon > 0) {
112
+ bundleFilter = reference.slice(0, colon);
113
+ id = reference.slice(colon + 1);
114
+ }
115
+ const matches = available.filter((a) => a.id === id && (bundleFilter === undefined || a.bundleName === bundleFilter));
116
+ if (matches.length === 1) {
117
+ return { ok: true, archetype: matches[0], available };
118
+ }
119
+ if (matches.length === 0) {
120
+ const known = available.map((a) => `${a.bundleName}:${a.id}`).join(", ");
121
+ return {
122
+ ok: false,
123
+ available,
124
+ error: available.length === 0
125
+ ? `No archetype registries found in ${BUNDLE_CACHE_REL}/ — sync an archetype-bearing bundle first (ADR 0176).`
126
+ : `Archetype '${reference}' not found in cached registries. Available: ${known}`,
127
+ };
128
+ }
129
+ const collisions = matches.map((a) => `${a.bundleName}:${a.id}`).join(", ");
130
+ return {
131
+ ok: false,
132
+ available,
133
+ error: `Archetype id '${id}' is declared by multiple bundles (${collisions}). Use the qualified form '<bundle>:<id>'.`,
134
+ };
135
+ }
136
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1,7 @@
1
+ import { dirname, resolve } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ export function resolveBundledScript(name) {
4
+ const here = dirname(fileURLToPath(import.meta.url));
5
+ return resolve(here, "..", "..", "scripts", name);
6
+ }
7
+ //# sourceMappingURL=scripts.js.map