@milehimikey/em 1.8.1 → 1.9.1

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 (105) 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 +40 -14
  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 +115 -83
  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 +150 -0
  13. package/.claude/skills/event-modeling-shared/reference/slice-doc-schema.md +381 -0
  14. package/.claude/skills/{event-modeling → event-modeling-shared}/templates/model-readme.md +2 -2
  15. package/.claude/skills/{event-modeling → event-modeling-shared}/templates/slice.md +57 -14
  16. package/README.md +24 -4
  17. package/dist/catalog/build.js +9 -0
  18. package/dist/catalog/build.js.map +1 -1
  19. package/dist/catalog/docJoin.d.ts +15 -0
  20. package/dist/catalog/docJoin.js +8 -0
  21. package/dist/catalog/docJoin.js.map +1 -1
  22. package/dist/catalog/modelCollisionValidate.d.ts +22 -0
  23. package/dist/catalog/modelCollisionValidate.js +67 -0
  24. package/dist/catalog/modelCollisionValidate.js.map +1 -0
  25. package/dist/catalog/orphanedSliceDocValidate.d.ts +11 -0
  26. package/dist/catalog/orphanedSliceDocValidate.js +98 -0
  27. package/dist/catalog/orphanedSliceDocValidate.js.map +1 -0
  28. package/dist/catalog/sliceDoc.d.ts +15 -0
  29. package/dist/catalog/sliceDoc.js +18 -0
  30. package/dist/catalog/sliceDoc.js.map +1 -1
  31. package/dist/cli/changelogBuild.d.ts +12 -0
  32. package/dist/cli/changelogBuild.js +89 -0
  33. package/dist/cli/changelogBuild.js.map +1 -0
  34. package/dist/cli/ciInit.d.ts +42 -0
  35. package/dist/cli/ciInit.js +298 -0
  36. package/dist/cli/ciInit.js.map +1 -0
  37. package/dist/cli/conformSupersede.d.ts +32 -0
  38. package/dist/cli/conformSupersede.js +102 -0
  39. package/dist/cli/conformSupersede.js.map +1 -0
  40. package/dist/cli/coverage.d.ts +6 -1
  41. package/dist/cli/coverage.js +28 -3
  42. package/dist/cli/coverage.js.map +1 -1
  43. package/dist/cli/frontmatterSurgery.d.ts +28 -0
  44. package/dist/cli/frontmatterSurgery.js +66 -0
  45. package/dist/cli/frontmatterSurgery.js.map +1 -0
  46. package/dist/cli/markImplemented.js +6 -45
  47. package/dist/cli/markImplemented.js.map +1 -1
  48. package/dist/cli/ratify.d.ts +41 -0
  49. package/dist/cli/ratify.js +151 -0
  50. package/dist/cli/ratify.js.map +1 -0
  51. package/dist/cli/reratify.d.ts +33 -0
  52. package/dist/cli/reratify.js +137 -0
  53. package/dist/cli/reratify.js.map +1 -0
  54. package/dist/cli/skillCheck.d.ts +6 -0
  55. package/dist/cli/skillCheck.js +46 -0
  56. package/dist/cli/skillCheck.js.map +1 -1
  57. package/dist/cli/skillDirs.d.ts +15 -0
  58. package/dist/cli/skillDirs.js +34 -0
  59. package/dist/cli/skillDirs.js.map +1 -0
  60. package/dist/cli/skillSync.d.ts +10 -0
  61. package/dist/cli/skillSync.js +15 -0
  62. package/dist/cli/skillSync.js.map +1 -1
  63. package/dist/cli/sliceIndex.d.ts +3 -0
  64. package/dist/cli/sliceIndex.js +6 -2
  65. package/dist/cli/sliceIndex.js.map +1 -1
  66. package/dist/cli/sliceLink.d.ts +52 -0
  67. package/dist/cli/sliceLink.js +152 -0
  68. package/dist/cli/sliceLink.js.map +1 -0
  69. package/dist/cli/status.d.ts +261 -0
  70. package/dist/cli/status.js +536 -0
  71. package/dist/cli/status.js.map +1 -0
  72. package/dist/cli/usageLog.d.ts +75 -0
  73. package/dist/cli/usageLog.js +193 -0
  74. package/dist/cli/usageLog.js.map +1 -0
  75. package/dist/cli.js +503 -132
  76. package/dist/cli.js.map +1 -1
  77. package/dist/emit/freshnessJson.d.ts +6 -0
  78. package/dist/emit/freshnessJson.js +24 -0
  79. package/dist/emit/freshnessJson.js.map +1 -0
  80. package/dist/emit/json.d.ts +62 -8
  81. package/dist/emit/json.js +14 -3
  82. package/dist/emit/json.js.map +1 -1
  83. package/dist/emit/statusJson.d.ts +7 -0
  84. package/dist/emit/statusJson.js +39 -0
  85. package/dist/emit/statusJson.js.map +1 -0
  86. package/dist/emit/typespec.d.ts +26 -0
  87. package/dist/emit/typespec.js +356 -0
  88. package/dist/emit/typespec.js.map +1 -0
  89. package/dist/emit/usageReportJson.d.ts +3 -0
  90. package/dist/emit/usageReportJson.js +23 -0
  91. package/dist/emit/usageReportJson.js.map +1 -0
  92. package/dist/mcp/server.d.ts +1 -1
  93. package/dist/mcp/server.js +301 -11
  94. package/dist/mcp/server.js.map +1 -1
  95. package/dist/model/rules.d.ts +13 -0
  96. package/dist/model/rules.js +20 -0
  97. package/dist/model/rules.js.map +1 -1
  98. package/dist/templates.d.ts +1 -1
  99. package/dist/templates.js +2 -2
  100. package/dist/util/markers.d.ts +16 -4
  101. package/dist/util/markers.js +23 -10
  102. package/dist/util/markers.js.map +1 -1
  103. package/package.json +2 -1
  104. /package/.claude/skills/{event-modeling → event-modeling-shared}/templates/conformance-report.md +0 -0
  105. /package/.claude/skills/{event-modeling → event-modeling-shared}/templates/state.md +0 -0
@@ -49,6 +49,21 @@ export interface SliceDocExport {
49
49
  * `version` above from the same doc parse — a finding built from `driftSignal` should always
50
50
  * cite `version` alongside it, never cache one without the other. */
51
51
  driftSignal: DriftSignalKind | null;
52
+ /** MIL-165: who ratified this doc's current `status`/`version` (frontmatter `ratifiedBy:`),
53
+ * written only by `em slice ratify` — null when absent (a doc predating this feature, or
54
+ * ratified by hand before it existed). */
55
+ ratifiedBy: string | null;
56
+ /** MIL-165: when this doc was ratified (frontmatter `ratifiedOn:`, `YYYY-MM-DD`), written only
57
+ * by `em slice ratify` — null when absent, same as `ratifiedBy`. */
58
+ ratifiedOn: string | null;
59
+ /** MIL-171: who (a person or team) holds this slice, from frontmatter `owner:` — hand-filled,
60
+ * no `em` command writes it. Null when absent. */
61
+ owner: string | null;
62
+ /** MIL-171: a URL into an external tracker mirroring this slice, from frontmatter `tracking:`
63
+ * — hand-filled, no `em` command writes it. Null when absent. This is the exact field
64
+ * em-tracker-bridge reads to find the mirrored ticket — its name/shape here is a cross-tool
65
+ * contract, not just an internal display field. */
66
+ tracking: string | null;
52
67
  }
53
68
  export interface SliceDocJoinResult {
54
69
  doc: SliceDocExport;
@@ -66,6 +66,10 @@ const EMPTY_CONTENT = {
66
66
  mergedFrom: [],
67
67
  supersededBy: [],
68
68
  driftSignal: null,
69
+ ratifiedBy: null,
70
+ ratifiedOn: null,
71
+ owner: null,
72
+ tracking: null,
69
73
  };
70
74
  /**
71
75
  * Resolve one slice's doc join. `baseDir` is the `.em` file's directory (doc paths, like note
@@ -150,6 +154,10 @@ function foundDoc(path, parsed) {
150
154
  mergedFrom: parsed.mergedFrom,
151
155
  supersededBy: parsed.supersededBy,
152
156
  driftSignal: classifyImplementationDrift(parsed),
157
+ ratifiedBy: parsed.ratifiedBy,
158
+ ratifiedOn: parsed.ratifiedOn,
159
+ owner: parsed.owner,
160
+ tracking: parsed.tracking,
153
161
  };
154
162
  }
155
163
  //# sourceMappingURL=docJoin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"docJoin.js","sourceRoot":"","sources":["../../src/catalog/docJoin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"docJoin.js","sourceRoot":"","sources":["../../src/catalog/docJoin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { Diagnostic } from "../model/validate.js";
2
+ export interface ModelSliceKeys {
3
+ /** The `.em` file as given on the command line — same identity every other multi-model
4
+ * diagnostic (StatusDiagnostic, CatalogBuildResult.diagnostics) tags itself with. */
5
+ file: string;
6
+ /** This model's own compiled slice export keys, same order/index as `computeRefs()`'s
7
+ * `sliceKeys` — duplicates already deduped with a `~2` suffix by computeRefs() itself, so a
8
+ * key here is always a real, single doc path this model expects to read/write. */
9
+ sliceKeys: string[];
10
+ }
11
+ /**
12
+ * Detect colliding `slices/<key>.md` doc paths across `models`: any two files whose resolved
13
+ * base directory (`dirname(file)`, absolute so `./a.em` and `a.em` from the same cwd count as
14
+ * the same directory) is identical AND who share at least one slice export key. One diagnostic
15
+ * per colliding key, attributed to the SECOND model to use that key in file-list order — same
16
+ * "first wins, the later one gets flagged" convention `computeRefs()`'s own `duplicate-slice-name`
17
+ * diagnostic uses, so a collision reads as "this model's key collides with an earlier one," not
18
+ * the reverse. A model list of 0 or 1 files (or where every file resolves to a distinct
19
+ * directory) always returns `[]` — the ordinary single-model-per-directory case this function
20
+ * exists to leave alone.
21
+ */
22
+ export declare function detectSliceDocCollisions(models: ModelSliceKeys[]): Diagnostic[];
@@ -0,0 +1,67 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Cross-model slice-doc collision detection (MIL-160). readSliceDoc.ts resolves every slice doc
3
+ // at `<dirname(modelFile)>/slices/<sliceKey>.md` — safe as long as every model owns its own
4
+ // directory (the documented convention, docs/cli.md "Multi-model projects"), since computeRefs()
5
+ // only dedupes a slice key against the OTHER slices in the SAME model's compile
6
+ // (src/model/refs.ts). Two sibling `.em` files sharing a directory, each producing a slice
7
+ // keyed e.g. "checkout", would both resolve to the same `slices/checkout.md` — silently: neither
8
+ // model's compile ever sees the other, so nothing raises a diagnostic today. This is the one
9
+ // check that does: given every input model's file path and its own compiled slice keys, group by
10
+ // resolved base directory and flag any key more than one model in the same group produces.
11
+ //
12
+ // The only cross-model rule in the codebase — every other rule in model/rules.ts is a
13
+ // single-model concern raised from inside one compile. Deliberately NOT part of
14
+ // model/validate.ts's pipeline (which only ever sees one model at a time); instead wired
15
+ // directly into the two commands that ever compile more than one model in the same run
16
+ // (`em status` in src/cli.ts, `em catalog` in src/catalog/build.ts) — the only places that
17
+ // could possibly witness a collision. Pure — no fs — the compiled `sliceKeys` are handed in by
18
+ // the caller, already computed by the same computeRefs() call the caller made anyway.
19
+ import { dirname, resolve } from "node:path";
20
+ import { makeDiag } from "../model/rules.js";
21
+ /**
22
+ * Detect colliding `slices/<key>.md` doc paths across `models`: any two files whose resolved
23
+ * base directory (`dirname(file)`, absolute so `./a.em` and `a.em` from the same cwd count as
24
+ * the same directory) is identical AND who share at least one slice export key. One diagnostic
25
+ * per colliding key, attributed to the SECOND model to use that key in file-list order — same
26
+ * "first wins, the later one gets flagged" convention `computeRefs()`'s own `duplicate-slice-name`
27
+ * diagnostic uses, so a collision reads as "this model's key collides with an earlier one," not
28
+ * the reverse. A model list of 0 or 1 files (or where every file resolves to a distinct
29
+ * directory) always returns `[]` — the ordinary single-model-per-directory case this function
30
+ * exists to leave alone.
31
+ */
32
+ export function detectSliceDocCollisions(models) {
33
+ const diagnostics = [];
34
+ const byDir = new Map();
35
+ for (const m of models) {
36
+ const dir = resolve(dirname(m.file));
37
+ const bucket = byDir.get(dir);
38
+ if (bucket)
39
+ bucket.push(m);
40
+ else
41
+ byDir.set(dir, [m]);
42
+ }
43
+ for (const bucket of byDir.values()) {
44
+ if (bucket.length < 2)
45
+ continue; // only one model in this directory — no collision possible
46
+ const firstFileForKey = new Map();
47
+ for (const m of bucket) {
48
+ for (const key of m.sliceKeys) {
49
+ const earlier = firstFileForKey.get(key);
50
+ if (earlier === undefined) {
51
+ firstFileForKey.set(key, m.file);
52
+ continue;
53
+ }
54
+ if (earlier === m.file)
55
+ continue; // same model listed twice on the command line
56
+ diagnostics.push(makeDiag("cross-model-slice-doc-collision", {
57
+ message: `"${m.file}" and "${earlier}" share a directory and both produce slice key "${key}" — ` +
58
+ `both would read/write "slices/${key}.md"; give each model its own directory ` +
59
+ `(see docs/cli.md, "Multi-model projects")`,
60
+ refs: [key, earlier, m.file],
61
+ }));
62
+ }
63
+ }
64
+ }
65
+ return diagnostics;
66
+ }
67
+ //# sourceMappingURL=modelCollisionValidate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modelCollisionValidate.js","sourceRoot":"","sources":["../../src/catalog/modelCollisionValidate.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,gGAAgG;AAChG,4FAA4F;AAC5F,iGAAiG;AACjG,gFAAgF;AAChF,2FAA2F;AAC3F,iGAAiG;AACjG,6FAA6F;AAC7F,iGAAiG;AACjG,2FAA2F;AAC3F,EAAE;AACF,sFAAsF;AACtF,gFAAgF;AAChF,yFAAyF;AACzF,uFAAuF;AACvF,2FAA2F;AAC3F,+FAA+F;AAC/F,sFAAsF;AAEtF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAY7C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,wBAAwB,CAAC,MAAwB;IAC/D,MAAM,WAAW,GAAiB,EAAE,CAAC;IACrC,MAAM,KAAK,GAAG,IAAI,GAAG,EAA4B,CAAC;IAClD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACrC,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;;YACtB,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;QACpC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS,CAAC,2DAA2D;QAC5F,MAAM,eAAe,GAAG,IAAI,GAAG,EAAkB,CAAC;QAClD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;gBAC9B,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACzC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;oBAC1B,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;oBACjC,SAAS;gBACX,CAAC;gBACD,IAAI,OAAO,KAAK,CAAC,CAAC,IAAI;oBAAE,SAAS,CAAC,8CAA8C;gBAChF,WAAW,CAAC,IAAI,CACd,QAAQ,CAAC,iCAAiC,EAAE;oBAC1C,OAAO,EACL,IAAI,CAAC,CAAC,IAAI,UAAU,OAAO,mDAAmD,GAAG,MAAM;wBACvF,iCAAiC,GAAG,0CAA0C;wBAC9E,2CAA2C;oBAC7C,IAAI,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC;iBAC7B,CAAC,CACH,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { NormalizedModel } from "../model/model.js";
2
+ import { RefsResult } from "../model/refs.js";
3
+ import { Diagnostic } from "../model/validate.js";
4
+ /**
5
+ * Scan `<baseDir>/slices/` for a doc file that no current slice's own key names by filename
6
+ * convention, and whose `covers:` list (if any — MIL-121) doesn't ratify a current slice either.
7
+ * `baseDir` is the `.em` file's directory, same convention every other doc/note path in em uses.
8
+ * Returns `[]` when `slices/` doesn't exist at all — nothing to a scan with no directory to walk,
9
+ * the ordinary state for a model that hasn't authored any slice docs yet.
10
+ */
11
+ export declare function validateOrphanedSliceDocs(_model: NormalizedModel, refs: RefsResult, baseDir: string): Diagnostic[];
@@ -0,0 +1,98 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // `em validate`'s fifth fs-aware rule (MIL-183, the fragility half of GH #128): a slice doc left
3
+ // behind in `slices/` after its slice is renamed or removed used to just quietly stop applying —
4
+ // nothing ever pointed at the ORPHANED FILE itself. Same fs-aware-sibling shape as
5
+ // catalog/lineageValidate.ts (MIL-84), catalog/frontmatterCoherenceValidate.ts (MIL-85),
6
+ // catalog/noteBindingValidate.ts (MIL-126), and catalog/docModelConsistencyValidate.ts (MIL-124):
7
+ // a module next to model/validate.ts, not folded into it, because it needs `baseDir`/fs access
8
+ // the rest of validate deliberately never touches. Distinct from all four of those, though, in
9
+ // which direction it walks: every one of them starts from a *slice* and asks "is its doc/note
10
+ // okay?" — this is the only rule that instead walks the filesystem and asks the opposite
11
+ // direction, "does every file out there still belong to something?"
12
+ //
13
+ // Two doc-join mechanisms coexist in this codebase (docJoin.ts's own header comment spells out
14
+ // the same split): `docJoin.ts`'s `resolveSliceDocJoin`, gated on an explicit
15
+ // `note "slices/<key>.md"` binding, drives `em export`/`em status`/the MCP tools; `em catalog`
16
+ // (catalog/build.ts) instead reads `slices/<sliceKey>.md` by BARE FILENAME CONVENTION, ignoring
17
+ // `note` entirely — a standing, deliberately-kept-separate, tested invariant (see build.ts's own
18
+ // header comment and test/catalog.e2e.test.ts). The GH #128 reporter's "matched by name, silently
19
+ // stops applying" experience is build.ts's convention path, not docJoin's note-gated one — status
20
+ // coloring on the diagram comes from whether a file happens to sit at the right name, full stop.
21
+ // So "orphaned" here is judged the same name-convention way build.ts resolves a doc: by filename
22
+ // key (and, for a MIL-121 covering doc, by its `covers:` list), never by whether some element
23
+ // happens to carry a `note`. A note-binding problem (a note pointing at the wrong place) is
24
+ // noteBindingValidate.ts's business; a stale file nothing names by convention or `covers:` any
25
+ // more is this rule's.
26
+ //
27
+ // A file only counts as a slice doc worth checking when its frontmatter is USABLE
28
+ // (hasUsableFrontmatter — sliceDoc.ts, the exact gate `em export`'s `frontmatter-invalid` and
29
+ // every sibling module already use, so this rule can't silently disagree with them on what counts
30
+ // as a readable doc). This is what keeps a README, a scratch note, or any other non-doc file in
31
+ // `slices/` from ever being flagged: nothing here can distinguish such a file from "meant to
32
+ // become a slice doc but hasn't been fleshed out yet" except the file declaring itself one via
33
+ // frontmatter — the same declare-gating posture docModelConsistencyValidate.ts's checks take.
34
+ import { readdirSync, readFileSync } from "node:fs";
35
+ import { join } from "node:path";
36
+ import { pushDiag } from "../model/rules.js";
37
+ import { hasUsableFrontmatter, parseSliceDoc } from "./sliceDoc.js";
38
+ /**
39
+ * Scan `<baseDir>/slices/` for a doc file that no current slice's own key names by filename
40
+ * convention, and whose `covers:` list (if any — MIL-121) doesn't ratify a current slice either.
41
+ * `baseDir` is the `.em` file's directory, same convention every other doc/note path in em uses.
42
+ * Returns `[]` when `slices/` doesn't exist at all — nothing to a scan with no directory to walk,
43
+ * the ordinary state for a model that hasn't authored any slice docs yet.
44
+ */
45
+ export function validateOrphanedSliceDocs(_model, refs, baseDir) {
46
+ // `_model` is unused — `refs.sliceKeys` already carries every current slice's key. Kept in the
47
+ // signature anyway to match every sibling fs-aware rule's `(model, refs, baseDir)` shape, so
48
+ // every call site can pass the same three arguments uniformly.
49
+ const slicesDir = join(baseDir, "slices");
50
+ let entries;
51
+ try {
52
+ entries = readdirSync(slicesDir, { withFileTypes: true })
53
+ .filter((e) => e.isFile())
54
+ .map((e) => e.name);
55
+ }
56
+ catch {
57
+ return []; // no slices/ directory (or unreadable) — nothing to orphan
58
+ }
59
+ const liveKeys = new Set(refs.sliceKeys.map((k) => k.toLowerCase()));
60
+ const diags = [];
61
+ for (const entry of entries.slice().sort()) {
62
+ if (!entry.toLowerCase().endsWith(".md"))
63
+ continue; // not a slice-doc-shaped file at all
64
+ const key = entry.slice(0, -".md".length);
65
+ if (liveKeys.has(key.toLowerCase()))
66
+ continue; // matches a current slice's key by name — never orphaned
67
+ let parsed;
68
+ try {
69
+ parsed = parseSliceDoc(readFileSync(join(slicesDir, entry), "utf8"));
70
+ }
71
+ catch {
72
+ continue; // unreadable file (permissions, ...) — not this rule's business
73
+ }
74
+ // Gate on usable frontmatter, same predicate every sibling fs-aware rule uses: a README, a
75
+ // freeform note, or a draft that never got as far as a full frontmatter block is not
76
+ // confidently a slice doc at all, so it's never flagged as one gone stale.
77
+ if (!hasUsableFrontmatter(parsed))
78
+ continue;
79
+ // MIL-121: a doc whose own canonical slice is gone can still legitimately serve a DIFFERENT,
80
+ // still-live slice via `covers:` — the two-slice Automation/Translation shape's shared-doc
81
+ // case. Ratifying coverage of any current slice is enough; this mirrors docJoin.ts's own
82
+ // predicate loosely (it doesn't require an actual winning cross-note here, only that the
83
+ // `covers:` declaration itself still names something live) — a stricter "and some note also
84
+ // points here" check would reintroduce exactly the kind of false positive this ticket calls
85
+ // out to avoid.
86
+ if (parsed.covers.some((c) => liveKeys.has(c)))
87
+ continue;
88
+ pushDiag(diags, "orphaned-slice-doc", {
89
+ message: `slice doc "slices/${entry}" matches no current slice's key, and its \`covers:\` list ` +
90
+ `(if any) doesn't name one either — likely left behind by a rename or removal. Rename it ` +
91
+ `to the renamed slice's key, add \`covers: <slice-key>\` (plus a \`note\` binding) to ` +
92
+ `attach it to a live slice, or delete it if it's no longer needed`,
93
+ refs: [key],
94
+ });
95
+ }
96
+ return diags;
97
+ }
98
+ //# sourceMappingURL=orphanedSliceDocValidate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orphanedSliceDocValidate.js","sourceRoot":"","sources":["../../src/catalog/orphanedSliceDocValidate.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,iGAAiG;AACjG,iGAAiG;AACjG,mFAAmF;AACnF,yFAAyF;AACzF,kGAAkG;AAClG,+FAA+F;AAC/F,+FAA+F;AAC/F,8FAA8F;AAC9F,yFAAyF;AACzF,oEAAoE;AACpE,EAAE;AACF,+FAA+F;AAC/F,8EAA8E;AAC9E,+FAA+F;AAC/F,gGAAgG;AAChG,iGAAiG;AACjG,kGAAkG;AAClG,kGAAkG;AAClG,iGAAiG;AACjG,iGAAiG;AACjG,8FAA8F;AAC9F,4FAA4F;AAC5F,+FAA+F;AAC/F,uBAAuB;AACvB,EAAE;AACF,kFAAkF;AAClF,8FAA8F;AAC9F,kGAAkG;AAClG,gGAAgG;AAChG,6FAA6F;AAC7F,+FAA+F;AAC/F,8FAA8F;AAE9F,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEpE;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CAAC,MAAuB,EAAE,IAAgB,EAAE,OAAe;IAClG,+FAA+F;IAC/F,6FAA6F;IAC7F,+DAA+D;IAC/D,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC1C,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,GAAG,WAAW,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;aACtD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;aACzB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC,CAAC,2DAA2D;IACxE,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACrE,MAAM,KAAK,GAAiB,EAAE,CAAC;IAE/B,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;QAC3C,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,SAAS,CAAC,qCAAqC;QACzF,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;YAAE,SAAS,CAAC,yDAAyD;QAExG,IAAI,MAAM,CAAC;QACX,IAAI,CAAC;YACH,MAAM,GAAG,aAAa,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACvE,CAAC;QAAC,MAAM,CAAC;YACP,SAAS,CAAC,gEAAgE;QAC5E,CAAC;QACD,2FAA2F;QAC3F,qFAAqF;QACrF,2EAA2E;QAC3E,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC;YAAE,SAAS;QAC5C,6FAA6F;QAC7F,2FAA2F;QAC3F,yFAAyF;QACzF,yFAAyF;QACzF,4FAA4F;QAC5F,4FAA4F;QAC5F,gBAAgB;QAChB,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAAE,SAAS;QAEzD,QAAQ,CAAC,KAAK,EAAE,oBAAoB,EAAE;YACpC,OAAO,EACL,qBAAqB,KAAK,6DAA6D;gBACvF,0FAA0F;gBAC1F,uFAAuF;gBACvF,kEAAkE;YACpE,IAAI,EAAE,CAAC,GAAG,CAAC;SACZ,CAAC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -59,6 +59,21 @@ export interface SliceDoc {
59
59
  * the noting slice back. Empty array when absent — the common case; a doc always covers its
60
60
  * own canonical slice key implicitly and never needs to list it here. */
61
61
  covers: string[];
62
+ /** MIL-165: `ratifiedBy:` — free text, typically a person's name — or null when absent.
63
+ * Written only by `em slice ratify`; no legacy bullet-line form. */
64
+ ratifiedBy: string | null;
65
+ /** MIL-165: `ratifiedOn:` — a `YYYY-MM-DD` date string, or null when absent. Written only by
66
+ * `em slice ratify`; validated by the CLI layer, not re-validated here (this parser stays as
67
+ * lenient about value shape as every other frontmatter field). */
68
+ ratifiedOn: string | null;
69
+ /** MIL-171: `owner:` — free text, typically a person or team name — or null when absent.
70
+ * Hand-filled; no `em` command writes it. */
71
+ owner: string | null;
72
+ /** MIL-171: `tracking:` — free text, typically an external ticket/issue URL — or null when
73
+ * absent. Hand-filled; no `em` command writes it. This is the field em-tracker-bridge reads
74
+ * to find the ticket mirroring this slice — its export name/shape (docJoin.ts) is a
75
+ * cross-tool contract, not just an internal display field. */
76
+ tracking: string | null;
62
77
  /** True when a well-formed leading `---`/`---` frontmatter fence was found and
63
78
  * closed — independent of which keys it contained. False for a legacy
64
79
  * status-bullet-only doc, a doc with no frontmatter at all, or an
@@ -33,6 +33,20 @@
33
33
  // `note "slices/<this-key>.md"` instead of authoring its own. Parsed the same
34
34
  // comma-separated-list shape as `merged-from`/`superseded-by`; see docJoin.ts for the
35
35
  // two-ended handshake that actually uses it.
36
+ //
37
+ // `ratifiedBy`/`ratifiedOn` (MIL-165) are a fifth and sixth optional frontmatter-only field:
38
+ // who ratified this doc's current `status`/`version`, and when, written by `em slice ratify`
39
+ // (cli/ratify.ts) alone — same "one write path" discipline `implementedIn` has with `em slice
40
+ // mark-implemented`. Additive, tolerate-unknown-fields: a doc that predates this feature (or was
41
+ // hand-ratified) simply has neither key, same as any other optional field's absence.
42
+ //
43
+ // `owner`/`tracking` (MIL-171) are a seventh and eighth optional frontmatter-only field: who
44
+ // (a person or team) holds this slice, and a URL into an external tracker mirroring it. Unlike
45
+ // `ratifiedBy`/`ratifiedOn`, neither has a dedicated `em` write path — both are hand-filled, free
46
+ // text, exactly like `implementedIn`. `em` only stores and displays them; `tracking` in
47
+ // particular is the field em-tracker-bridge reads to find the mirrored ticket, so its export
48
+ // name/shape is a cross-tool contract — see docJoin.ts/emit/json.ts. Additive,
49
+ // tolerate-unknown-fields: absent on every doc predating this feature.
36
50
  import { marked } from "marked";
37
51
  /** Frontmatter keys docs/slice-doc-schema.md's required-vs-optional table marks
38
52
  * required at every `status` — the mechanical basis for `frontmatter-invalid`
@@ -182,6 +196,10 @@ export function parseSliceDoc(markdown) {
182
196
  supersededBy: parseSliceRefList(fields.get("superseded-by")),
183
197
  implementedIn: fields.get("implementedin") ?? null,
184
198
  covers: parseKeyList(fields.get("covers")),
199
+ ratifiedBy: fields.get("ratifiedby") ?? null,
200
+ ratifiedOn: fields.get("ratifiedon") ?? null,
201
+ owner: fields.get("owner") ?? null,
202
+ tracking: fields.get("tracking") ?? null,
185
203
  frontmatterPresent,
186
204
  missingRequiredFields: REQUIRED_FRONTMATTER_KEYS.filter((k) => !fields.has(k)),
187
205
  html: marked.parse(body, { async: false }),
@@ -1 +1 @@
1
- {"version":3,"file":"sliceDoc.js","sourceRoot":"","sources":["../../src/catalog/sliceDoc.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sliceDoc.js","sourceRoot":"","sources":["../../src/catalog/sliceDoc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { CommitInfo } from "./changelog-git.js";
2
+ /**
3
+ * Build the `em changelog` markdown document for an already-resolved commit list
4
+ * (oldest -> newest, see `listModelCommits`). Compiles every revision once; per-revision
5
+ * warnings are deliberately never surfaced (historical revisions can be noisy) — only a compile
6
+ * *failure* (parse error or validation error, same threshold `em diff` uses) surfaces, as that
7
+ * entry's error note, never a crash. Diffs are computed against the previous *parseable*
8
+ * revision, so a single bad revision in the middle of the walk doesn't break every entry after
9
+ * it. Content is read at each commit's own path (`readFileAtCommit`), so the walk survives
10
+ * renames.
11
+ */
12
+ export declare function buildChangelogDoc(file: string, repoRoot: string, commits: CommitInfo[]): string;
@@ -0,0 +1,89 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // `em changelog`'s document builder (MIL-100), extracted out of cli.ts (MIL-167) so the MCP
3
+ // server's `changelog` tool can call the exact same function the CLI command does — same
4
+ // "one builder, two callers" pattern as buildDiffJson/buildGlossaryJson, just markdown instead
5
+ // of JSON (the CLI command itself has no `--json` flag; the document IS the markdown text).
6
+ //
7
+ // Already pure enough to share as-is: no process.exit, no console — a per-revision compile
8
+ // failure becomes that entry's `error` field, never a crash (see the docstring below). The only
9
+ // impure bit (`readFileAtCommit`, a `git show`) is injected in, same convention as
10
+ // changelog-git.ts/diff-inputs.ts's GitRunner.
11
+ import { dirname, join } from "node:path";
12
+ import { existsSync, readFileSync } from "node:fs";
13
+ import { compile } from "../pipeline.js";
14
+ import { ParseError } from "../parser/parser.js";
15
+ import { hasErrors } from "../model/validate.js";
16
+ import { diffModels } from "../model/diff.js";
17
+ import { buildChangelog, parseDecisionsLog } from "../emit/changelog.js";
18
+ import { readFileAtCommit } from "./changelog-git.js";
19
+ import { STATE_FILE_NAME } from "./stateFile.js";
20
+ /**
21
+ * Build the `em changelog` markdown document for an already-resolved commit list
22
+ * (oldest -> newest, see `listModelCommits`). Compiles every revision once; per-revision
23
+ * warnings are deliberately never surfaced (historical revisions can be noisy) — only a compile
24
+ * *failure* (parse error or validation error, same threshold `em diff` uses) surfaces, as that
25
+ * entry's error note, never a crash. Diffs are computed against the previous *parseable*
26
+ * revision, so a single bad revision in the middle of the walk doesn't break every entry after
27
+ * it. Content is read at each commit's own path (`readFileAtCommit`), so the walk survives
28
+ * renames.
29
+ */
30
+ export function buildChangelogDoc(file, repoRoot, commits) {
31
+ const models = [];
32
+ const refsList = [];
33
+ const errors = [];
34
+ for (const c of commits) {
35
+ const rev = readFileAtCommit(repoRoot, c);
36
+ if (!rev.ok) {
37
+ models.push(null);
38
+ refsList.push(null);
39
+ errors.push(rev.message);
40
+ continue;
41
+ }
42
+ try {
43
+ const { model, refs, diagnostics } = compile(rev.content);
44
+ if (hasErrors(diagnostics)) {
45
+ models.push(null);
46
+ refsList.push(null);
47
+ errors.push(`validation errors at ${c.shortHash} — fix with \`em validate\` at that revision`);
48
+ }
49
+ else {
50
+ models.push(model);
51
+ refsList.push(refs);
52
+ errors.push(null);
53
+ }
54
+ }
55
+ catch (e) {
56
+ models.push(null);
57
+ refsList.push(null);
58
+ errors.push(e instanceof ParseError ? `parse error: ${e.message}` : e instanceof Error ? e.message : String(e));
59
+ }
60
+ }
61
+ const entries = [];
62
+ let prevParseable = -1;
63
+ commits.forEach((c, i) => {
64
+ const base = { shortHash: c.shortHash, date: c.date, subject: c.subject };
65
+ if (i === 0) {
66
+ entries.push({ ...base, diff: null });
67
+ }
68
+ else if (!models[i]) {
69
+ entries.push({ ...base, diff: null, error: errors[i] });
70
+ }
71
+ else if (prevParseable === -1) {
72
+ entries.push({ ...base, diff: null, error: `no earlier parseable revision to diff against (${commits[0].shortHash}: ${errors[0]})` });
73
+ }
74
+ else {
75
+ entries.push({
76
+ ...base,
77
+ diff: diffModels(models[prevParseable], models[i], refsList[prevParseable], refsList[i]),
78
+ });
79
+ }
80
+ if (models[i])
81
+ prevParseable = i;
82
+ });
83
+ const intro = models[0] ? { slices: models[0].slices.length, elements: models[0].elements.length } : null;
84
+ const introError = models[0] ? undefined : (errors[0] ?? undefined);
85
+ const stateFile = join(dirname(file), STATE_FILE_NAME);
86
+ const decisions = existsSync(stateFile) ? parseDecisionsLog(readFileSync(stateFile, "utf8")) : [];
87
+ return buildChangelog(entries, decisions, { file, intro, introError });
88
+ }
89
+ //# sourceMappingURL=changelogBuild.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changelogBuild.js","sourceRoot":"","sources":["../../src/cli/changelogBuild.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ export declare const CI_WORKFLOW_MARKER = "em-ci";
2
+ export declare const CONFORM_WORKFLOW_MARKER = "em-conform";
3
+ export declare function ciWorkflowPath(repoRoot: string): string;
4
+ export declare function conformWorkflowPath(repoRoot: string): string;
5
+ export declare function findUnsafeCiInitArg(value: string): string | null;
6
+ /** The managed block only (no header/`on:`/`jobs:` scaffolding) — what gets written between
7
+ * the marker pair, both for a fresh file and to patch an existing marked one in place. */
8
+ export declare function ciManagedBody(model: string, testsDir: string): string;
9
+ export declare function buildCiWorkflowFile(model: string, testsDir: string, emVersion: string): string;
10
+ /** The managed block only (no header/`on:`/`permissions:`/`jobs:` scaffolding) — what gets
11
+ * written between the marker pair, both for a fresh file and to patch an existing marked one
12
+ * in place. */
13
+ export declare function conformManagedBody(model: string): string;
14
+ export declare function buildConformWorkflowFile(model: string, emVersion: string): string;
15
+ export type CiFileStatus = {
16
+ kind: "create";
17
+ content: string;
18
+ } | {
19
+ kind: "ok";
20
+ content: string;
21
+ } | {
22
+ kind: "stale";
23
+ content: string;
24
+ current: string;
25
+ } | {
26
+ kind: "missing-markers";
27
+ } | {
28
+ kind: "would-replace";
29
+ content: string;
30
+ };
31
+ /**
32
+ * Decide what to do with one generated file: create it if missing, patch the managed block if
33
+ * the marker pair is present, or (without `force`) leave an existing unmarked file alone. Pure
34
+ * — never touches disk; `applyCiFile` below does the actual write.
35
+ *
36
+ * `generated` is the full from-scratch file content (header + `on:`/`jobs:` scaffolding +
37
+ * marker-wrapped body) — written verbatim for `create`/`would-replace`. `managedBody` is just
38
+ * the text between the markers, reused to patch an existing marked file in place without
39
+ * touching whatever a repo added around it.
40
+ */
41
+ export declare function planCiFile(path: string, generated: string, managedBody: string, markerName: string, force: boolean): CiFileStatus;
42
+ export declare function applyCiFile(path: string, status: CiFileStatus): void;