@aglyn/plugins-ai 1.0.0-beta.288 → 1.0.0-beta.290

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 (92) hide show
  1. package/package.json +17 -17
  2. package/src/lib/activity/ai-activity-actions.d.ts +3 -2
  3. package/src/lib/activity/ai-activity-actions.js +3 -0
  4. package/src/lib/activity/ai-activity-actions.js.map +1 -1
  5. package/src/lib/components/ai-job-requests.d.ts +2 -0
  6. package/src/lib/components/ai-job-requests.js +2 -0
  7. package/src/lib/components/ai-job-requests.js.map +1 -1
  8. package/src/lib/components/ai-site-build-page.component.js +4 -0
  9. package/src/lib/components/ai-site-build-page.component.js.map +1 -1
  10. package/src/lib/components/ai-site-import-job.component.d.ts +6 -1
  11. package/src/lib/components/ai-site-import-job.component.js +124 -17
  12. package/src/lib/components/ai-site-import-job.component.js.map +1 -1
  13. package/src/lib/components/ai-site-import-start.component.d.ts +6 -0
  14. package/src/lib/components/ai-site-import-start.component.js +18 -4
  15. package/src/lib/components/ai-site-import-start.component.js.map +1 -1
  16. package/src/lib/components/ai-site-start-card.component.js +2 -1
  17. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  18. package/src/lib/jobs/ai-image-reads.d.ts +20 -2
  19. package/src/lib/jobs/ai-image-reads.js +47 -0
  20. package/src/lib/jobs/ai-image-reads.js.map +1 -1
  21. package/src/lib/jobs/ai-job-import-step.d.ts +53 -3
  22. package/src/lib/jobs/ai-job-import-step.js +386 -64
  23. package/src/lib/jobs/ai-job-import-step.js.map +1 -1
  24. package/src/lib/jobs/ai-job-layout-language.d.ts +33 -0
  25. package/src/lib/jobs/ai-job-layout-language.js +75 -1
  26. package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
  27. package/src/lib/jobs/ai-job-layout-step.js +8 -3
  28. package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
  29. package/src/lib/jobs/ai-job-page-language.d.ts +29 -0
  30. package/src/lib/jobs/ai-job-page-language.js +178 -2
  31. package/src/lib/jobs/ai-job-page-language.js.map +1 -1
  32. package/src/lib/jobs/ai-job-page-step.js +3 -0
  33. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  34. package/src/lib/jobs/ai-site-import-document.d.ts +117 -0
  35. package/src/lib/jobs/ai-site-import-document.js +710 -0
  36. package/src/lib/jobs/ai-site-import-document.js.map +1 -0
  37. package/src/lib/jobs/ai-site-import-look.d.ts +112 -0
  38. package/src/lib/jobs/ai-site-import-look.js +402 -0
  39. package/src/lib/jobs/ai-site-import-look.js.map +1 -0
  40. package/src/lib/jobs/ai-site-import-publish.d.ts +41 -0
  41. package/src/lib/jobs/ai-site-import-publish.js +92 -0
  42. package/src/lib/jobs/ai-site-import-publish.js.map +1 -0
  43. package/src/lib/jobs/ai-theme-brand-inputs.d.ts +27 -2
  44. package/src/lib/jobs/ai-theme-brand-inputs.js +37 -8
  45. package/src/lib/jobs/ai-theme-brand-inputs.js.map +1 -1
  46. package/src/lib/layout-language/ai-layout-frame.d.ts +17 -0
  47. package/src/lib/layout-language/ai-layout-frame.js +73 -2
  48. package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
  49. package/src/lib/layout-language/ai-layout-language.d.ts +43 -0
  50. package/src/lib/layout-language/ai-layout-language.js +199 -0
  51. package/src/lib/layout-language/ai-layout-language.js.map +1 -1
  52. package/src/lib/model/ai-credit-estimate.d.ts +15 -0
  53. package/src/lib/model/ai-credit-estimate.js +14 -1
  54. package/src/lib/model/ai-credit-estimate.js.map +1 -1
  55. package/src/lib/model/ai-jobs.types.d.ts +13 -1
  56. package/src/lib/model/ai-jobs.types.js.map +1 -1
  57. package/src/lib/model/ai-site-import-view.d.ts +47 -3
  58. package/src/lib/model/ai-site-import-view.js +122 -20
  59. package/src/lib/model/ai-site-import-view.js.map +1 -1
  60. package/src/lib/model/ai-site-import.d.ts +232 -7
  61. package/src/lib/model/ai-site-import.js +365 -35
  62. package/src/lib/model/ai-site-import.js.map +1 -1
  63. package/src/lib/runtime/ai-doctrine-validators.d.ts +18 -0
  64. package/src/lib/runtime/ai-doctrine-validators.js +16 -5
  65. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  66. package/src/lib/runtime/ai-palette.generated.js +31 -0
  67. package/src/lib/runtime/ai-palette.generated.js.map +1 -1
  68. package/src/lib/server/ai-image-reads-route.js +24 -1
  69. package/src/lib/server/ai-image-reads-route.js.map +1 -1
  70. package/src/lib/server/ai-jobs-resume.js +7 -1
  71. package/src/lib/server/ai-jobs-resume.js.map +1 -1
  72. package/src/lib/site-import/fixtures/aglyn-com-recordings.d.ts +57 -0
  73. package/src/lib/site-import/fixtures/aglyn-com-recordings.js +172 -0
  74. package/src/lib/site-import/fixtures/aglyn-com-recordings.js.map +1 -0
  75. package/src/lib/site-import/site-import-crawl.d.ts +32 -7
  76. package/src/lib/site-import/site-import-crawl.js +133 -44
  77. package/src/lib/site-import/site-import-crawl.js.map +1 -1
  78. package/src/lib/site-import/site-import-edge-server.d.ts +31 -0
  79. package/src/lib/site-import/site-import-edge-server.js +31 -0
  80. package/src/lib/site-import/site-import-edge-server.js.map +1 -0
  81. package/src/lib/site-import/site-import-edge.d.ts +44 -0
  82. package/src/lib/site-import/site-import-edge.js +108 -0
  83. package/src/lib/site-import/site-import-edge.js.map +1 -0
  84. package/src/lib/site-import/site-import-html.d.ts +73 -3
  85. package/src/lib/site-import/site-import-html.js +332 -45
  86. package/src/lib/site-import/site-import-html.js.map +1 -1
  87. package/src/lib/site-import/site-import-images.d.ts +22 -0
  88. package/src/lib/site-import/site-import-images.js +78 -2
  89. package/src/lib/site-import/site-import-images.js.map +1 -1
  90. package/src/lib/site-import/site-import-page.d.ts +44 -2
  91. package/src/lib/site-import/site-import-page.js +116 -16
  92. package/src/lib/site-import/site-import-page.js.map +1 -1
@@ -39,8 +39,15 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
39
39
  * starts the next one but them.
40
40
  * - **The price.** An imported page is an AI page (`AI_MEASURED_IMPORT_CREDITS`,
41
41
  * about 27 credits); a wave is quoted before it starts as its pages and,
42
- * for the first, its header and footer.
43
- *=========================================*/ import { aiCreditRangeOrdered, AI_MEASURED_IMPORT_CREDITS } from "./ai-credit-estimate.js";
42
+ * for the first, its header and footer. Once the step says how each page
43
+ * is built, a page copied as it is costs its listing and a page Aglyn AI
44
+ * arranges its arrangement, and the quote names both (AGL-4083).
45
+ * - **Home first (AGL-4083).** The read's verdict (`aiSiteImportReadVerdict`)
46
+ * stops an import whose home page could not be read before anything is
47
+ * planned, quoted or spent: a site seen without its home page is not the
48
+ * site. The person is told why and checks again.
49
+ *=========================================*/ import { PLATFORM_BRAND_NAME } from "@aglyn/aglyn/app-utils/platform-brand";
50
+ import { aiCreditRangeOrdered, aiCreditRangeText, AI_MEASURED_IMPORT_CREDITS } from "./ai-credit-estimate.js";
44
51
  /** The job kind. */ export const AI_SITE_IMPORT_KIND = 'import';
45
52
  /** The input naming the proved domain the job brings in. */ export const AI_SITE_IMPORT_DOMAIN_INPUT = 'domain';
46
53
  /** The most pages one wave brings in. */ export const AI_SITE_IMPORT_WAVE_PAGES = 10;
@@ -51,12 +58,34 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
51
58
  */ export const AI_SITE_IMPORT_MAX_PAGES = 200;
52
59
  /** The fewest pages under one address prefix that make it a collection. */ export const AI_SITE_IMPORT_COLLECTION_MIN = 3;
53
60
  /** The most photos brought in from one page. */ export const AI_SITE_IMPORT_IMAGES_PER_PAGE = 8;
54
- /** The most characters of one page's text a wave keeps for its model answer. */ export const AI_SITE_IMPORT_PAGE_TEXT_MAX_CHARS = 6000;
55
- /** The most sections one imported page is planned with. */ export const AI_SITE_IMPORT_MAX_SECTIONS = 6;
61
+ /**
62
+ * The most characters of one page's text a wave keeps for the page step's
63
+ * prompt, which reads no more than this; every word is kept on the read's
64
+ * `blocks` (AGL-4083).
65
+ */ export const AI_SITE_IMPORT_PAGE_TEXT_MAX_CHARS = 6000;
66
+ /** The most sections one imported page is planned with: one for every second-level heading (AGL-4083). */ export const AI_SITE_IMPORT_MAX_SECTIONS = 24;
67
+ /** The most blocks of one page a wave's read keeps. */ export const AI_SITE_IMPORT_READ_MAX_BLOCKS = 2000;
68
+ /** The most characters of one page's blocks a wave's read keeps: a long policy is 40,000. */ export const AI_SITE_IMPORT_READ_MAX_CHARS = 120000;
69
+ /**
70
+ * The most characters of blocks the reads of one import hold at once: they
71
+ * ride the job document, which Firestore caps at 1 MiB, beside the
72
+ * inventory and the ledger. A wave's later page past it keeps what fits and
73
+ * says it was cut.
74
+ */ export const AI_SITE_IMPORT_WAVE_READ_MAX_CHARS = 400000;
75
+ /**
76
+ * A page with more words of its own than this is copied as it is, never
77
+ * arranged (AGL-4083): a policy, an article, a long story.
78
+ */ export const AI_SITE_IMPORT_PROSE_WORDS = 900;
79
+ /** The answers bot protection and firewalls turn a crawler away with: asked to sign in, refused, or told to slow down. */ export const AI_SITE_IMPORT_BLOCKED_STATUSES = new Set([
80
+ 401,
81
+ 403,
82
+ 429
83
+ ]);
56
84
  /** The most characters a section's name, a page's title or a label keeps. */ export const AI_SITE_IMPORT_LABEL_MAX_CHARS = 60;
57
85
  /** A page with fewer words than this and no photo has nothing to bring in. */ export const AI_SITE_IMPORT_MIN_WORDS = 5;
58
86
  /** The item ledger slot of the site's header and footer. */ export const AI_SITE_IMPORT_FRAME_SLOT = 'frame';
59
87
  /** The ceiling one imported page reserves: its answer pass and its listing pass, at 50 each. */ export const AI_SITE_IMPORT_PAGE_CEILING_CREDITS = 100;
88
+ /** The ceiling a page copied as it is reserves: its listing pass alone. */ export const AI_SITE_IMPORT_COPIED_CEILING_CREDITS = 50;
60
89
  /** The ceiling the header and footer reserve: one answer at 50. */ export const AI_SITE_IMPORT_FRAME_CEILING_CREDITS = 50;
61
90
  /** The most left-out pages listed by address; the rest are counted. */ export const AI_SITE_IMPORT_LEFT_OUT_LISTED = 60;
62
91
  export const AI_SITE_IMPORT_LEFT_OUT_REASONS = [
@@ -67,8 +96,171 @@ export const AI_SITE_IMPORT_LEFT_OUT_REASONS = [
67
96
  'unreadable',
68
97
  'blocked',
69
98
  'too-large',
70
- 'off-site'
99
+ 'off-site',
100
+ 'not-reached'
101
+ ];
102
+ /** The reasons that mean the page was there and AglynBot could not read it: the "could not be read" of what was found. */ export const AI_SITE_IMPORT_UNREAD_REASONS = [
103
+ 'unreadable',
104
+ 'blocked',
105
+ 'too-large',
106
+ 'not-reached'
71
107
  ];
108
+ const pathOfUrl = (url)=>{
109
+ try {
110
+ return new URL(url).pathname.replace(/\/+$/, '') || '/';
111
+ } catch (unused) {
112
+ return '';
113
+ }
114
+ };
115
+ const wordsOf = (text)=>{
116
+ var _text_match;
117
+ return ((_text_match = text.match(RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376-\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0560-\\u0588\\u05D0-\\u05EA\\u05EF-\\u05F2\\u0620-\\u064A\\u066E-\\u066F\\u0671-\\u06D3\\u06D5\\u06E5-\\u06E6\\u06EE-\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4-\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u0860-\\u086A\\u0870-\\u0887\\u0889-\\u088F\\u08A0-\\u08C9\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098C\\u098F-\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC-\\u09DD\\u09DF-\\u09E1\\u09F0-\\u09F1\\u09FC\\u0A05-\\u0A0A\\u0A0F-\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32-\\u0A33\\u0A35-\\u0A36\\u0A38-\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2-\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0-\\u0AE1\\u0AF9\\u0B05-\\u0B0C\\u0B0F-\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32-\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C-\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99-\\u0B9A\\u0B9C\\u0B9E-\\u0B9F\\u0BA3-\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58-\\u0C5A\\u0C5C-\\u0C5D\\u0C60-\\u0C61\\u0C80\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDC-\\u0CDE\\u0CE0-\\u0CE1\\u0CF1-\\u0CF2\\u0D04-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D54-\\u0D56\\u0D5F-\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32-\\u0E33\\u0E40-\\u0E46\\u0E81-\\u0E82\\u0E84\\u0E86-\\u0E8A\\u0E8C-\\u0EA3\\u0EA5\\u0EA7-\\u0EB0\\u0EB2-\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065-\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F5\\u13F8-\\u13FD\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16F1-\\u16F8\\u1700-\\u1711\\u171F-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1878\\u1880-\\u1884\\u1887-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19B0-\\u19C9\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4C\\u1B83-\\u1BA0\\u1BAE-\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1C80-\\u1C8A\\u1C90-\\u1CBA\\u1CBD-\\u1CBF\\u1CE9-\\u1CEC\\u1CEE-\\u1CF3\\u1CF5-\\u1CF6\\u1CFA\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183-\\u2184\\u2C00-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2-\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3006\\u3031-\\u3035\\u303B-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312F\\u3131-\\u318E\\u31A0-\\u31BF\\u31F0-\\u31FF\\u3400-\\u4DBF\\u4E00-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A-\\uA62B\\uA640-\\uA66E\\uA67F-\\uA69D\\uA6A0-\\uA6E5\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA7DC\\uA7F1-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA8FD-\\uA8FE\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5-\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB69\\uAB70-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40-\\uFB41\\uFB43-\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC\\u{10000}-\\u{1000B}\\u{1000D}-\\u{10026}\\u{10028}-\\u{1003A}\\u{1003C}-\\u{1003D}\\u{1003F}-\\u{1004D}\\u{10050}-\\u{1005D}\\u{10080}-\\u{100FA}\\u{10280}-\\u{1029C}\\u{102A0}-\\u{102D0}\\u{10300}-\\u{1031F}\\u{1032D}-\\u{10340}\\u{10342}-\\u{10349}\\u{10350}-\\u{10375}\\u{10380}-\\u{1039D}\\u{103A0}-\\u{103C3}\\u{103C8}-\\u{103CF}\\u{10400}-\\u{1049D}\\u{104B0}-\\u{104D3}\\u{104D8}-\\u{104FB}\\u{10500}-\\u{10527}\\u{10530}-\\u{10563}\\u{10570}-\\u{1057A}\\u{1057C}-\\u{1058A}\\u{1058C}-\\u{10592}\\u{10594}-\\u{10595}\\u{10597}-\\u{105A1}\\u{105A3}-\\u{105B1}\\u{105B3}-\\u{105B9}\\u{105BB}-\\u{105BC}\\u{105C0}-\\u{105F3}\\u{10600}-\\u{10736}\\u{10740}-\\u{10755}\\u{10760}-\\u{10767}\\u{10780}-\\u{10785}\\u{10787}-\\u{107B0}\\u{107B2}-\\u{107BA}\\u{10800}-\\u{10805}\\u{10808}\\u{1080A}-\\u{10835}\\u{10837}-\\u{10838}\\u{1083C}\\u{1083F}-\\u{10855}\\u{10860}-\\u{10876}\\u{10880}-\\u{1089E}\\u{108E0}-\\u{108F2}\\u{108F4}-\\u{108F5}\\u{10900}-\\u{10915}\\u{10920}-\\u{10939}\\u{10940}-\\u{10959}\\u{10980}-\\u{109B7}\\u{109BE}-\\u{109BF}\\u{10A00}\\u{10A10}-\\u{10A13}\\u{10A15}-\\u{10A17}\\u{10A19}-\\u{10A35}\\u{10A60}-\\u{10A7C}\\u{10A80}-\\u{10A9C}\\u{10AC0}-\\u{10AC7}\\u{10AC9}-\\u{10AE4}\\u{10B00}-\\u{10B35}\\u{10B40}-\\u{10B55}\\u{10B60}-\\u{10B72}\\u{10B80}-\\u{10B91}\\u{10C00}-\\u{10C48}\\u{10C80}-\\u{10CB2}\\u{10CC0}-\\u{10CF2}\\u{10D00}-\\u{10D23}\\u{10D4A}-\\u{10D65}\\u{10D6F}-\\u{10D85}\\u{10E80}-\\u{10EA9}\\u{10EB0}-\\u{10EB1}\\u{10EC2}-\\u{10EC7}\\u{10F00}-\\u{10F1C}\\u{10F27}\\u{10F30}-\\u{10F45}\\u{10F70}-\\u{10F81}\\u{10FB0}-\\u{10FC4}\\u{10FE0}-\\u{10FF6}\\u{11003}-\\u{11037}\\u{11071}-\\u{11072}\\u{11075}\\u{11083}-\\u{110AF}\\u{110D0}-\\u{110E8}\\u{11103}-\\u{11126}\\u{11144}\\u{11147}\\u{11150}-\\u{11172}\\u{11176}\\u{11183}-\\u{111B2}\\u{111C1}-\\u{111C4}\\u{111DA}\\u{111DC}\\u{11200}-\\u{11211}\\u{11213}-\\u{1122B}\\u{1123F}-\\u{11240}\\u{11280}-\\u{11286}\\u{11288}\\u{1128A}-\\u{1128D}\\u{1128F}-\\u{1129D}\\u{1129F}-\\u{112A8}\\u{112B0}-\\u{112DE}\\u{11305}-\\u{1130C}\\u{1130F}-\\u{11310}\\u{11313}-\\u{11328}\\u{1132A}-\\u{11330}\\u{11332}-\\u{11333}\\u{11335}-\\u{11339}\\u{1133D}\\u{11350}\\u{1135D}-\\u{11361}\\u{11380}-\\u{11389}\\u{1138B}\\u{1138E}\\u{11390}-\\u{113B5}\\u{113B7}\\u{113D1}\\u{113D3}\\u{11400}-\\u{11434}\\u{11447}-\\u{1144A}\\u{1145F}-\\u{11461}\\u{11480}-\\u{114AF}\\u{114C4}-\\u{114C5}\\u{114C7}\\u{11580}-\\u{115AE}\\u{115D8}-\\u{115DB}\\u{11600}-\\u{1162F}\\u{11644}\\u{11680}-\\u{116AA}\\u{116B8}\\u{11700}-\\u{1171A}\\u{11740}-\\u{11746}\\u{11800}-\\u{1182B}\\u{118A0}-\\u{118DF}\\u{118FF}-\\u{11906}\\u{11909}\\u{1190C}-\\u{11913}\\u{11915}-\\u{11916}\\u{11918}-\\u{1192F}\\u{1193F}\\u{11941}\\u{119A0}-\\u{119A7}\\u{119AA}-\\u{119D0}\\u{119E1}\\u{119E3}\\u{11A00}\\u{11A0B}-\\u{11A32}\\u{11A3A}\\u{11A50}\\u{11A5C}-\\u{11A89}\\u{11A9D}\\u{11AB0}-\\u{11AF8}\\u{11BC0}-\\u{11BE0}\\u{11C00}-\\u{11C08}\\u{11C0A}-\\u{11C2E}\\u{11C40}\\u{11C72}-\\u{11C8F}\\u{11D00}-\\u{11D06}\\u{11D08}-\\u{11D09}\\u{11D0B}-\\u{11D30}\\u{11D46}\\u{11D60}-\\u{11D65}\\u{11D67}-\\u{11D68}\\u{11D6A}-\\u{11D89}\\u{11D98}\\u{11DB0}-\\u{11DDB}\\u{11EE0}-\\u{11EF2}\\u{11F02}\\u{11F04}-\\u{11F10}\\u{11F12}-\\u{11F33}\\u{11FB0}\\u{12000}-\\u{12399}\\u{12480}-\\u{12543}\\u{12F90}-\\u{12FF0}\\u{13000}-\\u{1342F}\\u{13441}-\\u{13446}\\u{13460}-\\u{143FA}\\u{14400}-\\u{14646}\\u{16100}-\\u{1611D}\\u{16800}-\\u{16A38}\\u{16A40}-\\u{16A5E}\\u{16A70}-\\u{16ABE}\\u{16AD0}-\\u{16AED}\\u{16B00}-\\u{16B2F}\\u{16B40}-\\u{16B43}\\u{16B63}-\\u{16B77}\\u{16B7D}-\\u{16B8F}\\u{16D40}-\\u{16D6C}\\u{16E40}-\\u{16E7F}\\u{16EA0}-\\u{16EB8}\\u{16EBB}-\\u{16ED3}\\u{16F00}-\\u{16F4A}\\u{16F50}\\u{16F93}-\\u{16F9F}\\u{16FE0}-\\u{16FE1}\\u{16FE3}\\u{16FF2}-\\u{16FF3}\\u{17000}-\\u{18CD5}\\u{18CFF}-\\u{18D1E}\\u{18D80}-\\u{18DF2}\\u{1AFF0}-\\u{1AFF3}\\u{1AFF5}-\\u{1AFFB}\\u{1AFFD}-\\u{1AFFE}\\u{1B000}-\\u{1B122}\\u{1B132}\\u{1B150}-\\u{1B152}\\u{1B155}\\u{1B164}-\\u{1B167}\\u{1B170}-\\u{1B2FB}\\u{1BC00}-\\u{1BC6A}\\u{1BC70}-\\u{1BC7C}\\u{1BC80}-\\u{1BC88}\\u{1BC90}-\\u{1BC99}\\u{1D400}-\\u{1D454}\\u{1D456}-\\u{1D49C}\\u{1D49E}-\\u{1D49F}\\u{1D4A2}\\u{1D4A5}-\\u{1D4A6}\\u{1D4A9}-\\u{1D4AC}\\u{1D4AE}-\\u{1D4B9}\\u{1D4BB}\\u{1D4BD}-\\u{1D4C3}\\u{1D4C5}-\\u{1D505}\\u{1D507}-\\u{1D50A}\\u{1D50D}-\\u{1D514}\\u{1D516}-\\u{1D51C}\\u{1D51E}-\\u{1D539}\\u{1D53B}-\\u{1D53E}\\u{1D540}-\\u{1D544}\\u{1D546}\\u{1D54A}-\\u{1D550}\\u{1D552}-\\u{1D6A5}\\u{1D6A8}-\\u{1D6C0}\\u{1D6C2}-\\u{1D6DA}\\u{1D6DC}-\\u{1D6FA}\\u{1D6FC}-\\u{1D714}\\u{1D716}-\\u{1D734}\\u{1D736}-\\u{1D74E}\\u{1D750}-\\u{1D76E}\\u{1D770}-\\u{1D788}\\u{1D78A}-\\u{1D7A8}\\u{1D7AA}-\\u{1D7C2}\\u{1D7C4}-\\u{1D7CB}\\u{1DF00}-\\u{1DF1E}\\u{1DF25}-\\u{1DF2A}\\u{1E030}-\\u{1E06D}\\u{1E100}-\\u{1E12C}\\u{1E137}-\\u{1E13D}\\u{1E14E}\\u{1E290}-\\u{1E2AD}\\u{1E2C0}-\\u{1E2EB}\\u{1E4D0}-\\u{1E4EB}\\u{1E5D0}-\\u{1E5ED}\\u{1E5F0}\\u{1E6C0}-\\u{1E6DE}\\u{1E6E0}-\\u{1E6E2}\\u{1E6E4}-\\u{1E6E5}\\u{1E6E7}-\\u{1E6ED}\\u{1E6F0}-\\u{1E6F4}\\u{1E6FE}-\\u{1E6FF}\\u{1E7E0}-\\u{1E7E6}\\u{1E7E8}-\\u{1E7EB}\\u{1E7ED}-\\u{1E7EE}\\u{1E7F0}-\\u{1E7FE}\\u{1E800}-\\u{1E8C4}\\u{1E900}-\\u{1E943}\\u{1E94B}\\u{1EE00}-\\u{1EE03}\\u{1EE05}-\\u{1EE1F}\\u{1EE21}-\\u{1EE22}\\u{1EE24}\\u{1EE27}\\u{1EE29}-\\u{1EE32}\\u{1EE34}-\\u{1EE37}\\u{1EE39}\\u{1EE3B}\\u{1EE42}\\u{1EE47}\\u{1EE49}\\u{1EE4B}\\u{1EE4D}-\\u{1EE4F}\\u{1EE51}-\\u{1EE52}\\u{1EE54}\\u{1EE57}\\u{1EE59}\\u{1EE5B}\\u{1EE5D}\\u{1EE5F}\\u{1EE61}-\\u{1EE62}\\u{1EE64}\\u{1EE67}-\\u{1EE6A}\\u{1EE6C}-\\u{1EE72}\\u{1EE74}-\\u{1EE77}\\u{1EE79}-\\u{1EE7C}\\u{1EE7E}\\u{1EE80}-\\u{1EE89}\\u{1EE8B}-\\u{1EE9B}\\u{1EEA1}-\\u{1EEA3}\\u{1EEA5}-\\u{1EEA9}\\u{1EEAB}-\\u{1EEBB}\\u{20000}-\\u{2A6DF}\\u{2A700}-\\u{2B81D}\\u{2B820}-\\u{2CEAD}\\u{2CEB0}-\\u{2EBE0}\\u{2EBF0}-\\u{2EE5D}\\u{2F800}-\\u{2FA1D}\\u{30000}-\\u{3134A}\\u{31350}-\\u{33479}\\u0030-\\u0039\\u00B2-\\u00B3\\u00B9\\u00BC-\\u00BE\\u0660-\\u0669\\u06F0-\\u06F9\\u07C0-\\u07C9\\u0966-\\u096F\\u09E6-\\u09EF\\u09F4-\\u09F9\\u0A66-\\u0A6F\\u0AE6-\\u0AEF\\u0B66-\\u0B6F\\u0B72-\\u0B77\\u0BE6-\\u0BF2\\u0C66-\\u0C6F\\u0C78-\\u0C7E\\u0CE6-\\u0CEF\\u0D58-\\u0D5E\\u0D66-\\u0D78\\u0DE6-\\u0DEF\\u0E50-\\u0E59\\u0ED0-\\u0ED9\\u0F20-\\u0F33\\u1040-\\u1049\\u1090-\\u1099\\u1369-\\u137C\\u16EE-\\u16F0\\u17E0-\\u17E9\\u17F0-\\u17F9\\u1810-\\u1819\\u1946-\\u194F\\u19D0-\\u19DA\\u1A80-\\u1A89\\u1A90-\\u1A99\\u1B50-\\u1B59\\u1BB0-\\u1BB9\\u1C40-\\u1C49\\u1C50-\\u1C59\\u2070\\u2074-\\u2079\\u2080-\\u2089\\u2150-\\u2182\\u2185-\\u2189\\u2460-\\u249B\\u24EA-\\u24FF\\u2776-\\u2793\\u2CFD\\u3007\\u3021-\\u3029\\u3038-\\u303A\\u3192-\\u3195\\u3220-\\u3229\\u3248-\\u324F\\u3251-\\u325F\\u3280-\\u3289\\u32B1-\\u32BF\\uA620-\\uA629\\uA6E6-\\uA6EF\\uA830-\\uA835\\uA8D0-\\uA8D9\\uA900-\\uA909\\uA9D0-\\uA9D9\\uA9F0-\\uA9F9\\uAA50-\\uAA59\\uABF0-\\uABF9\\uFF10-\\uFF19\\u{10107}-\\u{10133}\\u{10140}-\\u{10178}\\u{1018A}-\\u{1018B}\\u{102E1}-\\u{102FB}\\u{10320}-\\u{10323}\\u{10341}\\u{1034A}\\u{103D1}-\\u{103D5}\\u{104A0}-\\u{104A9}\\u{10858}-\\u{1085F}\\u{10879}-\\u{1087F}\\u{108A7}-\\u{108AF}\\u{108FB}-\\u{108FF}\\u{10916}-\\u{1091B}\\u{109BC}-\\u{109BD}\\u{109C0}-\\u{109CF}\\u{109D2}-\\u{109FF}\\u{10A40}-\\u{10A48}\\u{10A7D}-\\u{10A7E}\\u{10A9D}-\\u{10A9F}\\u{10AEB}-\\u{10AEF}\\u{10B58}-\\u{10B5F}\\u{10B78}-\\u{10B7F}\\u{10BA9}-\\u{10BAF}\\u{10CFA}-\\u{10CFF}\\u{10D30}-\\u{10D39}\\u{10D40}-\\u{10D49}\\u{10E60}-\\u{10E7E}\\u{10F1D}-\\u{10F26}\\u{10F51}-\\u{10F54}\\u{10FC5}-\\u{10FCB}\\u{11052}-\\u{1106F}\\u{110F0}-\\u{110F9}\\u{11136}-\\u{1113F}\\u{111D0}-\\u{111D9}\\u{111E1}-\\u{111F4}\\u{112F0}-\\u{112F9}\\u{11450}-\\u{11459}\\u{114D0}-\\u{114D9}\\u{11650}-\\u{11659}\\u{116C0}-\\u{116C9}\\u{116D0}-\\u{116E3}\\u{11730}-\\u{1173B}\\u{118E0}-\\u{118F2}\\u{11950}-\\u{11959}\\u{11BF0}-\\u{11BF9}\\u{11C50}-\\u{11C6C}\\u{11D50}-\\u{11D59}\\u{11DA0}-\\u{11DA9}\\u{11DE0}-\\u{11DE9}\\u{11F50}-\\u{11F59}\\u{11FC0}-\\u{11FD4}\\u{12400}-\\u{1246E}\\u{16130}-\\u{16139}\\u{16A60}-\\u{16A69}\\u{16AC0}-\\u{16AC9}\\u{16B50}-\\u{16B59}\\u{16B5B}-\\u{16B61}\\u{16D70}-\\u{16D79}\\u{16E80}-\\u{16E96}\\u{16FF4}-\\u{16FF6}\\u{1CCF0}-\\u{1CCF9}\\u{1D2C0}-\\u{1D2D3}\\u{1D2E0}-\\u{1D2F3}\\u{1D360}-\\u{1D378}\\u{1D7CE}-\\u{1D7FF}\\u{1E140}-\\u{1E149}\\u{1E2F0}-\\u{1E2F9}\\u{1E4F0}-\\u{1E4F9}\\u{1E5F1}-\\u{1E5FA}\\u{1E8C7}-\\u{1E8CF}\\u{1E950}-\\u{1E959}\\u{1EC71}-\\u{1ECAB}\\u{1ECAD}-\\u{1ECAF}\\u{1ECB1}-\\u{1ECB4}\\u{1ED01}-\\u{1ED2D}\\u{1ED2F}-\\u{1ED3D}\\u{1F100}-\\u{1F10C}\\u{1FBF0}-\\u{1FBF9}]+", "gu"))) != null ? _text_match : []).length;
118
+ };
119
+ /** One verdict from what became of the home page and how much of the site was turned away. */ function readVerdictOf(home, blocked, total) {
120
+ var _ref, _ref1;
121
+ const edge = (home == null ? void 0 : home.edge) === 'vercel' ? 'vercel' : (home == null ? void 0 : home.edge) === 'cloudflare' ? 'cloudflare' : null;
122
+ const base = {
123
+ blocked,
124
+ total,
125
+ homeStatus: (_ref = home == null ? void 0 : home.status) != null ? _ref : null,
126
+ homeProblem: (_ref1 = home == null ? void 0 : home.problem) != null ? _ref1 : null,
127
+ edge
128
+ };
129
+ if (home) return _extends({
130
+ kind: home.problem === 'blocked' ? 'home-blocked' : 'home-unreadable'
131
+ }, base);
132
+ return _extends({
133
+ kind: total > 0 && blocked * 2 > total ? 'mostly-blocked' : 'ok'
134
+ }, base);
135
+ }
136
+ /** What a crawler skip of the home page means for it. */ function homeProblemOfSkip(reason, status) {
137
+ switch(reason){
138
+ case 'http-error':
139
+ return status !== undefined && AI_SITE_IMPORT_BLOCKED_STATUSES.has(status) ? 'blocked' : 'http-error';
140
+ case 'off-origin-redirect':
141
+ return 'off-site';
142
+ case 'not-html':
143
+ case 'too-large':
144
+ case 'robots':
145
+ case 'login-form':
146
+ case 'not-reached':
147
+ return reason;
148
+ default:
149
+ return 'unreachable';
150
+ }
151
+ }
152
+ /**
153
+ * The read's verdict (AGL-4083), pure over the crawl: whether the home page
154
+ * came in, and how much of the site bot protection turned away. An import
155
+ * whose verdict stops (`aiSiteImportReadStops`) plans no wave, quotes
156
+ * nothing and spends nothing: the person is told why and checks again.
157
+ */ export function aiSiteImportReadVerdict(crawled) {
158
+ var _crawled_pages_find, _skip_status, _skip_edge;
159
+ const blocked = crawled.skipped.filter((entry)=>entry.reason === 'http-error' && entry.status !== undefined && AI_SITE_IMPORT_BLOCKED_STATUSES.has(entry.status)).length;
160
+ const total = Math.max(crawled.sitemapUrls, crawled.pages.length + crawled.skipped.length);
161
+ const page = (_crawled_pages_find = crawled.pages.find((entry)=>entry.foundBy === 'home')) != null ? _crawled_pages_find : crawled.pages.find((entry)=>(entry.path.replace(/\/+$/, '') || '/') === '/');
162
+ if (page) {
163
+ const words = page.blocks.reduce((sum, block)=>{
164
+ var _block_text;
165
+ return sum + (block.kind === 'image' || block.inline ? 0 : wordsOf((_block_text = block.text) != null ? _block_text : ''));
166
+ }, 0);
167
+ const empty = words < AI_SITE_IMPORT_MIN_WORDS && page.images.length === 0;
168
+ return readVerdictOf(empty ? {
169
+ problem: 'empty',
170
+ status: null,
171
+ edge: null
172
+ } : null, blocked, total);
173
+ }
174
+ const skip = crawled.skipped.find((entry)=>pathOfUrl(entry.url) === '/');
175
+ return readVerdictOf(skip ? {
176
+ problem: homeProblemOfSkip(skip.reason, skip.status),
177
+ status: (_skip_status = skip.status) != null ? _skip_status : null,
178
+ edge: (_skip_edge = skip.edge) != null ? _skip_edge : null
179
+ } : {
180
+ problem: 'not-reached',
181
+ status: null,
182
+ edge: null
183
+ }, blocked, total);
184
+ }
185
+ /** Whether a verdict stops the import before anything is planned: its home page is not in. */ export function aiSiteImportReadStops(verdict) {
186
+ return (verdict == null ? void 0 : verdict.kind) === 'home-blocked' || (verdict == null ? void 0 : verdict.kind) === 'home-unreadable';
187
+ }
188
+ /** The review an import that stopped at its read waits under: `blocked` or `unreadable`; `null` when it goes on. */ export function aiSiteImportReadVerdictReason(verdict) {
189
+ if ((verdict == null ? void 0 : verdict.kind) === 'home-blocked') return 'blocked';
190
+ if ((verdict == null ? void 0 : verdict.kind) === 'home-unreadable') return 'unreadable';
191
+ return null;
192
+ }
193
+ /** Where a site owner lets AglynBot through, on the edges that name themselves. */ export const AI_SITE_IMPORT_EDGE_HINTS = {
194
+ vercel: 'Your site answers through Vercel: in its Firewall, under Rules, add a bypass rule for the user agent AglynBot.',
195
+ cloudflare: 'Your site answers through Cloudflare: under Security, WAF, add a custom rule that skips the checks when the user agent contains AglynBot.'
196
+ };
197
+ const NOTHING_SPENT = 'Nothing was brought in and no AI credits were used.';
198
+ /** Why the home page could not be read, inside the sentence that says so. */ function homeProblemText(verdict) {
199
+ switch(verdict.homeProblem){
200
+ case 'http-error':
201
+ return verdict.homeStatus ? `it answered with an error, ${verdict.homeStatus}` : 'it answered with an error';
202
+ case 'not-html':
203
+ return 'it did not answer with a web page';
204
+ case 'too-large':
205
+ return 'it is larger than a page can be to bring in';
206
+ case 'off-site':
207
+ return 'it sends visitors to another website';
208
+ case 'not-reached':
209
+ return 'the read ran out of time before it';
210
+ default:
211
+ return 'it did not answer';
212
+ }
213
+ }
214
+ /**
215
+ * What the person is told about the read (AGL-4083), in console words: why
216
+ * nothing was brought in and what to do, or that most of the site was turned
217
+ * away. `null` when there is nothing to say.
218
+ */ export function aiSiteImportReadVerdictMessage(verdict, domain) {
219
+ if (!verdict) return null;
220
+ if (verdict.kind === 'home-blocked') {
221
+ const others = Math.max(0, verdict.blocked - 1);
222
+ const more = others ? `, and ${others.toLocaleString('en-US')} other ${others === 1 ? 'page' : 'pages'}` : '';
223
+ const lead = `Your site’s bot protection or firewall turned AglynBot away before it could read your home page${more}. ${NOTHING_SPENT} Allow AglynBot in your site’s bot or firewall settings, then choose Check again.`;
224
+ return verdict.edge ? `${lead} ${AI_SITE_IMPORT_EDGE_HINTS[verdict.edge]}` : lead;
225
+ }
226
+ if (verdict.kind === 'home-unreadable') {
227
+ switch(verdict.homeProblem){
228
+ case 'robots':
229
+ return `Your site’s robots.txt asks AglynBot not to read your home page. ${NOTHING_SPENT} Allow AglynBot in your robots.txt, then choose Check again.`;
230
+ case 'login-form':
231
+ return `Your home page asks for a password, and pages that do are never brought in. ${NOTHING_SPENT} Open your home page to visitors, then choose Check again.`;
232
+ case 'empty':
233
+ return `No text could be read from your home page. If your site is built in a way that needs a browser to show its words, it cannot be brought in yet. ${NOTHING_SPENT}`;
234
+ default:
235
+ return `Your home page could not be read (${homeProblemText(verdict)}). ${NOTHING_SPENT} Check that ${domain} is up and answers at https://${domain}/, then choose Check again.`;
236
+ }
237
+ }
238
+ if (verdict.kind === 'mostly-blocked') {
239
+ return `${verdict.blocked.toLocaleString('en-US')} of ${verdict.total.toLocaleString('en-US')} pages were turned away by your site’s bot protection; see Not brought in.`;
240
+ }
241
+ return null;
242
+ }
243
+ /** The verdict an inventory reads from its own pages and skips, when the step did not hand it the crawl's. */ function inventoryVerdict(input) {
244
+ var _input_skippedOverflow, _input_pages_find;
245
+ const blocked = input.skipped.filter((entry)=>entry.reason === 'blocked').length;
246
+ const total = input.pages.length + input.skipped.length + Math.max(0, (_input_skippedOverflow = input.skippedOverflow) != null ? _input_skippedOverflow : 0);
247
+ const page = (_input_pages_find = input.pages.find((entry)=>entry.foundBy === 'home')) != null ? _input_pages_find : input.pages.find((entry)=>(entry.path.replace(/\/+$/, '') || '/') === '/');
248
+ if (page) {
249
+ const empty = page.words < AI_SITE_IMPORT_MIN_WORDS && page.images === 0;
250
+ return readVerdictOf(empty ? {
251
+ problem: 'empty',
252
+ status: null,
253
+ edge: null
254
+ } : null, blocked, total);
255
+ }
256
+ const skip = input.skipped.find((entry)=>pathOfUrl(entry.url) === '/');
257
+ const problem = !skip ? 'not-reached' : skip.reason === 'blocked' ? 'blocked' : skip.reason === 'robots' || skip.reason === 'login-form' || skip.reason === 'too-large' || skip.reason === 'off-site' || skip.reason === 'not-reached' || skip.reason === 'empty' ? skip.reason : 'unreachable';
258
+ return readVerdictOf({
259
+ problem,
260
+ status: null,
261
+ edge: null
262
+ }, blocked, total);
263
+ }
72
264
  /*------------------------------------------
73
265
  * Grouping and waves
74
266
  *-----------------------------------------*/ const clipLabel = (text)=>{
@@ -203,9 +395,10 @@ const segmentsOf = (path)=>String(path != null ? path : '').split('/').filter(Bo
203
395
  * The site's inventory cut into waves, every page left out said with its
204
396
  * reason. Pure: the step reads the site, this decides what comes in.
205
397
  */ export function aiSiteImportInventory(input) {
206
- var _input_wavePages, _leftOutCount_unreadable, _input_reviewId;
398
+ var _input_wavePages, _leftOutCount_unreadable, _input_verdict, _input_reviewId;
207
399
  var _waves_;
208
400
  const wavePages = Math.max(1, Math.floor((_input_wavePages = input.wavePages) != null ? _input_wavePages : AI_SITE_IMPORT_WAVE_PAGES));
401
+ const limit = input.pageLimit === null || !Number.isFinite(input.pageLimit) ? null : Math.max(0, Math.floor(input.pageLimit));
209
402
  const leftOut = [];
210
403
  const leftOutCount = {};
211
404
  const leave = (entry)=>{
@@ -213,6 +406,9 @@ const segmentsOf = (path)=>String(path != null ? path : '').split('/').filter(Bo
213
406
  leftOutCount[entry.reason] = ((_leftOutCount_entry_reason = leftOutCount[entry.reason]) != null ? _leftOutCount_entry_reason : 0) + 1;
214
407
  if (leftOut.length < AI_SITE_IMPORT_LEFT_OUT_LISTED) leftOut.push(entry);
215
408
  };
409
+ // The read asks for a wave's worth past the plan's room, so a page its page
410
+ // budget never reached is past the plan; any other stop is not the plan's.
411
+ const unreached = input.stoppedBy === 'page-budget' && limit !== null ? 'plan-limit' : 'not-reached';
216
412
  for (const skipped of input.skipped){
217
413
  let path = '/';
218
414
  try {
@@ -224,10 +420,33 @@ const segmentsOf = (path)=>String(path != null ? path : '').split('/').filter(Bo
224
420
  url: skipped.url,
225
421
  path,
226
422
  title: '',
227
- reason: skipped.reason
423
+ reason: skipped.reason === 'not-reached' ? unreached : skipped.reason
228
424
  });
229
425
  }
230
426
  if (input.skippedOverflow) leftOutCount['unreadable'] = ((_leftOutCount_unreadable = leftOutCount['unreadable']) != null ? _leftOutCount_unreadable : 0) + input.skippedOverflow;
427
+ // Home first: a site read without its home page plans nothing at all.
428
+ const verdict = (_input_verdict = input.verdict) != null ? _input_verdict : inventoryVerdict(input);
429
+ if (aiSiteImportReadStops(verdict)) {
430
+ var _input_reviewId1;
431
+ return {
432
+ domain: input.domain,
433
+ siteName: clipLabel(input.siteName) || input.domain,
434
+ ownership: input.ownership,
435
+ readAt: input.readAt,
436
+ pageLimit: limit,
437
+ existingPages: Math.max(0, input.existingPages),
438
+ found: input.pages.length,
439
+ stoppedBy: input.stoppedBy,
440
+ groups: [],
441
+ pages: [],
442
+ waves: [],
443
+ leftOut,
444
+ leftOutCount,
445
+ frame: null,
446
+ reviewId: (_input_reviewId1 = input.reviewId) != null ? _input_reviewId1 : null,
447
+ verdict
448
+ };
449
+ }
231
450
  const readable = input.pages.filter((page)=>{
232
451
  if (page.words >= AI_SITE_IMPORT_MIN_WORDS || page.images > 0) return true;
233
452
  leave({
@@ -239,7 +458,6 @@ const segmentsOf = (path)=>String(path != null ? path : '').split('/').filter(Bo
239
458
  return false;
240
459
  });
241
460
  const { groups, groupOf } = aiSiteImportGroups(readable, input.menu);
242
- const limit = input.pageLimit === null || !Number.isFinite(input.pageLimit) ? null : Math.max(0, Math.floor(input.pageLimit));
243
461
  let room = limit === null ? Number.POSITIVE_INFINITY : Math.max(0, limit - Math.max(0, input.existingPages));
244
462
  const pages = [];
245
463
  const waves = [];
@@ -311,7 +529,8 @@ const segmentsOf = (path)=>String(path != null ? path : '').split('/').filter(Bo
311
529
  frame: ((_waves_ = waves[0]) == null ? void 0 : _waves_.frame) ? {
312
530
  draftId: input.mintId()
313
531
  } : null,
314
- reviewId: (_input_reviewId = input.reviewId) != null ? _input_reviewId : null
532
+ reviewId: (_input_reviewId = input.reviewId) != null ? _input_reviewId : null,
533
+ verdict
315
534
  };
316
535
  }
317
536
  /** The item ledger an inventory starts: the header and footer, then every page, all pending. */ export function aiSiteImportLedger(state) {
@@ -346,7 +565,7 @@ const OPEN = new Set([
346
565
  }
347
566
  /** The next wave a person may start, else `null`. */ export function aiSiteImportNextWave(state) {
348
567
  var _state_waves_find;
349
- if (!state || aiSiteImportRunningWave(state)) return null;
568
+ if (!state || aiSiteImportRunningWave(state) || aiSiteImportReadStops(state.verdict)) return null;
350
569
  return (_state_waves_find = state.waves.find((wave)=>wave.status === 'waiting')) != null ? _state_waves_find : null;
351
570
  }
352
571
  /** The wave a person is reviewing, else `null`. */ export function aiSiteImportReviewWave(state) {
@@ -354,7 +573,8 @@ const OPEN = new Set([
354
573
  return (_ref = state == null ? void 0 : state.waves.find((wave)=>wave.status === 'review')) != null ? _ref : null;
355
574
  }
356
575
  /** What the next pass of the step does. */ export function aiSiteImportNextWork(state, items) {
357
- if (!state) return {
576
+ // A read that stopped at its home page reads again: the person's Check again.
577
+ if (!state || aiSiteImportReadStops(state.verdict)) return {
358
578
  kind: 'inventory'
359
579
  };
360
580
  const running = aiSiteImportRunningWave(state);
@@ -420,15 +640,62 @@ const withWave = (state, index, patch)=>_extends({}, state, {
420
640
  });
421
641
  return aiSiteImportPagesRead(next, reads);
422
642
  }
423
- /** More of a running wave's pages, read now. */ export function aiSiteImportPagesRead(state, reads) {
643
+ /** How many characters a block holds, as the job document stores it. */ export function aiSiteImportBlockChars(block) {
644
+ if (block.kind === 'image') return block.url.length + block.alt.length;
645
+ return block.text.length + (block.kind === 'link' ? block.href.length : 0);
646
+ }
647
+ /** A page's blocks in order, as many as fit `maxChars` and `maxBlocks`, and whether any had to go. */ export function aiSiteImportCapBlocks(blocks, maxChars, maxBlocks = AI_SITE_IMPORT_READ_MAX_BLOCKS) {
648
+ const kept = [];
649
+ let chars = 0;
650
+ for (const block of blocks){
651
+ const size = aiSiteImportBlockChars(block);
652
+ if (kept.length >= maxBlocks || chars + size > maxChars) return {
653
+ blocks: kept,
654
+ chars,
655
+ cut: true
656
+ };
657
+ kept.push(block);
658
+ chars += size;
659
+ }
660
+ return {
661
+ blocks: kept,
662
+ chars,
663
+ cut: false
664
+ };
665
+ }
666
+ const readChars = (read)=>{
667
+ var _ref;
668
+ return ((_ref = read == null ? void 0 : read.blocks) != null ? _ref : []).reduce((total, block)=>total + aiSiteImportBlockChars(block), 0);
669
+ };
670
+ /**
671
+ * More of a running wave's pages, read now. Their blocks share
672
+ * `AI_SITE_IMPORT_WAVE_READ_MAX_CHARS` with every read still held: a page
673
+ * past it keeps what fits, in order, and is marked `cut`.
674
+ */ export function aiSiteImportPagesRead(state, reads) {
675
+ let held = state.pages.filter((page)=>!reads.has(page.slot)).reduce((total, page)=>total + readChars(page.read), 0);
424
676
  let next = state;
425
677
  for (const [slot, read] of reads){
426
678
  var _next_pages_find;
427
- next = typeof read === 'string' ? withPage(next, slot, {
428
- refused: read,
429
- read: null
430
- }) : withPage(next, slot, {
431
- read,
679
+ if (typeof read === 'string') {
680
+ next = withPage(next, slot, {
681
+ refused: read,
682
+ read: null
683
+ });
684
+ continue;
685
+ }
686
+ let kept = read;
687
+ if (read.blocks) {
688
+ const room = Math.max(0, Math.min(AI_SITE_IMPORT_READ_MAX_CHARS, AI_SITE_IMPORT_WAVE_READ_MAX_CHARS - held));
689
+ const capped = aiSiteImportCapBlocks(read.blocks, room);
690
+ held += capped.chars;
691
+ kept = _extends({}, read, {
692
+ blocks: capped.blocks
693
+ }, capped.cut || read.cut ? {
694
+ cut: true
695
+ } : {});
696
+ }
697
+ next = withPage(next, slot, {
698
+ read: kept,
432
699
  refused: null,
433
700
  title: clipLabel(read.title) || ((_next_pages_find = next.pages.find((page)=>page.slot === slot)) == null ? void 0 : _next_pages_find.title) || ''
434
701
  });
@@ -440,12 +707,13 @@ const withWave = (state, index, patch)=>_extends({}, state, {
440
707
  photos
441
708
  });
442
709
  }
443
- /** A page is in: its text is no longer kept. */ export function aiSiteImportPageSettled(state, slot) {
710
+ /** A page is in: its text and its blocks are no longer kept. */ export function aiSiteImportPageSettled(state, slot) {
444
711
  const page = state.pages.find((entry)=>entry.slot === slot);
445
712
  if (!(page == null ? void 0 : page.read)) return state;
446
713
  return withPage(state, slot, {
447
714
  read: _extends({}, page.read, {
448
- text: ''
715
+ text: '',
716
+ blocks: []
449
717
  })
450
718
  });
451
719
  }
@@ -453,8 +721,9 @@ const withWave = (state, index, patch)=>_extends({}, state, {
453
721
  var _ref;
454
722
  var _state_waves_find;
455
723
  const later = state.waves.some((wave)=>wave.index > index && wave.status === 'waiting');
724
+ // Start every remaining wave: no review between waves, the last one's close is the stop.
456
725
  let next = withWave(state, index, {
457
- status: later ? 'review' : 'done',
726
+ status: later && !state.autoContinue ? 'review' : 'done',
458
727
  finishedAt: at
459
728
  });
460
729
  // What the wave read is no longer needed by any model answer.
@@ -467,7 +736,9 @@ const withWave = (state, index, patch)=>_extends({}, state, {
467
736
  pages: state.pages.map((page)=>page.read ? _extends({}, page, {
468
737
  read: _extends({}, page.read, {
469
738
  text: '',
470
- images: []
739
+ images: [],
740
+ blocks: [],
741
+ forms: []
471
742
  })
472
743
  }) : page)
473
744
  });
@@ -475,44 +746,103 @@ const withWave = (state, index, patch)=>_extends({}, state, {
475
746
  /*------------------------------------------
476
747
  * Credits
477
748
  *-----------------------------------------*/ /**
749
+ * How a page is built (AGL-4083), decided by code: every page of a collection
750
+ * (a blog, the legal pages, news) and any page longer than
751
+ * `AI_SITE_IMPORT_PROSE_WORDS` is copied as it is; the main pages are
752
+ * arranged by Aglyn AI, their words kept as written.
753
+ */ export function aiSiteImportPageBuild(page) {
754
+ return page.group !== 'main' || page.words > AI_SITE_IMPORT_PROSE_WORDS ? 'copied' : 'arranged';
755
+ }
756
+ const whole = (value)=>Math.max(0, Math.floor(Number.isFinite(value) ? value : 0));
757
+ /**
478
758
  * What bringing in this many pages costs, quoted before it starts (AGL-3976):
479
759
  * each page an AI page as measured, its ceiling its two passes, and the
480
- * site's header and footer once when the wave builds them.
760
+ * site's header and footer once when the wave builds them. Pages the step has
761
+ * chosen a build for (AGL-4083) are priced by it: `arranged` at the
762
+ * arrangement answer and its listing, `copied` at the listing alone.
481
763
  */ export function aiSiteImportCreditRange(pages, options = {}) {
482
- const count = Math.max(0, Math.floor(Number.isFinite(pages) ? pages : 0));
483
- const { page, frame } = AI_MEASURED_IMPORT_CREDITS;
764
+ const count = whole(pages);
765
+ const arranged = whole(options.arranged);
766
+ const copied = whole(options.copied);
767
+ const measured = AI_MEASURED_IMPORT_CREDITS;
484
768
  return aiCreditRangeOrdered({
485
- likely: count * page.median + (options.frame ? frame.median : 0),
486
- p90: count * page.p90 + (options.frame ? frame.p90 : 0),
487
- ceiling: count * AI_SITE_IMPORT_PAGE_CEILING_CREDITS + (options.frame ? AI_SITE_IMPORT_FRAME_CEILING_CREDITS : 0)
769
+ likely: count * measured.page.median + arranged * measured.arranged.median + copied * measured.copied.median + (options.frame ? measured.frame.median : 0),
770
+ p90: count * measured.page.p90 + arranged * measured.arranged.p90 + copied * measured.copied.p90 + (options.frame ? measured.frame.p90 : 0),
771
+ ceiling: (count + arranged) * AI_SITE_IMPORT_PAGE_CEILING_CREDITS + copied * AI_SITE_IMPORT_COPIED_CEILING_CREDITS + (options.frame ? AI_SITE_IMPORT_FRAME_CEILING_CREDITS : 0)
488
772
  });
489
773
  }
490
- /** A wave's quote: the pages it has still to bring in, and its header and footer while they are owed. */ export function aiSiteImportWaveCreditRange(state, wave, items) {
774
+ /** What a wave still owes, by how its pages are built, and whether its header and footer are owed. */ export function aiSiteImportWaveOwed(state, wave, items) {
491
775
  const owed = (slot)=>items ? aiSiteImportItemOpen(items, slot) : true;
492
- const pages = wave.slots.filter((slot)=>{
493
- var _state_pages_find;
494
- return owed(slot) && !((_state_pages_find = state.pages.find((page)=>page.slot === slot)) == null ? void 0 : _state_pages_find.refused);
495
- }).length;
496
- return aiSiteImportCreditRange(pages, {
776
+ const counts = {
777
+ pages: 0,
778
+ arranged: 0,
779
+ copied: 0,
497
780
  frame: wave.frame && !!state.frame && owed(AI_SITE_IMPORT_FRAME_SLOT)
781
+ };
782
+ for (const slot of wave.slots){
783
+ const page = state.pages.find((entry)=>entry.slot === slot);
784
+ if (!owed(slot) || (page == null ? void 0 : page.refused)) continue;
785
+ if ((page == null ? void 0 : page.build) === 'arranged') counts.arranged += 1;
786
+ else if ((page == null ? void 0 : page.build) === 'copied') counts.copied += 1;
787
+ else counts.pages += 1;
788
+ }
789
+ return counts;
790
+ }
791
+ /** A wave's quote: the pages it has still to bring in, and its header and footer while they are owed. */ export function aiSiteImportWaveCreditRange(state, wave, items) {
792
+ const owed = aiSiteImportWaveOwed(state, wave, items);
793
+ return aiSiteImportCreditRange(owed.pages, {
794
+ frame: owed.frame,
795
+ arranged: owed.arranged,
796
+ copied: owed.copied
498
797
  });
499
798
  }
799
+ /** Every wave still waiting, quoted at once: "Start every remaining wave" (AGL-4083). */ export function aiSiteImportRemainingCreditRange(state, items) {
800
+ const total = {
801
+ pages: 0,
802
+ arranged: 0,
803
+ copied: 0,
804
+ frame: false
805
+ };
806
+ for (const wave of state.waves){
807
+ if (wave.status !== 'waiting') continue;
808
+ const owed = aiSiteImportWaveOwed(state, wave, items);
809
+ total.pages += owed.pages;
810
+ total.arranged += owed.arranged;
811
+ total.copied += owed.copied;
812
+ total.frame = total.frame || owed.frame;
813
+ }
814
+ return aiSiteImportCreditRange(total.pages, {
815
+ frame: total.frame,
816
+ arranged: total.arranged,
817
+ copied: total.copied
818
+ });
819
+ }
820
+ /** "About 95 credits (up to 600): 7 pages arranged by Aglyn AI, 3 copied as they are"; the build is named once the step has chosen. */ export function aiSiteImportQuoteText(range, owed) {
821
+ const parts = [];
822
+ if (owed.arranged) parts.push(`${aiSiteImportPagesText(owed.arranged)} arranged by ${PLATFORM_BRAND_NAME} AI`);
823
+ if (owed.copied) parts.push(`${owed.arranged ? owed.copied.toLocaleString('en-US') : aiSiteImportPagesText(owed.copied)} copied as ${owed.copied === 1 ? 'it is' : 'they are'}`);
824
+ return parts.length ? `${aiCreditRangeText(range)}: ${parts.join(', ')}` : aiCreditRangeText(range);
825
+ }
500
826
  /*------------------------------------------
501
827
  * Words
502
828
  *-----------------------------------------*/ /** Why a page is not brought in, as a person reads it. */ export const AI_SITE_IMPORT_LEFT_OUT_COPY = {
503
829
  'plan-limit': 'Past your plan’s page count. Upgrade for more pages, then bring the rest in.',
504
830
  robots: 'The site’s robots.txt asks AglynBot not to read it.',
505
831
  'login-form': 'A sign-in page. Pages that ask for a password are never brought in.',
506
- empty: 'Nothing to bring in: the page has no text or photos.',
832
+ empty: 'No text could be read from this page. If your site is built in a way that needs a browser to show its words, it cannot be brought in yet.',
507
833
  unreadable: 'It could not be read just now.',
508
834
  blocked: 'The site’s bot protection or firewall turned AglynBot away. Allow AglynBot in your site’s bot or firewall settings, then bring the site in again.',
509
835
  'too-large': 'Larger than a page can be to bring in.',
510
- 'off-site': 'It sends visitors to another website.'
836
+ 'off-site': 'It sends visitors to another website.',
837
+ 'not-reached': 'Not reached: the read stopped before it got to this page.'
511
838
  };
512
839
  /** "3 pages" / "1 page". */ export function aiSiteImportPagesText(count) {
513
840
  return `${count.toLocaleString('en-US')} ${count === 1 ? 'page' : 'pages'}`;
514
841
  }
515
842
  /** The review a finished wave parks on, or the first wave's go-ahead once the site is read. */ export function aiSiteImportWaveMessage(state, items) {
843
+ var _aiSiteImportReadVerdictMessage;
844
+ // A read that stopped at its home page says why, and what to do.
845
+ if (aiSiteImportReadStops(state.verdict)) return (_aiSiteImportReadVerdictMessage = aiSiteImportReadVerdictMessage(state.verdict, state.domain)) != null ? _aiSiteImportReadVerdictMessage : '';
516
846
  const next = aiSiteImportNextWave(state);
517
847
  const reviewing = aiSiteImportReviewWave(state);
518
848
  if (!reviewing) {