@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.
- package/.claude/skills/event-modeling/SKILL.md +58 -404
- package/.claude/skills/event-modeling-conform/SKILL.md +77 -0
- package/.claude/skills/{event-modeling → event-modeling-conform}/reference/conform.md +39 -13
- package/.claude/skills/event-modeling-design/SKILL.md +139 -0
- package/.claude/skills/event-modeling-discover/SKILL.md +89 -0
- package/.claude/skills/{event-modeling → event-modeling-discover}/reference/extract.md +3 -2
- package/.claude/skills/event-modeling-implement/SKILL.md +40 -0
- package/.claude/skills/{event-modeling → event-modeling-implement}/reference/implement.md +3 -2
- package/.claude/skills/event-modeling-review/SKILL.md +58 -0
- package/.claude/skills/{event-modeling → event-modeling-shared}/reference/em-dsl.md +115 -83
- package/.claude/skills/{event-modeling → event-modeling-shared}/reference/methodology.md +6 -5
- package/.claude/skills/event-modeling-shared/reference/operating-principles.md +147 -0
- package/.claude/skills/{event-modeling → event-modeling-shared}/templates/model-readme.md +2 -2
- package/.claude/skills/{event-modeling → event-modeling-shared}/templates/slice.md +51 -8
- package/README.md +24 -4
- package/dist/catalog/build.js +9 -0
- package/dist/catalog/build.js.map +1 -1
- package/dist/catalog/docJoin.d.ts +15 -0
- package/dist/catalog/docJoin.js +8 -0
- package/dist/catalog/docJoin.js.map +1 -1
- package/dist/catalog/modelCollisionValidate.d.ts +22 -0
- package/dist/catalog/modelCollisionValidate.js +67 -0
- package/dist/catalog/modelCollisionValidate.js.map +1 -0
- package/dist/catalog/orphanedSliceDocValidate.d.ts +11 -0
- package/dist/catalog/orphanedSliceDocValidate.js +98 -0
- package/dist/catalog/orphanedSliceDocValidate.js.map +1 -0
- package/dist/catalog/sliceDoc.d.ts +15 -0
- package/dist/catalog/sliceDoc.js +18 -0
- package/dist/catalog/sliceDoc.js.map +1 -1
- package/dist/cli/changelogBuild.d.ts +12 -0
- package/dist/cli/changelogBuild.js +89 -0
- package/dist/cli/changelogBuild.js.map +1 -0
- package/dist/cli/ciInit.d.ts +42 -0
- package/dist/cli/ciInit.js +298 -0
- package/dist/cli/ciInit.js.map +1 -0
- package/dist/cli/conformSupersede.d.ts +32 -0
- package/dist/cli/conformSupersede.js +102 -0
- package/dist/cli/conformSupersede.js.map +1 -0
- package/dist/cli/coverage.d.ts +6 -1
- package/dist/cli/coverage.js +28 -3
- package/dist/cli/coverage.js.map +1 -1
- package/dist/cli/frontmatterSurgery.d.ts +28 -0
- package/dist/cli/frontmatterSurgery.js +66 -0
- package/dist/cli/frontmatterSurgery.js.map +1 -0
- package/dist/cli/markImplemented.js +6 -45
- package/dist/cli/markImplemented.js.map +1 -1
- package/dist/cli/ratify.d.ts +41 -0
- package/dist/cli/ratify.js +151 -0
- package/dist/cli/ratify.js.map +1 -0
- package/dist/cli/reratify.d.ts +33 -0
- package/dist/cli/reratify.js +137 -0
- package/dist/cli/reratify.js.map +1 -0
- package/dist/cli/skillCheck.d.ts +6 -0
- package/dist/cli/skillCheck.js +46 -0
- package/dist/cli/skillCheck.js.map +1 -1
- package/dist/cli/skillDirs.d.ts +15 -0
- package/dist/cli/skillDirs.js +34 -0
- package/dist/cli/skillDirs.js.map +1 -0
- package/dist/cli/skillSync.d.ts +10 -0
- package/dist/cli/skillSync.js +15 -0
- package/dist/cli/skillSync.js.map +1 -1
- package/dist/cli/sliceIndex.d.ts +3 -0
- package/dist/cli/sliceIndex.js +6 -2
- package/dist/cli/sliceIndex.js.map +1 -1
- package/dist/cli/sliceLink.d.ts +52 -0
- package/dist/cli/sliceLink.js +152 -0
- package/dist/cli/sliceLink.js.map +1 -0
- package/dist/cli/status.d.ts +261 -0
- package/dist/cli/status.js +536 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/usageLog.d.ts +75 -0
- package/dist/cli/usageLog.js +193 -0
- package/dist/cli/usageLog.js.map +1 -0
- package/dist/cli.js +501 -130
- package/dist/cli.js.map +1 -1
- package/dist/emit/freshnessJson.d.ts +6 -0
- package/dist/emit/freshnessJson.js +24 -0
- package/dist/emit/freshnessJson.js.map +1 -0
- package/dist/emit/json.d.ts +62 -8
- package/dist/emit/json.js +14 -3
- package/dist/emit/json.js.map +1 -1
- package/dist/emit/statusJson.d.ts +7 -0
- package/dist/emit/statusJson.js +39 -0
- package/dist/emit/statusJson.js.map +1 -0
- package/dist/emit/typespec.d.ts +26 -0
- package/dist/emit/typespec.js +356 -0
- package/dist/emit/typespec.js.map +1 -0
- package/dist/emit/usageReportJson.d.ts +3 -0
- package/dist/emit/usageReportJson.js +23 -0
- package/dist/emit/usageReportJson.js.map +1 -0
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +301 -11
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/rules.d.ts +13 -0
- package/dist/model/rules.js +20 -0
- package/dist/model/rules.js.map +1 -1
- package/dist/templates.d.ts +1 -1
- package/dist/templates.js +2 -2
- package/dist/util/markers.d.ts +16 -4
- package/dist/util/markers.js +23 -10
- package/dist/util/markers.js.map +1 -1
- package/package.json +2 -1
- /package/.claude/skills/{event-modeling → event-modeling-shared}/templates/conformance-report.md +0 -0
- /package/.claude/skills/{event-modeling → event-modeling-shared}/templates/state.md +0 -0
package/dist/cli/skillSync.d.ts
CHANGED
|
@@ -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;
|
package/dist/cli/skillSync.js
CHANGED
|
@@ -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":"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"}
|
|
1
|
+
{"version":3,"file":"skillSync.js","sourceRoot":"","sources":["../../src/cli/skillSync.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/sliceIndex.d.ts
CHANGED
package/dist/cli/sliceIndex.js
CHANGED
|
@@ -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":"AAAA,+BAA+B;AAC/B,6FAA6F;AAC7F,6FAA6F;AAC7F,sFAAsF;AACtF,iGAAiG;AACjG,EAAE;AACF,0FAA0F;AAC1F,uFAAuF;AACvF,+FAA+F;AAC/F,sDAAsD;AAEtD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAI1C,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAkB,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD;2EAC2E;AAC3E,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAQ,CAAC;AAE3C,MAAM,YAAY,GAChB,
|
|
1
|
+
{"version":3,"file":"sliceIndex.js","sourceRoot":"","sources":["../../src/cli/sliceIndex.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,6FAA6F;AAC7F,6FAA6F;AAC7F,sFAAsF;AACtF,iGAAiG;AACjG,EAAE;AACF,0FAA0F;AAC1F,uFAAuF;AACvF,+FAA+F;AAC/F,sDAAsD;AAEtD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAI1C,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAkB,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD;2EAC2E;AAC3E,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAQ,CAAC;AAE3C,MAAM,YAAY,GAChB,mGAAmG;IACnG,iGAAiG,CAAC;AAEpG;;yBAEyB;AACzB,SAAS,UAAU,CAAC,CAAS;IAC3B,wFAAwF;IACxF,yFAAyF;IACzF,wFAAwF;IACxF,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;AAC/E,CAAC;AAED;;;;;;8EAM8E;AAC9E,SAAS,UAAU,CAAC,GAAmB;IACrC,IAAI,CAAC,GAAG,CAAC,KAAK;QAAE,OAAO,YAAY,CAAC;IACpC,OAAO,GAAG,CAAC,MAAM,IAAI,SAAS,CAAC;AACjC,CAAC;AAwBD;oFACoF;AACpF,MAAM,UAAU,oBAAoB,CAAC,KAAsB,EAAE,IAAgB,EAAE,OAAe;IAC5F,MAAM,WAAW,GAAiB,EAAE,CAAC;IAErC,MAAM,IAAI,GAAoB,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAC5C,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,mBAAmB,CACxD,KAAK,EACL,QAAQ,EACR,OAAO,EACP,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAE,CAC9B,CAAC;QACF,WAAW,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;QAC9B,OAAO;YACL,KAAK,EAAE,CAAC,GAAG,CAAC;YACZ,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC;YACnC,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC;YACvB,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,GAAG;YACjC,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,GAAG;YACvB,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,GAAG;YAC7B,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,GAAG;YACvC,OAAO,EAAE,GAAG,CAAC,IAAI;SAClB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CACpB,CAAC,CAAC,EAAE,EAAE,CACJ,KAAK,CAAC,CAAC,KAAK,MAAM,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK;QAC9F,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK;QACrF,GAAG,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK,CACpE,CAAC;IAEF,OAAO,EAAE,QAAQ,EAAE,CAAC,YAAY,EAAE,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AAC9E,CAAC;AAMD;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAC3B,KAAsB,EACtB,IAAgB,EAChB,UAAkB,EAClB,KAAc;IAEd,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACpC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAEzD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,IAAI,EAAE,gBAAgB;YACtB,OAAO,EACL,gDAAgD,UAAU,gBAAgB,UAAU,MAAM;gBAC1F,gEAAgE;YAClE,KAAK;SACN,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,WAAW,CAAC,QAAQ,EAAE,kBAAkB,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC1E,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,IAAI,EAAE,iBAAiB;YACvB,OAAO,EACL,mBAAmB,UAAU,0BAA0B,kBAAkB,eAAe;gBACxF,kBAAkB,kBAAkB,sDAAsD;gBAC1F,4FAA4F;gBAC5F,8BAA8B;YAChC,KAAK;SACN,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,KAAK,QAAQ,CAAC;IACrC,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAEnF,IAAI,KAAK,EAAE,CAAC;QACV,OAAO;YACL,EAAE,EAAE,KAAK;YACT,IAAI,EAAE,OAAO;YACb,OAAO,EACL,2BAA2B,UAAU,iCAAiC;gBACtE,oBAAoB,UAAU,2BAA2B;YAC3D,KAAK;SACN,CAAC;IACJ,CAAC;IAED,aAAa,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC3C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACrE,CAAC"}
|
|
@@ -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;
|