@milehimikey/em 1.8.1 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +40 -14
- 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 +150 -0
- package/.claude/skills/event-modeling-shared/reference/slice-doc-schema.md +381 -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 +57 -14
- 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 +503 -132
- 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
|
@@ -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
|
-
|
|
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":"AAAA,+BAA+B;AAC/B,+FAA+F;AAC/F,iGAAiG;AACjG,+FAA+F;AAC/F,gGAAgG;AAChG,+EAA+E;AAC/E,8FAA8F;AAC9F,oFAAoF;AACpF,EAAE;AACF,8FAA8F;AAC9F,iGAAiG;AACjG,6FAA6F;AAC7F,8FAA8F;AAC9F,gGAAgG;AAChG,+FAA+F;AAC/F,4FAA4F;AAC5F,4FAA4F;AAC5F,iGAAiG;AACjG,6FAA6F;AAC7F,8EAA8E;AAC9E,EAAE;AACF,uFAAuF;AACvF,4FAA4F;AAC5F,+FAA+F;AAC/F,oFAAoF;
|
|
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":"AAAA,+BAA+B;AAC/B,2FAA2F;AAC3F,+FAA+F;AAC/F,qFAAqF;AACrF,+FAA+F;AAC/F,gGAAgG;AAChG,sFAAsF;AACtF,8CAA8C;AAC9C,EAAE;AACF,2BAA2B;AAC3B,+BAA+B;AAC/B,EAAE;AACF,2EAA2E;AAC3E,8FAA8F;AAC9F,6FAA6F;AAC7F,6FAA6F;AAC7F,gGAAgG;AAChG,8FAA8F;AAC9F,+FAA+F;AAC/F,6FAA6F;AAC7F,eAAe;AACf,EAAE;AACF,+FAA+F;AAC/F,4FAA4F;AAC5F,gGAAgG;AAChG,6FAA6F;AAC7F,+FAA+F;AAC/F,6FAA6F;AAC7F,EAAE;AACF,8FAA8F;AAC9F,4FAA4F;AAC5F,8FAA8F;AAC9F,8FAA8F;AAC9F,gGAAgG;AAChG,gGAAgG;AAEhG,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE7H;;4BAE4B;AAC5B,MAAM,kBAAkB,GAAG,aAAa,CAAC;AACzC,MAAM,aAAa,GAAG,oBAAoB,CAAC;AAM3C;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CAAC,GAAW;IAClD,MAAM,KAAK,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,4BAA4B,EAAE,CAAC;IACxE,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IAE1D,MAAM,WAAW,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzD,IAAI,CAAC,WAAW;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,yCAAyC,EAAE,CAAC;IAC3F,MAAM,aAAa,GAAG,mBAAmB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,IAAI,CAAC;IACjF,IAAI,aAAa,KAAK,kBAAkB,EAAE,CAAC;QACzC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EACL,oBAAoB,aAAa,IAAI,SAAS,uDAAuD;gBACrG,kGAAkG;gBAClG,+FAA+F;gBAC/F,sBAAsB;SACzB,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3D,IAAI,CAAC,YAAY;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,0CAA0C,EAAE,CAAC;IAC7F,MAAM,iBAAiB,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,MAAM,cAAc,GAAG,iBAAiB,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACpF,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;QAC5D,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE,6BAA6B,iBAAiB,IAAI,EAAE,uDAAuD;SACrH,CAAC;IACJ,CAAC;IACD,MAAM,UAAU,GAAG,cAAc,GAAG,CAAC,CAAC;IAEtC,8FAA8F;IAC9F,oCAAoC;IACpC,MAAM,KAAK,GAAG;QACZ,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,aAAa,EAAE,EAAE;QACtG,EAAE,KAAK,EAAE,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,UAAU,EAAE,EAAE;KACvG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IACpC,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,YAAY,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9G,CAAC;IAED,qFAAqF;IACrF,0FAA0F;IAC1F,+FAA+F;IAC/F,2EAA2E;IAC3E,YAAY,GAAG,YAAY,CAAC,OAAO,CAAC,qBAAqB,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC;IAE9H,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,GAAG,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC1F,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;AAC3C,CAAC;AAMD;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CACzB,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,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,6BAA6B,QAAQ,iBAAiB,EAAE,CAAC;IACxF,CAAC;IACD,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,IAAI,GAAG,CAAC,MAAM,KAAK,cAAc,EAAE,CAAC;QAClC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE,UAAU,QAAQ,yCAAyC,QAAQ,iDAAiD;SAC9H,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,sBAAsB,EAAE,CAAC;QAC1C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,QAAQ,YAAY,GAAG,CAAC,IAAI,2BAA2B,EAAE,CAAC;IACnG,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,qBAAqB,EAAE,CAAC;QACzC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE,cAAc,GAAG,CAAC,IAAI,wEAAwE;SACxG,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,wBAAwB,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;IAClE,CAAC;IACD,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC/C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;AACrE,CAAC"}
|
package/dist/cli/skillCheck.d.ts
CHANGED
|
@@ -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;
|
package/dist/cli/skillCheck.js
CHANGED
|
@@ -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":"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"}
|
|
@@ -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"}
|