@jevitate/cli 0.9.0 → 0.11.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 (190) hide show
  1. package/dist/anchor-baselines.d.ts +26 -0
  2. package/dist/anchor-baselines.js +25 -0
  3. package/dist/anchor-baselines.js.map +1 -0
  4. package/dist/approval-provenance.d.ts +32 -2
  5. package/dist/approval-provenance.js +92 -5
  6. package/dist/approval-provenance.js.map +1 -1
  7. package/dist/approved-demo.d.ts +86 -0
  8. package/dist/approved-demo.js +184 -0
  9. package/dist/approved-demo.js.map +1 -0
  10. package/dist/bin.js +13352 -7050
  11. package/dist/build-info.generated.js +2 -2
  12. package/dist/campaign-api.d.ts +15 -0
  13. package/dist/campaign-api.js +67 -6
  14. package/dist/campaign-api.js.map +1 -1
  15. package/dist/campaign-cli.js +7 -2
  16. package/dist/campaign-cli.js.map +1 -1
  17. package/dist/campaign-preflight.d.ts +76 -0
  18. package/dist/campaign-preflight.js +117 -0
  19. package/dist/campaign-preflight.js.map +1 -0
  20. package/dist/catalog-analysis.js +14 -0
  21. package/dist/catalog-analysis.js.map +1 -1
  22. package/dist/catalog-api.js +12 -4
  23. package/dist/catalog-api.js.map +1 -1
  24. package/dist/catalog-bundle-api.d.ts +83 -0
  25. package/dist/catalog-bundle-api.js +309 -0
  26. package/dist/catalog-bundle-api.js.map +1 -0
  27. package/dist/catalog-bundle-findings.d.ts +64 -0
  28. package/dist/catalog-bundle-findings.js +326 -0
  29. package/dist/catalog-bundle-findings.js.map +1 -0
  30. package/dist/catalog-bundle.d.ts +296 -0
  31. package/dist/catalog-bundle.js +777 -0
  32. package/dist/catalog-bundle.js.map +1 -0
  33. package/dist/catalog-cli.d.ts +6 -0
  34. package/dist/catalog-cli.js +181 -5
  35. package/dist/catalog-cli.js.map +1 -1
  36. package/dist/catalog-refs.d.ts +42 -0
  37. package/dist/catalog-refs.js +188 -0
  38. package/dist/catalog-refs.js.map +1 -0
  39. package/dist/catalog-review.d.ts +3 -1
  40. package/dist/catalog-review.js +61 -0
  41. package/dist/catalog-review.js.map +1 -1
  42. package/dist/catalog.d.ts +27 -3
  43. package/dist/catalog.js +46 -2
  44. package/dist/catalog.js.map +1 -1
  45. package/dist/check-api.js +180 -9
  46. package/dist/check-api.js.map +1 -1
  47. package/dist/check-cli.d.ts +2 -0
  48. package/dist/check-cli.js +96 -2
  49. package/dist/check-cli.js.map +1 -1
  50. package/dist/check-execute.d.ts +18 -0
  51. package/dist/check-execute.js +56 -3
  52. package/dist/check-execute.js.map +1 -1
  53. package/dist/check-types.d.ts +105 -0
  54. package/dist/check-types.js.map +1 -1
  55. package/dist/cli-output.d.ts +6 -0
  56. package/dist/cli-output.js +38 -1
  57. package/dist/cli-output.js.map +1 -1
  58. package/dist/cli-shared.d.ts +10 -0
  59. package/dist/cli-shared.js +0 -4
  60. package/dist/cli-shared.js.map +1 -1
  61. package/dist/cold-start-report.d.ts +32 -0
  62. package/dist/cold-start-report.js +31 -0
  63. package/dist/cold-start-report.js.map +1 -0
  64. package/dist/defect-evidence.js +10 -5
  65. package/dist/defect-evidence.js.map +1 -1
  66. package/dist/demo-aspect-api.d.ts +11 -0
  67. package/dist/demo-aspect-api.js +27 -2
  68. package/dist/demo-aspect-api.js.map +1 -1
  69. package/dist/demo-aspect-cli.js +5 -0
  70. package/dist/demo-aspect-cli.js.map +1 -1
  71. package/dist/demo-capture.d.ts +79 -2
  72. package/dist/demo-capture.js +504 -12
  73. package/dist/demo-capture.js.map +1 -1
  74. package/dist/environments.d.ts +8 -1
  75. package/dist/environments.js +14 -3
  76. package/dist/environments.js.map +1 -1
  77. package/dist/exit-codes.js +16 -0
  78. package/dist/exit-codes.js.map +1 -1
  79. package/dist/explore-adversarial.js +2 -2
  80. package/dist/explore-adversarial.js.map +1 -1
  81. package/dist/explore-shared.d.ts +11 -0
  82. package/dist/explore-shared.js +9 -0
  83. package/dist/explore-shared.js.map +1 -1
  84. package/dist/findings-filing.js +7 -3
  85. package/dist/findings-filing.js.map +1 -1
  86. package/dist/forge-verify.d.ts +224 -0
  87. package/dist/forge-verify.js +649 -0
  88. package/dist/forge-verify.js.map +1 -0
  89. package/dist/github-issue-filer.js +15 -9
  90. package/dist/github-issue-filer.js.map +1 -1
  91. package/dist/init-codeowners.d.ts +19 -0
  92. package/dist/init-codeowners.js +66 -0
  93. package/dist/init-codeowners.js.map +1 -1
  94. package/dist/job-draft-api.d.ts +52 -0
  95. package/dist/job-draft-api.js +110 -0
  96. package/dist/job-draft-api.js.map +1 -0
  97. package/dist/journeeze-api.d.ts +77 -0
  98. package/dist/journeeze-api.js +371 -0
  99. package/dist/journeeze-api.js.map +1 -0
  100. package/dist/journeeze-connect.d.ts +156 -0
  101. package/dist/journeeze-connect.js +357 -0
  102. package/dist/journeeze-connect.js.map +1 -0
  103. package/dist/journey-anchor-api.d.ts +37 -0
  104. package/dist/journey-anchor-api.js +58 -0
  105. package/dist/journey-anchor-api.js.map +1 -0
  106. package/dist/journey-anchor-cli.d.ts +17 -0
  107. package/dist/journey-anchor-cli.js +104 -0
  108. package/dist/journey-anchor-cli.js.map +1 -0
  109. package/dist/journey-anchor-gate.d.ts +52 -0
  110. package/dist/journey-anchor-gate.js +101 -0
  111. package/dist/journey-anchor-gate.js.map +1 -0
  112. package/dist/journey-api.d.ts +30 -1
  113. package/dist/journey-api.js +118 -16
  114. package/dist/journey-api.js.map +1 -1
  115. package/dist/journey-cli.js +93 -10
  116. package/dist/journey-cli.js.map +1 -1
  117. package/dist/journey-demo-api.d.ts +29 -0
  118. package/dist/journey-demo-api.js +29 -7
  119. package/dist/journey-demo-api.js.map +1 -1
  120. package/dist/journey-heal.js +1 -1
  121. package/dist/journey-heal.js.map +1 -1
  122. package/dist/journey-lint-sarif.d.ts +3 -2
  123. package/dist/journey-lint-sarif.js +11 -2
  124. package/dist/journey-lint-sarif.js.map +1 -1
  125. package/dist/journey-migrate-api.d.ts +54 -0
  126. package/dist/journey-migrate-api.js +64 -0
  127. package/dist/journey-migrate-api.js.map +1 -0
  128. package/dist/journey-network-checks.d.ts +11 -0
  129. package/dist/journey-network-checks.js +36 -13
  130. package/dist/journey-network-checks.js.map +1 -1
  131. package/dist/journey-proposal-store.d.ts +9 -0
  132. package/dist/journey-proposal-store.js +23 -0
  133. package/dist/journey-proposal-store.js.map +1 -1
  134. package/dist/journey-result-record.d.ts +2 -0
  135. package/dist/journey-result-record.js +5 -0
  136. package/dist/journey-result-record.js.map +1 -1
  137. package/dist/journey-review-api.js +9 -1
  138. package/dist/journey-review-api.js.map +1 -1
  139. package/dist/journey-review.d.ts +11 -1
  140. package/dist/journey-review.js +77 -5
  141. package/dist/journey-review.js.map +1 -1
  142. package/dist/journey-stale-api.d.ts +40 -0
  143. package/dist/journey-stale-api.js +57 -0
  144. package/dist/journey-stale-api.js.map +1 -0
  145. package/dist/load-api.js +4 -2
  146. package/dist/load-api.js.map +1 -1
  147. package/dist/locator-health-api.d.ts +101 -0
  148. package/dist/locator-health-api.js +203 -0
  149. package/dist/locator-health-api.js.map +1 -0
  150. package/dist/locator-health.d.ts +195 -0
  151. package/dist/locator-health.js +419 -0
  152. package/dist/locator-health.js.map +1 -0
  153. package/dist/mcp-api.d.ts +3 -1
  154. package/dist/mcp-api.js +21 -2
  155. package/dist/mcp-api.js.map +1 -1
  156. package/dist/mcp-cli-tools.d.ts +4 -1
  157. package/dist/mcp-cli-tools.js +82 -10
  158. package/dist/mcp-cli-tools.js.map +1 -1
  159. package/dist/openrouter-call.d.ts +23 -10
  160. package/dist/openrouter-call.js +14 -11
  161. package/dist/openrouter-call.js.map +1 -1
  162. package/dist/png-pixels.d.ts +12 -0
  163. package/dist/png-pixels.js +96 -0
  164. package/dist/png-pixels.js.map +1 -0
  165. package/dist/project-config.d.ts +29 -0
  166. package/dist/project-config.js +76 -0
  167. package/dist/project-config.js.map +1 -0
  168. package/dist/regression-api.js +2 -1
  169. package/dist/regression-api.js.map +1 -1
  170. package/dist/server-log-verify.js +2 -1
  171. package/dist/server-log-verify.js.map +1 -1
  172. package/dist/signal-triage.js +7 -3
  173. package/dist/signal-triage.js.map +1 -1
  174. package/dist/source-run-api.js +2 -2
  175. package/dist/source-run-api.js.map +1 -1
  176. package/dist/verify-fix-api.d.ts +29 -0
  177. package/dist/verify-fix-api.js +43 -2
  178. package/dist/verify-fix-api.js.map +1 -1
  179. package/dist/verify-fix-cli.js +4 -0
  180. package/dist/verify-fix-cli.js.map +1 -1
  181. package/dist/zip-store.d.ts +15 -0
  182. package/dist/zip-store.js +93 -0
  183. package/dist/zip-store.js.map +1 -0
  184. package/package.json +12 -10
  185. package/skills/jevitate-ci-check/SKILL.md +16 -0
  186. package/skills/jevitate-demo/SKILL.md +4 -1
  187. package/skills/jevitate-getting-started/SKILL.md +7 -2
  188. package/skills/jevitate-run-journey/SKILL.md +15 -0
  189. package/skills/jevitate-test-campaign/SKILL.md +26 -0
  190. package/skills/jevitate-verify-fix/SKILL.md +5 -0
@@ -0,0 +1,309 @@
1
+ import { createHash, randomBytes } from "node:crypto";
2
+ import { existsSync } from "node:fs";
3
+ import { copyFile, lstat, mkdir, open, readdir, readFile, rename, rm, writeFile } from "node:fs/promises";
4
+ import { basename, dirname, join, resolve, sep } from "node:path";
5
+ import { CatalogInputError, CatalogLoader, PERSONAS_FILE } from "./catalog.js";
6
+ import { buildCatalogBundle, BUNDLE_KIND, looksPersonal, subtitlesTextProblem } from "./catalog-bundle.js";
7
+ import { currentDigest, readApprovedDemo } from "./approved-demo.js";
8
+ import { collectBundleFindings, locatorFindings } from "./catalog-bundle-findings.js";
9
+ import { execGitReadOnly } from "./change-context.js";
10
+ import { testIdAttributesOrDefault } from "./locator-health-api.js";
11
+ import { readCliVersion } from "./version.js";
12
+ /**
13
+ * #464 — `jevitate catalog export --format journeeze-bundle --out <dir>` / MCP
14
+ * `export_catalog_bundle`: write the project's catalog (personas, jobs, promoted Journeys with their
15
+ * approvals and links, check results with machine baselines) as a Journeeze catalog bundle v1.0
16
+ * (journeeze-saas `docs/contract/catalog-bundle-v1.md` @ 61f8c92). The bundle itself is built by the
17
+ * pure `buildCatalogBundle` (catalog-bundle.ts — what goes out and what never does is documented
18
+ * there); this module does the I/O around it.
19
+ *
20
+ * It writes `bundle.json` under `outDir` (atomically: a temp file renamed into place; over MCP
21
+ * `outDir` is a confined path inside the project) and, #471, the approved demos' media under
22
+ * `outDir/media/<journey id>/` (contract §2), refuses an `outDir` holding anything but a previous
23
+ * bundle, never uploads (that is `publish journeeze`) and never approves anything.
24
+ *
25
+ * #471 media: a Journey's approved-demo record (approved-demo.ts, `<journeys>/.demos/<id>/`) is
26
+ * read only for a promoted Journey; every file it lists is re-verified here — present, the sha256
27
+ * and size recorded when it was proven masked, and the right kind of file (PNG / WebM signature,
28
+ * WebVTT whose every cue is §7 machine text) — or it is left out with a warning. The pure builder
29
+ * then applies the contract's text rules and limits.
30
+ *
31
+ * Inputs it reads: `<catalogDir>/personas.json` + `jobs.json`, the Journeys dir, and the
32
+ * `jevitate check` records — `req.checkFiles`, else `<project>/jevitate-check/check.json` (the
33
+ * `check --out` default) when it exists. The product repo's HEAD (`git rev-parse HEAD`) is
34
+ * `producer.commit`; a check's commit is its `--target-build`.
35
+ */
36
+ export const CATALOG_EXPORT_FORMATS = ["journeeze-bundle"];
37
+ /** `--out` would overwrite something that is not a bundle (or is not a directory) — exit 64. */
38
+ export class CatalogExportOutError extends CatalogInputError {
39
+ code = "E_CATALOG_EXPORT_ARGS";
40
+ }
41
+ /** The contract's `bundle.json` cap (§10). */
42
+ export const MAX_BUNDLE_BYTES = 16 * 1024 * 1024;
43
+ export const BUNDLE_FILE = "bundle.json";
44
+ /** #471: the bundle's media folder (contract §2). */
45
+ export const MEDIA_DIR = "media";
46
+ export const DEFAULT_CHECK_FILE = join("jevitate-check", "check.json");
47
+ function isRecord(v) {
48
+ return v !== null && typeof v === "object" && !Array.isArray(v);
49
+ }
50
+ async function readJson(path, what) {
51
+ const raw = await readFile(path, "utf8");
52
+ try {
53
+ return JSON.parse(raw);
54
+ }
55
+ catch (err) {
56
+ throw new CatalogInputError(`${what} ${path} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
57
+ }
58
+ }
59
+ /** Each persona's raw keys (all but `name`/`id`), in both personas.json forms — the persona hash input. */
60
+ async function rawPersonaFields(catalogDir) {
61
+ const out = new Map();
62
+ if (catalogDir === null)
63
+ return out;
64
+ const path = join(catalogDir, PERSONAS_FILE);
65
+ if (!existsSync(path))
66
+ return out;
67
+ const raw = await readJson(path, "personas file");
68
+ const list = Array.isArray(raw) ? raw : isRecord(raw) && Array.isArray(raw.personas) ? raw.personas : null;
69
+ if (list !== null) {
70
+ for (const e of list) {
71
+ if (!isRecord(e))
72
+ continue;
73
+ const { name, id, ...fields } = e;
74
+ const key = name ?? id;
75
+ if (typeof key === "string")
76
+ out.set(key, fields);
77
+ }
78
+ }
79
+ else if (isRecord(raw)) {
80
+ for (const [id, v] of Object.entries(raw))
81
+ out.set(id, typeof v === "string" ? { storageState: v } : isRecord(v) ? { ...v } : {});
82
+ }
83
+ return out;
84
+ }
85
+ async function gitOut(git, cwd, args) {
86
+ try {
87
+ return (await git(args, { cwd, env: process.env })).stdout.trim();
88
+ }
89
+ catch {
90
+ return null;
91
+ }
92
+ }
93
+ /** `product.name`: the request's, else the project's package.json name, else its folder name — whichever is one plain line. */
94
+ export function isPlainProductName(s) {
95
+ return typeof s === "string" && s.trim() !== "" && s.length <= 200 && !/[\u0000-\u001f\u007f]/u.test(s) && !looksPersonal(s);
96
+ }
97
+ async function productNameOf(req, root) {
98
+ const ok = isPlainProductName;
99
+ if (req.productName !== undefined) {
100
+ if (!ok(req.productName))
101
+ throw new CatalogExportOutError("productName must be one plain line of 1-200 characters (no control characters or personal data)");
102
+ return req.productName;
103
+ }
104
+ const pkg = join(root, "package.json");
105
+ if (existsSync(pkg)) {
106
+ try {
107
+ const name = JSON.parse(await readFile(pkg, "utf8")).name;
108
+ if (ok(name))
109
+ return name;
110
+ }
111
+ catch {
112
+ // not a readable package.json: fall back to the folder name
113
+ }
114
+ }
115
+ const folder = basename(root);
116
+ return ok(folder) ? folder : "jevitate-project";
117
+ }
118
+ /** Refuses an `outDir` that is not a directory, or that holds anything but a previous `bundle.json`. */
119
+ async function assertBundleDir(outDir) {
120
+ let st;
121
+ try {
122
+ st = await lstat(outDir);
123
+ }
124
+ catch {
125
+ return; // missing: created
126
+ }
127
+ if (!st.isDirectory())
128
+ throw new CatalogExportOutError(`--out ${outDir} exists and is not a directory`);
129
+ const entries = await readdir(outDir);
130
+ // A previous bundle's media folder is replaced with the bundle (never without its bundle.json).
131
+ const other = entries.filter((e) => e !== BUNDLE_FILE && !(e === MEDIA_DIR && entries.includes(BUNDLE_FILE)));
132
+ if (other.length > 0) {
133
+ throw new CatalogExportOutError(`--out ${outDir} holds other content (${other.slice(0, 5).join(", ")}${other.length > 5 ? ", …" : ""}) — export into an empty directory or a previous bundle's`);
134
+ }
135
+ if (entries.includes(BUNDLE_FILE)) {
136
+ const file = join(outDir, BUNDLE_FILE);
137
+ const fst = await lstat(file);
138
+ let kind;
139
+ try {
140
+ kind = fst.isFile() ? JSON.parse(await readFile(file, "utf8")).kind : undefined;
141
+ }
142
+ catch {
143
+ kind = undefined;
144
+ }
145
+ if (kind !== BUNDLE_KIND)
146
+ throw new CatalogExportOutError(`--out ${outDir}: ${BUNDLE_FILE} there is not a Journeeze catalog bundle — not overwritten`);
147
+ }
148
+ if (entries.includes(MEDIA_DIR) && !(await lstat(join(outDir, MEDIA_DIR))).isDirectory())
149
+ throw new CatalogExportOutError(`--out ${outDir}: ${MEDIA_DIR} there is not a directory — not overwritten`);
150
+ }
151
+ const PNG_MAGIC = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
152
+ const WEBM_MAGIC = Buffer.from([0x1a, 0x45, 0xdf, 0xa3]);
153
+ async function head(path, n) {
154
+ const fh = await open(path, "r");
155
+ try {
156
+ const buf = Buffer.alloc(n);
157
+ const { bytesRead } = await fh.read(buf, 0, n, 0);
158
+ return buf.subarray(0, bytesRead);
159
+ }
160
+ finally {
161
+ await fh.close();
162
+ }
163
+ }
164
+ /**
165
+ * #471: the approved demos of the catalog's promoted Journeys, with each media file re-verified on
166
+ * disk (else left out with a warning). A Journey without a record has no exportable demo (a draft,
167
+ * or one approved on an environment that does not declare synthetic data): nothing is said.
168
+ */
169
+ async function approvedDemos(journeysDir, ids, warnings) {
170
+ const out = [];
171
+ for (const id of ids) {
172
+ let found;
173
+ try {
174
+ found = await readApprovedDemo(journeysDir, id);
175
+ }
176
+ catch (err) {
177
+ warnings.push(`demo ${id}: its approved-demo record is unreadable (${err instanceof Error ? err.message : String(err)}) — the demo is left out`);
178
+ continue;
179
+ }
180
+ if (found === null)
181
+ continue;
182
+ const { record, dir } = found;
183
+ const media = {};
184
+ for (const [name, want] of Object.entries(record.files)) {
185
+ const source = join(dir, name);
186
+ const got = await currentDigest(source);
187
+ if (got === null) {
188
+ warnings.push(`demo ${id}: ${name} is missing — left out`);
189
+ continue;
190
+ }
191
+ if (got.sha256 !== want.sha256 || got.bytes !== want.bytes) {
192
+ warnings.push(`demo ${id}: ${name} changed since it was proven masked — left out`);
193
+ continue;
194
+ }
195
+ let kindProblem = null;
196
+ if (name.endsWith(".png"))
197
+ kindProblem = (await head(source, 8)).equals(PNG_MAGIC) ? null : "is not a PNG";
198
+ else if (name.endsWith(".webm"))
199
+ kindProblem = (await head(source, 4)).equals(WEBM_MAGIC) ? null : "is not a WebM";
200
+ else if (name.endsWith(".vtt")) {
201
+ const p = subtitlesTextProblem(await readFile(source, "utf8"));
202
+ kindProblem = p === null ? null : `breaks the text rules (${p})`;
203
+ }
204
+ else
205
+ kindProblem = "is not a demo media file";
206
+ if (kindProblem !== null) {
207
+ warnings.push(`demo ${id}: ${name} ${kindProblem} — left out`);
208
+ continue;
209
+ }
210
+ media[name] = { source, ...got };
211
+ }
212
+ out.push({
213
+ journey: record.journey,
214
+ renderedFrom: record.renderedFrom,
215
+ ...(record.title === undefined ? {} : { title: record.title }),
216
+ steps: record.steps,
217
+ ...(record.video === undefined ? {} : { video: record.video }),
218
+ ...(record.subtitles === undefined ? {} : { subtitles: record.subtitles }),
219
+ privacy: record.privacy,
220
+ media,
221
+ });
222
+ }
223
+ return out;
224
+ }
225
+ export async function exportCatalogBundle(req, deps = {}) {
226
+ const git = deps.git ?? execGitReadOnly;
227
+ const outDir = resolve(req.outDir);
228
+ await assertBundleDir(outDir);
229
+ const root = req.catalogDir === null ? process.cwd() : dirname(resolve(req.catalogDir));
230
+ const catalog = await new CatalogLoader({ catalogDir: req.catalogDir, journeysDir: req.journeysDir }).load();
231
+ const personaFields = await rawPersonaFields(req.catalogDir);
232
+ const checkFiles = req.checkFiles ?? [join(root, DEFAULT_CHECK_FILE)].filter((p) => existsSync(p));
233
+ const checks = [];
234
+ for (const f of checkFiles)
235
+ checks.push({ source: f, record: await readJson(f, "check record") });
236
+ const warnings = [];
237
+ const head = await gitOut(git, root, ["rev-parse", "--verify", "--quiet", "HEAD"]);
238
+ if (head === null || head === "")
239
+ warnings.push(`${root} is not a git checkout with a commit — the bundle names no producer commit`);
240
+ else {
241
+ for (const dir of [req.catalogDir, req.journeysDir]) {
242
+ if (dir === null || !existsSync(dir))
243
+ continue;
244
+ const dirty = await gitOut(git, root, ["status", "--porcelain", "--", resolve(dir)]);
245
+ if (dirty !== null && dirty !== "")
246
+ warnings.push(`${dir} has uncommitted changes — the bundle is the working tree, but its producer commit is HEAD (${head.slice(0, 12)})`);
247
+ }
248
+ }
249
+ const found = deps.findings === undefined ? await collectBundleFindings({ root, dataDir: req.catalogDir }) : { findings: await deps.findings(), warnings: [] };
250
+ const demoWarnings = [];
251
+ const demos = await approvedDemos(req.journeysDir, catalog.journeys.filter((j) => j.promoted).map((j) => j.id), demoWarnings);
252
+ const locators = locatorFindings(catalog.journeys.filter((j) => j.promoted), testIdAttributesOrDefault(req.catalogDir));
253
+ const collected = new Set(found.findings.map((f) => f.fingerprint));
254
+ const { bundle, media, warnings: buildWarnings } = buildCatalogBundle({
255
+ producer: { version: (deps.version ?? readCliVersion)(), ...(head === null || head === "" ? {} : { commit: head }) },
256
+ productName: await productNameOf(req, root),
257
+ catalog,
258
+ personaFields,
259
+ checks,
260
+ findings: [...found.findings, ...locators.findings.filter((f) => !collected.has(f.fingerprint))],
261
+ demos,
262
+ });
263
+ const text = `${JSON.stringify(bundle, null, 2)}\n`;
264
+ const bytes = Buffer.byteLength(text, "utf8");
265
+ if (bytes > MAX_BUNDLE_BYTES)
266
+ throw new CatalogInputError(`the bundle is ${bytes} bytes; the contract's limit is ${MAX_BUNDLE_BYTES} (16 MiB)`);
267
+ await mkdir(outDir, { recursive: true });
268
+ // #471: the media first (a fresh folder), then bundle.json — a bundle never names a file it lacks.
269
+ const mediaDir = join(outDir, MEDIA_DIR);
270
+ await rm(mediaDir, { recursive: true, force: true });
271
+ for (const m of media) {
272
+ const to = join(outDir, ...m.path.split("/"));
273
+ if (!resolve(to).startsWith(`${mediaDir}${sep}`))
274
+ throw new CatalogInputError(`media path ${m.path} leaves the bundle's media folder`);
275
+ await mkdir(dirname(to), { recursive: true });
276
+ await copyFile(m.source, to);
277
+ }
278
+ const bundlePath = join(outDir, BUNDLE_FILE);
279
+ const tmp = join(outDir, `.${BUNDLE_FILE}.${randomBytes(6).toString("hex")}.tmp`);
280
+ try {
281
+ await writeFile(tmp, text, { encoding: "utf8", flag: "wx" });
282
+ await rename(tmp, bundlePath);
283
+ }
284
+ catch (err) {
285
+ await rm(tmp, { force: true });
286
+ throw err;
287
+ }
288
+ return {
289
+ format: req.format,
290
+ bundlePath,
291
+ digest: `sha256-${createHash("sha256").update(text, "utf8").digest("hex")}`,
292
+ counts: {
293
+ personas: bundle.catalog.personas.length,
294
+ jobs: bundle.catalog.jobs.length,
295
+ journeys: bundle.catalog.journeys.length,
296
+ checks: bundle.checks.length,
297
+ findings: bundle.findings.length,
298
+ demos: bundle.demos?.length ?? 0,
299
+ media: bundle.files?.length ?? 0,
300
+ },
301
+ warnings: [...warnings, ...found.warnings, ...locators.warnings, ...demoWarnings, ...buildWarnings],
302
+ };
303
+ }
304
+ /** The human rendering (no `--json`). */
305
+ export function renderCatalogExport(r) {
306
+ const c = r.counts;
307
+ return `wrote ${r.bundlePath} (${r.digest}): ${c.personas} persona(s), ${c.jobs} job(s), ${c.journeys} Journey(s), ${c.demos} demo(s) with ${c.media} media file(s), ${c.checks} check(s), ${c.findings} finding(s)\n${r.warnings.map((w) => `warning: ${w}\n`).join("")}`;
308
+ }
309
+ //# sourceMappingURL=catalog-bundle-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-bundle-api.js","sourceRoot":"","sources":["../src/catalog-bundle-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1G,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,aAAa,EAAE,oBAAoB,EAAiF,MAAM,qBAAqB,CAAC;AAC1L,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACtF,OAAO,EAAE,eAAe,EAAgB,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,kBAAkB,CAAU,CAAC;AA6CpE,gGAAgG;AAChG,MAAM,OAAO,qBAAsB,SAAQ,iBAAiB;IACxC,IAAI,GAAW,uBAAuB,CAAC;CAC1D;AAED,8CAA8C;AAC9C,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AACjD,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;AACzC,qDAAqD;AACrD,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC;AACjC,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAC;AAEvE,SAAS,QAAQ,CAAC,CAAU;IAC1B,OAAO,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,IAAY,EAAE,IAAY;IAChD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACzC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,iBAAiB,CAAC,GAAG,IAAI,IAAI,IAAI,uBAAuB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACxH,CAAC;AACH,CAAC;AAED,2GAA2G;AAC3G,KAAK,UAAU,gBAAgB,CAAC,UAAyB;IACvD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAmC,CAAC;IACvD,IAAI,UAAU,KAAK,IAAI;QAAE,OAAO,GAAG,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IAC7C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC;IAClC,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3G,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAAE,SAAS;YAC3B,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,MAAM,EAAE,GAAG,CAAC,CAAC;YAClC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,OAAO,GAAG,KAAK,QAAQ;gBAAE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;SAAM,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC;YAAE,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpI,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,GAAY,EAAE,GAAW,EAAE,IAAc;IAC7D,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,+HAA+H;AAC/H,MAAM,UAAU,kBAAkB,CAAC,CAAU;IAC3C,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AAC/H,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,GAA+B,EAAE,IAAY;IACxE,MAAM,EAAE,GAAG,kBAAkB,CAAC;IAC9B,IAAI,GAAG,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QAClC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC;YAAE,MAAM,IAAI,qBAAqB,CAAC,iGAAiG,CAAC,CAAC;QAC7J,OAAO,GAAG,CAAC,WAAW,CAAC;IACzB,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IACvC,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,IAAI,GAAI,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAwB,CAAC,IAAI,CAAC;YAClF,IAAI,EAAE,CAAC,IAAI,CAAC;gBAAE,OAAO,IAAI,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,4DAA4D;QAC9D,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC;AAClD,CAAC;AAED,wGAAwG;AACxG,KAAK,UAAU,eAAe,CAAC,MAAc;IAC3C,IAAI,EAAE,CAAC;IACP,IAAI,CAAC;QACH,EAAE,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,mBAAmB;IAC7B,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE;QAAE,MAAM,IAAI,qBAAqB,CAAC,SAAS,MAAM,gCAAgC,CAAC,CAAC;IACxG,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACtC,gGAAgG;IAChG,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,WAAW,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAC9G,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,qBAAqB,CAAC,SAAS,MAAM,yBAAyB,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,2DAA2D,CAAC,CAAC;IACnM,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAwB,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1G,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,GAAG,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,IAAI,KAAK,WAAW;YAAE,MAAM,IAAI,qBAAqB,CAAC,SAAS,MAAM,KAAK,WAAW,4DAA4D,CAAC,CAAC;IACzJ,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;QAAE,MAAM,IAAI,qBAAqB,CAAC,SAAS,MAAM,KAAK,SAAS,6CAA6C,CAAC,CAAC;AACxM,CAAC;AAED,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AAChF,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AAEzD,KAAK,UAAU,IAAI,CAAC,IAAY,EAAE,CAAS;IACzC,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAClD,OAAO,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IACpC,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,aAAa,CAAC,WAAmB,EAAE,GAAsB,EAAE,QAAkB;IAC1F,MAAM,GAAG,GAA6B,EAAE,CAAC;IACzC,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACrB,IAAI,KAAmD,CAAC;QACxD,IAAI,CAAC;YACH,KAAK,GAAG,MAAM,gBAAgB,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,6CAA6C,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;YACjJ,SAAS;QACX,CAAC;QACD,IAAI,KAAK,KAAK,IAAI;YAAE,SAAS;QAC7B,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;QAC9B,MAAM,KAAK,GAAsE,EAAE,CAAC;QACpF,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACxD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAC/B,MAAM,GAAG,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;YACxC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBACjB,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI,wBAAwB,CAAC,CAAC;gBAC3D,SAAS;YACX,CAAC;YACD,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC3D,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI,gDAAgD,CAAC,CAAC;gBACnF,SAAS;YACX,CAAC;YACD,IAAI,WAAW,GAAkB,IAAI,CAAC;YACtC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAAE,WAAW,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC;iBACtG,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAE,WAAW,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC;iBAC9G,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC/B,MAAM,CAAC,GAAG,oBAAoB,CAAC,MAAM,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;gBAC/D,WAAW,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,0BAA0B,CAAC,GAAG,CAAC;YACnE,CAAC;;gBAAM,WAAW,GAAG,0BAA0B,CAAC;YAChD,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;gBACzB,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI,IAAI,WAAW,aAAa,CAAC,CAAC;gBAC/D,SAAS;YACX,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAG,EAAE,CAAC;QACnC,CAAC;QACD,GAAG,CAAC,IAAI,CAAC;YACP,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;YAC9D,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;YAC9D,GAAG,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC;YAC1E,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,KAAK;SACN,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,GAA+B,EAAE,OAAgC,EAAE;IAC3G,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,eAAe,CAAC;IACxC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACnC,MAAM,eAAe,CAAC,MAAM,CAAC,CAAC;IAE9B,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;IACxF,MAAM,OAAO,GAAG,MAAM,IAAI,aAAa,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7G,MAAM,aAAa,GAAG,MAAM,gBAAgB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAE7D,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IACnG,MAAM,MAAM,GAAuB,EAAE,CAAC;IACtC,KAAK,MAAM,CAAC,IAAI,UAAU;QAAE,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC,CAAC,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC;IAElG,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;IACnF,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,4EAA4E,CAAC,CAAC;SAChI,CAAC;QACJ,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YACpD,IAAI,GAAG,KAAK,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAS;YAC/C,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACrF,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE;gBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,GAAG,+FAA+F,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;QAC/K,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,qBAAqB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC/J,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC;IAC9H,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,yBAAyB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;IACxH,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;IACpE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,kBAAkB,CAAC;QACpE,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,OAAO,IAAI,cAAc,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE;QACpH,WAAW,EAAE,MAAM,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC;QAC3C,OAAO;QACP,aAAa;QACb,MAAM;QACN,QAAQ,EAAE,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;QAChG,KAAK;KACN,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;IACpD,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC9C,IAAI,KAAK,GAAG,gBAAgB;QAAE,MAAM,IAAI,iBAAiB,CAAC,iBAAiB,KAAK,mCAAmC,gBAAgB,WAAW,CAAC,CAAC;IAChJ,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,mGAAmG;IACnG,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACzC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,QAAQ,GAAG,GAAG,EAAE,CAAC;YAAE,MAAM,IAAI,iBAAiB,CAAC,cAAc,CAAC,CAAC,IAAI,mCAAmC,CAAC,CAAC;QACvI,MAAM,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,MAAM,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC/B,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,WAAW,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAClF,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7D,MAAM,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/B,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,OAAO;QACL,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,UAAU;QACV,MAAM,EAAE,UAAU,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;QAC3E,MAAM,EAAE;YACN,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM;YACxC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM;YAChC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM;YACxC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM;YAC5B,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM;YAChC,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;YAChC,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;SACjC;QACD,QAAQ,EAAE,CAAC,GAAG,QAAQ,EAAE,GAAG,KAAK,CAAC,QAAQ,EAAE,GAAG,QAAQ,CAAC,QAAQ,EAAE,GAAG,YAAY,EAAE,GAAG,aAAa,CAAC;KACpG,CAAC;AACJ,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,mBAAmB,CAAC,CAA4B;IAC9D,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IACnB,OAAO,SAAS,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,QAAQ,gBAAgB,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC,QAAQ,gBAAgB,CAAC,CAAC,KAAK,iBAAiB,CAAC,CAAC,KAAK,mBAAmB,CAAC,CAAC,MAAM,cAAc,CAAC,CAAC,QAAQ,gBAAgB,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;AAC7Q,CAAC"}
@@ -0,0 +1,64 @@
1
+ import { type RunRecord } from "@jevitate/findings";
2
+ import { type CatalogBundleFinding } from "./catalog-bundle.js";
3
+ import type { CatalogJourney } from "./catalog.js";
4
+ import type { RunIndexDeps } from "./run-index.js";
5
+ /**
6
+ * #464 (d464c) — the machine findings a Journeeze catalog bundle carries (journeeze-saas
7
+ * `docs/contract/catalog-bundle-v1.md` §4.4 @ 61f8c92): UX claims, defects and hangs, one per
8
+ * fingerprint (the latest sighting wins). It only READS what the runners persisted (every result
9
+ * was redacted before it was written), from the same places `jevitate report` reads — this
10
+ * project's logs and its indexed runs — plus offline `ux-<stamp>.json` reviews and the committed
11
+ * finding ledger.
12
+ *
13
+ * - Defects and hangs: `jevitate report`'s deduped list (`consolidate`), with jevitate's own
14
+ * fingerprint. A declared invariant is a defect. Advisory flags, Journey assertions, goal checks
15
+ * and approvals have no fingerprint and are not bundle finding kinds: they stay out. The tflowId
16
+ * is the acting step's (`identity.tflowId`, #468).
17
+ * - UX: each shown finding of a usability or `ux` report (never the heuristic appendix), with the
18
+ * contract's derived fingerprint (`uxFindingFingerprint`) over the EXPORTED claim, route and
19
+ * element — the reader recomputes it. A claim type the contract does not know (a rubric or signal
20
+ * finding) goes as `other` + `producerClaim`. On-screen `quotes` are never exported.
21
+ * - Routes are templates (`contractRouteTemplate`: no host, query, fragment or record id).
22
+ * - Privacy: each finding passes the builder's own guard (`findingIssues`: no personal data, URL
23
+ * or record id in any text). A finding that cannot is LEFT OUT with a warning naming only its
24
+ * fingerprint and why — never rewritten into something it did not say, and never allowed to
25
+ * refuse the whole export. A defect whose own title cannot travel is described by its signal and
26
+ * route instead (producer-written text).
27
+ * - No media in 0.10 (no `screenshot`/`box`).
28
+ */
29
+ export interface UxReportSource {
30
+ /** The `UxReport` (a usability report file, a usability result's `result.report`, or an offline `ux` review). */
31
+ readonly report: unknown;
32
+ /** The run it came from: when, which build, which Journey step it branched from. */
33
+ readonly run: RunRecord;
34
+ }
35
+ export interface FindingSources {
36
+ readonly runs: readonly RunRecord[];
37
+ readonly uxReports: readonly UxReportSource[];
38
+ }
39
+ export interface BundleFindings {
40
+ readonly findings: readonly CatalogBundleFinding[];
41
+ /** Findings left out or degraded, each with why. */
42
+ readonly warnings: readonly string[];
43
+ }
44
+ /** The bundle's findings from what the runs persisted (pure): one per fingerprint, latest sighting first-class. */
45
+ export declare function bundleFindings(src: FindingSources): BundleFindings;
46
+ /**
47
+ * #479 (minor 1) — the locator findings: one per brittle ELEMENT (§4.4, spec bundle-minor1 §1). Each
48
+ * promoted Journey's locator health (`journeyLocatorHealth`) becomes suggestions, de-duplicated by
49
+ * element across Journeys; each suggestion is a `kind: "ux"` / claim `other` / producerClaim
50
+ * `locator-brittle` finding, dated at the latest approval of the Journeys it occurs in. A suggestion
51
+ * whose route cannot be a template, that has no approval time, or that fails the builder's privacy
52
+ * guard is LEFT OUT with a warning. Pure: no clock, no I/O.
53
+ */
54
+ export declare function locatorFindings(journeys: readonly CatalogJourney[], testIdAttributes: readonly string[]): BundleFindings;
55
+ export interface CollectBundleFindingsOptions {
56
+ /** The project root (where its `.jevitate/` is). */
57
+ readonly root: string;
58
+ /** The project data dir (`--dir`, else `<root>/.jevitate`); null outside a project. */
59
+ readonly dataDir: string | null;
60
+ /** Test seam: the run index. */
61
+ readonly index?: RunIndexDeps;
62
+ }
63
+ /** Reads the project's runs, UX reports and ledger, and returns the bundle's findings. */
64
+ export declare function collectBundleFindings(opts: CollectBundleFindingsOptions): Promise<BundleFindings>;