@milehimikey/em 1.8.1 → 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 (104) 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 +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 +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 +6 -1
  40. package/dist/cli/coverage.js +28 -3
  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/freshnessJson.d.ts +6 -0
  77. package/dist/emit/freshnessJson.js +24 -0
  78. package/dist/emit/freshnessJson.js.map +1 -0
  79. package/dist/emit/json.d.ts +62 -8
  80. package/dist/emit/json.js +14 -3
  81. package/dist/emit/json.js.map +1 -1
  82. package/dist/emit/statusJson.d.ts +7 -0
  83. package/dist/emit/statusJson.js +39 -0
  84. package/dist/emit/statusJson.js.map +1 -0
  85. package/dist/emit/typespec.d.ts +26 -0
  86. package/dist/emit/typespec.js +356 -0
  87. package/dist/emit/typespec.js.map +1 -0
  88. package/dist/emit/usageReportJson.d.ts +3 -0
  89. package/dist/emit/usageReportJson.js +23 -0
  90. package/dist/emit/usageReportJson.js.map +1 -0
  91. package/dist/mcp/server.d.ts +1 -1
  92. package/dist/mcp/server.js +301 -11
  93. package/dist/mcp/server.js.map +1 -1
  94. package/dist/model/rules.d.ts +13 -0
  95. package/dist/model/rules.js +20 -0
  96. package/dist/model/rules.js.map +1 -1
  97. package/dist/templates.d.ts +1 -1
  98. package/dist/templates.js +2 -2
  99. package/dist/util/markers.d.ts +16 -4
  100. package/dist/util/markers.js +23 -10
  101. package/dist/util/markers.js.map +1 -1
  102. package/package.json +2 -1
  103. /package/.claude/skills/{event-modeling → event-modeling-shared}/templates/conformance-report.md +0 -0
  104. /package/.claude/skills/{event-modeling → event-modeling-shared}/templates/state.md +0 -0
@@ -20,3 +20,13 @@ export declare function planSkillSync(packagedDir: string, vendoredDir: string):
20
20
  * with no changes is a no-op. Creates vendoredDir (and any needed subdirectories) as needed.
21
21
  */
22
22
  export declare function applySkillSync(plan: SkillSyncPlan, packagedDir: string, vendoredDir: string): void;
23
+ export interface SkillSyncBundleDirPlan {
24
+ dirName: string;
25
+ plan: SkillSyncPlan;
26
+ }
27
+ /** Pure: one planSkillSync call per named directory, paired with the directory name so the
28
+ * caller can report/apply per directory. No fs writes. */
29
+ export declare function planSkillSyncBundle(packagedRoot: string, vendoredRoot: string, dirNames: readonly string[]): SkillSyncBundleDirPlan[];
30
+ /** Shell: applies every directory's plan from planSkillSyncBundle. Same idempotency/no-merge
31
+ * contract as applySkillSync, just looped. */
32
+ export declare function applySkillSyncBundle(bundlePlan: SkillSyncBundleDirPlan[], packagedRoot: string, vendoredRoot: string): void;
@@ -66,4 +66,19 @@ export function applySkillSync(plan, packagedDir, vendoredDir) {
66
66
  }
67
67
  }
68
68
  }
69
+ /** Pure: one planSkillSync call per named directory, paired with the directory name so the
70
+ * caller can report/apply per directory. No fs writes. */
71
+ export function planSkillSyncBundle(packagedRoot, vendoredRoot, dirNames) {
72
+ return dirNames.map((dirName) => ({
73
+ dirName,
74
+ plan: planSkillSync(join(packagedRoot, dirName), join(vendoredRoot, dirName)),
75
+ }));
76
+ }
77
+ /** Shell: applies every directory's plan from planSkillSyncBundle. Same idempotency/no-merge
78
+ * contract as applySkillSync, just looped. */
79
+ export function applySkillSyncBundle(bundlePlan, packagedRoot, vendoredRoot) {
80
+ for (const { dirName, plan } of bundlePlan) {
81
+ applySkillSync(plan, join(packagedRoot, dirName), join(vendoredRoot, dirName));
82
+ }
83
+ }
69
84
  //# sourceMappingURL=skillSync.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"skillSync.js","sourceRoot":"","sources":["../../src/cli/skillSync.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"skillSync.js","sourceRoot":"","sources":["../../src/cli/skillSync.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,yFAAyF;AACzF,mFAAmF;AACnF,yFAAyF;AACzF,0FAA0F;AAC1F,0EAA0E;AAC1E,EAAE;AACF,0FAA0F;AAC1F,4FAA4F;AAC5F,uFAAuF;AACvF,2FAA2F;AAC3F,yCAAyC;AACzC,EAAE;AACF,+FAA+F;AAC/F,sFAAsF;AACtF,yDAAyD;AAEzD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACpF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAgB7C,SAAS,MAAM,CAAC,IAAY;IAC1B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACvE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,WAAmB,EAAE,WAAmB;IACpE,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;IACpD,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACnF,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,aAAa,EAAE,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAE3E,MAAM,OAAO,GAA0B,EAAE,CAAC;IAC1C,IAAI,cAAc,GAAG,CAAC,CAAC;IAEvB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC9C,IAAI,UAAU,IAAI,CAAC,UAAU,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAC3C,CAAC;aAAM,IAAI,CAAC,UAAU,IAAI,UAAU,EAAE,CAAC;YACrC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QAC7C,CAAC;aAAM,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;YACrF,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QAC9C,CAAC;aAAM,CAAC;YACN,cAAc,EAAE,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;AACrC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,IAAmB,EAAE,WAAmB,EAAE,WAAmB;IAC1F,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QAC/C,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,CAAC;QACf,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9C,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;AACH,CAAC;AAaD;2DAC2D;AAC3D,MAAM,UAAU,mBAAmB,CACjC,YAAoB,EACpB,YAAoB,EACpB,QAA2B;IAE3B,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAChC,OAAO;QACP,IAAI,EAAE,aAAa,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;KAC9E,CAAC,CAAC,CAAC;AACN,CAAC;AAED;+CAC+C;AAC/C,MAAM,UAAU,oBAAoB,CAAC,UAAoC,EAAE,YAAoB,EAAE,YAAoB;IACnH,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,UAAU,EAAE,CAAC;QAC3C,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;IACjF,CAAC;AACH,CAAC"}
@@ -9,6 +9,9 @@ export interface SliceIndexRow {
9
9
  name: string;
10
10
  pattern: string;
11
11
  status: string;
12
+ ratifiedBy: string;
13
+ owner: string;
14
+ tracking: string;
12
15
  implementedIn: string;
13
16
  docPath: string;
14
17
  }
@@ -16,8 +16,8 @@ import { applyMarker } from "../util/markers.js";
16
16
  /** The marker name wrapping the Slices table: `<!-- GENERATED:slices:start -->` /
17
17
  * `<!-- GENERATED:slices:end -->`, matching templates/model-readme.md. */
18
18
  export const SLICE_INDEX_MARKER = "slices";
19
- const TABLE_HEADER = "| # | Slice | Pattern | Status | Implemented in | Design doc |\n" +
20
- "|---|-------|---------|--------|----------------|------------|";
19
+ const TABLE_HEADER = "| # | Slice | Pattern | Status | Ratified by | Owner | Tracking | Implemented in | Design doc |\n" +
20
+ "|---|-------|---------|--------|-------------|-------|----------|----------------|------------|";
21
21
  /** Escape characters that would break a markdown table cell: `|` (the column separator) and
22
22
  * newlines (a slice name is always one line, but a doc's freeform `implementedIn` text isn't
23
23
  * guaranteed to be). */
@@ -53,11 +53,15 @@ export function buildSliceIndexTable(model, refs, baseDir) {
53
53
  name: slice.name,
54
54
  pattern: slicePatternLabel(pattern),
55
55
  status: statusCell(doc),
56
+ ratifiedBy: doc.ratifiedBy ?? "—",
57
+ owner: doc.owner ?? "—",
58
+ tracking: doc.tracking ?? "—",
56
59
  implementedIn: doc.implementedIn ?? "—",
57
60
  docPath: doc.path,
58
61
  };
59
62
  });
60
63
  const lines = rows.map((r) => `| ${r.index} | ${escapeCell(r.name)} | ${escapeCell(r.pattern)} | ${escapeCell(r.status)} | ` +
64
+ `${escapeCell(r.ratifiedBy)} | ${escapeCell(r.owner)} | ${escapeCell(r.tracking)} | ` +
61
65
  `${escapeCell(r.implementedIn)} | [${r.docPath}](${r.docPath}) |`);
62
66
  return { markdown: [TABLE_HEADER, ...lines].join("\n"), rows, diagnostics };
63
67
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sliceIndex.js","sourceRoot":"","sources":["../../src/cli/sliceIndex.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sliceIndex.js","sourceRoot":"","sources":["../../src/cli/sliceIndex.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import { NormalizedModel, Element } from "../model/model.js";
2
+ import { RefsResult } from "../model/refs.js";
3
+ import { SlicePattern } from "./sliceNew.js";
4
+ export type ResolvePrimaryElementResult = {
5
+ ok: true;
6
+ sliceIndex: number;
7
+ element: Element;
8
+ } | {
9
+ ok: false;
10
+ message: string;
11
+ };
12
+ /** Resolve `sliceKey`'s primary element for `pattern` — the export key must match a slice
13
+ * already declared in `model` (the ordinary case: the model phase already created the slice;
14
+ * `slice` phase authoring adds its doc afterward), and that slice must have EXACTLY one element
15
+ * of the pattern's primary kind(s) — zero or more than one is refused rather than guessed. */
16
+ export declare function resolvePrimaryElement(model: NormalizedModel, refs: RefsResult, sliceKey: string, pattern: SlicePattern): ResolvePrimaryElementResult;
17
+ export type InsertNoteResult = {
18
+ ok: true;
19
+ content: string;
20
+ } | {
21
+ ok: false;
22
+ message: string;
23
+ };
24
+ /** Insert `note "<notePath>"` into one raw source line — see module header for the placement
25
+ * rule. Pure string transform, no fs, no knowledge of the rest of the file. */
26
+ export declare function insertNoteClause(rawLine: string, notePath: string): InsertNoteResult;
27
+ /** Byte offsets of physical line `lineNo` (1-indexed) within `source`: `[start, end)` excludes
28
+ * the line's own terminator (a trailing `\r` before `\n` is excluded too, so a CRLF file's line
29
+ * content never carries a stray `\r`). Scans once, character by character, rather than
30
+ * `split(/\r?\n/)` — a split+rejoin would silently normalize every OTHER line's terminator
31
+ * style the moment the file is written back (the same pitfall markImplemented.ts/ratify.ts's
32
+ * module headers document for frontmatter surgery — this is the `.em`-source counterpart). */
33
+ export declare function findLineSpan(source: string, lineNo: number): {
34
+ start: number;
35
+ end: number;
36
+ } | null;
37
+ export type WireSliceNoteResult = {
38
+ ok: true;
39
+ content: string;
40
+ sliceName: string;
41
+ elementName: string;
42
+ } | {
43
+ ok: false;
44
+ message: string;
45
+ };
46
+ /**
47
+ * Full `--wire` operation: resolve `sliceKey`'s primary element for `pattern`, then insert
48
+ * `note "<notePath>"` on its exact header line in `source`. `source` MUST be the same text
49
+ * `model`/`refs` were compiled from — line numbers are meaningless against any other text.
50
+ * Every byte outside that one line's span is returned unchanged.
51
+ */
52
+ export declare function wireSliceNote(source: string, model: NormalizedModel, refs: RefsResult, sliceKey: string, pattern: SlicePattern, notePath: string): WireSliceNoteResult;
@@ -0,0 +1,152 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // `em slice new --wire` (MIL-161 finding #3): `em slice new` already computes the exact
3
+ // `note "slices/<key>.md"` line and knows which element is the slice's "primary" one for its
4
+ // pattern (SKILL.md's slice phase, step 4) — this module does the mechanical part that used to
5
+ // stop at printing that line: inserting it into the `.em` source directly, onto the right
6
+ // element's declaration line.
7
+ //
8
+ // Deliberately narrow, matching every other .em-source-editing decision in this codebase (there
9
+ // is no general .em serializer — see docModelConsistencyValidate.ts's header for why a
10
+ // parse+re-serialize is never on the table here either): this ONLY ever edits the ONE physical
11
+ // source line an element's declaration STARTS on (`Element.line`, 1-indexed, straight from the
12
+ // parser — parser.ts's `parseElement`/`lineNo`), and only ever INSERTS a `note "..."` clause
13
+ // into it. Every other line — including the rest of a multi-line field block and its closing
14
+ // `}` — is copied through byte-for-byte; multi-line field text on the SAME line as a note
15
+ // insertion (a block's opening line, e.g. `command Place Order { customerId`) is preserved
16
+ // verbatim too, since the insertion point is always relative to the unquoted `{`, never to
17
+ // anything after it.
18
+ //
19
+ // Placement follows the grammar exactly (parser.ts's `extractClauses`): `note`/`issue`/
20
+ // `divergence`/`tag`/`renamed from` are all extracted from an element's header line BEFORE
21
+ // `from`, and by locating the keyword anywhere in the line rather than requiring it in a fixed
22
+ // position — so a `note "..."` clause parses identically whether it comes before or after a
23
+ // `from "..."` clause, before or after a `@Tag`, immediately before an opening `{`, or right
24
+ // after a `}` that already closed inline. That's what makes one placement rule safe for every
25
+ // element shape:
26
+ //
27
+ // - the header line opens a field block on this SAME line (an unquoted `{`, MIL-122's
28
+ // quote-aware scan — a literal `{` inside a quoted clause like `issue "PUT /widgets/{id}"`
29
+ // is not a block opener): insert immediately BEFORE that `{`, matching every existing
30
+ // note-before-fields example in the DSL (`event X @Ctx note "..." { ... }`).
31
+ // - otherwise (no field block at all on this line, OR a fully inline `{ ... }` block that
32
+ // already closed on the same line): append at the very end of the code, before any trailing
33
+ // `# comment` — matching the grammar's "clauses may trail a closing `}` on the same line"
34
+ // rule, which already covers both shapes identically.
35
+ //
36
+ // Refuses (never overwrites/duplicates) when the header line already carries a `note` clause —
37
+ // the caller falls back to printing the line for a hand edit, same as when `--wire` isn't passed
38
+ // at all.
39
+ import { indexOfUnquoted, stripComment } from "../parser/lexer.js";
40
+ /** Which element kind(s) count as a slice's "primary" element per pattern — the one `note
41
+ * "slices/<key>.md"` binds to (SKILL.md's slice phase, step 4): the command for State Change,
42
+ * the view for State View, the reactor (processor/automation/saga) for Automation, the
43
+ * translation for Translation. Distinct from classify.ts's classifySlicePattern, which groups
44
+ * every kind a pattern's slice may contain (e.g. an Automation slice's command too) — this
45
+ * narrows to the single element the note actually binds to. */
46
+ const PRIMARY_KINDS = {
47
+ "state-change": ["command"],
48
+ "state-view": ["view"],
49
+ automation: ["processor", "automation", "saga"],
50
+ translation: ["translation"],
51
+ };
52
+ /** Resolve `sliceKey`'s primary element for `pattern` — the export key must match a slice
53
+ * already declared in `model` (the ordinary case: the model phase already created the slice;
54
+ * `slice` phase authoring adds its doc afterward), and that slice must have EXACTLY one element
55
+ * of the pattern's primary kind(s) — zero or more than one is refused rather than guessed. */
56
+ export function resolvePrimaryElement(model, refs, sliceKey, pattern) {
57
+ const sliceIndex = refs.sliceKeys.indexOf(sliceKey);
58
+ if (sliceIndex === -1) {
59
+ return { ok: false, message: `no slice with export key "${sliceKey}" in this model` };
60
+ }
61
+ const slice = model.slices[sliceIndex];
62
+ const kinds = PRIMARY_KINDS[pattern];
63
+ const candidates = slice.elements.filter((el) => kinds.includes(el.kind));
64
+ if (candidates.length === 0) {
65
+ return {
66
+ ok: false,
67
+ message: `slice "${slice.name}" has no ${kinds.join("/")} element to wire the note onto`,
68
+ };
69
+ }
70
+ if (candidates.length > 1) {
71
+ return {
72
+ ok: false,
73
+ message: `slice "${slice.name}" has ${candidates.length} ${kinds.join("/")} elements — ambiguous, wire the note by hand`,
74
+ };
75
+ }
76
+ return { ok: true, sliceIndex, element: candidates[0] };
77
+ }
78
+ /** Insert `note "<notePath>"` into one raw source line — see module header for the placement
79
+ * rule. Pure string transform, no fs, no knowledge of the rest of the file. */
80
+ export function insertNoteClause(rawLine, notePath) {
81
+ const code = stripComment(rawLine);
82
+ const comment = rawLine.slice(code.length); // '' or the (whitespace + '#...') tail stripComment dropped
83
+ const trimmedCode = code.replace(/[ \t]+$/, "");
84
+ // Conservative existing-clause check: a bare "note" immediately followed by a quote is
85
+ // EXACTLY how the parser itself recognizes the clause (lexer.ts's QUOTE_OPENER_KEYWORDS
86
+ // anchoring), regardless of where else it appears — a false positive here just means an
87
+ // avoidable refusal (falls back to a hand edit), never a corrupted line.
88
+ if (/\bnote\s*"/.test(trimmedCode)) {
89
+ return { ok: false, message: "this line already has a `note` clause — edit it by hand instead" };
90
+ }
91
+ const clause = `note "${notePath}"`;
92
+ const braceAt = indexOfUnquoted(trimmedCode, "{");
93
+ // A `{` on THIS line only means "insert before it" when the block actually stays open past
94
+ // this line (no matching unquoted `}` here too) — a fully inline `{ ... }` block that already
95
+ // closed on the same line is grammatically just like having no braces at all: the note clause
96
+ // trails it, same as the no-brace case below.
97
+ const closesInline = braceAt >= 0 && indexOfUnquoted(trimmedCode.slice(braceAt + 1), "}") >= 0;
98
+ const newCode = braceAt >= 0 && !closesInline
99
+ ? `${trimmedCode.slice(0, braceAt).replace(/[ \t]+$/, "")} ${clause} ${trimmedCode.slice(braceAt)}`
100
+ : `${trimmedCode} ${clause}`;
101
+ return { ok: true, content: comment ? `${newCode} ${comment}` : newCode };
102
+ }
103
+ /** Byte offsets of physical line `lineNo` (1-indexed) within `source`: `[start, end)` excludes
104
+ * the line's own terminator (a trailing `\r` before `\n` is excluded too, so a CRLF file's line
105
+ * content never carries a stray `\r`). Scans once, character by character, rather than
106
+ * `split(/\r?\n/)` — a split+rejoin would silently normalize every OTHER line's terminator
107
+ * style the moment the file is written back (the same pitfall markImplemented.ts/ratify.ts's
108
+ * module headers document for frontmatter surgery — this is the `.em`-source counterpart). */
109
+ export function findLineSpan(source, lineNo) {
110
+ let line = 1;
111
+ let start = 0;
112
+ for (let i = 0; i <= source.length; i++) {
113
+ if (i === source.length || source[i] === "\n") {
114
+ let end = i;
115
+ if (end > start && source[end - 1] === "\r")
116
+ end--;
117
+ if (line === lineNo)
118
+ return { start, end };
119
+ line++;
120
+ start = i + 1;
121
+ }
122
+ }
123
+ return null;
124
+ }
125
+ /**
126
+ * Full `--wire` operation: resolve `sliceKey`'s primary element for `pattern`, then insert
127
+ * `note "<notePath>"` on its exact header line in `source`. `source` MUST be the same text
128
+ * `model`/`refs` were compiled from — line numbers are meaningless against any other text.
129
+ * Every byte outside that one line's span is returned unchanged.
130
+ */
131
+ export function wireSliceNote(source, model, refs, sliceKey, pattern, notePath) {
132
+ const resolved = resolvePrimaryElement(model, refs, sliceKey, pattern);
133
+ if (!resolved.ok)
134
+ return resolved;
135
+ const span = findLineSpan(source, resolved.element.line);
136
+ if (!span) {
137
+ return {
138
+ ok: false,
139
+ message: `element "${resolved.element.name}"'s line ${resolved.element.line} not found in the given source — source doesn't match the compiled model`,
140
+ };
141
+ }
142
+ const inserted = insertNoteClause(source.slice(span.start, span.end), notePath);
143
+ if (!inserted.ok)
144
+ return inserted;
145
+ return {
146
+ ok: true,
147
+ content: source.slice(0, span.start) + inserted.content + source.slice(span.end),
148
+ sliceName: model.slices[resolved.sliceIndex].name,
149
+ elementName: resolved.element.name,
150
+ };
151
+ }
152
+ //# sourceMappingURL=sliceLink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sliceLink.js","sourceRoot":"","sources":["../../src/cli/sliceLink.ts"],"names":[],"mappings":"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"}
@@ -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;