@ainyc/canonry 4.55.1 → 4.55.3

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 (24) hide show
  1. package/assets/agent-workspace/skills/canonry/references/server-side-traffic.md +9 -4
  2. package/assets/assets/{BacklinksPage-DVmaM864.js → BacklinksPage-buvZ4ZOd.js} +1 -1
  3. package/assets/assets/{ProjectPage-DtL3LFne.js → ProjectPage-D0UqSqe7.js} +1 -1
  4. package/assets/assets/{RunRow-BRqiLxj2.js → RunRow-D-DTu1PA.js} +1 -1
  5. package/assets/assets/{RunsPage-UxZ93-cg.js → RunsPage-CrBpgwkO.js} +1 -1
  6. package/assets/assets/{SettingsPage-Cr5_EGbk.js → SettingsPage-Bgsi9tZ2.js} +1 -1
  7. package/assets/assets/{TrafficPage-CUC_lfTe.js → TrafficPage-DAHXrzqz.js} +1 -1
  8. package/assets/assets/TrafficSourceDetailPage-DCcDN3VD.js +1 -0
  9. package/assets/assets/{extract-error-message-DD5MibWI.js → extract-error-message-BGhWiJPr.js} +1 -1
  10. package/assets/assets/{index-nnF1LnyK.js → index-CbDkoDBH.js} +2 -2
  11. package/assets/assets/{index-Bm3JQsW0.css → index-dxdJhCQO.css} +1 -1
  12. package/assets/assets/{server-traffic-DjRISEZ-.js → server-traffic-3xxyOEIX.js} +1 -1
  13. package/assets/assets/{trash-2-CJ5M--Le.js → trash-2-dppRdHYI.js} +1 -1
  14. package/assets/index.html +2 -2
  15. package/dist/{chunk-2OI7HFAB.js → chunk-5EAGNVCJ.js} +131 -188
  16. package/dist/{chunk-ZY3EDW3S.js → chunk-UOQ62KDD.js} +8 -3
  17. package/dist/{chunk-UTM3FPAJ.js → chunk-XB6Y63NI.js} +181 -3
  18. package/dist/{chunk-OFY3Z2F7.js → chunk-XHU35P3S.js} +359 -361
  19. package/dist/cli.js +12 -10
  20. package/dist/index.js +4 -4
  21. package/dist/{intelligence-service-NKAEHHJ5.js → intelligence-service-4PT22FED.js} +2 -2
  22. package/dist/mcp.js +2 -2
  23. package/package.json +6 -6
  24. package/assets/assets/TrafficSourceDetailPage-DARPL2TU.js +0 -1
@@ -1 +1 @@
1
- import{c as d,j as a,bE as S,bz as l,bF as v,aj as m,l as t,bG as y,bA as i,bH as T,bI as h,bJ as p,bK as b}from"./index-nnF1LnyK.js";import{u as s,r as C,n as c,o as u}from"./vendor-tanstack-Dq7p98wZ.js";const g=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]],F=d("refresh-cw",g);function M(e){switch(e){case i.connected:return"positive";case i.paused:return"caution";case i.error:return"negative";case i.archived:return"neutral"}}function w(e){const r={};return e.kind&&e.kind!=="all"&&(r.kind=e.kind),e.sourceId&&(r.sourceId=e.sourceId),e.sinceMinutes!==void 0&&(r.since=new Date(Date.now()-e.sinceMinutes*6e4).toISOString()),e.limit!==void 0&&(r.limit=String(e.limit)),r}function o(e){e.invalidateQueries({predicate:r=>{const n=r.queryKey[0];return typeof n?._id=="string"&&n._id.startsWith("getApiV1ProjectsByNameTraffic")}})}function P(e){return s({...S({client:t,path:{name:e??""}}),enabled:!!e,staleTime:a})}function k(e){return s({...b({client:t,path:{name:e??""}}),enabled:!!e,staleTime:a})}function A(e,r){return s({...l({client:t,path:{name:e??"",id:r??""}}),enabled:!!(e&&r),staleTime:a})}function E(e,r){const n=C.useMemo(()=>w(r),[r.kind,r.sourceId,r.sinceMinutes,r.limit]);return s({...v({client:t,path:{name:e??""},query:n}),enabled:!!e,staleTime:a})}function V(e){const r=c();return u({mutationFn:n=>{if(!e)throw new Error("Project is required to connect a Cloud Run source");return p(e,n)},onSuccess:()=>{e&&o(r)}})}function I(e){const r=c();return u({mutationFn:n=>{if(!e)throw new Error("Project is required to connect a WordPress source");return T(e,n)},onSuccess:()=>{e&&o(r)}})}function Q(e){const r=c();return u({mutationFn:n=>{if(!e)throw new Error("Project is required to connect a Vercel source");return h(e,n)},onSuccess:()=>{e&&o(r)}})}function R(e,r){const n=c();return u({mutationFn:f=>{if(!e||!r)throw new Error("Project and sourceId are required to sync");return y(e,r,f??void 0)},onSuccess:()=>{e&&(o(n),n.invalidateQueries({queryKey:m({client:t})}))}})}export{F as R,I as a,Q as b,V as c,P as d,A as e,E as f,R as g,M as t,k as u};
1
+ import{c as d,j as a,bE as S,bz as l,bF as v,aj as m,l as t,bG as y,bA as i,bH as T,bI as h,bJ as p,bK as b}from"./index-CbDkoDBH.js";import{u as s,r as C,n as c,o as u}from"./vendor-tanstack-Dq7p98wZ.js";const g=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]],F=d("refresh-cw",g);function M(e){switch(e){case i.connected:return"positive";case i.paused:return"caution";case i.error:return"negative";case i.archived:return"neutral"}}function w(e){const r={};return e.kind&&e.kind!=="all"&&(r.kind=e.kind),e.sourceId&&(r.sourceId=e.sourceId),e.sinceMinutes!==void 0&&(r.since=new Date(Date.now()-e.sinceMinutes*6e4).toISOString()),e.limit!==void 0&&(r.limit=String(e.limit)),r}function o(e){e.invalidateQueries({predicate:r=>{const n=r.queryKey[0];return typeof n?._id=="string"&&n._id.startsWith("getApiV1ProjectsByNameTraffic")}})}function P(e){return s({...S({client:t,path:{name:e??""}}),enabled:!!e,staleTime:a})}function k(e){return s({...b({client:t,path:{name:e??""}}),enabled:!!e,staleTime:a})}function A(e,r){return s({...l({client:t,path:{name:e??"",id:r??""}}),enabled:!!(e&&r),staleTime:a})}function E(e,r){const n=C.useMemo(()=>w(r),[r.kind,r.sourceId,r.sinceMinutes,r.limit]);return s({...v({client:t,path:{name:e??""},query:n}),enabled:!!e,staleTime:a})}function V(e){const r=c();return u({mutationFn:n=>{if(!e)throw new Error("Project is required to connect a Cloud Run source");return p(e,n)},onSuccess:()=>{e&&o(r)}})}function I(e){const r=c();return u({mutationFn:n=>{if(!e)throw new Error("Project is required to connect a WordPress source");return T(e,n)},onSuccess:()=>{e&&o(r)}})}function Q(e){const r=c();return u({mutationFn:n=>{if(!e)throw new Error("Project is required to connect a Vercel source");return h(e,n)},onSuccess:()=>{e&&o(r)}})}function R(e,r){const n=c();return u({mutationFn:f=>{if(!e||!r)throw new Error("Project and sourceId are required to sync");return y(e,r,f??void 0)},onSuccess:()=>{e&&(o(n),n.invalidateQueries({queryKey:m({client:t})}))}})}export{F as R,I as a,Q as b,V as c,P as d,A as e,E as f,R as g,M as t,k as u};
@@ -1 +1 @@
1
- import{c}from"./index-nnF1LnyK.js";const a=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],h=c("circle-check",a);const e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]],n=c("circle-question-mark",e);const o=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],s=c("download",o);const t=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],r=c("trash-2",t);export{h as C,s as D,r as T,n as a};
1
+ import{c}from"./index-CbDkoDBH.js";const a=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],h=c("circle-check",a);const e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]],n=c("circle-question-mark",e);const o=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],s=c("download",o);const t=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],r=c("trash-2",t);export{h as C,s as D,r as T,n as a};
package/assets/index.html CHANGED
@@ -12,12 +12,12 @@
12
12
  <link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
13
13
  <link rel="apple-touch-icon" href="./apple-touch-icon.png" />
14
14
  <title>Canonry</title>
15
- <script type="module" crossorigin src="./assets/index-nnF1LnyK.js"></script>
15
+ <script type="module" crossorigin src="./assets/index-CbDkoDBH.js"></script>
16
16
  <link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-Dq7p98wZ.js">
17
17
  <link rel="modulepreload" crossorigin href="./assets/vendor-radix-B57xfQbP.js">
18
18
  <link rel="modulepreload" crossorigin href="./assets/vendor-recharts-DWvKDyBF.js">
19
19
  <link rel="modulepreload" crossorigin href="./assets/vendor-markdown-DK7fbRNb.js">
20
- <link rel="stylesheet" crossorigin href="./assets/index-Bm3JQsW0.css">
20
+ <link rel="stylesheet" crossorigin href="./assets/index-dxdJhCQO.css">
21
21
  </head>
22
22
  <body>
23
23
  <div id="root"></div>
@@ -6,7 +6,7 @@ import {
6
6
  loadConfig,
7
7
  loadConfigRaw,
8
8
  saveConfigPatch
9
- } from "./chunk-ZY3EDW3S.js";
9
+ } from "./chunk-UOQ62KDD.js";
10
10
  import {
11
11
  DEFAULT_RUN_HISTORY_LIMIT,
12
12
  IntelligenceService,
@@ -45,14 +45,17 @@ import {
45
45
  categorizeQueryByIntent,
46
46
  ccReleaseSyncs,
47
47
  competitors,
48
+ computeCompetitorOverlap,
48
49
  contentTargetDismissals,
49
50
  crawlerEventsHourly,
50
51
  createClient,
51
52
  createLogger,
53
+ determineCitationState,
52
54
  discoveryProbes,
53
55
  discoverySessions,
54
56
  dropLegacyCredentialColumns,
55
57
  extractLegacyCredentials,
58
+ extractRecommendedCompetitors,
56
59
  filterTrackedSnapshots,
57
60
  gaAiReferrals,
58
61
  gaSocialReferrals,
@@ -84,7 +87,7 @@ import {
84
87
  smoothedRunDelta,
85
88
  trafficSources,
86
89
  usageCounters
87
- } from "./chunk-UTM3FPAJ.js";
90
+ } from "./chunk-XB6Y63NI.js";
88
91
  import {
89
92
  AGENT_MEMORY_VALUE_MAX_BYTES,
90
93
  AGENT_PROVIDER_IDS,
@@ -144,7 +147,6 @@ import {
144
147
  bingSitesResponseDtoSchema,
145
148
  bingStatusDtoSchema,
146
149
  bingUrlInspectionDtoSchema,
147
- brandKeyFromText,
148
150
  brandLabelFromDomain,
149
151
  buildRunErrorFromMessages,
150
152
  categorizeSource,
@@ -286,7 +288,7 @@ import {
286
288
  wordpressSchemaDeployResultDtoSchema,
287
289
  wordpressSchemaStatusResultDtoSchema,
288
290
  wordpressStatusDtoSchema
289
- } from "./chunk-OFY3Z2F7.js";
291
+ } from "./chunk-XHU35P3S.js";
290
292
 
291
293
  // src/telemetry.ts
292
294
  import crypto from "crypto";
@@ -1657,7 +1659,9 @@ async function runRoutes(app, opts) {
1657
1659
  const project = resolveProject(app.db, request.params.name);
1658
1660
  const parsedLimit = parseInt(request.query.limit ?? "", 10);
1659
1661
  const limit = Number.isNaN(parsedLimit) || parsedLimit <= 0 ? void 0 : parsedLimit;
1660
- const rows = limit == null ? app.db.select().from(runs).where(eq7(runs.projectId, project.id)).orderBy(asc(runs.createdAt)).all() : app.db.select().from(runs).where(eq7(runs.projectId, project.id)).orderBy(desc(runs.createdAt)).limit(limit).all().reverse();
1662
+ const kind = parseListKind(request.query.kind);
1663
+ const where = kind ? and2(eq7(runs.projectId, project.id), eq7(runs.kind, kind)) : eq7(runs.projectId, project.id);
1664
+ const rows = limit == null ? app.db.select().from(runs).where(where).orderBy(asc(runs.createdAt)).all() : app.db.select().from(runs).where(where).orderBy(desc(runs.createdAt)).limit(limit).all().reverse();
1661
1665
  return reply.send(rows.map(formatRun));
1662
1666
  });
1663
1667
  app.get("/projects/:name/runs/latest", async (request, reply) => {
@@ -9118,7 +9122,7 @@ var routeCatalog = [
9118
9122
  path: "/api/v1/projects/{name}/runs",
9119
9123
  summary: "List project runs",
9120
9124
  tags: ["runs"],
9121
- parameters: [nameParameter, limitQueryParameter],
9125
+ parameters: [nameParameter, limitQueryParameter, runsListKindQueryParameter],
9122
9126
  responses: {
9123
9127
  200: jsonArrayResponse("Runs returned.", "RunDto")
9124
9128
  }
@@ -21683,18 +21687,62 @@ async function listVercelTrafficEvents(options) {
21683
21687
 
21684
21688
  // ../integration-vercel/src/drain.ts
21685
21689
  var MIN_SUB_WINDOW_MS = 6e4;
21690
+ var FLOOR_SLICE_MAX_PAGES = 1e3;
21691
+ var RETENTION_BOUNDARY_TOLERANCE_MS = 60 * 6e4;
21686
21692
  function toMs(value) {
21687
21693
  return typeof value === "number" ? value : value.getTime();
21688
21694
  }
21695
+ function isRetentionError(error) {
21696
+ return error instanceof VercelLogsApiError && error.status === 400 && (error.body ?? "").includes("ExceedsBillingLimitError");
21697
+ }
21698
+ async function isServable(options, windowStartMs, windowEndMs) {
21699
+ try {
21700
+ await options.pull({
21701
+ token: options.token,
21702
+ projectId: options.projectId,
21703
+ teamId: options.teamId,
21704
+ environment: options.environment,
21705
+ startDate: windowStartMs,
21706
+ endDate: windowEndMs,
21707
+ maxPages: 1
21708
+ });
21709
+ return true;
21710
+ } catch (error) {
21711
+ if (isRetentionError(error)) return false;
21712
+ throw error;
21713
+ }
21714
+ }
21715
+ async function resolveRetainedStart(options, unservableStartMs, endMs) {
21716
+ const tailStartMs = Math.max(unservableStartMs, endMs - MIN_SUB_WINDOW_MS);
21717
+ if (!await isServable(options, tailStartMs, endMs)) {
21718
+ return endMs;
21719
+ }
21720
+ let lo = unservableStartMs;
21721
+ let hi = tailStartMs;
21722
+ while (hi - lo > RETENTION_BOUNDARY_TOLERANCE_MS) {
21723
+ const mid = lo + Math.floor((hi - lo) / 2);
21724
+ if (await isServable(options, mid, endMs)) {
21725
+ hi = mid;
21726
+ } else {
21727
+ lo = mid;
21728
+ }
21729
+ }
21730
+ return hi;
21731
+ }
21689
21732
  async function drainVercelTrafficEvents(options) {
21690
21733
  const startMs = toMs(options.startDate);
21691
21734
  const endMs = toMs(options.endDate);
21692
21735
  const events = [];
21693
21736
  const seenEventIds = /* @__PURE__ */ new Set();
21694
- if (endMs <= startMs) return { events, subWindowCount: 0 };
21737
+ if (endMs <= startMs) {
21738
+ return { events, subWindowCount: 0, effectiveStartMs: startMs, retentionClamped: false };
21739
+ }
21695
21740
  let cursorMs = startMs;
21696
21741
  let spanMs = endMs - startMs;
21697
21742
  let subWindowCount = 0;
21743
+ let effectiveStartMs = startMs;
21744
+ let retentionClamped = false;
21745
+ let retentionResolved = false;
21698
21746
  while (cursorMs < endMs) {
21699
21747
  if (subWindowCount >= options.maxSubWindows) {
21700
21748
  throw new Error(
@@ -21702,25 +21750,51 @@ async function drainVercelTrafficEvents(options) {
21702
21750
  );
21703
21751
  }
21704
21752
  const subEndMs = Math.min(cursorMs + spanMs, endMs);
21705
- const page = await options.pull({
21706
- token: options.token,
21707
- projectId: options.projectId,
21708
- teamId: options.teamId,
21709
- environment: options.environment,
21710
- startDate: cursorMs,
21711
- endDate: subEndMs,
21712
- maxPages: options.pagesPerSubWindow
21713
- });
21753
+ let page;
21754
+ try {
21755
+ page = await options.pull({
21756
+ token: options.token,
21757
+ projectId: options.projectId,
21758
+ teamId: options.teamId,
21759
+ environment: options.environment,
21760
+ startDate: cursorMs,
21761
+ endDate: subEndMs,
21762
+ maxPages: options.pagesPerSubWindow
21763
+ });
21764
+ } catch (error) {
21765
+ if (isRetentionError(error) && !retentionResolved) {
21766
+ retentionResolved = true;
21767
+ const retainedStartMs = await resolveRetainedStart(options, cursorMs, endMs);
21768
+ retentionClamped = retainedStartMs > cursorMs;
21769
+ cursorMs = retainedStartMs;
21770
+ effectiveStartMs = retainedStartMs;
21771
+ spanMs = Math.max(endMs - cursorMs, MIN_SUB_WINDOW_MS);
21772
+ continue;
21773
+ }
21774
+ throw error;
21775
+ }
21714
21776
  subWindowCount += 1;
21715
21777
  if (page.hasMore) {
21716
21778
  const subSpanMs = subEndMs - cursorMs;
21717
- if (subSpanMs <= MIN_SUB_WINDOW_MS) {
21779
+ if (subSpanMs > MIN_SUB_WINDOW_MS) {
21780
+ spanMs = Math.max(Math.floor(subSpanMs / 2), MIN_SUB_WINDOW_MS);
21781
+ continue;
21782
+ }
21783
+ page = await options.pull({
21784
+ token: options.token,
21785
+ projectId: options.projectId,
21786
+ teamId: options.teamId,
21787
+ environment: options.environment,
21788
+ startDate: cursorMs,
21789
+ endDate: subEndMs,
21790
+ maxPages: FLOOR_SLICE_MAX_PAGES
21791
+ });
21792
+ subWindowCount += 1;
21793
+ if (page.hasMore) {
21718
21794
  throw new Error(
21719
- `Vercel window holds more than ${options.pagesPerSubWindow} pages within a ${MIN_SUB_WINDOW_MS / 6e4}-minute slice \u2014 cannot subdivide further`
21795
+ `Vercel ${MIN_SUB_WINDOW_MS / 6e4}-minute slice holds more than ${FLOOR_SLICE_MAX_PAGES} pages and cannot be drained further`
21720
21796
  );
21721
21797
  }
21722
- spanMs = Math.max(Math.floor(subSpanMs / 2), MIN_SUB_WINDOW_MS);
21723
- continue;
21724
21798
  }
21725
21799
  for (const event of page.events) {
21726
21800
  if (!seenEventIds.has(event.eventId)) {
@@ -21734,7 +21808,7 @@ async function drainVercelTrafficEvents(options) {
21734
21808
  spanMs = Math.min(spanMs * 2, remainingMs);
21735
21809
  }
21736
21810
  }
21737
- return { events, subWindowCount };
21811
+ return { events, subWindowCount, effectiveStartMs, retentionClamped };
21738
21812
  }
21739
21813
 
21740
21814
  // ../api-routes/src/traffic.ts
@@ -21960,8 +22034,12 @@ async function trafficRoutes(app, opts) {
21960
22034
  const { address, family } = check.target;
21961
22035
  return new UndiciAgent({
21962
22036
  connect: {
21963
- lookup: (_hostname, _options, cb) => {
21964
- cb(null, address, family === 6 ? 6 : 4);
22037
+ lookup: (_hostname, options, cb) => {
22038
+ if (options?.all) {
22039
+ cb(null, [{ address, family: family === 6 ? 6 : 4 }]);
22040
+ } else {
22041
+ cb(null, address, family === 6 ? 6 : 4);
22042
+ }
21965
22043
  }
21966
22044
  }
21967
22045
  });
@@ -22416,6 +22494,16 @@ async function trafficRoutes(app, opts) {
22416
22494
  pagesPerSubWindow: vercelMaxPages,
22417
22495
  maxSubWindows: VERCEL_MAX_SUB_WINDOWS
22418
22496
  });
22497
+ if (drained.retentionClamped) {
22498
+ app.log.warn(
22499
+ {
22500
+ sourceId: sourceRow.id,
22501
+ requestedStart: windowStart.toISOString(),
22502
+ servedStart: new Date(drained.effectiveStartMs).toISOString()
22503
+ },
22504
+ "Vercel request-logs retention clamp: sync window predated plan retention; ingested only the portion Vercel still serves"
22505
+ );
22506
+ }
22419
22507
  allEvents = drained.events;
22420
22508
  } catch (e) {
22421
22509
  const msg = e instanceof Error ? e.message : String(e);
@@ -22773,6 +22861,21 @@ async function trafficRoutes(app, opts) {
22773
22861
  pagesPerSubWindow: vercelMaxPages,
22774
22862
  maxSubWindows: VERCEL_MAX_SUB_WINDOWS
22775
22863
  });
22864
+ if (drained.retentionClamped) {
22865
+ const servedDays = Math.round(
22866
+ (windowEnd.getTime() - drained.effectiveStartMs) / 864e5
22867
+ );
22868
+ app.log.warn(
22869
+ {
22870
+ sourceId: sourceRow.id,
22871
+ requestedDays,
22872
+ servedDays,
22873
+ requestedStart: windowStart.toISOString(),
22874
+ servedStart: new Date(drained.effectiveStartMs).toISOString()
22875
+ },
22876
+ "Vercel request-logs retention clamp: backfill window predates plan retention; ingested only the portion Vercel still serves"
22877
+ );
22878
+ }
22776
22879
  return drained.events;
22777
22880
  };
22778
22881
  }
@@ -27694,166 +27797,6 @@ function buildRunCompletedProps(input) {
27694
27797
  return props;
27695
27798
  }
27696
27799
 
27697
- // src/citation-utils.ts
27698
- function domainMatches(domain, canonicalDomain) {
27699
- const normalized = normalizeProjectDomain(canonicalDomain);
27700
- const d = normalizeProjectDomain(domain);
27701
- return d === normalized || d.endsWith(`.${normalized}`);
27702
- }
27703
- function determineCitationState(normalized, domains) {
27704
- for (const canonicalDomain of domains) {
27705
- const bareDomain = normalizeProjectDomain(canonicalDomain);
27706
- if (normalized.citedDomains.some((d) => domainMatches(d, bareDomain))) {
27707
- return "cited";
27708
- }
27709
- const lowerDomain = bareDomain.toLowerCase();
27710
- for (const source of normalized.groundingSources) {
27711
- try {
27712
- const uri = source.uri.toLowerCase();
27713
- if (lowerDomain.includes(".") && uri.includes(lowerDomain)) {
27714
- return "cited";
27715
- }
27716
- } catch {
27717
- }
27718
- if (source.title) {
27719
- const titleLower = source.title.toLowerCase().replace(/^www\./, "");
27720
- if (titleLower === lowerDomain || titleLower.endsWith(`.${lowerDomain}`)) {
27721
- return "cited";
27722
- }
27723
- }
27724
- }
27725
- }
27726
- return "not-cited";
27727
- }
27728
- function computeCompetitorOverlap(normalized, competitorDomains) {
27729
- const overlapSet = /* @__PURE__ */ new Set();
27730
- for (const d of normalized.citedDomains) {
27731
- for (const cd of competitorDomains) {
27732
- if (domainMatches(d, cd)) {
27733
- overlapSet.add(cd);
27734
- }
27735
- }
27736
- }
27737
- for (const source of normalized.groundingSources) {
27738
- const uri = source.uri.toLowerCase();
27739
- for (const cd of competitorDomains) {
27740
- if (uri.includes(cd.toLowerCase())) {
27741
- overlapSet.add(cd);
27742
- }
27743
- }
27744
- }
27745
- if (normalized.answerText) {
27746
- const lowerAnswer = normalized.answerText.toLowerCase();
27747
- for (const cd of competitorDomains) {
27748
- if (lowerAnswer.includes(cd.toLowerCase())) {
27749
- overlapSet.add(cd);
27750
- }
27751
- const brand = brandLabelFromDomain(cd);
27752
- if (brand.length >= 4 && new RegExp(`\\b${escapeRegExp5(brand)}\\b`, "i").test(lowerAnswer)) {
27753
- overlapSet.add(cd);
27754
- }
27755
- }
27756
- }
27757
- return [...overlapSet];
27758
- }
27759
- function escapeRegExp5(value) {
27760
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
27761
- }
27762
- function extractRecommendedCompetitors(answerText, ownDomains, citedDomains, competitorDomains, ownBrandNames = []) {
27763
- if (!answerText || answerText.length < 20) return [];
27764
- const ownBrandKeys = new Set(
27765
- ownDomains.flatMap((domain) => collectBrandKeysFromDomain(domain))
27766
- );
27767
- for (const name of ownBrandNames) {
27768
- const key = brandKeyFromText(name);
27769
- if (key.length >= 4) ownBrandKeys.add(key);
27770
- }
27771
- const knownCompetitorKeys = new Set(
27772
- [...citedDomains, ...competitorDomains].flatMap((domain) => collectBrandKeysFromDomain(domain)).filter((key) => !ownBrandKeys.has(key))
27773
- );
27774
- if (knownCompetitorKeys.size === 0) return [];
27775
- const candidatePatterns = [
27776
- /^\s*(?:[-*]|\d+\.)\s+(?:\*\*)?([A-Z0-9][A-Za-z0-9][\w\s.&',/()-]{1,50}?)(?:\*\*)?\s*[:\u2014\u2013-]/gm,
27777
- /\*\*([A-Z0-9][A-Za-z0-9][\w\s.&',/()-]{1,50})\*\*/g,
27778
- /^#{1,4}\s+(?:\d+\.\s+)?(?:\*\*)?([A-Z0-9][A-Za-z0-9][\w\s.&',/()-]{1,50}?)(?:\*\*)?$/gm,
27779
- /\[([A-Z0-9][A-Za-z0-9][\w\s.&',/()-]{1,50})\]\(https?:\/\/[^\s)]+\)/g
27780
- ];
27781
- const genericKeys = /* @__PURE__ */ new Set([
27782
- "additional",
27783
- "best",
27784
- "benefits",
27785
- "bottomline",
27786
- "comparison",
27787
- "conclusion",
27788
- "directorylisting",
27789
- "example",
27790
- "expertise",
27791
- "features",
27792
- "finalthoughts",
27793
- "howitworks",
27794
- "important",
27795
- "keybenefits",
27796
- "keyfeatures",
27797
- "major",
27798
- "note",
27799
- "notable",
27800
- "option",
27801
- "other",
27802
- "overview",
27803
- "pricing",
27804
- "pros",
27805
- "reviews",
27806
- "step",
27807
- "summary",
27808
- "top",
27809
- "verdict",
27810
- "whattolookfor",
27811
- "whyitmatters",
27812
- "whyitstandsout",
27813
- "whywechoseit"
27814
- ]);
27815
- const seen = /* @__PURE__ */ new Map();
27816
- for (const pattern of candidatePatterns) {
27817
- let match;
27818
- while ((match = pattern.exec(answerText)) !== null) {
27819
- const candidate = cleanCandidateName(match[1] ?? "");
27820
- const candidateKey = brandKeyFromText(candidate);
27821
- if (!candidateKey) continue;
27822
- if (genericKeys.has(candidateKey)) continue;
27823
- if (candidate.split(/\s+/).length > 6) continue;
27824
- if (matchesBrandKey(candidateKey, ownBrandKeys)) continue;
27825
- if (!matchesBrandKey(candidateKey, knownCompetitorKeys)) continue;
27826
- if (!seen.has(candidateKey)) seen.set(candidateKey, candidate);
27827
- }
27828
- }
27829
- return [...seen.values()].slice(0, 10);
27830
- }
27831
- function cleanCandidateName(candidate) {
27832
- return candidate.replace(/^[\s"'`]+|[\s"'`.,:;!?]+$/g, "").replace(/\s+/g, " ").trim();
27833
- }
27834
- function collectBrandKeysFromDomain(domain) {
27835
- const reg = registrableDomain(domain);
27836
- if (!reg) {
27837
- const hostname = normalizeProjectDomain(domain).split("/")[0] ?? "";
27838
- const fallback = hostname.replace(/[^a-z0-9]/gi, "").toLowerCase();
27839
- return fallback.length >= 4 ? [fallback] : [];
27840
- }
27841
- const keys = /* @__PURE__ */ new Set();
27842
- const fullKey = reg.replace(/[^a-z0-9]/gi, "").toLowerCase();
27843
- if (fullKey.length >= 4) keys.add(fullKey);
27844
- const brand = brandLabelFromDomain(reg).replace(/[^a-z0-9]/gi, "").toLowerCase();
27845
- if (brand.length >= 4) keys.add(brand);
27846
- return [...keys];
27847
- }
27848
- function matchesBrandKey(candidateKey, brandKeys) {
27849
- for (const brandKey of brandKeys) {
27850
- if (candidateKey === brandKey) return true;
27851
- if (candidateKey.startsWith(brandKey) || candidateKey.endsWith(brandKey)) return true;
27852
- if (brandKey.startsWith(candidateKey) || brandKey.endsWith(candidateKey)) return true;
27853
- }
27854
- return false;
27855
- }
27856
-
27857
27800
  // src/job-runner.ts
27858
27801
  var log = createLogger("JobRunner");
27859
27802
  var RunCancelledError = class extends Error {
@@ -30063,7 +30006,7 @@ function readStoredGroundingSources(rawResponse) {
30063
30006
  return result;
30064
30007
  }
30065
30008
  async function backfillInsightsCommand(project, opts) {
30066
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-NKAEHHJ5.js");
30009
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-4PT22FED.js");
30067
30010
  const config = loadConfig();
30068
30011
  const db = createClient(config.database);
30069
30012
  migrate(db);
@@ -33077,7 +33020,7 @@ function buildFallbackRecommendedActions(audit) {
33077
33020
  function citesTargetDomain(citedDomains, groundingSources, targetDomain) {
33078
33021
  const normalizedTarget = extractHostname2(targetDomain);
33079
33022
  for (const domain of citedDomains) {
33080
- if (domainMatches2(domain, normalizedTarget)) {
33023
+ if (domainMatches(domain, normalizedTarget)) {
33081
33024
  return true;
33082
33025
  }
33083
33026
  }
@@ -33098,8 +33041,8 @@ function extractCompetitorsFromResponse(ctx) {
33098
33041
  for (const hint of ctx.manualCompetitors) {
33099
33042
  if (isDomainLike(hint)) {
33100
33043
  const normalizedHint = normalizeDomain3(hint);
33101
- if (domainMatches2(normalizedHint, targetDomain)) continue;
33102
- if (ctx.citedDomains.some((domain) => domainMatches2(domain, normalizedHint)) || lowerAnswer.includes(normalizedHint.toLowerCase())) {
33044
+ if (domainMatches(normalizedHint, targetDomain)) continue;
33045
+ if (ctx.citedDomains.some((domain) => domainMatches(domain, normalizedHint)) || lowerAnswer.includes(normalizedHint.toLowerCase())) {
33103
33046
  competitors2.add(normalizedHint);
33104
33047
  }
33105
33048
  continue;
@@ -33169,7 +33112,7 @@ function normalizeDomain3(value) {
33169
33112
  function extractHostname2(value) {
33170
33113
  return normalizeDomain3(value);
33171
33114
  }
33172
- function domainMatches2(candidate, target) {
33115
+ function domainMatches(candidate, target) {
33173
33116
  const normalizedCandidate = normalizeDomain3(candidate);
33174
33117
  const normalizedTarget = normalizeDomain3(target);
33175
33118
  return normalizedCandidate === normalizedTarget || normalizedCandidate.endsWith(`.${normalizedTarget}`);
@@ -22,7 +22,7 @@ import {
22
22
  trafficConnectVercelRequestSchema,
23
23
  trafficConnectWordpressRequestSchema,
24
24
  trafficEventKindSchema
25
- } from "./chunk-OFY3Z2F7.js";
25
+ } from "./chunk-XHU35P3S.js";
26
26
 
27
27
  // src/config.ts
28
28
  import fs from "fs";
@@ -3564,9 +3564,14 @@ var ApiClient = class {
3564
3564
  })
3565
3565
  );
3566
3566
  }
3567
- async listRuns(project, limit) {
3567
+ async listRuns(project, limit, kind) {
3568
3568
  return this.invoke(
3569
- () => getApiV1ProjectsByNameRuns({ client: this.heyClient, path: { name: project }, query: { limit } })
3569
+ () => getApiV1ProjectsByNameRuns({
3570
+ client: this.heyClient,
3571
+ path: { name: project },
3572
+ // kind arrives as a free CLI string; the server validates it against the enum.
3573
+ query: { limit, kind }
3574
+ })
3570
3575
  );
3571
3576
  }
3572
3577
  async getLatestRun(project) {