@scribe-platform/cli 0.9.1 → 0.11.0

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.
Files changed (69) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/build.d.ts.map +1 -1
  3. package/dist/commands/build.js +4 -2
  4. package/dist/commands/build.js.map +1 -1
  5. package/dist/commands/content.d.ts.map +1 -1
  6. package/dist/commands/content.js +5 -1
  7. package/dist/commands/content.js.map +1 -1
  8. package/dist/commands/login.d.ts.map +1 -1
  9. package/dist/commands/login.js +25 -4
  10. package/dist/commands/login.js.map +1 -1
  11. package/dist/commands/profile.d.ts +12 -0
  12. package/dist/commands/profile.d.ts.map +1 -0
  13. package/dist/commands/profile.js +81 -0
  14. package/dist/commands/profile.js.map +1 -0
  15. package/dist/commands/proof.d.ts.map +1 -1
  16. package/dist/commands/proof.js +6 -6
  17. package/dist/commands/proof.js.map +1 -1
  18. package/dist/commands/prospect.d.ts.map +1 -1
  19. package/dist/commands/prospect.js +4 -2
  20. package/dist/commands/prospect.js.map +1 -1
  21. package/dist/commands/request.d.ts.map +1 -1
  22. package/dist/commands/request.js +8 -4
  23. package/dist/commands/request.js.map +1 -1
  24. package/dist/commands/schema.js +1 -1
  25. package/dist/commands/schema.js.map +1 -1
  26. package/dist/commands/site.d.ts.map +1 -1
  27. package/dist/commands/site.js +48 -3
  28. package/dist/commands/site.js.map +1 -1
  29. package/dist/commands/submission.d.ts.map +1 -1
  30. package/dist/commands/submission.js +4 -1
  31. package/dist/commands/submission.js.map +1 -1
  32. package/dist/commands/update.js.map +1 -1
  33. package/dist/commands/user.d.ts +11 -0
  34. package/dist/commands/user.d.ts.map +1 -0
  35. package/dist/commands/user.js +88 -0
  36. package/dist/commands/user.js.map +1 -0
  37. package/dist/index.d.ts +1 -1
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +5 -1
  40. package/dist/index.js.map +1 -1
  41. package/dist/lib/client.d.ts +117 -0
  42. package/dist/lib/client.d.ts.map +1 -1
  43. package/dist/lib/client.js +128 -10
  44. package/dist/lib/client.js.map +1 -1
  45. package/dist/lib/config.d.ts +53 -0
  46. package/dist/lib/config.d.ts.map +1 -1
  47. package/dist/lib/config.js +116 -8
  48. package/dist/lib/config.js.map +1 -1
  49. package/dist/lib/proof-folder.d.ts.map +1 -1
  50. package/dist/lib/proof-folder.js +10 -3
  51. package/dist/lib/proof-folder.js.map +1 -1
  52. package/dist/lib/proof-preview.d.ts.map +1 -1
  53. package/dist/lib/proof-preview.js.map +1 -1
  54. package/dist/lib/proof-push.d.ts.map +1 -1
  55. package/dist/lib/proof-push.js +6 -1
  56. package/dist/lib/proof-push.js.map +1 -1
  57. package/dist/lib/seo-report.d.ts +19 -0
  58. package/dist/lib/seo-report.d.ts.map +1 -0
  59. package/dist/lib/seo-report.js +79 -0
  60. package/dist/lib/seo-report.js.map +1 -0
  61. package/dist/lib/skill.js +1 -1
  62. package/package.json +2 -2
  63. package/skills/scribe-site-builder/SKILL.md +32 -5
  64. package/skills/scribe-site-builder/recipes/README.md +7 -4
  65. package/skills/scribe-site-builder/recipes/client-logins.md +74 -0
  66. package/skills/scribe-site-builder/recipes/deploy.md +41 -10
  67. package/skills/scribe-site-builder/recipes/domains.md +4 -1
  68. package/skills/scribe-site-builder/recipes/forms.md +21 -1
  69. package/skills/scribe-site-builder/recipes/seo.md +193 -0
@@ -0,0 +1,193 @@
1
+ # Recipe: being found
2
+
3
+ > **The commands below are yours to run, not hers to read.** If she's asking
4
+ > what this is or how to do it, answer it the way *Who you're talking to* in
5
+ > [`../SKILL.md`](../SKILL.md) says to: what it is, what she'd say to get it,
6
+ > what's her call, and an offer to do it now.
7
+
8
+ Everything `scribe site seo <site>` checks, and how to make each one pass. Build
9
+ a site with all of it and the check is a regression guard rather than a list of
10
+ things to go and fix.
11
+
12
+ **Run `scribe site seo <site>` before `scribe site promote`**, not after. Going
13
+ live is the deadline for being findable, not the starting gun — and `promote`
14
+ refuses on a failure, the same way it already refuses when DNS is not ready.
15
+
16
+ Three checks (`sitemap`, `canonical`, `indexable`) skip until the site is on the
17
+ client's own domain, because before the cutover those all correctly name
18
+ `*.github.io`. That is expected, not a problem, and not something to fix.
19
+
20
+ ## The four files
21
+
22
+ Almost everything here comes from four pieces. A site with all four passes all
23
+ eleven checks.
24
+
25
+ ### 1. `site` in `astro.config.mjs`
26
+
27
+ Nothing else works without it. Astro needs the site's real address to build
28
+ absolute URLs, and a canonical or a sitemap entry that is not absolute is not
29
+ valid.
30
+
31
+ ```js
32
+ import { defineConfig } from 'astro/config';
33
+ import sitemap from '@astrojs/sitemap';
34
+
35
+ export default defineConfig({
36
+ // The live address. Set it to the client's domain from the start, even
37
+ // before the cutover — it is what the sitemap and every canonical are built
38
+ // from, and it is the one value that cannot be derived from the environment.
39
+ site: 'https://riversidedental.com',
40
+ base: process.env.PUBLIC_BASE_PATH || '/',
41
+ integrations: [sitemap()],
42
+ });
43
+ ```
44
+
45
+ `npm install @astrojs/sitemap` first. The integration writes `sitemap-index.xml`
46
+ and `sitemap-0.xml` into `dist/` on every build, so the page list can never go
47
+ stale the way a hand-written one does.
48
+
49
+ ### 2. `public/robots.txt`
50
+
51
+ ```
52
+ User-agent: *
53
+ Allow: /
54
+
55
+ Sitemap: https://riversidedental.com/sitemap-index.xml
56
+ ```
57
+
58
+ Three things the check looks for: that the file exists at all, that it does not
59
+ carry a blanket `Disallow: /`, and that it names a `Sitemap:` line. A commented
60
+ `# Sitemap:` does not count.
61
+
62
+ ### 3. A `<SeoHead>` component
63
+
64
+ One component, used by every layout, so a page cannot be built that forgets
65
+ half of it. This is the piece that covers five of the eleven checks at once.
66
+
67
+ ```astro
68
+ ---
69
+ // src/components/SeoHead.astro
70
+ interface Props {
71
+ title: string;
72
+ description: string;
73
+ /** Falls back to the site-wide card image. */
74
+ image?: string;
75
+ }
76
+
77
+ const { title, description, image = '/og-card.png' } = Astro.props;
78
+
79
+ // Astro.site comes from astro.config.mjs. Astro.url.pathname is this page.
80
+ const canonical = new URL(Astro.url.pathname, Astro.site);
81
+ const imageUrl = new URL(image, Astro.site);
82
+ ---
83
+ <title>{title}</title>
84
+ <meta name="description" content={description} />
85
+ <link rel="canonical" href={canonical} />
86
+
87
+ <meta property="og:title" content={title} />
88
+ <meta property="og:description" content={description} />
89
+ <meta property="og:image" content={imageUrl} />
90
+ <meta property="og:url" content={canonical} />
91
+ <meta property="og:type" content="website" />
92
+ ```
93
+
94
+ Then in the layout:
95
+
96
+ ```astro
97
+ ---
98
+ import SeoHead from '../components/SeoHead.astro';
99
+ const { title, description } = Astro.props;
100
+ ---
101
+ <html lang="en">
102
+ <head>
103
+ <meta charset="utf-8" />
104
+ <meta name="viewport" content="width=device-width" />
105
+ <SeoHead title={title} description={description} />
106
+ </head>
107
+ <body><slot /></body>
108
+ </html>
109
+ ```
110
+
111
+ **`lang="en"` on `<html>` is its own check** and is easy to drop when a layout
112
+ gets rewritten.
113
+
114
+ **Every page passes its own title and description.** Two pages sharing either
115
+ one is a failure, not a warning — it is the normal result of a layout setting a
116
+ default that a page forgets to override, and it cannot be seen by looking at any
117
+ single page.
118
+
119
+ ### 4. The business, in structured data
120
+
121
+ On the home page only. This is what puts a business in a local result rather
122
+ than a plain blue link.
123
+
124
+ ```astro
125
+ ---
126
+ const business = {
127
+ '@context': 'https://schema.org',
128
+ '@type': 'LocalBusiness', // or a more specific type: Dentist, Plumber, HairSalon
129
+ name: 'Riverside Dental',
130
+ url: 'https://riversidedental.com',
131
+ telephone: '+1-717-555-0100',
132
+ address: {
133
+ '@type': 'PostalAddress',
134
+ streetAddress: '14 Market Street',
135
+ addressLocality: 'Lancaster',
136
+ addressRegion: 'PA',
137
+ postalCode: '17602',
138
+ addressCountry: 'US',
139
+ },
140
+ areaServed: 'Lancaster County, PA',
141
+ };
142
+ ---
143
+ <script type="application/ld+json" set:html={JSON.stringify(business)} />
144
+ ```
145
+
146
+ `name`, `url` and `telephone` are what the check requires. The address and
147
+ `areaServed` are not checked and are worth having anyway — they are most of what
148
+ a local result is made of.
149
+
150
+ **A business that does not want its street address public can leave
151
+ `address` out** and keep `areaServed`. Google's own guidance is that a business
152
+ customers do not visit should hide the address and declare a service area.
153
+
154
+ **Do not mark up reviews you are displaying for yourself.** Google reserves
155
+ review markup for a site reviewing *other* businesses, and a demo's placeholder
156
+ five stars is exactly the thing that gets a site penalised.
157
+
158
+ ## The two smaller ones
159
+
160
+ **`contactable`** — a phone number on the home page and on any contact page. A
161
+ `tel:` link counts, and so does a plain number in the text. This exists because
162
+ a real site went live with its number on four guide articles and on none of the
163
+ pages anybody lands on.
164
+
165
+ ```astro
166
+ <a href="tel:+17175550100">(717) 555-0100</a>
167
+ ```
168
+
169
+ **`alt`** — every `<img>` needs an `alt` attribute. `alt=""` passes and is the
170
+ correct markup for a decorative image; a *missing* attribute is the failure.
171
+
172
+ ## What the checks will not tell you
173
+
174
+ Eleven checks are mechanical. The things that actually decide whether a site
175
+ ranks are not, and `scribe site seo` ends by asking about them rather than
176
+ pretending to measure them:
177
+
178
+ - Does the site say which town and area the business serves, on the pages a
179
+ visitor lands on? A local business that never names its town is the single
180
+ most common reason one does not show up.
181
+ - Is there real client proof — a name, a review, a photo of finished work —
182
+ rather than a placeholder?
183
+ - Is there a page for each main thing they sell, rather than one page with
184
+ sections? One page cannot rank for six different searches.
185
+ - Does the contact form sit next to a privacy policy, if it collects a name,
186
+ email or phone?
187
+ - Would someone who has never heard of this business understand what it does
188
+ from the home page alone?
189
+ - Is the business claimed on Google with the same name, address and phone number
190
+ as the site?
191
+
192
+ Ask the client. "Not yet" is a real answer — the point is that it gets said
193
+ before the site goes live, not that every site has all six.