@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatterSurgery.js","sourceRoot":"","sources":["../../src/cli/frontmatterSurgery.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,uFAAuF;AACvF,4FAA4F;AAC5F,yFAAyF;AACzF,yFAAyF;AACzF,8FAA8F;AAC9F,gGAAgG;AAChG,sEAAsE;AACtE,EAAE;AACF,+FAA+F;AAE/F;;;;mDAImD;AACnD,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,gGAAgG;IAChG,6FAA6F;IAC7F,6FAA6F;IAC7F,+FAA+F;IAC/F,OAAO,IAAI,MAAM,CAAC,KAAK,GAAG,8BAA8B,EAAE,IAAI,CAAC,CAAC;AAClE,CAAC;AAED;;;qBAGqB;AACrB,MAAM,UAAU,mBAAmB,CAAC,GAAuB;IACzD,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IACjD,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,CAAC;AAED;;;;;kDAKkD;AAClD,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,OAAO,IAAI,MAAM,CAAC,IAAI,GAAG,mCAAmC,EAAE,IAAI,CAAC,CAAC;AACtE,CAAC;AAED;;;;;0FAK0F;AAC1F,MAAM,UAAU,sBAAsB,CAAC,QAAgB;IACrD,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9C,IAAI,GAAG,GAAG,UAAU,CAAC;IACrB,OAAO,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC9B,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACvC,MAAM,OAAO,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC1C,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;QACvC,CAAC;QACD,IAAI,EAAE,KAAK,CAAC,CAAC;YAAE,MAAM;QACrB,GAAG,GAAG,EAAE,GAAG,CAAC,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -23,54 +23,15 @@
23
23
  // `- **Status:** ...` / `- **Implemented in:** ...` bullet dialect; this module targets the
24
24
  // canonical frontmatter dialect (MIL-86) instead, and folds in the note-binding resolution the
25
25
  // bridge's caller (`mark-implemented.ts`) did via a separate `em export` shell-out.
26
+ //
27
+ // The three primitives above (`fieldLineRegex`/`normalizeFieldValue`/`locateFrontmatterInner`)
28
+ // now live in `./frontmatterSurgery.js` (MIL-165) — `ratify.ts` needs the exact same span-finding
29
+ // discipline for its own `status`/`ratifiedBy`/`ratifiedOn` edit, so they moved out to a shared
30
+ // module rather than being copy-pasted a second time.
26
31
  import { readFileSync, writeFileSync } from "node:fs";
27
32
  import { join } from "node:path";
28
33
  import { resolveSliceDocJoin } from "../catalog/docJoin.js";
29
- /** A field line's matched span within a frontmatter `inner` string: `key[:]<ws>` prefix
30
- * (preserved verbatim on write) plus the value text that follows, lowercase-key-matched the
31
- * same way sliceDoc.ts's own parser folds keys for lookup. Column-0 only — same grammar as
32
- * sliceDoc.ts's `^([A-Za-z][\w-]*):\s*(.*)$`, so this never matches an indented/list-style line
33
- * the parser wouldn't treat as a field either. */
34
- function fieldLineRegex(key) {
35
- // `[^\r\n]*` (not a lazy `.*?` + `\r?$`) deliberately -- JS regex `$`/multiline line-terminator
36
- // semantics treat a lone `\r` as its own line boundary, which makes a trailing-`\r?$` anchor
37
- // ambiguous on CRLF input. Excluding \r/\n from the value class sidesteps that entirely: the
38
- // match always stops at the first \r or \n, full stop, no boundary-matching subtlety involved.
39
- return new RegExp(`^(${key}[ \\t]*:[ \\t]*)([^\\r\\n]*)`, "im");
40
- }
41
- /** Strip a value the same way sliceDoc.ts's splitFrontmatter does when reading (surrounding
42
- * quotes, then blank-after-trim collapses to "absent") — used here only to classify the
43
- * *current* implementedIn value for the idempotent/refusal guard, matching what the parser
44
- * would have reported for the same text. */
45
- function normalizeFieldValue(raw) {
46
- if (raw === undefined)
47
- return null;
48
- const v = raw.trim().replace(/^["']|["']$/g, "");
49
- return v === "" ? null : v;
50
- }
51
- /** Byte offsets of the frontmatter block's inner lines (between the two `---` fences), located
52
- * by walking lines with `indexOf` rather than `split(/\r?\n/)` — see the module header for why
53
- * a rewrite can't afford the line-ending normalization a split/join would silently perform.
54
- * `null` when there's no well-formed leading `---`/`---` fence, mirroring sliceDoc.ts's own
55
- * "unterminated fence = no frontmatter" treatment. */
56
- function locateFrontmatterInner(markdown) {
57
- if (!/^---[ \t]*\r?\n/.test(markdown))
58
- return null;
59
- const innerStart = markdown.indexOf("\n") + 1;
60
- let pos = innerStart;
61
- while (pos <= markdown.length) {
62
- const nl = markdown.indexOf("\n", pos);
63
- const lineEnd = nl === -1 ? markdown.length : nl;
64
- const line = markdown.slice(pos, lineEnd);
65
- if (/^---[ \t]*\r?$/.test(line)) {
66
- return { innerStart, innerEnd: pos };
67
- }
68
- if (nl === -1)
69
- break;
70
- pos = nl + 1;
71
- }
72
- return null;
73
- }
34
+ import { fieldLineRegex, locateFrontmatterInner, normalizeFieldValue } from "./frontmatterSurgery.js";
74
35
  /**
75
36
  * Pure text transform: flips `status:` to `implemented` and sets `implementedIn:` to `prUrl` in
76
37
  * `raw`'s frontmatter block. Idempotent (re-applying the same URL is a no-op, `changed: false`,
@@ -1 +1 @@
1
- {"version":3,"file":"markImplemented.js","sourceRoot":"","sources":["../../src/cli/markImplemented.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"markImplemented.js","sourceRoot":"","sources":["../../src/cli/markImplemented.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { NormalizedModel } from "../model/model.js";
2
+ import { RefsResult } from "../model/refs.js";
3
+ /** The status this command flips a slice doc to — the handoff gate
4
+ * (docs/process.md#what-ratified-means): contracts/invariants agreed, open questions resolved
5
+ * or deferred, ready for an implementing agent or engineer to pick up. */
6
+ export declare const RATIFIED_STATUS = "ready-to-implement";
7
+ export type ApplyRatifyResult = {
8
+ ok: true;
9
+ content: string;
10
+ changed: boolean;
11
+ } | {
12
+ ok: false;
13
+ message: string;
14
+ };
15
+ /**
16
+ * Pure text transform: flips `status:` to `ready-to-implement` and sets `ratifiedBy:`/
17
+ * `ratifiedOn:` in `raw`'s frontmatter block. Idempotent (re-applying the same by/on pair once
18
+ * already ratified is a no-op, `changed: false`, `content` returned byte-identical to `raw`);
19
+ * refuses (`ok: false`) rather than silently overwrite provenance when the doc is already
20
+ * `status: ready-to-implement` with a *different* recorded ratifier/date — mirroring
21
+ * `applyImplementedFrontmatter`'s refusal to overwrite a different `implementedIn`. There is no
22
+ * such refusal when `status` isn't already the target: re-ratifying a slice that has since moved
23
+ * on (e.g. back from `implemented` after a version bump — docs/slice-doc-schema.md#status-under-
24
+ * re-ratification) is the ordinary, expected use of this command, so it always applies cleanly.
25
+ * No fs access — the caller reads/writes; see `runRatify` below.
26
+ */
27
+ export declare function applyRatifyFrontmatter(raw: string, ratifiedBy: string, ratifiedOn: string): ApplyRatifyResult;
28
+ export type RunRatifyResult = {
29
+ ok: true;
30
+ path: string;
31
+ changed: boolean;
32
+ } | {
33
+ ok: false;
34
+ message: string;
35
+ };
36
+ /**
37
+ * Resolves `sliceKey` to its bound doc via the same note-binding join `mark-implemented`/
38
+ * `--slice-ready`/`em export` use (MIL-121 cross-binding included), then reads/applies/writes
39
+ * it. `baseDir` is the `.em` file's directory, same convention every doc/note path in `em` uses.
40
+ */
41
+ export declare function runRatify(model: NormalizedModel, refs: RefsResult, baseDir: string, sliceKey: string, ratifiedBy: string, ratifiedOn: string): RunRatifyResult;
@@ -0,0 +1,151 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // `em slice ratify` (MIL-165): makes "who ratified, and when" a first-class recorded fact
3
+ // instead of an unnamed edit anyone with commit access could make. Flips `status:
4
+ // ready-to-implement` and sets `ratifiedBy:`/`ratifiedOn:` on the slice doc resolved from the
5
+ // key via the SAME note-binding resolution `mark-implemented`/`--slice-ready`/`em export` use
6
+ // (catalog/docJoin.ts's resolveSliceDocJoin) — same shape and idempotency discipline as
7
+ // `em slice mark-implemented` (MIL-103, markImplemented.ts), mirrored deliberately so the two
8
+ // lifecycle-flip commands (ratify at handoff, mark-implemented at merge) read as one family.
9
+ //
10
+ // Write strategy: the same surgical index-math splicing markImplemented.ts uses, via the shared
11
+ // primitives in ./frontmatterSurgery.js — never a parse+re-serialize (sliceDoc.ts's own parser
12
+ // is deliberately read-only and drops everything not in its `SliceDoc` shape). Everything
13
+ // outside the edited value spans — the body, `version:`, `implementedIn:`, the lineage/`covers`
14
+ // keys, and (best-effort) the file's own line-ending style — is copied through verbatim.
15
+ //
16
+ // `ratifiedBy`/`ratifiedOn` are additive, optional frontmatter keys (docs/slice-doc-schema.md):
17
+ // omitting them is not an error to any existing `em` command (the "unknown keys are captured,
18
+ // never read, never a warning" contract already covers a doc that predates this feature), and
19
+ // this command is the only thing that ever writes them — same "one write path" discipline
20
+ // `mark-implemented` holds for `implementedIn`.
21
+ import { readFileSync, writeFileSync } from "node:fs";
22
+ import { join } from "node:path";
23
+ import { resolveSliceDocJoin } from "../catalog/docJoin.js";
24
+ import { fieldLineRegex, locateFrontmatterInner, normalizeFieldValue } from "./frontmatterSurgery.js";
25
+ import { isValidDateString } from "./stateFile.js";
26
+ /** The status this command flips a slice doc to — the handoff gate
27
+ * (docs/process.md#what-ratified-means): contracts/invariants agreed, open questions resolved
28
+ * or deferred, ready for an implementing agent or engineer to pick up. */
29
+ export const RATIFIED_STATUS = "ready-to-implement";
30
+ /**
31
+ * Pure text transform: flips `status:` to `ready-to-implement` and sets `ratifiedBy:`/
32
+ * `ratifiedOn:` in `raw`'s frontmatter block. Idempotent (re-applying the same by/on pair once
33
+ * already ratified is a no-op, `changed: false`, `content` returned byte-identical to `raw`);
34
+ * refuses (`ok: false`) rather than silently overwrite provenance when the doc is already
35
+ * `status: ready-to-implement` with a *different* recorded ratifier/date — mirroring
36
+ * `applyImplementedFrontmatter`'s refusal to overwrite a different `implementedIn`. There is no
37
+ * such refusal when `status` isn't already the target: re-ratifying a slice that has since moved
38
+ * on (e.g. back from `implemented` after a version bump — docs/slice-doc-schema.md#status-under-
39
+ * re-ratification) is the ordinary, expected use of this command, so it always applies cleanly.
40
+ * No fs access — the caller reads/writes; see `runRatify` below.
41
+ */
42
+ export function applyRatifyFrontmatter(raw, ratifiedBy, ratifiedOn) {
43
+ const trimmedBy = ratifiedBy.trim();
44
+ if (!trimmedBy)
45
+ return { ok: false, message: "a ratifier name is required (--by)" };
46
+ // Refuse control characters (including an embedded \r/\n, which could splice a multi-line
47
+ // value into the frontmatter and corrupt the fence) — unlike mark-implemented's PR-URL guard,
48
+ // internal whitespace is fine: a person's name legitimately contains spaces ("Alice Smith").
49
+ if (/[\x00-\x1f\x7f]/.test(trimmedBy)) {
50
+ return { ok: false, message: "ratifier name must not contain control characters" };
51
+ }
52
+ if (!isValidDateString(ratifiedOn)) {
53
+ return { ok: false, message: `invalid date "${ratifiedOn}" — expected YYYY-MM-DD` };
54
+ }
55
+ const range = locateFrontmatterInner(raw);
56
+ if (!range)
57
+ return { ok: false, message: "no frontmatter block found" };
58
+ const inner = raw.slice(range.innerStart, range.innerEnd);
59
+ const statusMatch = fieldLineRegex("status").exec(inner);
60
+ if (!statusMatch)
61
+ return { ok: false, message: "no `status:` field found in frontmatter" };
62
+ const byMatch = fieldLineRegex("ratifiedBy").exec(inner);
63
+ const onMatch = fieldLineRegex("ratifiedOn").exec(inner);
64
+ const currentStatus = normalizeFieldValue(statusMatch[2])?.toLowerCase() ?? null;
65
+ const currentBy = byMatch ? normalizeFieldValue(byMatch[2]) : null;
66
+ const currentOn = onMatch ? normalizeFieldValue(onMatch[2]) : null;
67
+ if (currentStatus === RATIFIED_STATUS && currentBy !== null && currentOn !== null) {
68
+ if (currentBy === trimmedBy && currentOn === ratifiedOn) {
69
+ return { ok: true, content: raw, changed: false }; // idempotent no-op
70
+ }
71
+ return {
72
+ ok: false,
73
+ message: `already ratified by ${currentBy} on ${currentOn} — refusing to overwrite with ` +
74
+ `${trimmedBy} on ${ratifiedOn}`,
75
+ };
76
+ }
77
+ // Match the file's own line-ending style for any freshly-inserted line, same trick
78
+ // markImplemented.ts uses: on a CRLF doc, the text right after the status line's match starts
79
+ // with the "\r\n" that used to terminate it, so reusing it keeps a new line consistent with
80
+ // its neighbors instead of being the one bare-LF line in an otherwise-CRLF file.
81
+ const afterStatus = inner.slice(statusMatch.index + statusMatch[0].length);
82
+ const eol = afterStatus.startsWith("\r\n") ? "\r\n" : "\n";
83
+ // Whichever of ratifiedBy/ratifiedOn have no existing line get folded directly into the status
84
+ // edit's replacement text (inserted right after the new status value) rather than added as
85
+ // separate zero-length "insert" edits — simpler and unambiguous to splice than reasoning about
86
+ // an insert-edit's index coinciding with an adjacent replace-edit's span.
87
+ const missingLines = [];
88
+ if (!byMatch)
89
+ missingLines.push(`ratifiedBy: ${trimmedBy}`);
90
+ if (!onMatch)
91
+ missingLines.push(`ratifiedOn: ${ratifiedOn}`);
92
+ const newStatusText = `${statusMatch[1]}${RATIFIED_STATUS}`;
93
+ const statusNext = missingLines.length > 0 ? `${newStatusText}${eol}${missingLines.join(eol)}` : newStatusText;
94
+ // Apply from the highest index first so an earlier edit's index stays valid — same convention
95
+ // markImplemented.ts uses. Each present match (status always, ratifiedBy/ratifiedOn only when
96
+ // an existing line was found) is replaced independently of the others' positions, so this is
97
+ // safe even when the frontmatter's keys are out of the usual order.
98
+ const edits = [
99
+ { index: statusMatch.index, oldLen: statusMatch[0].length, next: statusNext },
100
+ ];
101
+ if (byMatch)
102
+ edits.push({ index: byMatch.index, oldLen: byMatch[0].length, next: `${byMatch[1]}${trimmedBy}` });
103
+ if (onMatch)
104
+ edits.push({ index: onMatch.index, oldLen: onMatch[0].length, next: `${onMatch[1]}${ratifiedOn}` });
105
+ edits.sort((a, b) => b.index - a.index);
106
+ let updatedInner = inner;
107
+ for (const edit of edits) {
108
+ updatedInner = updatedInner.slice(0, edit.index) + edit.next + updatedInner.slice(edit.index + edit.oldLen);
109
+ }
110
+ const content = raw.slice(0, range.innerStart) + updatedInner + raw.slice(range.innerEnd);
111
+ return { ok: true, content, changed: true };
112
+ }
113
+ /**
114
+ * Resolves `sliceKey` to its bound doc via the same note-binding join `mark-implemented`/
115
+ * `--slice-ready`/`em export` use (MIL-121 cross-binding included), then reads/applies/writes
116
+ * it. `baseDir` is the `.em` file's directory, same convention every doc/note path in `em` uses.
117
+ */
118
+ export function runRatify(model, refs, baseDir, sliceKey, ratifiedBy, ratifiedOn) {
119
+ const sliceIndex = refs.sliceKeys.indexOf(sliceKey);
120
+ if (sliceIndex === -1) {
121
+ return { ok: false, message: `no slice with export key "${sliceKey}" in this model` };
122
+ }
123
+ const slice = model.slices[sliceIndex];
124
+ const { doc } = resolveSliceDocJoin(slice, sliceKey, baseDir, (id) => refs.refById.get(id));
125
+ if (doc.reason === "no-doc-bound") {
126
+ return {
127
+ ok: false,
128
+ message: `slice "${sliceKey}" has no doc bound via \`note "slices/${sliceKey}.md"\` — bind a slice doc before ratifying it`,
129
+ };
130
+ }
131
+ if (doc.reason === "binding-missing-file") {
132
+ return { ok: false, message: `slice "${sliceKey}" notes "${doc.path}" but no such file exists` };
133
+ }
134
+ if (doc.reason === "frontmatter-invalid") {
135
+ return {
136
+ ok: false,
137
+ message: `slice doc "${doc.path}" has missing or invalid frontmatter — run \`em validate\` for details`,
138
+ };
139
+ }
140
+ const absPath = join(baseDir, doc.path);
141
+ const raw = readFileSync(absPath, "utf8");
142
+ const result = applyRatifyFrontmatter(raw, ratifiedBy, ratifiedOn);
143
+ if (!result.ok) {
144
+ return { ok: false, message: `${doc.path}: ${result.message}` };
145
+ }
146
+ if (result.changed) {
147
+ writeFileSync(absPath, result.content, "utf8");
148
+ }
149
+ return { ok: true, path: doc.path, changed: result.changed };
150
+ }
151
+ //# sourceMappingURL=ratify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ratify.js","sourceRoot":"","sources":["../../src/cli/ratify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { NormalizedModel } from "../model/model.js";
2
+ import { RefsResult } from "../model/refs.js";
3
+ export type ApplyReratifyResult = {
4
+ ok: true;
5
+ content: string;
6
+ newVersion: number;
7
+ } | {
8
+ ok: false;
9
+ message: string;
10
+ };
11
+ /**
12
+ * Pure text transform: bumps `version:` by 1 and flips `status:` to `ready-to-implement` in
13
+ * `raw`'s frontmatter block, clearing any `ratifiedBy:`/`ratifiedOn:` lines found (see module
14
+ * header). Refuses (`ok: false`) unless the doc's CURRENT `status:` is exactly `implemented` —
15
+ * see module header for why this precondition (not idempotent-no-op) is the right refusal
16
+ * shape here. No fs access — the caller reads/writes; see `runReratify` below.
17
+ */
18
+ export declare function applyReratifyFrontmatter(raw: string): ApplyReratifyResult;
19
+ export type RunReratifyResult = {
20
+ ok: true;
21
+ path: string;
22
+ newVersion: number;
23
+ } | {
24
+ ok: false;
25
+ message: string;
26
+ };
27
+ /**
28
+ * Resolves `sliceKey` to its bound doc via the same note-binding join `mark-implemented`/
29
+ * `ratify`/`--slice-ready`/`em export` use (MIL-121 cross-binding included), then reads/applies/
30
+ * writes it. `baseDir` is the `.em` file's directory, same convention every doc/note path in
31
+ * `em` uses.
32
+ */
33
+ export declare function runReratify(model: NormalizedModel, refs: RefsResult, baseDir: string, sliceKey: string): RunReratifyResult;
@@ -0,0 +1,137 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // `em slice reratify` (MIL-161 finding #4): the version-bump / status-flip mechanical edit
3
+ // SKILL.md's `slice` phase (step 0/2, re-ratification) has always described as "bump `version`
4
+ // and flip `status` back to `ready-to-implement` by hand" — the same shape `em slice
5
+ // mark-implemented` (MIL-103) already mechanized at the OTHER end of the lifecycle (the merge-
6
+ // time flip). Sets exactly two frontmatter fields on the doc resolved from the key via the SAME
7
+ // note-binding resolution `mark-implemented`/`ratify`/`--slice-ready`/`em export` use
8
+ // (catalog/docJoin.ts's resolveSliceDocJoin):
9
+ //
10
+ // version: <current + 1>
11
+ // status: ready-to-implement
12
+ //
13
+ // Only applies to a doc currently `status: implemented` — the precondition
14
+ // docs/slice-doc-schema.md#status-under-re-ratification describes ("a new version is ratified
15
+ // for a slice whose previous version already shipped"). Refuses (never guesses) otherwise: a
16
+ // `draft`/`reviewed` doc hasn't shipped yet, so there's no prior version to bump FROM, and a
17
+ // doc already `ready-to-implement` means either first-time authoring (never touch this doc with
18
+ // reratify at all — `em slice new` is what scaffolds those) or a reratify that already ran (a
19
+ // second bump would silently double-increment `version`, which this command deliberately never
20
+ // does — bumping isn't naturally idempotent the way ratify/mark-implemented's absolute-value
21
+ // writes are).
22
+ //
23
+ // Also clears `ratifiedBy:`/`ratifiedOn:` if either is present: those fields record who signed
24
+ // off the PRIOR version (`em slice ratify`, MIL-165) and describing the brand-new, not-yet-
25
+ // reviewed version as already ratified by the old signer would be actively misleading. Clearing
26
+ // them (rather than leaving them stale) is also what lets a subsequent `em slice ratify --by
27
+ // <name>` apply cleanly afterward — ratify's own idempotent-refusal guard would otherwise read
28
+ // the leftover prior ratifiedBy/ratifiedOn as "already ratified by someone else" and refuse.
29
+ //
30
+ // Write strategy: the same surgical index-math splicing markImplemented.ts/ratify.ts use, via
31
+ // the shared primitives in ./frontmatterSurgery.js — never a parse+re-serialize. Everything
32
+ // outside the edited value spans — the body, `implementedIn:`, the lineage/`covers` keys, and
33
+ // (best-effort) the file's own line-ending style — is copied through verbatim. The `## Delta`
34
+ // section (docs/slice-doc-schema.md#delta-section-grammar-and-lifecycle) recording WHAT changed
35
+ // stays entirely hand-authored — this command only ever touches the two lifecycle fields above.
36
+ import { readFileSync, writeFileSync } from "node:fs";
37
+ import { join } from "node:path";
38
+ import { resolveSliceDocJoin } from "../catalog/docJoin.js";
39
+ import { fieldLineRegex, fieldLineWithEolRegex, locateFrontmatterInner, normalizeFieldValue } from "./frontmatterSurgery.js";
40
+ /** The status a doc must already be in for `reratify` to apply — mirrors `RATIFIED_STATUS` in
41
+ * ratify.ts (the status this command flips TO), named separately since it's the precondition
42
+ * here, not the target. */
43
+ const IMPLEMENTED_STATUS = "implemented";
44
+ const TARGET_STATUS = "ready-to-implement";
45
+ /**
46
+ * Pure text transform: bumps `version:` by 1 and flips `status:` to `ready-to-implement` in
47
+ * `raw`'s frontmatter block, clearing any `ratifiedBy:`/`ratifiedOn:` lines found (see module
48
+ * header). Refuses (`ok: false`) unless the doc's CURRENT `status:` is exactly `implemented` —
49
+ * see module header for why this precondition (not idempotent-no-op) is the right refusal
50
+ * shape here. No fs access — the caller reads/writes; see `runReratify` below.
51
+ */
52
+ export function applyReratifyFrontmatter(raw) {
53
+ const range = locateFrontmatterInner(raw);
54
+ if (!range)
55
+ return { ok: false, message: "no frontmatter block found" };
56
+ const inner = raw.slice(range.innerStart, range.innerEnd);
57
+ const statusMatch = fieldLineRegex("status").exec(inner);
58
+ if (!statusMatch)
59
+ return { ok: false, message: "no `status:` field found in frontmatter" };
60
+ const currentStatus = normalizeFieldValue(statusMatch[2])?.toLowerCase() ?? null;
61
+ if (currentStatus !== IMPLEMENTED_STATUS) {
62
+ return {
63
+ ok: false,
64
+ message: `doc is \`status: ${currentStatus ?? "(empty)"}\`, not \`implemented\` — reratify only applies to a ` +
65
+ "slice doc that has already shipped (see docs/slice-doc-schema.md#status-under-re-ratification); " +
66
+ "first-time authoring uses `em slice new`, and a doc already `ready-to-implement` may already " +
67
+ "have been reratified",
68
+ };
69
+ }
70
+ const versionMatch = fieldLineRegex("version").exec(inner);
71
+ if (!versionMatch)
72
+ return { ok: false, message: "no `version:` field found in frontmatter" };
73
+ const currentVersionRaw = normalizeFieldValue(versionMatch[2]);
74
+ const currentVersion = currentVersionRaw !== null ? Number(currentVersionRaw) : NaN;
75
+ if (!Number.isInteger(currentVersion) || currentVersion < 1) {
76
+ return {
77
+ ok: false,
78
+ message: `doc's \`version:\` value "${currentVersionRaw ?? ""}" isn't a positive integer — refusing to guess a bump`,
79
+ };
80
+ }
81
+ const newVersion = currentVersion + 1;
82
+ // Apply from the highest index first so an earlier edit's index stays valid — same convention
83
+ // markImplemented.ts/ratify.ts use.
84
+ const edits = [
85
+ { index: statusMatch.index, oldLen: statusMatch[0].length, next: `${statusMatch[1]}${TARGET_STATUS}` },
86
+ { index: versionMatch.index, oldLen: versionMatch[0].length, next: `${versionMatch[1]}${newVersion}` },
87
+ ].sort((a, b) => b.index - a.index);
88
+ let updatedInner = inner;
89
+ for (const edit of edits) {
90
+ updatedInner = updatedInner.slice(0, edit.index) + edit.next + updatedInner.slice(edit.index + edit.oldLen);
91
+ }
92
+ // Clear stale ratifiedBy:/ratifiedOn: — see module header. A plain `.replace()` (not
93
+ // index-spliced alongside the edits above) is safe here: these two keys are disjoint from
94
+ // `status:`/`version:` by construction (fieldLineRegex matches one key at a time), so removing
95
+ // them from the ALREADY-updated text can't disturb the edits just applied.
96
+ updatedInner = updatedInner.replace(fieldLineWithEolRegex("ratifiedBy"), "").replace(fieldLineWithEolRegex("ratifiedOn"), "");
97
+ const content = raw.slice(0, range.innerStart) + updatedInner + raw.slice(range.innerEnd);
98
+ return { ok: true, content, newVersion };
99
+ }
100
+ /**
101
+ * Resolves `sliceKey` to its bound doc via the same note-binding join `mark-implemented`/
102
+ * `ratify`/`--slice-ready`/`em export` use (MIL-121 cross-binding included), then reads/applies/
103
+ * writes it. `baseDir` is the `.em` file's directory, same convention every doc/note path in
104
+ * `em` uses.
105
+ */
106
+ export function runReratify(model, refs, baseDir, sliceKey) {
107
+ const sliceIndex = refs.sliceKeys.indexOf(sliceKey);
108
+ if (sliceIndex === -1) {
109
+ return { ok: false, message: `no slice with export key "${sliceKey}" in this model` };
110
+ }
111
+ const slice = model.slices[sliceIndex];
112
+ const { doc } = resolveSliceDocJoin(slice, sliceKey, baseDir, (id) => refs.refById.get(id));
113
+ if (doc.reason === "no-doc-bound") {
114
+ return {
115
+ ok: false,
116
+ message: `slice "${sliceKey}" has no doc bound via \`note "slices/${sliceKey}.md"\` — bind a slice doc before reratifying it`,
117
+ };
118
+ }
119
+ if (doc.reason === "binding-missing-file") {
120
+ return { ok: false, message: `slice "${sliceKey}" notes "${doc.path}" but no such file exists` };
121
+ }
122
+ if (doc.reason === "frontmatter-invalid") {
123
+ return {
124
+ ok: false,
125
+ message: `slice doc "${doc.path}" has missing or invalid frontmatter — run \`em validate\` for details`,
126
+ };
127
+ }
128
+ const absPath = join(baseDir, doc.path);
129
+ const raw = readFileSync(absPath, "utf8");
130
+ const result = applyReratifyFrontmatter(raw);
131
+ if (!result.ok) {
132
+ return { ok: false, message: `${doc.path}: ${result.message}` };
133
+ }
134
+ writeFileSync(absPath, result.content, "utf8");
135
+ return { ok: true, path: doc.path, newVersion: result.newVersion };
136
+ }
137
+ //# sourceMappingURL=reratify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reratify.js","sourceRoot":"","sources":["../../src/cli/reratify.ts"],"names":[],"mappings":"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"}
@@ -16,3 +16,9 @@ export interface SkillCheckResult {
16
16
  * em-version: stamp. No process.exit, no console.
17
17
  */
18
18
  export declare function checkSkillSync(packagedDir: string, vendoredDir: string, installedVersion: string): SkillCheckResult;
19
+ /**
20
+ * Pure: checkSkillSync for every stamp-checked skill directory, plus content-drift-only
21
+ * (planSkillSync) for every shared directory. Same `SkillCheckResult` shape as checkSkillSync
22
+ * itself — a bundle check is just several single-directory checks with prefixed findings.
23
+ */
24
+ export declare function checkSkillSyncBundle(packagedRoot: string, vendoredRoot: string, installedVersion: string, skillDirNames: readonly string[], sharedDirNames: readonly string[]): SkillCheckResult;
@@ -60,4 +60,50 @@ export function checkSkillSync(packagedDir, vendoredDir, installedVersion) {
60
60
  }
61
61
  return { findings, ok: findings.length === 0 };
62
62
  }
63
+ // ---- Bundle variant (MIL-157) — the em skill ships as several sibling directories under
64
+ // `.claude/skills/` (see src/cli/skillDirs.ts): the stamp-checked skill directories (each with
65
+ // its own SKILL.md) and the shared, non-skill directories (reference/template material with no
66
+ // SKILL.md, so no stamp to check — content drift only). Findings from every directory are
67
+ // prefixed with `[<dirName>]` and their `driftedFiles` with `<dirName>/`, so a single aggregated
68
+ // report still tells you exactly which directory each finding concerns.
69
+ function prefixFinding(dirName, f) {
70
+ return {
71
+ ...f,
72
+ message: `[${dirName}] ${f.message}`,
73
+ driftedFiles: f.driftedFiles?.map((p) => `${dirName}/${p}`),
74
+ };
75
+ }
76
+ /**
77
+ * Pure: checkSkillSync for every stamp-checked skill directory, plus content-drift-only
78
+ * (planSkillSync) for every shared directory. Same `SkillCheckResult` shape as checkSkillSync
79
+ * itself — a bundle check is just several single-directory checks with prefixed findings.
80
+ */
81
+ export function checkSkillSyncBundle(packagedRoot, vendoredRoot, installedVersion, skillDirNames, sharedDirNames) {
82
+ const findings = [];
83
+ for (const name of skillDirNames) {
84
+ const result = checkSkillSync(join(packagedRoot, name), join(vendoredRoot, name), installedVersion);
85
+ for (const f of result.findings)
86
+ findings.push(prefixFinding(name, f));
87
+ }
88
+ for (const name of sharedDirNames) {
89
+ const vendoredDir = join(vendoredRoot, name);
90
+ if (!existsSync(vendoredDir)) {
91
+ findings.push(prefixFinding(name, {
92
+ code: "skill-check-not-installed",
93
+ message: `no vendored skill found at ${vendoredDir} — run \`em skill sync\` first`,
94
+ }));
95
+ continue;
96
+ }
97
+ const plan = planSkillSync(join(packagedRoot, name), vendoredDir);
98
+ if (plan.changes.length > 0) {
99
+ const driftedFiles = plan.changes.map((c) => c.relPath).sort();
100
+ findings.push(prefixFinding(name, {
101
+ code: "skill-check-content-drift",
102
+ message: `vendored skill differs from the packaged skill in ${driftedFiles.length} file(s) — run \`em skill sync\``,
103
+ driftedFiles,
104
+ }));
105
+ }
106
+ }
107
+ return { findings, ok: findings.length === 0 };
108
+ }
63
109
  //# sourceMappingURL=skillCheck.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"skillCheck.js","sourceRoot":"","sources":["../../src/cli/skillCheck.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,6FAA6F;AAC7F,0FAA0F;AAC1F,6FAA6F;AAC7F,6FAA6F;AAC7F,kFAAkF;AAClF,uDAAuD;AACvD,EAAE;AACF,+EAA+E;AAC/E,kFAAkF;AAClF,+FAA+F;AAC/F,0FAA0F;AAC1F,iEAAiE;AAEjE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAqB/C;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,WAAmB,EAAE,WAAmB,EAAE,gBAAwB;IAC/F,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,2BAA2B;oBACjC,OAAO,EAAE,8BAA8B,WAAW,gCAAgC;iBACnF;aACF;SACF,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAwB,EAAE,CAAC;IAEzC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IAClD,MAAM,aAAa,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEhH,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;QAC3B,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,2BAA2B;YACjC,OAAO,EAAE,GAAG,WAAW,8EAA8E;SACtG,CAAC,CAAC;IACL,CAAC;SAAM,IAAI,aAAa,KAAK,gBAAgB,EAAE,CAAC;QAC9C,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,4BAA4B;YAClC,OAAO,EAAE,uCAAuC,aAAa,iCAAiC,gBAAgB,2BAA2B;YACzI,aAAa;YACb,gBAAgB;SACjB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,IAAI,GAAG,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACrD,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/D,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,2BAA2B;YACjC,OAAO,EAAE,qDAAqD,YAAY,CAAC,MAAM,kCAAkC;YACnH,YAAY;SACb,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;AACjD,CAAC"}
1
+ {"version":3,"file":"skillCheck.js","sourceRoot":"","sources":["../../src/cli/skillCheck.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,6FAA6F;AAC7F,0FAA0F;AAC1F,6FAA6F;AAC7F,6FAA6F;AAC7F,kFAAkF;AAClF,uDAAuD;AACvD,EAAE;AACF,+EAA+E;AAC/E,kFAAkF;AAClF,+FAA+F;AAC/F,0FAA0F;AAC1F,iEAAiE;AAEjE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAqB/C;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,WAAmB,EAAE,WAAmB,EAAE,gBAAwB;IAC/F,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,2BAA2B;oBACjC,OAAO,EAAE,8BAA8B,WAAW,gCAAgC;iBACnF;aACF;SACF,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAwB,EAAE,CAAC;IAEzC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IAClD,MAAM,aAAa,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEhH,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;QAC3B,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,2BAA2B;YACjC,OAAO,EAAE,GAAG,WAAW,8EAA8E;SACtG,CAAC,CAAC;IACL,CAAC;SAAM,IAAI,aAAa,KAAK,gBAAgB,EAAE,CAAC;QAC9C,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,4BAA4B;YAClC,OAAO,EAAE,uCAAuC,aAAa,iCAAiC,gBAAgB,2BAA2B;YACzI,aAAa;YACb,gBAAgB;SACjB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,IAAI,GAAG,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACrD,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/D,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,2BAA2B;YACjC,OAAO,EAAE,qDAAqD,YAAY,CAAC,MAAM,kCAAkC;YACnH,YAAY;SACb,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;AACjD,CAAC;AAED,0FAA0F;AAC1F,+FAA+F;AAC/F,+FAA+F;AAC/F,0FAA0F;AAC1F,iGAAiG;AACjG,wEAAwE;AAExE,SAAS,aAAa,CAAC,OAAe,EAAE,CAAoB;IAC1D,OAAO;QACL,GAAG,CAAC;QACJ,OAAO,EAAE,IAAI,OAAO,KAAK,CAAC,CAAC,OAAO,EAAE;QACpC,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,OAAO,IAAI,CAAC,EAAE,CAAC;KAC5D,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,YAAoB,EACpB,YAAoB,EACpB,gBAAwB,EACxB,aAAgC,EAChC,cAAiC;IAEjC,MAAM,QAAQ,GAAwB,EAAE,CAAC;IAEzC,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,gBAAgB,CAAC,CAAC;QACpG,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ;YAAE,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACzE,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;QAClC,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC7B,QAAQ,CAAC,IAAI,CACX,aAAa,CAAC,IAAI,EAAE;gBAClB,IAAI,EAAE,2BAA2B;gBACjC,OAAO,EAAE,8BAA8B,WAAW,gCAAgC;aACnF,CAAC,CACH,CAAC;YACF,SAAS;QACX,CAAC;QACD,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC;QAClE,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;YAC/D,QAAQ,CAAC,IAAI,CACX,aAAa,CAAC,IAAI,EAAE;gBAClB,IAAI,EAAE,2BAA2B;gBACjC,OAAO,EAAE,qDAAqD,YAAY,CAAC,MAAM,kCAAkC;gBACnH,YAAY;aACb,CAAC,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;AACjD,CAAC"}
@@ -0,0 +1,15 @@
1
+ /** Directories with their own SKILL.md (a `name:`/`description:`/`em-version:` frontmatter and
2
+ * Claude Code entry point). Order is display order only, not load-bearing. */
3
+ export declare const EM_SKILL_DIR_NAMES: readonly string[];
4
+ /** Directories with no SKILL.md of their own — shared reference/template material every skill
5
+ * above points back to instead of duplicating. Still part of the sync/check bundle (content
6
+ * drift matters here too), just never stamp-checked for an `em-version:` frontmatter that
7
+ * doesn't exist. */
8
+ export declare const EM_SHARED_DIR_NAMES: readonly string[];
9
+ /** Every directory `em skill install`/`sync`/`check` treat as part of the one bundle. */
10
+ export declare const EM_ALL_SKILL_BUNDLE_DIRS: readonly string[];
11
+ /** The one directory whose presence/absence gates the bundle as a whole (used by `em skill
12
+ * install`'s already-installed check and `em ci init`'s generated CI gate) — the router skill,
13
+ * since it's the fixed entry point every consumer's `/event-modeling` resolves to regardless of
14
+ * which other skills in the bundle they've actually used. */
15
+ export declare const EM_SKILL_ANCHOR_DIR = "event-modeling";
@@ -0,0 +1,34 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // The set of directories under `.claude/skills/` that together make up the em-bundled
3
+ // event-modeling skill (MIL-157): five focused, SDLC-stage skills plus the thin `event-modeling`
4
+ // router skill that preserves `/event-modeling` as a single resumable entry point, and one
5
+ // non-skill directory (`event-modeling-shared`, no SKILL.md) holding reference/template material
6
+ // every skill points back to instead of duplicating. `em skill install`/`sync`/`check` treat this
7
+ // whole set as one atomic bundle — installing/syncing/checking all of it in one command, exactly
8
+ // like before the split (MIL-93) — so a consumer repo's `.claude/skills/` never needs per-skill
9
+ // awareness, and unrelated skills already living in that directory (this em bundle isn't the only
10
+ // thing that can be there) are never touched: only these named directories are ever walked, never
11
+ // `.claude/skills/` wholesale.
12
+ /** Directories with their own SKILL.md (a `name:`/`description:`/`em-version:` frontmatter and
13
+ * Claude Code entry point). Order is display order only, not load-bearing. */
14
+ export const EM_SKILL_DIR_NAMES = [
15
+ "event-modeling",
16
+ "event-modeling-discover",
17
+ "event-modeling-design",
18
+ "event-modeling-implement",
19
+ "event-modeling-conform",
20
+ "event-modeling-review",
21
+ ];
22
+ /** Directories with no SKILL.md of their own — shared reference/template material every skill
23
+ * above points back to instead of duplicating. Still part of the sync/check bundle (content
24
+ * drift matters here too), just never stamp-checked for an `em-version:` frontmatter that
25
+ * doesn't exist. */
26
+ export const EM_SHARED_DIR_NAMES = ["event-modeling-shared"];
27
+ /** Every directory `em skill install`/`sync`/`check` treat as part of the one bundle. */
28
+ export const EM_ALL_SKILL_BUNDLE_DIRS = [...EM_SKILL_DIR_NAMES, ...EM_SHARED_DIR_NAMES];
29
+ /** The one directory whose presence/absence gates the bundle as a whole (used by `em skill
30
+ * install`'s already-installed check and `em ci init`'s generated CI gate) — the router skill,
31
+ * since it's the fixed entry point every consumer's `/event-modeling` resolves to regardless of
32
+ * which other skills in the bundle they've actually used. */
33
+ export const EM_SKILL_ANCHOR_DIR = "event-modeling";
34
+ //# sourceMappingURL=skillDirs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skillDirs.js","sourceRoot":"","sources":["../../src/cli/skillDirs.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,sFAAsF;AACtF,iGAAiG;AACjG,2FAA2F;AAC3F,iGAAiG;AACjG,kGAAkG;AAClG,iGAAiG;AACjG,gGAAgG;AAChG,kGAAkG;AAClG,kGAAkG;AAClG,+BAA+B;AAE/B;+EAC+E;AAC/E,MAAM,CAAC,MAAM,kBAAkB,GAAsB;IACnD,gBAAgB;IAChB,yBAAyB;IACzB,uBAAuB;IACvB,0BAA0B;IAC1B,wBAAwB;IACxB,uBAAuB;CACxB,CAAC;AAEF;;;qBAGqB;AACrB,MAAM,CAAC,MAAM,mBAAmB,GAAsB,CAAC,uBAAuB,CAAC,CAAC;AAEhF,yFAAyF;AACzF,MAAM,CAAC,MAAM,wBAAwB,GAAsB,CAAC,GAAG,kBAAkB,EAAE,GAAG,mBAAmB,CAAC,CAAC;AAE3G;;;8DAG8D;AAC9D,MAAM,CAAC,MAAM,mBAAmB,GAAG,gBAAgB,CAAC"}