katman-mcp 0.1.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 (97) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +160 -0
  3. package/dist/cli.js +71 -0
  4. package/dist/context.js +43 -0
  5. package/dist/crawlers.js +86 -0
  6. package/dist/index.js +25 -0
  7. package/dist/license.js +448 -0
  8. package/dist/meta.js +28 -0
  9. package/dist/net.js +128 -0
  10. package/dist/server.js +17 -0
  11. package/dist/state.js +81 -0
  12. package/dist/tools/account/account.js +64 -0
  13. package/dist/tools/account/cli.js +21 -0
  14. package/dist/tools/account/index.js +48 -0
  15. package/dist/tools/account/sync.js +142 -0
  16. package/dist/tools/account/upsell.js +290 -0
  17. package/dist/tools/crawl/audit/analyze.js +719 -0
  18. package/dist/tools/crawl/audit/bots.js +114 -0
  19. package/dist/tools/crawl/audit/checks.js +126 -0
  20. package/dist/tools/crawl/audit/html.js +382 -0
  21. package/dist/tools/crawl/audit/index.js +364 -0
  22. package/dist/tools/crawl/audit/model.js +1 -0
  23. package/dist/tools/crawl/audit/report.js +199 -0
  24. package/dist/tools/crawl/audit/robots.js +199 -0
  25. package/dist/tools/crawl/audit/sitemap.js +147 -0
  26. package/dist/tools/crawl/cli.js +106 -0
  27. package/dist/tools/crawl/common/advice.js +61 -0
  28. package/dist/tools/crawl/common/findings.js +57 -0
  29. package/dist/tools/crawl/common/routes.js +80 -0
  30. package/dist/tools/crawl/common/text.js +89 -0
  31. package/dist/tools/crawl/common/urls.js +64 -0
  32. package/dist/tools/crawl/index.js +226 -0
  33. package/dist/tools/crawl/indexnow.js +271 -0
  34. package/dist/tools/crawl/keywords.js +178 -0
  35. package/dist/tools/crawl/scan/framework.js +645 -0
  36. package/dist/tools/crawl/scan/index.js +175 -0
  37. package/dist/tools/crawl/scan/project.js +180 -0
  38. package/dist/tools/crawl/scan/routes.js +354 -0
  39. package/dist/tools/crawl/scan/signals.js +414 -0
  40. package/dist/tools/method/cli.js +42 -0
  41. package/dist/tools/method/core/brief.js +302 -0
  42. package/dist/tools/method/core/extract.js +435 -0
  43. package/dist/tools/method/core/generate.js +504 -0
  44. package/dist/tools/method/core/lint.js +556 -0
  45. package/dist/tools/method/core/plan.js +405 -0
  46. package/dist/tools/method/core/prompt.js +150 -0
  47. package/dist/tools/method/core/questions.js +196 -0
  48. package/dist/tools/method/core/report.js +182 -0
  49. package/dist/tools/method/core/research-run.js +148 -0
  50. package/dist/tools/method/core/research.js +448 -0
  51. package/dist/tools/method/core/snippets.js +292 -0
  52. package/dist/tools/method/core/start.js +277 -0
  53. package/dist/tools/method/data/anatomy.js +141 -0
  54. package/dist/tools/method/data/appendices.js +202 -0
  55. package/dist/tools/method/data/cloudflare.js +192 -0
  56. package/dist/tools/method/data/evidence.js +137 -0
  57. package/dist/tools/method/data/geo-jobs.js +128 -0
  58. package/dist/tools/method/data/index.js +19 -0
  59. package/dist/tools/method/data/landing.js +67 -0
  60. package/dist/tools/method/data/lessons.js +127 -0
  61. package/dist/tools/method/data/measurement.js +142 -0
  62. package/dist/tools/method/data/method.js +141 -0
  63. package/dist/tools/method/data/offsite.js +148 -0
  64. package/dist/tools/method/data/pages.js +167 -0
  65. package/dist/tools/method/data/prompts.js +633 -0
  66. package/dist/tools/method/data/publish.js +113 -0
  67. package/dist/tools/method/data/render.js +117 -0
  68. package/dist/tools/method/data/research.js +131 -0
  69. package/dist/tools/method/data/roadmap.js +105 -0
  70. package/dist/tools/method/data/traps.js +74 -0
  71. package/dist/tools/method/data/verify.js +88 -0
  72. package/dist/tools/method/data/viral-list.js +39 -0
  73. package/dist/tools/method/index.js +209 -0
  74. package/dist/tools/method/lib/calls.js +53 -0
  75. package/dist/tools/method/lib/framework.js +525 -0
  76. package/dist/tools/method/lib/l10n.js +17 -0
  77. package/dist/tools/method/lib/routes.js +118 -0
  78. package/dist/tools/method/lib/state.js +454 -0
  79. package/dist/tools/method/lib/text.js +165 -0
  80. package/dist/tools/method/mcp/prompts.js +79 -0
  81. package/dist/tools/method/mcp/resources.js +50 -0
  82. package/dist/tools/visibility/analyze.js +463 -0
  83. package/dist/tools/visibility/cli.js +86 -0
  84. package/dist/tools/visibility/estimate.js +105 -0
  85. package/dist/tools/visibility/index.js +108 -0
  86. package/dist/tools/visibility/judge.js +156 -0
  87. package/dist/tools/visibility/manual.js +275 -0
  88. package/dist/tools/visibility/models.js +277 -0
  89. package/dist/tools/visibility/monitoring.js +165 -0
  90. package/dist/tools/visibility/openrouter.js +449 -0
  91. package/dist/tools/visibility/render.js +295 -0
  92. package/dist/tools/visibility/run.js +684 -0
  93. package/dist/tools/visibility/summary.js +164 -0
  94. package/dist/types.js +3 -0
  95. package/dist/util.js +92 -0
  96. package/package.json +54 -0
  97. package/server.json +34 -0
@@ -0,0 +1,141 @@
1
+ export const ANATOMY_INTRO = {
2
+ en: "A page is written for two readers at once: Google and the assistant. The invoice example below is invented; its structure is the same as the sample site's situation pages. Blocks tagged SEO are for the search engine, GEO blocks are for the assistant to quote you. Most serve both.",
3
+ tr: "Bir sayfa iki okuyucuya birden yazılır: Google’a ve asistana. Aşağıdaki fatura örneği uydurmadır; yapı, örnek sitenin durum sayfalarıyla aynı. SEO etiketli bloklar arama motoru için, GEO etiketliler asistanın sizi alıntılaması için. Çoğu ikisine birden yarıyor.",
4
+ };
5
+ export const ANATOMY = [
6
+ {
7
+ n: 1,
8
+ tags: ["SEO", "GEO"],
9
+ name: { en: "<title> · meta description · canonical · og:image", tr: "<title> · meta description · canonical · og:image" },
10
+ example: { en: "yoursite.com/import-pdf-invoices", tr: "siteniz.com/faturami-muhasebeye-aktar" },
11
+ rule: {
12
+ en: "Title: the situation first, then the brand, about 60 characters. Meta description: the sentence you want the assistant to say; Google mostly builds the snippet from the page text, so the same sentence must also be in block 3.",
13
+ tr: "Title önce durum, sonra marka, yaklaşık 60 karakter. Meta açıklama asistanın söylemesini istediğiniz cümle; Google snippet’i çoğunlukla sayfa metninden kurar, bu yüzden aynı cümle 3. blokta da olmalı.",
14
+ },
15
+ },
16
+ {
17
+ n: 2,
18
+ tags: ["SEO", "GEO"],
19
+ name: { en: "H1", tr: "H1" },
20
+ example: { en: "I type my invoices in by hand and it takes hours", tr: "Faturalarımı elle giriyorum, saatlerimi alıyor" },
21
+ rule: { en: "The H1 is the customer's own sentence. The URL uses the same words.", tr: "H1 müşterinin kendi cümlesi. Adres de aynı kelimelerle." },
22
+ },
23
+ {
24
+ n: 3,
25
+ tags: ["GEO"],
26
+ name: { en: "The first 1–3 sentences", tr: "İlk 1–3 cümle" },
27
+ example: {
28
+ en: "Upload your invoice. We move the line items into your accounting software in 30 seconds and flag the ones that don't match. Your document is never stored.",
29
+ tr: "Faturanı yükle. Kalemleri 30 saniyede muhasebe programına aktarırız, eşleşmeyenleri işaretleriz. Belgen saklanmaz.",
30
+ },
31
+ rule: {
32
+ en: "The most important block. The assistant takes a sentence for its answer from here: short, concrete, understandable on its own. ChatGPT repeated the sample site's sentence almost word for word. Keep the key claim within the H1 and the first ~200 characters.",
33
+ tr: "Sayfanın en önemli bloğu. Asistan cevabına buradan bir cümle alır: kısa, somut, tek başına anlaşılır. Örnek sitenin cümlesini ChatGPT neredeyse kelimesi kelimesine tekrar etti. Asıl iddiayı H1’de ve ilk ~200 karakterde tutun.",
34
+ },
35
+ },
36
+ {
37
+ n: 4,
38
+ tags: [],
39
+ name: { en: "Try it now / one clear action", tr: "Hemen deneme / tek net eylem" },
40
+ example: { en: "Drop your invoice · try it free", tr: "Faturanı bırak · ücretsiz dene" },
41
+ rule: {
42
+ en: "The visitor arrives with the situation they told ChatGPT. On the sample site we put a file drop box on the two pages ChatGPT sent people to; 52 of the first 68 generations in week one used the visitor's own file.",
43
+ tr: "Ziyaretçi ChatGPT’ye anlattığı durumla gelir. Örnek sitede ChatGPT’nin gönderdiği iki sayfaya dosya kutusu koyduk; ilk haftadaki 68 ilk üretimin 52’si ziyaretçinin kendi dosyasıyla yapıldı.",
44
+ },
45
+ },
46
+ {
47
+ n: 5,
48
+ tags: ["GEO"],
49
+ name: { en: "Proof: number + date", tr: "Kanıt: sayı + tarih" },
50
+ example: { en: "A verifiable number with its date", tr: "Doğrulanabilir sayı, tarihiyle" },
51
+ rule: {
52
+ en: "A verifiable number, with its date. Don't claim more than your proof: the assistant repeats it and a competitor refutes it.",
53
+ tr: "Doğrulanabilir sayı, tarihiyle. Kanıtından büyük iddia yazmayın; asistan tekrar eder, rakip çürütür.",
54
+ },
55
+ },
56
+ {
57
+ n: 6,
58
+ tags: ["SEO", "GEO"],
59
+ name: { en: "How it works: 3–5 steps", tr: "Nasıl çalışır: 3–5 adım" },
60
+ example: { en: "3–5 plain-text steps", tr: "3–5 düz metin adım" },
61
+ rule: {
62
+ en: "Plain HTML text; a demo drawn with JavaScript is an empty page to a bot.",
63
+ tr: "Düz HTML metin; JavaScript ile çizilen bir demo bot için boş sayfadır.",
64
+ },
65
+ },
66
+ {
67
+ n: 7,
68
+ tags: ["GEO"],
69
+ name: { en: "Who it's not for", tr: "Kimler için değil" },
70
+ example: { en: "2–3 bullets", tr: "2–3 madde" },
71
+ rule: {
72
+ en: "Saying who it's not for and naming competitors honestly builds trust; assistants quote one-sided pages less.",
73
+ tr: "“Kime uygun değil” ve rakipleri dürüstçe saymak güven verir; asistan tek taraflı sayfayı daha az alıntılar.",
74
+ },
75
+ },
76
+ {
77
+ n: 8,
78
+ tags: ["GEO"],
79
+ name: { en: "Alternatives, honestly", tr: "Alternatifler, dürüstçe" },
80
+ example: { en: "Competitor: who it fits", tr: "Rakip: kime uygun" },
81
+ rule: {
82
+ en: "Name the alternatives and say whom each one fits; take competitor facts only from their own pages, with a date.",
83
+ tr: "Alternatifleri sayın, hangisinin kime uygun olduğunu yazın; rakip bilgisini yalnızca kendi sayfasından, tarihiyle alın.",
84
+ },
85
+ },
86
+ {
87
+ n: 9,
88
+ tags: ["GEO"],
89
+ name: { en: "FAQ: 5–8 questions", tr: "SSS: 5–8 soru" },
90
+ example: { en: "Questions in the customer's words", tr: "Müşterinin ağzından sorular" },
91
+ rule: {
92
+ en: "Questions in the customer's words, answers whose first sentence is the answer. Google no longer shows an FAQ rich result; this block is for the assistant.",
93
+ tr: "Müşterinin ağzından sorular, ilk cümlesi cevap olan yanıtlar. Google’da SSS zengin sonucu yok; bu blok asistan için.",
94
+ },
95
+ },
96
+ {
97
+ n: 10,
98
+ tags: ["SEO"],
99
+ name: { en: "Related pages", tr: "İlgili sayfalar" },
100
+ example: { en: "3–5 text links", tr: "3–5 metinli link" },
101
+ rule: {
102
+ en: "Internal links with descriptive text; every page gets a link from somewhere.",
103
+ tr: "Metinli iç linkler; her sayfa en az bir yerden link alsın.",
104
+ },
105
+ },
106
+ {
107
+ n: 11,
108
+ tags: ["SEO", "GEO"],
109
+ name: { en: "Updated date · author · JSON-LD", tr: "Güncellendi · yazar · JSON-LD" },
110
+ example: { en: "Updated: 29 Sep 2026 · Author · JSON-LD", tr: "Güncellendi: 29.09.2026 · Yazar · JSON-LD" },
111
+ rule: {
112
+ en: "A real update date (changed only when the text changes), the author, valid JSON-LD. In the sample site's first version all 85 pages carried the launch date; we fixed it.",
113
+ tr: "Gerçek güncelleme tarihi (yalnızca metin değişince), yazar, geçerli JSON-LD. Örnek sitede ilk sürümde 85 sayfanın hepsi yayın tarihini taşıyordu; düzelttik.",
114
+ },
115
+ },
116
+ ];
117
+ /** The page brief the book tells you to start P6 with. */
118
+ export const PAGE_BRIEF_TEMPLATE = {
119
+ en: `Situation: [the customer's sentence]
120
+ URL: /[words] Title: [situation] — [brand]
121
+ First sentence: [brings] → [we do] → [they get]. [fear is unnecessary].
122
+ Action: [file drop / trial / pricing]
123
+ Proof: [number, source, date]
124
+ Not for: [2–3 bullets]
125
+ Alternatives: [competitor: who it fits]
126
+ FAQ: [5–8 questions, in the customer's words]
127
+ Related pages: [3–5 URLs]`,
128
+ tr: `Durum: [müşterinin cümlesi]
129
+ Adres: /[kelimeler] Title: [durum] — [marka]
130
+ İlk cümle: [getirir] → [yaparız] → [eline geçer]. [korku gereksiz].
131
+ Eylem: [dosya kutusu / deneme / fiyat]
132
+ Kanıt: [sayı, kaynak, tarih]
133
+ Kimler için değil: [2-3 madde]
134
+ Alternatifler: [rakip: kime uygun]
135
+ SSS: [5-8 soru, müşterinin ağzından]
136
+ İlgili sayfalar: [3-5 adres]`,
137
+ };
138
+ export const ANATOMY_EXERCISE = {
139
+ en: "Write your own four-part sentence (brings → we do → gets → fear is unnecessary). Put the same sentence in three places: the first paragraph of your most important page, that page's meta description, and llms.txt.",
140
+ tr: "Kendi dört parçalı cümlenizi yazın (getirir → yaparız → eline geçer → korku gereksiz). Aynı cümleyi üç yere koyun: en önemli sayfanın ilk paragrafı, o sayfanın meta açıklaması, llms.txt.",
141
+ };
@@ -0,0 +1,202 @@
1
+ /** Appendix A — the sample robots.txt (katman_generate builds the project-specific version). */
2
+ export const APPENDIX_A_ROBOTS = {
3
+ en: `# Open to search engines, AI assistants and crawlers.
4
+ # Content signals: search=yes, ai-input=yes, ai-train=yes
5
+ # (Written as a comment: as a rule line, Lighthouse reported "robots.txt is not valid".)
6
+
7
+ User-agent: *
8
+ Allow: /
9
+ Disallow: /app/
10
+ Disallow: /admin/
11
+ Disallow: /api/
12
+
13
+ User-agent: OAI-SearchBot
14
+ Allow: /
15
+ Disallow: /app/
16
+ Disallow: /admin/
17
+ Disallow: /api/
18
+
19
+ # The same group is repeated for: ChatGPT-User, GPTBot, Claude-SearchBot,
20
+ # Claude-User, ClaudeBot, PerplexityBot, Perplexity-User, Google-Extended,
21
+ # Applebot, Applebot-Extended, Bingbot, DuckAssistBot, Meta-ExternalAgent, Amazonbot
22
+
23
+ Sitemap: https://yourdomain.com/sitemap.xml
24
+ # For assistants: https://yourdomain.com/llms.txt`,
25
+ tr: `# Arama motorlarına, yapay zekâ asistanlarına ve tarayıcılara açığız.
26
+ # Content signals: search=yes, ai-input=yes, ai-train=yes
27
+ # (Yorum olarak yazıldı: kural olarak yazılınca Lighthouse "robots.txt geçersiz" dedi.)
28
+
29
+ User-agent: *
30
+ Allow: /
31
+ Disallow: /app/
32
+ Disallow: /admin/
33
+ Disallow: /api/
34
+
35
+ User-agent: OAI-SearchBot
36
+ Allow: /
37
+ Disallow: /app/
38
+ Disallow: /admin/
39
+ Disallow: /api/
40
+
41
+ # Aynı grup şunlar için de tekrarlanır: ChatGPT-User, GPTBot, Claude-SearchBot,
42
+ # Claude-User, ClaudeBot, PerplexityBot, Perplexity-User, Google-Extended,
43
+ # Applebot, Applebot-Extended, Bingbot, DuckAssistBot, Meta-ExternalAgent, Amazonbot
44
+
45
+ Sitemap: https://alanadiniz.com/sitemap.xml
46
+ # Asistanlar için: https://alanadiniz.com/llms.txt`,
47
+ };
48
+ export const APPENDIX_A_NOTE = {
49
+ en: "A bot that has a group with its own name doesn't read the * group, so repeat the closed paths in every group. Don't write bare prefixes: Disallow: /t closes both /tr and /tools; write /t/. Have your coding tool generate this file with P4.",
50
+ tr: "Bir bot için adıyla yazılmış grup varsa o bot * grubunu okumaz; bu yüzden kapalı yolları her grupta tekrar yazın. Çıplak önek yazmayın: Disallow: /t hem /tr’yi hem /tools’u kapatır, /t/ yazın. Kod aracınıza bu dosyayı P4 ile ürettirin.",
51
+ };
52
+ /** Appendix B — llms.txt skeleton. */
53
+ export const APPENDIX_B_LLMS = {
54
+ en: `# [Brand] [category word]
55
+
56
+ > [Brand] is a [product type] that turns [input] into [output]. [The most important difference, one sentence].
57
+ > Operated by [company name] ([country]).
58
+
59
+ Key facts: [pricing model, lowest price, trial], [cancellation], [usage limits].
60
+ Not to be confused with: [Brand] is not [similarly named product]; it is not a [big company] product.
61
+ Limits of the evidence: [the test behind the claim and its size, stated plainly].
62
+
63
+ ## Product
64
+ - [Home](https://yourdomain.com/): what it is
65
+ - [Pricing](https://yourdomain.com/pricing): plans
66
+ - [Situation page](https://yourdomain.com/...): [the four-part sentence]
67
+
68
+ ## Guides
69
+ ## Comparisons
70
+ ## Optional
71
+ - [Terms](...), [Privacy](...)`,
72
+ tr: `# [Marka] [kategori kelimesi]
73
+
74
+ > [Marka], [girdi]yi [çıktı]ya dönüştüren bir [ürün tipi]. [En önemli fark, tek cümle].
75
+ > [Şirket adı] tarafından işletilir ([ülke]).
76
+
77
+ Temel bilgiler: [fiyat modeli, en düşük fiyat, deneme], [iptal], [kullanım sınırları].
78
+ Karıştırılmasın: [Marka], [benzer adlı ürün] değildir; [büyük şirket]in ürünü değildir.
79
+ Kanıtın sınırı: [iddianın dayandığı test ve büyüklüğü, açıkça].
80
+
81
+ ## Ürün
82
+ - [Ana sayfa](https://alanadiniz.com/): ne olduğu
83
+ - [Fiyatlar](https://alanadiniz.com/fiyatlandirma): planlar
84
+ - [Durum sayfası](https://alanadiniz.com/...): [dört parçalı cümle]
85
+
86
+ ## Rehberler
87
+ ## Karşılaştırmalar
88
+ ## Optional
89
+ - [Şartlar](...), [Gizlilik](...)`,
90
+ };
91
+ export const APPENDIX_B_NOTE = {
92
+ en: "Keep it short: the sample site's llms.txt grew to 65 KB and is being trimmed. Every figure should come from the same source as the pages.",
93
+ tr: "Kısa tutun: örnek sitenin llms.txt’si 65 KB’a çıktı, inceltilecek. Her rakam sayfalarla aynı kaynaktan gelsin.",
94
+ };
95
+ /** Appendix C — Organization JSON-LD with the not-X note. */
96
+ export const APPENDIX_C_ORG = `{
97
+ "@context": "https://schema.org",
98
+ "@type": "Organization",
99
+ "@id": "https://yourdomain.com/#org",
100
+ "name": "[Brand] [Category]",
101
+ "alternateName": ["[Brand]"],
102
+ "disambiguatingDescription": "A [category] product. Not [similarly named product]; not a [big company] product.",
103
+ "url": "https://yourdomain.com",
104
+ "logo": "https://yourdomain.com/img/logo-512.png",
105
+ "sameAs": ["https://www.youtube.com/@[channel]", "https://www.instagram.com/[account]"],
106
+ "address": { "@type": "PostalAddress", "addressCountry": "TR" }
107
+ }`;
108
+ export const APPENDIX_C_NOTE = {
109
+ en: "On every page also WebSite, BreadcrumbList and, by page type, Article (datePublished, dateModified, author), FAQPage (the real questions and answers on the page), VideoObject (if a video is embedded). Everything in the schema must also be visible on the page.",
110
+ tr: "Her sayfada ayrıca WebSite, BreadcrumbList ve sayfa tipine göre Article (datePublished, dateModified, author), FAQPage (sayfadaki gerçek soru-cevaplar), VideoObject (gömülü video varsa). Schema’daki her bilgi sayfada da görünmeli.",
111
+ };
112
+ /** Appendix D — content rules (+ the 2026 additions). */
113
+ export const CONTENT_RULES = [
114
+ { en: "The first 1–3 sentences answer the question and can be quoted on their own.", tr: "İlk 1–3 cümle soruyu cevaplar ve tek başına alıntılanabilir." },
115
+ { en: "Every claim's proof is on the page; if the proof is small, say it's small.", tr: "Her iddianın kanıtı sayfada; kanıt küçükse küçük olduğunu yazın." },
116
+ { en: "About competitors, write only what their own pages say, with the date.", tr: "Rakipler hakkında yalnızca kendi sayfalarında yazanı, tarihiyle yazın." },
117
+ { en: "Prices and features come from one source; no two pages contradict each other.", tr: "Fiyat ve özellik tek kaynaktan; iki sayfa birbiriyle çelişmesin." },
118
+ { en: "Don't call a paid product “free”; don't write headlines that imply another brand's endorsement.", tr: "Ücretli ürüne “ücretsiz” demeyin; başka markanın onayını ima eden başlık yazmayın." },
119
+ {
120
+ en: "Let AI write the draft, but don't publish until it passes a rule script (no made-up numbers, no “best / perfect”, no real people's names) and a human read. katman_lint_content is that rule script.",
121
+ tr: "Taslağı yapay zekâya yazdırın, ama bir kural betiğinden (uydurma sayı, “en iyi / mükemmel”, gerçek kişi adı yok) ve bir insan okumasından geçmeden yayınlamayın. katman_lint_content bu kural betiğidir.",
122
+ },
123
+ {
124
+ en: "Question sources: Google autocomplete (seed keyword + letter by letter), situation sentences people really ask the assistant, the pages the assistant sends people to in your analytics.",
125
+ tr: "Soru kaynağı: Google’ın otomatik tamamlaması (tohum kelime + harf harf), asistana gerçekten sorulan durum cümleleri, analitikte asistanın indirdiği sayfalar.",
126
+ },
127
+ {
128
+ en: "Watch the page mix: Perplexity took the sample site for a “template and education site” because it had ~110 template pages against 10 product pages. The mix of your pages decides what the assistant thinks you are.",
129
+ tr: "Sayfa karışımına dikkat: Perplexity örnek sitemizi “şablon ve eğitim sitesi” sandı, çünkü yaklaşık 110 şablon sayfasına karşı 10 ürün sayfası vardı. Sayfalarınızın dağılımı asistanın sizi ne sandığını belirler.",
130
+ },
131
+ {
132
+ en: "On a new domain, 5–10 pages a week. Don't grow a template whose “crawled – not indexed” rate passes 30%.",
133
+ tr: "Yeni alan adında haftada 5–10 sayfa. “Tarandı, dizine eklenmedi” oranı %30’u geçen şablonu büyütmeyin.",
134
+ },
135
+ {
136
+ en: "Put the key claim in the H1 and the first ~200 characters. Don't keyword-stuff: keyword-heavy titles and URLs get cited less.",
137
+ tr: "Asıl iddiayı H1’e ve ilk ~200 karaktere koyun. Anahtar kelime doldurmayın: anahtar kelime yüklü başlıklar ve adresler daha az alıntılanıyor.",
138
+ },
139
+ {
140
+ en: "Never show bots different content than people (cloaking), never hide instructions for AI in the page (prompt injection): Google's spam policy covers both since May 2026.",
141
+ tr: "Botlara insanlardan farklı içerik göstermeyin (cloaking), sayfaya yapay zekâ için gizli talimat koymayın (prompt enjeksiyonu): Google’ın spam politikası Mayıs 2026’dan beri ikisini de kapsıyor.",
142
+ },
143
+ {
144
+ en: "Real freshness only: update the facts and show the date; faking dates is manipulation.",
145
+ tr: "Yalnızca gerçek tazelik: bilgiyi güncelleyin, tarihi gösterin; tarih uydurmak manipülasyondur.",
146
+ },
147
+ ];
148
+ /** Appendix E — the full site audit checklist (what the crawl script checks). */
149
+ export const SITE_AUDIT_CHECKLIST = {
150
+ perUrl: [
151
+ { en: "Status 200 (no redirect), content-type text/html", tr: "Durum 200 (yönlendirme yok), content-type text/html" },
152
+ { en: "No noindex in meta robots or X-Robots-Tag (special pages should have it)", tr: "meta robots’ta ve X-Robots-Tag’de noindex yok (özel sayfalarda olmalı)" },
153
+ { en: "<title> present, unique, not longer than 60–65 characters", tr: "<title> var, benzersiz, 60–65 karakteri geçmiyor" },
154
+ { en: "Meta description present, unique, 70–160 characters", tr: "Meta açıklama var, benzersiz, 70–160 karakter" },
155
+ { en: "One H1, no heading level skips (h1 → h2 → h3)", tr: "Tek H1, başlık seviyesi atlaması yok (h1 → h2 → h3)" },
156
+ { en: "One absolute, self-referencing canonical", tr: "Tek, mutlak, kendini gösteren canonical" },
157
+ { en: "Reciprocal hreflang pairs, an x-default, a correct <html lang>", tr: "hreflang çiftleri karşılıklı, x-default var, <html lang> doğru" },
158
+ { en: "JSON-LD parses; the expected types are there", tr: "JSON-LD ayrıştırılabiliyor, beklenen tipler var" },
159
+ { en: "og:title, og:description, og:image (with width, height, alt), og:url, og:locale, twitter:card", tr: "og:title, og:description, og:image (width, height, alt ile), og:url, og:locale, twitter:card" },
160
+ { en: "Every <img> has alt, width and height; lazy below the fold; a modern format", tr: "Bütün <img>’lerde alt, width ve height; ekranın altındaysa lazy; modern format" },
161
+ { en: "No http:// resources (mixed content)", tr: "http:// kaynak yok (karışık içerik)" },
162
+ { en: "URL: lowercase, hyphens, ASCII, short, no trailing /", tr: "URL: küçük harf, tire, ASCII, kısa, sonda / yok" },
163
+ { en: "At least 3 internal links point to the page (no orphans)", tr: "Sayfaya gelen iç link en az 3 (yetim yok)" },
164
+ { en: "Every internal and external link on the page is 200 or a deliberate redirect", tr: "Sayfadaki bütün iç ve dış linkler 200 ya da bilinçli yönlendirme" },
165
+ { en: "Content is visible with JavaScript off (a sensible word count)", tr: "JavaScript kapalıyken içerik görünüyor (kelime sayısı makul)" },
166
+ ],
167
+ siteWide: [
168
+ { en: "http → https 301, www → bare domain 301, HSTS", tr: "http → https 301, www → yalın alan adı 301, HSTS" },
169
+ { en: "HTML, CSS and JS compressed (Content-Encoding: br or gzip)", tr: "HTML, CSS ve JS sıkıştırılmış (Content-Encoding: br ya da gzip)" },
170
+ { en: "Long caching and versioning for static files", tr: "Statik dosyalarda uzun önbellek ve sürümleme" },
171
+ { en: "robots.txt valid, with a sitemap line", tr: "robots.txt geçerli, sitemap satırı var" },
172
+ { en: "A missing page returns a real 404", tr: "Olmayan sayfa gerçek 404" },
173
+ { en: "Lighthouse mobile, 5 pages: performance ≥ 90, the others 100", tr: "Lighthouse mobil, 5 sayfa: performans ≥ 90, diğerleri 100" },
174
+ { en: "Search Console and Bing Webmaster verified, sitemap submitted, IndexNow working", tr: "Search Console ve Bing Webmaster doğrulandı, sitemap gönderildi, IndexNow çalışıyor" },
175
+ { en: "AI bots get 200 through the CDN (ch. 6)", tr: "CDN’de yapay zekâ botları 200 alıyor (06. bölüm)" },
176
+ ],
177
+ };
178
+ /** Appendix F — glossary. Terms as used in English by Katman. */
179
+ export const GLOSSARY = [
180
+ { term: { en: "GEO", tr: "GEO" }, def: { en: "Generative engine optimisation: visibility in generative engines (assistants).", tr: "Üretken motorlarda (asistanlarda) görünürlük optimizasyonu." } },
181
+ { term: { en: "AEO", tr: "AEO" }, def: { en: "Answer engine optimisation: quotable answers for direct-answer boxes and AI Overviews.", tr: "Cevap motoru optimizasyonu; doğrudan cevap kutuları ve AI Overviews için alıntılanabilir cevap." } },
182
+ { term: { en: "Read / Quote / Fit", tr: "Okunmak / Alıntılanmak / Soruya uymak" }, def: { en: "The three gates every public page must pass: bots can read it, the assistant can quote its first sentences, and it fits the situation the customer describes.", tr: "Her herkese açık sayfanın geçmesi gereken üç kapı: botlar okuyabilir, asistan ilk cümlelerini alıntılayabilir, sayfa müşterinin anlattığı duruma uyar." } },
183
+ { term: { en: "Situation page", tr: "Durum sayfası" }, def: { en: "A page written for one concrete situation a user describes to the assistant, answering in the first sentence.", tr: "Kullanıcının asistana anlattığı somut bir duruma yazılmış, ilk cümlede cevap veren sayfa." } },
184
+ { term: { en: "The one sentence", tr: "Tek cümle" }, def: { en: "The brand's four-part description (brings → we do → gets → fear is unnecessary), word for word the same on the page, in the meta description and in llms.txt.", tr: "Markanın dört parçalı tanımı (getirir → yaparız → eline geçer → korku gereksiz); sayfada, meta açıklamada ve llms.txt’de kelimesi kelimesine aynı." } },
185
+ { term: { en: "Not-X note", tr: "“X değildir” notu" }, def: { en: "A plain statement of what the brand is not confused with (llms.txt, About, FAQ, Organization disambiguatingDescription).", tr: "Markanın neyle karıştırılmaması gerektiğini açıkça söyleyen cümle (llms.txt, Hakkımızda, SSS, Organization disambiguatingDescription)." } },
186
+ { term: { en: "Question set", tr: "Soru seti" }, def: { en: "12 unbranded questions + 2 diagnostic ones, asked the same way every 14 days.", tr: "12 markasız soru + 2 teşhis sorusu; 14 günde bir aynı şekilde sorulur." } },
187
+ { term: { en: "OAI-SearchBot", tr: "OAI-SearchBot" }, def: { en: "The bot that fills ChatGPT's search index (doesn't run JavaScript).", tr: "ChatGPT’nin arama dizinini dolduran bot (JavaScript çalıştırmaz)." } },
188
+ { term: { en: "GPTBot", tr: "GPTBot" }, def: { en: "OpenAI's training-data bot.", tr: "OpenAI’ın eğitim verisi botu." } },
189
+ { term: { en: "ChatGPT-User, Claude-User", tr: "ChatGPT-User, Claude-User" }, def: { en: "Agents that open a page on the user's behalf during a chat.", tr: "Sohbet sırasında kullanıcı adına sayfa açan ajan." } },
190
+ { term: { en: "ClaudeBot, Claude-SearchBot", tr: "ClaudeBot, Claude-SearchBot" }, def: { en: "Anthropic's training bot and search bot.", tr: "Anthropic’in eğitim botu ve arama botu." } },
191
+ { term: { en: "llms.txt", tr: "llms.txt" }, def: { en: "A short Markdown summary of the site for language models (llmstxt.org).", tr: "Sitenin dil modelleri için kısa Markdown özeti (llmstxt.org)." } },
192
+ { term: { en: "IndexNow", tr: "IndexNow" }, def: { en: "A protocol that tells search engines about changed URLs instantly.", tr: "Değişen adresleri arama motorlarına anında bildiren protokol." } },
193
+ { term: { en: "hreflang", tr: "hreflang" }, def: { en: "The tag linking a page's language and region versions.", tr: "Bir sayfanın dil ve bölge sürümlerini birbirine bağlayan etiket." } },
194
+ { term: { en: "Canonical", tr: "Canonical" }, def: { en: "The preferred URL of a piece of content.", tr: "Bir içeriğin tercih edilen adresi." } },
195
+ { term: { en: "lastmod", tr: "lastmod" }, def: { en: "A page's last real change date in the sitemap.", tr: "Sitemap’te sayfanın son gerçek değişiklik tarihi." } },
196
+ { term: { en: "Entity", tr: "Varlık (entity)" }, def: { en: "What search engines and models recognise as “who/what is this”: name, definition, distinction.", tr: "Arama motorunun ve modellerin “bu kim, ne” diye tanıdığı şey: ad, tanım, ayrım." } },
197
+ { term: { en: "Human filter", tr: "İnsan filtresi" }, def: { en: "A behaviour rule that separates bots from people in analytics.", tr: "Botları analitikten ayıran davranış kuralı." } },
198
+ { term: { en: "Facade", tr: "Kapak (facade)" }, def: { en: "An embed that is just an image until clicked, then loads the real player.", tr: "Tıklanana kadar yalnızca resim olan, tıklanınca gerçek oynatıcıyı yükleyen gömme." } },
199
+ { term: { en: "CWV", tr: "CWV" }, def: { en: "Core Web Vitals: LCP (largest content), CLS (shift), INP (interaction).", tr: "Core Web Vitals: LCP (en büyük içerik), CLS (kayma), INP (etkileşim)." } },
200
+ { term: { en: "Soft 404", tr: "Sahte 404 (soft 404)" }, def: { en: "A page that says “page not found” but returns a 200 status code.", tr: "“Sayfa yok” diyen ama 200 durum kodu dönen sayfa." } },
201
+ { term: { en: "Training / search / user bot", tr: "Eğitim / arama / kullanıcı botu" }, def: { en: "Bots that collect pages to train models, fill an assistant's search index, and open pages during a chat (ch. 6).", tr: "Model eğitmek için toplayan, asistanın arama dizinini dolduran ve sohbet sırasında sayfa açan botlar (06. bölüm)." } },
202
+ ];
@@ -0,0 +1,192 @@
1
+ export const CF_INTRO = {
2
+ en: "If a CDN such as Cloudflare sits in front of your site, bots pass its rules before they ever reach your robots.txt. robots.txt is a request; the CDN's decision is the door. If a bot gets a 403, whatever robots.txt says no longer matters.",
3
+ tr: "Sitenizin önünde Cloudflare gibi bir CDN varsa, botlar robots.txt’nize ulaşmadan önce onun kurallarından geçer. robots.txt bir rica; CDN’in kararı kapıdır. Bir bot 403 alırsa robots.txt’de ne yazdığının hiçbir önemi kalmaz.",
4
+ };
5
+ export const BOT_TYPES = [
6
+ {
7
+ key: "training",
8
+ name: { en: "Training", tr: "Eğitim" },
9
+ what: { en: "Collects pages to train models.", tr: "Model eğitmek için sayfa toplar." },
10
+ bots: ["GPTBot", "ClaudeBot", "CCBot", "Bytespider"],
11
+ ifBlocked: {
12
+ en: "Future models can't learn about you from your site. According to OpenAI, blocking GPTBot doesn't affect ChatGPT search: “each setting is independent of the others”.",
13
+ tr: "Gelecek modeller sizi sitenizden öğrenemez. OpenAI’a göre GPTBot’u engellemek ChatGPT aramasını etkilemez: “her ayar diğerlerinden bağımsız”.",
14
+ },
15
+ },
16
+ {
17
+ key: "search",
18
+ name: { en: "Search", tr: "Arama" },
19
+ what: {
20
+ en: "Fills the assistant's search index; the pages shown in an answer are chosen from here.",
21
+ tr: "Asistanın arama dizinini doldurur; cevapta hangi sayfaların gösterileceği buradan seçilir.",
22
+ },
23
+ bots: ["OAI-SearchBot", "Claude-SearchBot", "PerplexityBot"],
24
+ ifBlocked: {
25
+ en: "You don't appear in the assistant's search. OpenAI: a site that blocks OAI-SearchBot isn't shown in ChatGPT search answers (it may appear only as a bare link).",
26
+ tr: "Asistanın aramasında çıkmazsınız. OpenAI: OAI-SearchBot’u engelleyen site ChatGPT arama cevaplarında gösterilmez (yalnızca adres linki olarak çıkabilir).",
27
+ },
28
+ },
29
+ {
30
+ key: "user",
31
+ name: { en: "User (agent)", tr: "Kullanıcı (ajan)" },
32
+ what: {
33
+ en: "Opens a page during a chat because the user asked for it.",
34
+ tr: "Sohbet sırasında, kullanıcı istediği için sayfayı açar.",
35
+ },
36
+ bots: ["ChatGPT-User", "Claude-User", "Perplexity-User"],
37
+ ifBlocked: {
38
+ en: "When a user gives the assistant your link, it can't read your page. OpenAI writes that robots.txt rules may not apply to this bot.",
39
+ tr: "Kullanıcı linkinizi verdiğinde asistan sayfanızı okuyamaz. OpenAI bu bot için robots.txt kurallarının geçerli olmayabileceğini yazıyor.",
40
+ },
41
+ },
42
+ ];
43
+ export const PERMISSION_TOKENS_NOTE = {
44
+ en: "Google-Extended and Applebot-Extended aren't bots but permission names used in robots.txt: they have no crawler of their own (Google and Apple docs), so testing them with a user-agent shows nothing. Googlebot, Bingbot and Applebot are used for both search and training — which is why the Cloudflare change below matters. Note: Google-Extended also controls Gemini grounding; blocking it removes you from Gemini answers (not from Google Search).",
45
+ tr: "Google-Extended ve Applebot-Extended bot değil, robots.txt’de kullanılan izin adlarıdır: ayrı bir tarayıcıları yok (Google ve Apple belgeleri). Onları user-agent ile test etmek bir şey göstermez. Googlebot, Bingbot ve Applebot ise hem arama hem eğitim için kullanılıyor; aşağıdaki Cloudflare değişikliği bu yüzden önemli. Not: Google-Extended Gemini’nin kaynak göstermesini (grounding) de yönetir; engellerseniz Gemini cevaplarından çıkarsınız (Google aramasından değil).",
46
+ };
47
+ export const CF_SETTINGS = [
48
+ {
49
+ name: { en: "Block AI bots (legacy toggle)", tr: "Block AI bots (eski düğme)" },
50
+ api: "ai_bots_protection",
51
+ what: {
52
+ en: "Blocks verified training bots and some unverified bots that look like them. Options: off, on every page, only on pages with ads (ad detection is per domain). Cloudflare marked this toggle for removal on 15 September 2026.",
53
+ tr: "Doğrulanmış eğitim botlarını ve onlara benzeyen bazı doğrulanmamış botları engeller. Seçenekler: kapalı, her sayfada, yalnızca reklamlı sayfalarda (reklam tespiti alan adı bazında). Cloudflare bu düğmeyi 15 Eylül 2026’da kaldırılacak diye işaretledi.",
54
+ },
55
+ recommendation: { en: "Off. Choose the policy settings below deliberately instead.", tr: "Kapalı. Yerine aşağıdaki politika ayarını bilerek seçin." },
56
+ },
57
+ {
58
+ name: { en: "AI bot policies (Training / Search / Agent)", tr: "AI bot politikaları (Eğitim / Arama / Ajan)" },
59
+ api: "ai_training, ai_search, ai_user",
60
+ what: {
61
+ en: "A separate choice per type: block on every page, block on pages with ads, or allow.",
62
+ tr: "Her tür için ayrı seçim: her sayfada engelle, reklamlı sayfalarda engelle ya da izin ver.",
63
+ },
64
+ recommendation: { en: "Search and Agent: allow. Training: your business decision (below).", tr: "Arama ve Ajan: izin ver. Eğitim: iş kararınız (aşağıda)." },
65
+ },
66
+ {
67
+ name: { en: "Managed robots.txt", tr: "Yönetilen robots.txt" },
68
+ what: {
69
+ en: "Prepends Cloudflare's block to your own robots.txt: ai-train=no and Disallow: / for GPTBot, ClaudeBot, CCBot, Bytespider, Google-Extended, Applebot-Extended, Amazonbot and meta-externalagent.",
70
+ tr: "Kendi robots.txt’nizin önüne Cloudflare’in bloğunu ekler: ai-train=no ve GPTBot, ClaudeBot, CCBot, Bytespider, Google-Extended, Applebot-Extended, Amazonbot, meta-externalagent için Disallow: /.",
71
+ },
72
+ recommendation: { en: "Off; write your own robots.txt (appendix A).", tr: "Kapalı; kendi robots.txt’nizi yazın (Ek A)." },
73
+ },
74
+ {
75
+ name: { en: "AI Labyrinth", tr: "AI Labyrinth" },
76
+ what: {
77
+ en: "Adds hidden links to pages to keep rule-breaking crawlers busy in an “endless link labyrinth”; it doesn't block.",
78
+ tr: "Sayfalara gizli linkler koyup kuralsız tarayıcıları “bitmeyen bir link labirentinde” oyalar; engellemez.",
79
+ },
80
+ recommendation: { en: "Off: it adds nothing to GEO.", tr: "Kapalı: GEO’ya katkısı yok." },
81
+ },
82
+ {
83
+ name: { en: "AI Crawl Control (formerly AI Audit)", tr: "AI Crawl Control (eski adı AI Audit)" },
84
+ what: {
85
+ en: "Shows how much each AI bot visits; blocking a bot here creates a WAF rule. On the free plan bots are recognised by user-agent only. “Pay per crawl” is in closed beta.",
86
+ tr: "Hangi yapay zekâ botunun ne kadar geldiğini gösterir; bir botu buradan engellemek bir WAF kuralı oluşturur. Ücretsiz planda botlar yalnızca user-agent’tan tanınır. “Taramaya ücret” (pay per crawl) kapalı betada.",
87
+ },
88
+ recommendation: { en: "Turn it on for read-only monitoring; don't block.", tr: "Salt okunur izleme için açın; engellemeyin." },
89
+ },
90
+ {
91
+ name: { en: "Bot Fight Mode", tr: "Bot Fight Mode" },
92
+ what: {
93
+ en: "Shows a challenge to unverified bots; WAF rules can't bypass it.",
94
+ tr: "Doğrulanmamış botlara meydan okuma (challenge) gösterir; WAF kurallarıyla atlanamaz.",
95
+ },
96
+ recommendation: { en: "If you see it leaving bots at the door, turn it off.", tr: "Botları kapıda bıraktığını görürseniz kapatın." },
97
+ },
98
+ {
99
+ name: { en: "Email obfuscation", tr: "E-posta gizleme" },
100
+ what: { en: "Hides e-mail addresses on the page with JavaScript.", tr: "Sayfadaki e-posta adresini JavaScript’le gizler." },
101
+ recommendation: {
102
+ en: "Off: bots and assistants should be able to read your address as text.",
103
+ tr: "Kapalı: bot ve asistan adresinizi metin olarak okuyabilsin.",
104
+ },
105
+ },
106
+ ];
107
+ export const CF_DEFAULT_CHANGES = [
108
+ {
109
+ en: "July 2025: every domain newly added to Cloudflare is asked during setup whether to allow AI bots. Someone clicking quickly through setup may miss this question.",
110
+ tr: "Temmuz 2025: Cloudflare’e yeni eklenen her alan adına, kurulum sırasında yapay zekâ botlarına izin verip vermeyeceği soruluyor. Kurulumu hızlı geçen biri bu soruya dikkat etmeyebilir.",
111
+ },
112
+ {
113
+ en: "15 September 2026 (announced 1 July 2026): on new domains, Training and Agent bots start blocked on pages with ads, and Search bots start allowed.",
114
+ tr: "15 Eylül 2026 (1 Temmuz 2026’da duyuruldu): yeni alan adlarında Eğitim ve Ajan botları reklamlı sayfalarda engelli, Arama botları açık başlıyor.",
115
+ },
116
+ {
117
+ en: "Same announcement: anyone blocking training (legacy toggle included) will also block bots that work for both search and training; Cloudflare names Googlebot, Applebot and Bingbot as examples. There was an opt-out before 15 September. ANNOUNCEMENT: we found no record confirming it took effect — but if it did, leaving the legacy toggle on may also affect Google and Bing.",
118
+ tr: "Aynı duyuruda: eğitimi engelleyen herkes (eski düğme dahil), hem arama hem eğitim için çalışan botları da engelleyecek; Cloudflare örnek olarak Googlebot, Applebot ve Bingbot’u sayıyor. 15 Eylül’den önce vazgeçme (opt-out) hakkı vardı. DUYURU: bunun devreye girdiğini doğrulayan bir kayıt bulamadık; ama doğruysa eski düğmeyi açık bırakmak Google’ı ve Bing’i de etkileyebilir.",
119
+ },
120
+ ];
121
+ export const CF_OUR_SITE = [
122
+ {
123
+ en: "30 Aug 2026: the first version of our audit tool found a CRITICAL issue on our own site: Cloudflare's managed robots.txt was silently closing GPTBot, ClaudeBot, Google-Extended, CCBot and Bytespider. We turned it off.",
124
+ tr: "30 Ağu 2026: denetim aracımızın ilk sürümü kendi sitemizde KRİTİK buldu: Cloudflare’in yönetilen robots.txt’si GPTBot, ClaudeBot, Google-Extended, CCBot ve Bytespider’ı sessizce kapatıyordu. Kapattık.",
125
+ },
126
+ {
127
+ en: "29 Sep 2026: retested while writing the book. Our robots.txt allowed GPTBot, but the legacy “Block AI bots” toggle was on in “only on pages with ads” mode and the AI training policy was “disallow”. Our site has no ads; training bots still got 403 on every page. The four blocked bots match Cloudflare's “AI Crawler” list exactly. We turned the legacy toggle off the same day; Cloudflare then set the training policy to “disabled” by itself, so “disallow” was a trace of the legacy toggle, not a separate decision. 20 seconds later all ten bots got 200.",
128
+ tr: "29 Eyl 2026: kitabı yazarken yeniden test ettik. robots.txt’miz GPTBot’a izin veriyordu, ama eski “Block AI bots” düğmesi “yalnızca reklamlı sayfalarda” konumunda açık, AI eğitim politikası da “disallow” idi. Sitemizde reklam yok; buna rağmen eğitim botları her sayfada 403 alıyordu. Engellenen dört bot, Cloudflare’in “AI Crawler” listesiyle birebir aynı. Eski düğmeyi aynı gün kapattık; Cloudflare eğitim politikasını da kendiliğinden “disabled” yaptı, yani “disallow” ayrı bir karar değil, eski düğmenin iziydi. 20 saniye sonra on botun onu da 200 aldı.",
129
+ },
130
+ ];
131
+ export const CF_BEFORE_AFTER = [
132
+ { bot: "GPTBot", category: "AI Crawler (training)", before: 403, after: 200 },
133
+ { bot: "ClaudeBot", category: "AI Crawler (training)", before: 403, after: 200 },
134
+ { bot: "CCBot", category: "AI Crawler (training)", before: 403, after: 200 },
135
+ { bot: "Bytespider", category: "AI Crawler (training)", before: 403, after: 200 },
136
+ { bot: "OAI-SearchBot", category: "AI Search", before: 200, after: 200 },
137
+ { bot: "Claude-SearchBot", category: "AI Search", before: 200, after: 200 },
138
+ { bot: "PerplexityBot", category: "AI Search", before: 200, after: 200 },
139
+ { bot: "ChatGPT-User", category: "AI Assistant (user)", before: 200, after: 200 },
140
+ { bot: "Claude-User", category: "AI Assistant (user)", before: 200, after: 200 },
141
+ { bot: "Perplexity-User", category: "AI Assistant (user)", before: 200, after: 200 },
142
+ ];
143
+ export const CF_CHECK_COMMAND = `# Status code for each bot. 403 = blocked at the door. (Spoofing the user-agent only shows user-agent-based rules;
144
+ # you can't impersonate IP-verified bots such as Googlebot: check Search Console for those.)
145
+ for b in GPTBot/1.2 ClaudeBot/1.0 CCBot/2.0 OAI-SearchBot/1.0 Claude-SearchBot/1.0 PerplexityBot/1.0 ChatGPT-User/1.0 Claude-User/1.0; do
146
+ printf "%-22s %s\\n" "$b" "$(curl -s -o /dev/null -w '%{http_code}' -A "Mozilla/5.0 (compatible; $b)" {site_url}/)"; done`;
147
+ export const CF_WHERE_TO_LOOK = [
148
+ {
149
+ en: "Cloudflare dashboard → Security → Analytics → Events: which request was blocked by which rule (on the free plan, a sampled log of the last 24 hours).",
150
+ tr: "Cloudflare paneli → Security → Analytics → Events: hangi isteğin hangi kuralla engellendiği (ücretsiz planda son 24 saatin örneklenmiş kaydı).",
151
+ },
152
+ { en: "AI Crawl Control → Metrics: AI bot requests and status codes.", tr: "AI Crawl Control → Metrics: yapay zekâ botlarının istekleri ve durum kodları." },
153
+ {
154
+ en: "Search Console → Settings → Crawl stats → By response: the 403 and “other 4xx” responses Googlebot got, with URL and date.",
155
+ tr: "Search Console → Ayarlar → Tarama istatistikleri → Yanıta göre: Googlebot’un aldığı 403 ve “diğer 4xx” yanıtları, adres ve tarihiyle.",
156
+ },
157
+ {
158
+ en: "Your own server logs: search for the bot names. If they never appear, your door may be closed (ch. 15).",
159
+ tr: "Kendi sunucu kayıtlarınız: bot adlarını arayın. Hiç görünmüyorlarsa kapınız kapalı olabilir (15. bölüm).",
160
+ },
161
+ ];
162
+ export const TRAINING_DECISION = {
163
+ allow: {
164
+ en: "If you allow it: models can learn you in your own words, and an assistant may know your name even when it answers without looking at the web. The sample site chose this: ai-train=yes in robots.txt, every block off on Cloudflare. In the first week ClaudeBot made 578 requests, GPTBot 362.",
165
+ tr: "İzin verirseniz: modeller sizi kendi cümlelerinizle öğrenebilir; asistan web’e bakmadan cevap verdiğinde de adınızı bilebilir. Örnek site bunu seçti: robots.txt’de ai-train=yes, Cloudflare’de bütün engeller kapalı. İlk haftada ClaudeBot 578, GPTBot 362 istek yaptı.",
166
+ },
167
+ block: {
168
+ en: "If you block it: your content stays out of training data. It doesn't stop you appearing in ChatGPT search (OpenAI). A sensible choice for publishers and paid-content sellers.",
169
+ tr: "Engellerseniz: içeriğiniz eğitim verisine girmez. ChatGPT aramasında görünmeyi engellemez (OpenAI). Yayıncılar ve ücretli içerik satanlar için mantıklı bir seçim olabilir.",
170
+ },
171
+ conditions: {
172
+ en: "Whichever you choose, three conditions: search and user bots must be open; robots.txt and the CDN must say the same thing; the decision must be made deliberately, not while clicking “next” on a setup screen. We couldn't measure a direct effect of training traffic on visitors from ChatGPT: the sample site's ChatGPT visitors came from pages the search bot had read.",
173
+ tr: "Hangisini seçerseniz seçin üç şart var: arama ve kullanıcı botları açık olmalı; robots.txt ile CDN aynı şeyi söylemeli; karar bilerek verilmeli, kurulum ekranında “ileri”ye basarken değil. Eğitim trafiğinin ChatGPT’den gelen ziyaretçiye doğrudan etkisini ölçemedik: örnek sitenin ChatGPT ziyaretçileri arama botunun okuduğu sayfalardan geldi.",
174
+ },
175
+ };
176
+ export const CF_FIX_STEPS = [
177
+ { en: "Cloudflare dashboard → your domain → Security → Settings: turn off the “Block AI bots” toggle.", tr: "Cloudflare paneli → alan adınız → Security → Settings: “Block AI bots” düğmesini kapatın." },
178
+ { en: "In the same place, AI bot policies: “allow” for Search and Agent; decide on Training.", tr: "Aynı yerde AI bot politikaları: Arama ve Ajan için “izin ver”; Eğitim için kararınızı verin." },
179
+ {
180
+ en: "Managed robots.txt, AI Labyrinth and, if needed, Bot Fight Mode: off. Email Address Obfuscation: off.",
181
+ tr: "“Yönetilen robots.txt”, AI Labyrinth ve gerekirse Bot Fight Mode: kapalı. E-posta gizleme (Email Address Obfuscation): kapalı.",
182
+ },
183
+ { en: "Run the check command again; OpenAI says changes take about 24 hours to take effect.", tr: "Kontrol komutunu tekrar çalıştırın; OpenAI değişikliklerin yaklaşık 24 saatte yansıdığını yazıyor." },
184
+ {
185
+ en: "Developers: the same settings are in the API — PUT /zones/<zone>/bot_management with ai_bots_protection: \"disabled\" and ai_training according to your training decision.",
186
+ tr: "Geliştiriciyseniz aynı ayarlar API’de: PUT /zones/<zone>/bot_management ile ai_bots_protection: \"disabled\" ve eğitim kararınıza göre ai_training.",
187
+ },
188
+ ];
189
+ export const CF_EXERCISE = {
190
+ en: "Run the check command on your own site. Write every bot that gets 403 into research and note next to it “deliberate?”. If it isn't deliberate, fix it today.",
191
+ tr: "Kontrol komutunu kendi sitenizde çalıştırın. 403 alan her botu research.md’ye yazın ve karşısına “bilerek mi?” diye not düşün. Bilerek değilse bugün düzeltin.",
192
+ };