@tritard/waterbrother 0.8.21 → 0.8.23
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 +1 -1
- package/src/agent.js +11 -4
- package/src/frontend.js +106 -17
package/package.json
CHANGED
package/src/agent.js
CHANGED
|
@@ -59,12 +59,12 @@ When you use tools:
|
|
|
59
59
|
- define the typography, color system, spacing rhythm, and motion restraint through the code you write
|
|
60
60
|
- avoid fake press badges, fake testimonials, fake founder lore, and placeholder image services unless explicitly requested
|
|
61
61
|
- avoid generic Tailwind CDN template output and default premium-blog serif/sans pairings
|
|
62
|
-
- avoid invented publication brands, named authors, issue numbers, staff credits, or editorial worldbuilding unless the user explicitly asked for fictional framing
|
|
63
62
|
- avoid browser-default Georgia/Times plus system-sans typography as a final design answer
|
|
64
63
|
- avoid fake keyboard shortcuts, fake command palettes, and demo-only interaction chrome
|
|
65
|
-
- avoid generic reflective-editorial copy about slowness, attention, or the examined life unless the user explicitly asked for that voice
|
|
66
|
-
- prefer fewer sections and at least one asymmetrical or compositionally distinctive move over a fully balanced template layout
|
|
67
64
|
- prefer fewer stronger sections over a busy page with fake search, fake filters, or filler widgets
|
|
65
|
+
- adapt the above rules to the site type; docs and dashboards may need clearer repetitive utility layouts than editorial or portfolio pages
|
|
66
|
+
- for ecommerce/store tasks, prioritize merchandising, trust, objection handling, and purchase flow over editorial atmosphere
|
|
67
|
+
- only apply benchmark-grade strictness about publication framing, reflective-editorial copy, and forced asymmetry when the task is clearly a benchmark/comparison ask
|
|
68
68
|
- After making code or file edits:
|
|
69
69
|
- lead with the file path or paths you changed
|
|
70
70
|
- summarize concrete changes, not vibes or quality claims
|
|
@@ -124,9 +124,16 @@ function buildSystemPrompt(profile, experienceMode = "standard", autonomyMode =
|
|
|
124
124
|
`- tone: ${frontend.tone || "unknown"}`,
|
|
125
125
|
`- content mode: ${frontend.contentMode || "designed-placeholder"}`,
|
|
126
126
|
`- asset policy: ${frontend.assetPolicy || "no-placeholder-images-unless-explicit"}`,
|
|
127
|
-
`- layout starter: ${frontend.layoutStarter || "choose a strong non-generic section grammar"}
|
|
127
|
+
`- layout starter: ${frontend.layoutStarter || "choose a strong non-generic section grammar"}`,
|
|
128
|
+
`- benchmark mode: ${frontend.benchmarkMode ? "on" : "off"}`
|
|
128
129
|
].join("\n")
|
|
129
130
|
);
|
|
131
|
+
if (Array.isArray(frontend.siteTypeRules) && frontend.siteTypeRules.length > 0) {
|
|
132
|
+
ctxLines.push(`Site-type rules:\n- ${frontend.siteTypeRules.join("\n- ")}`);
|
|
133
|
+
}
|
|
134
|
+
if (Array.isArray(frontend.benchmarkSiteTypeRules) && frontend.benchmarkSiteTypeRules.length > 0) {
|
|
135
|
+
ctxLines.push(`Benchmark site-type rules:\n- ${frontend.benchmarkSiteTypeRules.join("\n- ")}`);
|
|
136
|
+
}
|
|
130
137
|
}
|
|
131
138
|
if (executionContext.reminders) ctxLines.push(`Scope reminders:\n${executionContext.reminders}`);
|
|
132
139
|
if (ctxLines.length > 0) base += `\n\nExecution context:\n${ctxLines.join("\n")}`;
|
package/src/frontend.js
CHANGED
|
@@ -49,7 +49,35 @@ Rules:
|
|
|
49
49
|
|
|
50
50
|
const BENCHMARK_FRONTEND_PROMPT = /\b(?:benchmark|squarespace quality|ultimate design|first class|on par|codex|claude code|cc)\b/i;
|
|
51
51
|
|
|
52
|
+
const UNIVERSAL_FRONTEND_REMINDERS = [
|
|
53
|
+
"Choose one visual direction and stay consistent across typography, spacing, color, and motion.",
|
|
54
|
+
"Choose a real type system with deliberate character. Browser-default Georgia/Times plus system sans is not an acceptable final design direction.",
|
|
55
|
+
"Prefer hand-authored CSS variables and layout rules over generic template utility sprawl when feasible.",
|
|
56
|
+
"Cut fake credibility elements, fake brands, fake testimonials, and filler interface chrome unless explicitly requested.",
|
|
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.",
|
|
59
|
+
"Prefer fewer sections with stronger hierarchy over a long page full of low-value widgets."
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const BENCHMARK_FRONTEND_REMINDERS = [
|
|
63
|
+
"For benchmark frontend tasks, cut generic reflective-editorial copy. Use sharper, more concrete language or neutral structural placeholders instead of atmosphere-writing.",
|
|
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."
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
const BENCHMARK_SITE_TYPE_RULES = {
|
|
69
|
+
blog: [
|
|
70
|
+
"Benchmark blog mode: use neutral structural placeholders or concrete subject matter instead of publication worldbuilding or reflective-editorial atmosphere prose."
|
|
71
|
+
],
|
|
72
|
+
store: [
|
|
73
|
+
"Benchmark ecommerce mode: prioritize conversion architecture over editorial styling. The page should sell, not just look clean.",
|
|
74
|
+
"Benchmark ecommerce mode: include proof, objection handling, and trust signals that belong on a real single-product PDP.",
|
|
75
|
+
"Benchmark ecommerce mode: do not leave the main merchandising surface as a literal placeholder or demo box."
|
|
76
|
+
]
|
|
77
|
+
};
|
|
78
|
+
|
|
52
79
|
const SITE_TYPES = [
|
|
80
|
+
["store", /\b(shopify|ecommerce|e-commerce|store|shop|product page|pdp|single product|product detail page)\b/i],
|
|
53
81
|
["blog", /\b(blog|journal|essays?|articles?|publication|editorial)\b/i],
|
|
54
82
|
["landing", /\b(landing page|homepage|home page|marketing site|product site|launch page|hero section)\b/i],
|
|
55
83
|
["portfolio", /\b(portfolio|studio site|agency site|showcase)\b/i],
|
|
@@ -58,6 +86,7 @@ const SITE_TYPES = [
|
|
|
58
86
|
];
|
|
59
87
|
|
|
60
88
|
const ARCHETYPES = [
|
|
89
|
+
["single-product-commerce", /\b(shopify|ecommerce|e-commerce|single product|product page|pdp|store)\b/i],
|
|
61
90
|
["editorial-minimal", /\b(editorial|minimal|literary|journal|quiet)\b/i],
|
|
62
91
|
["luxury-magazine", /\b(luxury|magazine|fashion|elegant|squarespace)\b/i],
|
|
63
92
|
["founder-journal", /\b(founder|memo|notebook|letter|essay)\b/i],
|
|
@@ -73,6 +102,36 @@ const AUDIENCE_HINTS = [
|
|
|
73
102
|
["operators", /\b(founders?|operators?|engineers?|designers?)\b/i]
|
|
74
103
|
];
|
|
75
104
|
|
|
105
|
+
const SITE_TYPE_RULES = {
|
|
106
|
+
blog: [
|
|
107
|
+
"For blogs and editorial sites, prefer structural placeholder labels over inventing fictional publication brands, named editors, or fake biographical lore.",
|
|
108
|
+
"Do not invent issue numbers, seasonal issue metadata, staff credits, or named authors/photographers unless the user explicitly asked for fictional worldbuilding.",
|
|
109
|
+
"Do not add a newsletter/signup block unless the user explicitly asked for one or the site type clearly requires capture."
|
|
110
|
+
],
|
|
111
|
+
landing: [
|
|
112
|
+
"For landing pages, prioritize the value proposition, proof, and one primary action over editorial atmosphere.",
|
|
113
|
+
"CTA sections are acceptable when they are genuinely part of the requested product flow; avoid fake testimonials or fake customer logos."
|
|
114
|
+
],
|
|
115
|
+
portfolio: [
|
|
116
|
+
"For portfolios, let work samples, case studies, and identity carry the page rather than editorial filler.",
|
|
117
|
+
"Do not add newsletter/signup blocks or publication framing unless explicitly requested."
|
|
118
|
+
],
|
|
119
|
+
docs: [
|
|
120
|
+
"For docs and help centers, clarity and information scent matter more than asymmetry or art direction.",
|
|
121
|
+
"Balanced, repetitive utility layouts are acceptable when they improve scanability."
|
|
122
|
+
],
|
|
123
|
+
dashboard: [
|
|
124
|
+
"For dashboards and app UI, useful controls and information density matter more than editorial composition.",
|
|
125
|
+
"Do not remove necessary navigation or controls just to make the page feel minimal."
|
|
126
|
+
],
|
|
127
|
+
store: [
|
|
128
|
+
"For ecommerce and single-product store pages, prioritize merchandising clarity, trust, and purchase flow over editorial atmosphere.",
|
|
129
|
+
"Include a clear product hierarchy near the buy action: product name, price, variant controls, purchase CTA, and shipping/returns or guarantee context.",
|
|
130
|
+
"Use proof and objection handling where appropriate: reviews, trust indicators, fit/material guidance, FAQ, shipping, or returns.",
|
|
131
|
+
"Do not add fake command palettes, fake app chrome, or non-commerce sections that distract from purchase intent."
|
|
132
|
+
]
|
|
133
|
+
};
|
|
134
|
+
|
|
76
135
|
const ARCHETYPE_RULES = {
|
|
77
136
|
"editorial-minimal": [
|
|
78
137
|
"Use restrained editorial hierarchy with fewer, larger blocks of content.",
|
|
@@ -109,6 +168,12 @@ const ARCHETYPE_RULES = {
|
|
|
109
168
|
"Do not add fake command-palette or keyboard-shortcut gimmicks unless the interface truly needs them.",
|
|
110
169
|
"Target type palette: sharp grotesk or mono-accent system with disciplined scale and hard contrast."
|
|
111
170
|
],
|
|
171
|
+
"single-product-commerce": [
|
|
172
|
+
"Use a commerce-first hierarchy: product image, offer, price, variants, CTA, trust, and objection handling should be visually obvious.",
|
|
173
|
+
"Favor sharp sans-serif typography with disciplined emphasis; avoid editorial-magazine drift.",
|
|
174
|
+
"The hero surface must merchandise the product, not just reserve space for a placeholder.",
|
|
175
|
+
"Target type palette: assertive commerce sans with compact utility text and a restrained accent display if needed."
|
|
176
|
+
],
|
|
112
177
|
"quiet-portfolio": [
|
|
113
178
|
"Let work and case-study structure carry the page, not decorative chrome.",
|
|
114
179
|
"Use calm spacing and image framing with minimal interface noise.",
|
|
@@ -146,6 +211,10 @@ const LAYOUT_STARTERS = {
|
|
|
146
211
|
"landing:high-contrast-tech": [
|
|
147
212
|
"Preferred layout starter: sharp hero + proof strip + product detail band + focused CTA footer.",
|
|
148
213
|
"Avoid generic 6-section SaaS marketing pages unless explicitly requested."
|
|
214
|
+
],
|
|
215
|
+
"store:single-product-commerce": [
|
|
216
|
+
"Preferred layout starter: media gallery + purchase stack + trust strip + proof/reviews + FAQ or care/shipping objections.",
|
|
217
|
+
"Do not stop at a clean two-column PDP shell; include the conversion architecture a strong Shopify single-product page needs."
|
|
149
218
|
]
|
|
150
219
|
};
|
|
151
220
|
|
|
@@ -172,6 +241,11 @@ const SLOP_PATTERNS = [
|
|
|
172
241
|
{ 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 }
|
|
173
242
|
];
|
|
174
243
|
|
|
244
|
+
function getBenchmarkSiteTypeRules(siteType, benchmarkMode) {
|
|
245
|
+
if (!benchmarkMode) return [];
|
|
246
|
+
return BENCHMARK_SITE_TYPE_RULES[siteType] || [];
|
|
247
|
+
}
|
|
248
|
+
|
|
175
249
|
function getLayoutStarter(siteType, archetype) {
|
|
176
250
|
return LAYOUT_STARTERS[`${siteType}:${archetype}`] || null;
|
|
177
251
|
}
|
|
@@ -252,6 +326,10 @@ function inferAssetPolicy(text) {
|
|
|
252
326
|
return "no-placeholder-images-unless-explicit";
|
|
253
327
|
}
|
|
254
328
|
|
|
329
|
+
function getSiteTypeRules(siteType) {
|
|
330
|
+
return SITE_TYPE_RULES[siteType] || [];
|
|
331
|
+
}
|
|
332
|
+
|
|
255
333
|
export function isFrontendGenerationPrompt(promptText = "", profile = "coder") {
|
|
256
334
|
const text = String(promptText || "").trim();
|
|
257
335
|
if (!text) return false;
|
|
@@ -275,25 +353,21 @@ export function buildFrontendExecutionContext({ promptText = "", profile = "code
|
|
|
275
353
|
if (benchmarkMode && siteType === "blog" && contentMode === "designed-placeholder") {
|
|
276
354
|
contentMode = "structural-placeholder";
|
|
277
355
|
}
|
|
356
|
+
if (benchmarkMode && siteType === "store" && contentMode === "designed-placeholder") {
|
|
357
|
+
contentMode = "conversion-placeholder";
|
|
358
|
+
}
|
|
278
359
|
const assetPolicy = inferAssetPolicy(text);
|
|
279
360
|
const layoutStarter = getLayoutStarter(siteType, archetype);
|
|
361
|
+
const siteTypeRules = getSiteTypeRules(siteType);
|
|
362
|
+
const benchmarkSiteTypeRules = getBenchmarkSiteTypeRules(siteType, benchmarkMode);
|
|
280
363
|
const reminders = [
|
|
281
364
|
`Frontend brief: site type = ${siteType}, archetype = ${archetype}, audience = ${audience}, tone = ${tone}.`,
|
|
282
365
|
`Content mode: ${contentMode}. Asset policy: ${assetPolicy}.`,
|
|
283
366
|
layoutStarter ? `Layout starter: ${layoutStarter[0]}` : "",
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
"For blogs and editorial sites, prefer structural placeholder labels over inventing fictional publication brands, named editors, or fake biographical lore.",
|
|
289
|
-
"Do not invent issue numbers, seasonal issue metadata, staff credits, or named authors/photographers unless the user explicitly asked for fictional worldbuilding.",
|
|
290
|
-
"Do not add a newsletter/signup block unless the user explicitly asked for one or the site type clearly requires capture.",
|
|
291
|
-
"Do not add fake keyboard shortcuts, fake command palettes, or demo-only interactive chrome unless the interface truly needs them.",
|
|
292
|
-
"Avoid placeholder image services, Inter/Playfair default pairings, Tailwind CDN starter aesthetics, and generic premium-blog tropes.",
|
|
293
|
-
"Prefer fewer sections with stronger hierarchy over a long page full of low-value widgets.",
|
|
294
|
-
"For benchmark frontend tasks, cut generic reflective-editorial copy. Use sharper, more concrete language or neutral structural placeholders instead of atmosphere-writing.",
|
|
295
|
-
"For benchmark frontend tasks, force at least one asymmetrical or compositionally distinctive move instead of a fully balanced template layout.",
|
|
296
|
-
benchmarkMode ? "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." : "",
|
|
367
|
+
...UNIVERSAL_FRONTEND_REMINDERS,
|
|
368
|
+
...siteTypeRules,
|
|
369
|
+
...(benchmarkMode ? BENCHMARK_FRONTEND_REMINDERS : []),
|
|
370
|
+
...benchmarkSiteTypeRules,
|
|
297
371
|
...(layoutStarter ? [layoutStarter[1]] : []),
|
|
298
372
|
...(ARCHETYPE_RULES[archetype] || [])
|
|
299
373
|
].join("\n");
|
|
@@ -307,7 +381,9 @@ export function buildFrontendExecutionContext({ promptText = "", profile = "code
|
|
|
307
381
|
contentMode,
|
|
308
382
|
assetPolicy,
|
|
309
383
|
layoutStarter: layoutStarter ? layoutStarter[0] : null,
|
|
310
|
-
benchmarkMode
|
|
384
|
+
benchmarkMode,
|
|
385
|
+
siteTypeRules,
|
|
386
|
+
benchmarkSiteTypeRules
|
|
311
387
|
},
|
|
312
388
|
reminders
|
|
313
389
|
};
|
|
@@ -343,6 +419,18 @@ export function detectFrontendSlop({ promptText = "", assistantText = "", receip
|
|
|
343
419
|
}
|
|
344
420
|
const siteType = pickByPattern(String(promptText || ""), SITE_TYPES, "landing");
|
|
345
421
|
const benchmarkMode = isBenchmarkFrontendTask(promptText);
|
|
422
|
+
if (siteType === "store" && benchmarkMode && /\b(?:product image|visual placeholder|replace with real product photography)\b/i.test(haystack)) {
|
|
423
|
+
flags.push("benchmark store left the primary merchandising surface as a placeholder");
|
|
424
|
+
score += 4;
|
|
425
|
+
}
|
|
426
|
+
if (siteType === "store" && benchmarkMode && !/\b(?:review|reviews|testimonial|rated|stars?|customers?)\b/i.test(haystack)) {
|
|
427
|
+
flags.push("benchmark store lacks social proof or review architecture");
|
|
428
|
+
score += 2;
|
|
429
|
+
}
|
|
430
|
+
if (siteType === "store" && benchmarkMode && !/\b(?:faq|shipping|returns|guarantee|size guide|fit|materials?|care)\b/i.test(haystack)) {
|
|
431
|
+
flags.push("benchmark store lacks objection-handling content");
|
|
432
|
+
score += 2;
|
|
433
|
+
}
|
|
346
434
|
if (siteType === "blog" && !hasExplicitNewsletterRequest(promptText) && /\bnewsletter|subscribe|email\b/i.test(haystack)) {
|
|
347
435
|
flags.push("newsletter block added without being requested");
|
|
348
436
|
score += 3;
|
|
@@ -355,12 +443,12 @@ export function detectFrontendSlop({ promptText = "", assistantText = "", receip
|
|
|
355
443
|
flags.push("fake keyboard or command-palette gimmick");
|
|
356
444
|
score += 3;
|
|
357
445
|
}
|
|
358
|
-
if (siteType === "blog" && benchmarkMode && /\b(?:measure of time in ordinary things|quiet rituals|architecture of memory|cult of productivity|considered writing|the slow accumulation of days|craft of attention|in defense of silence)\b/i.test(haystack)) {
|
|
446
|
+
if (siteType === "blog" && benchmarkMode && /\b(?:measure of time in ordinary things|quiet rituals|architecture of memory|cult of productivity|considered writing|the slow accumulation of days|craft of attention|in defense of silence|meditation on permanence and ephemerality|stillness and the act of looking|deliberate observation)\b/i.test(haystack)) {
|
|
359
447
|
flags.push("benchmark blog fell back to reflective-editorial atmosphere copy");
|
|
360
448
|
score += 3;
|
|
361
449
|
}
|
|
362
450
|
const editorialLayoutHits = GENERIC_EDITORIAL_LAYOUT_PATTERNS.filter((pattern) => pattern.test(haystack)).length;
|
|
363
|
-
if (siteType === "blog" && editorialLayoutHits >= 3) {
|
|
451
|
+
if (siteType === "blog" && benchmarkMode && editorialLayoutHits >= 3) {
|
|
364
452
|
flags.push("generic editorial starter layout");
|
|
365
453
|
score += 2;
|
|
366
454
|
}
|
|
@@ -369,7 +457,7 @@ export function detectFrontendSlop({ promptText = "", assistantText = "", receip
|
|
|
369
457
|
return {
|
|
370
458
|
score,
|
|
371
459
|
flags,
|
|
372
|
-
hardBlock: flags.some((flag) => /fictional publication identity|fake keyboard|reflective-editorial atmosphere/.test(flag)),
|
|
460
|
+
hardBlock: flags.some((flag) => /fictional publication identity|fake keyboard|reflective-editorial atmosphere|primary merchandising surface as a placeholder/.test(flag)),
|
|
373
461
|
severe: score >= 5,
|
|
374
462
|
summary: flags.length > 0 ? `frontend slop flags: ${flags.join(", ")}` : "no deterministic frontend slop flags"
|
|
375
463
|
};
|
|
@@ -410,6 +498,7 @@ export function buildFrontendRevisionPrompt({
|
|
|
410
498
|
"Remove fake keyboard shortcuts, fake command palettes, and demo-only interaction flourishes that do not help the page.",
|
|
411
499
|
"Cut reflective-editorial filler copy and replace it with either concrete language or neutral structural placeholders.",
|
|
412
500
|
"For benchmark blog tasks, default to neutral structural placeholder content instead of invented publication framing, issue metadata, or named contributors.",
|
|
501
|
+
"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.",
|
|
413
502
|
"Reduce section count if needed and push one stronger asymmetrical composition instead of a sequence of balanced blocks.",
|
|
414
503
|
"Simplify the page if needed. Stronger direction with fewer elements is preferred over busier generic output.",
|
|
415
504
|
"Rewrite the weakest sections rather than making superficial tweaks."
|