@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.
- package/README.md +1 -1
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +4 -2
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/content.d.ts.map +1 -1
- package/dist/commands/content.js +5 -1
- package/dist/commands/content.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +25 -4
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/profile.d.ts +12 -0
- package/dist/commands/profile.d.ts.map +1 -0
- package/dist/commands/profile.js +81 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/commands/proof.d.ts.map +1 -1
- package/dist/commands/proof.js +6 -6
- package/dist/commands/proof.js.map +1 -1
- package/dist/commands/prospect.d.ts.map +1 -1
- package/dist/commands/prospect.js +4 -2
- package/dist/commands/prospect.js.map +1 -1
- package/dist/commands/request.d.ts.map +1 -1
- package/dist/commands/request.js +8 -4
- package/dist/commands/request.js.map +1 -1
- package/dist/commands/schema.js +1 -1
- package/dist/commands/schema.js.map +1 -1
- package/dist/commands/site.d.ts.map +1 -1
- package/dist/commands/site.js +48 -3
- package/dist/commands/site.js.map +1 -1
- package/dist/commands/submission.d.ts.map +1 -1
- package/dist/commands/submission.js +4 -1
- package/dist/commands/submission.js.map +1 -1
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/user.d.ts +11 -0
- package/dist/commands/user.d.ts.map +1 -0
- package/dist/commands/user.js +88 -0
- package/dist/commands/user.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/client.d.ts +117 -0
- package/dist/lib/client.d.ts.map +1 -1
- package/dist/lib/client.js +128 -10
- package/dist/lib/client.js.map +1 -1
- package/dist/lib/config.d.ts +53 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +116 -8
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/proof-folder.d.ts.map +1 -1
- package/dist/lib/proof-folder.js +10 -3
- package/dist/lib/proof-folder.js.map +1 -1
- package/dist/lib/proof-preview.d.ts.map +1 -1
- package/dist/lib/proof-preview.js.map +1 -1
- package/dist/lib/proof-push.d.ts.map +1 -1
- package/dist/lib/proof-push.js +6 -1
- package/dist/lib/proof-push.js.map +1 -1
- package/dist/lib/seo-report.d.ts +19 -0
- package/dist/lib/seo-report.d.ts.map +1 -0
- package/dist/lib/seo-report.js +79 -0
- package/dist/lib/seo-report.js.map +1 -0
- package/dist/lib/skill.js +1 -1
- package/package.json +2 -2
- package/skills/scribe-site-builder/SKILL.md +32 -5
- package/skills/scribe-site-builder/recipes/README.md +7 -4
- package/skills/scribe-site-builder/recipes/client-logins.md +74 -0
- package/skills/scribe-site-builder/recipes/deploy.md +41 -10
- package/skills/scribe-site-builder/recipes/domains.md +4 -1
- package/skills/scribe-site-builder/recipes/forms.md +21 -1
- 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.
|