@canonry/canonry 4.128.0 → 4.129.1
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/README.md +15 -10
- package/assets/agent-workspace/skills/aero/SKILL.md +15 -7
- package/assets/agent-workspace/skills/aero/references/aeo-discovery.md +3 -1
- package/assets/agent-workspace/skills/aero/references/orchestration.md +5 -3
- package/assets/agent-workspace/skills/aero/soul.md +1 -1
- package/assets/agent-workspace/skills/canonry/SKILL.md +50 -13
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +9 -1
- package/assets/agent-workspace/skills/canonry/references/indexing.md +4 -2
- package/assets/assets/{AuditHistoryPanel-DwJpVWme.js → AuditHistoryPanel-wJqs99Ak.js} +1 -1
- package/assets/assets/{BacklinksPage-K8FQUBxI.js → BacklinksPage-BBDExYo_.js} +1 -1
- package/assets/assets/{ChartPrimitives-6oFKrJFk.js → ChartPrimitives-DSr5ldMf.js} +1 -1
- package/assets/assets/{HistoryPage-DwOAoN1Z.js → HistoryPage-Ca-GGnTI.js} +1 -1
- package/assets/assets/{ProjectPage-CdgFUk7h.js → ProjectPage-BuaSDSwf.js} +1 -1
- package/assets/assets/{RunRow-lt9IS99U.js → RunRow-O9TbOdQY.js} +1 -1
- package/assets/assets/{RunsPage-DitYcIdx.js → RunsPage-C1Sqd7AN.js} +1 -1
- package/assets/assets/{SettingsPage-CAOrh65Q.js → SettingsPage-DPFh62BV.js} +1 -1
- package/assets/assets/{TrafficPage-BqzNvx75.js → TrafficPage-5vKoQyoP.js} +1 -1
- package/assets/assets/TrafficSourceDetailPage-D17oADs8.js +1 -0
- package/assets/assets/{arrow-left-AmG4gtUR.js → arrow-left-De5P5AIE.js} +1 -1
- package/assets/assets/extract-error-message-BqMd-fQ6.js +1 -0
- package/assets/assets/{index-BiCDkOH4.js → index-C1ABEgkr.js} +53 -53
- package/assets/assets/{trash-2-gFHWd1A1.js → trash-2-6ZpABj9G.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-ZKUSY4PI.js → chunk-GYAKRVE2.js} +25 -5
- package/dist/{chunk-BLSHHRRU.js → chunk-K4FDDCYG.js} +29 -0
- package/dist/{chunk-NCFH26X5.js → chunk-LPEE5AYY.js} +198 -25
- package/dist/{chunk-IHRW6WWV.js → chunk-WWZE7VDQ.js} +10 -6
- package/dist/cli.js +226 -38
- package/dist/index.d.ts +3 -1
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-SH5Z6JFT.js → intelligence-service-2QBAGT5X.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +7 -7
- package/assets/assets/TrafficSourceDetailPage-DXbygZUA.js +0 -1
- package/assets/assets/extract-error-message-DlVtjoPz.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c}from"./index-
|
|
1
|
+
import{c}from"./index-C1ABEgkr.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,7 +12,7 @@
|
|
|
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-C1ABEgkr.js"></script>
|
|
16
16
|
<link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-Be8JdV5M.js">
|
|
17
17
|
<link rel="modulepreload" crossorigin href="./assets/vendor-radix-CQ77EO2y.js">
|
|
18
18
|
<link rel="modulepreload" crossorigin href="./assets/vendor-recharts-DSxTZhaH.js">
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
loadConfig,
|
|
11
11
|
loadConfigRaw,
|
|
12
12
|
saveConfigPatch
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-WWZE7VDQ.js";
|
|
14
14
|
import {
|
|
15
15
|
CC_CACHE_DIR,
|
|
16
16
|
DUCKDB_SPEC,
|
|
@@ -116,7 +116,7 @@ import {
|
|
|
116
116
|
siteAuditPages,
|
|
117
117
|
siteAuditSnapshots,
|
|
118
118
|
usageCounters
|
|
119
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-LPEE5AYY.js";
|
|
120
120
|
import {
|
|
121
121
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
122
122
|
AGENT_PROVIDER_IDS,
|
|
@@ -186,7 +186,7 @@ import {
|
|
|
186
186
|
validationError,
|
|
187
187
|
winnabilityClassLabel,
|
|
188
188
|
withRetry
|
|
189
|
-
} from "./chunk-
|
|
189
|
+
} from "./chunk-K4FDDCYG.js";
|
|
190
190
|
|
|
191
191
|
// src/telemetry.ts
|
|
192
192
|
import crypto from "crypto";
|
|
@@ -6967,7 +6967,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
6967
6967
|
return result;
|
|
6968
6968
|
}
|
|
6969
6969
|
async function backfillInsightsCommand(project, opts) {
|
|
6970
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
6970
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-2QBAGT5X.js");
|
|
6971
6971
|
const config = loadConfig();
|
|
6972
6972
|
const db = createClient(config.database);
|
|
6973
6973
|
migrate(db);
|
|
@@ -7776,7 +7776,7 @@ function emitInstallSummary(summary, format) {
|
|
|
7776
7776
|
Target: ${summary.targetDir}`);
|
|
7777
7777
|
console.log(summary.message);
|
|
7778
7778
|
}
|
|
7779
|
-
function getMissingUserSkillsNudge(home) {
|
|
7779
|
+
function getMissingUserSkillsNudge(home, agentPlugin) {
|
|
7780
7780
|
if (!home) return null;
|
|
7781
7781
|
const skillsBase = path5.join(home, ".claude", "skills");
|
|
7782
7782
|
const installed = [];
|
|
@@ -7786,6 +7786,25 @@ function getMissingUserSkillsNudge(home) {
|
|
|
7786
7786
|
if (existsSafe(skillFile)) installed.push(name);
|
|
7787
7787
|
else missing.push(name);
|
|
7788
7788
|
}
|
|
7789
|
+
if (agentPlugin && agentPlugin.configuredClients.length > 0) {
|
|
7790
|
+
const unverifiedClients = agentPlugin.configuredClients.filter((client) => !agentPlugin.verifiedClients.includes(client));
|
|
7791
|
+
const mismatchedClients = agentPlugin.verifiedClients.filter((client) => agentPlugin.verifiedClientVersions?.[client] !== PACKAGE_VERSION);
|
|
7792
|
+
if (unverifiedClients.length === 0 && mismatchedClients.length === 0) return null;
|
|
7793
|
+
const displayClients = (clients) => clients.map((client) => client === "claude-code" ? "Claude Code" : "Codex").join(" + ");
|
|
7794
|
+
const problems = [];
|
|
7795
|
+
if (unverifiedClients.length > 0) {
|
|
7796
|
+
problems.push(`The Canonry plugin is enabled for ${displayClients(unverifiedClients)}, but its cached manifest and skill assets could not be verified.`);
|
|
7797
|
+
}
|
|
7798
|
+
if (mismatchedClients.length > 0) {
|
|
7799
|
+
const versions = mismatchedClients.map((client) => `${client === "claude-code" ? "Claude Code" : "Codex"} v${agentPlugin.verifiedClientVersions?.[client] ?? "unknown"}`).join(", ");
|
|
7800
|
+
problems.push(`${versions} ${mismatchedClients.length === 1 ? "does" : "do"} not match the running Canonry v${PACKAGE_VERSION}.`);
|
|
7801
|
+
}
|
|
7802
|
+
return {
|
|
7803
|
+
message: `Tip: ${problems.join(" ")} Update or reinstall \`canonry@canonry\` with the affected client plugin manager.`,
|
|
7804
|
+
missing,
|
|
7805
|
+
installed
|
|
7806
|
+
};
|
|
7807
|
+
}
|
|
7789
7808
|
if (missing.length === 0) return null;
|
|
7790
7809
|
const fix = missing.length === BUNDLED_SKILL_NAMES.length ? "canonry skills install --user" : `canonry skills install ${missing.join(" ")} --user`;
|
|
7791
7810
|
return {
|
|
@@ -12574,6 +12593,7 @@ async function createServer(opts) {
|
|
|
12574
12593
|
return void 0;
|
|
12575
12594
|
}
|
|
12576
12595
|
})(),
|
|
12596
|
+
getAgentPluginState: opts.getAgentPluginState,
|
|
12577
12597
|
// Local canonry serve runs on the operator's machine, where pointing a
|
|
12578
12598
|
// webhook at localhost (Discord test container, Pipedream-mock dev server,
|
|
12579
12599
|
// etc.) is a legitimate workflow. Default to allowing it for the local
|
|
@@ -5995,6 +5995,18 @@ var trafficStatusResponseSchema = z34.object({
|
|
|
5995
5995
|
});
|
|
5996
5996
|
var trafficEventKindSchema = z34.enum(["crawler", "ai-user-fetch", "ai-referral"]);
|
|
5997
5997
|
var TrafficEventKinds = trafficEventKindSchema.enum;
|
|
5998
|
+
var trafficSeriesGranularitySchema = z34.enum(["hour", "day"]);
|
|
5999
|
+
var TrafficSeriesGranularities = trafficSeriesGranularitySchema.enum;
|
|
6000
|
+
var trafficSeriesPointSchema = z34.object({
|
|
6001
|
+
/**
|
|
6002
|
+
* UTC bucket key: an ISO hour for hourly series, or `YYYY-MM-DD` for daily
|
|
6003
|
+
* series. The response includes zero-value buckets across the full window.
|
|
6004
|
+
*/
|
|
6005
|
+
bucket: z34.string(),
|
|
6006
|
+
crawlerHits: z34.number().int().nonnegative(),
|
|
6007
|
+
aiUserFetchHits: z34.number().int().nonnegative(),
|
|
6008
|
+
aiReferralHits: z34.number().int().nonnegative()
|
|
6009
|
+
});
|
|
5998
6010
|
var trafficCrawlerEventEntrySchema = z34.object({
|
|
5999
6011
|
kind: z34.literal(TrafficEventKinds.crawler),
|
|
6000
6012
|
sourceId: z34.string(),
|
|
@@ -6050,6 +6062,14 @@ var trafficEventEntrySchema = z34.discriminatedUnion("kind", [
|
|
|
6050
6062
|
var trafficEventsResponseSchema = z34.object({
|
|
6051
6063
|
windowStart: z34.string(),
|
|
6052
6064
|
windowEnd: z34.string(),
|
|
6065
|
+
/**
|
|
6066
|
+
* Full-window chart data, aggregated independently from the capped detail
|
|
6067
|
+
* rows below. This prevents dense windows from silently losing old buckets.
|
|
6068
|
+
*/
|
|
6069
|
+
series: z34.object({
|
|
6070
|
+
granularity: trafficSeriesGranularitySchema,
|
|
6071
|
+
points: z34.array(trafficSeriesPointSchema)
|
|
6072
|
+
}),
|
|
6053
6073
|
totals: z34.object({
|
|
6054
6074
|
/** Total classified-crawler hits across the window. UNCHANGED contract. */
|
|
6055
6075
|
crawlerHits: z34.number().int().nonnegative(),
|
|
@@ -6069,6 +6089,13 @@ var trafficEventsResponseSchema = z34.object({
|
|
|
6069
6089
|
/** AI-referral sessions ingested before the classifier shipped; unresolvable, never organic. */
|
|
6070
6090
|
aiReferralUnknownHits: z34.number().int().nonnegative()
|
|
6071
6091
|
}),
|
|
6092
|
+
eventRows: z34.object({
|
|
6093
|
+
/** Total detail rows matching the window/source/kind filters before `limit`. */
|
|
6094
|
+
total: z34.number().int().nonnegative(),
|
|
6095
|
+
/** Number of newest detail rows included in `events`. */
|
|
6096
|
+
returned: z34.number().int().nonnegative(),
|
|
6097
|
+
truncated: z34.boolean()
|
|
6098
|
+
}),
|
|
6072
6099
|
events: z34.array(trafficEventEntrySchema)
|
|
6073
6100
|
});
|
|
6074
6101
|
|
|
@@ -7420,6 +7447,8 @@ export {
|
|
|
7420
7447
|
trafficStatusResponseSchema,
|
|
7421
7448
|
trafficEventKindSchema,
|
|
7422
7449
|
TrafficEventKinds,
|
|
7450
|
+
trafficSeriesGranularitySchema,
|
|
7451
|
+
TrafficSeriesGranularities,
|
|
7423
7452
|
trafficEventsResponseSchema,
|
|
7424
7453
|
classifyTrafficPath,
|
|
7425
7454
|
segmentCrawlerHits,
|
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
TrafficEventConfidences,
|
|
48
48
|
TrafficEventKinds,
|
|
49
49
|
TrafficEvidenceKinds,
|
|
50
|
+
TrafficSeriesGranularities,
|
|
50
51
|
TrafficSourceAuthModes,
|
|
51
52
|
TrafficSourceStatuses,
|
|
52
53
|
TrafficSourceTypes,
|
|
@@ -336,7 +337,7 @@ import {
|
|
|
336
337
|
wordpressSchemaDeployResultDtoSchema,
|
|
337
338
|
wordpressSchemaStatusResultDtoSchema,
|
|
338
339
|
wordpressStatusDtoSchema
|
|
339
|
-
} from "./chunk-
|
|
340
|
+
} from "./chunk-K4FDDCYG.js";
|
|
340
341
|
|
|
341
342
|
// src/intelligence-service.ts
|
|
342
343
|
import { eq as eq41, desc as desc18, asc as asc9, and as and32, ne as ne6, or as or8, inArray as inArray15, gte as gte10, lte as lte6 } from "drizzle-orm";
|
|
@@ -20791,15 +20792,16 @@ var routeCatalog = [
|
|
|
20791
20792
|
method: "get",
|
|
20792
20793
|
path: "/api/v1/projects/{name}/traffic/events",
|
|
20793
20794
|
summary: "List rolled-up crawler hits, AI user-fetch hits, and AI-referral sessions within a window",
|
|
20794
|
-
description: "Returns hourly
|
|
20795
|
+
description: "Returns full-window hourly or daily chart series plus newest-first detail rows from `crawler_events_hourly`, `ai_user_fetch_events_hourly`, and `ai_referral_events_hourly`. Defaults to the last 24h. Totals and `series.points` reflect the full window; only the `events` array is capped by `limit` (default 500, max 5000). `eventRows` reports the true pre-limit row count.",
|
|
20795
20796
|
tags: ["traffic"],
|
|
20796
20797
|
parameters: [
|
|
20797
20798
|
nameParameter,
|
|
20798
20799
|
{ name: "since", in: "query", description: "ISO-8601 window start (defaults to 24h ago).", schema: stringSchema },
|
|
20799
20800
|
{ name: "until", in: "query", description: "ISO-8601 window end (defaults to now).", schema: stringSchema },
|
|
20800
20801
|
{ name: "kind", in: "query", description: 'Filter to "crawler", "ai-user-fetch", "ai-referral", or "all" (default).', schema: stringSchema },
|
|
20801
|
-
{ name: "limit", in: "query", description: "Max
|
|
20802
|
-
{ name: "sourceId", in: "query", description: "Restrict to a single traffic source.", schema: stringSchema }
|
|
20802
|
+
{ name: "limit", in: "query", description: "Max newest combined detail rows in the events array (default 500, max 5000).", schema: stringSchema },
|
|
20803
|
+
{ name: "sourceId", in: "query", description: "Restrict to a single traffic source.", schema: stringSchema },
|
|
20804
|
+
{ name: "granularity", in: "query", description: 'Full-window series bucket size: "hour" (default) or "day".', schema: { type: "string", enum: ["hour", "day"] } }
|
|
20803
20805
|
],
|
|
20804
20806
|
responses: {
|
|
20805
20807
|
200: jsonResponse("Events returned with windowed totals.", "TrafficEventsResponse"),
|
|
@@ -23338,6 +23340,13 @@ function stableStringify3(value) {
|
|
|
23338
23340
|
}
|
|
23339
23341
|
|
|
23340
23342
|
// ../api-routes/src/google.ts
|
|
23343
|
+
function isOnProjectDomain(url, projectDomain) {
|
|
23344
|
+
try {
|
|
23345
|
+
return new URL(url).hostname.toLowerCase().replace(/^www\./, "") === projectDomain;
|
|
23346
|
+
} catch {
|
|
23347
|
+
return false;
|
|
23348
|
+
}
|
|
23349
|
+
}
|
|
23341
23350
|
function scopesForConnectionType(type) {
|
|
23342
23351
|
switch (type) {
|
|
23343
23352
|
case "gsc":
|
|
@@ -24142,14 +24151,21 @@ async function googleRoutes(app, opts) {
|
|
|
24142
24151
|
latestByUrl.set(row.url, row);
|
|
24143
24152
|
}
|
|
24144
24153
|
}
|
|
24154
|
+
const gatherDomain = normalizeProjectDomain(project.canonicalDomain);
|
|
24145
24155
|
const unindexedUrls = [];
|
|
24156
|
+
let skippedOtherHost = 0;
|
|
24146
24157
|
for (const [url, row] of latestByUrl) {
|
|
24147
|
-
if (row.indexingState
|
|
24148
|
-
|
|
24158
|
+
if (row.indexingState === "INDEXING_ALLOWED") continue;
|
|
24159
|
+
if (!isOnProjectDomain(url, gatherDomain)) {
|
|
24160
|
+
skippedOtherHost += 1;
|
|
24161
|
+
continue;
|
|
24149
24162
|
}
|
|
24163
|
+
unindexedUrls.push(url);
|
|
24150
24164
|
}
|
|
24151
24165
|
if (unindexedUrls.length === 0) {
|
|
24152
|
-
throw validationError(
|
|
24166
|
+
throw validationError(
|
|
24167
|
+
skippedOtherHost > 0 ? `No unindexed URLs found on "${project.canonicalDomain}" (skipped ${skippedOtherHost} on other hosts). Run "canonry google inspect-sitemap" first.` : 'No unindexed URLs found. Run "canonry google inspect-sitemap" first.'
|
|
24168
|
+
);
|
|
24153
24169
|
}
|
|
24154
24170
|
urlsToNotify = unindexedUrls;
|
|
24155
24171
|
}
|
|
@@ -24160,14 +24176,7 @@ async function googleRoutes(app, opts) {
|
|
|
24160
24176
|
throw validationError(`Cannot request indexing for more than ${INDEXING_API_DAILY_LIMIT} URLs per request (got ${urlsToNotify.length})`);
|
|
24161
24177
|
}
|
|
24162
24178
|
const projectDomain = normalizeProjectDomain(project.canonicalDomain);
|
|
24163
|
-
const invalidUrls = urlsToNotify.filter((url) =>
|
|
24164
|
-
try {
|
|
24165
|
-
const hostname = new URL(url).hostname.toLowerCase().replace(/^www\./, "");
|
|
24166
|
-
return hostname !== projectDomain;
|
|
24167
|
-
} catch {
|
|
24168
|
-
return true;
|
|
24169
|
-
}
|
|
24170
|
-
});
|
|
24179
|
+
const invalidUrls = urlsToNotify.filter((url) => !isOnProjectDomain(url, projectDomain));
|
|
24171
24180
|
if (invalidUrls.length > 0) {
|
|
24172
24181
|
throw validationError(
|
|
24173
24182
|
`URLs must belong to project domain "${project.canonicalDomain}". Invalid: ${invalidUrls.slice(0, 5).join(", ")}`
|
|
@@ -36915,6 +36924,35 @@ var DEFAULT_TRAFFIC_SYNC_CRON = "*/30 * * * *";
|
|
|
36915
36924
|
var MAX_BACKFILL_DAYS = 90;
|
|
36916
36925
|
var BACKFILL_MAX_PAGES = 1e3;
|
|
36917
36926
|
var BACKFILL_SAMPLE_LIMIT = 500;
|
|
36927
|
+
function emptyTrafficSeriesPoint(bucket) {
|
|
36928
|
+
return { bucket, crawlerHits: 0, aiUserFetchHits: 0, aiReferralHits: 0 };
|
|
36929
|
+
}
|
|
36930
|
+
function completeTrafficSeries(windowStart, windowEnd, granularity, pointsByBucket) {
|
|
36931
|
+
const cursor = new Date(windowStart);
|
|
36932
|
+
const last = new Date(windowEnd);
|
|
36933
|
+
if (granularity === TrafficSeriesGranularities.day) {
|
|
36934
|
+
cursor.setUTCHours(0, 0, 0, 0);
|
|
36935
|
+
last.setUTCHours(0, 0, 0, 0);
|
|
36936
|
+
} else {
|
|
36937
|
+
cursor.setUTCMinutes(0, 0, 0);
|
|
36938
|
+
last.setUTCMinutes(0, 0, 0);
|
|
36939
|
+
}
|
|
36940
|
+
const points = [];
|
|
36941
|
+
while (cursor <= last) {
|
|
36942
|
+
const bucket = granularity === TrafficSeriesGranularities.day ? cursor.toISOString().slice(0, 10) : cursor.toISOString();
|
|
36943
|
+
points.push(pointsByBucket.get(bucket) ?? emptyTrafficSeriesPoint(bucket));
|
|
36944
|
+
if (granularity === TrafficSeriesGranularities.day) cursor.setUTCDate(cursor.getUTCDate() + 1);
|
|
36945
|
+
else cursor.setUTCHours(cursor.getUTCHours() + 1);
|
|
36946
|
+
}
|
|
36947
|
+
return points;
|
|
36948
|
+
}
|
|
36949
|
+
function trafficSeriesPoint(pointsByBucket, bucket) {
|
|
36950
|
+
const existing = pointsByBucket.get(bucket);
|
|
36951
|
+
if (existing) return existing;
|
|
36952
|
+
const created = emptyTrafficSeriesPoint(bucket);
|
|
36953
|
+
pointsByBucket.set(bucket, created);
|
|
36954
|
+
return created;
|
|
36955
|
+
}
|
|
36918
36956
|
function parseSourceConfig(row) {
|
|
36919
36957
|
return row.configJson;
|
|
36920
36958
|
}
|
|
@@ -38290,6 +38328,17 @@ async function trafficRoutes(app, opts) {
|
|
|
38290
38328
|
throw validationError('"limit" must be a positive integer');
|
|
38291
38329
|
}
|
|
38292
38330
|
const limit = Math.min(requestedLimit, 5e3);
|
|
38331
|
+
const granularityParam = request.query?.granularity;
|
|
38332
|
+
let granularity = TrafficSeriesGranularities.hour;
|
|
38333
|
+
if (granularityParam !== void 0) {
|
|
38334
|
+
if (granularityParam === TrafficSeriesGranularities.hour || granularityParam === TrafficSeriesGranularities.day) {
|
|
38335
|
+
granularity = granularityParam;
|
|
38336
|
+
} else {
|
|
38337
|
+
throw validationError(
|
|
38338
|
+
`"granularity" must be one of: ${TrafficSeriesGranularities.hour}, ${TrafficSeriesGranularities.day}`
|
|
38339
|
+
);
|
|
38340
|
+
}
|
|
38341
|
+
}
|
|
38293
38342
|
const sourceIdParam = request.query?.sourceId;
|
|
38294
38343
|
const sinceIso = since.toISOString();
|
|
38295
38344
|
const untilIso = until.toISOString();
|
|
@@ -38298,6 +38347,8 @@ async function trafficRoutes(app, opts) {
|
|
|
38298
38347
|
let crawlerSegments = { content: 0, sitemap: 0, robots: 0, asset: 0, other: 0 };
|
|
38299
38348
|
let aiUserFetchTotal = 0;
|
|
38300
38349
|
let aiReferralCounts = aiReferralClassCounts(0, 0, 0);
|
|
38350
|
+
let totalEventRows = 0;
|
|
38351
|
+
const seriesByBucket = /* @__PURE__ */ new Map();
|
|
38301
38352
|
if (kind === "all" || kind === TrafficEventKinds.crawler) {
|
|
38302
38353
|
const crawlerFilters = [
|
|
38303
38354
|
eq31(crawlerEventsHourly.projectId, project.id),
|
|
@@ -38308,12 +38359,22 @@ async function trafficRoutes(app, opts) {
|
|
|
38308
38359
|
const crawlerWhere = and26(...crawlerFilters);
|
|
38309
38360
|
const pathTotals = app.db.select({
|
|
38310
38361
|
pathNormalized: crawlerEventsHourly.pathNormalized,
|
|
38311
|
-
hits: sql14`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)
|
|
38362
|
+
hits: sql14`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`,
|
|
38363
|
+
rows: sql14`COUNT(*)`
|
|
38312
38364
|
}).from(crawlerEventsHourly).where(crawlerWhere).groupBy(crawlerEventsHourly.pathNormalized).all();
|
|
38313
38365
|
crawlerSegments = segmentCrawlerHits(
|
|
38314
38366
|
pathTotals.map((r) => ({ pathNormalized: r.pathNormalized, hits: Number(r.hits) }))
|
|
38315
38367
|
);
|
|
38316
38368
|
crawlerTotal = crawlerSegments.content + crawlerSegments.sitemap + crawlerSegments.robots + crawlerSegments.asset + crawlerSegments.other;
|
|
38369
|
+
totalEventRows += pathTotals.reduce((sum, row) => sum + Number(row.rows), 0);
|
|
38370
|
+
const crawlerSeriesBucket = granularity === TrafficSeriesGranularities.day ? sql14`substr(${crawlerEventsHourly.tsHour}, 1, 10)` : crawlerEventsHourly.tsHour;
|
|
38371
|
+
const crawlerSeries = app.db.select({
|
|
38372
|
+
bucket: crawlerSeriesBucket,
|
|
38373
|
+
hits: sql14`COALESCE(SUM(${crawlerEventsHourly.hits}), 0)`
|
|
38374
|
+
}).from(crawlerEventsHourly).where(crawlerWhere).groupBy(crawlerSeriesBucket).all();
|
|
38375
|
+
for (const row of crawlerSeries) {
|
|
38376
|
+
trafficSeriesPoint(seriesByBucket, row.bucket).crawlerHits = Number(row.hits);
|
|
38377
|
+
}
|
|
38317
38378
|
const rows = app.db.select().from(crawlerEventsHourly).where(crawlerWhere).orderBy(desc15(crawlerEventsHourly.tsHour)).limit(limit).all();
|
|
38318
38379
|
for (const r of rows) {
|
|
38319
38380
|
events.push({
|
|
@@ -38338,8 +38399,20 @@ async function trafficRoutes(app, opts) {
|
|
|
38338
38399
|
];
|
|
38339
38400
|
if (sourceIdParam) userFetchFilters.push(eq31(aiUserFetchEventsHourly.sourceId, sourceIdParam));
|
|
38340
38401
|
const userFetchWhere = and26(...userFetchFilters);
|
|
38341
|
-
const total = app.db.select({
|
|
38402
|
+
const total = app.db.select({
|
|
38403
|
+
total: sql14`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`,
|
|
38404
|
+
rows: sql14`COUNT(*)`
|
|
38405
|
+
}).from(aiUserFetchEventsHourly).where(userFetchWhere).get();
|
|
38342
38406
|
aiUserFetchTotal = Number(total?.total ?? 0);
|
|
38407
|
+
totalEventRows += Number(total?.rows ?? 0);
|
|
38408
|
+
const userFetchSeriesBucket = granularity === TrafficSeriesGranularities.day ? sql14`substr(${aiUserFetchEventsHourly.tsHour}, 1, 10)` : aiUserFetchEventsHourly.tsHour;
|
|
38409
|
+
const userFetchSeries = app.db.select({
|
|
38410
|
+
bucket: userFetchSeriesBucket,
|
|
38411
|
+
hits: sql14`COALESCE(SUM(${aiUserFetchEventsHourly.hits}), 0)`
|
|
38412
|
+
}).from(aiUserFetchEventsHourly).where(userFetchWhere).groupBy(userFetchSeriesBucket).all();
|
|
38413
|
+
for (const row of userFetchSeries) {
|
|
38414
|
+
trafficSeriesPoint(seriesByBucket, row.bucket).aiUserFetchHits = Number(row.hits);
|
|
38415
|
+
}
|
|
38343
38416
|
const rows = app.db.select().from(aiUserFetchEventsHourly).where(userFetchWhere).orderBy(desc15(aiUserFetchEventsHourly.tsHour)).limit(limit).all();
|
|
38344
38417
|
for (const r of rows) {
|
|
38345
38418
|
events.push({
|
|
@@ -38366,13 +38439,23 @@ async function trafficRoutes(app, opts) {
|
|
|
38366
38439
|
const total = app.db.select({
|
|
38367
38440
|
total: sql14`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`,
|
|
38368
38441
|
paid: sql14`COALESCE(SUM(${aiReferralEventsHourly.paidSessionsOrHits}), 0)`,
|
|
38369
|
-
organic: sql14`COALESCE(SUM(${aiReferralEventsHourly.organicSessionsOrHits}), 0)
|
|
38442
|
+
organic: sql14`COALESCE(SUM(${aiReferralEventsHourly.organicSessionsOrHits}), 0)`,
|
|
38443
|
+
rows: sql14`COUNT(*)`
|
|
38370
38444
|
}).from(aiReferralEventsHourly).where(aiWhere).get();
|
|
38371
38445
|
aiReferralCounts = aiReferralClassCounts(
|
|
38372
38446
|
Number(total?.total ?? 0),
|
|
38373
38447
|
Number(total?.paid ?? 0),
|
|
38374
38448
|
Number(total?.organic ?? 0)
|
|
38375
38449
|
);
|
|
38450
|
+
totalEventRows += Number(total?.rows ?? 0);
|
|
38451
|
+
const referralSeriesBucket = granularity === TrafficSeriesGranularities.day ? sql14`substr(${aiReferralEventsHourly.tsHour}, 1, 10)` : aiReferralEventsHourly.tsHour;
|
|
38452
|
+
const referralSeries = app.db.select({
|
|
38453
|
+
bucket: referralSeriesBucket,
|
|
38454
|
+
hits: sql14`COALESCE(SUM(${aiReferralEventsHourly.sessionsOrHits}), 0)`
|
|
38455
|
+
}).from(aiReferralEventsHourly).where(aiWhere).groupBy(referralSeriesBucket).all();
|
|
38456
|
+
for (const row of referralSeries) {
|
|
38457
|
+
trafficSeriesPoint(seriesByBucket, row.bucket).aiReferralHits = Number(row.hits);
|
|
38458
|
+
}
|
|
38376
38459
|
const rows = app.db.select().from(aiReferralEventsHourly).where(aiWhere).orderBy(desc15(aiReferralEventsHourly.tsHour)).limit(limit).all();
|
|
38377
38460
|
for (const r of rows) {
|
|
38378
38461
|
const counts2 = aiReferralClassCounts(r.sessionsOrHits, r.paidSessionsOrHits, r.organicSessionsOrHits);
|
|
@@ -38398,6 +38481,10 @@ async function trafficRoutes(app, opts) {
|
|
|
38398
38481
|
const response = {
|
|
38399
38482
|
windowStart: sinceIso,
|
|
38400
38483
|
windowEnd: untilIso,
|
|
38484
|
+
series: {
|
|
38485
|
+
granularity,
|
|
38486
|
+
points: completeTrafficSeries(since, until, granularity, seriesByBucket)
|
|
38487
|
+
},
|
|
38401
38488
|
totals: {
|
|
38402
38489
|
crawlerHits: crawlerTotal,
|
|
38403
38490
|
crawlerContentHits: crawlerSegments.content,
|
|
@@ -38409,6 +38496,11 @@ async function trafficRoutes(app, opts) {
|
|
|
38409
38496
|
aiReferralOrganicHits: aiReferralCounts.organic,
|
|
38410
38497
|
aiReferralUnknownHits: aiReferralCounts.unknown
|
|
38411
38498
|
},
|
|
38499
|
+
eventRows: {
|
|
38500
|
+
total: totalEventRows,
|
|
38501
|
+
returned: trimmed.length,
|
|
38502
|
+
truncated: trimmed.length < totalEventRows
|
|
38503
|
+
},
|
|
38412
38504
|
events: trimmed
|
|
38413
38505
|
};
|
|
38414
38506
|
return response;
|
|
@@ -38420,12 +38512,47 @@ import crypto29 from "crypto";
|
|
|
38420
38512
|
import fs6 from "fs";
|
|
38421
38513
|
import path7 from "path";
|
|
38422
38514
|
var REQUIRED_SKILLS = ["canonry", "aero"];
|
|
38515
|
+
function pluginStateFor(ctx) {
|
|
38516
|
+
try {
|
|
38517
|
+
return ctx.getAgentPluginState?.();
|
|
38518
|
+
} catch {
|
|
38519
|
+
return void 0;
|
|
38520
|
+
}
|
|
38521
|
+
}
|
|
38522
|
+
function unverifiedPluginClients(state) {
|
|
38523
|
+
if (!state) return [];
|
|
38524
|
+
return state.configuredClients.filter((client) => !state.verifiedClients.includes(client));
|
|
38525
|
+
}
|
|
38526
|
+
function displayPluginClients(clients) {
|
|
38527
|
+
return clients.map((client) => client === "claude-code" ? "Claude Code" : "Codex").join(" + ");
|
|
38528
|
+
}
|
|
38423
38529
|
var skillsInstalledCheck = {
|
|
38424
38530
|
id: "agent.skills.installed",
|
|
38425
38531
|
category: CheckCategories.agent,
|
|
38426
38532
|
scope: CheckScopes.global,
|
|
38427
|
-
title: "Agent skills
|
|
38428
|
-
run: () => {
|
|
38533
|
+
title: "Agent skills available",
|
|
38534
|
+
run: (ctx) => {
|
|
38535
|
+
const agentPlugin = pluginStateFor(ctx);
|
|
38536
|
+
const unverifiedClients = unverifiedPluginClients(agentPlugin);
|
|
38537
|
+
if (unverifiedClients.length > 0) {
|
|
38538
|
+
return {
|
|
38539
|
+
status: CheckStatuses.warn,
|
|
38540
|
+
code: "agent.skills.plugin-unverified",
|
|
38541
|
+
summary: `The Canonry plugin is enabled for ${displayPluginClients(unverifiedClients)}, but its cached manifest and skill assets could not be verified.`,
|
|
38542
|
+
remediation: "Reinstall `canonry@canonry` with the affected client plugin manager, or disable the stale plugin entry.",
|
|
38543
|
+
details: { delivery: "plugin", ...agentPlugin, unverifiedClients }
|
|
38544
|
+
};
|
|
38545
|
+
}
|
|
38546
|
+
if (agentPlugin && agentPlugin.configuredClients.length > 0) {
|
|
38547
|
+
const clients = displayPluginClients(agentPlugin.verifiedClients);
|
|
38548
|
+
return {
|
|
38549
|
+
status: CheckStatuses.ok,
|
|
38550
|
+
code: "agent.skills.plugin-installed",
|
|
38551
|
+
summary: `Canonry skills are available through the verified native ${clients} plugin${agentPlugin.verifiedClients.length === 1 ? "" : "s"}.`,
|
|
38552
|
+
remediation: null,
|
|
38553
|
+
details: { delivery: "plugin", ...agentPlugin }
|
|
38554
|
+
};
|
|
38555
|
+
}
|
|
38429
38556
|
const home = process.env.HOME;
|
|
38430
38557
|
if (!home) {
|
|
38431
38558
|
return {
|
|
@@ -38446,7 +38573,8 @@ var skillsInstalledCheck = {
|
|
|
38446
38573
|
const details = {
|
|
38447
38574
|
checkedPath: skillsBase,
|
|
38448
38575
|
installed,
|
|
38449
|
-
missing
|
|
38576
|
+
missing,
|
|
38577
|
+
...agentPlugin ? { agentPlugin } : {}
|
|
38450
38578
|
};
|
|
38451
38579
|
if (missing.length === 0) {
|
|
38452
38580
|
return {
|
|
@@ -38479,9 +38607,51 @@ var skillsCurrentCheck = {
|
|
|
38479
38607
|
id: "agent.skills.current",
|
|
38480
38608
|
category: CheckCategories.agent,
|
|
38481
38609
|
scope: CheckScopes.global,
|
|
38482
|
-
title: "Agent skills up to date
|
|
38610
|
+
title: "Agent skills up to date",
|
|
38483
38611
|
run: (ctx) => {
|
|
38612
|
+
const agentPlugin = pluginStateFor(ctx);
|
|
38484
38613
|
const bundled = ctx.bundledSkills;
|
|
38614
|
+
const unverifiedClients = unverifiedPluginClients(agentPlugin);
|
|
38615
|
+
if (unverifiedClients.length > 0) {
|
|
38616
|
+
return {
|
|
38617
|
+
status: CheckStatuses.warn,
|
|
38618
|
+
code: "agent.skills.plugin-unverified",
|
|
38619
|
+
summary: `The Canonry plugin cache could not be verified for ${displayPluginClients(unverifiedClients)}; freshness cannot be assessed.`,
|
|
38620
|
+
remediation: "Reinstall `canonry@canonry` with the affected client plugin manager, or disable the stale plugin entry.",
|
|
38621
|
+
details: { delivery: "plugin", ...agentPlugin, unverifiedClients }
|
|
38622
|
+
};
|
|
38623
|
+
}
|
|
38624
|
+
if (agentPlugin && agentPlugin.configuredClients.length > 0) {
|
|
38625
|
+
const clients = displayPluginClients(agentPlugin.verifiedClients);
|
|
38626
|
+
if (!bundled || bundled.length === 0) {
|
|
38627
|
+
return {
|
|
38628
|
+
status: CheckStatuses.skipped,
|
|
38629
|
+
code: "agent.skills.bundle-unavailable",
|
|
38630
|
+
summary: `Canonry skills are supplied by the verified native ${clients} plugin${agentPlugin.verifiedClients.length === 1 ? "" : "s"}, but the running bundle version is unavailable for comparison.`,
|
|
38631
|
+
remediation: null,
|
|
38632
|
+
details: { delivery: "plugin", ...agentPlugin }
|
|
38633
|
+
};
|
|
38634
|
+
}
|
|
38635
|
+
const bundledVersion2 = bundled[0].version;
|
|
38636
|
+
const mismatchedClients = agentPlugin.verifiedClients.filter((client) => agentPlugin.verifiedClientVersions?.[client] !== bundledVersion2);
|
|
38637
|
+
if (mismatchedClients.length > 0) {
|
|
38638
|
+
const versions = mismatchedClients.map((client) => `${client === "claude-code" ? "Claude Code" : "Codex"} v${agentPlugin.verifiedClientVersions?.[client] ?? "unknown"}`).join(", ");
|
|
38639
|
+
return {
|
|
38640
|
+
status: CheckStatuses.warn,
|
|
38641
|
+
code: "agent.skills.plugin-version-mismatch",
|
|
38642
|
+
summary: `${versions} ${mismatchedClients.length === 1 ? "does" : "do"} not match the running Canonry v${bundledVersion2}; plugin skills may be stale or incompatible.`,
|
|
38643
|
+
remediation: "Update the Canonry runtime and `canonry@canonry` plugin to the same version with the affected client plugin manager.",
|
|
38644
|
+
details: { delivery: "plugin", bundledVersion: bundledVersion2, ...agentPlugin, mismatchedClients }
|
|
38645
|
+
};
|
|
38646
|
+
}
|
|
38647
|
+
return {
|
|
38648
|
+
status: CheckStatuses.ok,
|
|
38649
|
+
code: "agent.skills.plugin-current",
|
|
38650
|
+
summary: `Canonry skills are supplied by the verified native ${clients} plugin${agentPlugin.verifiedClients.length === 1 ? "" : "s"} at the running version (v${bundledVersion2}).`,
|
|
38651
|
+
remediation: null,
|
|
38652
|
+
details: { delivery: "plugin", bundledVersion: bundledVersion2, ...agentPlugin }
|
|
38653
|
+
};
|
|
38654
|
+
}
|
|
38485
38655
|
if (!bundled || bundled.length === 0) {
|
|
38486
38656
|
return {
|
|
38487
38657
|
status: CheckStatuses.skipped,
|
|
@@ -40485,7 +40655,8 @@ async function doctorRoutes(app, opts) {
|
|
|
40485
40655
|
getAgentProviderSummary: opts.getAgentProviderSummary,
|
|
40486
40656
|
trafficSourceValidators: opts.trafficSourceValidators,
|
|
40487
40657
|
runtimeStatePaths: opts.runtimeStatePaths,
|
|
40488
|
-
bundledSkills: opts.bundledSkills
|
|
40658
|
+
bundledSkills: opts.bundledSkills,
|
|
40659
|
+
getAgentPluginState: opts.getAgentPluginState
|
|
40489
40660
|
};
|
|
40490
40661
|
return runChecks(ctx, ALL_CHECKS, { checkIds });
|
|
40491
40662
|
});
|
|
@@ -40512,7 +40683,8 @@ async function doctorRoutes(app, opts) {
|
|
|
40512
40683
|
getAgentProviderSummary: opts.getAgentProviderSummary,
|
|
40513
40684
|
trafficSourceValidators: opts.trafficSourceValidators,
|
|
40514
40685
|
runtimeStatePaths: opts.runtimeStatePaths,
|
|
40515
|
-
bundledSkills: opts.bundledSkills
|
|
40686
|
+
bundledSkills: opts.bundledSkills,
|
|
40687
|
+
getAgentPluginState: opts.getAgentPluginState
|
|
40516
40688
|
};
|
|
40517
40689
|
return runChecks(ctx, ALL_CHECKS, { checkIds });
|
|
40518
40690
|
});
|
|
@@ -41554,7 +41726,8 @@ async function apiRoutes(app, opts) {
|
|
|
41554
41726
|
getAgentProviderSummary: opts.getAgentProviderSummary,
|
|
41555
41727
|
trafficSourceValidators: buildTrafficSourceValidators(opts),
|
|
41556
41728
|
runtimeStatePaths: opts.runtimeStatePaths,
|
|
41557
|
-
bundledSkills: opts.bundledSkills
|
|
41729
|
+
bundledSkills: opts.bundledSkills,
|
|
41730
|
+
getAgentPluginState: opts.getAgentPluginState
|
|
41558
41731
|
});
|
|
41559
41732
|
if (opts.registerAuthenticatedRoutes) {
|
|
41560
41733
|
await opts.registerAuthenticatedRoutes(api);
|
|
@@ -36,8 +36,9 @@ import {
|
|
|
36
36
|
trafficConnectCloudRunRequestSchema,
|
|
37
37
|
trafficConnectVercelRequestSchema,
|
|
38
38
|
trafficConnectWordpressRequestSchema,
|
|
39
|
-
trafficEventKindSchema
|
|
40
|
-
|
|
39
|
+
trafficEventKindSchema,
|
|
40
|
+
trafficSeriesGranularitySchema
|
|
41
|
+
} from "./chunk-K4FDDCYG.js";
|
|
41
42
|
|
|
42
43
|
// src/config.ts
|
|
43
44
|
import fs from "fs";
|
|
@@ -5335,7 +5336,8 @@ var ApiClient = class {
|
|
|
5335
5336
|
until: params?.until,
|
|
5336
5337
|
kind: params?.kind,
|
|
5337
5338
|
limit: params?.limit !== void 0 ? String(params.limit) : void 0,
|
|
5338
|
-
sourceId: params?.sourceId
|
|
5339
|
+
sourceId: params?.sourceId,
|
|
5340
|
+
granularity: params?.granularity
|
|
5339
5341
|
}
|
|
5340
5342
|
})
|
|
5341
5343
|
);
|
|
@@ -6190,9 +6192,10 @@ var trafficEventsInputSchema = z2.object({
|
|
|
6190
6192
|
project: projectNameSchema,
|
|
6191
6193
|
since: z2.string().optional().describe("ISO 8601 lower bound. Defaults to 24h ago when omitted."),
|
|
6192
6194
|
until: z2.string().optional().describe("ISO 8601 upper bound. Defaults to now when omitted."),
|
|
6193
|
-
kind: z2.union([trafficEventKindSchema, z2.literal("all")]).optional().describe('Filter to
|
|
6195
|
+
kind: z2.union([trafficEventKindSchema, z2.literal("all")]).optional().describe('Filter to one traffic kind; "all" (default) returns every kind.'),
|
|
6194
6196
|
sourceId: z2.string().min(1).optional().describe("Restrict to a single traffic source ID."),
|
|
6195
|
-
limit: z2.number().int().positive().max(5e3).optional().describe("Max combined rows. Defaults to 500, max 5000. Totals always reflect the full window.")
|
|
6197
|
+
limit: z2.number().int().positive().max(5e3).optional().describe("Max combined rows. Defaults to 500, max 5000. Totals always reflect the full window."),
|
|
6198
|
+
granularity: trafficSeriesGranularitySchema.optional().describe("Full-window chart series bucket size: hour (default) or day.")
|
|
6196
6199
|
});
|
|
6197
6200
|
var trafficSourceIdInputSchema = z2.object({
|
|
6198
6201
|
project: projectNameSchema,
|
|
@@ -7110,7 +7113,7 @@ var canonryMcpTools = [
|
|
|
7110
7113
|
defineTool({
|
|
7111
7114
|
name: "canonry_traffic_events",
|
|
7112
7115
|
title: "List traffic events",
|
|
7113
|
-
description:
|
|
7116
|
+
description: "Read crawler, AI user-fetch, and AI-referral rollups from server-side traffic sources. Returns complete full-window chart series and totals plus a capped discriminated detail list with explicit truncation metadata. Window defaults to last 24h.",
|
|
7114
7117
|
access: "read",
|
|
7115
7118
|
tier: "traffic",
|
|
7116
7119
|
inputSchema: trafficEventsInputSchema,
|
|
@@ -7123,6 +7126,7 @@ var canonryMcpTools = [
|
|
|
7123
7126
|
if (input.kind) params.kind = input.kind;
|
|
7124
7127
|
if (input.sourceId) params.sourceId = input.sourceId;
|
|
7125
7128
|
if (input.limit !== void 0) params.limit = input.limit;
|
|
7129
|
+
if (input.granularity) params.granularity = input.granularity;
|
|
7126
7130
|
return client2.trafficListEvents(input.project, params);
|
|
7127
7131
|
}
|
|
7128
7132
|
}),
|