@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.
Files changed (83) hide show
  1. package/dist/commands/archive.js +57 -3
  2. package/dist/commands/archive.js.map +1 -1
  3. package/dist/commands/close-out.d.ts +2 -0
  4. package/dist/commands/close-out.js +167 -0
  5. package/dist/commands/close-out.js.map +1 -0
  6. package/dist/commands/conformance.js +20 -1
  7. package/dist/commands/conformance.js.map +1 -1
  8. package/dist/commands/create.js +25 -4
  9. package/dist/commands/create.js.map +1 -1
  10. package/dist/commands/metrics.js +15 -0
  11. package/dist/commands/metrics.js.map +1 -1
  12. package/dist/commands/run.d.ts +10 -0
  13. package/dist/commands/run.js +230 -0
  14. package/dist/commands/run.js.map +1 -0
  15. package/dist/commands/validate.d.ts +7 -0
  16. package/dist/commands/validate.js +46 -7
  17. package/dist/commands/validate.js.map +1 -1
  18. package/dist/commands/walkthrough.d.ts +2 -0
  19. package/dist/commands/walkthrough.js +76 -0
  20. package/dist/commands/walkthrough.js.map +1 -0
  21. package/dist/index.d.ts +1 -0
  22. package/dist/index.js +15 -0
  23. package/dist/index.js.map +1 -1
  24. package/dist/lib/ai-call.d.ts +12 -0
  25. package/dist/lib/ai-call.js +6 -0
  26. package/dist/lib/ai-call.js.map +1 -1
  27. package/dist/lib/closeout-core.d.ts +46 -0
  28. package/dist/lib/closeout-core.js +34 -0
  29. package/dist/lib/closeout-core.js.map +1 -0
  30. package/dist/lib/closeout-predicate.d.ts +36 -0
  31. package/dist/lib/closeout-predicate.js +130 -0
  32. package/dist/lib/closeout-predicate.js.map +1 -0
  33. package/dist/lib/cost.js +7 -0
  34. package/dist/lib/cost.js.map +1 -1
  35. package/dist/lib/events.d.ts +15 -1
  36. package/dist/lib/events.js.map +1 -1
  37. package/dist/lib/frontmatter.d.ts +38 -0
  38. package/dist/lib/frontmatter.js +76 -0
  39. package/dist/lib/frontmatter.js.map +1 -1
  40. package/dist/lib/gate-executor.d.ts +80 -0
  41. package/dist/lib/gate-executor.js +311 -0
  42. package/dist/lib/gate-executor.js.map +1 -0
  43. package/dist/lib/llm-health.d.ts +28 -0
  44. package/dist/lib/llm-health.js +46 -0
  45. package/dist/lib/llm-health.js.map +1 -0
  46. package/dist/lib/metrics.d.ts +26 -0
  47. package/dist/lib/metrics.js +35 -0
  48. package/dist/lib/metrics.js.map +1 -1
  49. package/dist/lib/next-action.d.ts +10 -4
  50. package/dist/lib/next-action.js +10 -4
  51. package/dist/lib/next-action.js.map +1 -1
  52. package/dist/lib/ollama-embed.d.ts +5 -0
  53. package/dist/lib/ollama-embed.js +5 -0
  54. package/dist/lib/ollama-embed.js.map +1 -1
  55. package/dist/lib/output.d.ts +3 -0
  56. package/dist/lib/output.js +3 -0
  57. package/dist/lib/output.js.map +1 -1
  58. package/dist/lib/pipeline-config.js +10 -0
  59. package/dist/lib/pipeline-config.js.map +1 -1
  60. package/dist/lib/pipeline-map.js +9 -0
  61. package/dist/lib/pipeline-map.js.map +1 -1
  62. package/dist/lib/precedent-search.d.ts +1 -0
  63. package/dist/lib/precedent-search.js +19 -2
  64. package/dist/lib/precedent-search.js.map +1 -1
  65. package/dist/lib/predicate-registry.js +7 -0
  66. package/dist/lib/predicate-registry.js.map +1 -1
  67. package/dist/lib/run-pipeline.d.ts +118 -0
  68. package/dist/lib/run-pipeline.js +106 -0
  69. package/dist/lib/run-pipeline.js.map +1 -0
  70. package/dist/lib/scorecard.js +9 -0
  71. package/dist/lib/scorecard.js.map +1 -1
  72. package/dist/lib/spec-pure.d.ts +69 -4
  73. package/dist/lib/spec-pure.js +125 -15
  74. package/dist/lib/spec-pure.js.map +1 -1
  75. package/dist/lib/specs.d.ts +3 -3
  76. package/dist/lib/specs.js +43 -20
  77. package/dist/lib/specs.js.map +1 -1
  78. package/dist/lib/version.d.ts +1 -1
  79. package/dist/lib/version.js +1 -1
  80. package/dist/lib/walkthrough-coverage.d.ts +81 -0
  81. package/dist/lib/walkthrough-coverage.js +111 -0
  82. package/dist/lib/walkthrough-coverage.js.map +1 -0
  83. 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":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@encore-os/eos-spec",
3
- "version": "0.7.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",