@milehimikey/em 1.8.0 → 1.9.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 (127) hide show
  1. package/.claude/skills/event-modeling/SKILL.md +58 -404
  2. package/.claude/skills/event-modeling-conform/SKILL.md +77 -0
  3. package/.claude/skills/{event-modeling → event-modeling-conform}/reference/conform.md +39 -13
  4. package/.claude/skills/event-modeling-design/SKILL.md +139 -0
  5. package/.claude/skills/event-modeling-discover/SKILL.md +89 -0
  6. package/.claude/skills/{event-modeling → event-modeling-discover}/reference/extract.md +3 -2
  7. package/.claude/skills/event-modeling-implement/SKILL.md +40 -0
  8. package/.claude/skills/{event-modeling → event-modeling-implement}/reference/implement.md +3 -2
  9. package/.claude/skills/event-modeling-review/SKILL.md +58 -0
  10. package/.claude/skills/{event-modeling → event-modeling-shared}/reference/em-dsl.md +128 -84
  11. package/.claude/skills/{event-modeling → event-modeling-shared}/reference/methodology.md +6 -5
  12. package/.claude/skills/event-modeling-shared/reference/operating-principles.md +147 -0
  13. package/.claude/skills/{event-modeling → event-modeling-shared}/templates/model-readme.md +2 -2
  14. package/.claude/skills/{event-modeling → event-modeling-shared}/templates/slice.md +51 -8
  15. package/README.md +24 -4
  16. package/dist/catalog/build.js +9 -0
  17. package/dist/catalog/build.js.map +1 -1
  18. package/dist/catalog/docJoin.d.ts +15 -0
  19. package/dist/catalog/docJoin.js +8 -0
  20. package/dist/catalog/docJoin.js.map +1 -1
  21. package/dist/catalog/modelCollisionValidate.d.ts +22 -0
  22. package/dist/catalog/modelCollisionValidate.js +67 -0
  23. package/dist/catalog/modelCollisionValidate.js.map +1 -0
  24. package/dist/catalog/orphanedSliceDocValidate.d.ts +11 -0
  25. package/dist/catalog/orphanedSliceDocValidate.js +98 -0
  26. package/dist/catalog/orphanedSliceDocValidate.js.map +1 -0
  27. package/dist/catalog/sliceDoc.d.ts +15 -0
  28. package/dist/catalog/sliceDoc.js +18 -0
  29. package/dist/catalog/sliceDoc.js.map +1 -1
  30. package/dist/cli/changelogBuild.d.ts +12 -0
  31. package/dist/cli/changelogBuild.js +89 -0
  32. package/dist/cli/changelogBuild.js.map +1 -0
  33. package/dist/cli/ciInit.d.ts +42 -0
  34. package/dist/cli/ciInit.js +298 -0
  35. package/dist/cli/ciInit.js.map +1 -0
  36. package/dist/cli/conformSupersede.d.ts +32 -0
  37. package/dist/cli/conformSupersede.js +102 -0
  38. package/dist/cli/conformSupersede.js.map +1 -0
  39. package/dist/cli/coverage.d.ts +17 -10
  40. package/dist/cli/coverage.js +61 -16
  41. package/dist/cli/coverage.js.map +1 -1
  42. package/dist/cli/frontmatterSurgery.d.ts +28 -0
  43. package/dist/cli/frontmatterSurgery.js +66 -0
  44. package/dist/cli/frontmatterSurgery.js.map +1 -0
  45. package/dist/cli/markImplemented.js +6 -45
  46. package/dist/cli/markImplemented.js.map +1 -1
  47. package/dist/cli/ratify.d.ts +41 -0
  48. package/dist/cli/ratify.js +151 -0
  49. package/dist/cli/ratify.js.map +1 -0
  50. package/dist/cli/reratify.d.ts +33 -0
  51. package/dist/cli/reratify.js +137 -0
  52. package/dist/cli/reratify.js.map +1 -0
  53. package/dist/cli/skillCheck.d.ts +6 -0
  54. package/dist/cli/skillCheck.js +46 -0
  55. package/dist/cli/skillCheck.js.map +1 -1
  56. package/dist/cli/skillDirs.d.ts +15 -0
  57. package/dist/cli/skillDirs.js +34 -0
  58. package/dist/cli/skillDirs.js.map +1 -0
  59. package/dist/cli/skillSync.d.ts +10 -0
  60. package/dist/cli/skillSync.js +15 -0
  61. package/dist/cli/skillSync.js.map +1 -1
  62. package/dist/cli/sliceIndex.d.ts +3 -0
  63. package/dist/cli/sliceIndex.js +6 -2
  64. package/dist/cli/sliceIndex.js.map +1 -1
  65. package/dist/cli/sliceLink.d.ts +52 -0
  66. package/dist/cli/sliceLink.js +152 -0
  67. package/dist/cli/sliceLink.js.map +1 -0
  68. package/dist/cli/status.d.ts +261 -0
  69. package/dist/cli/status.js +536 -0
  70. package/dist/cli/status.js.map +1 -0
  71. package/dist/cli/usageLog.d.ts +75 -0
  72. package/dist/cli/usageLog.js +193 -0
  73. package/dist/cli/usageLog.js.map +1 -0
  74. package/dist/cli.js +501 -130
  75. package/dist/cli.js.map +1 -1
  76. package/dist/emit/diffJson.d.ts +9 -1
  77. package/dist/emit/diffJson.js +44 -1
  78. package/dist/emit/diffJson.js.map +1 -1
  79. package/dist/emit/freshnessJson.d.ts +6 -0
  80. package/dist/emit/freshnessJson.js +24 -0
  81. package/dist/emit/freshnessJson.js.map +1 -0
  82. package/dist/emit/json.d.ts +67 -8
  83. package/dist/emit/json.js +19 -3
  84. package/dist/emit/json.js.map +1 -1
  85. package/dist/emit/statusJson.d.ts +7 -0
  86. package/dist/emit/statusJson.js +39 -0
  87. package/dist/emit/statusJson.js.map +1 -0
  88. package/dist/emit/typespec.d.ts +26 -0
  89. package/dist/emit/typespec.js +356 -0
  90. package/dist/emit/typespec.js.map +1 -0
  91. package/dist/emit/usageReportJson.d.ts +3 -0
  92. package/dist/emit/usageReportJson.js +23 -0
  93. package/dist/emit/usageReportJson.js.map +1 -0
  94. package/dist/mcp/server.d.ts +1 -1
  95. package/dist/mcp/server.js +301 -11
  96. package/dist/mcp/server.js.map +1 -1
  97. package/dist/model/rules.d.ts +13 -0
  98. package/dist/model/rules.js +20 -0
  99. package/dist/model/rules.js.map +1 -1
  100. package/dist/model/validate.js +9 -1
  101. package/dist/model/validate.js.map +1 -1
  102. package/dist/parser/ast.d.ts +6 -0
  103. package/dist/parser/parser.js +20 -6
  104. package/dist/parser/parser.js.map +1 -1
  105. package/dist/render/drawNotes.d.ts +11 -1
  106. package/dist/render/drawNotes.js +20 -2
  107. package/dist/render/drawNotes.js.map +1 -1
  108. package/dist/render/render.js +31 -6
  109. package/dist/render/render.js.map +1 -1
  110. package/dist/render/serve.js +4 -0
  111. package/dist/render/serve.js.map +1 -1
  112. package/dist/render/sliceOverlay.d.ts +7 -2
  113. package/dist/render/sliceOverlay.js +19 -7
  114. package/dist/render/sliceOverlay.js.map +1 -1
  115. package/dist/render/sliceStatus.d.ts +7 -3
  116. package/dist/render/sliceStatus.js +21 -14
  117. package/dist/render/sliceStatus.js.map +1 -1
  118. package/dist/render/viewerHtml.js +1 -1
  119. package/dist/render/viewerHtml.js.map +1 -1
  120. package/dist/templates.d.ts +2 -2
  121. package/dist/templates.js +5 -5
  122. package/dist/util/markers.d.ts +16 -4
  123. package/dist/util/markers.js +23 -10
  124. package/dist/util/markers.js.map +1 -1
  125. package/package.json +2 -1
  126. /package/.claude/skills/{event-modeling → event-modeling-shared}/templates/conformance-report.md +0 -0
  127. /package/.claude/skills/{event-modeling → event-modeling-shared}/templates/state.md +0 -0
@@ -0,0 +1,261 @@
1
+ import { NormalizedModel } from "../model/model.js";
2
+ import { RefsResult } from "../model/refs.js";
3
+ import { DocReason } from "../catalog/docJoin.js";
4
+ import { DriftSignalKind } from "../catalog/driftSignal.js";
5
+ import { Diagnostic } from "../model/validate.js";
6
+ import { CoverageReport } from "./coverage.js";
7
+ import { GitRunner } from "./diff-inputs.js";
8
+ import { SliceDocFacts } from "./conformScope.js";
9
+ /** The 4 canonical slice-doc lifecycle statuses (docs/slice-doc-schema.md) — the same enum
10
+ * `em catalog`'s header coloring and `em render`'s status legend already recognize. */
11
+ export declare const CANONICAL_STATUSES: readonly ["draft", "reviewed", "ready-to-implement", "implemented"];
12
+ export type CanonicalStatus = (typeof CANONICAL_STATUSES)[number];
13
+ /** Bucket a slice's lifecycle status falls into for the rollup: one of the 4 canonical values,
14
+ * `"no-doc"` (no doc bound at all, or the binding names a missing file — `resolveSliceDocJoin`'s
15
+ * `found: false`), `"frontmatter-invalid"` (a doc WAS found — a note binds it — but its
16
+ * frontmatter is missing or malformed, so nothing reliable can be read from it; kept distinct
17
+ * from `"no-doc"` because "nothing was ever referenced" and "something's referenced but broken"
18
+ * are different states worth telling apart in a rollup), or `"unknown"` (a doc was found and its
19
+ * frontmatter usable, but `status` isn't one of the 4 canonical strings — a freeform doc,
20
+ * matching `em slice index`'s own "unknown" convention). */
21
+ export type StatusBucket = CanonicalStatus | "no-doc" | "frontmatter-invalid" | "unknown";
22
+ export declare function classifyStatusBucket(found: boolean, reason: DocReason, status: string | null): StatusBucket;
23
+ /** One slice's status-rollup facts, joined from the same doc read every doc-aware command
24
+ * shares — never a second parse of the model or the doc. */
25
+ export interface SliceStatusFact {
26
+ file: string;
27
+ key: string;
28
+ docFound: boolean;
29
+ docReason: DocReason;
30
+ /** Resolved absolute path to the bound doc file, or null when none was found. Two slices can
31
+ * legitimately resolve to the SAME doc (MIL-121 `covers:` cross-binding, one doc ratifying
32
+ * coverage for several slices) — this is how `buildStatusReport` dedupes doc-body-derived
33
+ * counts (Open Questions) so a shared doc's single unresolved question isn't counted once per
34
+ * covered slice. */
35
+ docPath: string | null;
36
+ rawStatus: string | null;
37
+ /** The doc's own `implementedIn:` value verbatim (or null) — carried through from the same
38
+ * `resolveSliceDocJoin` call this fact set already makes, so `resolveSlicePRsBehindHead`
39
+ * (MIL-164) can build its `SliceDocFacts[]` input from these facts directly rather than
40
+ * joining every slice's doc a second time. */
41
+ implementedIn: string | null;
42
+ /** MIL-171: the doc's own `owner:` value verbatim (or null) — carried through from the same
43
+ * `resolveSliceDocJoin` call this fact set already makes, so a per-slice owner rollup
44
+ * (`StatusReport.owners`) never needs a second doc join. */
45
+ owner: string | null;
46
+ bucket: StatusBucket;
47
+ driftSignal: DriftSignalKind | null;
48
+ openQuestionsTotal: number;
49
+ openQuestionsUnchecked: number;
50
+ }
51
+ export interface SliceStatusFactsResult {
52
+ facts: SliceStatusFact[];
53
+ /** Doc-join diagnostics (`binding-missing-file`/`frontmatter-invalid` warnings) raised while
54
+ * resolving each slice's doc — the same diagnostics `em export`'s doc join raises. Carried
55
+ * back rather than dropped: a state-of-the-system report shouldn't silently swallow "this
56
+ * slice's doc reference is broken." */
57
+ diagnostics: Diagnostic[];
58
+ }
59
+ /**
60
+ * Resolve every slice's status-rollup facts for one already-compiled model. `baseDir` is the
61
+ * `.em` file's directory, same doc-resolution convention every other doc-aware command uses.
62
+ * Open Questions counts are read from the slice's OWN bound doc (re-deriving the key from
63
+ * `doc.path`, not assuming it's this slice's own — MIL-121 cross-binding can resolve to a
64
+ * different slice's doc, same re-derivation `em coverage`/`--slice-ready` use) rather than a
65
+ * second independent parse.
66
+ */
67
+ export declare function resolveSliceStatusFacts(file: string, model: NormalizedModel, refs: RefsResult, baseDir: string): SliceStatusFactsResult;
68
+ /** Open `issue "text"` markers in a model — the same predicate `em validate --list-issues`
69
+ * counts, here reduced to a bare count for the rollup. */
70
+ export declare function countOpenIssues(model: NormalizedModel): number;
71
+ export interface ConformanceEntry {
72
+ file: string;
73
+ modelDir: string;
74
+ hasStateFile: boolean;
75
+ lastConformance: {
76
+ date: string;
77
+ revision: string;
78
+ } | null;
79
+ /** The repo `commitsBehindHead` was computed in — `--repo` when given, else the model's own
80
+ * directory (works out of the box for a single-repo project; conform-scope's `--repo`
81
+ * convention still applies for a model whose implementation lives in a different repo). */
82
+ repo: string;
83
+ commitsBehindHead: number | null;
84
+ /** Slices whose bound doc's `implementedIn:` maps to a path changed since `lastConformance`'s
85
+ * revision (MIL-164) — the same `candidateSlices` computation `em conform-scope` makes for
86
+ * one model at a time (`conformScope.ts`'s `changedPathsSince` + `buildConformScope`), rolled
87
+ * up here to a single count: "how many slices likely shipped code since the last conform
88
+ * sweep." Each candidate slice typically corresponds to one merged slice PR, hence the name.
89
+ * Null under the same conditions `commitsBehindHead` is null — it needs the same revision to
90
+ * diff against, and by construction is only ever null when `error` is also set (see
91
+ * `resolveConformanceEntry` below): a bare "opted out of computing this" state doesn't occur
92
+ * on the real CLI/MCP call paths, which always supply `sliceDocFacts`. */
93
+ slicePRsBehindHead: number | null;
94
+ /** Set when the state file exists and parses, but git couldn't answer commits-behind-HEAD or
95
+ * slice-PRs-behind-HEAD (not a git repo, unknown revision, ...) — reported per-model rather
96
+ * than aborting the whole rollup, since `em status` is a soft report, not a gate. Also carries
97
+ * a state-file parse failure (unparseable `Last conformance:` bullet), same non-fatal
98
+ * treatment. */
99
+ error: string | null;
100
+ }
101
+ /**
102
+ * `git rev-list --count <revision>..HEAD` in `repo` (any directory inside it, not necessarily
103
+ * its root — same "anchor dir, resolve toplevel" convention `conformScope.ts`'s
104
+ * `changedPathsSince` uses). The git runner is injectable so every failure branch is
105
+ * unit-testable without a real repository.
106
+ */
107
+ export declare function commitsBehindHead(repo: string, revision: string, runGit?: GitRunner): {
108
+ ok: true;
109
+ count: number;
110
+ } | {
111
+ ok: false;
112
+ message: string;
113
+ };
114
+ /**
115
+ * `M` in "N commits and M slice-PRs behind HEAD" (MIL-164) — how many slices whose doc's
116
+ * `implementedIn:` names a path this model's target repo changed since `revision`. Reuses the
117
+ * exact `em conform-scope` machinery for one model at a time: `changedPathsSince` (the same
118
+ * `git diff --name-only <revision>..HEAD` walk, same injectable `GitRunner`) to get the changed
119
+ * paths, then `buildConformScope`'s own `implementedIn`-prefix matching (never fuzzy, never a
120
+ * second guess) to turn them into a candidate-slice count. `full` is always `false` here — this
121
+ * is only ever called once `lastConformance` is known non-null (see `resolveConformanceEntry`
122
+ * below), so there is always a revision to diff against.
123
+ */
124
+ export declare function resolveSlicePRsBehindHead(repo: string, revision: string, slices: SliceDocFacts[], runGit?: GitRunner): {
125
+ ok: true;
126
+ count: number;
127
+ } | {
128
+ ok: false;
129
+ message: string;
130
+ };
131
+ /**
132
+ * Resolve one model's conformance entry: read its sibling state file (if any — not every model
133
+ * has reached the `conform` phase, so a missing state file is routine, not an error), then
134
+ * compute commits-behind-HEAD and slice-PRs-behind-HEAD (MIL-164) when `Last conformance:` is
135
+ * set. `repoOverride` is `--repo`; omitted, each model's own directory is used as the repo to
136
+ * walk (the common single-repo project case — see `repo` field doc above). `sliceDocFacts` is
137
+ * THIS model's own slice facts (`key`/`status`/`implementedIn`) — the caller's responsibility to
138
+ * scope correctly per file, since `resolveSlicePRsBehindHead` matches against exactly this
139
+ * model's slices, not some other input model's.
140
+ *
141
+ * A state file is shared by every `.em` file in its directory (`.event-modeling.md` has no
142
+ * per-model namespacing), but its `Model file:` bullet names exactly ONE of them — so a sibling
143
+ * file it does NOT describe (the common case: a `conform-scope --seed-asis` scratch copy like
144
+ * `checkout-asis.em` sitting next to `checkout.em`) must not inherit `checkout.em`'s conformance
145
+ * record just because it lives in the same directory. When `Model file:` is set and doesn't match
146
+ * `basename(file)`, the record is reported as unattributed (via `error`, the same non-fatal
147
+ * channel a git failure uses) rather than silently misattributed.
148
+ */
149
+ export declare function resolveConformanceEntry(file: string, repoOverride: string | undefined, sliceDocFacts: SliceDocFacts[], runGit?: GitRunner): ConformanceEntry;
150
+ export interface StatusSliceCounts {
151
+ total: number;
152
+ byStatus: {
153
+ draft: number;
154
+ reviewed: number;
155
+ readyToImplement: number;
156
+ implemented: number;
157
+ noDoc: number;
158
+ /** A doc IS bound (a `note` names it) but its frontmatter is missing/malformed — see
159
+ * `StatusBucket`'s `"frontmatter-invalid"` doc comment. Kept apart from `noDoc` (nothing
160
+ * bound at all) and `unknown` (bound, usable, just a freeform `status` value), and always
161
+ * equal to `driftSignal.frontmatterInvalid` below — same slices, two dimensions. */
162
+ frontmatterInvalid: number;
163
+ unknown: number;
164
+ };
165
+ }
166
+ export interface StatusDriftCounts {
167
+ inSync: number;
168
+ neverImplemented: number;
169
+ unpropagatedDelta: number;
170
+ implementedWithoutLink: number;
171
+ /** Slices with no doc bound at all (or a binding naming a missing file) — driftSignal is null
172
+ * because there's nothing to classify. Distinct from `frontmatterInvalid` below: THIS bucket
173
+ * is `resolveSliceDocJoin`'s `found: false`, in either dimension. */
174
+ notApplicable: number;
175
+ /** A doc IS bound and found (`found: true`) but its frontmatter is missing/malformed, so
176
+ * `driftSignal` couldn't be classified — always equal to `slices.byStatus.frontmatterInvalid`
177
+ * (same slices). Kept apart from `notApplicable` so "nothing was ever referenced" and
178
+ * "something's referenced but broken" don't collapse into one ambiguous bucket (a doc that
179
+ * IS found shouldn't tally the same as one that plain doesn't exist). */
180
+ frontmatterInvalid: number;
181
+ }
182
+ export interface StatusInvariantTotals {
183
+ testsDir: string;
184
+ total: number;
185
+ cited: number;
186
+ uncovered: number;
187
+ }
188
+ export interface StatusIssueTotals {
189
+ openIssues: number;
190
+ openQuestionsTotal: number;
191
+ openQuestionsUnchecked: number;
192
+ }
193
+ /** One doc-join diagnostic, tagged with the input file it came from — `em status` can aggregate
194
+ * several models in one run, so (unlike `em export`'s single-model diagnostics) each entry
195
+ * needs to say which file it concerns. */
196
+ export type StatusDiagnostic = {
197
+ file: string;
198
+ } & Diagnostic;
199
+ /** MIL-171: one slice's owner fact — the per-slice detail this ticket asked `em status` to
200
+ * surface, kept deliberately minimal (no other fact duplicated here that `slices`/`diagnostics`
201
+ * already carry elsewhere in the report). `file`+`key` identify the slice the same way
202
+ * `StatusDiagnostic`'s `file` tags a diagnostic to its model; `owner` is the doc's own `owner:`
203
+ * verbatim, null when absent OR when no doc was found at all — same "null when absent"
204
+ * convention `em export`'s doc join uses. Listed once per slice, never deduped: two slices
205
+ * legitimately sharing one doc (MIL-121 `covers:`) also legitimately share the same owner. */
206
+ export interface StatusOwnerEntry {
207
+ file: string;
208
+ key: string;
209
+ owner: string | null;
210
+ }
211
+ export interface StatusReport {
212
+ files: string[];
213
+ slices: StatusSliceCounts;
214
+ driftSignal: StatusDriftCounts;
215
+ /** Null when `--tests <dir>` wasn't given — invariant coverage is opt-in (it needs a test
216
+ * tree to scan), unlike every other rollup dimension, which is always computable from the
217
+ * model(s) alone. */
218
+ invariants: StatusInvariantTotals | null;
219
+ issues: StatusIssueTotals;
220
+ conformance: ConformanceEntry[];
221
+ /** Doc-join diagnostics (`binding-missing-file`/`frontmatter-invalid` warnings) collected
222
+ * while resolving every slice's doc, across every input file — carried here rather than
223
+ * discarded, so a state-of-the-system report doesn't hide a broken doc reference just
224
+ * because it also folded that slice into `frontmatterInvalid`/`noDoc` above. */
225
+ diagnostics: StatusDiagnostic[];
226
+ /** MIL-171: per-slice owner facts, one entry per slice across every input file — see
227
+ * `StatusOwnerEntry`. */
228
+ owners: StatusOwnerEntry[];
229
+ }
230
+ /** Aggregate everything `em status` reports into one `StatusReport` — pure, no I/O. Callers
231
+ * (the CLI action, the MCP tool) resolve every input first (compile each model, join every
232
+ * slice's doc, scan the test tree once, resolve conformance) and hand the results here. */
233
+ export declare function buildStatusReport(files: string[], sliceFacts: SliceStatusFact[], openIssuesCount: number, invariants: StatusInvariantTotals | null, conformance: ConformanceEntry[], diagnostics: StatusDiagnostic[]): StatusReport;
234
+ /** Sum per-model `CoverageReport`s (see `./coverage.ts`) into one `StatusInvariantTotals` —
235
+ * `em status` doesn't need the per-slice/per-ID detail `em coverage --json` carries, just the
236
+ * totals, across however many models `--tests <dir>` was scanned against. */
237
+ export declare function aggregateInvariantTotals(testsDir: string, reports: CoverageReport[]): StatusInvariantTotals;
238
+ /** Exported for `em freshness` (freshness.ts, MIL-164) — the standalone surface for exactly
239
+ * this one clause, without pulling in the rest of `em status`'s rollup. */
240
+ export declare function formatConformancePart(entry: ConformanceEntry): string;
241
+ /** The one-line rollup: `"8/8 implemented · 20/20 invariants covered · 0 open issues · last
242
+ * conformed <rev>, N commits behind HEAD"` (MIL-163's acceptance line). For multiple input
243
+ * models, the conformance clause reports the FIRST file's entry — a single-file invocation is
244
+ * the common case this line is written for; the full per-model breakdown is always in
245
+ * `formatStatusDetail`/the JSON document regardless of file count. */
246
+ export declare function formatStatusSummary(report: StatusReport): string;
247
+ /** The detail block below the summary line: one line per rollup dimension, plus one line per
248
+ * model's conformance entry. */
249
+ export declare function formatStatusDetail(report: StatusReport): string;
250
+ /** Full text report: the summary line, a blank line, then the detail block — same
251
+ * "rollup line, then detail" shape `em diff`'s text report uses. */
252
+ export declare function formatStatusText(report: StatusReport): string;
253
+ /** A markdown block suited for pasting into a README (MIL-163's `--md`) — a small table,
254
+ * same spirit as `em slice index`'s GENERATED Slices table, but not marker-managed: `--md`
255
+ * just prints the block, leaving where/whether to embed it to the caller. */
256
+ export declare function formatStatusMarkdown(report: StatusReport): string;
257
+ /** Render one flat-style SVG badge — two colored rects (label, message) plus centered text,
258
+ * no external fonts/images/scripts, so it renders identically anywhere an SVG does. */
259
+ export declare function renderBadgeSvg(label: string, message: string, color: string): string;
260
+ /** Build the `em status --badge` SVG document. */
261
+ export declare function buildStatusBadge(report: StatusReport): string;