@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.
- package/assets/agent-workspace/skills/canonry/references/server-side-traffic.md +9 -4
- package/assets/assets/{BacklinksPage-DVmaM864.js → BacklinksPage-buvZ4ZOd.js} +1 -1
- package/assets/assets/{ProjectPage-DtL3LFne.js → ProjectPage-D0UqSqe7.js} +1 -1
- package/assets/assets/{RunRow-BRqiLxj2.js → RunRow-D-DTu1PA.js} +1 -1
- package/assets/assets/{RunsPage-UxZ93-cg.js → RunsPage-CrBpgwkO.js} +1 -1
- package/assets/assets/{SettingsPage-Cr5_EGbk.js → SettingsPage-Bgsi9tZ2.js} +1 -1
- package/assets/assets/{TrafficPage-CUC_lfTe.js → TrafficPage-DAHXrzqz.js} +1 -1
- package/assets/assets/TrafficSourceDetailPage-DCcDN3VD.js +1 -0
- package/assets/assets/{extract-error-message-DD5MibWI.js → extract-error-message-BGhWiJPr.js} +1 -1
- package/assets/assets/{index-nnF1LnyK.js → index-CbDkoDBH.js} +2 -2
- package/assets/assets/{index-Bm3JQsW0.css → index-dxdJhCQO.css} +1 -1
- package/assets/assets/{server-traffic-DjRISEZ-.js → server-traffic-3xxyOEIX.js} +1 -1
- package/assets/assets/{trash-2-CJ5M--Le.js → trash-2-dppRdHYI.js} +1 -1
- package/assets/index.html +2 -2
- package/dist/{chunk-2OI7HFAB.js → chunk-5EAGNVCJ.js} +131 -188
- package/dist/{chunk-ZY3EDW3S.js → chunk-UOQ62KDD.js} +8 -3
- package/dist/{chunk-UTM3FPAJ.js → chunk-XB6Y63NI.js} +181 -3
- package/dist/{chunk-OFY3Z2F7.js → chunk-XHU35P3S.js} +359 -361
- package/dist/cli.js +12 -10
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-NKAEHHJ5.js → intelligence-service-4PT22FED.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +6 -6
- 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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
|
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)
|
|
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
|
-
|
|
21706
|
-
|
|
21707
|
-
|
|
21708
|
-
|
|
21709
|
-
|
|
21710
|
-
|
|
21711
|
-
|
|
21712
|
-
|
|
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
|
|
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
|
|
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,
|
|
21964
|
-
|
|
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-
|
|
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 (
|
|
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 (
|
|
33102
|
-
if (ctx.citedDomains.some((domain) =>
|
|
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
|
|
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-
|
|
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({
|
|
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) {
|