seo 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/mcp.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createRequire as __seoCreateRequire } from 'node:module'; const require = __seoCreateRequire(import.meta.url);
2
- import { i as __toESM, n as version, r as __commonJSMin, t as load } from "./esm-CM7xTOjT.js";
2
+ import { i as __toESM, n as version, r as __commonJSMin, t as load } from "./esm-ZQwQYL0U.js";
3
3
  import { createHash, randomUUID, sign } from "node:crypto";
4
4
  import { ZodOptional, z } from "zod";
5
5
  import { arch, homedir, platform, tmpdir, totalmem } from "node:os";
@@ -26,6 +26,7 @@ import { TextDecoder as TextDecoder$1, promisify } from "node:util";
26
26
  import { execFile } from "node:child_process";
27
27
  import "pino";
28
28
  import "pino-pretty";
29
+ import { request } from "node:https";
29
30
  import * as z3rt from "zod/v3";
30
31
  import { ZodFirstPartyTypeKind } from "zod/v3";
31
32
  import * as z4mini from "zod/v4-mini";
@@ -13877,7 +13878,7 @@ async function runAnalyticsReport(gfetch, propertyId, body, options) {
13877
13878
  //#endregion
13878
13879
  //#region packages/core/dist/bing/api.js
13879
13880
  const BASE = "https://ssl.bing.com/webmaster/api.svc/json";
13880
- const MAX_BYTES$2 = 8e6;
13881
+ const MAX_BYTES$3 = 8e6;
13881
13882
  function bingCall(auth, options) {
13882
13883
  return async (method, params = {}) => {
13883
13884
  const url = new URL(`${BASE}/${method}`);
@@ -13902,7 +13903,7 @@ function bingCall(auth, options) {
13902
13903
  if (response.status === 429 || /throttle/i.test(detail)) throw new SeoError("RATE_LIMITED", "Bing Webmaster is limiting requests. Try again in a few minutes.");
13903
13904
  throw new SeoError("OPTIONAL_PROVIDER_UNAVAILABLE", `Bing Webmaster answered ${response.status}. ${detail}`.trim());
13904
13905
  }
13905
- return (await readJson(response, "Bing Webmaster", { maxBytes: MAX_BYTES$2 })).d;
13906
+ return (await readJson(response, "Bing Webmaster", { maxBytes: MAX_BYTES$3 })).d;
13906
13907
  };
13907
13908
  }
13908
13909
  function day(value) {
@@ -16763,10 +16764,12 @@ function initDb(database, isNewDatabase) {
16763
16764
  database.exec("DROP TABLE IF EXISTS provider_spend_notices");
16764
16765
  ensureColumn(database, "http_cache", "metadata_json", "TEXT");
16765
16766
  }).immediate();
16766
- runCacheMaintenance(database, {
16767
- compact: true,
16768
- allowFullVacuum: true
16769
- });
16767
+ try {
16768
+ runCacheMaintenance(database, {
16769
+ compact: true,
16770
+ allowFullVacuum: true
16771
+ });
16772
+ } catch {}
16770
16773
  }
16771
16774
  function getDb() {
16772
16775
  if (db) return db;
@@ -16777,12 +16780,41 @@ function getDb() {
16777
16780
  mode: 448
16778
16781
  });
16779
16782
  ensurePrivateDatabaseFiles(path);
16780
- db = new SqliteDatabase(path);
16781
- ensurePrivateDatabaseFiles(path);
16782
- initDb(db, isNewDatabase);
16783
- ensurePrivateDatabaseFiles(path);
16783
+ const opened = new SqliteDatabase(path);
16784
+ try {
16785
+ ensurePrivateDatabaseFiles(path);
16786
+ initDb(opened, isNewDatabase);
16787
+ ensurePrivateDatabaseFiles(path);
16788
+ } catch (error) {
16789
+ opened.close();
16790
+ throw error;
16791
+ }
16792
+ db = opened;
16784
16793
  return db;
16785
16794
  }
16795
+ let memoryDb;
16796
+ function memoryCache() {
16797
+ if (!memoryDb) {
16798
+ memoryDb = new SqliteDatabase(":memory:");
16799
+ memoryDb.exec(CREATE_SQL);
16800
+ }
16801
+ return memoryDb;
16802
+ }
16803
+ function cacheDb() {
16804
+ if (memoryDb) return memoryDb;
16805
+ try {
16806
+ return getDb();
16807
+ } catch {
16808
+ return memoryCache();
16809
+ }
16810
+ }
16811
+ function writeToCache(write) {
16812
+ try {
16813
+ write(cacheDb());
16814
+ } catch {
16815
+ memoryCache();
16816
+ }
16817
+ }
16786
16818
  function noteCacheWrite(sizeBytes = 0, database = getDb()) {
16787
16819
  const counter = cacheMaintenanceCounters.get(database) ?? {
16788
16820
  writes: 0,
@@ -16810,7 +16842,7 @@ function ga4RequestCanUseCache(body) {
16810
16842
  }
16811
16843
  async function runGa4Report(propertyId, body, opts = {}) {
16812
16844
  const { client, identity } = await createGoogleAccessTokenClient(opts.accountEmail);
16813
- const db = getDb();
16845
+ const db = cacheDb();
16814
16846
  const queryHash = hashKey([
16815
16847
  propertyId,
16816
16848
  identity,
@@ -16823,10 +16855,12 @@ async function runGa4Report(propertyId, body, opts = {}) {
16823
16855
  if (cacheable) {
16824
16856
  const requestJson = JSON.stringify(body);
16825
16857
  const responseJson = JSON.stringify(result);
16826
- db.prepare(`INSERT OR REPLACE INTO ga4_cache
16827
- (property_id, query_hash, request_json, response_json, row_count, fetched_at, expires_at)
16828
- VALUES (?, ?, ?, ?, ?, ?, ?)`).run(propertyId, queryHash, requestJson, responseJson, result.rowCount ?? result.rows?.length ?? 0, Date.now(), Date.now() + 864e5);
16829
- noteCacheWrite(Buffer.byteLength(requestJson) + Buffer.byteLength(responseJson));
16858
+ writeToCache((database) => {
16859
+ database.prepare(`INSERT OR REPLACE INTO ga4_cache
16860
+ (property_id, query_hash, request_json, response_json, row_count, fetched_at, expires_at)
16861
+ VALUES (?, ?, ?, ?, ?, ?, ?)`).run(propertyId, queryHash, requestJson, responseJson, result.rowCount ?? result.rows?.length ?? 0, Date.now(), Date.now() + 864e5);
16862
+ noteCacheWrite(Buffer.byteLength(requestJson) + Buffer.byteLength(responseJson), database);
16863
+ });
16830
16864
  }
16831
16865
  return result;
16832
16866
  }
@@ -19198,7 +19232,7 @@ async function fetchRobotsSource(origin, refresh, options) {
19198
19232
  const robotsUrl = new URL("/robots.txt", origin).toString();
19199
19233
  const key = hashKey(["robots", robotsUrl]);
19200
19234
  if (!refresh) {
19201
- const cached = getDb().prepare("SELECT status, body_blob, expires_at FROM http_cache WHERE url_hash = ?").get(key);
19235
+ const cached = cacheDb().prepare("SELECT status, body_blob, expires_at FROM http_cache WHERE url_hash = ?").get(key);
19202
19236
  if (cached?.body_blob && cached.status !== void 0 && cacheableStatus(cached.status) && cached.expires_at && cached.expires_at > Date.now()) return {
19203
19237
  robotsUrl,
19204
19238
  status: cached.status,
@@ -19217,12 +19251,12 @@ async function fetchRobotsSource(origin, refresh, options) {
19217
19251
  signal: controller.signal
19218
19252
  });
19219
19253
  const text = await readBoundedResponseText(response, MAX_ROBOTS_RESPONSE_BYTES, "robots.txt response");
19220
- if (options.writeCache !== false && cacheableStatus(response.status)) {
19221
- getDb().prepare(`INSERT OR REPLACE INTO http_cache
19222
- (url_hash, url, status, headers_json, body_blob, etag, fetched_at, expires_at)
19223
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(key, robotsUrl, response.status, "{}", Buffer.from(text), null, Date.now(), Date.now() + 864e5);
19224
- noteCacheWrite(Buffer.byteLength(text));
19225
- }
19254
+ if (options.writeCache !== false && cacheableStatus(response.status)) writeToCache((database) => {
19255
+ database.prepare(`INSERT OR REPLACE INTO http_cache
19256
+ (url_hash, url, status, headers_json, body_blob, etag, fetched_at, expires_at)
19257
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(key, robotsUrl, response.status, "{}", Buffer.from(text), null, Date.now(), Date.now() + 864e5);
19258
+ noteCacheWrite(Buffer.byteLength(text), database);
19259
+ });
19226
19260
  return {
19227
19261
  robotsUrl,
19228
19262
  status: response.status,
@@ -19329,7 +19363,6 @@ function decodePageFetchCacheEvidence(value) {
19329
19363
  }
19330
19364
  async function fetchPlain(url, refresh = false, timeoutMs = 2e4, rate, signal, respectRobots = false, writeCache = true) {
19331
19365
  const startedAt = Date.now();
19332
- const db = getDb();
19333
19366
  const key = hashKey(["page", url]);
19334
19367
  const host = new URL(url).host;
19335
19368
  let robots = respectRobots ? await fetchRobots(new URL(url).origin, url, refresh, {
@@ -19337,7 +19370,7 @@ async function fetchPlain(url, refresh = false, timeoutMs = 2e4, rate, signal, r
19337
19370
  signal
19338
19371
  }) : void 0;
19339
19372
  if (robots && robots.allowed !== true) throw new RobotsAccessError(robots.allowed === false ? "robots-disallowed" : "robots-deferred", robots);
19340
- const cached = db.prepare("SELECT status, headers_json, body_blob, metadata_json, expires_at FROM http_cache WHERE url_hash = ? AND expires_at > ?").get(key, Date.now());
19373
+ const cached = cacheDb().prepare("SELECT status, headers_json, body_blob, metadata_json, expires_at FROM http_cache WHERE url_hash = ? AND expires_at > ?").get(key, Date.now());
19341
19374
  if (!refresh && cached) {
19342
19375
  const evidence = decodePageFetchCacheEvidence(cached.metadata_json);
19343
19376
  return {
@@ -19439,12 +19472,12 @@ async function fetchPlain(url, refresh = false, timeoutMs = 2e4, rate, signal, r
19439
19472
  warnings: [...robots.allowed === null ? [`robots.txt availability is unknown${robots.status ? ` after HTTP ${robots.status}` : ""}; this fetch does not prove crawler access is allowed.`] : [], ...accessBlock ? [`${accessBlock.guidance.summary} Identify the crawler as ${accessBlock.crawler.userAgent}.`] : []],
19440
19473
  robotsTxt: pageRobotsEvidence(robots)
19441
19474
  };
19442
- if (!accessBlock && writeCache) {
19443
- db.prepare(`INSERT OR REPLACE INTO http_cache
19444
- (url_hash, url, status, headers_json, body_blob, metadata_json, etag, fetched_at, expires_at)
19445
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(key, url, response.response.status, JSON.stringify(headerMap), Buffer.from(html), encodePageFetchCacheEvidence(result), response.response.headers.get("etag"), Date.now(), Date.now() + 36e5);
19446
- noteCacheWrite(Buffer.byteLength(html));
19447
- }
19475
+ if (!accessBlock && writeCache) writeToCache((database) => {
19476
+ database.prepare(`INSERT OR REPLACE INTO http_cache
19477
+ (url_hash, url, status, headers_json, body_blob, metadata_json, etag, fetched_at, expires_at)
19478
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(key, url, response.response.status, JSON.stringify(headerMap), Buffer.from(html), encodePageFetchCacheEvidence(result), response.response.headers.get("etag"), Date.now(), Date.now() + 36e5);
19479
+ noteCacheWrite(Buffer.byteLength(html), database);
19480
+ });
19448
19481
  return result;
19449
19482
  }
19450
19483
  //#endregion
@@ -20302,7 +20335,7 @@ function resolveSearchDateWindow(input = 28) {
20302
20335
  }
20303
20336
  async function querySearchAnalytics(site, body, opts = {}) {
20304
20337
  const { client, identity } = await getAuthorized(opts.accountEmail ?? await cloudAccountFor(site));
20305
- const db = getDb();
20338
+ const db = cacheDb();
20306
20339
  const queryHash = hashKey([
20307
20340
  site,
20308
20341
  identity,
@@ -20322,10 +20355,12 @@ async function querySearchAnalytics(site, body, opts = {}) {
20322
20355
  const calls = result.calls;
20323
20356
  const requestJson = JSON.stringify(body);
20324
20357
  const responseJson = JSON.stringify(allRows);
20325
- db.prepare(`INSERT OR REPLACE INTO gsc_cache
20326
- (site_url, query_hash, request_json, response_json, row_count, fetched_at, expires_at)
20327
- VALUES (?, ?, ?, ?, ?, ?, ?)`).run(site, queryHash, requestJson, responseJson, allRows.length, Date.now(), Date.now() + 864e5);
20328
- noteCacheWrite(Buffer.byteLength(requestJson) + Buffer.byteLength(responseJson));
20358
+ writeToCache((database) => {
20359
+ database.prepare(`INSERT OR REPLACE INTO gsc_cache
20360
+ (site_url, query_hash, request_json, response_json, row_count, fetched_at, expires_at)
20361
+ VALUES (?, ?, ?, ?, ?, ?, ?)`).run(site, queryHash, requestJson, responseJson, allRows.length, Date.now(), Date.now() + 864e5);
20362
+ noteCacheWrite(Buffer.byteLength(requestJson) + Buffer.byteLength(responseJson), database);
20363
+ });
20329
20364
  return {
20330
20365
  rows: allRows,
20331
20366
  calls,
@@ -20461,8 +20496,10 @@ async function queryPagesTopQueriesBatch(site, pageUrls, range = 28) {
20461
20496
  //#region packages/core/dist/gsc/client/sites.js
20462
20497
  async function listSites(_refresh = false, accountEmail) {
20463
20498
  const entries = !accountEmail && cloudLinked() ? await allCloudSites() : await listSearchConsoleSites(googleFetchFor((await getAuthorized(accountEmail)).client), LOCAL_SIGN_IN);
20464
- const insert = getDb().prepare("INSERT OR REPLACE INTO sites (site_url, display_name, permission, added_at, is_default) VALUES (?, ?, ?, ?, COALESCE((SELECT is_default FROM sites WHERE site_url = ?), 0))");
20465
- for (const site of entries) insert.run(site.siteUrl, site.siteUrl, site.permissionLevel ?? null, Date.now(), site.siteUrl);
20499
+ writeToCache((database) => {
20500
+ const insert = database.prepare("INSERT OR REPLACE INTO sites (site_url, display_name, permission, added_at, is_default) VALUES (?, ?, ?, ?, COALESCE((SELECT is_default FROM sites WHERE site_url = ?), 0))");
20501
+ for (const site of entries) insert.run(site.siteUrl, site.siteUrl, site.permissionLevel ?? null, Date.now(), site.siteUrl);
20502
+ });
20466
20503
  return entries;
20467
20504
  }
20468
20505
  async function allCloudSites() {
@@ -26587,7 +26624,7 @@ function taskIds(value) {
26587
26624
  }
26588
26625
  }
26589
26626
  function readProviderCache(key, schema, options = {}) {
26590
- const database = options.database ?? getDb();
26627
+ const database = options.database ?? cacheDb();
26591
26628
  const now = options.now ?? Date.now();
26592
26629
  const hash = requestHash(key, stableProviderRequestJson(key.request));
26593
26630
  const row = database.prepare(`SELECT response_json, row_count, source_cost_micros, task_ids_json,
@@ -26608,9 +26645,11 @@ function readProviderCache(key, schema, options = {}) {
26608
26645
  taskIds: taskIds(row.task_ids_json)
26609
26646
  };
26610
26647
  } catch {
26611
- database.prepare(`DELETE FROM provider_cache
26612
- WHERE provider = ? AND credential_scope = ? AND operation = ?
26613
- AND request_hash = ?`).run(key.provider, key.credentialScope, key.operation, hash);
26648
+ try {
26649
+ database.prepare(`DELETE FROM provider_cache
26650
+ WHERE provider = ? AND credential_scope = ? AND operation = ?
26651
+ AND request_hash = ?`).run(key.provider, key.credentialScope, key.operation, hash);
26652
+ } catch {}
26614
26653
  return null;
26615
26654
  }
26616
26655
  }
@@ -26621,19 +26660,22 @@ function writeProviderCache(key, input, options = {}) {
26621
26660
  code: "configuration",
26622
26661
  message: `Provider cache TTL must be between 1 and ${CACHE_MAX_AGE_MS} milliseconds.`
26623
26662
  });
26624
- const database = options.database ?? getDb();
26625
26663
  const now = options.now ?? Date.now();
26626
26664
  const expiresAt = now + input.ttlMs;
26627
26665
  const requestJson = stableProviderRequestJson(key.request);
26628
26666
  const responseJson = JSON.stringify(input.data);
26629
26667
  const normalizedTaskIds = [...new Set(input.taskIds)].filter((id) => id.length > 0 && id.length <= 100).sort((left, right) => left < right ? -1 : left > right ? 1 : 0).slice(0, 20);
26630
26668
  const taskIdsJson = JSON.stringify(normalizedTaskIds);
26631
- database.prepare(`INSERT OR REPLACE INTO provider_cache (
26632
- provider, credential_scope, operation, request_hash, request_json,
26633
- response_json, row_count, source_cost_micros, task_ids_json,
26634
- fetched_at, expires_at
26635
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(key.provider, key.credentialScope, key.operation, requestHash(key, requestJson), requestJson, responseJson, input.rowCount, input.sourceCostMicros, taskIdsJson, now, expiresAt);
26636
- noteCacheWrite(Buffer.byteLength(requestJson) + Buffer.byteLength(responseJson) + Buffer.byteLength(taskIdsJson), database);
26669
+ const save = (database) => {
26670
+ database.prepare(`INSERT OR REPLACE INTO provider_cache (
26671
+ provider, credential_scope, operation, request_hash, request_json,
26672
+ response_json, row_count, source_cost_micros, task_ids_json,
26673
+ fetched_at, expires_at
26674
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(key.provider, key.credentialScope, key.operation, requestHash(key, requestJson), requestJson, responseJson, input.rowCount, input.sourceCostMicros, taskIdsJson, now, expiresAt);
26675
+ noteCacheWrite(Buffer.byteLength(requestJson) + Buffer.byteLength(responseJson) + Buffer.byteLength(taskIdsJson), database);
26676
+ };
26677
+ if (options.database) save(options.database);
26678
+ else writeToCache(save);
26637
26679
  return {
26638
26680
  data: input.data,
26639
26681
  storedAt: new Date(now).toISOString(),
@@ -27256,7 +27298,7 @@ async function loadInstalledProviderExtensions(options = {}) {
27256
27298
  const DEFAULT_MAX_REQUESTS = 8;
27257
27299
  const MAX_RESPONSE_BYTES$1 = 10 * 1024 * 1024;
27258
27300
  const MAX_REQUEST_BODY_BYTES = 64 * 1024;
27259
- const TIMEOUT_MS$1 = 15e3;
27301
+ const TIMEOUT_MS$2 = 15e3;
27260
27302
  function normalizeProviderExtensionAccount(provider, account) {
27261
27303
  const fields = provider.connection.fields.filter((field) => field.kind === "account");
27262
27304
  const allowed = new Set(fields.map((field) => field.id));
@@ -27303,7 +27345,7 @@ function runtimeForProvider(provider, options = {}) {
27303
27345
  },
27304
27346
  fetch: providerFetch,
27305
27347
  maxResponseBytes: MAX_RESPONSE_BYTES$1,
27306
- timeoutMs: TIMEOUT_MS$1,
27348
+ timeoutMs: TIMEOUT_MS$2,
27307
27349
  retry: (input.method ?? "GET") === "GET" ? "safe" : "never",
27308
27350
  schema: z.unknown()
27309
27351
  });
@@ -36851,7 +36893,7 @@ function reportId$1(input) {
36851
36893
  })).digest("hex").slice(0, 20)}`;
36852
36894
  }
36853
36895
  function cacheGet(id, now) {
36854
- const row = getDb().prepare("SELECT report_json FROM performance_reports WHERE id = ? AND expires_at > ?").get(id, now);
36896
+ const row = cacheDb().prepare("SELECT report_json FROM performance_reports WHERE id = ? AND expires_at > ?").get(id, now);
36855
36897
  if (!row?.report_json) return void 0;
36856
36898
  try {
36857
36899
  const report = JSON.parse(row.report_json);
@@ -36866,10 +36908,12 @@ function cacheSet(report, now) {
36866
36908
  raw: void 0
36867
36909
  };
36868
36910
  const reportJson = JSON.stringify(stored);
36869
- getDb().prepare(`INSERT OR REPLACE INTO performance_reports
36870
- (id, url, strategy, report_json, created_at, expires_at)
36871
- VALUES (?, ?, ?, ?, ?, ?)`).run(report.id, report.url, report.strategy, reportJson, Date.parse(report.generatedAt), now + CACHE_TTL_MS);
36872
- noteCacheWrite(Buffer.byteLength(reportJson));
36911
+ writeToCache((database) => {
36912
+ database.prepare(`INSERT OR REPLACE INTO performance_reports
36913
+ (id, url, strategy, report_json, created_at, expires_at)
36914
+ VALUES (?, ?, ?, ?, ?, ?)`).run(report.id, report.url, report.strategy, reportJson, Date.parse(report.generatedAt), now + CACHE_TTL_MS);
36915
+ noteCacheWrite(Buffer.byteLength(reportJson), database);
36916
+ });
36873
36917
  }
36874
36918
  async function fallbackReport(input) {
36875
36919
  const fetched = await fetchPage(input.url, {
@@ -39053,7 +39097,7 @@ async function updatePostmortemWorkflow(input, dependencies = {}) {
39053
39097
  //#endregion
39054
39098
  //#region packages/core/dist/clicky/api.js
39055
39099
  const ENDPOINT$1 = "https://api.clicky.com/api/stats/4";
39056
- const MAX_BYTES$1 = 5e6;
39100
+ const MAX_BYTES$2 = 5e6;
39057
39101
  var ClickyError = class extends Error {
39058
39102
  code;
39059
39103
  constructor(code, message) {
@@ -39080,7 +39124,7 @@ async function clickyStats(site, types, options = {}) {
39080
39124
  throw new ClickyError("remote", "Could not reach Clicky. Try again.");
39081
39125
  });
39082
39126
  if (!response.ok) throw new ClickyError("remote", `Clicky returned ${response.status}.`);
39083
- const groups = await readJson(response, "Clicky", { maxBytes: MAX_BYTES$1 });
39127
+ const groups = await readJson(response, "Clicky", { maxBytes: MAX_BYTES$2 });
39084
39128
  if (!Array.isArray(groups)) throw new ClickyError("remote", "Clicky returned invalid data.");
39085
39129
  const failed = groups.find((group) => typeof group?.error === "string");
39086
39130
  if (failed?.error) throw /sitekey|site id|authenticat|permission/iu.test(failed.error) ? new ClickyError("auth", `Clicky rejected site ID ${site.siteId} or its sitekey.`) : new ClickyError("remote", `Clicky: ${failed.error.slice(0, 200)}`);
@@ -40897,8 +40941,8 @@ function internalLinksText(report, options) {
40897
40941
  //#endregion
40898
40942
  //#region packages/core/dist/commands/page-facts.js
40899
40943
  const MAX_PAGES = 20;
40900
- const TIMEOUT_MS = 6e3;
40901
- const MAX_BYTES = 1e6;
40944
+ const TIMEOUT_MS$1 = 6e3;
40945
+ const MAX_BYTES$1 = 1e6;
40902
40946
  const clean = (value) => value?.trim().replace(/\s+/g, " ") || null;
40903
40947
  async function boundedText(response) {
40904
40948
  if (!response.body) return "";
@@ -40906,7 +40950,7 @@ async function boundedText(response) {
40906
40950
  const decoder = new TextDecoder();
40907
40951
  let text = "";
40908
40952
  let total = 0;
40909
- while (total < MAX_BYTES) {
40953
+ while (total < MAX_BYTES$1) {
40910
40954
  const { done, value } = await reader.read();
40911
40955
  if (done) return text + decoder.decode();
40912
40956
  total += value.byteLength;
@@ -40986,7 +41030,7 @@ async function facts(url) {
40986
41030
  "user-agent": SEO_CRAWLER_USER_AGENT,
40987
41031
  accept: "text/html"
40988
41032
  },
40989
- signal: AbortSignal.timeout(TIMEOUT_MS)
41033
+ signal: AbortSignal.timeout(TIMEOUT_MS$1)
40990
41034
  });
40991
41035
  out.status = response.status;
40992
41036
  const location = response.headers.get("location");
@@ -42759,6 +42803,94 @@ var LocalCredentialsProvider = class {
42759
42803
  };
42760
42804
  new LocalCredentialsProvider();
42761
42805
  //#endregion
42806
+ //#region packages/core/dist/update-notice.js
42807
+ const REGISTRY_URL = "https://registry.npmjs.org/seo/latest";
42808
+ const CHECK_EVERY_MS = 864e5;
42809
+ const TIMEOUT_MS = 2e3;
42810
+ const MAX_BYTES = 65536;
42811
+ let checking = false;
42812
+ function runByNpx(env, cliPath) {
42813
+ if (env.npm_command === "exec" || /npx/i.test(env.npm_execpath ?? "")) return true;
42814
+ if (!cliPath) return false;
42815
+ let path = cliPath;
42816
+ try {
42817
+ path = realpathSync(cliPath);
42818
+ } catch {}
42819
+ return /[\\/](?:_npx|dlx)[\\/]/.test(path);
42820
+ }
42821
+ function isNewerVersion(current, latest) {
42822
+ const parse = (value) => value.replace(/^v/, "").split("-")[0]?.split(".").map((part) => Number.parseInt(part, 10)) ?? [];
42823
+ const currentParts = parse(current);
42824
+ const latestParts = parse(latest);
42825
+ for (let index = 0; index < 3; index += 1) {
42826
+ const currentPart = currentParts[index] ?? 0;
42827
+ const latestPart = latestParts[index] ?? 0;
42828
+ if (!Number.isFinite(currentPart) || !Number.isFinite(latestPart)) return false;
42829
+ if (latestPart > currentPart) return true;
42830
+ if (latestPart < currentPart) return false;
42831
+ }
42832
+ return false;
42833
+ }
42834
+ function isLatestCache(value) {
42835
+ if (!value || typeof value !== "object") return false;
42836
+ const cache = value;
42837
+ return typeof cache.checkedAt === "number" && typeof cache.latest === "string" && /^\d+\.\d+\.\d+$/.test(cache.latest);
42838
+ }
42839
+ function checkRegistry(cacheFile, now) {
42840
+ if (checking) return;
42841
+ checking = true;
42842
+ const done = () => {
42843
+ checking = false;
42844
+ };
42845
+ const req = request(REGISTRY_URL, { headers: { accept: "application/json" } });
42846
+ const timer = setTimeout(() => req.destroy(), TIMEOUT_MS);
42847
+ timer.unref();
42848
+ req.on("socket", (socket) => socket.unref());
42849
+ req.on("error", () => void 0);
42850
+ req.on("close", () => {
42851
+ clearTimeout(timer);
42852
+ done();
42853
+ });
42854
+ req.on("response", (response) => {
42855
+ const chunks = [];
42856
+ let size = 0;
42857
+ response.on("error", () => void 0);
42858
+ response.on("data", (chunk) => {
42859
+ size += chunk.length;
42860
+ if (size > MAX_BYTES) req.destroy();
42861
+ else chunks.push(chunk);
42862
+ });
42863
+ response.on("end", () => {
42864
+ if (response.statusCode !== 200 || size > MAX_BYTES) return;
42865
+ readJson(new Response(Buffer.concat(chunks)), "The npm registry").then((body) => {
42866
+ const cache = {
42867
+ checkedAt: now,
42868
+ latest: body.version
42869
+ };
42870
+ if (isLatestCache(cache)) writeJsonAtomic(cacheFile, cache, 384);
42871
+ }).catch(() => void 0);
42872
+ });
42873
+ });
42874
+ req.end();
42875
+ }
42876
+ function updateNotice(options = {}) {
42877
+ try {
42878
+ const env = options.env ?? process.env;
42879
+ const argv = options.argv ?? process.argv;
42880
+ if (env.NO_UPDATE_NOTIFIER || argv.includes("--no-update-notifier") || isTelemetryCi(env)) return;
42881
+ const cacheFile = options.cacheFile ?? join(getSeoCliPaths().cacheDir, "latest-version.json");
42882
+ const now = (options.now ?? /* @__PURE__ */ new Date()).getTime();
42883
+ const stored = readJsonFile(cacheFile);
42884
+ const cache = isLatestCache(stored) ? stored : void 0;
42885
+ if (!cache || now - cache.checkedAt >= CHECK_EVERY_MS) checkRegistry(cacheFile, now);
42886
+ const current = options.version ?? SEO_VERSION;
42887
+ if (!cache || !isNewerVersion(current, cache.latest)) return void 0;
42888
+ return runByNpx(env, options.cliPath ?? argv[1]) ? `seo ${cache.latest} is out (you have ${current}). Run npx -y seo@latest; in an MCP config use seo@latest, then restart the client.` : `seo ${cache.latest} is out (you have ${current}). Update with: npm i -g seo`;
42889
+ } catch {
42890
+ return;
42891
+ }
42892
+ }
42893
+ //#endregion
42762
42894
  //#region packages/mcp/src/agent-output-budget.ts
42763
42895
  const AGENT_STRUCTURED_OUTPUT_MAX_BYTES = 96 * 1024;
42764
42896
  function jsonBytes(value) {
@@ -45305,7 +45437,7 @@ function text(value) {
45305
45437
  text: value
45306
45438
  }] };
45307
45439
  }
45308
- async function counted(command, args, telemetry, run) {
45440
+ async function countedRun(command, args, telemetry, run) {
45309
45441
  const report = telemetry ? telemetryReportFor(command, {
45310
45442
  section: typeof args.section === "string" ? args.section : void 0,
45311
45443
  action: typeof args.action === "string" ? args.action : void 0
@@ -45317,10 +45449,22 @@ async function counted(command, args, telemetry, run) {
45317
45449
  else trackTelemetryReportComplete(report, telemetry());
45318
45450
  return result;
45319
45451
  } catch (error) {
45320
- if (report && telemetry) trackTelemetryReportFailed(report, error, telemetry());
45321
- return toolError(localError(error));
45452
+ const failure = localError(error);
45453
+ if (report && telemetry) trackTelemetryReportFailed(report, failure, telemetry());
45454
+ return toolError(failure);
45322
45455
  }
45323
45456
  }
45457
+ async function counted(command, args, telemetry, run) {
45458
+ const result = await countedRun(command, args, telemetry, run);
45459
+ const notice = updateNotice();
45460
+ return notice ? {
45461
+ ...result,
45462
+ content: [...result.content, {
45463
+ type: "text",
45464
+ text: notice
45465
+ }]
45466
+ } : result;
45467
+ }
45324
45468
  function registerSharedTools(server, options = {}) {
45325
45469
  const surface = {
45326
45470
  deps: nodeCommandDeps({ call: mcpCall }),
@@ -45433,6 +45577,7 @@ async function startMcpServer(opts = {}) {
45433
45577
  }
45434
45578
  const transport = new StdioServerTransport();
45435
45579
  await server.connect(transport);
45580
+ updateNotice();
45436
45581
  }
45437
45582
  //#endregion
45438
45583
  export { AGENT_STRUCTURED_OUTPUT_MAX_BYTES, REPORT_CATEGORIES, compactAgentWorkflowOutput, createServer, describeReport, executeReport, listReports, runReport, startMcpServer };