@koehler8/cms 1.0.0-beta.38 → 1.0.0-beta.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koehler8/cms",
3
- "version": "1.0.0-beta.38",
3
+ "version": "1.0.0-beta.39",
4
4
  "description": "Vertex CMS — lightweight, config-driven Vue 3 framework with theming, extensions, and SSG support",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -15,6 +15,16 @@
15
15
  * - "Disallow: <prefix>" for each entry in site.draftPaths
16
16
  * - "Disallow: <path>" for each page with draft === true
17
17
  *
18
+ * site.robots.allowAiCrawlers (opt-in, default off): appends a dedicated block
19
+ * per known AI/LLM crawler (GPTBot, ClaudeBot, PerplexityBot, CCBot, etc.),
20
+ * each carrying the exact same Disallow list as the wildcard block — i.e.
21
+ * identical effective access, just declared explicitly per bot. Several sites
22
+ * were hand-editing this list directly into public/robots.txt; since that file
23
+ * is regenerated on every build, the hand edits were silently reverted on the
24
+ * next `build:ssg`/`generate:public-assets` run. This option makes the
25
+ * customization durable. Skipped entirely when site.draft === true — a
26
+ * pre-launch site shouldn't explicitly invite crawlers.
27
+ *
18
28
  * If sitemapUrl is provided, appends a "Sitemap: <url>" line.
19
29
  */
20
30
 
@@ -22,18 +32,27 @@ import { normalizeDraftPath } from './draftMode.js';
22
32
 
23
33
  const FRAMEWORK_DEFAULTS = ['/admin'];
24
34
 
25
- export function buildRobotsTxt(siteConfig, sitemapUrl = '') {
26
- const lines = ['User-agent: *'];
27
-
28
- for (const p of FRAMEWORK_DEFAULTS) {
29
- lines.push(`Disallow: ${p}`);
30
- }
35
+ // Order/grouping mirrors the hand-rolled lists sites had converged on before
36
+ // this became a config option.
37
+ const AI_CRAWLER_GROUPS = [
38
+ { comment: 'OpenAI / ChatGPT', agents: ['GPTBot', 'OAI-SearchBot', 'ChatGPT-User'] },
39
+ { comment: 'Anthropic / Claude', agents: ['anthropic-ai', 'ClaudeBot'] },
40
+ { comment: 'Perplexity', agents: ['PerplexityBot'] },
41
+ { comment: 'Common Crawl (used by many LLM training datasets)', agents: ['CCBot'] },
42
+ { comment: 'Google', agents: ['Googlebot', 'Googlebot-Extended'] },
43
+ { comment: 'Microsoft / Bing', agents: ['Bingbot'] },
44
+ { comment: 'Meta', agents: ['FacebookBot'] },
45
+ { comment: 'Diffbot', agents: ['Diffbot'] },
46
+ ];
31
47
 
48
+ export function buildRobotsTxt(siteConfig, sitemapUrl = '') {
32
49
  const site = siteConfig?.site || {};
33
50
  const pages = siteConfig?.pages || {};
34
51
 
52
+ const disallows = [...FRAMEWORK_DEFAULTS];
53
+
35
54
  if (site.draft === true) {
36
- lines.push('Disallow: /');
55
+ disallows.push('/');
37
56
  } else {
38
57
  const additional = new Set();
39
58
 
@@ -51,7 +70,25 @@ export function buildRobotsTxt(siteConfig, sitemapUrl = '') {
51
70
  }
52
71
 
53
72
  for (const p of Array.from(additional).sort()) {
54
- lines.push(`Disallow: ${p}`);
73
+ disallows.push(p);
74
+ }
75
+ }
76
+
77
+ const lines = ['User-agent: *'];
78
+ for (const d of disallows) {
79
+ lines.push(`Disallow: ${d}`);
80
+ }
81
+
82
+ if (site.robots?.allowAiCrawlers === true && site.draft !== true) {
83
+ for (const group of AI_CRAWLER_GROUPS) {
84
+ lines.push('');
85
+ lines.push(`# ${group.comment}`);
86
+ for (const agent of group.agents) {
87
+ lines.push(`User-agent: ${agent}`);
88
+ for (const d of disallows) {
89
+ lines.push(`Disallow: ${d}`);
90
+ }
91
+ }
55
92
  }
56
93
  }
57
94