@tritard/waterbrother 0.8.30 → 0.8.32

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tritard/waterbrother",
3
- "version": "0.8.30",
3
+ "version": "0.8.32",
4
4
  "description": "Waterbrother: Grok-powered coding CLI with local tools, sessions, operator modes, and approval controls",
5
5
  "type": "module",
6
6
  "bin": {
package/src/frontend.js CHANGED
@@ -55,30 +55,31 @@ const UNIVERSAL_FRONTEND_REMINDERS = [
55
55
  "Prefer hand-authored CSS variables and layout rules over generic template utility sprawl when feasible.",
56
56
  "Cut fake credibility elements, fake brands, fake testimonials, and filler interface chrome unless explicitly requested.",
57
57
  "Do not add fake keyboard shortcuts, fake command palettes, or demo-only interactive chrome unless the interface truly needs them.",
58
- "Avoid placeholder image services, Inter/Playfair default pairings, Tailwind CDN starter aesthetics, and generic premium-blog tropes.",
58
+ "Avoid placeholder image services, Font Awesome CDN chrome, Inter/Playfair default pairings, Tailwind CDN starter aesthetics, and generic premium-blog tropes.",
59
59
  "Prefer fewer sections with stronger hierarchy over a long page full of low-value widgets."
60
60
  ];
61
61
 
62
62
  const BENCHMARK_FRONTEND_REMINDERS = [
63
63
  "For benchmark frontend tasks, cut generic reflective-editorial copy. Use sharper, more concrete language or neutral structural placeholders instead of atmosphere-writing.",
64
64
  "For benchmark frontend tasks, force at least one asymmetrical or compositionally distinctive move instead of a fully balanced template layout.",
65
- "Benchmark mode: treat fake issue framing, fake publication history, fake keyboard shortcuts, and invented named contributors as disallowed outputs. Use neutral structural placeholders if needed."
65
+ "Benchmark mode: treat fake issue framing, fake publication history, fake keyboard shortcuts, invented named contributors, and demo-page behavior as disallowed outputs. Use neutral structural placeholders if needed.",
66
+ "Benchmark mode: the page should feel publishable, not like a static demo or wireframe explanation."
66
67
  ];
67
68
 
68
69
  const BENCHMARK_SITE_TYPE_RULES = {
69
70
  blog: [
70
71
  "Benchmark blog mode: use neutral structural placeholders or concrete subject matter instead of publication worldbuilding or reflective-editorial atmosphere prose.",
71
- "Benchmark blog mode: do not wrap the page in a generic publication shell like Journal, Featured Essay, Latest Dispatches, Print Edition, Submit Work, or similar magazine-site framing.",
72
+ "Benchmark blog mode: do not wrap the page in a generic publication shell like Journal, Featured Essay, Latest Dispatches, Notes, Archive, Print Edition, Submit Work, or similar magazine-site framing.",
72
73
  "Benchmark blog mode: avoid the default editorial scaffold of hero, story list, archive rail, topics grid, and publication footer unless the user explicitly asked for a magazine-style site.",
73
- "Benchmark blog mode: do not use Tailwind CDN starter theming, picsum/placehold imagery, or fake keyboard/search chrome."
74
+ "Benchmark blog mode: do not use Tailwind CDN starter theming, Font Awesome chrome, picsum/placehold imagery, fake keyboard/search chrome, or demo-only modal article previews."
74
75
  ],
75
76
  store: [
76
77
  "Benchmark ecommerce mode: prioritize conversion architecture over editorial styling. The page should sell, not just look clean.",
77
78
  "Benchmark ecommerce mode: include proof, objection handling, and trust signals that belong on a real single-product PDP.",
78
- "Benchmark ecommerce mode: do not leave the main merchandising surface as a literal placeholder or demo box.",
79
- "Benchmark ecommerce mode: do not use Tailwind CDN starter theming or placeholder product images such as picsum/placehold on the live merchandising surface.",
80
- "Benchmark ecommerce mode: fake command palettes, fake app shortcuts, and unrelated theme chrome are disallowed.",
81
- "Benchmark ecommerce mode: fake review counts, fake bestseller labels, and fake as-featured-in proof are disallowed."
79
+ "Benchmark ecommerce mode: do not leave the main merchandising surface as a literal placeholder, dashed demo box, emoji stand-in, or visual wireframe.",
80
+ "Benchmark ecommerce mode: do not use Tailwind CDN starter theming, Font Awesome chrome, or placeholder product images such as picsum/placehold on the live merchandising surface.",
81
+ "Benchmark ecommerce mode: fake command palettes, fake app shortcuts, demo-only cart gimmicks, and unrelated theme chrome are disallowed.",
82
+ "Benchmark ecommerce mode: fake review counts, fake bestseller labels, fake sales counters, and fake as-featured-in proof are disallowed."
82
83
  ]
83
84
  };
84
85
 
@@ -112,7 +113,8 @@ const SITE_TYPE_RULES = {
112
113
  blog: [
113
114
  "For blogs and editorial sites, prefer structural placeholder labels over inventing fictional publication brands, named editors, or fake biographical lore.",
114
115
  "Do not invent issue numbers, seasonal issue metadata, staff credits, or named authors/photographers unless the user explicitly asked for fictional worldbuilding.",
115
- "Do not add a newsletter/signup block unless the user explicitly asked for one or the site type clearly requires capture."
116
+ "Do not add a newsletter/signup block unless the user explicitly asked for one or the site type clearly requires capture.",
117
+ "Prefer concrete topics or neutral structural labels over essay-magazine abstractions about slowness, attention, memory, or restraint."
116
118
  ],
117
119
  landing: [
118
120
  "For landing pages, prioritize the value proposition, proof, and one primary action over editorial atmosphere.",
@@ -178,6 +180,7 @@ const ARCHETYPE_RULES = {
178
180
  "Use a commerce-first hierarchy: product image, offer, price, variants, CTA, trust, and objection handling should be visually obvious.",
179
181
  "Favor sharp sans-serif typography with disciplined emphasis; avoid editorial-magazine drift.",
180
182
  "The hero surface must merchandise the product, not just reserve space for a placeholder.",
183
+ "If no real photo is available, create a product-shaped merchandising composition with material callouts and silhouette treatment, not a dashed placeholder box or emoji stand-in.",
181
184
  "Target type palette: assertive commerce sans with compact utility text and a restrained accent display if needed."
182
185
  ],
183
186
  "quiet-portfolio": [
@@ -240,16 +243,20 @@ const GENERIC_EDITORIAL_LAYOUT_PATTERNS = [
240
243
  const SLOP_PATTERNS = [
241
244
  { key: "placeholder_images", label: "placeholder image service", pattern: /\b(?:picsum\.photos|placehold\.co|placeholder\.com)\b/i, weight: 3 },
242
245
  { key: "tailwind_cdn", label: "Tailwind CDN starter styling", pattern: /cdn\.tailwindcss\.com/i, weight: 2 },
246
+ { key: "font_awesome_cdn", label: "Font Awesome CDN chrome", pattern: /cdnjs\.cloudflare\.com\/ajax\/libs\/font-awesome|fontawesome/i, weight: 2 },
243
247
  { key: "inter_playfair", label: "generic Inter/Playfair premium pairing", pattern: /Inter|Playfair\s+Display/i, weight: 2 },
244
248
  { key: "browser_default_type", label: "browser-default serif/sans fallback typography", pattern: /\b(?:Georgia|Times New Roman|serif;|system-ui|BlinkMacSystemFont|Segoe UI|Helvetica|Arial)\b/i, weight: 2 },
245
249
  { key: "fake_prestige", label: "fake prestige or publication badge", pattern: /\b(?:featured in|as seen in|forbes|the atlantic|wall street journal|award-winning)\b/i, weight: 3 },
246
250
  { key: "fake_founder_lore", label: "fake founder or studio lore", pattern: /\b(?:founded in|est\s+20\d{2}|from the studio|published from a small studio|founder\s*&\s*essayist)\b/i, weight: 2 },
247
251
  { key: "newsletter_cliche", label: "generic newsletter promise copy", pattern: /\b(?:no spam, ever|respect your inbox|join the newsletter|subscribe to the journal|receive the next dispatch|quarterly letters from the edge of attention|only the essential)\b/i, weight: 2 },
248
252
  { key: "fake_ui_chrome", label: "fake low-value UI chrome", pattern: /\b(?:search|filterCategory|showPostModal|toggleSearch|Latest Stories|Recent Dispatches|command palette would open here|metaKey && e\.key === ['"]k['"])\b/i, weight: 2 },
253
+ { key: "demo_modal_chrome", label: "demo modal or prompt/alert interaction chrome", pattern: /\b(?:prompt\(|alert\(|modal|demo only|structural preview|select an essay to read a structural preview)\b/i, weight: 2 },
254
+ { key: "demo_page_language", label: "demo page explanation copy", pattern: /\b(?:static demonstration page|demonstration only|demo only|not a real store|not a real publication|structural demonstration|built as a single html file|static demo)\b/i, weight: 3 },
249
255
  { key: "premium_blog_trope", label: "generic premium-blog editorial trope", pattern: /\b(?:thoughtful living|slow living|curated reflections|crafted with intention|made with intention|a quiet publication|made with restraint|journal of attention|discipline of seeing|private notes made public)\b/i, weight: 2 },
250
256
  { key: "reflective_editorial_copy", label: "generic reflective-editorial copy trope", pattern: /\b(?:quiet architecture of attention|great thinkers understood|value of slowness|the examined life|deliberate cultivation of focus|most radical act|what we have forgotten|how everyday items carry|still matters)\b/i, weight: 2 },
251
257
  { key: "fictional_publication_brand", label: "invented publication/author scaffolding", pattern: /\b(?:by [A-Z][a-z]+ [A-Z][a-z]+|photography by [A-Z][a-z]+ [A-Z][a-z]+|journal of attention|vesper|lumen|dispatches|vol\.\s*\d+|winter 20\d{2}|autumn 20\d{2}|spring 20\d{2}|summer 20\d{2}|the quarterly|editorial\.)\b/i, weight: 3 },
252
- { key: "fake_social_proof", label: "fake reader count or social proof", pattern: /\b(?:\d+\s+readers joined this month|\d+\s+subscribers?|trusted by)\b/i, weight: 2 }
258
+ { key: "fake_social_proof", label: "fake reader count or social proof", pattern: /\b(?:\d+\s+readers joined this month|\d+\s+subscribers?|trusted by)\b/i, weight: 2 },
259
+ { key: "placeholder_surface", label: "placeholder surface or stand-in hero", pattern: /\b(?:placeholder|visual placeholder|product representation|hero placeholder|dashed|emoji stand-in|🧥|🎧)\b/i, weight: 3 }
253
260
  ];
254
261
 
255
262
  function getBenchmarkSiteTypeRules(siteType, benchmarkMode) {
@@ -434,18 +441,30 @@ export function detectFrontendSlop({ promptText = "", assistantText = "", receip
434
441
  flags.push("benchmark store left the primary merchandising surface as a placeholder");
435
442
  score += 4;
436
443
  }
444
+ if (siteType === "store" && benchmarkMode && /\b(?:placeholder|visual placeholder|product representation|dashed|emoji stand-in|🧥|🎧)\b/i.test(haystack)) {
445
+ flags.push("benchmark store used a placeholder hero surface instead of product-shaped merchandising");
446
+ score += 4;
447
+ }
437
448
  if (siteType === "store" && benchmarkMode && /cdn\.tailwindcss\.com/i.test(haystack)) {
438
449
  flags.push("benchmark store relied on Tailwind CDN starter theming");
439
450
  score += 4;
440
451
  }
452
+ if (siteType === "store" && benchmarkMode && /(?:cdnjs\.cloudflare\.com\/ajax\/libs\/font-awesome|fontawesome)/i.test(haystack)) {
453
+ flags.push("benchmark store relied on Font Awesome chrome");
454
+ score += 3;
455
+ }
441
456
  if (siteType === "store" && benchmarkMode && /\b(?:picsum\.photos|placehold\.co|placeholder\.com)\b/i.test(haystack)) {
442
457
  flags.push("benchmark store used placeholder product imagery");
443
458
  score += 4;
444
459
  }
445
- if (siteType === "store" && benchmarkMode && /\b(?:best seller|best seller|\d[\d,]*\s+reviews|as featured in|featured in|trusted by|studio engineers approved)\b/i.test(haystack)) {
460
+ if (siteType === "store" && benchmarkMode && /\b(?:best seller|bestseller|\d[\d,]*\s+reviews|\d[\d,]*\s+\w+\s+sold\s+this\s+month|sold this month|as featured in|featured in|trusted by|studio engineers approved)\b/i.test(haystack)) {
446
461
  flags.push("benchmark store used fake proof or badge chrome");
447
462
  score += 4;
448
463
  }
464
+ if (siteType === "store" && benchmarkMode && /\b(?:metaKey && e\.key === ['"]k['"]|command palette|keyboard shortcuts?)\b/i.test(haystack)) {
465
+ flags.push("benchmark store used fake keyboard or shortcut chrome");
466
+ score += 4;
467
+ }
449
468
  if (siteType === "store" && benchmarkMode && !/\b(?:review|reviews|testimonial|rated|stars?|customers?)\b/i.test(haystack)) {
450
469
  flags.push("benchmark store lacks social proof or review architecture");
451
470
  score += 2;
@@ -466,14 +485,26 @@ export function detectFrontendSlop({ promptText = "", assistantText = "", receip
466
485
  flags.push("benchmark blog used generic publication-shell framing");
467
486
  score += 3;
468
487
  }
488
+ if (siteType === "blog" && benchmarkMode && /\b(?:Featured Essay|In Praise of Slowness|Measure of Restraint|On Attention|Craft and Memory|Latest Dispatches|From the Archive|Notes)\b/i.test(haystack)) {
489
+ flags.push("benchmark blog fell back to essay-magazine placeholder language");
490
+ score += 3;
491
+ }
469
492
  if (siteType === "blog" && benchmarkMode && /cdn\.tailwindcss\.com/i.test(haystack)) {
470
493
  flags.push("benchmark blog relied on Tailwind CDN starter theming");
471
494
  score += 4;
472
495
  }
496
+ if (siteType === "blog" && benchmarkMode && /(?:cdnjs\.cloudflare\.com\/ajax\/libs\/font-awesome|fontawesome)/i.test(haystack)) {
497
+ flags.push("benchmark blog relied on Font Awesome chrome");
498
+ score += 3;
499
+ }
473
500
  if (siteType === "blog" && benchmarkMode && /\b(?:picsum\.photos|placehold\.co|placeholder\.com)\b/i.test(haystack)) {
474
501
  flags.push("benchmark blog used placeholder imagery");
475
502
  score += 4;
476
503
  }
504
+ if (siteType === "blog" && benchmarkMode && /\b(?:prompt\(|alert\(|toggleSearch|viewPost\(|modal|structural preview|subscribe)\b/i.test(haystack)) {
505
+ flags.push("benchmark blog used demo interaction chrome");
506
+ score += 3;
507
+ }
477
508
  if (/\b(?:command palette would open here|metaKey && e\.key === ['"]k['"]|keyboard accessibility)\b/i.test(haystack)) {
478
509
  flags.push("fake keyboard or command-palette gimmick");
479
510
  score += 3;
@@ -492,14 +523,14 @@ export function detectFrontendSlop({ promptText = "", assistantText = "", receip
492
523
  return {
493
524
  score,
494
525
  flags,
495
- hardBlock: flags.some((flag) => /fictional publication identity|generic publication-shell framing|fake keyboard|reflective-editorial atmosphere|primary merchandising surface as a placeholder|Tailwind CDN starter theming|placeholder product imagery|placeholder imagery|fake proof or badge chrome/.test(flag)),
526
+ hardBlock: flags.some((flag) => /fictional publication identity|generic publication-shell framing|essay-magazine placeholder language|fake keyboard|reflective-editorial atmosphere|primary merchandising surface as a placeholder|placeholder hero surface|Tailwind CDN starter theming|Font Awesome chrome|placeholder product imagery|placeholder imagery|fake proof or badge chrome|demo interaction chrome|demo page explanation copy/.test(flag)),
496
527
  severe: score >= 5,
497
528
  summary: flags.length > 0 ? `frontend slop flags: ${flags.join(", ")}` : "no deterministic frontend slop flags"
498
529
  };
499
530
  }
500
531
 
501
532
  export function shouldAutoReviseFrontend({ designReview = null, slop = null, revisionCount = 0 } = {}) {
502
- if (revisionCount >= 2) return false;
533
+ if (revisionCount >= 3) return false;
503
534
  if (!designReview) return false;
504
535
  if (slop?.hardBlock) return true;
505
536
  if (designReview.verdict === "weak") return true;
@@ -528,16 +559,21 @@ export function buildFrontendRevisionPrompt({
528
559
  visualNextPass.length > 0 ? `Screenshot revision priorities:\n- ${visualNextPass.join("\n- ")}` : "",
529
560
  "Do not add new filler sections.",
530
561
  "Do not add fake prestige, fake testimonials, fake brands, placeholder-image services, or fictional publication/persona lore unless the user explicitly asked for that worldbuilding.",
562
+ "Do not use Tailwind CDN or Font Awesome CDN for benchmark pages. Use authored CSS and native SVG or plain text/icon treatment instead.",
531
563
  "If this is a blog or editorial site, prefer structural labels and a stronger layout idea over invented magazines, authors, newsletter promises, or atmosphere-copy.",
532
564
  "Do not use browser-default serif/sans fallback stacks as the end-state typography. Pick a deliberate type system or simplify until the typography feels intentional.",
533
565
  "Remove fake keyboard shortcuts, fake command palettes, and demo-only interaction flourishes that do not help the page.",
566
+ "Remove demo toasts, alerts, console narration, and static-demo explanation copy. The page should stand on its own without explaining that it is a demo.",
534
567
  "Cut reflective-editorial filler copy and replace it with either concrete language or neutral structural placeholders.",
535
568
  "For benchmark blog tasks, default to neutral structural placeholder content instead of invented publication framing, issue metadata, or named contributors.",
536
- "For benchmark blog tasks, do not use generic publication-shell labels like Journal, Featured Essay, Latest Dispatches, Print Edition, Submit Work, or publication-footer framing.",
537
- "For benchmark blog tasks, do not use Tailwind CDN starter theming, picsum-style placeholder imagery, or fake search/shortcut chrome.",
569
+ "For benchmark blog tasks, do not use generic publication-shell labels like Journal, Featured Essay, Latest Dispatches, Notes, Archive, Print Edition, Submit Work, or publication-footer framing.",
570
+ "For benchmark blog tasks, do not use essay-magazine fallback headlines like In Praise of Slowness, On Attention, The Measure of Restraint, or similar reflective placeholders.",
571
+ "For benchmark blog tasks, do not use Tailwind CDN starter theming, Font Awesome chrome, picsum-style placeholder imagery, fake search/shortcut chrome, subscribe/newsletter CTA chrome, or demo modal article previews.",
538
572
  "For benchmark store tasks, do not leave the product image area as a labeled placeholder. Use product-shaped merchandising composition, proof, and objection-handling blocks instead.",
539
- "For benchmark store tasks, do not use Tailwind CDN starter theming, picsum-style placeholder imagery, or fake command-palette behavior.",
540
- "For benchmark store tasks, do not invent review counts, bestseller labels, or as-featured-in proof unless the user explicitly requested fictional marketing chrome.",
573
+ "For benchmark store tasks, do not use dashed placeholder boxes, emoji stand-ins, or wireframe hero surfaces. If needed, build a graphic product silhouette or material-driven composition instead.",
574
+ "For benchmark store tasks, do not use Tailwind CDN starter theming, Font Awesome chrome, picsum-style placeholder imagery, or fake command-palette behavior.",
575
+ "For benchmark store tasks, do not invent review counts, bestseller labels, sold-this-month counters, or as-featured-in proof unless the user explicitly requested fictional marketing chrome.",
576
+ slop?.hardBlock ? "Hard-fail benchmark patterns are still present. Rebuild the page from scratch if needed rather than preserving those patterns." : "",
541
577
  "Reduce section count if needed and push one stronger asymmetrical composition instead of a sequence of balanced blocks.",
542
578
  "Simplify the page if needed. Stronger direction with fewer elements is preferred over busier generic output.",
543
579
  "Rewrite the weakest sections rather than making superficial tweaks."
package/src/tools.js CHANGED
@@ -506,11 +506,20 @@ function normalizeContractArgs(args = {}) {
506
506
  summary: String(args.summary || "").trim(),
507
507
  paths: normalizePathList(args.paths || []),
508
508
  commands: uniqueStrings(args.commands || []),
509
- verification: uniqueStrings(args.verification || []),
509
+ verification: uniqueStrings((args.verification || []).map((command) => normalizeVerificationCommand(command))),
510
510
  risk: ["low", "medium", "high"].includes(String(args.risk || "").toLowerCase()) ? String(args.risk).toLowerCase() : "medium"
511
511
  };
512
512
  }
513
513
 
514
+ function normalizeVerificationCommand(command) {
515
+ const raw = String(command || "").trim();
516
+ if (!raw) return raw;
517
+ return raw
518
+ .replace(/(^|[\s("'`])\/desktop(?=\/|$)/gi, `$1${shellEscape(path.join(os.homedir(), "Desktop"))}`)
519
+ .replace(/(^|[\s("'`])\/downloads(?=\/|$)/gi, `$1${shellEscape(path.join(os.homedir(), "Downloads"))}`)
520
+ .replace(/(^|[\s("'`])\/documents(?=\/|$)/gi, `$1${shellEscape(path.join(os.homedir(), "Documents"))}`);
521
+ }
522
+
514
523
  function getTouchedPathsForTool(toolName, args = {}) {
515
524
  if (toolName === "write_file" || toolName === "replace_in_file" || toolName === "make_directory" || toolName === "delete_path") {
516
525
  return normalizePathList([args.path || ""]);