@canonry/canonry 7.66.0 → 7.68.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 (139) hide show
  1. package/assets/agent-workspace/skills/aero/references/seo-analysis.md +12 -4
  2. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +2 -2
  3. package/assets/assets/{AgentSetupPage-DXFxOJ1W.js → AgentSetupPage-DyssdZ1J.js} +3 -3
  4. package/assets/assets/{AuditHistoryPanel-CS8UfTHc.js → AuditHistoryPanel-Bma4Q6p0.js} +1 -1
  5. package/assets/assets/{BacklinksPage-D5IA2tNY.js → BacklinksPage-C3GoO2Wf.js} +1 -1
  6. package/assets/assets/{HistoryPage-DsQAUkgR.js → HistoryPage-6iYvYCL7.js} +1 -1
  7. package/assets/assets/MeasurementPropertyPage-CjI5eB3b.js +4 -0
  8. package/assets/assets/ProjectPage-GYIgNPxn.js +9 -0
  9. package/assets/assets/{RunsPage-BgjN1N3t.js → RunsPage-Cw0GTxgx.js} +1 -1
  10. package/assets/assets/{SettingsPage-BQuqnEvm.js → SettingsPage-Cvg8BvZn.js} +1 -1
  11. package/assets/assets/SiteHealthSection-vejp2Igj.js +2 -0
  12. package/assets/assets/ToneBadge-c2bgjqqz.js +60 -0
  13. package/assets/assets/{TrafficPage-BBqpvwl5.js → TrafficPage-BUb0xr-b.js} +1 -1
  14. package/assets/assets/TrafficSourceDetailPage-DmrtEYs8.js +1 -0
  15. package/assets/assets/{account-context-wRthfm6K.js → account-context-qhg8esXw.js} +1 -1
  16. package/assets/assets/{card-Bq64-UB5.js → card-BNthgfAY.js} +1 -1
  17. package/assets/assets/{extract-error-message-BRDc8As2.js → extract-error-message-DuYEL09s.js} +1 -1
  18. package/assets/assets/{format-helpers-D5wFtgg2.js → format-helpers-6v-a8B3S.js} +1 -1
  19. package/assets/assets/index-BUigRGam.js +60 -0
  20. package/assets/assets/{index-C6U4u18w.css → index-CqNwsqjm.css} +1 -1
  21. package/assets/assets/{query-client-IopmAOx0.js → query-client-COFiuVJB.js} +1 -1
  22. package/assets/assets/react-query-ZdpN7cFt.js +1 -0
  23. package/assets/assets/{react-sigma_core.esm.min-d72rX0Uo.js → react-sigma_core.esm.min-EbeNATny.js} +1 -1
  24. package/assets/assets/service-DGFjEsYR.js +1 -0
  25. package/assets/index.html +8 -8
  26. package/dist/{ads-IFKZU7SC.js → ads-AHM5LMVT.js} +3 -3
  27. package/dist/{agent-3KMENHL3.js → agent-2FSGY7SD.js} +7 -7
  28. package/dist/{agent-ask-7WVQLLD5.js → agent-ask-GIK7T2HD.js} +3 -3
  29. package/dist/{agent-conversations-5LR67TBD.js → agent-conversations-JEIFZHT3.js} +3 -3
  30. package/dist/{agent-memory-GKUCCKVX.js → agent-memory-JC3JJXON.js} +3 -3
  31. package/dist/{agent-providers-TVCRM3YZ.js → agent-providers-JRL3VZA7.js} +3 -3
  32. package/dist/{agent-transcript-MUTCOOWG.js → agent-transcript-ZQDNW3IE.js} +3 -3
  33. package/dist/{analytics-2IXSG5ML.js → analytics-HMYE6EIX.js} +3 -3
  34. package/dist/{apply-7RIYK4VC.js → apply-F5CHVFC3.js} +3 -3
  35. package/dist/{backfill-VU3FV6DQ.js → backfill-JZDQKZHY.js} +9 -9
  36. package/dist/{backlinks-DLSRYEX2.js → backlinks-L7XEHBAP.js} +3 -3
  37. package/dist/{bing-4CXTZUH4.js → bing-XTMKLVRJ.js} +3 -3
  38. package/dist/{bootstrap-OOHSBSDQ.js → bootstrap-AEHBYC77.js} +10 -10
  39. package/dist/{cdp-Y53SRSRV.js → cdp-SSIHU3PU.js} +7 -7
  40. package/dist/{chunk-6ASEI24F.js → chunk-2D7O5UHJ.js} +1 -1
  41. package/dist/{chunk-LBRG6RKI.js → chunk-33LH4ZGF.js} +2 -1
  42. package/dist/{chunk-VGUZPC3I.js → chunk-4KMUJOYL.js} +4 -4
  43. package/dist/{chunk-2YBEI6LE.js → chunk-5SK27UE7.js} +1 -1
  44. package/dist/{chunk-JYOMHNRP.js → chunk-6W3ENB2X.js} +758 -467
  45. package/dist/{chunk-IHOVPHUW.js → chunk-7AXVACK6.js} +2 -2
  46. package/dist/{chunk-TJZLICMB.js → chunk-7NMCRHQL.js} +3 -3
  47. package/dist/{chunk-YRX5UOM3.js → chunk-7SGZHGZ2.js} +1 -1
  48. package/dist/{chunk-JALKQREN.js → chunk-ARIYTYOM.js} +83 -11
  49. package/dist/{chunk-PFKBQTYD.js → chunk-ARYBII44.js} +1 -1
  50. package/dist/{chunk-743NYXIK.js → chunk-CZUPNWLH.js} +2 -2
  51. package/dist/{chunk-EIMXB6UH.js → chunk-FDRZQH3Y.js} +14 -2
  52. package/dist/{chunk-OSF27DCY.js → chunk-IVBJEVHS.js} +2 -2
  53. package/dist/{chunk-BCRRAH5C.js → chunk-J4CNNYRQ.js} +1 -1
  54. package/dist/{chunk-DH5QRKFW.js → chunk-JPVG5LIE.js} +3 -3
  55. package/dist/{chunk-QRBZBJ4U.js → chunk-K2P2XO6P.js} +1 -1
  56. package/dist/{chunk-ZRSNMEB3.js → chunk-K54WGCZV.js} +409 -340
  57. package/dist/{chunk-L7DQYID4.js → chunk-LABVR6K7.js} +4 -4
  58. package/dist/{chunk-FNI3QSVD.js → chunk-LTMQ4MHF.js} +1 -1
  59. package/dist/{chunk-EYWC24VC.js → chunk-MVRPFLEL.js} +1 -1
  60. package/dist/{chunk-CKTA5374.js → chunk-PAVSKSKA.js} +1 -1
  61. package/dist/{chunk-AVQQRTMD.js → chunk-QXCQSRHL.js} +72 -33
  62. package/dist/{chunk-K2HDTMRI.js → chunk-R42VEDCB.js} +3 -3
  63. package/dist/{chunk-H37CDAZX.js → chunk-RNA6ZCM6.js} +2 -2
  64. package/dist/{chunk-FG7KMVA6.js → chunk-U3EJ5RW7.js} +12 -6
  65. package/dist/{chunk-DE2UI37M.js → chunk-V6ALEP33.js} +2 -2
  66. package/dist/{chunk-WNCOBSPN.js → chunk-VPZMSV3Q.js} +254 -9
  67. package/dist/{chunk-DVYS2RMM.js → chunk-W7PA35VJ.js} +4 -4
  68. package/dist/{chunk-YJYLFIVT.js → chunk-XMXYUP7X.js} +1 -1
  69. package/dist/{chunk-J5YZXRD5.js → chunk-Y42G2YKT.js} +8 -8
  70. package/dist/{chunk-ALQEGGYM.js → chunk-YIIIYNPW.js} +22 -4
  71. package/dist/{chunk-XC44Q5XR.js → chunk-ZD5G5QEV.js} +1 -1
  72. package/dist/{chunk-SGZWOUIZ.js → chunk-ZU6X4SN2.js} +5 -5
  73. package/dist/{chunk-IPF2S5G2.js → chunk-ZUXFHO4T.js} +4 -4
  74. package/dist/{citations-ZTQIYYDB.js → citations-NIFKIG6Y.js} +3 -3
  75. package/dist/{cli-catalog-IZJXAHFQ.js → cli-catalog-ONYERYPV.js} +3 -3
  76. package/dist/{cli-commands-XYM2VMAK.js → cli-commands-LWI2NEWW.js} +7 -7
  77. package/dist/cli.js +13 -13
  78. package/dist/{competitor-SIXAPHOM.js → competitor-NSUSTLNW.js} +3 -3
  79. package/dist/{content-XPS3D3Y6.js → content-W5VYYMAW.js} +3 -3
  80. package/dist/{dashboard-FMJDM5PA.js → dashboard-NNA3P645.js} +6 -6
  81. package/dist/{demo-QQKSHTPO.js → demo-5M4YGVV4.js} +1 -1
  82. package/dist/{demo-server-LQ3QXUAS.js → demo-server-FDR4RKLM.js} +14 -11
  83. package/dist/{discover-K5HFEU2T.js → discover-VCKMXFOR.js} +3 -3
  84. package/dist/{discover-eval-6536Z2YN.js → discover-eval-CPVP7EK5.js} +3 -3
  85. package/dist/{doctor-STNH3PHH.js → doctor-EVCP6PDM.js} +3 -3
  86. package/dist/{evidence-W2EWKBAV.js → evidence-ZWRGNZWN.js} +3 -3
  87. package/dist/{export-cmd-EGHMY3M6.js → export-cmd-AM6SIRUW.js} +3 -3
  88. package/dist/{ga-DVIG3PVW.js → ga-6J67NDMZ.js} +3 -3
  89. package/dist/{gbp-SNS4XZBO.js → gbp-ERTWK26L.js} +3 -3
  90. package/dist/{google-KGPHZG6E.js → google-O6VQFK4L.js} +4 -4
  91. package/dist/{google-marketing-VZR6W3L6.js → google-marketing-OEW2YGUR.js} +1 -1
  92. package/dist/{health-cmd-2KWO2GOM.js → health-cmd-OPGK37MK.js} +3 -3
  93. package/dist/{history-ZY27B7JE.js → history-WTU4ETCU.js} +3 -3
  94. package/dist/index.d.ts +114 -8
  95. package/dist/index.js +24 -24
  96. package/dist/{init-5TXIKII2.js → init-WTAVKFGR.js} +11 -11
  97. package/dist/{insights-MUYEOSOG.js → insights-LPEDLSEV.js} +3 -3
  98. package/dist/intelligence-service-4OO2VQ2I.js +15 -0
  99. package/dist/{journeys-YO54IRVC.js → journeys-TWVQNRLT.js} +3 -3
  100. package/dist/{keys-M4QZGYVJ.js → keys-C6FPREBZ.js} +3 -3
  101. package/dist/{keyword-MU62MGWT.js → keyword-PBSE65DK.js} +3 -3
  102. package/dist/{logs-BAQM334Q.js → logs-62RUOAKT.js} +3 -3
  103. package/dist/{mcp-LYS5P3PB.js → mcp-P4LNENKX.js} +2 -2
  104. package/dist/mcp.js +9 -9
  105. package/dist/{measurement-plan-HVSTZWTW.js → measurement-plan-HKW3IVIE.js} +5 -5
  106. package/dist/{notify-XSP5JXU3.js → notify-A3I3G7NK.js} +3 -3
  107. package/dist/{organic-evidence-4HYW4PVO.js → organic-evidence-OFUJBDCK.js} +3 -3
  108. package/dist/{overview-XH72WTZT.js → overview-NSRODN2X.js} +4 -4
  109. package/dist/{project-UKH7FTQX.js → project-B5G2HEAB.js} +3 -3
  110. package/dist/{query-RRD5M4QV.js → query-UQHJVYUJ.js} +3 -3
  111. package/dist/{research-V2IGDUKL.js → research-ZWBJDLJY.js} +3 -3
  112. package/dist/{results-export-5FC7ZT6O.js → results-export-FOJYT4MK.js} +3 -3
  113. package/dist/{run-B2A4LMWU.js → run-ZIUQ2TNN.js} +4 -4
  114. package/dist/{schedule-PLY6CHQT.js → schedule-B5CORKGT.js} +3 -3
  115. package/dist/{search-ACVK3WH5.js → search-2XCZKP6A.js} +3 -3
  116. package/dist/{serve-2LTQZPEK.js → serve-3BSLRICO.js} +25 -25
  117. package/dist/{session-IHXMPETX.js → session-PILSYOTX.js} +12 -12
  118. package/dist/{settings-ZHBNX2I5.js → settings-Y3LVGZH4.js} +3 -3
  119. package/dist/{skills-KWRTCXTF.js → skills-6E3RVQAQ.js} +2 -2
  120. package/dist/{snapshot-GBDCCV6L.js → snapshot-RAV2HCL7.js} +3 -3
  121. package/dist/{src-NOTQWGYV.js → src-VUD6WO5N.js} +6 -2
  122. package/dist/{status-FGDDGBMJ.js → status-2WCUV6C2.js} +4 -4
  123. package/dist/{technical-aeo-AK4QI63Q.js → technical-aeo-2TJEHHBR.js} +3 -3
  124. package/dist/{telemetry-6QPWYMCR.js → telemetry-LQAD26UJ.js} +4 -4
  125. package/dist/{tools-PBNTVVN7.js → tools-U6VGYZV2.js} +11 -11
  126. package/dist/{traffic-AS4PIOQL.js → traffic-3TBXSHPV.js} +5 -5
  127. package/dist/{users-BNYKF35J.js → users-2HDDA5GT.js} +3 -3
  128. package/dist/{visibility-stats-TWL3GJMD.js → visibility-stats-HSGT3OL3.js} +3 -3
  129. package/dist/{wordpress-XBWXAACD.js → wordpress-ALODIEFK.js} +3 -3
  130. package/package.json +1 -1
  131. package/assets/assets/MeasurementPropertyPage-CdCnjCaS.js +0 -4
  132. package/assets/assets/ProjectPage-D3oFKnBG.js +0 -9
  133. package/assets/assets/SiteHealthSection-C6QE9xNk.js +0 -2
  134. package/assets/assets/ToneBadge-DNva5_AM.js +0 -60
  135. package/assets/assets/TrafficSourceDetailPage-uxd0ojry.js +0 -1
  136. package/assets/assets/index-Ttz5_bL3.js +0 -60
  137. package/assets/assets/react-query-CISHjSch.js +0 -1
  138. package/assets/assets/service-DsDxSQuN.js +0 -1
  139. package/dist/intelligence-service-U4NSGZUH.js +0 -15
@@ -5,7 +5,7 @@ import {
5
5
  loadConfig,
6
6
  loadConfigRaw,
7
7
  saveConfigPatch
8
- } from "./chunk-EYWC24VC.js";
8
+ } from "./chunk-MVRPFLEL.js";
9
9
  import {
10
10
  CANONRY_NPM_PACKAGE_URL,
11
11
  compareSemver,
@@ -18,7 +18,7 @@ import {
18
18
  updateCheckEnvOptOut,
19
19
  upgradeCaveatFor,
20
20
  upgradeCommandFor
21
- } from "./chunk-WNCOBSPN.js";
21
+ } from "./chunk-VPZMSV3Q.js";
22
22
 
23
23
  // src/runtime-context.ts
24
24
  function cliRuntimeContext(env = process.env, stdio = process) {
@@ -3,7 +3,7 @@ import {
3
3
  resolveCliAccess,
4
4
  resolveCliAccessForInvocation,
5
5
  windowOptions
6
- } from "./chunk-LBRG6RKI.js";
6
+ } from "./chunk-33LH4ZGF.js";
7
7
  import {
8
8
  emitJsonl
9
9
  } from "./chunk-Z7IUAJOF.js";
@@ -14,7 +14,7 @@ import {
14
14
  } from "./chunk-HGMYEDAQ.js";
15
15
  import {
16
16
  OperationAccesses
17
- } from "./chunk-WNCOBSPN.js";
17
+ } from "./chunk-VPZMSV3Q.js";
18
18
 
19
19
  // src/cli-catalog.ts
20
20
  import { createRequire } from "module";
@@ -111,7 +111,7 @@ async function dispatchRegisteredCommand(args, fallbackFormat, specs) {
111
111
  const accessValue = accessFilterFromArgs(argsWithoutHelp);
112
112
  validateAccessFilter(accessValue);
113
113
  if (fallbackFormat !== "text") {
114
- const { printCliCatalog: printCliCatalog2 } = await import("./cli-catalog-IZJXAHFQ.js");
114
+ const { printCliCatalog: printCliCatalog2 } = await import("./cli-catalog-ONYERYPV.js");
115
115
  const group2 = argsWithoutHelp.find((arg) => !arg.startsWith("--"));
116
116
  printCliCatalog2(specs, fallbackFormat, group2, accessValue);
117
117
  return true;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  USAGE_TELEMETRY_HEADERS,
3
3
  redactLogString
4
- } from "./chunk-WNCOBSPN.js";
4
+ } from "./chunk-VPZMSV3Q.js";
5
5
 
6
6
  // ../api-routes/src/request-context.ts
7
7
  import { AsyncLocalStorage } from "async_hooks";
@@ -20,7 +20,7 @@ import {
20
20
  templateLinkRatio,
21
21
  templateLinkUbiquityAvailable,
22
22
  validationError
23
- } from "./chunk-WNCOBSPN.js";
23
+ } from "./chunk-VPZMSV3Q.js";
24
24
  import {
25
25
  __export
26
26
  } from "./chunk-MLKGABMK.js";
@@ -227,8 +227,10 @@ var seoTasks = sqliteTable("seo_tasks", {
227
227
  reconciliation: text("reconciliation", { mode: "json" }).$type(),
228
228
  startedAt: text("started_at"),
229
229
  finishedAt: text("finished_at"),
230
- error: text("error")
231
- }, (t) => [index("idx_seo_tasks_job").on(t.jobId)]);
230
+ error: text("error"),
231
+ /** Set on a second attempt: the task whose search-engine error it repeats. A retry is never retried. */
232
+ retryOf: text("retry_of")
233
+ }, (t) => [index("idx_seo_tasks_job").on(t.jobId), index("idx_seo_tasks_retry").on(t.retryOf)]);
232
234
  var seoBudgets = sqliteTable("seo_budgets", {
233
235
  scope: text("scope").notNull(),
234
236
  period: text("period").notNull(),
@@ -971,6 +973,12 @@ var schedules = sqliteTable2("schedules", {
971
973
  sourceId: text2("source_id"),
972
974
  lastRunAt: text2("last_run_at"),
973
975
  nextRunAt: text2("next_run_at"),
976
+ /**
977
+ * When the schedule last turned on (created enabled, or changed from disabled to enabled);
978
+ * null while it is disabled. Rows written before migration 196 hold null while enabled:
979
+ * read those as enabled since `createdAt`.
980
+ */
981
+ enabledAt: text2("enabled_at"),
974
982
  createdAt: text2("created_at").notNull(),
975
983
  updatedAt: text2("updated_at").notNull()
976
984
  }, (table) => [
@@ -8224,6 +8232,28 @@ var MIGRATION_VERSIONS = [
8224
8232
  `ALTER TABLE ga_measurement_sync_state ADD COLUMN key_event_names TEXT`,
8225
8233
  `ALTER TABLE ga_measurement_sync_state ADD COLUMN key_events_error TEXT`
8226
8234
  ]
8235
+ },
8236
+ {
8237
+ // A market-rankings search that hit a search-engine error is sent once
8238
+ // more at the end of its refresh, as a new task that points at the first
8239
+ // attempt. Nullable with no default: existing tasks and every task an
8240
+ // older writer adds are first attempts.
8241
+ version: 195,
8242
+ name: "seo-task-retry",
8243
+ statements: [
8244
+ `ALTER TABLE seo_tasks ADD COLUMN retry_of TEXT`,
8245
+ `CREATE INDEX IF NOT EXISTS idx_seo_tasks_retry ON seo_tasks(retry_of)`
8246
+ ]
8247
+ },
8248
+ {
8249
+ // When a schedule last turned on, so a schedule enabled long after it was
8250
+ // created is graded from that point. Nullable with no default: existing
8251
+ // rows read as enabled since creation, and an older writer leaves it null.
8252
+ version: 196,
8253
+ name: "schedules-enabled-at",
8254
+ statements: [
8255
+ `ALTER TABLE schedules ADD COLUMN enabled_at TEXT`
8256
+ ]
8227
8257
  }
8228
8258
  ];
8229
8259
  var AERO_LEDGER_REBUILDS = [
@@ -9431,6 +9461,20 @@ var SentimentRepository = class {
9431
9461
  // ../db/src/seo-repository.ts
9432
9462
  import crypto from "crypto";
9433
9463
  import { and as and2, asc as asc2, eq as eq3, inArray as inArray2, sql as sql5 } from "drizzle-orm";
9464
+ function currentSeoTasks(tasks) {
9465
+ const replaced = new Set(tasks.flatMap((task) => task.retryOf && task.status !== SeoRunStatuses.cancelled ? [task.retryOf] : []));
9466
+ return tasks.filter((task) => task.retryOf ? task.status !== SeoRunStatuses.cancelled : !replaced.has(task.id));
9467
+ }
9468
+ function currentSeoTaskCondition() {
9469
+ return sql5`(${seoTasks.retryOf} IS NULL OR ${seoTasks.status} <> ${SeoRunStatuses.cancelled}) AND NOT EXISTS (SELECT 1 FROM seo_tasks AS retry WHERE retry.retry_of = ${seoTasks.id} AND retry.status <> ${SeoRunStatuses.cancelled})`;
9470
+ }
9471
+ function bucketLimits(job, policy) {
9472
+ return /* @__PURE__ */ new Map([
9473
+ [`account-day:${job.accountKey}`, policy.accountDailyLimitMicros],
9474
+ [`account-month:${job.accountKey}`, policy.accountMonthlyLimitMicros],
9475
+ [`project-month:${job.projectKey}`, policy.projectMonthlyLimitMicros]
9476
+ ]);
9477
+ }
9434
9478
  var SeoRepository = class {
9435
9479
  constructor(db) {
9436
9480
  this.db = db;
@@ -9481,15 +9525,11 @@ var SeoRepository = class {
9481
9525
  }
9482
9526
  if (tx.select({ id: seoTasks.id }).from(seoTasks).innerJoin(seoJobs, eq3(seoTasks.jobId, seoJobs.id)).where(and2(eq3(seoJobs.accountKey, job.accountKey), inArray2(seoTasks.status, [SeoRunStatuses.running, SeoRunStatuses["reconciliation-required"]]))).get()) return null;
9483
9527
  const allTasks = tx.select().from(seoTasks).where(eq3(seoTasks.jobId, jobId)).orderBy(asc2(seoTasks.id)).all();
9484
- const task = allTasks.find((row) => row.status === SeoRunStatuses.queued);
9528
+ const task = allTasks.find((row) => row.status === SeoRunStatuses.queued && !row.retryOf) ?? allTasks.find((row) => row.status === SeoRunStatuses.queued);
9485
9529
  if (!task) return null;
9486
9530
  const now = (/* @__PURE__ */ new Date()).toISOString();
9487
9531
  const outstanding = allTasks.filter((row) => row.status === SeoRunStatuses.queued).reduce((sum, row) => sum + row.reservedMicros, 0);
9488
- const limits = /* @__PURE__ */ new Map([
9489
- [`account-day:${job.accountKey}`, policy.accountDailyLimitMicros],
9490
- [`account-month:${job.accountKey}`, policy.accountMonthlyLimitMicros],
9491
- [`project-month:${job.projectKey}`, policy.projectMonthlyLimitMicros]
9492
- ]);
9532
+ const limits = bucketLimits(job, policy);
9493
9533
  const buckets = job.buckets.map((bucket) => ({ ...bucket, limit: limits.get(bucket.scope) ?? 0, period: now.slice(0, bucket.scope.startsWith("account-day:") ? 10 : 7) }));
9494
9534
  const runMaximum = allTasks.reduce((sum, row) => sum + (row.actualMicros ?? row.reservedMicros), 0);
9495
9535
  const allowed = runMaximum <= policy.maxRunCostMicros && buckets.every((bucket) => {
@@ -9520,7 +9560,11 @@ var SeoRepository = class {
9520
9560
  renew(taskId, owner) {
9521
9561
  this.db.update(seoTasks).set({ leaseUntil: new Date(Date.now() + 12e4).toISOString() }).where(and2(eq3(seoTasks.id, taskId), eq3(seoTasks.leaseOwner, owner), eq3(seoTasks.status, SeoRunStatuses.running))).run();
9522
9562
  }
9523
- settle(taskId, result, owner) {
9563
+ /**
9564
+ * Store a task's outcome. With `retryPolicy`, a search the adapter marks `retryable` gets one
9565
+ * more attempt, queued in the same transaction (see `queueRetry`).
9566
+ */
9567
+ settle(taskId, result, owner, retryPolicy) {
9524
9568
  return this.db.transaction((tx) => {
9525
9569
  const task = tx.select().from(seoTasks).where(eq3(seoTasks.id, taskId)).get();
9526
9570
  if (!task || task.leaseOwner !== owner || task.reconciliation || task.status !== SeoRunStatuses.running && task.status !== SeoRunStatuses["reconciliation-required"]) return false;
@@ -9532,10 +9576,36 @@ var SeoRepository = class {
9532
9576
  if (known) for (const bucket of job.buckets) tx.update(seoBudgets).set({ reservedMicros: sql5`${seoBudgets.reservedMicros} - ${task.reservedMicros}`, spentMicros: sql5`${seoBudgets.spentMicros} + ${actual}` }).where(and2(eq3(seoBudgets.scope, bucket.scope), eq3(seoBudgets.period, bucket.period))).run();
9533
9577
  const error = status === SeoRunStatuses["reconciliation-required"] ? "The upstream outcome needs operator reconciliation. This request will not be retried." : status === SeoRunStatuses.failed ? "The SEO provider could not complete this task." : null;
9534
9578
  tx.update(seoTasks).set({ status, collectionOutcome: result.outcome, actualMicros: known ? actual : null, receipts: result.tasks, results: result.results, error, leaseOwner: null, leaseUntil: null, finishedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq3(seoTasks.id, taskId)).run();
9579
+ if (status === SeoRunStatuses.failed && result.retryable === true && retryPolicy) this.queueRetry(tx, task, job, retryPolicy);
9535
9580
  this.finish(job.id);
9536
9581
  return true;
9537
9582
  }, { behavior: "immediate" });
9538
9583
  }
9584
+ /**
9585
+ * Queue the one retry a search gets after a search-engine error. It reserves the first attempt's
9586
+ * amount again, inside the same limits, and claims take it after every first attempt, so it runs
9587
+ * at the end of the refresh. A retry is never retried, a cancelled refresh gets none, and one that
9588
+ * would pass a limit is not queued, leaving the search failed.
9589
+ */
9590
+ queueRetry(tx, task, job, policy) {
9591
+ if (job.cancelRequested || task.retryOf || tx.select({ id: seoTasks.id }).from(seoTasks).where(eq3(seoTasks.retryOf, task.id)).get()) return;
9592
+ const amount = task.reservedMicros;
9593
+ const runCost = tx.select({ actualMicros: seoTasks.actualMicros, reservedMicros: seoTasks.reservedMicros }).from(seoTasks).where(eq3(seoTasks.jobId, job.id)).all().reduce((sum, row) => sum + (row.actualMicros ?? row.reservedMicros), 0);
9594
+ if (runCost + amount > policy.maxRunCostMicros) return;
9595
+ const limits = bucketLimits(job, policy);
9596
+ const fits = job.buckets.every((bucket) => {
9597
+ const current = tx.select({ spentMicros: seoBudgets.spentMicros }).from(seoBudgets).where(and2(eq3(seoBudgets.scope, bucket.scope), eq3(seoBudgets.period, bucket.period))).get();
9598
+ const held = tx.select({ total: sql5`coalesce(sum(${seoBudgets.reservedMicros}),0)` }).from(seoBudgets).where(eq3(seoBudgets.scope, bucket.scope)).get().total;
9599
+ return (current?.spentMicros ?? 0) + held + amount <= (limits.get(bucket.scope) ?? 0);
9600
+ });
9601
+ if (!fits) return;
9602
+ for (const bucket of job.buckets) {
9603
+ tx.insert(seoBudgets).values({ scope: bucket.scope, period: bucket.period }).onConflictDoNothing().run();
9604
+ tx.update(seoBudgets).set({ reservedMicros: sql5`${seoBudgets.reservedMicros} + ${amount}` }).where(and2(eq3(seoBudgets.scope, bucket.scope), eq3(seoBudgets.period, bucket.period))).run();
9605
+ }
9606
+ const id = crypto.randomUUID();
9607
+ tx.insert(seoTasks).values({ id, jobId: job.id, request: { ...task.request, tag: id }, status: SeoRunStatuses.queued, reservedMicros: amount, catalogRevision: task.catalogRevision, results: emptySeoResults(), retryOf: task.id }).run();
9608
+ }
9539
9609
  cancel(jobId) {
9540
9610
  return this.db.transaction((tx) => {
9541
9611
  const job = tx.select().from(seoJobs).where(eq3(seoJobs.id, jobId)).get();
@@ -9581,7 +9651,7 @@ var SeoRepository = class {
9581
9651
  }
9582
9652
  finish(jobId) {
9583
9653
  const job = this.db.select().from(seoJobs).where(eq3(seoJobs.id, jobId)).get();
9584
- const tasks = this.db.select().from(seoTasks).where(eq3(seoTasks.jobId, jobId)).all();
9654
+ const tasks = currentSeoTasks(this.db.select().from(seoTasks).where(eq3(seoTasks.jobId, jobId)).all());
9585
9655
  const pending = tasks.some((task) => task.status === SeoRunStatuses.queued || task.status === SeoRunStatuses.running);
9586
9656
  const unknown = tasks.some((task) => task.status === SeoRunStatuses["reconciliation-required"]);
9587
9657
  const completed = tasks.some((task) => task.status === SeoRunStatuses.completed || task.status === SeoRunStatuses.partial);
@@ -9758,5 +9828,7 @@ export {
9758
9828
  SentimentIdempotencyConflict,
9759
9829
  recordSentimentCompletion,
9760
9830
  SentimentRepository,
9831
+ currentSeoTasks,
9832
+ currentSeoTaskCondition,
9761
9833
  SeoRepository
9762
9834
  };
@@ -28,7 +28,7 @@ import {
28
28
  unknownUsageObservation,
29
29
  usdToMicros,
30
30
  withRetry
31
- } from "./chunk-WNCOBSPN.js";
31
+ } from "./chunk-VPZMSV3Q.js";
32
32
 
33
33
  // ../provider-answer-services/src/core/http.ts
34
34
  var MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createApiClient
3
- } from "./chunk-EIMXB6UH.js";
3
+ } from "./chunk-FDRZQH3Y.js";
4
4
  import {
5
5
  emitJsonl
6
6
  } from "./chunk-Z7IUAJOF.js";
@@ -19,7 +19,7 @@ import {
19
19
  formatMicros,
20
20
  formatRunErrorOneLine,
21
21
  resolveProviderInput
22
- } from "./chunk-WNCOBSPN.js";
22
+ } from "./chunk-VPZMSV3Q.js";
23
23
 
24
24
  // src/commands/run.ts
25
25
  function getClient() {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  loadConfig
3
- } from "./chunk-EYWC24VC.js";
3
+ } from "./chunk-MVRPFLEL.js";
4
4
  import {
5
5
  PACKAGE_VERSION
6
6
  } from "./chunk-AOJU5LKX.js";
@@ -36,7 +36,7 @@ import {
36
36
  sentimentSettingsReadSchema,
37
37
  sentimentSummaryReadSchema,
38
38
  upgradeCommandFor
39
- } from "./chunk-WNCOBSPN.js";
39
+ } from "./chunk-VPZMSV3Q.js";
40
40
 
41
41
  // ../api-client-generated/src/generated/core/bodySerializer.gen.ts
42
42
  var jsonBodySerializer = {
@@ -905,6 +905,11 @@ var getApiV1ProjectsByNameSeoMarketRankings = (options) => (options.client ?? cl
905
905
  url: "/api/v1/projects/{name}/seo/market-rankings",
906
906
  ...options
907
907
  });
908
+ var getApiV1ProjectsByNameSeoMarketRankingsSummary = (options) => (options.client ?? client).get({
909
+ security: [{ scheme: "bearer", type: "http" }],
910
+ url: "/api/v1/projects/{name}/seo/market-rankings/summary",
911
+ ...options
912
+ });
908
913
  var postApiV1ProjectsByNameSeoRefreshIntents = (options) => (options.client ?? client).post({
909
914
  security: [{ scheme: "bearer", type: "http" }],
910
915
  url: "/api/v1/projects/{name}/seo/refresh-intents",
@@ -6200,6 +6205,13 @@ var ApiClient = class {
6200
6205
  query
6201
6206
  }));
6202
6207
  }
6208
+ async getSeoMarketRankingSummary(project, query) {
6209
+ return this.invoke(() => getApiV1ProjectsByNameSeoMarketRankingsSummary({
6210
+ client: this.heyClient,
6211
+ path: { name: project },
6212
+ query
6213
+ }));
6214
+ }
6203
6215
  async getResearchRun(project, runId) {
6204
6216
  return this.invoke(
6205
6217
  () => getApiV1ProjectsByNameResearchRunsByRunId({
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  parseJsonColumn
3
- } from "./chunk-JALKQREN.js";
3
+ } from "./chunk-ARIYTYOM.js";
4
4
  import {
5
5
  AI_ENGINE_DOMAINS,
6
6
  AI_ENGINE_SELF_DOMAINS,
@@ -26,7 +26,7 @@ import {
26
26
  retryAfterDelayMs,
27
27
  usageCount,
28
28
  withRetry
29
- } from "./chunk-WNCOBSPN.js";
29
+ } from "./chunk-VPZMSV3Q.js";
30
30
 
31
31
  // ../provider-openai/src/normalize.ts
32
32
  import OpenAI from "openai";
@@ -8,7 +8,7 @@ import {
8
8
  classifyJourneyEntry,
9
9
  hostMatchesDomain,
10
10
  hostOf
11
- } from "./chunk-WNCOBSPN.js";
11
+ } from "./chunk-VPZMSV3Q.js";
12
12
 
13
13
  // ../integration-traffic/src/ip-ranges/amazonbot.json
14
14
  var amazonbot_default = {
@@ -2,18 +2,18 @@ import {
2
2
  configExists,
3
3
  loadConfigRaw,
4
4
  saveConfigPatch
5
- } from "./chunk-EYWC24VC.js";
5
+ } from "./chunk-MVRPFLEL.js";
6
6
  import {
7
7
  BUNDLED_SKILL_NAMES,
8
8
  installSkills
9
- } from "./chunk-6ASEI24F.js";
9
+ } from "./chunk-2D7O5UHJ.js";
10
10
  import {
11
11
  PACKAGE_VERSION
12
12
  } from "./chunk-AOJU5LKX.js";
13
13
  import {
14
14
  SKILL_MANIFEST_FILENAME,
15
15
  SkillsClients
16
- } from "./chunk-WNCOBSPN.js";
16
+ } from "./chunk-VPZMSV3Q.js";
17
17
 
18
18
  // src/skills-autosync.ts
19
19
  import fs from "fs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  hostMatchesDomain
3
- } from "./chunk-WNCOBSPN.js";
3
+ } from "./chunk-VPZMSV3Q.js";
4
4
 
5
5
  // src/citation-utils.ts
6
6
  function pickProjectCitedDomain(citedDomains, projectDomains) {