@koda-sl/baker-cli 0.290.2 → 0.290.3

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/README.md CHANGED
@@ -5870,6 +5870,8 @@ baker landing critique spring-offer summer-offer claude # score three landings
5870
5870
 
5871
5871
  - **Positioning integrity is scored too, and it is the one copy rule that blocks on a single sentence.** `competitor-concession` fires when the page ranks somebody else above the client, or says the client does not lead at what the page sells ("su constructor es mejor que el nuestro", "we're not the best"). Every other prose rule waits for a cluster because one AI tell proves nothing; this one is the whole defect on its own — the page is paid traffic, and it is arguing the visitor should leave. Two shapes that read identically are exempt by design: a concession about **price**, in either direction ("we are not the cheapest / the most expensive, and here is why" is premium positioning), and a superlative flipped by a negation ("ningún equipo trabaja más rápido que el nuestro"), which is the strongest claim *for* the client. Its warn-tier sibling `competitor-named-in-comparison` fires when a name from `src/content/competitors/` appears in a comparative sentence outside a `<table>` — a comparison table is a section the landing skill teaches, but naming a rival anywhere else on paid traffic is the client's call, not the build's. Spanish, Portuguese and English.
5872
5872
 
5873
+ - **Comments are not markup, and no rule reads one.** Astro expression comments (`{/* … */}`) and HTML comments (`<!-- … -->`) are blanked before detection, offsets preserved so `file:line` stays exact. A shared scaffold component explaining its `preconnect` in prose that spelled `<img>` twice was read as two broken images — block-tier — so every landing rendering a video failed the publish gate on a file the client cannot edit. Comment prose is also where a component's reasoning lives, em-dashes and buzzwords included, so reading it inflated the count-threshold tells too.
5874
+
5873
5875
  - **Copy held in component frontmatter is read like markup copy.** Astro landings keep FAQ pairs, testimonial quotes, feature cards and pricing rows as a `const items = [{ q, a }]` array above the `---` fence and render them in a `.map()`, so a critic that blanked the whole block was blind to a large share of every page's actual words. Prose string literals in that block now feed every copy rule; imports, class strings, URLs and config do not, and the bar is deliberately high in that direction — a Tailwind class list in front of the copy rules is worse than one missed tell.
5874
5876
 
5875
5877
  Output is the standard envelope `{ ok, data, hints }` with `data = { advisory, slug, overall, counts, dimensions, findings }`. `dimensions` scores seven design families (typography, color, borders_depth, motion, spacing, copy, integrity) 0–1 (higher is better); `counts` is the block/warn/advisory tally.
package/dist/cli.js CHANGED
@@ -48982,6 +48982,20 @@ function blankAstroFrontmatter(text2) {
48982
48982
  }
48983
48983
  return kept.join("") + text2.slice(cut);
48984
48984
  }
48985
+ function blankUnrenderedSource(text2) {
48986
+ return blankTemplateComments(blankAstroFrontmatter(text2));
48987
+ }
48988
+ function blankTemplateComments(text2) {
48989
+ const out = text2.split("");
48990
+ const pattern = /\{\s*\/\*[\s\S]*?\*\/\s*\}|<!--[\s\S]*?-->/g;
48991
+ for (const m of text2.matchAll(pattern)) {
48992
+ const start = m.index ?? 0;
48993
+ for (let i = start; i < start + m[0].length && i < out.length; i++) {
48994
+ if (out[i] !== "\n") out[i] = " ";
48995
+ }
48996
+ }
48997
+ return out.join("");
48998
+ }
48985
48999
  function frontmatterLength(text2) {
48986
49000
  if (!text2.startsWith("---")) return 0;
48987
49001
  const lines = text2.split("\n");
@@ -49355,7 +49369,7 @@ function distinctCompetitorNames(competitors) {
49355
49369
  return [...byFold.values()];
49356
49370
  }
49357
49371
  function mentionsInSource(source, names) {
49358
- const text2 = blankAstroFrontmatter(source.text);
49372
+ const text2 = blankUnrenderedSource(source.text);
49359
49373
  const visible = blankHtmlKeepingOffsets(text2);
49360
49374
  const tables = tableRanges(text2);
49361
49375
  const out = [];
@@ -49395,7 +49409,7 @@ function escapeRegExp(value) {
49395
49409
  }
49396
49410
  function detectSource(source) {
49397
49411
  const file = source.path;
49398
- const text2 = blankAstroFrontmatter(source.text);
49412
+ const text2 = blankUnrenderedSource(source.text);
49399
49413
  const findings = [];
49400
49414
  const lines = text2.split("\n");
49401
49415
  for (const matcher of LINE_MATCHERS) {
@@ -49413,7 +49427,7 @@ function detectSource(source) {
49413
49427
  }
49414
49428
  function detectPage(sources) {
49415
49429
  if (sources.length === 0) return [];
49416
- const combined = sources.map((s) => blankAstroFrontmatter(s.text)).join("\n");
49430
+ const combined = sources.map((s) => blankUnrenderedSource(s.text)).join("\n");
49417
49431
  const pageFile = sources.find((s) => s.path === "index.astro" || s.path.endsWith("/index.astro"))?.path ?? sources[0]?.path ?? "index.astro";
49418
49432
  const findings = [];
49419
49433
  for (const analyzer of ANALYZERS) {
@@ -49493,7 +49507,7 @@ function describeCounts(findings) {
49493
49507
  // src/commands/landing/snapshot.ts
49494
49508
  import { mkdir as mkdir9, rename as rename2, writeFile as writeFile13 } from "fs/promises";
49495
49509
  import path31 from "path";
49496
- var CRITIC_VERSION = "3";
49510
+ var CRITIC_VERSION = "4";
49497
49511
  function critiqueCacheDir(projectRoot) {
49498
49512
  return path31.join(projectRoot, ".cache", "landing-critique");
49499
49513
  }