@encore-os/eos-spec 0.7.0 → 0.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/dist/commands/archive.js +57 -3
- package/dist/commands/archive.js.map +1 -1
- package/dist/commands/close-out.d.ts +2 -0
- package/dist/commands/close-out.js +167 -0
- package/dist/commands/close-out.js.map +1 -0
- package/dist/commands/conformance.js +20 -1
- package/dist/commands/conformance.js.map +1 -1
- package/dist/commands/create.js +25 -4
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/metrics.js +15 -0
- package/dist/commands/metrics.js.map +1 -1
- package/dist/commands/run.d.ts +10 -0
- package/dist/commands/run.js +230 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/validate.d.ts +7 -0
- package/dist/commands/validate.js +46 -7
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/walkthrough.d.ts +2 -0
- package/dist/commands/walkthrough.js +76 -0
- package/dist/commands/walkthrough.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/ai-call.d.ts +12 -0
- package/dist/lib/ai-call.js +6 -0
- package/dist/lib/ai-call.js.map +1 -1
- package/dist/lib/closeout-core.d.ts +46 -0
- package/dist/lib/closeout-core.js +34 -0
- package/dist/lib/closeout-core.js.map +1 -0
- package/dist/lib/closeout-predicate.d.ts +36 -0
- package/dist/lib/closeout-predicate.js +130 -0
- package/dist/lib/closeout-predicate.js.map +1 -0
- package/dist/lib/cost.js +7 -0
- package/dist/lib/cost.js.map +1 -1
- package/dist/lib/events.d.ts +15 -1
- package/dist/lib/events.js.map +1 -1
- package/dist/lib/frontmatter.d.ts +38 -0
- package/dist/lib/frontmatter.js +76 -0
- package/dist/lib/frontmatter.js.map +1 -1
- package/dist/lib/gate-executor.d.ts +80 -0
- package/dist/lib/gate-executor.js +311 -0
- package/dist/lib/gate-executor.js.map +1 -0
- package/dist/lib/llm-health.d.ts +28 -0
- package/dist/lib/llm-health.js +46 -0
- package/dist/lib/llm-health.js.map +1 -0
- package/dist/lib/metrics.d.ts +26 -0
- package/dist/lib/metrics.js +35 -0
- package/dist/lib/metrics.js.map +1 -1
- package/dist/lib/next-action.d.ts +10 -4
- package/dist/lib/next-action.js +10 -4
- package/dist/lib/next-action.js.map +1 -1
- package/dist/lib/ollama-embed.d.ts +5 -0
- package/dist/lib/ollama-embed.js +5 -0
- package/dist/lib/ollama-embed.js.map +1 -1
- package/dist/lib/output.d.ts +3 -0
- package/dist/lib/output.js +3 -0
- package/dist/lib/output.js.map +1 -1
- package/dist/lib/pipeline-config.js +10 -0
- package/dist/lib/pipeline-config.js.map +1 -1
- package/dist/lib/pipeline-map.js +9 -0
- package/dist/lib/pipeline-map.js.map +1 -1
- package/dist/lib/precedent-search.d.ts +1 -0
- package/dist/lib/precedent-search.js +19 -2
- package/dist/lib/precedent-search.js.map +1 -1
- package/dist/lib/predicate-registry.js +7 -0
- package/dist/lib/predicate-registry.js.map +1 -1
- package/dist/lib/run-pipeline.d.ts +118 -0
- package/dist/lib/run-pipeline.js +106 -0
- package/dist/lib/run-pipeline.js.map +1 -0
- package/dist/lib/scorecard.js +9 -0
- package/dist/lib/scorecard.js.map +1 -1
- package/dist/lib/spec-pure.d.ts +69 -4
- package/dist/lib/spec-pure.js +125 -15
- package/dist/lib/spec-pure.js.map +1 -1
- package/dist/lib/specs.d.ts +3 -3
- package/dist/lib/specs.js +43 -20
- package/dist/lib/specs.js.map +1 -1
- package/dist/lib/version.d.ts +1 -1
- package/dist/lib/version.js +1 -1
- package/dist/lib/walkthrough-coverage.d.ts +81 -0
- package/dist/lib/walkthrough-coverage.js +111 -0
- package/dist/lib/walkthrough-coverage.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// src/lib/walkthrough-coverage.ts
|
|
2
|
+
//
|
|
3
|
+
// Canonical walkthrough filmed-coverage contract (the engine source of truth that
|
|
4
|
+
// encoreos's repo-local `scripts/specs/check-walkthrough-coverage.ts` and
|
|
5
|
+
// `tests/e2e/utils/walkthrough-manifest.ts` repoint to — REPOINT.md / encoreos#12).
|
|
6
|
+
//
|
|
7
|
+
// The `@walkthrough` Playwright lane records a per-AC clip + step screenshots and
|
|
8
|
+
// writes `docs/walkthroughs/<spec>/manifest.json`; `walkthrough:build` stitches the
|
|
9
|
+
// MP4 and patches each AC's `chapterStartMs`. This module is the predicate that
|
|
10
|
+
// consumes that manifest:
|
|
11
|
+
// • an AC is "filmed" only with a NON-EMPTY clip AND a NUMERIC chapterStartMs
|
|
12
|
+
// (the latter only exists after the stitch pass — a pass-1-only manifest fails);
|
|
13
|
+
// • a user story is "covered" only when a FILMED in-spec AC lists it;
|
|
14
|
+
// • a manifest whose specSha disagrees with the current spec is STALE (re-record).
|
|
15
|
+
//
|
|
16
|
+
// Pure + dependency-free so both the CLI (`eos-spec walkthrough --check`) and any
|
|
17
|
+
// browser/consumer call site share one definition.
|
|
18
|
+
import { createHash } from 'node:crypto';
|
|
19
|
+
/**
|
|
20
|
+
* Stable manifest sha over the spec's AC + user-story ids. Order-insensitive
|
|
21
|
+
* (ids sorted) so reordering the spec doesn't spuriously invalidate a recording;
|
|
22
|
+
* adding/removing an AC or story does (→ STALE, re-record). 16 hex chars.
|
|
23
|
+
*/
|
|
24
|
+
export function computeSpecSha(acIds, storyIds) {
|
|
25
|
+
const canonical = JSON.stringify({ ac: [...acIds].sort(), us: [...storyIds].sort() });
|
|
26
|
+
return createHash('sha256').update(canonical).digest('hex').slice(0, 16);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Is a single AC "filmed"? A non-empty `clip` AND a finite numeric `chapterStartMs`
|
|
30
|
+
* (the stitch-pass field). A pass-1-only manifest (clip present, chapterStartMs
|
|
31
|
+
* absent) is NOT filmed — `walkthrough:build` must run.
|
|
32
|
+
*/
|
|
33
|
+
export function acFilmStatus(ac) {
|
|
34
|
+
if (!ac.clip || ac.clip.trim() === '') {
|
|
35
|
+
return { id: ac.id, filmed: false, reason: 'no clip (AC not recorded — undriveable UI stays MISSING)' };
|
|
36
|
+
}
|
|
37
|
+
if (typeof ac.chapterStartMs !== 'number' || !Number.isFinite(ac.chapterStartMs)) {
|
|
38
|
+
return { id: ac.id, filmed: false, reason: 'no numeric chapterStartMs (run `walkthrough:build` to stitch)' };
|
|
39
|
+
}
|
|
40
|
+
return { id: ac.id, filmed: true, reason: `filmed (clip + chapter @ ${ac.chapterStartMs}ms)` };
|
|
41
|
+
}
|
|
42
|
+
/** The set of story ids covered by at least one FILMED AC that lists them. */
|
|
43
|
+
export function coveredStoryIds(manifest) {
|
|
44
|
+
const covered = new Set();
|
|
45
|
+
for (const ac of manifest.acceptance_criteria) {
|
|
46
|
+
if (!acFilmStatus(ac).filmed)
|
|
47
|
+
continue;
|
|
48
|
+
for (const s of ac.stories ?? [])
|
|
49
|
+
covered.add(s);
|
|
50
|
+
}
|
|
51
|
+
return covered;
|
|
52
|
+
}
|
|
53
|
+
/** Extract canonical AC ids (frontmatter) and user-story ids (body) from spec text. */
|
|
54
|
+
export function specRequirementIds(specText) {
|
|
55
|
+
const fmMatch = /^---\r?\n([\s\S]*?)\r?\n---/.exec(specText);
|
|
56
|
+
const fmRaw = fmMatch?.[0] ?? '';
|
|
57
|
+
const fmBlock = fmMatch?.[1] ?? '';
|
|
58
|
+
const acIds = [];
|
|
59
|
+
for (const line of fmBlock.split('\n')) {
|
|
60
|
+
const m = /^ {2}- id:\s*["']?(AC-\d+)["']?\s*$/.exec(line);
|
|
61
|
+
if (m?.[1])
|
|
62
|
+
acIds.push(m[1]);
|
|
63
|
+
}
|
|
64
|
+
const body = fmRaw ? specText.slice(fmRaw.length) : specText;
|
|
65
|
+
const storyIds = [];
|
|
66
|
+
for (const line of body.split('\n')) {
|
|
67
|
+
const m = /^\s*-\s+\*{0,2}(US-\d+)\*{0,2}\s+\[[a-z_]+\]/.exec(line);
|
|
68
|
+
if (m?.[1])
|
|
69
|
+
storyIds.push(m[1]);
|
|
70
|
+
}
|
|
71
|
+
return { acIds: [...new Set(acIds)], storyIds: [...new Set(storyIds)] };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Whole-manifest verdict against the spec's current requirement ids. The spec is
|
|
75
|
+
* the source of truth: an AC the spec declares but the manifest never recorded is
|
|
76
|
+
* `unfilmed`. The specSha is recomputed from the spec's ids and compared to the
|
|
77
|
+
* manifest's — a mismatch means the spec changed since recording (STALE).
|
|
78
|
+
*/
|
|
79
|
+
export function checkWalkthroughCoverage(manifest, expected) {
|
|
80
|
+
const currentSha = computeSpecSha(expected.acIds, expected.storyIds);
|
|
81
|
+
const stale = manifest.specSha !== currentSha;
|
|
82
|
+
const byId = new Map(manifest.acceptance_criteria.map((a) => [a.id, a]));
|
|
83
|
+
const unfilmed = [];
|
|
84
|
+
let acFilmed = 0;
|
|
85
|
+
for (const id of expected.acIds) {
|
|
86
|
+
const ac = byId.get(id);
|
|
87
|
+
if (!ac) {
|
|
88
|
+
unfilmed.push({ id, filmed: false, reason: 'declared in spec but absent from manifest (not recorded)' });
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const s = acFilmStatus(ac);
|
|
92
|
+
if (s.filmed)
|
|
93
|
+
acFilmed++;
|
|
94
|
+
else
|
|
95
|
+
unfilmed.push(s);
|
|
96
|
+
}
|
|
97
|
+
const covered = coveredStoryIds(manifest);
|
|
98
|
+
const uncovered = expected.storyIds.filter((s) => !covered.has(s));
|
|
99
|
+
const ok = !stale && unfilmed.length === 0 && uncovered.length === 0;
|
|
100
|
+
return {
|
|
101
|
+
stale,
|
|
102
|
+
acTotal: expected.acIds.length,
|
|
103
|
+
acFilmed,
|
|
104
|
+
unfilmed,
|
|
105
|
+
storiesTotal: expected.storyIds.length,
|
|
106
|
+
storiesCovered: expected.storyIds.length - uncovered.length,
|
|
107
|
+
uncovered,
|
|
108
|
+
ok,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=walkthrough-coverage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walkthrough-coverage.js","sourceRoot":"","sources":["../../src/lib/walkthrough-coverage.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,kFAAkF;AAClF,0EAA0E;AAC1E,oFAAoF;AACpF,EAAE;AACF,kFAAkF;AAClF,oFAAoF;AACpF,gFAAgF;AAChF,0BAA0B;AAC1B,gFAAgF;AAChF,qFAAqF;AACrF,wEAAwE;AACxE,qFAAqF;AACrF,EAAE;AACF,kFAAkF;AAClF,mDAAmD;AAEnD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAsDzC;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,KAAe,EAAE,QAAkB;IAChE,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACtF,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC3E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,EAAiB;IAC5C,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACtC,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,0DAA0D,EAAE,CAAC;IAC1G,CAAC;IACD,IAAI,OAAO,EAAE,CAAC,cAAc,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC;QACjF,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,+DAA+D,EAAE,CAAC;IAC/G,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,4BAA4B,EAAE,CAAC,cAAc,KAAK,EAAE,CAAC;AACjG,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,eAAe,CAAC,QAA6B;IAC3D,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,MAAM,EAAE,IAAI,QAAQ,CAAC,mBAAmB,EAAE,CAAC;QAC9C,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,MAAM;YAAE,SAAS;QACvC,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,OAAO,IAAI,EAAE;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,MAAM,OAAO,GAAG,6BAA6B,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACjC,MAAM,OAAO,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACnC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,CAAC,GAAG,qCAAqC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3D,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC7D,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,MAAM,CAAC,GAAG,8CAA8C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;AAC1E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAA6B,EAC7B,QAAiD;IAEjD,MAAM,UAAU,GAAG,cAAc,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACrE,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,KAAK,UAAU,CAAC;IAE9C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,MAAM,QAAQ,GAAmB,EAAE,CAAC;IACpC,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,KAAK,MAAM,EAAE,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QAChC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACxB,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,0DAA0D,EAAE,CAAC,CAAC;YACzG,SAAS;QACX,CAAC;QACD,MAAM,CAAC,GAAG,YAAY,CAAC,EAAE,CAAC,CAAC;QAC3B,IAAI,CAAC,CAAC,MAAM;YAAE,QAAQ,EAAE,CAAC;;YACpB,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;IAED,MAAM,OAAO,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAEnE,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC;IACrE,OAAO;QACL,KAAK;QACL,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM;QAC9B,QAAQ;QACR,QAAQ;QACR,YAAY,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM;QACtC,cAAc,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM;QAC3D,SAAS;QACT,EAAE;KACH,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@encore-os/eos-spec",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Portable, config-driven spec-pipeline engine + quality harness. One canonical engine consumed as a library (with a client-safe /pure subpath) by every Encore-OS repo.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|