@milehimikey/em 1.7.2 → 1.8.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.
- package/.claude/skills/event-modeling/SKILL.md +92 -65
- package/.claude/skills/event-modeling/reference/conform.md +45 -20
- package/.claude/skills/event-modeling/reference/em-dsl.md +132 -55
- package/.claude/skills/event-modeling/reference/extract.md +5 -4
- package/.claude/skills/event-modeling/reference/implement.md +34 -22
- package/.claude/skills/event-modeling/templates/model-readme.md +8 -5
- package/.claude/skills/event-modeling/templates/slice.md +19 -5
- package/README.md +6 -4
- package/dist/catalog/docJoin.d.ts +28 -3
- package/dist/catalog/docJoin.js +82 -13
- package/dist/catalog/docJoin.js.map +1 -1
- package/dist/catalog/docModelConsistencyValidate.d.ts +8 -0
- package/dist/catalog/docModelConsistencyValidate.js +335 -0
- package/dist/catalog/docModelConsistencyValidate.js.map +1 -0
- package/dist/catalog/noteBindingValidate.d.ts +8 -0
- package/dist/catalog/noteBindingValidate.js +133 -0
- package/dist/catalog/noteBindingValidate.js.map +1 -0
- package/dist/catalog/pages.js +3 -3
- package/dist/catalog/pages.js.map +1 -1
- package/dist/catalog/sliceDoc.d.ts +14 -0
- package/dist/catalog/sliceDoc.js +22 -0
- package/dist/catalog/sliceDoc.js.map +1 -1
- package/dist/catalog/sliceReadyValidate.d.ts +18 -0
- package/dist/catalog/sliceReadyValidate.js +25 -1
- package/dist/catalog/sliceReadyValidate.js.map +1 -1
- package/dist/cli/agentsMd.d.ts +15 -0
- package/dist/cli/agentsMd.js +72 -0
- package/dist/cli/agentsMd.js.map +1 -0
- package/dist/cli/conformScope.d.ts +86 -0
- package/dist/cli/conformScope.js +156 -0
- package/dist/cli/conformScope.js.map +1 -0
- package/dist/cli/contract.d.ts +7 -0
- package/dist/cli/contract.js +27 -0
- package/dist/cli/contract.js.map +1 -0
- package/dist/cli/coverage.d.ts +71 -0
- package/dist/cli/coverage.js +177 -0
- package/dist/cli/coverage.js.map +1 -0
- package/dist/cli/markImplemented.d.ts +34 -0
- package/dist/cli/markImplemented.js +180 -0
- package/dist/cli/markImplemented.js.map +1 -0
- package/dist/cli/migrateReactionShape.d.ts +62 -0
- package/dist/cli/migrateReactionShape.js +283 -0
- package/dist/cli/migrateReactionShape.js.map +1 -0
- package/dist/cli/sliceIndex.d.ts +49 -0
- package/dist/cli/sliceIndex.js +115 -0
- package/dist/cli/sliceIndex.js.map +1 -0
- package/dist/cli/sliceNew.d.ts +18 -0
- package/dist/cli/sliceNew.js +53 -0
- package/dist/cli/sliceNew.js.map +1 -0
- package/dist/cli/stateFile.d.ts +74 -0
- package/dist/cli/stateFile.js +191 -0
- package/dist/cli/stateFile.js.map +1 -0
- package/dist/cli.js +535 -43
- package/dist/cli.js.map +1 -1
- package/dist/emit/coverageJson.d.ts +8 -0
- package/dist/emit/coverageJson.js +30 -0
- package/dist/emit/coverageJson.js.map +1 -0
- package/dist/emit/diffJson.d.ts +9 -1
- package/dist/emit/diffJson.js +44 -1
- package/dist/emit/diffJson.js.map +1 -1
- package/dist/emit/dot.js +41 -10
- package/dist/emit/dot.js.map +1 -1
- package/dist/emit/json.d.ts +77 -4
- package/dist/emit/json.js +78 -4
- package/dist/emit/json.js.map +1 -1
- package/dist/emit/validateJson.d.ts +52 -0
- package/dist/emit/validateJson.js +120 -0
- package/dist/emit/validateJson.js.map +1 -0
- package/dist/mcp/main.d.ts +2 -0
- package/dist/mcp/main.js +20 -0
- package/dist/mcp/main.js.map +1 -0
- package/dist/mcp/server.d.ts +11 -0
- package/dist/mcp/server.js +260 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/model/model.d.ts +30 -1
- package/dist/model/model.js +26 -0
- package/dist/model/model.js.map +1 -1
- package/dist/model/rules.d.ts +114 -0
- package/dist/model/rules.js +116 -4
- package/dist/model/rules.js.map +1 -1
- package/dist/model/validate.js +92 -8
- package/dist/model/validate.js.map +1 -1
- package/dist/parser/ast.d.ts +47 -0
- package/dist/parser/lexer.d.ts +16 -0
- package/dist/parser/lexer.js +44 -2
- package/dist/parser/lexer.js.map +1 -1
- package/dist/parser/parser.js +354 -20
- package/dist/parser/parser.js.map +1 -1
- package/dist/render/drawNotes.d.ts +11 -1
- package/dist/render/drawNotes.js +28 -3
- package/dist/render/drawNotes.js.map +1 -1
- package/dist/render/render.js +116 -23
- package/dist/render/render.js.map +1 -1
- package/dist/render/serve.d.ts +4 -0
- package/dist/render/serve.js +27 -239
- package/dist/render/serve.js.map +1 -1
- package/dist/render/sliceOverlay.d.ts +7 -2
- package/dist/render/sliceOverlay.js +19 -7
- package/dist/render/sliceOverlay.js.map +1 -1
- package/dist/render/sliceStatus.d.ts +7 -3
- package/dist/render/sliceStatus.js +48 -12
- package/dist/render/sliceStatus.js.map +1 -1
- package/dist/render/viewerHtml.d.ts +1 -0
- package/dist/render/viewerHtml.js +5 -0
- package/dist/render/viewerHtml.js.map +1 -0
- package/dist/render/watch.d.ts +10 -0
- package/dist/render/watch.js +29 -0
- package/dist/render/watch.js.map +1 -1
- package/dist/templates.d.ts +20 -1
- package/dist/templates.js +172 -3
- package/dist/templates.js.map +1 -1
- package/dist/util/markers.d.ts +13 -0
- package/dist/util/markers.js +30 -0
- package/dist/util/markers.js.map +1 -0
- package/dist/util/walkDir.d.ts +10 -1
- package/dist/util/walkDir.js +11 -7
- package/dist/util/walkDir.js.map +1 -1
- package/package.json +12 -3
- package/.claude/skills/event-modeling/templates/live.html +0 -117
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// `em validate`'s note-binding mismatch check (MIL-126): stops a slice-doc-shaped `note` from
|
|
3
|
+
// being silently discarded when it doesn't actually participate in the slice's resolved doc
|
|
4
|
+
// binding. Follow-on to MIL-121 (cross-slice `covers:` binding) — that ticket deliberately left
|
|
5
|
+
// every non-ratifying cross-note silent ("that's MIL-126"); this module is where the silence
|
|
6
|
+
// ends. Same fs-aware-sibling shape as catalog/lineageValidate.ts (MIL-84) and
|
|
7
|
+
// catalog/frontmatterCoherenceValidate.ts (MIL-85): a module next to model/validate.ts, not
|
|
8
|
+
// folded into it, because resolving a slice's doc needs `baseDir`/fs access the rest of validate
|
|
9
|
+
// deliberately never touches.
|
|
10
|
+
//
|
|
11
|
+
// Only `note`s shaped like `slices/<key>.md` (`docJoin.ts`'s `NOTE_SLICE_PATH`, case-insensitive)
|
|
12
|
+
// are this module's business — `note` is a general annotation mechanism rendered on diagrams
|
|
13
|
+
// (src/render/drawNotes.ts) for freeform text files, other paths, anything at all; a note that
|
|
14
|
+
// was never trying to bind a slice doc in the first place must never warn here.
|
|
15
|
+
//
|
|
16
|
+
// For each slice, first resolve what it's ACTUALLY bound to — mirroring resolveSliceDocJoin's
|
|
17
|
+
// own precedence exactly (canonical note first, else the first ratified cross-binding in element
|
|
18
|
+
// order, reusing `resolveCrossCandidate` so the two modules can't disagree on "ratifies"). Then
|
|
19
|
+
// walk every doc-shaped note again and classify it against that resolution:
|
|
20
|
+
//
|
|
21
|
+
// - A note that equals the slice's OWN canonical path (`slices/<sliceKey>.md`, exact match) is
|
|
22
|
+
// always fine, whether or not the doc behind it actually resolves — MIL-91's
|
|
23
|
+
// `binding-missing-file`/`frontmatter-invalid` already cover a broken canonical doc; this
|
|
24
|
+
// module would only be duplicating them.
|
|
25
|
+
// - A note whose (normalized) path equals the slice's resolved bound path — canonical or the
|
|
26
|
+
// winning cross-binding — is fine too; multiple elements can legitimately carry the same
|
|
27
|
+
// winning note (`resolveSliceDocJoin`'s own `boundEls` semantics).
|
|
28
|
+
// - Anything else warns, with a reason:
|
|
29
|
+
// * the slice IS bound (to a different path) — `note-binding-extra`: this note is simply
|
|
30
|
+
// ignored. Covers both an extra note in an already-(canonically-)bound slice AND a
|
|
31
|
+
// second, later, also-technically-ratifiable cross-note losing to an earlier one
|
|
32
|
+
// (MIL-121's "first wins") — from this note's point of view both read the same: "the
|
|
33
|
+
// slice is already bound elsewhere, this note does nothing."
|
|
34
|
+
// * the slice is UNBOUND, and this note's own candidate resolution says why it couldn't
|
|
35
|
+
// become the binding: `note-binding-dangling` (file missing), `note-binding-unusable`
|
|
36
|
+
// (frontmatter unusable), or `note-binding-unratified` (usable doc, but its `covers:`
|
|
37
|
+
// doesn't name this slice).
|
|
38
|
+
//
|
|
39
|
+
// A note naming this slice's own key but in the wrong case (`note "slices/Checkout.md"` on
|
|
40
|
+
// slice "checkout") is deliberately NOT special-cased: `resolveSliceDocJoin`'s canonical check is
|
|
41
|
+
// exact-string, so a case-mismatched self-note can never bind canonically, and its cross-search
|
|
42
|
+
// skips same-key candidates outright (`resolveSliceDocJoin`'s own `if (otherKey === sliceKey)
|
|
43
|
+
// continue`) — the exact-case behavior predates this ticket. This module mirrors that same skip
|
|
44
|
+
// rather than inventing a new case-sensitivity linter MIL-126 never asked for; such a note stays
|
|
45
|
+
// exactly as inert as it always was.
|
|
46
|
+
import { pushDiag } from "../model/rules.js";
|
|
47
|
+
import { NOTE_SLICE_PATH, resolveCrossCandidate } from "./docJoin.js";
|
|
48
|
+
/**
|
|
49
|
+
* Resolve every slice's note-binding mismatches. `baseDir` is the `.em` file's directory, same
|
|
50
|
+
* convention every other doc/note path in em uses.
|
|
51
|
+
*/
|
|
52
|
+
export function validateNoteBindings(model, refs, baseDir) {
|
|
53
|
+
const diags = [];
|
|
54
|
+
model.slices.forEach((slice, sliceIndex) => {
|
|
55
|
+
const sliceKey = refs.sliceKeys[sliceIndex];
|
|
56
|
+
const canonicalPath = `slices/${sliceKey}.md`;
|
|
57
|
+
const hasCanonical = slice.elements.some((el) => el.note === canonicalPath);
|
|
58
|
+
// Mirrors resolveSliceDocJoin's own precedence exactly: canonical (any element noting the
|
|
59
|
+
// exact own path, regardless of whether that doc actually resolves) wins outright; otherwise
|
|
60
|
+
// the first ratified cross-binding candidate in element order. `boundPath` is null when
|
|
61
|
+
// neither applies — the slice is genuinely unbound.
|
|
62
|
+
let boundPath = null;
|
|
63
|
+
if (hasCanonical) {
|
|
64
|
+
boundPath = canonicalPath;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
for (const el of slice.elements) {
|
|
68
|
+
if (!el.note)
|
|
69
|
+
continue;
|
|
70
|
+
const m = el.note.match(NOTE_SLICE_PATH);
|
|
71
|
+
if (!m)
|
|
72
|
+
continue;
|
|
73
|
+
const candidateKey = m[1].toLowerCase();
|
|
74
|
+
if (candidateKey === sliceKey)
|
|
75
|
+
continue; // same self-key skip resolveSliceDocJoin makes
|
|
76
|
+
if (resolveCrossCandidate(baseDir, candidateKey, sliceKey).status === "ratified") {
|
|
77
|
+
boundPath = `slices/${candidateKey}.md`;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
for (const el of slice.elements) {
|
|
83
|
+
if (!el.note || el.note === canonicalPath)
|
|
84
|
+
continue; // absent, or the canonical slot itself
|
|
85
|
+
const m = el.note.match(NOTE_SLICE_PATH);
|
|
86
|
+
if (!m)
|
|
87
|
+
continue; // not doc-shaped at all — a freeform annotation, never this module's business
|
|
88
|
+
const candidateKey = m[1].toLowerCase();
|
|
89
|
+
if (candidateKey === sliceKey)
|
|
90
|
+
continue; // case-mismatched self-note — see header comment
|
|
91
|
+
const candidatePath = `slices/${candidateKey}.md`;
|
|
92
|
+
const elementRefs = [sliceKey, refs.refById.get(el.id)];
|
|
93
|
+
if (boundPath !== null) {
|
|
94
|
+
if (candidatePath === boundPath)
|
|
95
|
+
continue; // agrees with the resolved binding — fine
|
|
96
|
+
pushDiag(diags, "note-binding-extra", {
|
|
97
|
+
message: `slice "${slice.name}" is already bound to "${boundPath}"${boundPath === canonicalPath ? "" : " (a ratified cross-binding)"} — this note's "${el.note}" is ignored`,
|
|
98
|
+
line: el.line,
|
|
99
|
+
refs: elementRefs,
|
|
100
|
+
});
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
// Slice is unbound — classify why THIS candidate specifically didn't become the binding.
|
|
104
|
+
const result = resolveCrossCandidate(baseDir, candidateKey, sliceKey);
|
|
105
|
+
if (result.status === "missing") {
|
|
106
|
+
pushDiag(diags, "note-binding-dangling", {
|
|
107
|
+
message: `slice "${slice.name}" notes "${el.note}" but no such file exists — dangling, ignored`,
|
|
108
|
+
line: el.line,
|
|
109
|
+
refs: elementRefs,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
else if (result.status === "unusable") {
|
|
113
|
+
pushDiag(diags, "note-binding-unusable", {
|
|
114
|
+
message: `slice "${slice.name}" notes "${el.note}", but that doc's frontmatter isn't usable, so it can't ratify coverage of this slice`,
|
|
115
|
+
line: el.line,
|
|
116
|
+
refs: elementRefs,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
// result.status === "unratified" — the only remaining case: "ratified" is unreachable
|
|
121
|
+
// here, since a ratified non-self candidate would already have set `boundPath` above
|
|
122
|
+
// (self-key candidates, the one exception, were already skipped in this same loop).
|
|
123
|
+
pushDiag(diags, "note-binding-unratified", {
|
|
124
|
+
message: `slice "${slice.name}" notes "${el.note}", but that doc's \`covers:\` doesn't list "${sliceKey}" — add \`covers: ${sliceKey}\` there, or correct this note's path`,
|
|
125
|
+
line: el.line,
|
|
126
|
+
refs: elementRefs,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
return diags;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=noteBindingValidate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"noteBindingValidate.js","sourceRoot":"","sources":["../../src/catalog/noteBindingValidate.ts"],"names":[],"mappings":"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"}
|
package/dist/catalog/pages.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
// HTML-string builders for `em catalog`'s static site: an index page and one
|
|
3
3
|
// per-slice detail page. Hand-written template literals, no templating
|
|
4
|
-
// library
|
|
5
|
-
// src/render/
|
|
6
|
-
//
|
|
4
|
+
// library. (The live-viewer page went the other way — a real HTML file,
|
|
5
|
+
// src/render/viewer.html, shipped as a generated constant — because it is one
|
|
6
|
+
// static 600-line page; these stay literals since they vary per model/slice.)
|
|
7
7
|
import { slicePatternLabel } from "./classify.js";
|
|
8
8
|
export function escapeHtml(s) {
|
|
9
9
|
return s
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/catalog/pages.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,6EAA6E;AAC7E,uEAAuE;AACvE,
|
|
1
|
+
{"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/catalog/pages.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,6 +24,12 @@ export interface SliceDoc {
|
|
|
24
24
|
* `- **Status:** ...` bullet line, or null if neither is found (a freeform
|
|
25
25
|
* doc that doesn't follow the slice.md template). */
|
|
26
26
|
status: string | null;
|
|
27
|
+
/** Lowercased `pattern:` frontmatter value (`state-change`/`state-view`/`automation`/
|
|
28
|
+
* `translation`, per the template) — frontmatter-only, no legacy body form. Authored/
|
|
29
|
+
* informational per docs/slice-doc-schema.md, but MIL-124's doc-model-consistency check
|
|
30
|
+
* (catalog/docModelConsistencyValidate.ts) is the first `em` consumer that reads it back, to
|
|
31
|
+
* compare against `classify.ts`'s deterministic `classifySlicePattern()`. Null when absent. */
|
|
32
|
+
pattern: string | null;
|
|
27
33
|
/** This slice's own ratified-content version, from frontmatter `version:`
|
|
28
34
|
* (e.g. `version: 1`) — a cache of git truth (docset module 06), not
|
|
29
35
|
* derived or validated against git history. Null when absent or
|
|
@@ -45,6 +51,14 @@ export interface SliceDoc {
|
|
|
45
51
|
/** Frontmatter `implementedIn:` — free text, typically a PR/commit link — or null
|
|
46
52
|
* when absent. No legacy bullet-line form, same as `version`/lineage. */
|
|
47
53
|
implementedIn: string | null;
|
|
54
|
+
/** MIL-121: slice keys (comma-separated, lowercased, plain — NOT `<key>@v<N>` refs like the
|
|
55
|
+
* lineage keys above) this doc ratifies coverage for, from frontmatter `covers:`. This is the
|
|
56
|
+
* other end of the two-ended cross-binding handshake: a slice with no doc of its own may
|
|
57
|
+
* `note "slices/<this-doc's-key>.md"` on one of its elements, and docJoin.ts (`em export`'s
|
|
58
|
+
* doc join) only honors that note as a binding when the noted doc's own `covers` list names
|
|
59
|
+
* the noting slice back. Empty array when absent — the common case; a doc always covers its
|
|
60
|
+
* own canonical slice key implicitly and never needs to list it here. */
|
|
61
|
+
covers: string[];
|
|
48
62
|
/** True when a well-formed leading `---`/`---` frontmatter fence was found and
|
|
49
63
|
* closed — independent of which keys it contained. False for a legacy
|
|
50
64
|
* status-bullet-only doc, a doc with no frontmatter at all, or an
|
package/dist/catalog/sliceDoc.js
CHANGED
|
@@ -26,6 +26,13 @@
|
|
|
26
26
|
// classify a doc as `frontmatter-invalid` — no frontmatter fence at all, or
|
|
27
27
|
// missing one of the keys docs/slice-doc-schema.md says are required at every
|
|
28
28
|
// status — without export re-deriving frontmatter-shape rules of its own.
|
|
29
|
+
//
|
|
30
|
+
// `covers` (MIL-121) is a fourth optional frontmatter-only field, alongside
|
|
31
|
+
// `implementedIn`/lineage: a plain list of slice keys (not `<key>@v<N>` refs) this doc also
|
|
32
|
+
// ratifies coverage for, so a different slice can bind to THIS doc via a cross-slice
|
|
33
|
+
// `note "slices/<this-key>.md"` instead of authoring its own. Parsed the same
|
|
34
|
+
// comma-separated-list shape as `merged-from`/`superseded-by`; see docJoin.ts for the
|
|
35
|
+
// two-ended handshake that actually uses it.
|
|
29
36
|
import { marked } from "marked";
|
|
30
37
|
/** Frontmatter keys docs/slice-doc-schema.md's required-vs-optional table marks
|
|
31
38
|
* required at every `status` — the mechanical basis for `frontmatter-invalid`
|
|
@@ -102,6 +109,19 @@ function parseSliceRefList(raw) {
|
|
|
102
109
|
.filter(Boolean)
|
|
103
110
|
.map(parseSliceRef);
|
|
104
111
|
}
|
|
112
|
+
/** Parses `covers:` (MIL-121) — a comma-separated list of plain slice-key strings, NOT the
|
|
113
|
+
* `<slice-key>@v<N>` ref grammar `parseSliceRefList` handles: coverage isn't versioned, it's a
|
|
114
|
+
* standing "this doc also serves that slice" declaration, so there's no version component to
|
|
115
|
+
* parse or preserve. Lowercased to match `sliceKey` comparisons everywhere else (kebabSlug()
|
|
116
|
+
* output, and the export keys docJoin.ts compares against). */
|
|
117
|
+
function parseKeyList(raw) {
|
|
118
|
+
if (!raw)
|
|
119
|
+
return [];
|
|
120
|
+
return raw
|
|
121
|
+
.split(",")
|
|
122
|
+
.map((s) => s.trim().toLowerCase())
|
|
123
|
+
.filter(Boolean);
|
|
124
|
+
}
|
|
105
125
|
function parseVersion(raw) {
|
|
106
126
|
if (!raw)
|
|
107
127
|
return null;
|
|
@@ -155,11 +175,13 @@ export function parseSliceDoc(markdown) {
|
|
|
155
175
|
raw: markdown,
|
|
156
176
|
body,
|
|
157
177
|
status,
|
|
178
|
+
pattern: fields.get("pattern")?.toLowerCase() ?? null,
|
|
158
179
|
version: parseVersion(fields.get("version")),
|
|
159
180
|
splitFrom: splitFromRaw ? parseSliceRef(splitFromRaw) : null,
|
|
160
181
|
mergedFrom: parseSliceRefList(fields.get("merged-from")),
|
|
161
182
|
supersededBy: parseSliceRefList(fields.get("superseded-by")),
|
|
162
183
|
implementedIn: fields.get("implementedin") ?? null,
|
|
184
|
+
covers: parseKeyList(fields.get("covers")),
|
|
163
185
|
frontmatterPresent,
|
|
164
186
|
missingRequiredFields: REQUIRED_FRONTMATTER_KEYS.filter((k) => !fields.has(k)),
|
|
165
187
|
html: marked.parse(body, { async: false }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sliceDoc.js","sourceRoot":"","sources":["../../src/catalog/sliceDoc.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,yDAAyD;AACzD,2EAA2E;AAC3E,2EAA2E;AAC3E,8EAA8E;AAC9E,4EAA4E;AAC5E,8EAA8E;AAC9E,iEAAiE;AACjE,EAAE;AACF,2EAA2E;AAC3E,2EAA2E;AAC3E,6EAA6E;AAC7E,8EAA8E;AAC9E,2EAA2E;AAC3E,yEAAyE;AACzE,EAAE;AACF,oEAAoE;AACpE,wEAAwE;AACxE,kFAAkF;AAClF,8EAA8E;AAC9E,8EAA8E;AAC9E,6EAA6E;AAC7E,EAAE;AACF,8EAA8E;AAC9E,4EAA4E;AAC5E,4EAA4E;AAC5E,8EAA8E;AAC9E,0EAA0E;
|
|
1
|
+
{"version":3,"file":"sliceDoc.js","sourceRoot":"","sources":["../../src/catalog/sliceDoc.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,3 +9,21 @@ import { Diagnostic } from "../model/validate.js";
|
|
|
9
9
|
* flag in src/cli.ts is what decides whether these warnings gate the exit code.
|
|
10
10
|
*/
|
|
11
11
|
export declare function validateSliceReady(model: NormalizedModel, refs: RefsResult, baseDir: string, sliceKey: string): Diagnostic[];
|
|
12
|
+
/** The 4 named gate conditions `em validate --slice-ready <key> --json` reports individually
|
|
13
|
+
* (MIL-128): doc bound, frontmatter usable, status ready-to-implement, no unchecked Open
|
|
14
|
+
* Questions — the exact facts `validateSliceReady` above already derives from the same doc
|
|
15
|
+
* join and parse, exposed as independent pass/fail booleans instead of collapsed into
|
|
16
|
+
* short-circuited diagnostics, so a JSON consumer sees exactly which gate(s) failed without
|
|
17
|
+
* re-deriving anything or parsing prose. `null` when `sliceKey` names no slice in the model —
|
|
18
|
+
* mirrors `slice-ready-unknown-slice`'s error case, which has no gates to report. A gate not
|
|
19
|
+
* reached because an earlier one failed (e.g. status/open-questions when the doc itself isn't
|
|
20
|
+
* usable) reports `false`, not `null` — "not confirmed ready" either way, and consistent with
|
|
21
|
+
* the overall verdict being the AND of all four. No new judgment: same reads, same rules,
|
|
22
|
+
* reshaped for direct consumption instead of scraped from stderr prose. */
|
|
23
|
+
export interface SliceReadyGates {
|
|
24
|
+
docBound: boolean;
|
|
25
|
+
frontmatterUsable: boolean;
|
|
26
|
+
statusReady: boolean;
|
|
27
|
+
noUncheckedOpenQuestions: boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare function computeSliceReadyGates(model: NormalizedModel, refs: RefsResult, baseDir: string, sliceKey: string): SliceReadyGates | null;
|
|
@@ -72,7 +72,12 @@ export function validateSliceReady(model, refs, baseDir, sliceKey) {
|
|
|
72
72
|
// resolveSliceDocJoin's SliceDocExport deliberately never carries Open Questions counts (same
|
|
73
73
|
// hard boundary that keeps doc.html/doc.raw out of it) — re-read via readSliceDoc for the
|
|
74
74
|
// full SliceDoc. Non-null: doc.reason === null already implies the file exists and parses.
|
|
75
|
-
|
|
75
|
+
// Re-derive the key to read from `doc.path` rather than assuming it's `sliceKey`'s own
|
|
76
|
+
// conventional path — MIL-121's ratified cross-binding can resolve `doc` to a DIFFERENT
|
|
77
|
+
// slice's doc (`slices/<other-key>.md`), and Open Questions must come from whichever doc
|
|
78
|
+
// actually supplied status/version above, not always this slice's own file.
|
|
79
|
+
const boundKey = doc.path.replace(/^slices\//, "").replace(/\.md$/, "");
|
|
80
|
+
const parsed = readSliceDoc(baseDir, boundKey);
|
|
76
81
|
if (parsed.openQuestionsUnchecked > 0) {
|
|
77
82
|
pushDiag(diags, "slice-ready-open-questions-unchecked", {
|
|
78
83
|
message: `slice "${sliceKey}" has ${parsed.openQuestionsUnchecked} of ${parsed.openQuestionsTotal} Open Question(s) unchecked`,
|
|
@@ -82,4 +87,23 @@ export function validateSliceReady(model, refs, baseDir, sliceKey) {
|
|
|
82
87
|
}
|
|
83
88
|
return diags;
|
|
84
89
|
}
|
|
90
|
+
export function computeSliceReadyGates(model, refs, baseDir, sliceKey) {
|
|
91
|
+
const sliceIndex = refs.sliceKeys.indexOf(sliceKey);
|
|
92
|
+
if (sliceIndex === -1)
|
|
93
|
+
return null;
|
|
94
|
+
const slice = model.slices[sliceIndex];
|
|
95
|
+
const { doc } = resolveSliceDocJoin(slice, sliceKey, baseDir, (id) => refs.refById.get(id));
|
|
96
|
+
const docBound = doc.reason !== "no-doc-bound";
|
|
97
|
+
const frontmatterUsable = doc.reason === null;
|
|
98
|
+
if (!frontmatterUsable) {
|
|
99
|
+
return { docBound, frontmatterUsable, statusReady: false, noUncheckedOpenQuestions: false };
|
|
100
|
+
}
|
|
101
|
+
const statusReady = doc.status === "ready-to-implement";
|
|
102
|
+
// Same re-derivation of the bound key from doc.path as validateSliceReady above — see its
|
|
103
|
+
// own comment for why (MIL-121 cross-binding can resolve to a different slice's doc).
|
|
104
|
+
const boundKey = doc.path.replace(/^slices\//, "").replace(/\.md$/, "");
|
|
105
|
+
const parsed = readSliceDoc(baseDir, boundKey);
|
|
106
|
+
const noUncheckedOpenQuestions = parsed.openQuestionsUnchecked === 0;
|
|
107
|
+
return { docBound, frontmatterUsable, statusReady, noUncheckedOpenQuestions };
|
|
108
|
+
}
|
|
85
109
|
//# sourceMappingURL=sliceReadyValidate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sliceReadyValidate.js","sourceRoot":"","sources":["../../src/catalog/sliceReadyValidate.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sliceReadyValidate.js","sourceRoot":"","sources":["../../src/catalog/sliceReadyValidate.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,4FAA4F;AAC5F,2FAA2F;AAC3F,0FAA0F;AAC1F,6FAA6F;AAC7F,qBAAqB;AACrB,EAAE;AACF,qFAAqF;AACrF,uFAAuF;AACvF,4FAA4F;AAC5F,8FAA8F;AAC9F,+FAA+F;AAC/F,4FAA4F;AAC5F,8DAA8D;AAC9D,EAAE;AACF,gGAAgG;AAChG,uFAAuF;AACvF,6FAA6F;AAC7F,gGAAgG;AAChG,kGAAkG;AAClG,2DAA2D;AAC3D,EAAE;AACF,8FAA8F;AAC9F,6FAA6F;AAC7F,8FAA8F;AAC9F,kFAAkF;AAKlF,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAsB,EACtB,IAAgB,EAChB,OAAe,EACf,QAAgB;IAEhB,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpD,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;QACtB,OAAO;YACL,QAAQ,CAAC,2BAA2B,EAAE;gBACpC,OAAO,EAAE,6BAA6B,QAAQ,iBAAiB;gBAC/D,IAAI,EAAE,CAAC,QAAQ,CAAC;aACjB,CAAC;SACH,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACvC,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,eAAe,EAAE,GAAG,mBAAmB,CAC/D,KAAK,EACL,QAAQ,EACR,OAAO,EACP,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAE,CAC9B,CAAC;IAEF,IAAI,GAAG,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;QAClC,OAAO;YACL,QAAQ,CAAC,0BAA0B,EAAE;gBACnC,OAAO,EAAE,UAAU,QAAQ,yCAAyC,QAAQ,+DAA+D;gBAC3I,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,IAAI,EAAE,CAAC,QAAQ,CAAC;aACjB,CAAC;SACH,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,sBAAsB,IAAI,GAAG,CAAC,MAAM,KAAK,qBAAqB,EAAE,CAAC;QAClF,iFAAiF;QACjF,uEAAuE;QACvE,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,kDAAkD;IAClD,MAAM,KAAK,GAAiB,EAAE,CAAC;IAC/B,IAAI,GAAG,CAAC,MAAM,KAAK,oBAAoB,EAAE,CAAC;QACxC,QAAQ,CAAC,KAAK,EAAE,8BAA8B,EAAE;YAC9C,OAAO,EAAE,UAAU,QAAQ,gBAAgB,GAAG,CAAC,MAAM,IAAI,QAAQ,0BAA0B;YAC3F,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,CAAC,QAAQ,CAAC;SACjB,CAAC,CAAC;IACL,CAAC;IAED,8FAA8F;IAC9F,0FAA0F;IAC1F,2FAA2F;IAC3F,uFAAuF;IACvF,wFAAwF;IACxF,yFAAyF;IACzF,4EAA4E;IAC5E,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACxE,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAE,CAAC;IAChD,IAAI,MAAM,CAAC,sBAAsB,GAAG,CAAC,EAAE,CAAC;QACtC,QAAQ,CAAC,KAAK,EAAE,sCAAsC,EAAE;YACtD,OAAO,EAAE,UAAU,QAAQ,SAAS,MAAM,CAAC,sBAAsB,OAAO,MAAM,CAAC,kBAAkB,6BAA6B;YAC9H,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,CAAC,QAAQ,CAAC;SACjB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAoBD,MAAM,UAAU,sBAAsB,CACpC,KAAsB,EACtB,IAAgB,EAChB,OAAe,EACf,QAAgB;IAEhB,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpD,IAAI,UAAU,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACvC,MAAM,EAAE,GAAG,EAAE,GAAG,mBAAmB,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC,CAAC;IAE7F,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,KAAK,cAAc,CAAC;IAC/C,MAAM,iBAAiB,GAAG,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC;IAC9C,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,WAAW,EAAE,KAAK,EAAE,wBAAwB,EAAE,KAAK,EAAE,CAAC;IAC9F,CAAC;IAED,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,KAAK,oBAAoB,CAAC;IACxD,0FAA0F;IAC1F,sFAAsF;IACtF,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IACxE,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAE,CAAC;IAChD,MAAM,wBAAwB,GAAG,MAAM,CAAC,sBAAsB,KAAK,CAAC,CAAC;IAErE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,WAAW,EAAE,wBAAwB,EAAE,CAAC;AAChF,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** The marker name wrapping the section: `<!-- GENERATED:agent-contract:start -->` /
|
|
2
|
+
* `<!-- GENERATED:agent-contract:end -->`. */
|
|
3
|
+
export declare const AGENTS_MD_MARKER = "agent-contract";
|
|
4
|
+
export interface AgentsMdResult {
|
|
5
|
+
path: string;
|
|
6
|
+
/** True iff the file's content on disk changed (including a brand-new file). */
|
|
7
|
+
wrote: boolean;
|
|
8
|
+
/** True iff AGENTS.md didn't exist before this call. */
|
|
9
|
+
created: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Write/update the agent-contract section in `<repoRoot>/AGENTS.md`. Always idempotent: a
|
|
13
|
+
* second call with nothing else having changed leaves the file byte-identical (`wrote: false`).
|
|
14
|
+
*/
|
|
15
|
+
export declare function syncAgentsMd(repoRoot: string): AgentsMdResult;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// AGENTS.md managed section (MIL-129): a marker-delimited block that `em skill install`/
|
|
3
|
+
// `em skill sync` write/update in the consumer repo's AGENTS.md, pointing any implementing
|
|
4
|
+
// agent — Claude Code or otherwise — at the three pieces of agent-neutral discovery Slicewright
|
|
5
|
+
// story gap G5 identified as missing: the implementation contract (`em contract`), the
|
|
6
|
+
// slice-readiness gate (`em validate --slice-ready --json`, MIL-128), and the machine-readable
|
|
7
|
+
// read path (`em export --slice`, MIL-128). MIL-21 adds a fourth pointer: `em-mcp`, the MCP
|
|
8
|
+
// server exposing the same contract/gate/read-path (plus full validate/export) as tools for an
|
|
9
|
+
// MCP-native agent, instead of shell commands.
|
|
10
|
+
//
|
|
11
|
+
// Same marker discipline as `em slice index`'s README Slices table (src/cli/sliceIndex.ts,
|
|
12
|
+
// MIL-98): idempotent replace-between-markers via src/util/markers.ts, user content outside the
|
|
13
|
+
// markers untouched, repeat runs never duplicate the section. One deliberate difference from
|
|
14
|
+
// sliceIndex: sliceIndex refuses to create a missing README (a human has to scaffold one from
|
|
15
|
+
// templates/model-readme.md first) and refuses when the marker pair is absent from an existing
|
|
16
|
+
// one. AGENTS.md has no such "scaffold it first" step to point at — agent-neutral discovery
|
|
17
|
+
// *is* AGENTS.md's whole reason for existing here — so this module creates the file when it's
|
|
18
|
+
// missing, and appends the marker pair (with the section already inside it) when an existing
|
|
19
|
+
// file lacks markers, instead of refusing either way.
|
|
20
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
import { applyMarker } from "../util/markers.js";
|
|
23
|
+
/** The marker name wrapping the section: `<!-- GENERATED:agent-contract:start -->` /
|
|
24
|
+
* `<!-- GENERATED:agent-contract:end -->`. */
|
|
25
|
+
export const AGENTS_MD_MARKER = "agent-contract";
|
|
26
|
+
const SECTION_BODY = `## Working with an AI agent
|
|
27
|
+
|
|
28
|
+
This repo uses [em](https://github.com/milehimikey/em) for event modeling. Any implementing
|
|
29
|
+
agent — Claude Code or otherwise — should follow this contract:
|
|
30
|
+
|
|
31
|
+
- **Contract**: \`em contract\` prints the full implementation contract to stdout — what
|
|
32
|
+
"ready" means, treating the slice doc as the read-only spec, when to stop and hand a gap to
|
|
33
|
+
a human instead of deciding it silently.
|
|
34
|
+
- **Gate**: before implementing a slice, verify it's ready —
|
|
35
|
+
\`em validate <model>.em --slice-ready <slice-key> --json\` and read the JSON document's
|
|
36
|
+
\`ready\` field (don't infer readiness from the exit code or printed text). Never make the
|
|
37
|
+
gate pass yourself — that's a ratification decision.
|
|
38
|
+
- **Read path**: \`em export <model>.em --slice <slice-key>\` exports just that slice's
|
|
39
|
+
normalized JSON (pattern, fields, doc) to implement against; \`em export <model>.em\` exports
|
|
40
|
+
the whole model.
|
|
41
|
+
- **MCP alternative**: \`em-mcp\` starts an MCP server exposing the contract, gate, and read
|
|
42
|
+
path above (plus full validate/export) as tools instead of shell commands — see
|
|
43
|
+
[docs/mcp.md](https://github.com/milehimikey/em/blob/main/docs/mcp.md).`;
|
|
44
|
+
function markerBlock() {
|
|
45
|
+
return `<!-- GENERATED:${AGENTS_MD_MARKER}:start -->\n${SECTION_BODY}\n<!-- GENERATED:${AGENTS_MD_MARKER}:end -->`;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Write/update the agent-contract section in `<repoRoot>/AGENTS.md`. Always idempotent: a
|
|
49
|
+
* second call with nothing else having changed leaves the file byte-identical (`wrote: false`).
|
|
50
|
+
*/
|
|
51
|
+
export function syncAgentsMd(repoRoot) {
|
|
52
|
+
const path = join(repoRoot, "AGENTS.md");
|
|
53
|
+
if (!existsSync(path)) {
|
|
54
|
+
writeFileSync(path, markerBlock() + "\n", "utf8");
|
|
55
|
+
return { path, wrote: true, created: true };
|
|
56
|
+
}
|
|
57
|
+
const original = readFileSync(path, "utf8");
|
|
58
|
+
const updated = applyMarker(original, AGENTS_MD_MARKER, SECTION_BODY);
|
|
59
|
+
if (updated !== null) {
|
|
60
|
+
if (updated === original)
|
|
61
|
+
return { path, wrote: false, created: false };
|
|
62
|
+
writeFileSync(path, updated, "utf8");
|
|
63
|
+
return { path, wrote: true, created: false };
|
|
64
|
+
}
|
|
65
|
+
// No marker pair in the existing file: append it (with a blank-line separator, and one
|
|
66
|
+
// blank line before it if the file doesn't already end in one) rather than refusing — see
|
|
67
|
+
// this module's header comment for why that differs from `em slice index`'s README gate.
|
|
68
|
+
const separator = original.endsWith("\n\n") ? "" : original.endsWith("\n") ? "\n" : "\n\n";
|
|
69
|
+
writeFileSync(path, `${original}${separator}${markerBlock()}\n`, "utf8");
|
|
70
|
+
return { path, wrote: true, created: false };
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=agentsMd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentsMd.js","sourceRoot":"","sources":["../../src/cli/agentsMd.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,yFAAyF;AACzF,2FAA2F;AAC3F,gGAAgG;AAChG,uFAAuF;AACvF,+FAA+F;AAC/F,4FAA4F;AAC5F,+FAA+F;AAC/F,+CAA+C;AAC/C,EAAE;AACF,2FAA2F;AAC3F,gGAAgG;AAChG,6FAA6F;AAC7F,8FAA8F;AAC9F,+FAA+F;AAC/F,4FAA4F;AAC5F,8FAA8F;AAC9F,6FAA6F;AAC7F,sDAAsD;AAEtD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD;+CAC+C;AAC/C,MAAM,CAAC,MAAM,gBAAgB,GAAG,gBAAgB,CAAC;AAEjD,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;0EAiBqD,CAAC;AAE3E,SAAS,WAAW;IAClB,OAAO,kBAAkB,gBAAgB,eAAe,YAAY,oBAAoB,gBAAgB,UAAU,CAAC;AACrH,CAAC;AAUD;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAEzC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;QAClD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC9C,CAAC;IAED,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,WAAW,CAAC,QAAQ,EAAE,gBAAgB,EAAE,YAAY,CAAC,CAAC;IAEtE,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,IAAI,OAAO,KAAK,QAAQ;YAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QACxE,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACrC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC/C,CAAC;IAED,uFAAuF;IACvF,0FAA0F;IAC1F,yFAAyF;IACzF,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IAC3F,aAAa,CAAC,IAAI,EAAE,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACzE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { NormalizedModel } from "../model/model.js";
|
|
2
|
+
import { RefsResult } from "../model/refs.js";
|
|
3
|
+
import { Diagnostic } from "../model/validate.js";
|
|
4
|
+
import { GitRunner } from "./diff-inputs.js";
|
|
5
|
+
import { ParsedState } from "./stateFile.js";
|
|
6
|
+
/** The `Last conformance:` shape this module consumes — `stateFile.ts`'s own type, narrowed to
|
|
7
|
+
* non-null (a `null`/never marker is handled by the caller before this module gets involved). */
|
|
8
|
+
export type LastConformance = NonNullable<ParsedState["lastConformance"]>;
|
|
9
|
+
/** One slice's doc-derived facts, the narrow slice of `SliceDocExport` (catalog/docJoin.ts)
|
|
10
|
+
* the scoping logic below actually needs — kept separate from the full export shape so
|
|
11
|
+
* `buildConformScope` is testable with plain fixtures, no compiled model required. */
|
|
12
|
+
export interface SliceDocFacts {
|
|
13
|
+
key: string;
|
|
14
|
+
status: string | null;
|
|
15
|
+
implementedIn: string | null;
|
|
16
|
+
}
|
|
17
|
+
export interface CandidateSlice {
|
|
18
|
+
key: string;
|
|
19
|
+
matchedBy: "implementedIn" | "full";
|
|
20
|
+
paths: string[];
|
|
21
|
+
}
|
|
22
|
+
/** The `em conform-scope` JSON document (ticket MIL-100). `lastConformance` echoes what was
|
|
23
|
+
* parsed from the state file even under `--full` — the caller always knows what was on record,
|
|
24
|
+
* even when scoping ignored it for this run. */
|
|
25
|
+
export interface ConformScopeJson {
|
|
26
|
+
lastConformance: {
|
|
27
|
+
date: string;
|
|
28
|
+
revision: string;
|
|
29
|
+
} | null;
|
|
30
|
+
changedPaths: string[];
|
|
31
|
+
candidateSlices: CandidateSlice[];
|
|
32
|
+
unmappedPaths: string[];
|
|
33
|
+
}
|
|
34
|
+
/** The changed paths one slice's `implementedIn` textually, deterministically names: equal to
|
|
35
|
+
* the candidate path, or nested under it (the candidate names a directory). No fuzzy matching,
|
|
36
|
+
* no grep — that judgment call stays with the agent (reference/conform.md step 1). */
|
|
37
|
+
export declare function matchImplementedInToPaths(implementedIn: string | null, changedPaths: string[]): string[];
|
|
38
|
+
/**
|
|
39
|
+
* Build the `em conform-scope` JSON body — pure, no fs/git. `full` covers `--full`; a `null`
|
|
40
|
+
* `lastConformance` (the state file's `never` marker, first run) forces the same behavior
|
|
41
|
+
* regardless of `full`, matching reference/conform.md step 1 ("If it's `null` (first run) or
|
|
42
|
+
* the user passes `--full`, scope is every `implemented` slice"). In that mode `changedPaths`
|
|
43
|
+
* is `[]` (documented choice, not omitted — keeps the JSON shape stable across modes) and every
|
|
44
|
+
* `implemented`-status slice is a candidate with `matchedBy: "full"` and empty `paths`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function buildConformScope(slices: SliceDocFacts[], lastConformance: LastConformance | null, changedPaths: string[], full: boolean): ConformScopeJson;
|
|
47
|
+
export interface SliceDocFactsResult {
|
|
48
|
+
facts: SliceDocFacts[];
|
|
49
|
+
diagnostics: Diagnostic[];
|
|
50
|
+
}
|
|
51
|
+
/** Resolve every slice's doc-join facts in declaration order — exactly the two inputs
|
|
52
|
+
* `buildConformScope` needs (`status`, `implementedIn`), via the same `resolveSliceDocJoin`
|
|
53
|
+
* call `em export`/`em slice index` make, never a second doc parse. `diagnostics` carries any
|
|
54
|
+
* `binding-missing-file`/`frontmatter-invalid` warnings, for the caller to print the same way
|
|
55
|
+
* `em slice index` does. */
|
|
56
|
+
export declare function resolveSliceDocFacts(model: NormalizedModel, refs: RefsResult, baseDir: string): SliceDocFactsResult;
|
|
57
|
+
export type ChangedPathsResult = {
|
|
58
|
+
ok: true;
|
|
59
|
+
paths: string[];
|
|
60
|
+
} | {
|
|
61
|
+
ok: false;
|
|
62
|
+
message: string;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* `git diff --name-only <revision>..HEAD`, run from `repo` (any directory inside the target
|
|
66
|
+
* repo, not necessarily its root — same "anchor dir, resolve toplevel" convention
|
|
67
|
+
* diff-inputs.ts/changelog-git.ts use). Paths come back repo-root-relative — git's own default
|
|
68
|
+
* for `--name-only` without `--relative`.
|
|
69
|
+
*/
|
|
70
|
+
export declare function changedPathsSince(repo: string, revision: string, runGit?: GitRunner): ChangedPathsResult;
|
|
71
|
+
export interface SeedAsisResult {
|
|
72
|
+
asisPath: string;
|
|
73
|
+
gitignoreUpdated: boolean;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* `--seed-asis`: byte-copy `modelFile` to `<dirname(modelFile)>/<stem>-asis.em`, and make sure
|
|
77
|
+
* `*-asis.em` is gitignored. reference/conform.md's Conventions section says to add the pattern
|
|
78
|
+
* to "the repository's `.gitignore`" — read here as the git repo the model itself lives in
|
|
79
|
+
* (resolved the same "anchor dir, `rev-parse --show-toplevel`" way as `changedPathsSince`
|
|
80
|
+
* above, from the model's own directory — a different repo entirely from the `--repo` target
|
|
81
|
+
* codebase conform is checking), so the entry lands once, at that repo's root, covering every
|
|
82
|
+
* model the repo holds. Falls back to a `.gitignore` right next to the model when the model
|
|
83
|
+
* isn't inside a git repo at all. Idempotent: never appends a second `*-asis.em` line if one
|
|
84
|
+
* (exactly, on its own line) is already present anywhere in the file.
|
|
85
|
+
*/
|
|
86
|
+
export declare function seedAsisModel(modelFile: string, runGit?: GitRunner): SeedAsisResult;
|