@domandigital/craft 0.19.0 → 0.19.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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @domandigital/craft
2
2
 
3
+ ## 0.19.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 5056c6a: STANDARD.md: a new section 10, "The phone is the base layout" (DOM-774): base styles are the phone and wider layouts use `min-width` only, 375px is the floor every surface is designed and measured at, touch targets are at least 44 x 44 CSS px, form fields at least 16px, reviews start from the phone capture, and performance is judged on the mobile Lighthouse profile. What is not a rule is now section 11 and says layout stays free at every width; the numbers are section 12. The older sections lose their em dashes to the house copy check, with the wording unchanged. Docs only.
8
+ - 00d79a0: `craft copy` reads `title` and `description` in Markdown front matter. A dash or a stock phrase in an agent description or a page title is reported on that line, and `copy-ok` on the line or the line above still suppresses it. Other front matter keys stay unread, and fenced code stays unread.
9
+
3
10
  ## 0.19.0
4
11
 
5
12
  ### Minor Changes
package/README.md CHANGED
@@ -67,7 +67,7 @@ module.exports = { presets: [tailwindV3Preset()] };
67
67
 
68
68
  ## The standard itself
69
69
 
70
- [STANDARD.md](./STANDARD.md) is the eleven-section house standard, every numeric
70
+ [STANDARD.md](./STANDARD.md) is the twelve-section house standard, every numeric
71
71
  rule cited, including a section on what is deliberately *not* a rule. Its
72
72
  canonical numbers are compared against the code on every test run, so the
73
73
  document cannot drift from what ships.
package/STANDARD.md CHANGED
@@ -1,17 +1,18 @@
1
1
  # The Doman Digital craft standard
2
2
 
3
- Eleven sections. Every numeric rule is cited, and section 10 says what is
3
+ Twelve sections. Every numeric rule is cited, and section 11 says what is
4
4
  deliberately *not* a rule.
5
5
 
6
6
  This document and the package are bound together by a test: the machine-readable
7
- block in section 11 is compared against `HOUSE_BUDGET`, `EASE` and
7
+ block in section 12 is compared against `HOUSE_BUDGET`, `EASE` and
8
8
  `DURATION_MS` on every run, so the standard cannot drift from what ships.
9
9
 
10
10
  ---
11
11
 
12
+ <!-- copy-ok: the standard names the practice each rule replaces -->
12
13
  ## 1. Colour is derived, not picked
13
14
 
14
- Anchors — colours a surface already ships — are sacred and come back byte-identical.
15
+ Anchors, the colours a surface already ships, are sacred and come back byte-identical.
15
16
  Everything else is generated in OKLCh from those anchors.
16
17
 
17
18
  - Ramps have **11 steps** (50–950).
@@ -19,7 +20,7 @@ Everything else is generated in OKLCh from those anchors.
19
20
  (CSS Color 4 §13.2). RGB clipping is rejected: it walks a saturated violet
20
21
  toward magenta.
21
22
  - Derived values standing in for a hand-picked one must be within
22
- **ΔE_OK ≤ 0.02** — the just-noticeable difference — or be declared an
23
+ **ΔE_OK ≤ 0.02** (the just-noticeable difference) or be declared an
23
24
  intentional change.
24
25
 
25
26
  *Source: Ottosson, "A perceptual color space for image processing" (2020); CSS Color 4 §13.2.*
@@ -40,9 +41,9 @@ Everything else is generated in OKLCh from those anchors.
40
41
  ## 3. Type is fluid, and always has a rem term
41
42
 
42
43
  - Steps **−2 to 5**, `clamp()` interpolated between a small and a large viewport.
43
- - The interpolation term is **`rem + vw`, never bare `vw`** — a bare-`vw` size
44
+ - The interpolation term is **`rem + vw`, never bare `vw`**. A bare-`vw` size
44
45
  ignores the browser text-size setting and fails WCAG 1.4.4 at 200% zoom.
45
- - Existing sizes are **pinned**, not regenerated, so adopting the scale moves
46
+ - Existing sizes are **pinned**, not regenerated, so adopting the scale moves <!-- copy-ok -->
46
47
  nothing.
47
48
 
48
49
  *Source: Utopia (utopia.fyi); WCAG 2.2 SC 1.4.4.*
@@ -58,7 +59,7 @@ Everything else is generated in OKLCh from those anchors.
58
59
  - Clipped display text gets a **descender mask** (`padding-bottom: .16em;
59
60
  margin-bottom: -.16em`), or it loses the tails of g, j, p, q, y.
60
61
 
61
- *Source: house habit — the −0.01em display tracking and the ch measure were arrived at independently in two client repos.*
62
+ *Source: house habit. The −0.01em display tracking and the ch measure were arrived at independently in two client repos.*
62
63
 
63
64
  ## 5. Space is fluid and proportional to type
64
65
 
@@ -66,7 +67,7 @@ Everything else is generated in OKLCh from those anchors.
66
67
  - Section rhythm has **three** sizes, not five. Five shipped with zero consumers,
67
68
  which is the signature of a scale invented ahead of a need.
68
69
 
69
- *Source: Utopia; measured — `--space-section-xs..xl` had no consumers in the monorepo.*
70
+ *Source: Utopia; measured: `--space-section-xs..xl` had no consumers in the monorepo.*
70
71
 
71
72
  ## 6. Density is a property of the surface
72
73
 
@@ -89,7 +90,7 @@ needs. Set once on a shell via `[data-density]`, inherited below.
89
90
  meaning it covers more ground per unit time arriving than it averaged.
90
91
  - **UI durations ≤ 300ms.** Drawers and one gated reveal may exceed it.
91
92
  - **Don't animate what fires 100×/day**, and never animate a keyboard-triggered
92
- interaction — the user is moving faster than the animation.
93
+ interaction: the user is moving faster than the animation.
93
94
  - **One signature moment per page**, gated, never the LCP element.
94
95
 
95
96
  *Source: Emil Kowalski, "Animations on the Web"; Core Web Vitals (LCP).*
@@ -101,12 +102,12 @@ needs. Set once on a shell via `[data-density]`, inherited below.
101
102
 
102
103
  **Never `animation: none` inside the block.** That drops the `forwards` fill along with the
103
104
  animation, so a forwards-filled entrance never applies its end state and the
104
- element keeps `opacity: 0` from its base rule — permanently invisible, for
105
+ element keeps `opacity: 0` from its base rule, permanently invisible, for
105
106
  exactly the users who asked for less motion. This shipped.
106
107
 
107
108
  Images: AVIF and WebP, in that order.
108
109
 
109
- *Source: WCAG 2.2 SC 2.3.3; measured — a live site was stranded at opacity 0 by this exact defect.*
110
+ *Source: WCAG 2.2 SC 2.3.3; measured: a live site was stranded at opacity 0 by this exact defect.*
110
111
 
111
112
  ## 9. Restraint is the budget
112
113
 
@@ -118,11 +119,11 @@ step: `code { font-size: 0.875em }` states one relationship and applies it
118
119
  wherever code appears, rather than adding a rung to the ladder. Counting it
119
120
  against the scale is the same category error as counting the framework's theme.
120
121
  It is still counted, because eight competing ratios is as unreadable as eight
121
- competing steps — split, not dropped. A value that stops being reported is a
122
+ competing steps: split, not dropped. A value that stops being reported is a
122
123
  value that grows.
123
124
 
124
125
  Differentiation guards pass anything that differs from its siblings, however
125
- ugly. What they cannot see is accumulation — eighteen font sizes, six shadows,
126
+ ugly. What they cannot see is accumulation: eighteen font sizes, six shadows,
126
127
  four competing accents, each added reasonably, together reading as noise.
127
128
 
128
129
  The budget counts the vocabulary a surface **chose**, and the whole difficulty
@@ -141,7 +142,7 @@ second reports a pass.
141
142
 
142
143
  The line is **used versus unused**, which is not a property of the layer:
143
144
 
144
- - References are **resolved**, not skipped — through the token chain, to the
145
+ - References are **resolved**, not skipped: through the token chain, to the <!-- copy-ok -->
145
146
  value that renders.
146
147
  - A definition is only ever reached from a declaration in a kept layer, so a
147
148
  framework default nothing uses still counts for nothing.
@@ -154,7 +155,34 @@ The line is **used versus unused**, which is not a property of the layer:
154
155
 
155
156
  *Source: measured against the estate. The budget is the observed ceiling of the surfaces that read as designed; the resolution rule is what it took to measure them at all.*
156
157
 
157
- ## 10. What is deliberately not a rule
158
+ ## 10. The phone is the base layout
159
+
160
+ Mobile first is a rule about **order and floor**, not about a layout. The phone
161
+ is designed, built and measured first, and every wider layout is derived from
162
+ it. A desktop layout squeezed onto a phone keeps the desktop's priorities and
163
+ drops whatever did not fit; a phone layout widened keeps what matters and adds.
164
+
165
+ - **The phone is the base.** Base styles are the phone layout. Wider layouts
166
+ are added with `min-width` queries only (Tailwind: unprefixed is the phone,
167
+ `sm:` `md:` `lg:` add). A `max-width` query, a `width <` range or a Tailwind
168
+ `max-*:` variant needs a recorded exception with its reason.
169
+ - **375px is the floor.** Every surface is designed and measured at **375 CSS
170
+ px** first, the narrowest iPhone width in common use (SE, mini, X to 11 Pro).
171
+ Nothing scrolls sideways at 375. 390 is still measured: it is the width the
172
+ design is accepted at.
173
+ - **Touch targets at least 44 × 44 CSS px.** A link inside a sentence is exempt,
174
+ as in WCAG's own inline exception. 24px (SC 2.5.8, AA) is what an audit asks
175
+ for; 44 is the house bar.
176
+ - **Form inputs at least 16px.** Safari on iOS zooms the page when a field set
177
+ smaller gets focus, and the visitor has to pinch back out. Fix the size, never
178
+ the viewport: `maximum-scale=1` takes zoom away from people who need it.
179
+ - **Reviews look at the phone capture first**, then the desktop one.
180
+ - **Performance is judged on the mobile Lighthouse profile.** A desktop score
181
+ is not evidence: the phone is the slower device and the one Google indexes.
182
+
183
+ *Source: WCAG 2.2 SC 2.5.5 (Target Size, Enhanced), SC 2.5.8 and SC 1.4.4; Apple Human Interface Guidelines, "Accessibility" (44 × 44 pt hit targets); WebKit's focus zoom on fields under 16px; Lighthouse's default mobile emulation; Google Search Central, "Mobile-first indexing"; Luke Wroblewski, "Mobile First" (2011).*
184
+
185
+ ## 11. What is deliberately not a rule
158
186
 
159
187
  The package emits **plain CSS custom properties** precisely so these stay free:
160
188
 
@@ -162,9 +190,11 @@ The package emits **plain CSS custom properties** precisely so these stay free:
162
190
  two; the third needs nothing.
163
191
  - **The motion library.** `EASE_TUPLE` carries the same control points as `EASE`,
164
192
  so Framer Motion, GSAP and CSS agree without the package choosing one.
165
- - **Where tokens live.** A `:root` block, a generated file, a Tailwind theme —
193
+ - **Where tokens live.** A `:root` block, a generated file, a Tailwind theme:
166
194
  the package does not care.
167
- - **Layout, grid and component structure.** Not a rule. Layout *defaults*
195
+ - **Layout, grid and component structure.** Not a rule, at any width. Section
196
+ 10 fixes the order the widths are designed in and the floor they are
197
+ measured at; what the phone layout looks like stays free. Layout *defaults*
168
198
  (hero straight into a trust strip, three icon cards, a reveal on every
169
199
  section) are measured as character in [CHARACTER.md](./CHARACTER.md), as
170
200
  warnings with a declared-exception path, never as rules here.
@@ -172,7 +202,7 @@ The package emits **plain CSS custom properties** precisely so these stay free:
172
202
 
173
203
  A rule here has to be one that is wrong to break. Everything else is a default.
174
204
 
175
- ## 11. The numbers
205
+ ## 12. The numbers
176
206
 
177
207
  <!-- craft:canonical -->
178
208
  ```json
@@ -9,10 +9,10 @@ import {
9
9
  snapshotPage,
10
10
  snapshotUrl,
11
11
  snapshotUrls
12
- } from "./chunk-W7PMRSDG.js";
12
+ } from "./chunk-VDUIIWG7.js";
13
13
  import "./chunk-JYNXGCYZ.js";
14
- import "./chunk-IHT6CJOM.js";
15
- import "./chunk-4QWEAL4G.js";
14
+ import "./chunk-WK2WMWTH.js";
15
+ import "./chunk-CZ7KT452.js";
16
16
  import "./chunk-QYBAVU3P.js";
17
17
  export {
18
18
  PROVENANCE_BUDGET_MS,
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  snapshotUrl,
3
3
  snapshotUrls
4
- } from "./chunk-W7PMRSDG.js";
4
+ } from "./chunk-VDUIIWG7.js";
5
5
  import {
6
6
  describeTypicality,
7
7
  loadNull
8
- } from "./chunk-NCBCZFDY.js";
8
+ } from "./chunk-ORFILP5L.js";
9
9
  import {
10
10
  SOURCE_FILE,
11
11
  finish,
@@ -14,7 +14,7 @@ import {
14
14
  parseFlags,
15
15
  prepareReport,
16
16
  readPaths
17
- } from "./chunk-GNVZGG3E.js";
17
+ } from "./chunk-DUUDGR56.js";
18
18
  import {
19
19
  toJson
20
20
  } from "./chunk-QIEDBL4J.js";
@@ -28,7 +28,7 @@ import {
28
28
  rhythmOf,
29
29
  scanSource,
30
30
  typicality
31
- } from "./chunk-IHT6CJOM.js";
31
+ } from "./chunk-WK2WMWTH.js";
32
32
 
33
33
  // src/audit/cli.ts
34
34
  import { existsSync, readFileSync, writeFileSync } from "fs";
@@ -10,10 +10,10 @@ import {
10
10
  levenshtein,
11
11
  normaliseFamily,
12
12
  parseColour
13
- } from "./chunk-IHT6CJOM.js";
13
+ } from "./chunk-WK2WMWTH.js";
14
14
  import {
15
15
  TRADE_NOUNS
16
- } from "./chunk-4QWEAL4G.js";
16
+ } from "./chunk-CZ7KT452.js";
17
17
 
18
18
  // src/direction/types.ts
19
19
  var DIRECTION_VERSION = 2;
@@ -263,8 +263,100 @@ function markupParts(file) {
263
263
  function textNodeIsProse(body) {
264
264
  return /[a-zA-Z]{2,}/.test(body) && /\s/.test(body.trim()) || /[a-zA-Z]{4,}[.!?]/.test(body);
265
265
  }
266
+ var FRONT_MATTER_PROSE = /* @__PURE__ */ new Set(["title", "description"]);
267
+ var KEY_LINE = /^(\s*)(?:-\s+)?([A-Za-z][\w-]*)[ \t]*:[ \t]*/;
268
+ var BLOCK_SCALAR = /^(?:[|>][+-]?\d*|[|>]\d+[+-]?)$/;
269
+ function readFrontKey(line) {
270
+ const m = KEY_LINE.exec(line);
271
+ if (!m) return null;
272
+ return { indent: m[1].length, name: m[2], valueAt: m[0].length, value: line.slice(m[0].length) };
273
+ }
274
+ function indentOf(line) {
275
+ let i = 0;
276
+ while (i < line.length && (line[i] === " " || line[i] === " ")) i += 1;
277
+ return i;
278
+ }
279
+ function commentAt(value) {
280
+ if (value.startsWith("#")) return 0;
281
+ const found = /[ \t]+#/.exec(value);
282
+ return found ? found.index : -1;
283
+ }
284
+ function keepSpan(line, from, to) {
285
+ const start = Math.max(0, Math.min(from, line.length));
286
+ const end = Math.max(start, Math.min(to, line.length));
287
+ return " ".repeat(start) + line.slice(start, end) + " ".repeat(line.length - end);
288
+ }
289
+ function quoteEnd(line, from, quote) {
290
+ for (let i = from; i < line.length; i += 1) {
291
+ if (quote === '"' && line[i] === "\\") {
292
+ i += 1;
293
+ continue;
294
+ }
295
+ if (quote === "'" && line[i] === "'" && line[i + 1] === "'") {
296
+ i += 1;
297
+ continue;
298
+ }
299
+ if (line[i] === quote) return i;
300
+ }
301
+ return -1;
302
+ }
303
+ function maskFrontMatter(block) {
304
+ const lines = block.split("\n");
305
+ const out = lines.map((line) => blank(line));
306
+ for (let i = 1; i < lines.length; ) {
307
+ const line = lines[i];
308
+ if (line === "---" || line === "...") break;
309
+ const key = readFrontKey(line);
310
+ if (!key || !FRONT_MATTER_PROSE.has(key.name.toLowerCase())) {
311
+ i += 1;
312
+ continue;
313
+ }
314
+ const quote = key.value.startsWith('"') ? '"' : key.value.startsWith("'") ? "'" : "";
315
+ if (quote) {
316
+ let cursor = key.valueAt + 1;
317
+ while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
318
+ const current = lines[i];
319
+ const end = quoteEnd(current, cursor, quote);
320
+ out[i] = keepSpan(current, cursor, end === -1 ? current.length : end);
321
+ i += 1;
322
+ cursor = 0;
323
+ if (end !== -1) break;
324
+ }
325
+ continue;
326
+ }
327
+ const hash = commentAt(key.value);
328
+ const body = (hash === -1 ? key.value : key.value.slice(0, hash)).trim();
329
+ if (BLOCK_SCALAR.test(body)) {
330
+ i += 1;
331
+ while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
332
+ const current = lines[i];
333
+ if (current.trim() !== "" && indentOf(current) <= key.indent) break;
334
+ if (current.trim()) out[i] = current;
335
+ i += 1;
336
+ }
337
+ continue;
338
+ }
339
+ if (body === "" || body === "~" || /^null$/i.test(body) || body.startsWith("[") || body.startsWith("{")) {
340
+ i += 1;
341
+ continue;
342
+ }
343
+ out[i] = keepSpan(line, key.valueAt, hash === -1 ? line.length : key.valueAt + hash);
344
+ i += 1;
345
+ while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
346
+ const current = lines[i];
347
+ if (current.trim() === "" || indentOf(current) <= key.indent) break;
348
+ if (!/^\s*#/.test(current)) {
349
+ const cut = commentAt(current);
350
+ out[i] = cut === -1 ? current : keepSpan(current, 0, cut);
351
+ }
352
+ i += 1;
353
+ }
354
+ }
355
+ const masked = out.join("\n");
356
+ return masked.length === block.length ? masked : blank(block);
357
+ }
266
358
  function proseBlocks(file) {
267
- const masked = file.text.replace(/^(```|~~~)[\s\S]*?^\1/gm, blank).replace(/`[^`\n]*`/g, (m) => " ".repeat(m.length)).replace(/^---\n[\s\S]*?\n---\n/, blank).replace(/<!--[\s\S]*?-->/g, blank);
359
+ const masked = file.text.replace(/^(```|~~~)[\s\S]*?^\1/gm, blank).replace(/`[^`\n]*`/g, (m) => " ".repeat(m.length)).replace(/^---\n[\s\S]*?\n---\n/, (block) => maskFrontMatter(block)).replace(/<!--[\s\S]*?-->/g, blank);
268
360
  return [{ path: file.path, text: masked, offset: 0 }];
269
361
  }
270
362
  function isData(path) {
@@ -10,7 +10,7 @@ import {
10
10
  holdHouseBlocks,
11
11
  houseRule,
12
12
  scanSource
13
- } from "./chunk-IHT6CJOM.js";
13
+ } from "./chunk-WK2WMWTH.js";
14
14
  import {
15
15
  compareCompetitor,
16
16
  compareFacts,
@@ -21,7 +21,7 @@ import {
21
21
  pageCopy,
22
22
  protectedFacts,
23
23
  visibleText
24
- } from "./chunk-4QWEAL4G.js";
24
+ } from "./chunk-CZ7KT452.js";
25
25
 
26
26
  // src/character/config.ts
27
27
  var DEFAULT_IGNORE = [".claude", ".agents", ".cursor"];
@@ -601,7 +601,7 @@ async function pageSnapshot(target, cwd) {
601
601
  return readSnapshot(JSON.parse(readFileSync(local, "utf8")), target);
602
602
  }
603
603
  if (!/^https?:\/\//.test(target)) throw new Error(`${target} is neither a URL nor a snapshot file`);
604
- const { snapshotUrl } = await import("./audit-X7LGATAQ.js");
604
+ const { snapshotUrl } = await import("./audit-43PC4LMS.js");
605
605
  return snapshotUrl(target);
606
606
  }
607
607
  async function briefFor(flags, cwd) {
@@ -612,7 +612,7 @@ async function briefFor(flags, cwd) {
612
612
  if (typeof brief === "string" && brief.trim()) return brief;
613
613
  } else if (flags.direction) throw new Error(`no such file: ${flags.direction}`);
614
614
  if (flags.null) {
615
- const { loadNull } = await import("./cli-3WWHRJRG.js");
615
+ const { loadNull } = await import("./cli-L3VGKWZH.js");
616
616
  return loadNull(flags.null, cwd).brief;
617
617
  }
618
618
  return void 0;
@@ -638,31 +638,31 @@ async function compareWithCompetitor(flags, io) {
638
638
  function run(argv, io) {
639
639
  const [command, ...rest] = argv;
640
640
  if (command === "direction") {
641
- return import("./cli-DKI37OXK.js").then((m) => m.runDirection(rest, io));
641
+ return import("./cli-TH76ATN3.js").then((m) => m.runDirection(rest, io));
642
642
  }
643
643
  if (command === "report" || command === "retrofit") {
644
- return import("./cli-KXVJJDN5.js").then((m) => m.runReport(command, rest, io));
644
+ return import("./cli-AACBHRUG.js").then((m) => m.runReport(command, rest, io));
645
645
  }
646
646
  if (command === "register") {
647
- return import("./cli-JB4X5LAG.js").then((m) => m.runRegister(rest, io));
647
+ return import("./cli-VPARW6FY.js").then((m) => m.runRegister(rest, io));
648
648
  }
649
649
  if (command === "estate") {
650
- return import("./cli-U7WEVPZL.js").then((m) => m.runEstate(rest, io));
650
+ return import("./cli-3P44X6E3.js").then((m) => m.runEstate(rest, io));
651
651
  }
652
652
  if (command === "null") {
653
- return import("./cli-3WWHRJRG.js").then((m) => m.runNull(rest, io));
653
+ return import("./cli-L3VGKWZH.js").then((m) => m.runNull(rest, io));
654
654
  }
655
655
  if (command === "calibrate") {
656
- return import("./cli-YD3VN52R.js").then((m) => m.runCalibrate(rest, io));
656
+ return import("./cli-7OUA6ZSE.js").then((m) => m.runCalibrate(rest, io));
657
657
  }
658
658
  if (command === "tells" && rest[0] === "harvest") {
659
- return import("./cli-3WWHRJRG.js").then((m) => m.runHarvest(rest, io)).catch((error) => {
659
+ return import("./cli-L3VGKWZH.js").then((m) => m.runHarvest(rest, io)).catch((error) => {
660
660
  io.err(`craft: ${error.message}`);
661
661
  return 2;
662
662
  });
663
663
  }
664
664
  if (command === "snapshot" || command === "audit") {
665
- return import("./cli-ZGB6MUN2.js").then((m) => m.runAudit(command, rest, io));
665
+ return import("./cli-4D7Q5BCE.js").then((m) => m.runAudit(command, rest, io));
666
666
  }
667
667
  if (!command || command === "help" || command === "--help" || command === "-h") {
668
668
  io.out(HELP);
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-OQXTQQAU.js";
4
4
  import {
5
5
  parseFlags
6
- } from "./chunk-GNVZGG3E.js";
6
+ } from "./chunk-DUUDGR56.js";
7
7
  import {
8
8
  toJson
9
9
  } from "./chunk-QIEDBL4J.js";
@@ -22,10 +22,10 @@ import {
22
22
  hueSwatch,
23
23
  nullPrompt,
24
24
  scanSource
25
- } from "./chunk-IHT6CJOM.js";
25
+ } from "./chunk-WK2WMWTH.js";
26
26
  import {
27
27
  extractStrings
28
- } from "./chunk-4QWEAL4G.js";
28
+ } from "./chunk-CZ7KT452.js";
29
29
 
30
30
  // src/null/cli.ts
31
31
  import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from "fs";
@@ -120,7 +120,7 @@ async function build(flags, io) {
120
120
  const toShoot = ids.filter((id) => existsSync(join(pages, `${id}.html`)) && !existsSync(join(shots, `${id}.json`)));
121
121
  if (toShoot.length) {
122
122
  io.out(`craft null: snapshotting ${toShoot.length} page${toShoot.length === 1 ? "" : "s"}`);
123
- const { snapshotUrls } = await import("./audit-X7LGATAQ.js");
123
+ const { snapshotUrls } = await import("./audit-43PC4LMS.js");
124
124
  const results = await snapshotUrls(toShoot.map((id) => pathToFileURL(join(pages, `${id}.html`)).href));
125
125
  results.forEach((r, i) => {
126
126
  const id = toShoot[i];
@@ -241,7 +241,7 @@ async function importPages(flags, io) {
241
241
  const toShoot = pages.filter((p) => !existsSync(join(shots, `${p.id}.json`)));
242
242
  if (toShoot.length) {
243
243
  io.out(`craft null: snapshotting ${toShoot.length} page${toShoot.length === 1 ? "" : "s"} from ${flags.builder}`);
244
- const { snapshotUrls } = await import("./audit-X7LGATAQ.js");
244
+ const { snapshotUrls } = await import("./audit-43PC4LMS.js");
245
245
  const servers = /* @__PURE__ */ new Map();
246
246
  try {
247
247
  for (const p of toShoot) if (!servers.has(p.root)) servers.set(p.root, await serveDir(p.root));
@@ -4,13 +4,13 @@ import {
4
4
  formatDirectionMatches,
5
5
  summariseDirection,
6
6
  validateDirection
7
- } from "./chunk-RNHV2SXC.js";
7
+ } from "./chunk-4LJFZH2I.js";
8
8
  import {
9
9
  loadNull
10
- } from "./chunk-NCBCZFDY.js";
10
+ } from "./chunk-ORFILP5L.js";
11
11
  import {
12
12
  parseFlags
13
- } from "./chunk-GNVZGG3E.js";
13
+ } from "./chunk-DUUDGR56.js";
14
14
  import {
15
15
  toJson
16
16
  } from "./chunk-QIEDBL4J.js";
@@ -30,7 +30,7 @@ import {
30
30
  rhythmOf,
31
31
  shapeName,
32
32
  temperatureName
33
- } from "./chunk-IHT6CJOM.js";
33
+ } from "./chunk-WK2WMWTH.js";
34
34
 
35
35
  // src/estate/cli.ts
36
36
  import { existsSync, readFileSync, writeFileSync } from "fs";
@@ -133,7 +133,7 @@ async function snapshotOf(target, cwd) {
133
133
  return snap;
134
134
  }
135
135
  if (!/^https?:\/\//.test(target)) throw new Error(`${target} is neither a URL, a snapshot file, nor a site in the register`);
136
- const { snapshotUrl } = await import("./audit-X7LGATAQ.js");
136
+ const { snapshotUrl } = await import("./audit-43PC4LMS.js");
137
137
  return snapshotUrl(target);
138
138
  }
139
139
  var line = (distance, sibling, shared) => `${distance.toFixed(2)}${sibling ? " SIBLING" : ""}${shared.length ? ` shares ${shared.join(", ")}` : ""}`;
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  auditSnapshot,
6
6
  fingerprint
7
- } from "./chunk-IHT6CJOM.js";
7
+ } from "./chunk-WK2WMWTH.js";
8
8
  import {
9
9
  SNAPSHOT_VERSION
10
10
  } from "./chunk-QYBAVU3P.js";
@@ -9,7 +9,7 @@ import {
9
9
  parseFile,
10
10
  sentencesOf,
11
11
  specificity
12
- } from "./chunk-4QWEAL4G.js";
12
+ } from "./chunk-CZ7KT452.js";
13
13
  import {
14
14
  SNAPSHOT_VERSION
15
15
  } from "./chunk-QYBAVU3P.js";
@@ -4,15 +4,15 @@ import {
4
4
  formatPairs,
5
5
  loadEstate,
6
6
  runEstate
7
- } from "./chunk-LWKMGJSW.js";
8
- import "./chunk-RNHV2SXC.js";
9
- import "./chunk-NCBCZFDY.js";
7
+ } from "./chunk-P37LLKL4.js";
8
+ import "./chunk-4LJFZH2I.js";
9
+ import "./chunk-ORFILP5L.js";
10
10
  import "./chunk-OQXTQQAU.js";
11
- import "./chunk-GNVZGG3E.js";
11
+ import "./chunk-DUUDGR56.js";
12
12
  import "./chunk-QIEDBL4J.js";
13
13
  import "./chunk-WUACK2HX.js";
14
- import "./chunk-IHT6CJOM.js";
15
- import "./chunk-4QWEAL4G.js";
14
+ import "./chunk-WK2WMWTH.js";
15
+ import "./chunk-CZ7KT452.js";
16
16
  import "./chunk-QYBAVU3P.js";
17
17
  export {
18
18
  formatComponentPairs,
@@ -4,16 +4,16 @@ import {
4
4
  merge,
5
5
  resolvePages,
6
6
  runAudit
7
- } from "./chunk-J35UYAVV.js";
8
- import "./chunk-W7PMRSDG.js";
7
+ } from "./chunk-37ARRJAD.js";
8
+ import "./chunk-VDUIIWG7.js";
9
9
  import "./chunk-JYNXGCYZ.js";
10
- import "./chunk-NCBCZFDY.js";
10
+ import "./chunk-ORFILP5L.js";
11
11
  import "./chunk-OQXTQQAU.js";
12
- import "./chunk-GNVZGG3E.js";
12
+ import "./chunk-DUUDGR56.js";
13
13
  import "./chunk-QIEDBL4J.js";
14
14
  import "./chunk-WUACK2HX.js";
15
- import "./chunk-IHT6CJOM.js";
16
- import "./chunk-4QWEAL4G.js";
15
+ import "./chunk-WK2WMWTH.js";
16
+ import "./chunk-CZ7KT452.js";
17
17
  import "./chunk-QYBAVU3P.js";
18
18
  export {
19
19
  describeComponents,
@@ -4,11 +4,11 @@ import {
4
4
  import {
5
5
  expandNullTargets,
6
6
  loadNull
7
- } from "./chunk-NCBCZFDY.js";
7
+ } from "./chunk-ORFILP5L.js";
8
8
  import "./chunk-OQXTQQAU.js";
9
9
  import {
10
10
  parseFlags
11
- } from "./chunk-GNVZGG3E.js";
11
+ } from "./chunk-DUUDGR56.js";
12
12
  import {
13
13
  toJson
14
14
  } from "./chunk-QIEDBL4J.js";
@@ -21,8 +21,8 @@ import {
21
21
  fingerprint,
22
22
  scanSource,
23
23
  typicality
24
- } from "./chunk-IHT6CJOM.js";
25
- import "./chunk-4QWEAL4G.js";
24
+ } from "./chunk-WK2WMWTH.js";
25
+ import "./chunk-CZ7KT452.js";
26
26
  import {
27
27
  SNAPSHOT_VERSION
28
28
  } from "./chunk-QYBAVU3P.js";
@@ -188,7 +188,7 @@ async function runCalibrate(args, io) {
188
188
  if (toTake.length) {
189
189
  io.err(`craft calibrate: taking ${toTake.length} snapshot${toTake.length === 1 ? "" : "s"}`);
190
190
  try {
191
- const { snapshotUrls } = await import("./audit-X7LGATAQ.js");
191
+ const { snapshotUrls } = await import("./audit-43PC4LMS.js");
192
192
  const results = await snapshotUrls(toTake.map((t) => t.url));
193
193
  results.forEach((r, i) => {
194
194
  const { entry, keep } = toTake[i];
@@ -3,21 +3,21 @@ import {
3
3
  } from "./chunk-OKVHWXYV.js";
4
4
  import {
5
5
  merge
6
- } from "./chunk-J35UYAVV.js";
7
- import "./chunk-W7PMRSDG.js";
6
+ } from "./chunk-37ARRJAD.js";
7
+ import "./chunk-VDUIIWG7.js";
8
8
  import "./chunk-JYNXGCYZ.js";
9
9
  import {
10
10
  SIBLING_AT,
11
11
  compareToEstate,
12
12
  loadEstate
13
- } from "./chunk-LWKMGJSW.js";
13
+ } from "./chunk-P37LLKL4.js";
14
14
  import {
15
15
  PAGE_TYPES,
16
16
  validateDirection
17
- } from "./chunk-RNHV2SXC.js";
17
+ } from "./chunk-4LJFZH2I.js";
18
18
  import {
19
19
  loadNull
20
- } from "./chunk-NCBCZFDY.js";
20
+ } from "./chunk-ORFILP5L.js";
21
21
  import "./chunk-OQXTQQAU.js";
22
22
  import {
23
23
  COPY_FILE,
@@ -28,7 +28,7 @@ import {
28
28
  loadExceptions,
29
29
  parseFlags,
30
30
  readPaths
31
- } from "./chunk-GNVZGG3E.js";
31
+ } from "./chunk-DUUDGR56.js";
32
32
  import {
33
33
  toJson
34
34
  } from "./chunk-QIEDBL4J.js";
@@ -42,8 +42,8 @@ import {
42
42
  fingerprint,
43
43
  scanSource,
44
44
  typicality
45
- } from "./chunk-IHT6CJOM.js";
46
- import "./chunk-4QWEAL4G.js";
45
+ } from "./chunk-WK2WMWTH.js";
46
+ import "./chunk-CZ7KT452.js";
47
47
  import "./chunk-QYBAVU3P.js";
48
48
 
49
49
  // src/report/cli.ts
@@ -126,7 +126,7 @@ async function runReport(command, args, io) {
126
126
  if (/\.json$/i.test(target2) && existsSync(local)) {
127
127
  snap = readSnapshot(JSON.parse(readFileSync(local, "utf8")), target2);
128
128
  } else {
129
- const { snapshotUrl } = await import("./audit-X7LGATAQ.js");
129
+ const { snapshotUrl } = await import("./audit-43PC4LMS.js");
130
130
  snap = await snapshotUrl(target2);
131
131
  }
132
132
  const fp = fingerprint(snap);
@@ -9,13 +9,13 @@ import {
9
9
  runHarvest,
10
10
  runNull,
11
11
  serveDir
12
- } from "./chunk-NCBCZFDY.js";
12
+ } from "./chunk-ORFILP5L.js";
13
13
  import "./chunk-OQXTQQAU.js";
14
- import "./chunk-GNVZGG3E.js";
14
+ import "./chunk-DUUDGR56.js";
15
15
  import "./chunk-QIEDBL4J.js";
16
16
  import "./chunk-WUACK2HX.js";
17
- import "./chunk-IHT6CJOM.js";
18
- import "./chunk-4QWEAL4G.js";
17
+ import "./chunk-WK2WMWTH.js";
18
+ import "./chunk-CZ7KT452.js";
19
19
  import "./chunk-QYBAVU3P.js";
20
20
  export {
21
21
  describeTypicality,
@@ -7,10 +7,10 @@ import {
7
7
  PROPOSED,
8
8
  researchPrompt,
9
9
  validateDirection
10
- } from "./chunk-RNHV2SXC.js";
10
+ } from "./chunk-4LJFZH2I.js";
11
11
  import {
12
12
  parseFlags
13
- } from "./chunk-GNVZGG3E.js";
13
+ } from "./chunk-DUUDGR56.js";
14
14
  import {
15
15
  toJson
16
16
  } from "./chunk-QIEDBL4J.js";
@@ -26,8 +26,8 @@ import {
26
26
  isCream,
27
27
  oklchToRgb,
28
28
  parseColour
29
- } from "./chunk-IHT6CJOM.js";
30
- import "./chunk-4QWEAL4G.js";
29
+ } from "./chunk-WK2WMWTH.js";
30
+ import "./chunk-CZ7KT452.js";
31
31
  import "./chunk-QYBAVU3P.js";
32
32
 
33
33
  // src/direction/cli.ts
@@ -208,7 +208,7 @@ var readJson = (path) => JSON.parse(readFileSync(path, "utf8"));
208
208
  async function snapshotFrom(target, cwd) {
209
209
  if (!target) return void 0;
210
210
  if (/^https?:\/\//.test(target)) {
211
- const { snapshotUrl } = await import("./audit-X7LGATAQ.js");
211
+ const { snapshotUrl } = await import("./audit-43PC4LMS.js");
212
212
  return snapshotUrl(target);
213
213
  }
214
214
  return readSnapshot(readJson(resolve(cwd, target)), target);
@@ -9,7 +9,7 @@ import {
9
9
  STOCK_PHRASES,
10
10
  countWords,
11
11
  specificity
12
- } from "./chunk-4QWEAL4G.js";
12
+ } from "./chunk-CZ7KT452.js";
13
13
 
14
14
  // src/register/cli.ts
15
15
  import { existsSync, readFileSync } from "fs";
package/dist/cli.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  run
4
- } from "./chunk-GNVZGG3E.js";
4
+ } from "./chunk-DUUDGR56.js";
5
5
  import "./chunk-QIEDBL4J.js";
6
- import "./chunk-IHT6CJOM.js";
7
- import "./chunk-4QWEAL4G.js";
6
+ import "./chunk-WK2WMWTH.js";
7
+ import "./chunk-CZ7KT452.js";
8
8
  import "./chunk-QYBAVU3P.js";
9
9
 
10
10
  // src/cli.ts
package/dist/index.cjs CHANGED
@@ -4344,8 +4344,100 @@ function markupParts(file) {
4344
4344
  function textNodeIsProse(body) {
4345
4345
  return /[a-zA-Z]{2,}/.test(body) && /\s/.test(body.trim()) || /[a-zA-Z]{4,}[.!?]/.test(body);
4346
4346
  }
4347
+ var FRONT_MATTER_PROSE = /* @__PURE__ */ new Set(["title", "description"]);
4348
+ var KEY_LINE = /^(\s*)(?:-\s+)?([A-Za-z][\w-]*)[ \t]*:[ \t]*/;
4349
+ var BLOCK_SCALAR = /^(?:[|>][+-]?\d*|[|>]\d+[+-]?)$/;
4350
+ function readFrontKey(line) {
4351
+ const m = KEY_LINE.exec(line);
4352
+ if (!m) return null;
4353
+ return { indent: m[1].length, name: m[2], valueAt: m[0].length, value: line.slice(m[0].length) };
4354
+ }
4355
+ function indentOf(line) {
4356
+ let i = 0;
4357
+ while (i < line.length && (line[i] === " " || line[i] === " ")) i += 1;
4358
+ return i;
4359
+ }
4360
+ function commentAt(value) {
4361
+ if (value.startsWith("#")) return 0;
4362
+ const found = /[ \t]+#/.exec(value);
4363
+ return found ? found.index : -1;
4364
+ }
4365
+ function keepSpan(line, from, to) {
4366
+ const start = Math.max(0, Math.min(from, line.length));
4367
+ const end = Math.max(start, Math.min(to, line.length));
4368
+ return " ".repeat(start) + line.slice(start, end) + " ".repeat(line.length - end);
4369
+ }
4370
+ function quoteEnd(line, from, quote) {
4371
+ for (let i = from; i < line.length; i += 1) {
4372
+ if (quote === '"' && line[i] === "\\") {
4373
+ i += 1;
4374
+ continue;
4375
+ }
4376
+ if (quote === "'" && line[i] === "'" && line[i + 1] === "'") {
4377
+ i += 1;
4378
+ continue;
4379
+ }
4380
+ if (line[i] === quote) return i;
4381
+ }
4382
+ return -1;
4383
+ }
4384
+ function maskFrontMatter(block) {
4385
+ const lines = block.split("\n");
4386
+ const out = lines.map((line) => blank(line));
4387
+ for (let i = 1; i < lines.length; ) {
4388
+ const line = lines[i];
4389
+ if (line === "---" || line === "...") break;
4390
+ const key = readFrontKey(line);
4391
+ if (!key || !FRONT_MATTER_PROSE.has(key.name.toLowerCase())) {
4392
+ i += 1;
4393
+ continue;
4394
+ }
4395
+ const quote = key.value.startsWith('"') ? '"' : key.value.startsWith("'") ? "'" : "";
4396
+ if (quote) {
4397
+ let cursor = key.valueAt + 1;
4398
+ while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
4399
+ const current = lines[i];
4400
+ const end = quoteEnd(current, cursor, quote);
4401
+ out[i] = keepSpan(current, cursor, end === -1 ? current.length : end);
4402
+ i += 1;
4403
+ cursor = 0;
4404
+ if (end !== -1) break;
4405
+ }
4406
+ continue;
4407
+ }
4408
+ const hash = commentAt(key.value);
4409
+ const body = (hash === -1 ? key.value : key.value.slice(0, hash)).trim();
4410
+ if (BLOCK_SCALAR.test(body)) {
4411
+ i += 1;
4412
+ while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
4413
+ const current = lines[i];
4414
+ if (current.trim() !== "" && indentOf(current) <= key.indent) break;
4415
+ if (current.trim()) out[i] = current;
4416
+ i += 1;
4417
+ }
4418
+ continue;
4419
+ }
4420
+ if (body === "" || body === "~" || /^null$/i.test(body) || body.startsWith("[") || body.startsWith("{")) {
4421
+ i += 1;
4422
+ continue;
4423
+ }
4424
+ out[i] = keepSpan(line, key.valueAt, hash === -1 ? line.length : key.valueAt + hash);
4425
+ i += 1;
4426
+ while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
4427
+ const current = lines[i];
4428
+ if (current.trim() === "" || indentOf(current) <= key.indent) break;
4429
+ if (!/^\s*#/.test(current)) {
4430
+ const cut = commentAt(current);
4431
+ out[i] = cut === -1 ? current : keepSpan(current, 0, cut);
4432
+ }
4433
+ i += 1;
4434
+ }
4435
+ }
4436
+ const masked = out.join("\n");
4437
+ return masked.length === block.length ? masked : blank(block);
4438
+ }
4347
4439
  function proseBlocks(file) {
4348
- const masked = file.text.replace(/^(```|~~~)[\s\S]*?^\1/gm, blank).replace(/`[^`\n]*`/g, (m) => " ".repeat(m.length)).replace(/^---\n[\s\S]*?\n---\n/, blank).replace(/<!--[\s\S]*?-->/g, blank);
4440
+ const masked = file.text.replace(/^(```|~~~)[\s\S]*?^\1/gm, blank).replace(/`[^`\n]*`/g, (m) => " ".repeat(m.length)).replace(/^---\n[\s\S]*?\n---\n/, (block) => maskFrontMatter(block)).replace(/<!--[\s\S]*?-->/g, blank);
4349
4441
  return [{ path: file.path, text: masked, offset: 0 }];
4350
4442
  }
4351
4443
  function isData(path) {
package/dist/index.js CHANGED
@@ -4042,8 +4042,100 @@ function markupParts(file) {
4042
4042
  function textNodeIsProse(body) {
4043
4043
  return /[a-zA-Z]{2,}/.test(body) && /\s/.test(body.trim()) || /[a-zA-Z]{4,}[.!?]/.test(body);
4044
4044
  }
4045
+ var FRONT_MATTER_PROSE = /* @__PURE__ */ new Set(["title", "description"]);
4046
+ var KEY_LINE = /^(\s*)(?:-\s+)?([A-Za-z][\w-]*)[ \t]*:[ \t]*/;
4047
+ var BLOCK_SCALAR = /^(?:[|>][+-]?\d*|[|>]\d+[+-]?)$/;
4048
+ function readFrontKey(line) {
4049
+ const m = KEY_LINE.exec(line);
4050
+ if (!m) return null;
4051
+ return { indent: m[1].length, name: m[2], valueAt: m[0].length, value: line.slice(m[0].length) };
4052
+ }
4053
+ function indentOf(line) {
4054
+ let i = 0;
4055
+ while (i < line.length && (line[i] === " " || line[i] === " ")) i += 1;
4056
+ return i;
4057
+ }
4058
+ function commentAt(value) {
4059
+ if (value.startsWith("#")) return 0;
4060
+ const found = /[ \t]+#/.exec(value);
4061
+ return found ? found.index : -1;
4062
+ }
4063
+ function keepSpan(line, from, to) {
4064
+ const start = Math.max(0, Math.min(from, line.length));
4065
+ const end = Math.max(start, Math.min(to, line.length));
4066
+ return " ".repeat(start) + line.slice(start, end) + " ".repeat(line.length - end);
4067
+ }
4068
+ function quoteEnd(line, from, quote) {
4069
+ for (let i = from; i < line.length; i += 1) {
4070
+ if (quote === '"' && line[i] === "\\") {
4071
+ i += 1;
4072
+ continue;
4073
+ }
4074
+ if (quote === "'" && line[i] === "'" && line[i + 1] === "'") {
4075
+ i += 1;
4076
+ continue;
4077
+ }
4078
+ if (line[i] === quote) return i;
4079
+ }
4080
+ return -1;
4081
+ }
4082
+ function maskFrontMatter(block) {
4083
+ const lines = block.split("\n");
4084
+ const out = lines.map((line) => blank(line));
4085
+ for (let i = 1; i < lines.length; ) {
4086
+ const line = lines[i];
4087
+ if (line === "---" || line === "...") break;
4088
+ const key = readFrontKey(line);
4089
+ if (!key || !FRONT_MATTER_PROSE.has(key.name.toLowerCase())) {
4090
+ i += 1;
4091
+ continue;
4092
+ }
4093
+ const quote = key.value.startsWith('"') ? '"' : key.value.startsWith("'") ? "'" : "";
4094
+ if (quote) {
4095
+ let cursor = key.valueAt + 1;
4096
+ while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
4097
+ const current = lines[i];
4098
+ const end = quoteEnd(current, cursor, quote);
4099
+ out[i] = keepSpan(current, cursor, end === -1 ? current.length : end);
4100
+ i += 1;
4101
+ cursor = 0;
4102
+ if (end !== -1) break;
4103
+ }
4104
+ continue;
4105
+ }
4106
+ const hash = commentAt(key.value);
4107
+ const body = (hash === -1 ? key.value : key.value.slice(0, hash)).trim();
4108
+ if (BLOCK_SCALAR.test(body)) {
4109
+ i += 1;
4110
+ while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
4111
+ const current = lines[i];
4112
+ if (current.trim() !== "" && indentOf(current) <= key.indent) break;
4113
+ if (current.trim()) out[i] = current;
4114
+ i += 1;
4115
+ }
4116
+ continue;
4117
+ }
4118
+ if (body === "" || body === "~" || /^null$/i.test(body) || body.startsWith("[") || body.startsWith("{")) {
4119
+ i += 1;
4120
+ continue;
4121
+ }
4122
+ out[i] = keepSpan(line, key.valueAt, hash === -1 ? line.length : key.valueAt + hash);
4123
+ i += 1;
4124
+ while (i < lines.length && lines[i] !== "---" && lines[i] !== "...") {
4125
+ const current = lines[i];
4126
+ if (current.trim() === "" || indentOf(current) <= key.indent) break;
4127
+ if (!/^\s*#/.test(current)) {
4128
+ const cut = commentAt(current);
4129
+ out[i] = cut === -1 ? current : keepSpan(current, 0, cut);
4130
+ }
4131
+ i += 1;
4132
+ }
4133
+ }
4134
+ const masked = out.join("\n");
4135
+ return masked.length === block.length ? masked : blank(block);
4136
+ }
4045
4137
  function proseBlocks(file) {
4046
- const masked = file.text.replace(/^(```|~~~)[\s\S]*?^\1/gm, blank).replace(/`[^`\n]*`/g, (m) => " ".repeat(m.length)).replace(/^---\n[\s\S]*?\n---\n/, blank).replace(/<!--[\s\S]*?-->/g, blank);
4138
+ const masked = file.text.replace(/^(```|~~~)[\s\S]*?^\1/gm, blank).replace(/`[^`\n]*`/g, (m) => " ".repeat(m.length)).replace(/^---\n[\s\S]*?\n---\n/, (block) => maskFrontMatter(block)).replace(/<!--[\s\S]*?-->/g, blank);
4047
4139
  return [{ path: file.path, text: masked, offset: 0 }];
4048
4140
  }
4049
4141
  function isData(path) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@domandigital/craft",
3
- "version": "0.19.0",
3
+ "version": "0.19.1",
4
4
  "private": false,
5
5
  "description": "The Doman Digital house craft standard as numbers: OKLCh colour ramps that snap to existing anchors, derived semantic tokens with measured WCAG and APCA contrast, one shared motion vocabulary for CSS and JS, and a base stylesheet. Zero dependencies.",
6
6
  "license": "Apache-2.0",