@milehimikey/em 1.13.0 → 1.14.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 (239) hide show
  1. package/.claude/agents/em-critic.md +26 -0
  2. package/.claude/agents/em-implementer.md +34 -0
  3. package/.claude/agents/em-reviewer.md +31 -0
  4. package/.claude/agents/em-validator.md +27 -0
  5. package/.claude/skills/event-modeling/SKILL.md +52 -12
  6. package/.claude/skills/event-modeling-conform/SKILL.md +1 -1
  7. package/.claude/skills/event-modeling-conform/reference/conform.md +1 -1
  8. package/.claude/skills/event-modeling-design/SKILL.md +140 -18
  9. package/.claude/skills/event-modeling-discover/SKILL.md +1 -1
  10. package/.claude/skills/event-modeling-engagement/SKILL.md +192 -0
  11. package/.claude/skills/event-modeling-engagement/reference/engagement.md +143 -0
  12. package/.claude/skills/event-modeling-implement/SKILL.md +7 -4
  13. package/.claude/skills/event-modeling-implement/reference/implement.md +51 -12
  14. package/.claude/skills/event-modeling-review/SKILL.md +1 -1
  15. package/.claude/skills/event-modeling-shared/reference/em-dsl.md +274 -188
  16. package/.claude/skills/event-modeling-shared/reference/operating-principles.md +61 -0
  17. package/.claude/skills/event-modeling-shared/reference/slice-doc-schema.md +116 -4
  18. package/.claude/skills/event-modeling-shared/templates/constitution.md +18 -1
  19. package/.claude/skills/event-modeling-shared/templates/slice.md +64 -39
  20. package/.claude/skills/event-modeling-shared/templates/state.md +5 -1
  21. package/.claude-plugin/marketplace.json +14 -0
  22. package/README.md +25 -11
  23. package/dist/catalog/apiFirst.d.ts +28 -0
  24. package/dist/catalog/apiFirst.js +49 -0
  25. package/dist/catalog/apiFirst.js.map +1 -0
  26. package/dist/catalog/docJoin.d.ts +13 -0
  27. package/dist/catalog/docJoin.js +11 -0
  28. package/dist/catalog/docJoin.js.map +1 -1
  29. package/dist/catalog/docModelConsistencyValidate.js +44 -4
  30. package/dist/catalog/docModelConsistencyValidate.js.map +1 -1
  31. package/dist/catalog/invariantsValidate.d.ts +4 -0
  32. package/dist/catalog/invariantsValidate.js +102 -0
  33. package/dist/catalog/invariantsValidate.js.map +1 -0
  34. package/dist/catalog/scenarios.d.ts +15 -0
  35. package/dist/catalog/scenarios.js +97 -0
  36. package/dist/catalog/scenarios.js.map +1 -0
  37. package/dist/catalog/sliceDoc.d.ts +8 -0
  38. package/dist/catalog/sliceDoc.js +9 -0
  39. package/dist/catalog/sliceDoc.js.map +1 -1
  40. package/dist/catalog/sliceReadyValidate.d.ts +31 -4
  41. package/dist/catalog/sliceReadyValidate.js +66 -8
  42. package/dist/catalog/sliceReadyValidate.js.map +1 -1
  43. package/dist/catalog/sliceSections.d.ts +55 -0
  44. package/dist/catalog/sliceSections.js +317 -0
  45. package/dist/catalog/sliceSections.js.map +1 -0
  46. package/dist/cli/agentsMd.js +7 -1
  47. package/dist/cli/agentsMd.js.map +1 -1
  48. package/dist/cli/api.d.ts +90 -0
  49. package/dist/cli/api.js +318 -0
  50. package/dist/cli/api.js.map +1 -0
  51. package/dist/cli/ciInit.d.ts +88 -3
  52. package/dist/cli/ciInit.js +507 -50
  53. package/dist/cli/ciInit.js.map +1 -1
  54. package/dist/cli/conformScope.d.ts +28 -0
  55. package/dist/cli/conformScope.js +67 -0
  56. package/dist/cli/conformScope.js.map +1 -1
  57. package/dist/cli/coverage.d.ts +25 -2
  58. package/dist/cli/coverage.js +86 -12
  59. package/dist/cli/coverage.js.map +1 -1
  60. package/dist/cli/engagement.d.ts +210 -0
  61. package/dist/cli/engagement.js +444 -0
  62. package/dist/cli/engagement.js.map +1 -0
  63. package/dist/cli/engagementFile.d.ts +86 -0
  64. package/dist/cli/engagementFile.js +255 -0
  65. package/dist/cli/engagementFile.js.map +1 -0
  66. package/dist/cli/metrics.d.ts +10 -0
  67. package/dist/cli/metrics.js +49 -1
  68. package/dist/cli/metrics.js.map +1 -1
  69. package/dist/cli/pluginPin.d.ts +55 -0
  70. package/dist/cli/pluginPin.js +188 -0
  71. package/dist/cli/pluginPin.js.map +1 -0
  72. package/dist/cli/ratify.d.ts +27 -2
  73. package/dist/cli/ratify.js +112 -13
  74. package/dist/cli/ratify.js.map +1 -1
  75. package/dist/cli/reratify.d.ts +11 -4
  76. package/dist/cli/reratify.js +89 -35
  77. package/dist/cli/reratify.js.map +1 -1
  78. package/dist/cli/scopeInputs.d.ts +48 -0
  79. package/dist/cli/scopeInputs.js +176 -0
  80. package/dist/cli/scopeInputs.js.map +1 -0
  81. package/dist/cli/skillCheck.d.ts +15 -1
  82. package/dist/cli/skillCheck.js +22 -1
  83. package/dist/cli/skillCheck.js.map +1 -1
  84. package/dist/cli/skillDirs.d.ts +5 -0
  85. package/dist/cli/skillDirs.js +13 -1
  86. package/dist/cli/skillDirs.js.map +1 -1
  87. package/dist/cli/skillSync.d.ts +4 -0
  88. package/dist/cli/skillSync.js +23 -0
  89. package/dist/cli/skillSync.js.map +1 -1
  90. package/dist/cli/sliceNew.d.ts +11 -7
  91. package/dist/cli/sliceNew.js +91 -18
  92. package/dist/cli/sliceNew.js.map +1 -1
  93. package/dist/cli/sliceSync.d.ts +50 -0
  94. package/dist/cli/sliceSync.js +170 -0
  95. package/dist/cli/sliceSync.js.map +1 -0
  96. package/dist/cli/status.d.ts +24 -1
  97. package/dist/cli/status.js +20 -1
  98. package/dist/cli/status.js.map +1 -1
  99. package/dist/cli/systemInputs.d.ts +53 -10
  100. package/dist/cli/systemInputs.js +186 -11
  101. package/dist/cli/systemInputs.js.map +1 -1
  102. package/dist/cli/upgrade.d.ts +30 -7
  103. package/dist/cli/upgrade.js +434 -50
  104. package/dist/cli/upgrade.js.map +1 -1
  105. package/dist/cli/usageLog.d.ts +4 -2
  106. package/dist/cli/usageLog.js +4 -2
  107. package/dist/cli/usageLog.js.map +1 -1
  108. package/dist/cli.js +631 -100
  109. package/dist/cli.js.map +1 -1
  110. package/dist/emit/api.d.ts +29 -0
  111. package/dist/emit/api.js +220 -0
  112. package/dist/emit/api.js.map +1 -0
  113. package/dist/emit/apiCheckJson.d.ts +3 -0
  114. package/dist/emit/apiCheckJson.js +21 -0
  115. package/dist/emit/apiCheckJson.js.map +1 -0
  116. package/dist/emit/codeownersJson.d.ts +3 -0
  117. package/dist/emit/codeownersJson.js +19 -0
  118. package/dist/emit/codeownersJson.js.map +1 -0
  119. package/dist/emit/coverageJson.d.ts +5 -2
  120. package/dist/emit/coverageJson.js +6 -2
  121. package/dist/emit/coverageJson.js.map +1 -1
  122. package/dist/emit/diffJson.d.ts +1 -1
  123. package/dist/emit/diffJson.js +8 -1
  124. package/dist/emit/diffJson.js.map +1 -1
  125. package/dist/emit/engagementJson.d.ts +8 -0
  126. package/dist/emit/engagementJson.js +46 -0
  127. package/dist/emit/engagementJson.js.map +1 -0
  128. package/dist/emit/glossaryJson.d.ts +1 -1
  129. package/dist/emit/glossaryJson.js +4 -1
  130. package/dist/emit/glossaryJson.js.map +1 -1
  131. package/dist/emit/json.d.ts +17 -1
  132. package/dist/emit/json.js +30 -1
  133. package/dist/emit/json.js.map +1 -1
  134. package/dist/emit/metricsJson.d.ts +1 -1
  135. package/dist/emit/metricsJson.js +4 -1
  136. package/dist/emit/metricsJson.js.map +1 -1
  137. package/dist/emit/queryJson.d.ts +1 -1
  138. package/dist/emit/queryJson.js +7 -1
  139. package/dist/emit/queryJson.js.map +1 -1
  140. package/dist/emit/scopeJson.d.ts +12 -0
  141. package/dist/emit/scopeJson.js +26 -0
  142. package/dist/emit/scopeJson.js.map +1 -0
  143. package/dist/emit/skillCheckJson.d.ts +3 -2
  144. package/dist/emit/skillCheckJson.js +10 -2
  145. package/dist/emit/skillCheckJson.js.map +1 -1
  146. package/dist/emit/statusJson.d.ts +1 -1
  147. package/dist/emit/statusJson.js +15 -1
  148. package/dist/emit/statusJson.js.map +1 -1
  149. package/dist/emit/systemJson.d.ts +15 -8
  150. package/dist/emit/systemJson.js +28 -13
  151. package/dist/emit/systemJson.js.map +1 -1
  152. package/dist/emit/upgradeJson.d.ts +1 -1
  153. package/dist/emit/upgradeJson.js +4 -1
  154. package/dist/emit/upgradeJson.js.map +1 -1
  155. package/dist/emit/validateJson.d.ts +3 -3
  156. package/dist/emit/validateJson.js +10 -4
  157. package/dist/emit/validateJson.js.map +1 -1
  158. package/dist/mcp/server.d.ts +1 -1
  159. package/dist/mcp/server.js +186 -37
  160. package/dist/mcp/server.js.map +1 -1
  161. package/dist/model/diff.d.ts +4 -1
  162. package/dist/model/diff.js +44 -8
  163. package/dist/model/diff.js.map +1 -1
  164. package/dist/model/glossary.d.ts +2 -0
  165. package/dist/model/glossary.js +1 -0
  166. package/dist/model/glossary.js.map +1 -1
  167. package/dist/model/model.d.ts +55 -2
  168. package/dist/model/model.js +57 -0
  169. package/dist/model/model.js.map +1 -1
  170. package/dist/model/qualifiedRef.d.ts +18 -0
  171. package/dist/model/qualifiedRef.js +26 -0
  172. package/dist/model/qualifiedRef.js.map +1 -1
  173. package/dist/model/queryIndex.d.ts +9 -1
  174. package/dist/model/queryIndex.js +18 -2
  175. package/dist/model/queryIndex.js.map +1 -1
  176. package/dist/model/rules.d.ts +143 -2
  177. package/dist/model/rules.js +162 -3
  178. package/dist/model/rules.js.map +1 -1
  179. package/dist/model/validate.d.ts +40 -0
  180. package/dist/model/validate.js +147 -1
  181. package/dist/model/validate.js.map +1 -1
  182. package/dist/parser/ast.d.ts +31 -3
  183. package/dist/parser/parser.js +148 -14
  184. package/dist/parser/parser.js.map +1 -1
  185. package/dist/query/format.js +1 -1
  186. package/dist/query/format.js.map +1 -1
  187. package/dist/query/verbs.d.ts +6 -0
  188. package/dist/query/verbs.js +6 -2
  189. package/dist/query/verbs.js.map +1 -1
  190. package/dist/system/adaptation.d.ts +14 -0
  191. package/dist/system/adaptation.js +49 -0
  192. package/dist/system/adaptation.js.map +1 -0
  193. package/dist/system/codeowners.d.ts +77 -0
  194. package/dist/system/codeowners.js +242 -0
  195. package/dist/system/codeowners.js.map +1 -0
  196. package/dist/system/manifest.d.ts +10 -5
  197. package/dist/system/manifest.js +54 -26
  198. package/dist/system/manifest.js.map +1 -1
  199. package/dist/system/migrateManifest.d.ts +28 -0
  200. package/dist/system/migrateManifest.js +155 -0
  201. package/dist/system/migrateManifest.js.map +1 -0
  202. package/dist/system/scope.d.ts +46 -0
  203. package/dist/system/scope.js +132 -0
  204. package/dist/system/scope.js.map +1 -0
  205. package/dist/system/verify.d.ts +50 -13
  206. package/dist/system/verify.js +179 -58
  207. package/dist/system/verify.js.map +1 -1
  208. package/dist/templates.d.ts +2 -2
  209. package/dist/templates.js +23 -2
  210. package/dist/templates.js.map +1 -1
  211. package/package.json +6 -3
  212. package/plugin/.claude-plugin/plugin.json +18 -0
  213. package/plugin/agents/em-critic.md +27 -0
  214. package/plugin/agents/em-implementer.md +35 -0
  215. package/plugin/agents/em-reviewer.md +32 -0
  216. package/plugin/agents/em-validator.md +28 -0
  217. package/plugin/shared/reference/em-dsl.md +866 -0
  218. package/plugin/shared/reference/methodology.md +329 -0
  219. package/plugin/shared/reference/operating-principles.md +222 -0
  220. package/plugin/shared/reference/slice-doc-schema.md +566 -0
  221. package/plugin/shared/templates/conformance-report.md +85 -0
  222. package/plugin/shared/templates/constitution.md +136 -0
  223. package/plugin/shared/templates/model-readme.md +46 -0
  224. package/plugin/shared/templates/slice.md +251 -0
  225. package/plugin/shared/templates/state.md +77 -0
  226. package/plugin/skills/conform/SKILL.md +93 -0
  227. package/plugin/skills/conform/reference/conform.md +428 -0
  228. package/plugin/skills/design/SKILL.md +297 -0
  229. package/plugin/skills/discover/SKILL.md +90 -0
  230. package/plugin/skills/discover/reference/extract.md +147 -0
  231. package/plugin/skills/engagement/SKILL.md +193 -0
  232. package/plugin/skills/engagement/reference/engagement.md +144 -0
  233. package/plugin/skills/event-modeling/SKILL.md +132 -0
  234. package/plugin/skills/implement/SKILL.md +61 -0
  235. package/plugin/skills/implement/reference/implement.md +439 -0
  236. package/plugin/skills/review/SKILL.md +74 -0
  237. package/dist/emit/typespec.d.ts +0 -26
  238. package/dist/emit/typespec.js +0 -356
  239. package/dist/emit/typespec.js.map +0 -1
@@ -0,0 +1,90 @@
1
+ import { Diagnostic } from "../model/validate.js";
2
+ import { compile } from "../pipeline.js";
3
+ import { ElementExport, FieldExport, TypeExport } from "../emit/json.js";
4
+ import { GitRunner } from "./diff-inputs.js";
5
+ /** `<modelDir>/contracts/<modelKey>.tsp` (R6), built from the model path as given. */
6
+ export declare function contractPathFor(modelFile: string, modelKey: string): string;
7
+ /** The `Source:` label: the model path relative to the contract file's directory, `/`-separated,
8
+ * so the generated text never depends on the cwd `em api generate` ran from. */
9
+ export declare function sourceLabelFor(modelFile: string, contractFile: string): string;
10
+ export interface GeneratedContract {
11
+ modelKey: string;
12
+ contractPath: string;
13
+ /** Full file text, trailing newline included. */
14
+ text: string;
15
+ diagnostics: Diagnostic[];
16
+ }
17
+ /** Compile result + generated contract text for an error-free model. */
18
+ export declare function generateContract(file: string, source: string, compiled: ReturnType<typeof compile>, outPath?: string): GeneratedContract;
19
+ export type ApiChangeKind = "additive" | "breaking";
20
+ export interface ApiCheckChange {
21
+ kind: ApiChangeKind;
22
+ /** `<kind>.<slug>` of the element (or `type.<slug>` for a declared type) — contract-level
23
+ * identity, no slice key (moving an element between slices does not change the contract). */
24
+ element: string;
25
+ /** The field the change concerns, or null for an element-level change. */
26
+ field: string | null;
27
+ what: string;
28
+ }
29
+ type Role = "input" | "output";
30
+ interface SurfaceEntry {
31
+ /** command | event | view | type */
32
+ kind: string;
33
+ name: string;
34
+ /** Normalized identity key: kind + normalizeName(name). */
35
+ key: string;
36
+ fields: FieldExport[];
37
+ renamedFrom: string[];
38
+ roles: Set<Role>;
39
+ /** Model-declared invariants (MIL-265), declaration order; `[]` for a type. */
40
+ invariants: {
41
+ id: string;
42
+ rule: string | null;
43
+ }[];
44
+ }
45
+ interface Surface {
46
+ entries: SurfaceEntry[];
47
+ /** Normalized `kind:name` of every element present in the model, public or not — tells
48
+ * "`public` dropped" apart from "removed". */
49
+ allElements: Set<string>;
50
+ }
51
+ /** Build the public surface of one compiled model: public commands (input), events and views
52
+ * (output), and every declared type reachable from them (carrying the roles that reach it). */
53
+ export declare function surfaceOf(slices: {
54
+ elements: ElementExport[];
55
+ }[], types: TypeExport[]): Surface;
56
+ /** A field's type as the contract sees it: a declared type's name or the raw string,
57
+ * normalized, with its array arity. */
58
+ export declare function typeLabel(f: Pick<FieldExport, "type" | "typeRef">): string;
59
+ export declare function typeIdentity(f: Pick<FieldExport, "type" | "typeRef">): string;
60
+ /** Diff two public surfaces. `base === null` means the model did not exist at the base
61
+ * revision: every HEAD element is an additive addition. */
62
+ export declare function diffSurfaces(base: Surface | null, head: Surface): ApiCheckChange[];
63
+ export interface ApiCheckReport {
64
+ file: string;
65
+ contractPath: string;
66
+ current: boolean;
67
+ /** True when the contract file does not exist at all (a special case of not current). */
68
+ missing: boolean;
69
+ base: string | null;
70
+ changes: ApiCheckChange[];
71
+ }
72
+ export type ApiCheckOutcome = {
73
+ ok: true;
74
+ report: ApiCheckReport;
75
+ diagnostics: Diagnostic[];
76
+ } | {
77
+ ok: false;
78
+ message: string;
79
+ diagnostics: Diagnostic[];
80
+ };
81
+ /**
82
+ * Run `em api check <file> [--base <rev>]`. (a) "current" = regenerate from the working-tree
83
+ * model and compare to the committed contract file's text; (b) with `base`, compile the model
84
+ * at that revision (`resolveRevision`) and diff the public surfaces structurally. A model
85
+ * absent at `base` (new model) reports every public element as additive.
86
+ */
87
+ export declare function runApiCheck(file: string, base: string | undefined, runGit?: GitRunner): ApiCheckOutcome;
88
+ /** The text report: one status line, then one `additive:`/`breaking:` line per change. */
89
+ export declare function formatApiCheckText(r: ApiCheckReport): string[];
90
+ export {};
@@ -0,0 +1,318 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // `em api generate | check` (MIL-237): the contract path convention (briefing R6), the
3
+ // "is the committed contract current" text comparison, and the structural public-surface diff
4
+ // that annotates each change additive or breaking (briefing R8/R12). Pure where it can be —
5
+ // fs/git reads go through injectable readers so the diff and the classification are unit-
6
+ // testable without a repository; cli.ts and the MCP `api_check` tool share `runApiCheck`.
7
+ import { existsSync, readFileSync } from "node:fs";
8
+ import { dirname, join, relative, resolve, sep } from "node:path";
9
+ import { normalizeName } from "../model/model.js";
10
+ import { computeModelKey } from "../model/qualifiedRef.js";
11
+ import { hasErrors } from "../model/validate.js";
12
+ import { compile } from "../pipeline.js";
13
+ import { ParseError } from "../parser/parser.js";
14
+ import { buildApiContract, publicSurfaceOf } from "../emit/api.js";
15
+ import { buildExportDoc } from "../emit/json.js";
16
+ import { kebabSlug } from "../util/slug.js";
17
+ import { realGit, resolveRevision } from "./diff-inputs.js";
18
+ /** `<modelDir>/contracts/<modelKey>.tsp` (R6), built from the model path as given. */
19
+ export function contractPathFor(modelFile, modelKey) {
20
+ return join(dirname(modelFile), "contracts", `${modelKey}.tsp`);
21
+ }
22
+ /** The `Source:` label: the model path relative to the contract file's directory, `/`-separated,
23
+ * so the generated text never depends on the cwd `em api generate` ran from. */
24
+ export function sourceLabelFor(modelFile, contractFile) {
25
+ return relative(dirname(resolve(contractFile)), resolve(modelFile)).split(sep).join("/");
26
+ }
27
+ /** Compile result + generated contract text for an error-free model. */
28
+ export function generateContract(file, source, compiled, outPath) {
29
+ const modelKey = computeModelKey(compiled.model, file);
30
+ const contractPath = outPath ?? contractPathFor(file, modelKey);
31
+ const result = buildApiContract(compiled.model, compiled.refs, compiled.diagnostics, source, file, sourceLabelFor(file, contractPath));
32
+ return { modelKey, contractPath, text: result.text + "\n", diagnostics: result.diagnostics };
33
+ }
34
+ const keyOf = (kind, name) => `${kind}:${normalizeName(name)}`;
35
+ /** Build the public surface of one compiled model: public commands (input), events and views
36
+ * (output), and every declared type reachable from them (carrying the roles that reach it). */
37
+ export function surfaceOf(slices, types) {
38
+ const s = publicSurfaceOf(slices);
39
+ const entries = [];
40
+ const typesByRef = new Map(types.map((t) => [t.ref, t]));
41
+ const typeRoles = new Map();
42
+ const reach = (fields, role) => {
43
+ for (const f of fields ?? []) {
44
+ if (!f.typeRef)
45
+ continue;
46
+ const roles = typeRoles.get(f.typeRef.ref) ?? new Set();
47
+ if (roles.has(role))
48
+ continue;
49
+ roles.add(role);
50
+ typeRoles.set(f.typeRef.ref, roles);
51
+ reach(typesByRef.get(f.typeRef.ref)?.fields ?? null, role);
52
+ }
53
+ };
54
+ const push = (el, role) => {
55
+ entries.push({
56
+ kind: el.kind,
57
+ name: el.name,
58
+ key: keyOf(el.kind, el.name),
59
+ fields: el.fields ?? [],
60
+ renamedFrom: el.renamedFrom ?? [],
61
+ roles: new Set([role]),
62
+ invariants: el.invariants ?? [],
63
+ });
64
+ reach(el.fields, role);
65
+ };
66
+ for (const el of s.commands)
67
+ push(el, "input");
68
+ for (const el of s.events)
69
+ push(el, "output");
70
+ for (const el of s.views)
71
+ push(el, "output");
72
+ for (const t of types) {
73
+ const roles = typeRoles.get(t.ref);
74
+ if (!roles)
75
+ continue;
76
+ entries.push({ kind: "type", name: t.name, key: keyOf("type", t.name), fields: t.fields, renamedFrom: [], roles, invariants: [] });
77
+ }
78
+ const allElements = new Set();
79
+ for (const slice of slices)
80
+ for (const el of slice.elements)
81
+ allElements.add(keyOf(el.kind, el.name));
82
+ for (const t of types)
83
+ allElements.add(keyOf("type", t.name));
84
+ return { entries, allElements };
85
+ }
86
+ /** A field's type as the contract sees it: a declared type's name or the raw string,
87
+ * normalized, with its array arity. */
88
+ export function typeLabel(f) {
89
+ if (f.typeRef)
90
+ return `${f.typeRef.name}${f.typeRef.array ? "[]" : ""}`;
91
+ return f.type ?? "(none)";
92
+ }
93
+ export function typeIdentity(f) {
94
+ if (f.typeRef)
95
+ return `ref:${f.typeRef.ref}:${f.typeRef.array}`;
96
+ return `raw:${(f.type ?? "").replace(/\s+/g, "").toLowerCase()}`;
97
+ }
98
+ function diffFields(base, head, element, out) {
99
+ const roles = new Set([...base.roles, ...head.roles]);
100
+ const isInput = roles.has("input");
101
+ const isOutput = roles.has("output");
102
+ const headByName = new Map(head.fields.map((f) => [normalizeName(f.name), f]));
103
+ const baseByName = new Map(base.fields.map((f) => [normalizeName(f.name), f]));
104
+ // HEAD field -> base field it renames (a `renamed from` naming a base field that HEAD no
105
+ // longer carries under its old name).
106
+ const renamedTo = new Map();
107
+ for (const f of head.fields) {
108
+ if (baseByName.has(normalizeName(f.name)))
109
+ continue;
110
+ for (const old of f.renamedFrom ?? []) {
111
+ const k = normalizeName(old);
112
+ if (baseByName.has(k) && !headByName.has(k) && !renamedTo.has(k)) {
113
+ renamedTo.set(k, f);
114
+ break;
115
+ }
116
+ }
117
+ }
118
+ const compare = (b, h) => {
119
+ if (typeIdentity(b) !== typeIdentity(h)) {
120
+ out.push({ kind: "breaking", element, field: h.name, what: `type changed ${typeLabel(b)} → ${typeLabel(h)}` });
121
+ }
122
+ if (b.optional !== h.optional) {
123
+ if (h.optional) {
124
+ // required → optional: outputs may now omit it (breaking); inputs only loosen.
125
+ out.push({ kind: isOutput ? "breaking" : "additive", element, field: h.name, what: "changed required → optional" });
126
+ }
127
+ else {
128
+ out.push({ kind: "breaking", element, field: h.name, what: "changed optional → required" });
129
+ }
130
+ }
131
+ };
132
+ // Base order first: removals, renames and changes to existing fields.
133
+ for (const b of base.fields) {
134
+ const k = normalizeName(b.name);
135
+ const h = headByName.get(k);
136
+ if (h) {
137
+ compare(b, h);
138
+ continue;
139
+ }
140
+ const renamed = renamedTo.get(k);
141
+ if (renamed) {
142
+ out.push({ kind: "breaking", element, field: renamed.name, what: `renamed from "${b.name}"` });
143
+ compare(b, renamed);
144
+ continue;
145
+ }
146
+ out.push({ kind: "breaking", element, field: b.name, what: "removed" });
147
+ }
148
+ // Then HEAD-only fields, HEAD order.
149
+ const renameTargets = new Set([...renamedTo.values()]);
150
+ for (const h of head.fields) {
151
+ if (baseByName.has(normalizeName(h.name)) || renameTargets.has(h))
152
+ continue;
153
+ const required = !h.optional;
154
+ // Adding a required input is breaking (existing callers do not send it); adding to an
155
+ // output is additive (consumers tolerate unknown fields).
156
+ const kind = isInput && required ? "breaking" : "additive";
157
+ out.push({ kind, element, field: h.name, what: `added (${required ? "required" : "optional"})` });
158
+ }
159
+ }
160
+ /** MIL-265: a public element's invariants, base vs HEAD, matched by ID. Added or rule text
161
+ * changed = breaking (the contract got tighter); removed = additive (looser). HEAD order for
162
+ * additions/changes, then base order for removals. */
163
+ function diffInvariants(base, head, element, out) {
164
+ const baseById = new Map(base.invariants.map((i) => [i.id, i]));
165
+ const headIds = new Set(head.invariants.map((i) => i.id));
166
+ for (const h of head.invariants) {
167
+ const b = baseById.get(h.id);
168
+ if (!b)
169
+ out.push({ kind: "breaking", element, field: null, what: `invariant ${h.id} added` });
170
+ else if (b.rule !== h.rule)
171
+ out.push({ kind: "breaking", element, field: null, what: `invariant ${h.id} rule changed` });
172
+ }
173
+ for (const b of base.invariants) {
174
+ if (!headIds.has(b.id))
175
+ out.push({ kind: "additive", element, field: null, what: `invariant ${b.id} removed` });
176
+ }
177
+ }
178
+ /** Diff two public surfaces. `base === null` means the model did not exist at the base
179
+ * revision: every HEAD element is an additive addition. */
180
+ export function diffSurfaces(base, head) {
181
+ const out = [];
182
+ const elementId = (e) => `${e.kind}.${kebabSlug(e.name)}`;
183
+ if (!base) {
184
+ for (const h of head.entries)
185
+ out.push({ kind: "additive", element: elementId(h), field: null, what: "added" });
186
+ return out;
187
+ }
188
+ const baseByKey = new Map(base.entries.map((e) => [e.key, e]));
189
+ const matchedBase = new Set();
190
+ for (const h of head.entries) {
191
+ const element = elementId(h);
192
+ const same = baseByKey.get(h.key);
193
+ if (same) {
194
+ matchedBase.add(same.key);
195
+ diffFields(same, h, element, out);
196
+ diffInvariants(same, h, element, out);
197
+ continue;
198
+ }
199
+ const renamedFrom = h.renamedFrom
200
+ .map((old) => baseByKey.get(keyOf(h.kind, old)))
201
+ .find((b) => b !== undefined && !matchedBase.has(b.key) && !head.entries.some((x) => x.key === b.key));
202
+ if (renamedFrom) {
203
+ matchedBase.add(renamedFrom.key);
204
+ out.push({ kind: "breaking", element, field: null, what: `renamed from "${renamedFrom.name}"` });
205
+ diffFields(renamedFrom, h, element, out);
206
+ diffInvariants(renamedFrom, h, element, out);
207
+ continue;
208
+ }
209
+ if (h.kind !== "type" && base.allElements.has(h.key)) {
210
+ out.push({ kind: "additive", element, field: null, what: "marked public" });
211
+ }
212
+ else {
213
+ out.push({ kind: "additive", element, field: null, what: "added" });
214
+ }
215
+ }
216
+ for (const b of base.entries) {
217
+ if (matchedBase.has(b.key))
218
+ continue;
219
+ const element = elementId(b);
220
+ if (b.kind !== "type" && head.allElements.has(b.key)) {
221
+ out.push({ kind: "breaking", element, field: null, what: "`public` dropped" });
222
+ }
223
+ else {
224
+ out.push({ kind: "breaking", element, field: null, what: "removed" });
225
+ }
226
+ }
227
+ return out;
228
+ }
229
+ /**
230
+ * Run `em api check <file> [--base <rev>]`. (a) "current" = regenerate from the working-tree
231
+ * model and compare to the committed contract file's text; (b) with `base`, compile the model
232
+ * at that revision (`resolveRevision`) and diff the public surfaces structurally. A model
233
+ * absent at `base` (new model) reports every public element as additive.
234
+ */
235
+ export function runApiCheck(file, base, runGit = realGit) {
236
+ let source;
237
+ try {
238
+ source = readFileSync(file, "utf8");
239
+ }
240
+ catch {
241
+ return { ok: false, message: `em api check: cannot read ${file}`, diagnostics: [] };
242
+ }
243
+ let head;
244
+ try {
245
+ head = compile(source);
246
+ }
247
+ catch (e) {
248
+ if (e instanceof ParseError)
249
+ return { ok: false, message: `em api check: parse error in ${file} ${e.message}`, diagnostics: [] };
250
+ throw e;
251
+ }
252
+ if (hasErrors(head.diagnostics)) {
253
+ return { ok: false, message: "em api check: not checking — fix the errors above", diagnostics: head.diagnostics };
254
+ }
255
+ const generated = generateContract(file, source, head);
256
+ const missing = !existsSync(generated.contractPath);
257
+ const current = !missing && readFileSync(generated.contractPath, "utf8") === generated.text;
258
+ let changes = [];
259
+ if (base !== undefined) {
260
+ const top = runGit(["-C", dirname(resolve(file)), "rev-parse", "--show-toplevel"]);
261
+ if (top.status !== 0) {
262
+ return { ok: false, message: `em api check: ${file} is not inside a git repository (needed for --base)`, diagnostics: head.diagnostics };
263
+ }
264
+ const verify = runGit(["-C", dirname(resolve(file)), "rev-parse", "--verify", "--quiet", `${base}^{commit}`]);
265
+ if (verify.status !== 0) {
266
+ return { ok: false, message: `em api check: unknown revision "${base}" (needed for --base)`, diagnostics: head.diagnostics };
267
+ }
268
+ const headDoc = buildExportDoc(head.model, head.refs, head.diagnostics, source, file).doc;
269
+ const headSurface = surfaceOf(headDoc.model.slices, headDoc.model.types);
270
+ const atBase = resolveRevision(file, base, runGit);
271
+ let baseSurface = null;
272
+ if (atBase.ok) {
273
+ let baseCompiled;
274
+ try {
275
+ baseCompiled = compile(atBase.content);
276
+ }
277
+ catch (e) {
278
+ if (e instanceof ParseError) {
279
+ return { ok: false, message: `em api check: parse error in ${file}@${base} ${e.message}`, diagnostics: head.diagnostics };
280
+ }
281
+ throw e;
282
+ }
283
+ // Base-side validate errors (e.g. a pre-1.14 free-text public type) do not block the
284
+ // structural diff — the diff reads shapes, not strictness.
285
+ const baseDoc = buildExportDoc(baseCompiled.model, baseCompiled.refs, baseCompiled.diagnostics, atBase.content, file).doc;
286
+ baseSurface = surfaceOf(baseDoc.model.slices, baseDoc.model.types);
287
+ }
288
+ else if (!/is not tracked by git/.test(atBase.message)) {
289
+ return { ok: false, message: atBase.message.replace(/^em diff:/, "em api check:"), diagnostics: head.diagnostics };
290
+ }
291
+ changes = diffSurfaces(baseSurface, headSurface);
292
+ }
293
+ return {
294
+ ok: true,
295
+ report: { file, contractPath: generated.contractPath, current, missing, base: base ?? null, changes },
296
+ diagnostics: generated.diagnostics,
297
+ };
298
+ }
299
+ /** The text report: one status line, then one `additive:`/`breaking:` line per change. */
300
+ export function formatApiCheckText(r) {
301
+ const lines = [];
302
+ const regen = `run: em api generate ${r.file}`;
303
+ if (r.current)
304
+ lines.push(`contract ${r.contractPath} is current`);
305
+ else if (r.missing)
306
+ lines.push(`contract ${r.contractPath} is missing — ${regen}`);
307
+ else
308
+ lines.push(`contract ${r.contractPath} is stale — ${regen}`);
309
+ if (r.base !== null) {
310
+ if (r.changes.length === 0)
311
+ lines.push(`no public-surface changes since ${r.base}`);
312
+ for (const c of r.changes) {
313
+ lines.push(`${c.kind}: ${c.element}${c.field !== null ? ` field "${c.field}"` : ""} ${c.what}`);
314
+ }
315
+ }
316
+ return lines;
317
+ }
318
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/cli/api.ts"],"names":[],"mappings":"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"}
@@ -14,11 +14,35 @@ export declare function findUnsafeCiInitArg(value: string): string | null;
14
14
  * by a pre-pin em shows stale the same way. */
15
15
  export declare function ciManagedBody(model: string, testsDir: string, emVersion: string): string;
16
16
  export declare function buildCiWorkflowFile(model: string, testsDir: string, emVersion: string): string;
17
+ /** One model of a system, as `em ci init <system.yaml>` hands it to the generators: its manifest
18
+ * key and its path relative to the repo root (the working directory the workflow runs from). */
19
+ export interface CiModel {
20
+ key: string;
21
+ path: string;
22
+ }
23
+ /** Deterministic, valid GitHub Actions job-id suffix per model key. Keys are kebab-case with an
24
+ * optional `~N` collision suffix (MIL-193), and `~` is not an Actions id character, so it
25
+ * becomes `-`; if two keys then collide (`a-2` and `a~2`), the later one in key order gets a
26
+ * numeric suffix until it is unique. Keys are processed in sorted order, so the mapping never
27
+ * depends on manifest order. */
28
+ export declare function ciJobIds(keys: string[]): Map<string, string>;
29
+ /** The directory a model's design artifacts live in (R6: `dirname(<model>.em)`). */
30
+ export declare function ciModelDir(modelPath: string): string;
31
+ /** The managed block for a whole system: per-model `validate-`/`slice-index-`/`coverage-`/
32
+ * `ledger-`/`upgrade-check-`/`status-badge-<id>` jobs, then ONE `skill-check` and ONE
33
+ * `glossary` (both repo-wide). Same version-pin discipline as `ciManagedBody`. */
34
+ export declare function ciManagedBodyMulti(models: CiModel[], testsDir: string, emVersion: string): string;
35
+ export declare function buildCiWorkflowFileMulti(arg: string, models: CiModel[], testsDir: string, emVersion: string): string;
17
36
  /** The managed block only (no header/`on:`/`permissions:`/`jobs:` scaffolding) — what gets
18
37
  * written between the marker pair, both for a fresh file and to patch an existing marked one
19
38
  * in place. */
20
- export declare function conformManagedBody(model: string, emVersion: string): string;
21
- export declare function buildConformWorkflowFile(model: string, emVersion: string): string;
39
+ export declare function conformManagedBody(model: string, emVersion: string, usePlugin?: boolean): string;
40
+ export declare function buildConformWorkflowFile(model: string, emVersion: string, usePlugin?: boolean): string;
41
+ /** Conformance for a whole system: the same single `conform` job fanned out over a matrix of
42
+ * model directories (`MODEL_DIR: ${{ matrix.model }}`). Directories, not models: two models in
43
+ * one directory share a conformance folder, so the matrix lists each directory once. */
44
+ export declare function conformManagedBodyMulti(models: CiModel[], emVersion: string, usePlugin?: boolean): string;
45
+ export declare function buildConformWorkflowFileMulti(arg: string, models: CiModel[], emVersion: string, usePlugin?: boolean): string;
22
46
  export type CiFileStatus = {
23
47
  kind: "create";
24
48
  content: string;
@@ -34,7 +58,43 @@ export type CiFileStatus = {
34
58
  } | {
35
59
  kind: "would-replace";
36
60
  content: string;
61
+ } | {
62
+ kind: "other-models";
63
+ previous: string[];
64
+ requested: string[];
65
+ narrowing: boolean;
66
+ } | {
67
+ kind: "replace-models";
68
+ content: string;
69
+ previous: string[];
70
+ requested: string[];
71
+ narrowing: boolean;
37
72
  };
73
+ /**
74
+ * The model SET an existing managed block was generated for, read from the block's own content
75
+ * (MIL-256, widened to sets by MIL-233). Deliberately content-derived rather than a new marker
76
+ * line: blocks written by em 1.13.0 and earlier carry no machine-readable model, but every one
77
+ * of them bakes the model into the per-model `run:` lines. em-ci.yml: every
78
+ * `slice index "<model>" --check` line (one per model); em-conform.yml: every `matrix.model`
79
+ * entry of a multi-model block, else the single `MODEL_DIR: <dir>` line. None of these patterns
80
+ * includes the `npx @milehimikey/em@<ver>` pin, so a version difference can never read as a
81
+ * different model. Returns `[]` when the block was hand-edited past recognition - callers then
82
+ * treat it as covering the requested models (the conservative, pre-MIL-256 behavior) rather than
83
+ * refusing on a guess.
84
+ */
85
+ export declare function managedBlockModels(markerName: string, blockBody: string): string[];
86
+ /** The model set of an existing workflow file's managed block (`[]` when unmarked/unreadable). */
87
+ export declare function fileBlockModels(content: string, markerName: string): string[];
88
+ /** `--check`'s extra detail for a stale multi-model block: which models the manifest adds and
89
+ * which the workflow still names that the manifest no longer does. `null` when the sets agree. */
90
+ export declare function describeSetChange(previous: string[], requested: string[]): string | null;
91
+ /** The one-line explanation of an `other-models` refusal (also printed by `--check`), ending in
92
+ * what to do about it. Names both sets. */
93
+ export declare function describeOtherModels(path: string, status: {
94
+ previous: string[];
95
+ requested: string[];
96
+ narrowing: boolean;
97
+ }): string;
38
98
  /**
39
99
  * Decide what to do with one generated file: create it if missing, patch the managed block if
40
100
  * the marker pair is present, or (without `force`) leave an existing unmarked file alone. Pure
@@ -44,6 +104,31 @@ export type CiFileStatus = {
44
104
  * marker-wrapped body) — written verbatim for `create`/`would-replace`. `managedBody` is just
45
105
  * the text between the markers, reused to patch an existing marked file in place without
46
106
  * touching whatever a repo added around it.
107
+ *
108
+ * Block identity (MIL-256 #174, MIL-233): a block is identified by the SET of models it names
109
+ * (`managedBlockModels`). The requested set wins unless that would lose models by accident:
110
+ * - disjoint sets are `other-models` (refused without `force`, `replace-models` with it);
111
+ * - `multi` false (a single `<model.em>` argument) against a block naming several models is
112
+ * `other-models` too (`narrowing`) - the single-model form must never silently narrow it;
113
+ * - otherwise (same set, superset, subset or overlap, requested from the system manifest) the
114
+ * block is regenerated for the requested set - `stale` when anything differs, e.g. a version
115
+ * pin, an added model or a removed one.
116
+ * `em upgrade`'s ci-block step re-derives its arguments from the existing file (and, for a
117
+ * multi-model block, from the manifest), so it only ever plans the same set.
47
118
  */
48
- export declare function planCiFile(path: string, generated: string, managedBody: string, markerName: string, force: boolean): CiFileStatus;
119
+ export declare function planCiFile(path: string, generated: string, managedBody: string, markerName: string, force: boolean, multi?: boolean): CiFileStatus;
49
120
  export declare function applyCiFile(path: string, status: CiFileStatus): void;
121
+ export type CiModelsResult = {
122
+ ok: true;
123
+ models: CiModel[];
124
+ manifestPath: string;
125
+ } | {
126
+ ok: false;
127
+ message: string;
128
+ };
129
+ /** Read the system manifest at `target` (a file, or a directory holding `system.yaml`) and turn
130
+ * its `models:` into `CiModel`s whose paths are relative to `baseDir` - the repo root the
131
+ * workflows run from. Reuses MIL-235's `parseManifest`; compiling the models is not needed to
132
+ * write a workflow, so a model that does not compile does not block it. Every path goes through
133
+ * `findUnsafeCiInitArg`; a source must be a `.em` file inside `baseDir`. */
134
+ export declare function ciModelsFromManifest(target: string, baseDir: string): CiModelsResult;