@domandigital/craft 0.20.3 → 0.20.5
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 +12 -0
- package/CHARACTER.md +29 -1
- package/COPY.md +3 -1
- package/README.md +2 -0
- package/dist/{audit-BN2GSFKT.js → audit-5I2WWTL6.js} +3 -3
- package/dist/audit.cjs +41 -3
- package/dist/audit.js +41 -3
- package/dist/{chunk-KQF44RI3.js → chunk-BBJOLR3R.js} +5 -5
- package/dist/{chunk-2276FJVN.js → chunk-DMAMGFV7.js} +4 -4
- package/dist/{chunk-7DQDF3VL.js → chunk-FBWBDBW4.js} +38 -2
- package/dist/{chunk-S3L7TEJF.js → chunk-GJY2VMPD.js} +2 -2
- package/dist/{chunk-GBDPNNC2.js → chunk-N32UUN3S.js} +5 -5
- package/dist/{chunk-JGWOA4LI.js → chunk-PFVSKIPM.js} +4 -2
- package/dist/{chunk-NQAYRK2K.js → chunk-TSO5W32N.js} +14 -14
- package/dist/{chunk-YOZLPNJS.js → chunk-YFS32BZ2.js} +1 -1
- package/dist/{cli-6INEFJYN.js → cli-56H5IPWT.js} +3 -3
- package/dist/{cli-AK4EQHUF.js → cli-BI6XCMCL.js} +5 -5
- package/dist/{cli-6AZVLNWL.js → cli-JQYZXFRH.js} +5 -5
- package/dist/{cli-ZXDGVDYU.js → cli-NIH3WTNE.js} +1 -1
- package/dist/{cli-OYVZOHHV.js → cli-OH6427MC.js} +6 -6
- package/dist/{cli-QGJB6OUB.js → cli-SQC27VYC.js} +6 -6
- package/dist/{cli-AFKXDGUH.js → cli-V4QXTBWR.js} +4 -4
- package/dist/{cli-7HKVVL3P.js → cli-W6FNSHRN.js} +9 -9
- package/dist/cli.js +3 -3
- package/dist/index.cjs +41 -3
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +41 -3
- package/dist/{viewports-cli-WWWWEBKI.js → viewports-cli-C4DWICYI.js} +3 -3
- package/package.json +1 -1
- package/word-lists.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @domandigital/craft
|
|
2
2
|
|
|
3
|
+
## 0.20.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 6047f0e: `chatbot-residue` now finds "Certainly, here is…" at the start of any sentence that follows a full stop or exclamation mark, not only at the start of a line. An email opening "I hope this email finds you well! Certainly, here is the handover request." passed `craft copy --gate` before this. A question mark still does not count, so an FAQ answer such as "Do you work weekends? Absolutely, here are our hours." passes. New review-tier tell `stock-email-line` (catalogue 2026.10.3) reports the stock lines of a form email: "I hope this email finds you well", "hope you're having a great week", "let me know if you have any questions", "don't hesitate to contact us". It prints for review and never blocks, following the house rule that a new tell starts in review.
|
|
8
|
+
|
|
9
|
+
## 0.20.4
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- cc6c0b4: Document opening-photo selection using the Bellerose follow-up: compare photographic strength, crop and sequence before service variety or slide count, with stakeholder preference kept separate from unmeasured customer outcomes.
|
|
14
|
+
|
|
3
15
|
## 0.20.3
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/CHARACTER.md
CHANGED
|
@@ -589,6 +589,33 @@ before reading stakeholder recommendations when possible; if feedback is already
|
|
|
589
589
|
known, record that limitation. A preferred example is useful calibration, not a
|
|
590
590
|
universal order, a conversion claim or an exemption from future scrutiny.
|
|
591
591
|
|
|
592
|
+
#### Select photographs for their position in the sequence
|
|
593
|
+
|
|
594
|
+
Review every proposed opening photograph at the intended size and crop, in order.
|
|
595
|
+
Service coverage alone does not make a photograph suitable for the opening.
|
|
596
|
+
Compare clarity, framing, visible completion, distracting surroundings and the
|
|
597
|
+
visual standard set by the lead image. A technically sound carousel can still
|
|
598
|
+
weaken the page when its later slides are noticeably poorer.
|
|
599
|
+
|
|
600
|
+
On 18 October 2026, after approving Bellerose's mobile flow, Dmitri pointed out
|
|
601
|
+
that the radiator and kitchen-tap slides did not compare with the first bathroom
|
|
602
|
+
photograph. The initial selection had favoured showing different services. A
|
|
603
|
+
review of the available photographs found that the radiator's unfinished edge
|
|
604
|
+
and dust sheet, and the tap's busy surroundings, weakened the opening sequence.
|
|
605
|
+
The approved revision kept the bath-and-shower photograph and used the twin-basins
|
|
606
|
+
photograph second. The lower captioned project gallery retained its service
|
|
607
|
+
coverage. The two bathroom views are not evidence of two separate jobs.
|
|
608
|
+
|
|
609
|
+
The reusable lesson is to choose the strongest coherent sequence the available
|
|
610
|
+
assets support, then let that determine the count. Two strong images can serve
|
|
611
|
+
an opening better than three padded for variety; this is not a rule to always
|
|
612
|
+
use two images, bathrooms or a carousel. Useful job-record photographs can still
|
|
613
|
+
belong beside a service or further down the page. Do not fabricate or retouch
|
|
614
|
+
work into completion to fill a slot. Record rejected candidates, the intended
|
|
615
|
+
crop, the reason for the choice and the stakeholder response with the rendered
|
|
616
|
+
comparison. Here the evidence is visual judgement and an approved preference;
|
|
617
|
+
customer behaviour and enquiry effects remain unmeasured.
|
|
618
|
+
|
|
592
619
|
#### Using it
|
|
593
620
|
|
|
594
621
|
Generating a page: run `craft direction research`, which asks where the
|
|
@@ -1314,7 +1341,7 @@ Generated from the package. Run `pnpm --filter @domandigital/craft run docs`
|
|
|
1314
1341
|
after changing an entry; a test fails until you do.
|
|
1315
1342
|
|
|
1316
1343
|
<!-- craft:catalogue:start -->
|
|
1317
|
-
Catalogue version `2026.10.
|
|
1344
|
+
Catalogue version `2026.10.3`, 71 tells.
|
|
1318
1345
|
|
|
1319
1346
|
| Id | Gen | Surface | Severity | Tell | Why it is a default |
|
|
1320
1347
|
| --- | --- | --- | --- | --- | --- |
|
|
@@ -1361,6 +1388,7 @@ Catalogue version `2026.10.2`, 70 tells.
|
|
|
1361
1388
|
| `staccato-triplet` | 2 | copy | warn | Staccato triplet | Three fragments in a row ('Fast. Friendly. Local.' or 'No fuss. No jargon. Just results.') is the second wave's favourite rhythm. |
|
|
1362
1389
|
| `where-x-meets-y` | 2 | copy | warn | 'Where X meets Y' | 'Where luxury meets comfort' is a tagline shape that fits every business and so describes none. |
|
|
1363
1390
|
| `chatbot-residue` | 1 | copy | warn | Chatbot residue | 'Certainly! Here's a revised version', 'as an AI language model', a citeturn0search0 token, a link tracked utm_source=chatgpt.com: text that exists only because a chat reply was pasted whole. This is evidence, not style. |
|
|
1391
|
+
| `stock-email-line` | 1 | copy | warn | Stock email line | 'I hope this email finds you well', 'let me know if you have any questions', 'don't hesitate to contact us': the opener and closer of a form email. A client reads past them, and a model drafting an email writes them every time. |
|
|
1364
1392
|
| `prompt-context` | 1 | copy | warn | Prompt context | 'This article uses the attached Perplexity research file as the primary source', 'the attached research is right to say': the model talking about what it was given. A reader of a web page has no attachment. Found 38 times across five live DD articles in 2026-09, none caught by any other tell. |
|
|
1365
1393
|
| `placeholder` | 1 | copy | warn | Unfilled placeholder | '[Insert testimonial]', '[Your Name]', lorem ipsum, TODO_PLACEHOLDER: scaffolding a reader must never see, and the clearest sign a page shipped before anyone read it. |
|
|
1366
1394
|
| `question-reveal` | 2 | copy | warn | Staged reveal | 'The result? Faster growth.', 'What does this mean for you? It means...': the writer asks the reader's question for them and answers it. An infomercial hook, and a favourite of generated copy. |
|
package/COPY.md
CHANGED
|
@@ -45,7 +45,8 @@ A single hit fails the check. These are not judgment calls.
|
|
|
45
45
|
a signed-in route (`/admin/`, `/portal/`, `/dashboard/`).
|
|
46
46
|
- **"No X, no Y" as a list**, anywhere in a sentence. "No obligation, no
|
|
47
47
|
spam." Defining the business by what it is not, itemised.
|
|
48
|
-
- **Chatbot residue.** "Certainly! Here's a revised version"
|
|
48
|
+
- **Chatbot residue.** "Certainly! Here's a revised version" (at the start of
|
|
49
|
+
any sentence, not only a line), "as an AI
|
|
49
50
|
language model", "let me know if you'd like me to", ChatGPT citation tokens
|
|
50
51
|
and entity markers, links tracked `utm_source=chatgpt.com`. This is not
|
|
51
52
|
style: it is proof a chat reply was pasted in whole. Remove it, then source
|
|
@@ -90,6 +91,7 @@ person reading decides which instance earns its place.
|
|
|
90
91
|
| `sales-tagline` | advert lines that say nothing a reader can check: "so your budget goes where it counts", "real results", "results that matter", "work harder for you", "pages that convert" |
|
|
91
92
|
| `outcome-promise` | a hoped-for result written as delivered: "we'll turn that into enquiries", "once the first areas are working", "competitors you can outdo", "exactly what convinces", "guaranteed rankings", "you'll get more". Promise the work; measure and report the results |
|
|
92
93
|
| `ai-vocabulary` | tapestry, testament, realm, elevate, nestled, meticulous, unparalleled, moreover; and underscore, showcasing, pivotal, measured 10 to 14 times over-used in post-2022 text |
|
|
94
|
+
| `stock-email-line` | the form-email opener and closer: "I hope this email finds you well", "hope you're having a great week", "let me know if you have any questions", "don't hesitate to contact us". Start with the reason for writing; end with the next step and who to ask |
|
|
93
95
|
| `stock-phrase` | to the next level, one-stop shop, we pride ourselves, passionate about, peace of mind, "so here's", a journey used as a metaphor |
|
|
94
96
|
| `hollow-imperative` | Discover, Experience, Transform, Elevate as the opening verb of a heading or button |
|
|
95
97
|
| `rhetorical-opener` | "Looking for...?", "Tired of...?", "Ready to...?" |
|
package/README.md
CHANGED
|
@@ -364,3 +364,5 @@ widget name no longer proves duplication. A smaller implementation does not
|
|
|
364
364
|
select a better design automatically. Protected staging reviews may reserve
|
|
365
365
|
explicitly marked publication assets while reporting `publicationReady: false`.
|
|
366
366
|
See CHARACTER.md, “Context and learning from a later result”.
|
|
367
|
+
|
|
368
|
+
Opening photographs are selected as a rendered sequence: compare their quality and crop before filling a slide count or covering every service. See [Select photographs for their position in the sequence](./CHARACTER.md#select-photographs-for-their-position-in-the-sequence) for the Bellerose follow-up and its limits.
|
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
snapshotPage,
|
|
10
10
|
snapshotUrl,
|
|
11
11
|
snapshotUrls
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-YFS32BZ2.js";
|
|
13
13
|
import "./chunk-JYNXGCYZ.js";
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-PFVSKIPM.js";
|
|
15
|
+
import "./chunk-FBWBDBW4.js";
|
|
16
16
|
import "./chunk-QYBAVU3P.js";
|
|
17
17
|
export {
|
|
18
18
|
PROVENANCE_BUDGET_MS,
|
package/dist/audit.cjs
CHANGED
|
@@ -693,7 +693,12 @@ var FALSE_RANGE = [
|
|
|
693
693
|
];
|
|
694
694
|
var RESIDUE = [
|
|
695
695
|
/\bas an AI(?:\s+language)?\s+(?:model|assistant)\b/i,
|
|
696
|
-
|
|
696
|
+
// At the start of a line, or after a sentence that ends in a full stop or
|
|
697
|
+
// an exclamation mark: "I hope this email finds you well! Certainly, here
|
|
698
|
+
// is the handover request." slipped through when only a line start counted
|
|
699
|
+
// (found live, 2026-10-19). Not after a question mark: an FAQ answer may
|
|
700
|
+
// honestly open "Do you work weekends? Absolutely, here are our hours."
|
|
701
|
+
/(?<=^|[\n>]|[.!]\s+)\s*(?:Certainly|Sure|Absolutely|Of course|Great question)[!,.]\s+(?:Here(?:['’]s| is| are)|Below)\b/i,
|
|
697
702
|
/\bhere(?:['’]s| is)\s+(?:a|an|the|your)\s+(?:revised|rewritten|updated|polished|refined|improved|draft|more concise)\s+(?:version|draft|copy)\b/i,
|
|
698
703
|
/\blet me know if you(?:['’]d| would) like me to\b/i,
|
|
699
704
|
/\b(?:my|the) (?:knowledge|training) cut-?off\b|\bas of my last (?:update|training)\b/i,
|
|
@@ -709,6 +714,13 @@ var RESIDUE = [
|
|
|
709
714
|
/[\uE200-\uE2FF]*entity[\uE200-\uE2FF]*\["[a-z_]+"\s*,\s*"[^"\n]{1,80}"(?:\s*,\s*"[^"\n]{0,160}")*\][\uE200-\uE2FF]*/,
|
|
710
715
|
/【\d+(?:[:†][^】]{0,40})?】/
|
|
711
716
|
];
|
|
717
|
+
var STOCK_EMAIL = [
|
|
718
|
+
/\bI (?:hope|trust) (?:this|my|the) (?:e-?mail|message|note|letter) finds you(?: all)? (?:well|in good health)\b/i,
|
|
719
|
+
/\bI hope you(?:['’]re| are)(?: all)? (?:doing |keeping )?well\b/i,
|
|
720
|
+
/\b(?:I )?hope you(?:['’]re| are) having an? (?:great|good|lovely|wonderful|fantastic) (?:day|week|weekend)\b/i,
|
|
721
|
+
/\blet (?:me|us) know if you have any (?:further |other |more )?questions\b/i,
|
|
722
|
+
/\b(?:do not|don['’]t) hesitate to (?:contact|reach out|get in touch|ask|call)\b/i
|
|
723
|
+
];
|
|
712
724
|
var AI_UTM = /utm_source=(?:chatgpt\.com|chat\.openai\.com|openai|perplexity(?:\.ai)?|claude\.ai|copilot(?:\.microsoft\.com)?|gemini(?:\.google\.com)?)\b/gi;
|
|
713
725
|
function residueHits(ctx) {
|
|
714
726
|
const hits = phrases(RESIDUE, quoted, allText)(ctx);
|
|
@@ -790,15 +802,39 @@ var RESEARCH_TELLS = [
|
|
|
790
802
|
f("content/home.md", "Prices start at \xA340 :contentReference[oaicite:2]{index=2} for a full set."),
|
|
791
803
|
f("content/home.md", "Prices start at \xA340\u30104\u2020source\u3011 for a full set."),
|
|
792
804
|
f("app/guide.tsx", `export const Guide = () => <a href="https://example.com/guide?utm_source=chatgpt.com">Read the guide</a>;`),
|
|
793
|
-
f("content/home.md", "Here's a more concise version for the hero.")
|
|
805
|
+
f("content/home.md", "Here's a more concise version for the hero."),
|
|
806
|
+
// The client handover email that a clean copy-check let through, 2026-10-19.
|
|
807
|
+
f("emails/handover.md", "Hi,\n\nI hope this email finds you well! Certainly, here is the handover request. Let me know if you have any questions.")
|
|
794
808
|
],
|
|
795
809
|
pass: [
|
|
796
810
|
f("content/home.md", "Certainly the busiest week of the year: book early."),
|
|
811
|
+
f("content/faq.md", "Do you work weekends? Absolutely, here are our hours."),
|
|
797
812
|
f("content/home.md", "Here's the price list for 2026."),
|
|
798
813
|
f("app/guide.tsx", `export const Guide = () => <a href="https://example.com/guide?utm_source=newsletter">Read the guide</a>;`)
|
|
799
814
|
]
|
|
800
815
|
}
|
|
801
816
|
},
|
|
817
|
+
{
|
|
818
|
+
id: "stock-email-line",
|
|
819
|
+
name: "Stock email line",
|
|
820
|
+
generation: 1,
|
|
821
|
+
severity: "warn",
|
|
822
|
+
surface: "copy",
|
|
823
|
+
why: "'I hope this email finds you well', 'let me know if you have any questions', 'don't hesitate to contact us': the opener and closer of a form email. A client reads past them, and a model drafting an email writes them every time.",
|
|
824
|
+
fix: "Cut the opener and start with the reason for writing. Replace the closer with the next step and who to ask: 'Ring me on 07700 900123 if the date does not work.'",
|
|
825
|
+
detect: phrases(STOCK_EMAIL, quoted),
|
|
826
|
+
fixtures: {
|
|
827
|
+
flag: [
|
|
828
|
+
f("emails/handover.md", "Hi,\n\nI hope this email finds you well! Certainly, here is the handover request. Let me know if you have any questions."),
|
|
829
|
+
f("emails/quote.md", "Hope you're having a great week. The quote is attached."),
|
|
830
|
+
f("content/contact.md", "Please don't hesitate to contact us about a rewire.")
|
|
831
|
+
],
|
|
832
|
+
pass: [
|
|
833
|
+
f("emails/handover.md", "Hi Sam,\n\nThe handover pack is attached: certificates, the board schedule and the warranty. Ring me on 07700 900123 if anything is missing."),
|
|
834
|
+
f("content/contact.md", "If you have any questions, ring Jo on 01280 700123.")
|
|
835
|
+
]
|
|
836
|
+
}
|
|
837
|
+
},
|
|
802
838
|
{
|
|
803
839
|
id: "prompt-context",
|
|
804
840
|
name: "Prompt context",
|
|
@@ -3071,6 +3107,8 @@ var HOUSE = {
|
|
|
3071
3107
|
// New 2026-10-14 (founder): review first, like every new tell, until estate hits are read.
|
|
3072
3108
|
"sales-tagline": { tier: "review", label: "sales tagline, say what you will actually do" },
|
|
3073
3109
|
"outcome-promise": { tier: "review", label: "outcome promise, promise the work, not the result" },
|
|
3110
|
+
// New 2026-10-19: review first, like every new tell, until estate hits are read.
|
|
3111
|
+
"stock-email-line": { tier: "review", label: "stock email line, start with the reason for writing and end with the next step" },
|
|
3074
3112
|
"ai-vocabulary": { tier: "review", label: "AI vocabulary" },
|
|
3075
3113
|
"stock-phrase": { tier: "review", label: "stock phrase" },
|
|
3076
3114
|
"hollow-imperative": { tier: "review", label: "hollow imperative" },
|
|
@@ -3812,7 +3850,7 @@ var IMAGERY_TELLS = [
|
|
|
3812
3850
|
];
|
|
3813
3851
|
|
|
3814
3852
|
// src/character/check.ts
|
|
3815
|
-
var CATALOGUE_VERSION = "2026.10.
|
|
3853
|
+
var CATALOGUE_VERSION = "2026.10.3";
|
|
3816
3854
|
var CATALOGUE = [
|
|
3817
3855
|
...[...SOURCE_TELLS, ...COPY_TELLS, ...RESEARCH_TELLS, ...DENSITY_TELLS].map((t) => RENDERED_PATHS[t.id] ? { ...t, rendered: RENDERED_PATHS[t.id] } : t),
|
|
3818
3856
|
...SPECIFICITY_COPY_TELLS,
|
package/dist/audit.js
CHANGED
|
@@ -658,7 +658,12 @@ var FALSE_RANGE = [
|
|
|
658
658
|
];
|
|
659
659
|
var RESIDUE = [
|
|
660
660
|
/\bas an AI(?:\s+language)?\s+(?:model|assistant)\b/i,
|
|
661
|
-
|
|
661
|
+
// At the start of a line, or after a sentence that ends in a full stop or
|
|
662
|
+
// an exclamation mark: "I hope this email finds you well! Certainly, here
|
|
663
|
+
// is the handover request." slipped through when only a line start counted
|
|
664
|
+
// (found live, 2026-10-19). Not after a question mark: an FAQ answer may
|
|
665
|
+
// honestly open "Do you work weekends? Absolutely, here are our hours."
|
|
666
|
+
/(?<=^|[\n>]|[.!]\s+)\s*(?:Certainly|Sure|Absolutely|Of course|Great question)[!,.]\s+(?:Here(?:['’]s| is| are)|Below)\b/i,
|
|
662
667
|
/\bhere(?:['’]s| is)\s+(?:a|an|the|your)\s+(?:revised|rewritten|updated|polished|refined|improved|draft|more concise)\s+(?:version|draft|copy)\b/i,
|
|
663
668
|
/\blet me know if you(?:['’]d| would) like me to\b/i,
|
|
664
669
|
/\b(?:my|the) (?:knowledge|training) cut-?off\b|\bas of my last (?:update|training)\b/i,
|
|
@@ -674,6 +679,13 @@ var RESIDUE = [
|
|
|
674
679
|
/[\uE200-\uE2FF]*entity[\uE200-\uE2FF]*\["[a-z_]+"\s*,\s*"[^"\n]{1,80}"(?:\s*,\s*"[^"\n]{0,160}")*\][\uE200-\uE2FF]*/,
|
|
675
680
|
/【\d+(?:[:†][^】]{0,40})?】/
|
|
676
681
|
];
|
|
682
|
+
var STOCK_EMAIL = [
|
|
683
|
+
/\bI (?:hope|trust) (?:this|my|the) (?:e-?mail|message|note|letter) finds you(?: all)? (?:well|in good health)\b/i,
|
|
684
|
+
/\bI hope you(?:['’]re| are)(?: all)? (?:doing |keeping )?well\b/i,
|
|
685
|
+
/\b(?:I )?hope you(?:['’]re| are) having an? (?:great|good|lovely|wonderful|fantastic) (?:day|week|weekend)\b/i,
|
|
686
|
+
/\blet (?:me|us) know if you have any (?:further |other |more )?questions\b/i,
|
|
687
|
+
/\b(?:do not|don['’]t) hesitate to (?:contact|reach out|get in touch|ask|call)\b/i
|
|
688
|
+
];
|
|
677
689
|
var AI_UTM = /utm_source=(?:chatgpt\.com|chat\.openai\.com|openai|perplexity(?:\.ai)?|claude\.ai|copilot(?:\.microsoft\.com)?|gemini(?:\.google\.com)?)\b/gi;
|
|
678
690
|
function residueHits(ctx) {
|
|
679
691
|
const hits = phrases(RESIDUE, quoted, allText)(ctx);
|
|
@@ -755,15 +767,39 @@ var RESEARCH_TELLS = [
|
|
|
755
767
|
f("content/home.md", "Prices start at \xA340 :contentReference[oaicite:2]{index=2} for a full set."),
|
|
756
768
|
f("content/home.md", "Prices start at \xA340\u30104\u2020source\u3011 for a full set."),
|
|
757
769
|
f("app/guide.tsx", `export const Guide = () => <a href="https://example.com/guide?utm_source=chatgpt.com">Read the guide</a>;`),
|
|
758
|
-
f("content/home.md", "Here's a more concise version for the hero.")
|
|
770
|
+
f("content/home.md", "Here's a more concise version for the hero."),
|
|
771
|
+
// The client handover email that a clean copy-check let through, 2026-10-19.
|
|
772
|
+
f("emails/handover.md", "Hi,\n\nI hope this email finds you well! Certainly, here is the handover request. Let me know if you have any questions.")
|
|
759
773
|
],
|
|
760
774
|
pass: [
|
|
761
775
|
f("content/home.md", "Certainly the busiest week of the year: book early."),
|
|
776
|
+
f("content/faq.md", "Do you work weekends? Absolutely, here are our hours."),
|
|
762
777
|
f("content/home.md", "Here's the price list for 2026."),
|
|
763
778
|
f("app/guide.tsx", `export const Guide = () => <a href="https://example.com/guide?utm_source=newsletter">Read the guide</a>;`)
|
|
764
779
|
]
|
|
765
780
|
}
|
|
766
781
|
},
|
|
782
|
+
{
|
|
783
|
+
id: "stock-email-line",
|
|
784
|
+
name: "Stock email line",
|
|
785
|
+
generation: 1,
|
|
786
|
+
severity: "warn",
|
|
787
|
+
surface: "copy",
|
|
788
|
+
why: "'I hope this email finds you well', 'let me know if you have any questions', 'don't hesitate to contact us': the opener and closer of a form email. A client reads past them, and a model drafting an email writes them every time.",
|
|
789
|
+
fix: "Cut the opener and start with the reason for writing. Replace the closer with the next step and who to ask: 'Ring me on 07700 900123 if the date does not work.'",
|
|
790
|
+
detect: phrases(STOCK_EMAIL, quoted),
|
|
791
|
+
fixtures: {
|
|
792
|
+
flag: [
|
|
793
|
+
f("emails/handover.md", "Hi,\n\nI hope this email finds you well! Certainly, here is the handover request. Let me know if you have any questions."),
|
|
794
|
+
f("emails/quote.md", "Hope you're having a great week. The quote is attached."),
|
|
795
|
+
f("content/contact.md", "Please don't hesitate to contact us about a rewire.")
|
|
796
|
+
],
|
|
797
|
+
pass: [
|
|
798
|
+
f("emails/handover.md", "Hi Sam,\n\nThe handover pack is attached: certificates, the board schedule and the warranty. Ring me on 07700 900123 if anything is missing."),
|
|
799
|
+
f("content/contact.md", "If you have any questions, ring Jo on 01280 700123.")
|
|
800
|
+
]
|
|
801
|
+
}
|
|
802
|
+
},
|
|
767
803
|
{
|
|
768
804
|
id: "prompt-context",
|
|
769
805
|
name: "Prompt context",
|
|
@@ -3036,6 +3072,8 @@ var HOUSE = {
|
|
|
3036
3072
|
// New 2026-10-14 (founder): review first, like every new tell, until estate hits are read.
|
|
3037
3073
|
"sales-tagline": { tier: "review", label: "sales tagline, say what you will actually do" },
|
|
3038
3074
|
"outcome-promise": { tier: "review", label: "outcome promise, promise the work, not the result" },
|
|
3075
|
+
// New 2026-10-19: review first, like every new tell, until estate hits are read.
|
|
3076
|
+
"stock-email-line": { tier: "review", label: "stock email line, start with the reason for writing and end with the next step" },
|
|
3039
3077
|
"ai-vocabulary": { tier: "review", label: "AI vocabulary" },
|
|
3040
3078
|
"stock-phrase": { tier: "review", label: "stock phrase" },
|
|
3041
3079
|
"hollow-imperative": { tier: "review", label: "hollow imperative" },
|
|
@@ -3777,7 +3815,7 @@ var IMAGERY_TELLS = [
|
|
|
3777
3815
|
];
|
|
3778
3816
|
|
|
3779
3817
|
// src/character/check.ts
|
|
3780
|
-
var CATALOGUE_VERSION = "2026.10.
|
|
3818
|
+
var CATALOGUE_VERSION = "2026.10.3";
|
|
3781
3819
|
var CATALOGUE = [
|
|
3782
3820
|
...[...SOURCE_TELLS, ...COPY_TELLS, ...RESEARCH_TELLS, ...DENSITY_TELLS].map((t) => RENDERED_PATHS[t.id] ? { ...t, rendered: RENDERED_PATHS[t.id] } : t),
|
|
3783
3821
|
...SPECIFICITY_COPY_TELLS,
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-OQXTQQAU.js";
|
|
4
4
|
import {
|
|
5
5
|
parseFlags
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-TSO5W32N.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-
|
|
25
|
+
} from "./chunk-PFVSKIPM.js";
|
|
26
26
|
import {
|
|
27
27
|
extractStrings
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-FBWBDBW4.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-
|
|
123
|
+
const { snapshotUrls } = await import("./audit-5I2WWTL6.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-
|
|
244
|
+
const { snapshotUrls } = await import("./audit-5I2WWTL6.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));
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
snapshotUrl,
|
|
3
3
|
snapshotUrls
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-YFS32BZ2.js";
|
|
5
5
|
import {
|
|
6
6
|
describeTypicality,
|
|
7
7
|
loadNull
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-BBJOLR3R.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-
|
|
17
|
+
} from "./chunk-TSO5W32N.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-
|
|
31
|
+
} from "./chunk-PFVSKIPM.js";
|
|
32
32
|
|
|
33
33
|
// src/audit/cli.ts
|
|
34
34
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -1081,7 +1081,12 @@ var FALSE_RANGE = [
|
|
|
1081
1081
|
];
|
|
1082
1082
|
var RESIDUE = [
|
|
1083
1083
|
/\bas an AI(?:\s+language)?\s+(?:model|assistant)\b/i,
|
|
1084
|
-
|
|
1084
|
+
// At the start of a line, or after a sentence that ends in a full stop or
|
|
1085
|
+
// an exclamation mark: "I hope this email finds you well! Certainly, here
|
|
1086
|
+
// is the handover request." slipped through when only a line start counted
|
|
1087
|
+
// (found live, 2026-10-19). Not after a question mark: an FAQ answer may
|
|
1088
|
+
// honestly open "Do you work weekends? Absolutely, here are our hours."
|
|
1089
|
+
/(?<=^|[\n>]|[.!]\s+)\s*(?:Certainly|Sure|Absolutely|Of course|Great question)[!,.]\s+(?:Here(?:['’]s| is| are)|Below)\b/i,
|
|
1085
1090
|
/\bhere(?:['’]s| is)\s+(?:a|an|the|your)\s+(?:revised|rewritten|updated|polished|refined|improved|draft|more concise)\s+(?:version|draft|copy)\b/i,
|
|
1086
1091
|
/\blet me know if you(?:['’]d| would) like me to\b/i,
|
|
1087
1092
|
/\b(?:my|the) (?:knowledge|training) cut-?off\b|\bas of my last (?:update|training)\b/i,
|
|
@@ -1097,6 +1102,13 @@ var RESIDUE = [
|
|
|
1097
1102
|
/[\uE200-\uE2FF]*entity[\uE200-\uE2FF]*\["[a-z_]+"\s*,\s*"[^"\n]{1,80}"(?:\s*,\s*"[^"\n]{0,160}")*\][\uE200-\uE2FF]*/,
|
|
1098
1103
|
/【\d+(?:[:†][^】]{0,40})?】/
|
|
1099
1104
|
];
|
|
1105
|
+
var STOCK_EMAIL = [
|
|
1106
|
+
/\bI (?:hope|trust) (?:this|my|the) (?:e-?mail|message|note|letter) finds you(?: all)? (?:well|in good health)\b/i,
|
|
1107
|
+
/\bI hope you(?:['’]re| are)(?: all)? (?:doing |keeping )?well\b/i,
|
|
1108
|
+
/\b(?:I )?hope you(?:['’]re| are) having an? (?:great|good|lovely|wonderful|fantastic) (?:day|week|weekend)\b/i,
|
|
1109
|
+
/\blet (?:me|us) know if you have any (?:further |other |more )?questions\b/i,
|
|
1110
|
+
/\b(?:do not|don['’]t) hesitate to (?:contact|reach out|get in touch|ask|call)\b/i
|
|
1111
|
+
];
|
|
1100
1112
|
var AI_UTM = /utm_source=(?:chatgpt\.com|chat\.openai\.com|openai|perplexity(?:\.ai)?|claude\.ai|copilot(?:\.microsoft\.com)?|gemini(?:\.google\.com)?)\b/gi;
|
|
1101
1113
|
function residueHits(ctx) {
|
|
1102
1114
|
const hits = phrases(RESIDUE, quoted, allText)(ctx);
|
|
@@ -1178,15 +1190,39 @@ var RESEARCH_TELLS = [
|
|
|
1178
1190
|
f("content/home.md", "Prices start at \xA340 :contentReference[oaicite:2]{index=2} for a full set."),
|
|
1179
1191
|
f("content/home.md", "Prices start at \xA340\u30104\u2020source\u3011 for a full set."),
|
|
1180
1192
|
f("app/guide.tsx", `export const Guide = () => <a href="https://example.com/guide?utm_source=chatgpt.com">Read the guide</a>;`),
|
|
1181
|
-
f("content/home.md", "Here's a more concise version for the hero.")
|
|
1193
|
+
f("content/home.md", "Here's a more concise version for the hero."),
|
|
1194
|
+
// The client handover email that a clean copy-check let through, 2026-10-19.
|
|
1195
|
+
f("emails/handover.md", "Hi,\n\nI hope this email finds you well! Certainly, here is the handover request. Let me know if you have any questions.")
|
|
1182
1196
|
],
|
|
1183
1197
|
pass: [
|
|
1184
1198
|
f("content/home.md", "Certainly the busiest week of the year: book early."),
|
|
1199
|
+
f("content/faq.md", "Do you work weekends? Absolutely, here are our hours."),
|
|
1185
1200
|
f("content/home.md", "Here's the price list for 2026."),
|
|
1186
1201
|
f("app/guide.tsx", `export const Guide = () => <a href="https://example.com/guide?utm_source=newsletter">Read the guide</a>;`)
|
|
1187
1202
|
]
|
|
1188
1203
|
}
|
|
1189
1204
|
},
|
|
1205
|
+
{
|
|
1206
|
+
id: "stock-email-line",
|
|
1207
|
+
name: "Stock email line",
|
|
1208
|
+
generation: 1,
|
|
1209
|
+
severity: "warn",
|
|
1210
|
+
surface: "copy",
|
|
1211
|
+
why: "'I hope this email finds you well', 'let me know if you have any questions', 'don't hesitate to contact us': the opener and closer of a form email. A client reads past them, and a model drafting an email writes them every time.",
|
|
1212
|
+
fix: "Cut the opener and start with the reason for writing. Replace the closer with the next step and who to ask: 'Ring me on 07700 900123 if the date does not work.'",
|
|
1213
|
+
detect: phrases(STOCK_EMAIL, quoted),
|
|
1214
|
+
fixtures: {
|
|
1215
|
+
flag: [
|
|
1216
|
+
f("emails/handover.md", "Hi,\n\nI hope this email finds you well! Certainly, here is the handover request. Let me know if you have any questions."),
|
|
1217
|
+
f("emails/quote.md", "Hope you're having a great week. The quote is attached."),
|
|
1218
|
+
f("content/contact.md", "Please don't hesitate to contact us about a rewire.")
|
|
1219
|
+
],
|
|
1220
|
+
pass: [
|
|
1221
|
+
f("emails/handover.md", "Hi Sam,\n\nThe handover pack is attached: certificates, the board schedule and the warranty. Ring me on 07700 900123 if anything is missing."),
|
|
1222
|
+
f("content/contact.md", "If you have any questions, ring Jo on 01280 700123.")
|
|
1223
|
+
]
|
|
1224
|
+
}
|
|
1225
|
+
},
|
|
1190
1226
|
{
|
|
1191
1227
|
id: "prompt-context",
|
|
1192
1228
|
name: "Prompt context",
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
levenshtein,
|
|
11
11
|
normaliseFamily,
|
|
12
12
|
parseColour
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-PFVSKIPM.js";
|
|
14
14
|
import {
|
|
15
15
|
TRADE_NOUNS
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-FBWBDBW4.js";
|
|
17
17
|
|
|
18
18
|
// src/direction/types.ts
|
|
19
19
|
var DIRECTION_VERSION = 2;
|
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
formatDirectionMatches,
|
|
5
5
|
summariseDirection,
|
|
6
6
|
validateDirection
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-GJY2VMPD.js";
|
|
8
8
|
import {
|
|
9
9
|
loadNull
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-BBJOLR3R.js";
|
|
11
11
|
import {
|
|
12
12
|
parseFlags
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-TSO5W32N.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-
|
|
33
|
+
} from "./chunk-PFVSKIPM.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-
|
|
136
|
+
const { snapshotUrl } = await import("./audit-5I2WWTL6.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(", ")}` : ""}`;
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
parseFile,
|
|
10
10
|
sentencesOf,
|
|
11
11
|
specificity
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-FBWBDBW4.js";
|
|
13
13
|
import {
|
|
14
14
|
SNAPSHOT_VERSION
|
|
15
15
|
} from "./chunk-QYBAVU3P.js";
|
|
@@ -2428,6 +2428,8 @@ var HOUSE = {
|
|
|
2428
2428
|
// New 2026-10-14 (founder): review first, like every new tell, until estate hits are read.
|
|
2429
2429
|
"sales-tagline": { tier: "review", label: "sales tagline, say what you will actually do" },
|
|
2430
2430
|
"outcome-promise": { tier: "review", label: "outcome promise, promise the work, not the result" },
|
|
2431
|
+
// New 2026-10-19: review first, like every new tell, until estate hits are read.
|
|
2432
|
+
"stock-email-line": { tier: "review", label: "stock email line, start with the reason for writing and end with the next step" },
|
|
2431
2433
|
"ai-vocabulary": { tier: "review", label: "AI vocabulary" },
|
|
2432
2434
|
"stock-phrase": { tier: "review", label: "stock phrase" },
|
|
2433
2435
|
"hollow-imperative": { tier: "review", label: "hollow imperative" },
|
|
@@ -3023,7 +3025,7 @@ var IMAGERY_TELLS = [
|
|
|
3023
3025
|
];
|
|
3024
3026
|
|
|
3025
3027
|
// src/character/check.ts
|
|
3026
|
-
var CATALOGUE_VERSION = "2026.10.
|
|
3028
|
+
var CATALOGUE_VERSION = "2026.10.3";
|
|
3027
3029
|
var CATALOGUE = [
|
|
3028
3030
|
...[...SOURCE_TELLS, ...COPY_TELLS, ...RESEARCH_TELLS, ...DENSITY_TELLS].map((t) => RENDERED_PATHS[t.id] ? { ...t, rendered: RENDERED_PATHS[t.id] } : t),
|
|
3029
3031
|
...SPECIFICITY_COPY_TELLS,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
holdHouseBlocks,
|
|
11
11
|
houseRule,
|
|
12
12
|
scanSource
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-PFVSKIPM.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-
|
|
24
|
+
} from "./chunk-FBWBDBW4.js";
|
|
25
25
|
|
|
26
26
|
// src/character/config.ts
|
|
27
27
|
var DEFAULT_IGNORE = [".claude", ".agents", ".cursor"];
|
|
@@ -622,7 +622,7 @@ async function pageSnapshot(target, cwd) {
|
|
|
622
622
|
return readSnapshot(JSON.parse(readFileSync(local, "utf8")), target);
|
|
623
623
|
}
|
|
624
624
|
if (!/^https?:\/\//.test(target)) throw new Error(`${target} is neither a URL nor a snapshot file`);
|
|
625
|
-
const { snapshotUrl } = await import("./audit-
|
|
625
|
+
const { snapshotUrl } = await import("./audit-5I2WWTL6.js");
|
|
626
626
|
return snapshotUrl(target);
|
|
627
627
|
}
|
|
628
628
|
async function briefFor(flags, cwd) {
|
|
@@ -633,7 +633,7 @@ async function briefFor(flags, cwd) {
|
|
|
633
633
|
if (typeof brief === "string" && brief.trim()) return brief;
|
|
634
634
|
} else if (flags.direction) throw new Error(`no such file: ${flags.direction}`);
|
|
635
635
|
if (flags.null) {
|
|
636
|
-
const { loadNull } = await import("./cli-
|
|
636
|
+
const { loadNull } = await import("./cli-V4QXTBWR.js");
|
|
637
637
|
return loadNull(flags.null, cwd).brief;
|
|
638
638
|
}
|
|
639
639
|
return void 0;
|
|
@@ -659,37 +659,37 @@ async function compareWithCompetitor(flags, io) {
|
|
|
659
659
|
function run(argv, io) {
|
|
660
660
|
const [command, ...rest] = argv;
|
|
661
661
|
if (command === "direction") {
|
|
662
|
-
return import("./cli-
|
|
662
|
+
return import("./cli-JQYZXFRH.js").then((m) => m.runDirection(rest, io));
|
|
663
663
|
}
|
|
664
664
|
if (command === "report" || command === "retrofit") {
|
|
665
|
-
return import("./cli-
|
|
665
|
+
return import("./cli-W6FNSHRN.js").then((m) => m.runReport(command, rest, io));
|
|
666
666
|
}
|
|
667
667
|
if (command === "register") {
|
|
668
|
-
return import("./cli-
|
|
668
|
+
return import("./cli-NIH3WTNE.js").then((m) => m.runRegister(rest, io));
|
|
669
669
|
}
|
|
670
670
|
if (command === "estate") {
|
|
671
|
-
return import("./cli-
|
|
671
|
+
return import("./cli-SQC27VYC.js").then((m) => m.runEstate(rest, io));
|
|
672
672
|
}
|
|
673
673
|
if (command === "null") {
|
|
674
|
-
return import("./cli-
|
|
674
|
+
return import("./cli-V4QXTBWR.js").then((m) => m.runNull(rest, io));
|
|
675
675
|
}
|
|
676
676
|
if (command === "calibrate") {
|
|
677
|
-
return import("./cli-
|
|
677
|
+
return import("./cli-BI6XCMCL.js").then((m) => m.runCalibrate(rest, io));
|
|
678
678
|
}
|
|
679
679
|
if (command === "tells" && rest[0] === "harvest") {
|
|
680
|
-
return import("./cli-
|
|
680
|
+
return import("./cli-V4QXTBWR.js").then((m) => m.runHarvest(rest, io)).catch((error) => {
|
|
681
681
|
io.err(`craft: ${error.message}`);
|
|
682
682
|
return 2;
|
|
683
683
|
});
|
|
684
684
|
}
|
|
685
685
|
if (command === "phone-first") {
|
|
686
|
-
return import("./cli-
|
|
686
|
+
return import("./cli-56H5IPWT.js").then((m) => m.runPhoneFirst(rest, io));
|
|
687
687
|
}
|
|
688
688
|
if (command === "viewports") {
|
|
689
|
-
return import("./viewports-cli-
|
|
689
|
+
return import("./viewports-cli-C4DWICYI.js").then((m) => m.runViewports(rest, io));
|
|
690
690
|
}
|
|
691
691
|
if (command === "snapshot" || command === "audit") {
|
|
692
|
-
return import("./cli-
|
|
692
|
+
return import("./cli-OH6427MC.js").then((m) => m.runAudit(command, rest, io));
|
|
693
693
|
}
|
|
694
694
|
if (!command || command === "help" || command === "--help" || command === "-h") {
|
|
695
695
|
io.out(HELP);
|
|
@@ -9,12 +9,12 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
SOURCE_FILE,
|
|
11
11
|
readPaths
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-TSO5W32N.js";
|
|
13
13
|
import {
|
|
14
14
|
toJson
|
|
15
15
|
} from "./chunk-QIEDBL4J.js";
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-PFVSKIPM.js";
|
|
17
|
+
import "./chunk-FBWBDBW4.js";
|
|
18
18
|
import "./chunk-QYBAVU3P.js";
|
|
19
19
|
|
|
20
20
|
// src/phone/cli.ts
|
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
expandNullTargets,
|
|
6
6
|
loadNull
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-BBJOLR3R.js";
|
|
8
8
|
import "./chunk-OQXTQQAU.js";
|
|
9
9
|
import {
|
|
10
10
|
parseFlags
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-TSO5W32N.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-
|
|
25
|
-
import "./chunk-
|
|
24
|
+
} from "./chunk-PFVSKIPM.js";
|
|
25
|
+
import "./chunk-FBWBDBW4.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-
|
|
191
|
+
const { snapshotUrls } = await import("./audit-5I2WWTL6.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];
|
|
@@ -19,10 +19,10 @@ import {
|
|
|
19
19
|
checkReason,
|
|
20
20
|
researchPrompt,
|
|
21
21
|
validateDirection
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-GJY2VMPD.js";
|
|
23
23
|
import {
|
|
24
24
|
parseFlags
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-TSO5W32N.js";
|
|
26
26
|
import {
|
|
27
27
|
toJson
|
|
28
28
|
} from "./chunk-QIEDBL4J.js";
|
|
@@ -38,8 +38,8 @@ import {
|
|
|
38
38
|
isCream,
|
|
39
39
|
oklchToRgb,
|
|
40
40
|
parseColour
|
|
41
|
-
} from "./chunk-
|
|
42
|
-
import "./chunk-
|
|
41
|
+
} from "./chunk-PFVSKIPM.js";
|
|
42
|
+
import "./chunk-FBWBDBW4.js";
|
|
43
43
|
import "./chunk-QYBAVU3P.js";
|
|
44
44
|
|
|
45
45
|
// src/direction/cli.ts
|
|
@@ -484,7 +484,7 @@ var readJson = (path) => JSON.parse(readFileSync(path, "utf8"));
|
|
|
484
484
|
async function snapshotFrom(target, cwd) {
|
|
485
485
|
if (!target) return void 0;
|
|
486
486
|
if (/^https?:\/\//.test(target)) {
|
|
487
|
-
const { snapshotUrl } = await import("./audit-
|
|
487
|
+
const { snapshotUrl } = await import("./audit-5I2WWTL6.js");
|
|
488
488
|
return snapshotUrl(target);
|
|
489
489
|
}
|
|
490
490
|
return readSnapshot(readJson(resolve(cwd, target)), target);
|
|
@@ -4,16 +4,16 @@ import {
|
|
|
4
4
|
merge,
|
|
5
5
|
resolvePages,
|
|
6
6
|
runAudit
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-DMAMGFV7.js";
|
|
8
|
+
import "./chunk-YFS32BZ2.js";
|
|
9
9
|
import "./chunk-JYNXGCYZ.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-BBJOLR3R.js";
|
|
11
11
|
import "./chunk-OQXTQQAU.js";
|
|
12
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-TSO5W32N.js";
|
|
13
13
|
import "./chunk-QIEDBL4J.js";
|
|
14
14
|
import "./chunk-WUACK2HX.js";
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
15
|
+
import "./chunk-PFVSKIPM.js";
|
|
16
|
+
import "./chunk-FBWBDBW4.js";
|
|
17
17
|
import "./chunk-QYBAVU3P.js";
|
|
18
18
|
export {
|
|
19
19
|
describeComponents,
|
|
@@ -4,15 +4,15 @@ import {
|
|
|
4
4
|
formatPairs,
|
|
5
5
|
loadEstate,
|
|
6
6
|
runEstate
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-N32UUN3S.js";
|
|
8
|
+
import "./chunk-GJY2VMPD.js";
|
|
9
|
+
import "./chunk-BBJOLR3R.js";
|
|
10
10
|
import "./chunk-OQXTQQAU.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-TSO5W32N.js";
|
|
12
12
|
import "./chunk-QIEDBL4J.js";
|
|
13
13
|
import "./chunk-WUACK2HX.js";
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-PFVSKIPM.js";
|
|
15
|
+
import "./chunk-FBWBDBW4.js";
|
|
16
16
|
import "./chunk-QYBAVU3P.js";
|
|
17
17
|
export {
|
|
18
18
|
formatComponentPairs,
|
|
@@ -9,13 +9,13 @@ import {
|
|
|
9
9
|
runHarvest,
|
|
10
10
|
runNull,
|
|
11
11
|
serveDir
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-BBJOLR3R.js";
|
|
13
13
|
import "./chunk-OQXTQQAU.js";
|
|
14
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-TSO5W32N.js";
|
|
15
15
|
import "./chunk-QIEDBL4J.js";
|
|
16
16
|
import "./chunk-WUACK2HX.js";
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-PFVSKIPM.js";
|
|
18
|
+
import "./chunk-FBWBDBW4.js";
|
|
19
19
|
import "./chunk-QYBAVU3P.js";
|
|
20
20
|
export {
|
|
21
21
|
describeTypicality,
|
|
@@ -3,21 +3,21 @@ import {
|
|
|
3
3
|
} from "./chunk-OKVHWXYV.js";
|
|
4
4
|
import {
|
|
5
5
|
merge
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-DMAMGFV7.js";
|
|
7
|
+
import "./chunk-YFS32BZ2.js";
|
|
8
8
|
import "./chunk-JYNXGCYZ.js";
|
|
9
9
|
import {
|
|
10
10
|
SIBLING_AT,
|
|
11
11
|
compareToEstate,
|
|
12
12
|
loadEstate
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-N32UUN3S.js";
|
|
14
14
|
import {
|
|
15
15
|
PAGE_TYPES,
|
|
16
16
|
validateDirection
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-GJY2VMPD.js";
|
|
18
18
|
import {
|
|
19
19
|
loadNull
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-BBJOLR3R.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-
|
|
31
|
+
} from "./chunk-TSO5W32N.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-
|
|
46
|
-
import "./chunk-
|
|
45
|
+
} from "./chunk-PFVSKIPM.js";
|
|
46
|
+
import "./chunk-FBWBDBW4.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-
|
|
129
|
+
const { snapshotUrl } = await import("./audit-5I2WWTL6.js");
|
|
130
130
|
snap = await snapshotUrl(target2);
|
|
131
131
|
}
|
|
132
132
|
const fp = fingerprint(snap);
|
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
run
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-TSO5W32N.js";
|
|
5
5
|
import "./chunk-QIEDBL4J.js";
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-PFVSKIPM.js";
|
|
7
|
+
import "./chunk-FBWBDBW4.js";
|
|
8
8
|
import "./chunk-QYBAVU3P.js";
|
|
9
9
|
|
|
10
10
|
// src/cli.ts
|
package/dist/index.cjs
CHANGED
|
@@ -2494,7 +2494,12 @@ var FALSE_RANGE = [
|
|
|
2494
2494
|
];
|
|
2495
2495
|
var RESIDUE = [
|
|
2496
2496
|
/\bas an AI(?:\s+language)?\s+(?:model|assistant)\b/i,
|
|
2497
|
-
|
|
2497
|
+
// At the start of a line, or after a sentence that ends in a full stop or
|
|
2498
|
+
// an exclamation mark: "I hope this email finds you well! Certainly, here
|
|
2499
|
+
// is the handover request." slipped through when only a line start counted
|
|
2500
|
+
// (found live, 2026-10-19). Not after a question mark: an FAQ answer may
|
|
2501
|
+
// honestly open "Do you work weekends? Absolutely, here are our hours."
|
|
2502
|
+
/(?<=^|[\n>]|[.!]\s+)\s*(?:Certainly|Sure|Absolutely|Of course|Great question)[!,.]\s+(?:Here(?:['’]s| is| are)|Below)\b/i,
|
|
2498
2503
|
/\bhere(?:['’]s| is)\s+(?:a|an|the|your)\s+(?:revised|rewritten|updated|polished|refined|improved|draft|more concise)\s+(?:version|draft|copy)\b/i,
|
|
2499
2504
|
/\blet me know if you(?:['’]d| would) like me to\b/i,
|
|
2500
2505
|
/\b(?:my|the) (?:knowledge|training) cut-?off\b|\bas of my last (?:update|training)\b/i,
|
|
@@ -2510,6 +2515,13 @@ var RESIDUE = [
|
|
|
2510
2515
|
/[\uE200-\uE2FF]*entity[\uE200-\uE2FF]*\["[a-z_]+"\s*,\s*"[^"\n]{1,80}"(?:\s*,\s*"[^"\n]{0,160}")*\][\uE200-\uE2FF]*/,
|
|
2511
2516
|
/【\d+(?:[:†][^】]{0,40})?】/
|
|
2512
2517
|
];
|
|
2518
|
+
var STOCK_EMAIL = [
|
|
2519
|
+
/\bI (?:hope|trust) (?:this|my|the) (?:e-?mail|message|note|letter) finds you(?: all)? (?:well|in good health)\b/i,
|
|
2520
|
+
/\bI hope you(?:['’]re| are)(?: all)? (?:doing |keeping )?well\b/i,
|
|
2521
|
+
/\b(?:I )?hope you(?:['’]re| are) having an? (?:great|good|lovely|wonderful|fantastic) (?:day|week|weekend)\b/i,
|
|
2522
|
+
/\blet (?:me|us) know if you have any (?:further |other |more )?questions\b/i,
|
|
2523
|
+
/\b(?:do not|don['’]t) hesitate to (?:contact|reach out|get in touch|ask|call)\b/i
|
|
2524
|
+
];
|
|
2513
2525
|
var AI_UTM = /utm_source=(?:chatgpt\.com|chat\.openai\.com|openai|perplexity(?:\.ai)?|claude\.ai|copilot(?:\.microsoft\.com)?|gemini(?:\.google\.com)?)\b/gi;
|
|
2514
2526
|
function residueHits(ctx) {
|
|
2515
2527
|
const hits = phrases(RESIDUE, quoted, allText)(ctx);
|
|
@@ -2591,15 +2603,39 @@ var RESEARCH_TELLS = [
|
|
|
2591
2603
|
f("content/home.md", "Prices start at \xA340 :contentReference[oaicite:2]{index=2} for a full set."),
|
|
2592
2604
|
f("content/home.md", "Prices start at \xA340\u30104\u2020source\u3011 for a full set."),
|
|
2593
2605
|
f("app/guide.tsx", `export const Guide = () => <a href="https://example.com/guide?utm_source=chatgpt.com">Read the guide</a>;`),
|
|
2594
|
-
f("content/home.md", "Here's a more concise version for the hero.")
|
|
2606
|
+
f("content/home.md", "Here's a more concise version for the hero."),
|
|
2607
|
+
// The client handover email that a clean copy-check let through, 2026-10-19.
|
|
2608
|
+
f("emails/handover.md", "Hi,\n\nI hope this email finds you well! Certainly, here is the handover request. Let me know if you have any questions.")
|
|
2595
2609
|
],
|
|
2596
2610
|
pass: [
|
|
2597
2611
|
f("content/home.md", "Certainly the busiest week of the year: book early."),
|
|
2612
|
+
f("content/faq.md", "Do you work weekends? Absolutely, here are our hours."),
|
|
2598
2613
|
f("content/home.md", "Here's the price list for 2026."),
|
|
2599
2614
|
f("app/guide.tsx", `export const Guide = () => <a href="https://example.com/guide?utm_source=newsletter">Read the guide</a>;`)
|
|
2600
2615
|
]
|
|
2601
2616
|
}
|
|
2602
2617
|
},
|
|
2618
|
+
{
|
|
2619
|
+
id: "stock-email-line",
|
|
2620
|
+
name: "Stock email line",
|
|
2621
|
+
generation: 1,
|
|
2622
|
+
severity: "warn",
|
|
2623
|
+
surface: "copy",
|
|
2624
|
+
why: "'I hope this email finds you well', 'let me know if you have any questions', 'don't hesitate to contact us': the opener and closer of a form email. A client reads past them, and a model drafting an email writes them every time.",
|
|
2625
|
+
fix: "Cut the opener and start with the reason for writing. Replace the closer with the next step and who to ask: 'Ring me on 07700 900123 if the date does not work.'",
|
|
2626
|
+
detect: phrases(STOCK_EMAIL, quoted),
|
|
2627
|
+
fixtures: {
|
|
2628
|
+
flag: [
|
|
2629
|
+
f("emails/handover.md", "Hi,\n\nI hope this email finds you well! Certainly, here is the handover request. Let me know if you have any questions."),
|
|
2630
|
+
f("emails/quote.md", "Hope you're having a great week. The quote is attached."),
|
|
2631
|
+
f("content/contact.md", "Please don't hesitate to contact us about a rewire.")
|
|
2632
|
+
],
|
|
2633
|
+
pass: [
|
|
2634
|
+
f("emails/handover.md", "Hi Sam,\n\nThe handover pack is attached: certificates, the board schedule and the warranty. Ring me on 07700 900123 if anything is missing."),
|
|
2635
|
+
f("content/contact.md", "If you have any questions, ring Jo on 01280 700123.")
|
|
2636
|
+
]
|
|
2637
|
+
}
|
|
2638
|
+
},
|
|
2603
2639
|
{
|
|
2604
2640
|
id: "prompt-context",
|
|
2605
2641
|
name: "Prompt context",
|
|
@@ -5209,6 +5245,8 @@ var HOUSE = {
|
|
|
5209
5245
|
// New 2026-10-14 (founder): review first, like every new tell, until estate hits are read.
|
|
5210
5246
|
"sales-tagline": { tier: "review", label: "sales tagline, say what you will actually do" },
|
|
5211
5247
|
"outcome-promise": { tier: "review", label: "outcome promise, promise the work, not the result" },
|
|
5248
|
+
// New 2026-10-19: review first, like every new tell, until estate hits are read.
|
|
5249
|
+
"stock-email-line": { tier: "review", label: "stock email line, start with the reason for writing and end with the next step" },
|
|
5212
5250
|
"ai-vocabulary": { tier: "review", label: "AI vocabulary" },
|
|
5213
5251
|
"stock-phrase": { tier: "review", label: "stock phrase" },
|
|
5214
5252
|
"hollow-imperative": { tier: "review", label: "hollow imperative" },
|
|
@@ -6414,7 +6452,7 @@ var IMAGERY_TELLS = [
|
|
|
6414
6452
|
];
|
|
6415
6453
|
|
|
6416
6454
|
// src/character/check.ts
|
|
6417
|
-
var CATALOGUE_VERSION = "2026.10.
|
|
6455
|
+
var CATALOGUE_VERSION = "2026.10.3";
|
|
6418
6456
|
var CATALOGUE = [
|
|
6419
6457
|
...[...SOURCE_TELLS, ...COPY_TELLS, ...RESEARCH_TELLS, ...DENSITY_TELLS].map((t) => RENDERED_PATHS[t.id] ? { ...t, rendered: RENDERED_PATHS[t.id] } : t),
|
|
6420
6458
|
...SPECIFICITY_COPY_TELLS,
|
package/dist/index.d.cts
CHANGED
|
@@ -1252,7 +1252,7 @@ interface CheckReport {
|
|
|
1252
1252
|
* Bumped whenever an entry is added, removed or its detection changes, so a
|
|
1253
1253
|
* report can say which list it was judged against.
|
|
1254
1254
|
*/
|
|
1255
|
-
declare const CATALOGUE_VERSION = "2026.10.
|
|
1255
|
+
declare const CATALOGUE_VERSION = "2026.10.3";
|
|
1256
1256
|
declare const CATALOGUE: readonly Tell[];
|
|
1257
1257
|
declare function tellById(id: string): Tell | undefined;
|
|
1258
1258
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1252,7 +1252,7 @@ interface CheckReport {
|
|
|
1252
1252
|
* Bumped whenever an entry is added, removed or its detection changes, so a
|
|
1253
1253
|
* report can say which list it was judged against.
|
|
1254
1254
|
*/
|
|
1255
|
-
declare const CATALOGUE_VERSION = "2026.10.
|
|
1255
|
+
declare const CATALOGUE_VERSION = "2026.10.3";
|
|
1256
1256
|
declare const CATALOGUE: readonly Tell[];
|
|
1257
1257
|
declare function tellById(id: string): Tell | undefined;
|
|
1258
1258
|
/**
|
package/dist/index.js
CHANGED
|
@@ -2176,7 +2176,12 @@ var FALSE_RANGE = [
|
|
|
2176
2176
|
];
|
|
2177
2177
|
var RESIDUE = [
|
|
2178
2178
|
/\bas an AI(?:\s+language)?\s+(?:model|assistant)\b/i,
|
|
2179
|
-
|
|
2179
|
+
// At the start of a line, or after a sentence that ends in a full stop or
|
|
2180
|
+
// an exclamation mark: "I hope this email finds you well! Certainly, here
|
|
2181
|
+
// is the handover request." slipped through when only a line start counted
|
|
2182
|
+
// (found live, 2026-10-19). Not after a question mark: an FAQ answer may
|
|
2183
|
+
// honestly open "Do you work weekends? Absolutely, here are our hours."
|
|
2184
|
+
/(?<=^|[\n>]|[.!]\s+)\s*(?:Certainly|Sure|Absolutely|Of course|Great question)[!,.]\s+(?:Here(?:['’]s| is| are)|Below)\b/i,
|
|
2180
2185
|
/\bhere(?:['’]s| is)\s+(?:a|an|the|your)\s+(?:revised|rewritten|updated|polished|refined|improved|draft|more concise)\s+(?:version|draft|copy)\b/i,
|
|
2181
2186
|
/\blet me know if you(?:['’]d| would) like me to\b/i,
|
|
2182
2187
|
/\b(?:my|the) (?:knowledge|training) cut-?off\b|\bas of my last (?:update|training)\b/i,
|
|
@@ -2192,6 +2197,13 @@ var RESIDUE = [
|
|
|
2192
2197
|
/[\uE200-\uE2FF]*entity[\uE200-\uE2FF]*\["[a-z_]+"\s*,\s*"[^"\n]{1,80}"(?:\s*,\s*"[^"\n]{0,160}")*\][\uE200-\uE2FF]*/,
|
|
2193
2198
|
/【\d+(?:[:†][^】]{0,40})?】/
|
|
2194
2199
|
];
|
|
2200
|
+
var STOCK_EMAIL = [
|
|
2201
|
+
/\bI (?:hope|trust) (?:this|my|the) (?:e-?mail|message|note|letter) finds you(?: all)? (?:well|in good health)\b/i,
|
|
2202
|
+
/\bI hope you(?:['’]re| are)(?: all)? (?:doing |keeping )?well\b/i,
|
|
2203
|
+
/\b(?:I )?hope you(?:['’]re| are) having an? (?:great|good|lovely|wonderful|fantastic) (?:day|week|weekend)\b/i,
|
|
2204
|
+
/\blet (?:me|us) know if you have any (?:further |other |more )?questions\b/i,
|
|
2205
|
+
/\b(?:do not|don['’]t) hesitate to (?:contact|reach out|get in touch|ask|call)\b/i
|
|
2206
|
+
];
|
|
2195
2207
|
var AI_UTM = /utm_source=(?:chatgpt\.com|chat\.openai\.com|openai|perplexity(?:\.ai)?|claude\.ai|copilot(?:\.microsoft\.com)?|gemini(?:\.google\.com)?)\b/gi;
|
|
2196
2208
|
function residueHits(ctx) {
|
|
2197
2209
|
const hits = phrases(RESIDUE, quoted, allText)(ctx);
|
|
@@ -2273,15 +2285,39 @@ var RESEARCH_TELLS = [
|
|
|
2273
2285
|
f("content/home.md", "Prices start at \xA340 :contentReference[oaicite:2]{index=2} for a full set."),
|
|
2274
2286
|
f("content/home.md", "Prices start at \xA340\u30104\u2020source\u3011 for a full set."),
|
|
2275
2287
|
f("app/guide.tsx", `export const Guide = () => <a href="https://example.com/guide?utm_source=chatgpt.com">Read the guide</a>;`),
|
|
2276
|
-
f("content/home.md", "Here's a more concise version for the hero.")
|
|
2288
|
+
f("content/home.md", "Here's a more concise version for the hero."),
|
|
2289
|
+
// The client handover email that a clean copy-check let through, 2026-10-19.
|
|
2290
|
+
f("emails/handover.md", "Hi,\n\nI hope this email finds you well! Certainly, here is the handover request. Let me know if you have any questions.")
|
|
2277
2291
|
],
|
|
2278
2292
|
pass: [
|
|
2279
2293
|
f("content/home.md", "Certainly the busiest week of the year: book early."),
|
|
2294
|
+
f("content/faq.md", "Do you work weekends? Absolutely, here are our hours."),
|
|
2280
2295
|
f("content/home.md", "Here's the price list for 2026."),
|
|
2281
2296
|
f("app/guide.tsx", `export const Guide = () => <a href="https://example.com/guide?utm_source=newsletter">Read the guide</a>;`)
|
|
2282
2297
|
]
|
|
2283
2298
|
}
|
|
2284
2299
|
},
|
|
2300
|
+
{
|
|
2301
|
+
id: "stock-email-line",
|
|
2302
|
+
name: "Stock email line",
|
|
2303
|
+
generation: 1,
|
|
2304
|
+
severity: "warn",
|
|
2305
|
+
surface: "copy",
|
|
2306
|
+
why: "'I hope this email finds you well', 'let me know if you have any questions', 'don't hesitate to contact us': the opener and closer of a form email. A client reads past them, and a model drafting an email writes them every time.",
|
|
2307
|
+
fix: "Cut the opener and start with the reason for writing. Replace the closer with the next step and who to ask: 'Ring me on 07700 900123 if the date does not work.'",
|
|
2308
|
+
detect: phrases(STOCK_EMAIL, quoted),
|
|
2309
|
+
fixtures: {
|
|
2310
|
+
flag: [
|
|
2311
|
+
f("emails/handover.md", "Hi,\n\nI hope this email finds you well! Certainly, here is the handover request. Let me know if you have any questions."),
|
|
2312
|
+
f("emails/quote.md", "Hope you're having a great week. The quote is attached."),
|
|
2313
|
+
f("content/contact.md", "Please don't hesitate to contact us about a rewire.")
|
|
2314
|
+
],
|
|
2315
|
+
pass: [
|
|
2316
|
+
f("emails/handover.md", "Hi Sam,\n\nThe handover pack is attached: certificates, the board schedule and the warranty. Ring me on 07700 900123 if anything is missing."),
|
|
2317
|
+
f("content/contact.md", "If you have any questions, ring Jo on 01280 700123.")
|
|
2318
|
+
]
|
|
2319
|
+
}
|
|
2320
|
+
},
|
|
2285
2321
|
{
|
|
2286
2322
|
id: "prompt-context",
|
|
2287
2323
|
name: "Prompt context",
|
|
@@ -4891,6 +4927,8 @@ var HOUSE = {
|
|
|
4891
4927
|
// New 2026-10-14 (founder): review first, like every new tell, until estate hits are read.
|
|
4892
4928
|
"sales-tagline": { tier: "review", label: "sales tagline, say what you will actually do" },
|
|
4893
4929
|
"outcome-promise": { tier: "review", label: "outcome promise, promise the work, not the result" },
|
|
4930
|
+
// New 2026-10-19: review first, like every new tell, until estate hits are read.
|
|
4931
|
+
"stock-email-line": { tier: "review", label: "stock email line, start with the reason for writing and end with the next step" },
|
|
4894
4932
|
"ai-vocabulary": { tier: "review", label: "AI vocabulary" },
|
|
4895
4933
|
"stock-phrase": { tier: "review", label: "stock phrase" },
|
|
4896
4934
|
"hollow-imperative": { tier: "review", label: "hollow imperative" },
|
|
@@ -6096,7 +6134,7 @@ var IMAGERY_TELLS = [
|
|
|
6096
6134
|
];
|
|
6097
6135
|
|
|
6098
6136
|
// src/character/check.ts
|
|
6099
|
-
var CATALOGUE_VERSION = "2026.10.
|
|
6137
|
+
var CATALOGUE_VERSION = "2026.10.3";
|
|
6100
6138
|
var CATALOGUE = [
|
|
6101
6139
|
...[...SOURCE_TELLS, ...COPY_TELLS, ...RESEARCH_TELLS, ...DENSITY_TELLS].map((t) => RENDERED_PATHS[t.id] ? { ...t, rendered: RENDERED_PATHS[t.id] } : t),
|
|
6102
6140
|
...SPECIFICITY_COPY_TELLS,
|
|
@@ -5,13 +5,13 @@ import {
|
|
|
5
5
|
} from "./chunk-IJUZ7RV4.js";
|
|
6
6
|
import {
|
|
7
7
|
loadPlaywright
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-YFS32BZ2.js";
|
|
9
9
|
import "./chunk-JYNXGCYZ.js";
|
|
10
10
|
import {
|
|
11
11
|
toJson
|
|
12
12
|
} from "./chunk-QIEDBL4J.js";
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-PFVSKIPM.js";
|
|
14
|
+
import "./chunk-FBWBDBW4.js";
|
|
15
15
|
import "./chunk-QYBAVU3P.js";
|
|
16
16
|
|
|
17
17
|
// src/phone/viewports-cli.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@domandigital/craft",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.5",
|
|
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",
|
package/word-lists.json
CHANGED