@canonry/canonry 4.153.0 → 4.154.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 +2 -2
- package/assets/agent-workspace/skills/canonry/SKILL.md +4 -19
- package/assets/assets/{AuditHistoryPanel-CcoXjMxm.js → AuditHistoryPanel-WKf-vvmg.js} +1 -1
- package/assets/assets/BacklinksPage-By06DbHN.js +1 -0
- package/assets/assets/HistoryPage-C_PcPiyX.js +1 -0
- package/assets/assets/MeasurementPropertyPage-BHnNegEa.js +1 -0
- package/assets/assets/ProjectPage-VTbW21dz.js +12 -0
- package/assets/assets/{RunRow-xfuUNQ2O.js → RunRow-9qn5Eer_.js} +1 -1
- package/assets/assets/RunsPage-FxMTprK1.js +1 -0
- package/assets/assets/SettingsPage-Cr7_PrNW.js +1 -0
- package/assets/assets/TrafficPage-D0qk9uMN.js +1 -0
- package/assets/assets/TrafficSourceDetailPage-CXa_3_Gy.js +1 -0
- package/assets/assets/extract-error-message-RkTEH1Vb.js +1 -0
- package/assets/assets/{index-CaYn5phz.css → index-DyL54s8x.css} +1 -1
- package/assets/assets/index-nSWJ9yka.js +83 -0
- package/assets/assets/v2-overview-adapter-COMP5UGt.js +1 -0
- package/assets/assets/vendor-lucide-ByU7vBHt.js +1 -0
- package/assets/assets/vendor-yaml-GWJz5H2G.js +131 -0
- package/assets/index.html +4 -2
- package/dist/{chunk-LNJF7LL5.js → chunk-ANSQ6JNO.js} +1 -1
- package/dist/{chunk-YV4VKT4M.js → chunk-JOP2DGXL.js} +172 -77
- package/dist/{chunk-VTL2WOIO.js → chunk-KRMLGFY3.js} +130 -82
- package/dist/{chunk-SKTXCZZD.js → chunk-NNW7TJUZ.js} +6 -1
- package/dist/cli.js +27 -4
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-APPDGUH6.js → intelligence-service-ZY5KOSZV.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +9 -9
- package/assets/assets/BacklinksPage-Cij_A80K.js +0 -1
- package/assets/assets/HistoryPage-CdxhPEHF.js +0 -1
- package/assets/assets/MeasurementPropertyPage-CJaqCeMr.js +0 -1
- package/assets/assets/ProjectPage-BJPVmD_-.js +0 -12
- package/assets/assets/RunsPage-BirDqVe_.js +0 -1
- package/assets/assets/SettingsPage-BzMoD-42.js +0 -1
- package/assets/assets/TrafficPage-Du-7BL_j.js +0 -1
- package/assets/assets/TrafficSourceDetailPage-Dk6-TuNw.js +0 -1
- package/assets/assets/arrow-left-HyrLx9li.js +0 -1
- package/assets/assets/extract-error-message-Db0s9Qon.js +0 -1
- package/assets/assets/index-Bio0Z1kJ.js +0 -213
- package/assets/assets/refresh-cw-BFnkrZE9.js +0 -1
- package/assets/assets/trash-2-CQtsaJ-3.js +0 -1
- package/assets/assets/v2-overview-adapter-D81QVAhK.js +0 -1
|
@@ -521,7 +521,7 @@ import {
|
|
|
521
521
|
wordpressSchemaDeployResultDtoSchema,
|
|
522
522
|
wordpressSchemaStatusResultDtoSchema,
|
|
523
523
|
wordpressStatusDtoSchema
|
|
524
|
-
} from "./chunk-
|
|
524
|
+
} from "./chunk-NNW7TJUZ.js";
|
|
525
525
|
|
|
526
526
|
// src/intelligence-service.ts
|
|
527
527
|
import { eq as eq57, desc as desc26, asc as asc11, and as and45, ne as ne7, or as or11, inArray as inArray19, gte as gte13, lte as lte10 } from "drizzle-orm";
|
|
@@ -22384,15 +22384,19 @@ function loadQueryLookup(db, projectId) {
|
|
|
22384
22384
|
return { byId };
|
|
22385
22385
|
}
|
|
22386
22386
|
function buildGscSection(db, projectId, projectBrandNames, canonicalDomain, trackedQueries, windowDays2) {
|
|
22387
|
-
const
|
|
22388
|
-
const
|
|
22389
|
-
|
|
22390
|
-
for (const r of allRows) if (r.date > maxDate) maxDate = r.date;
|
|
22391
|
-
for (const r of allDailyTotals) if (r.date > maxDate) maxDate = r.date;
|
|
22387
|
+
const maxSearch = db.select({ m: sql9`MAX(${gscSearchData.date})` }).from(gscSearchData).where(eq28(gscSearchData.projectId, projectId)).get()?.m ?? "";
|
|
22388
|
+
const maxDaily = db.select({ m: sql9`MAX(${gscDailyTotals.date})` }).from(gscDailyTotals).where(eq28(gscDailyTotals.projectId, projectId)).get()?.m ?? "";
|
|
22389
|
+
const maxDate = maxSearch > maxDaily ? maxSearch : maxDaily;
|
|
22392
22390
|
if (!maxDate) return null;
|
|
22393
22391
|
const startDate = windowStartDate(maxDate, windowDays2);
|
|
22394
|
-
const rows =
|
|
22395
|
-
|
|
22392
|
+
const rows = db.select().from(gscSearchData).where(
|
|
22393
|
+
and22(
|
|
22394
|
+
eq28(gscSearchData.projectId, projectId),
|
|
22395
|
+
gte5(gscSearchData.date, startDate),
|
|
22396
|
+
lte3(gscSearchData.date, maxDate)
|
|
22397
|
+
)
|
|
22398
|
+
).all();
|
|
22399
|
+
const dailyTotals = readGscDailyTotals(db, projectId, startDate, maxDate);
|
|
22396
22400
|
if (rows.length === 0 && dailyTotals.length === 0) return null;
|
|
22397
22401
|
let dimensionedClicks = 0;
|
|
22398
22402
|
const queryDayAgg = /* @__PURE__ */ new Map();
|
|
@@ -22492,12 +22496,16 @@ function buildGaSection(db, projectId, windowDays2) {
|
|
|
22492
22496
|
)
|
|
22493
22497
|
).limit(1).get() : void 0;
|
|
22494
22498
|
const fallbackSummary = windowSummary ? null : db.select().from(gaTrafficSummaries).where(eq28(gaTrafficSummaries.projectId, projectId)).orderBy(desc12(gaTrafficSummaries.syncedAt)).limit(1).get();
|
|
22495
|
-
const
|
|
22496
|
-
if (!windowSummary && !fallbackSummary &&
|
|
22497
|
-
let snapshotMaxDate = "";
|
|
22498
|
-
for (const r of allSnapshotRows) if (r.date > snapshotMaxDate) snapshotMaxDate = r.date;
|
|
22499
|
+
const snapshotMaxDate = db.select({ m: sql9`MAX(${gaTrafficSnapshots.date})` }).from(gaTrafficSnapshots).where(eq28(gaTrafficSnapshots.projectId, projectId)).get()?.m ?? "";
|
|
22500
|
+
if (!windowSummary && !fallbackSummary && !snapshotMaxDate) return null;
|
|
22499
22501
|
const snapshotStartDate = snapshotMaxDate ? windowStartDate(snapshotMaxDate, windowDays2) : "";
|
|
22500
|
-
const snapshotRows = snapshotStartDate ?
|
|
22502
|
+
const snapshotRows = snapshotStartDate ? db.select().from(gaTrafficSnapshots).where(
|
|
22503
|
+
and22(
|
|
22504
|
+
eq28(gaTrafficSnapshots.projectId, projectId),
|
|
22505
|
+
gte5(gaTrafficSnapshots.date, snapshotStartDate),
|
|
22506
|
+
lte3(gaTrafficSnapshots.date, snapshotMaxDate)
|
|
22507
|
+
)
|
|
22508
|
+
).all() : db.select().from(gaTrafficSnapshots).where(eq28(gaTrafficSnapshots.projectId, projectId)).all();
|
|
22501
22509
|
const totalSessions = windowSummary?.totalSessions ?? fallbackSummary?.totalSessions ?? snapshotRows.reduce((s, r) => s + r.sessions, 0);
|
|
22502
22510
|
const totalUsers = windowSummary?.totalUsers ?? fallbackSummary?.totalUsers ?? snapshotRows.reduce((s, r) => s + r.users, 0);
|
|
22503
22511
|
const totalOrganicSessions = windowSummary?.totalOrganicSessions ?? fallbackSummary?.totalOrganicSessions ?? snapshotRows.reduce((s, r) => s + r.organicSessions, 0);
|
|
@@ -35501,8 +35509,9 @@ function isSitemapOwnedByProperty(sitemapUrl, propertyId, canonicalDomain) {
|
|
|
35501
35509
|
function signState(payload, secret) {
|
|
35502
35510
|
return crypto29.createHmac("sha256", secret).update(payload).digest("hex");
|
|
35503
35511
|
}
|
|
35512
|
+
var OAUTH_STATE_MAX_AGE_MS = 15 * 60 * 1e3;
|
|
35504
35513
|
function buildSignedState(data, secret) {
|
|
35505
|
-
const payload = JSON.stringify(data);
|
|
35514
|
+
const payload = JSON.stringify({ ...data, issuedAt: Date.now() });
|
|
35506
35515
|
const sig = signState(payload, secret);
|
|
35507
35516
|
return Buffer.from(JSON.stringify({ payload, sig })).toString("base64url");
|
|
35508
35517
|
}
|
|
@@ -35511,7 +35520,10 @@ function verifySignedState(encoded, secret) {
|
|
|
35511
35520
|
const { payload, sig } = JSON.parse(Buffer.from(encoded, "base64url").toString());
|
|
35512
35521
|
const expected = signState(payload, secret);
|
|
35513
35522
|
if (!crypto29.timingSafeEqual(Buffer.from(sig, "hex"), Buffer.from(expected, "hex"))) return null;
|
|
35514
|
-
|
|
35523
|
+
const parsed = JSON.parse(payload);
|
|
35524
|
+
const issuedAt = typeof parsed.issuedAt === "number" ? parsed.issuedAt : null;
|
|
35525
|
+
if (issuedAt === null || Date.now() - issuedAt > OAUTH_STATE_MAX_AGE_MS) return null;
|
|
35526
|
+
return parsed;
|
|
35515
35527
|
} catch {
|
|
35516
35528
|
return null;
|
|
35517
35529
|
}
|
|
@@ -41797,9 +41809,12 @@ async function adsRoutes(app, opts) {
|
|
|
41797
41809
|
}
|
|
41798
41810
|
|
|
41799
41811
|
// ../api-routes/src/bing.ts
|
|
41800
|
-
import
|
|
41812
|
+
import crypto34 from "crypto";
|
|
41801
41813
|
import { eq as eq42, and as and33, desc as desc19 } from "drizzle-orm";
|
|
41802
41814
|
|
|
41815
|
+
// ../integration-bing/src/bing-client.ts
|
|
41816
|
+
import crypto33 from "crypto";
|
|
41817
|
+
|
|
41803
41818
|
// ../integration-bing/src/constants.ts
|
|
41804
41819
|
var BING_WMT_API_BASE = "https://ssl.bing.com/webmaster/api.svc/json";
|
|
41805
41820
|
var BING_SUBMIT_URL_BATCH_LIMIT = 500;
|
|
@@ -41808,6 +41823,7 @@ var BING_REQUEST_TIMEOUT_MS = 3e4;
|
|
|
41808
41823
|
var BING_MAX_RETRIES = 4;
|
|
41809
41824
|
var BING_RETRY_BASE_DELAY_MS = 2e3;
|
|
41810
41825
|
var BING_RETRY_MAX_DELAY_MS = 3e4;
|
|
41826
|
+
var BING_THROTTLE_COOLDOWN_MS = 10 * 60 * 1e3;
|
|
41811
41827
|
|
|
41812
41828
|
// ../integration-bing/src/types.ts
|
|
41813
41829
|
var BING_THROTTLE_ERROR_CODES = /* @__PURE__ */ new Set([4, 5]);
|
|
@@ -41947,26 +41963,58 @@ async function bingFetchOnce(apiKey, endpoint, opts) {
|
|
|
41947
41963
|
throw new BingApiError("Bing API returned invalid JSON", 502);
|
|
41948
41964
|
}
|
|
41949
41965
|
}
|
|
41966
|
+
var throttleCooldownUntil = /* @__PURE__ */ new Map();
|
|
41967
|
+
var cooldownNow = () => Date.now();
|
|
41968
|
+
function cooldownKey(apiKey) {
|
|
41969
|
+
return crypto33.createHash("sha256").update(apiKey).digest("hex").slice(0, 12);
|
|
41970
|
+
}
|
|
41971
|
+
function throttleCooldownRemainingMs(apiKey) {
|
|
41972
|
+
const until = throttleCooldownUntil.get(cooldownKey(apiKey));
|
|
41973
|
+
if (until == null) return 0;
|
|
41974
|
+
const remaining = until - cooldownNow();
|
|
41975
|
+
if (remaining <= 0) {
|
|
41976
|
+
throttleCooldownUntil.delete(cooldownKey(apiKey));
|
|
41977
|
+
return 0;
|
|
41978
|
+
}
|
|
41979
|
+
return remaining;
|
|
41980
|
+
}
|
|
41981
|
+
function openThrottleCooldown(apiKey) {
|
|
41982
|
+
throttleCooldownUntil.set(cooldownKey(apiKey), cooldownNow() + BING_THROTTLE_COOLDOWN_MS);
|
|
41983
|
+
bingClientLog("error", "http.cooldown-open", { cooldownMs: BING_THROTTLE_COOLDOWN_MS });
|
|
41984
|
+
}
|
|
41950
41985
|
async function bingFetch(apiKey, endpoint, opts) {
|
|
41951
41986
|
const isIdempotent = (opts?.method ?? "GET") === "GET";
|
|
41952
|
-
|
|
41953
|
-
|
|
41954
|
-
|
|
41955
|
-
|
|
41956
|
-
|
|
41957
|
-
|
|
41958
|
-
|
|
41959
|
-
|
|
41960
|
-
|
|
41961
|
-
|
|
41962
|
-
|
|
41963
|
-
|
|
41964
|
-
|
|
41965
|
-
|
|
41966
|
-
|
|
41967
|
-
|
|
41968
|
-
|
|
41969
|
-
|
|
41987
|
+
const cooling = throttleCooldownRemainingMs(apiKey);
|
|
41988
|
+
if (cooling > 0) {
|
|
41989
|
+
bingClientLog("warn", "http.cooldown-skip", { endpoint, remainingMs: cooling });
|
|
41990
|
+
throw new BingApiError(
|
|
41991
|
+
`Bing API key is in a throttle cooldown for another ${Math.ceil(cooling / 1e3)}s; the account was still throttled after a full retry budget, so this call was not attempted.`,
|
|
41992
|
+
429
|
|
41993
|
+
);
|
|
41994
|
+
}
|
|
41995
|
+
try {
|
|
41996
|
+
return await withRetry(() => bingFetchOnce(apiKey, endpoint, opts), {
|
|
41997
|
+
maxRetries: BING_MAX_RETRIES,
|
|
41998
|
+
baseDelayMs: BING_RETRY_BASE_DELAY_MS,
|
|
41999
|
+
maxDelayMs: BING_RETRY_MAX_DELAY_MS,
|
|
42000
|
+
isRetryable: (err) => {
|
|
42001
|
+
if (err instanceof BingApiError && err.isThrottle) return true;
|
|
42002
|
+
return isIdempotent && isRetryableHttpError(err);
|
|
42003
|
+
},
|
|
42004
|
+
computeDelayMs: (_attempt, err, defaultMs) => retryAfterDelayMs(err) ?? defaultMs,
|
|
42005
|
+
onRetry: ({ attempt, err, delayMs }) => {
|
|
42006
|
+
bingClientLog("warn", "http.retry", {
|
|
42007
|
+
endpoint,
|
|
42008
|
+
attempt,
|
|
42009
|
+
delayMs: Math.round(delayMs),
|
|
42010
|
+
throttled: err instanceof BingApiError ? err.isThrottle : false
|
|
42011
|
+
});
|
|
42012
|
+
}
|
|
42013
|
+
});
|
|
42014
|
+
} catch (err) {
|
|
42015
|
+
if (err instanceof BingApiError && err.isThrottle) openThrottleCooldown(apiKey);
|
|
42016
|
+
throw err;
|
|
42017
|
+
}
|
|
41970
42018
|
}
|
|
41971
42019
|
async function getSites(apiKey) {
|
|
41972
42020
|
validateApiKey(apiKey);
|
|
@@ -42237,7 +42285,7 @@ async function bingRoutes(app, opts) {
|
|
|
42237
42285
|
const snapshotDate = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
42238
42286
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
42239
42287
|
app.db.insert(bingCoverageSnapshots).values({
|
|
42240
|
-
id:
|
|
42288
|
+
id: crypto34.randomUUID(),
|
|
42241
42289
|
projectId: project.id,
|
|
42242
42290
|
syncRunId: snapshotRunId,
|
|
42243
42291
|
date: snapshotDate,
|
|
@@ -42308,7 +42356,7 @@ async function bingRoutes(app, opts) {
|
|
|
42308
42356
|
throw validationError("url is required");
|
|
42309
42357
|
}
|
|
42310
42358
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
42311
|
-
const runId =
|
|
42359
|
+
const runId = crypto34.randomUUID();
|
|
42312
42360
|
app.db.insert(runs).values({
|
|
42313
42361
|
id: runId,
|
|
42314
42362
|
projectId: project.id,
|
|
@@ -42329,7 +42377,7 @@ async function bingRoutes(app, opts) {
|
|
|
42329
42377
|
discoveryDate: result.DiscoveryDate ?? null
|
|
42330
42378
|
});
|
|
42331
42379
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
42332
|
-
const id =
|
|
42380
|
+
const id = crypto34.randomUUID();
|
|
42333
42381
|
const httpCode = result.HttpStatus ?? result.HttpCode ?? null;
|
|
42334
42382
|
const lastCrawledDate = parseBingDate(result.LastCrawledDate);
|
|
42335
42383
|
const inIndexDate = parseBingDate(result.InIndexDate);
|
|
@@ -42399,7 +42447,7 @@ async function bingRoutes(app, opts) {
|
|
|
42399
42447
|
throw validationError('No Bing site configured. Run "canonry bing set-site <project> <url>" first.');
|
|
42400
42448
|
}
|
|
42401
42449
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
42402
|
-
const runId =
|
|
42450
|
+
const runId = crypto34.randomUUID();
|
|
42403
42451
|
app.db.insert(runs).values({
|
|
42404
42452
|
id: runId,
|
|
42405
42453
|
projectId: project.id,
|
|
@@ -42684,7 +42732,7 @@ async function cdpRoutes(app, opts) {
|
|
|
42684
42732
|
}
|
|
42685
42733
|
|
|
42686
42734
|
// ../api-routes/src/ga.ts
|
|
42687
|
-
import
|
|
42735
|
+
import crypto35 from "crypto";
|
|
42688
42736
|
import { eq as eq44, desc as desc20, and as and35, sql as sql16 } from "drizzle-orm";
|
|
42689
42737
|
|
|
42690
42738
|
// ../api-routes/src/ga-session-history.ts
|
|
@@ -42886,7 +42934,7 @@ function persistAcquisitionMeasurement(db, input) {
|
|
|
42886
42934
|
)).run();
|
|
42887
42935
|
for (const row of input.report.rows) {
|
|
42888
42936
|
tx.insert(gaAcquisitionDaily).values({
|
|
42889
|
-
id:
|
|
42937
|
+
id: crypto35.randomUUID(),
|
|
42890
42938
|
projectId: input.projectId,
|
|
42891
42939
|
date: row.date,
|
|
42892
42940
|
channelGroup: row.channelGroup,
|
|
@@ -42928,7 +42976,7 @@ function persistLeadMeasurement(db, input) {
|
|
|
42928
42976
|
)).run();
|
|
42929
42977
|
for (const row of input.report.rows) {
|
|
42930
42978
|
tx.insert(gaLeadEventsDaily).values({
|
|
42931
|
-
id:
|
|
42979
|
+
id: crypto35.randomUUID(),
|
|
42932
42980
|
projectId: input.projectId,
|
|
42933
42981
|
date: row.date,
|
|
42934
42982
|
eventName: row.eventName,
|
|
@@ -43208,7 +43256,7 @@ async function ga4Routes(app, opts) {
|
|
|
43208
43256
|
const leadDays = measurementState?.leadSyncedAt != null ? Math.min(Math.max(1, days), 90) : 90;
|
|
43209
43257
|
const leadEventNames = project.measurement.leadEventNames;
|
|
43210
43258
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
43211
|
-
const runId =
|
|
43259
|
+
const runId = crypto35.randomUUID();
|
|
43212
43260
|
app.db.insert(runs).values({
|
|
43213
43261
|
id: runId,
|
|
43214
43262
|
projectId: project.id,
|
|
@@ -43262,7 +43310,7 @@ async function ga4Routes(app, opts) {
|
|
|
43262
43310
|
).run();
|
|
43263
43311
|
for (const row of rows) {
|
|
43264
43312
|
tx.insert(gaTrafficSnapshots).values({
|
|
43265
|
-
id:
|
|
43313
|
+
id: crypto35.randomUUID(),
|
|
43266
43314
|
projectId: project.id,
|
|
43267
43315
|
date: row.date,
|
|
43268
43316
|
landingPage: row.landingPage,
|
|
@@ -43285,7 +43333,7 @@ async function ga4Routes(app, opts) {
|
|
|
43285
43333
|
).run();
|
|
43286
43334
|
for (const row of dailyTotals) {
|
|
43287
43335
|
tx.insert(gaDailyTotals).values({
|
|
43288
|
-
id:
|
|
43336
|
+
id: crypto35.randomUUID(),
|
|
43289
43337
|
projectId: project.id,
|
|
43290
43338
|
date: row.date,
|
|
43291
43339
|
sessions: row.sessions,
|
|
@@ -43311,7 +43359,7 @@ async function ga4Routes(app, opts) {
|
|
|
43311
43359
|
).run();
|
|
43312
43360
|
for (const row of aiReferrals) {
|
|
43313
43361
|
tx.insert(gaAiReferrals).values({
|
|
43314
|
-
id:
|
|
43362
|
+
id: crypto35.randomUUID(),
|
|
43315
43363
|
projectId: project.id,
|
|
43316
43364
|
date: row.date,
|
|
43317
43365
|
source: row.source,
|
|
@@ -43343,7 +43391,7 @@ async function ga4Routes(app, opts) {
|
|
|
43343
43391
|
).run();
|
|
43344
43392
|
for (const row of socialReferrals) {
|
|
43345
43393
|
tx.insert(gaSocialReferrals).values({
|
|
43346
|
-
id:
|
|
43394
|
+
id: crypto35.randomUUID(),
|
|
43347
43395
|
projectId: project.id,
|
|
43348
43396
|
date: row.date,
|
|
43349
43397
|
source: row.source,
|
|
@@ -43359,7 +43407,7 @@ async function ga4Routes(app, opts) {
|
|
|
43359
43407
|
if (syncSummary) {
|
|
43360
43408
|
tx.delete(gaTrafficSummaries).where(eq44(gaTrafficSummaries.projectId, project.id)).run();
|
|
43361
43409
|
tx.insert(gaTrafficSummaries).values({
|
|
43362
|
-
id:
|
|
43410
|
+
id: crypto35.randomUUID(),
|
|
43363
43411
|
projectId: project.id,
|
|
43364
43412
|
periodStart: summary.periodStart,
|
|
43365
43413
|
periodEnd: summary.periodEnd,
|
|
@@ -43372,7 +43420,7 @@ async function ga4Routes(app, opts) {
|
|
|
43372
43420
|
tx.delete(gaTrafficWindowSummaries).where(eq44(gaTrafficWindowSummaries.projectId, project.id)).run();
|
|
43373
43421
|
for (const ws of windowSummaries) {
|
|
43374
43422
|
tx.insert(gaTrafficWindowSummaries).values({
|
|
43375
|
-
id:
|
|
43423
|
+
id: crypto35.randomUUID(),
|
|
43376
43424
|
projectId: project.id,
|
|
43377
43425
|
windowKey: ws.windowKey,
|
|
43378
43426
|
periodStart: ws.periodStart,
|
|
@@ -44053,7 +44101,7 @@ function parseSchemaPageEntry(entry) {
|
|
|
44053
44101
|
}
|
|
44054
44102
|
|
|
44055
44103
|
// ../integration-wordpress/src/wordpress-client.ts
|
|
44056
|
-
import
|
|
44104
|
+
import crypto36 from "crypto";
|
|
44057
44105
|
function validateUsername(username) {
|
|
44058
44106
|
if (!username || typeof username !== "string" || username.trim().length === 0) {
|
|
44059
44107
|
throw new WordpressApiError("AUTH_INVALID", "Username is required and must be a non-empty string", 400);
|
|
@@ -44273,7 +44321,7 @@ function buildSnippet(content) {
|
|
|
44273
44321
|
return `${text2.slice(0, 157)}...`;
|
|
44274
44322
|
}
|
|
44275
44323
|
function contentHash(content) {
|
|
44276
|
-
return
|
|
44324
|
+
return crypto36.createHash("sha256").update(content).digest("hex");
|
|
44277
44325
|
}
|
|
44278
44326
|
function buildAmbiguousSlugMessage(slug, pages) {
|
|
44279
44327
|
const candidates = pages.map((page) => {
|
|
@@ -45573,7 +45621,7 @@ async function wordpressRoutes(app, opts) {
|
|
|
45573
45621
|
}
|
|
45574
45622
|
|
|
45575
45623
|
// ../api-routes/src/backlinks.ts
|
|
45576
|
-
import
|
|
45624
|
+
import crypto37 from "crypto";
|
|
45577
45625
|
import { and as and37, asc as asc9, desc as desc21, eq as eq45, sql as sql17 } from "drizzle-orm";
|
|
45578
45626
|
|
|
45579
45627
|
// ../integration-commoncrawl/src/constants.ts
|
|
@@ -46210,7 +46258,7 @@ async function backlinksRoutes(app, opts) {
|
|
|
46210
46258
|
const refreshed = app.db.select().from(ccReleaseSyncs).where(eq45(ccReleaseSyncs.id, existing.id)).get();
|
|
46211
46259
|
return reply.status(200).send(mapSyncRow(refreshed));
|
|
46212
46260
|
}
|
|
46213
|
-
const id =
|
|
46261
|
+
const id = crypto37.randomUUID();
|
|
46214
46262
|
app.db.insert(ccReleaseSyncs).values({
|
|
46215
46263
|
id,
|
|
46216
46264
|
release,
|
|
@@ -46267,7 +46315,7 @@ async function backlinksRoutes(app, opts) {
|
|
|
46267
46315
|
throw validationError("Invalid release id");
|
|
46268
46316
|
}
|
|
46269
46317
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
46270
|
-
const runId =
|
|
46318
|
+
const runId = crypto37.randomUUID();
|
|
46271
46319
|
app.db.insert(runs).values({
|
|
46272
46320
|
id: runId,
|
|
46273
46321
|
projectId: project.id,
|
|
@@ -46356,7 +46404,7 @@ async function backlinksRoutes(app, opts) {
|
|
|
46356
46404
|
}
|
|
46357
46405
|
|
|
46358
46406
|
// ../api-routes/src/traffic.ts
|
|
46359
|
-
import
|
|
46407
|
+
import crypto39 from "crypto";
|
|
46360
46408
|
import { Agent as UndiciAgent } from "undici";
|
|
46361
46409
|
import { and as and38, desc as desc22, eq as eq46, gte as gte10, lte as lte9, sql as sql18 } from "drizzle-orm";
|
|
46362
46410
|
|
|
@@ -46377,7 +46425,7 @@ function resolveVercelSyncDeadlineMs(env = process.env) {
|
|
|
46377
46425
|
}
|
|
46378
46426
|
|
|
46379
46427
|
// ../integration-cloud-run/src/auth.ts
|
|
46380
|
-
import
|
|
46428
|
+
import crypto38 from "crypto";
|
|
46381
46429
|
var GOOGLE_TOKEN_URL3 = "https://oauth2.googleapis.com/token";
|
|
46382
46430
|
var CLOUD_LOGGING_READ_SCOPE = "https://www.googleapis.com/auth/logging.read";
|
|
46383
46431
|
var TOKEN_REQUEST_TIMEOUT_MS = 3e4;
|
|
@@ -46408,7 +46456,7 @@ function createServiceAccountJwt2(clientEmail, privateKey, scope) {
|
|
|
46408
46456
|
const headerB64 = encode(header);
|
|
46409
46457
|
const payloadB64 = encode(payload);
|
|
46410
46458
|
const signingInput = `${headerB64}.${payloadB64}`;
|
|
46411
|
-
const sign =
|
|
46459
|
+
const sign = crypto38.createSign("RSA-SHA256");
|
|
46412
46460
|
sign.update(signingInput);
|
|
46413
46461
|
const signature = sign.sign(privateKey, "base64url");
|
|
46414
46462
|
return `${signingInput}.${signature}`;
|
|
@@ -50385,7 +50433,7 @@ async function runBackfillTask(options) {
|
|
|
50385
50433
|
}
|
|
50386
50434
|
})();
|
|
50387
50435
|
tx.insert(rawEventSamples).values({
|
|
50388
|
-
id:
|
|
50436
|
+
id: crypto39.randomUUID(),
|
|
50389
50437
|
projectId: project.id,
|
|
50390
50438
|
sourceId: sourceRow2.id,
|
|
50391
50439
|
ts: sample.observedAt,
|
|
@@ -50514,7 +50562,7 @@ async function trafficRoutes(app, opts) {
|
|
|
50514
50562
|
}).where(eq46(trafficSources.id, activeSource.id)).run();
|
|
50515
50563
|
sourceRow2 = app.db.select().from(trafficSources).where(eq46(trafficSources.id, activeSource.id)).get();
|
|
50516
50564
|
} else {
|
|
50517
|
-
const newId =
|
|
50565
|
+
const newId = crypto39.randomUUID();
|
|
50518
50566
|
app.db.insert(trafficSources).values({
|
|
50519
50567
|
id: newId,
|
|
50520
50568
|
projectId: project.id,
|
|
@@ -50595,7 +50643,7 @@ async function trafficRoutes(app, opts) {
|
|
|
50595
50643
|
}).where(eq46(trafficSources.id, activeSource.id)).run();
|
|
50596
50644
|
sourceRow2 = app.db.select().from(trafficSources).where(eq46(trafficSources.id, activeSource.id)).get();
|
|
50597
50645
|
} else {
|
|
50598
|
-
const newId =
|
|
50646
|
+
const newId = crypto39.randomUUID();
|
|
50599
50647
|
app.db.insert(trafficSources).values({
|
|
50600
50648
|
id: newId,
|
|
50601
50649
|
projectId: project.id,
|
|
@@ -50679,7 +50727,7 @@ async function trafficRoutes(app, opts) {
|
|
|
50679
50727
|
}).where(eq46(trafficSources.id, activeSource.id)).run();
|
|
50680
50728
|
row = tx.select().from(trafficSources).where(eq46(trafficSources.id, activeSource.id)).get();
|
|
50681
50729
|
} else {
|
|
50682
|
-
const newId =
|
|
50730
|
+
const newId = crypto39.randomUUID();
|
|
50683
50731
|
tx.insert(trafficSources).values({
|
|
50684
50732
|
id: newId,
|
|
50685
50733
|
projectId: project.id,
|
|
@@ -50713,7 +50761,7 @@ async function trafficRoutes(app, opts) {
|
|
|
50713
50761
|
let created = false;
|
|
50714
50762
|
if (!existingSchedule) {
|
|
50715
50763
|
tx.insert(schedules).values({
|
|
50716
|
-
id:
|
|
50764
|
+
id: crypto39.randomUUID(),
|
|
50717
50765
|
projectId: project.id,
|
|
50718
50766
|
kind: SchedulableRunKinds["traffic-sync"],
|
|
50719
50767
|
cronExpr: DEFAULT_TRAFFIC_SYNC_CRON,
|
|
@@ -50768,7 +50816,7 @@ async function trafficRoutes(app, opts) {
|
|
|
50768
50816
|
const windowEnd = /* @__PURE__ */ new Date();
|
|
50769
50817
|
const startedAt = windowEnd.toISOString();
|
|
50770
50818
|
const syncStartedAtMs = windowEnd.getTime();
|
|
50771
|
-
const runId =
|
|
50819
|
+
const runId = crypto39.randomUUID();
|
|
50772
50820
|
app.db.insert(runs).values({
|
|
50773
50821
|
id: runId,
|
|
50774
50822
|
projectId: project.id,
|
|
@@ -51161,7 +51209,7 @@ async function trafficRoutes(app, opts) {
|
|
|
51161
51209
|
}
|
|
51162
51210
|
})();
|
|
51163
51211
|
tx.insert(rawEventSamples).values({
|
|
51164
|
-
id:
|
|
51212
|
+
id: crypto39.randomUUID(),
|
|
51165
51213
|
projectId: project.id,
|
|
51166
51214
|
sourceId: sourceRow2.id,
|
|
51167
51215
|
ts: sample.observedAt,
|
|
@@ -51412,7 +51460,7 @@ async function trafficRoutes(app, opts) {
|
|
|
51412
51460
|
};
|
|
51413
51461
|
}
|
|
51414
51462
|
const startedAt = windowEnd.toISOString();
|
|
51415
|
-
const runId =
|
|
51463
|
+
const runId = crypto39.randomUUID();
|
|
51416
51464
|
app.db.insert(runs).values({
|
|
51417
51465
|
id: runId,
|
|
51418
51466
|
projectId: project.id,
|
|
@@ -51782,7 +51830,7 @@ async function trafficRoutes(app, opts) {
|
|
|
51782
51830
|
}
|
|
51783
51831
|
|
|
51784
51832
|
// ../api-routes/src/doctor/checks/agent.ts
|
|
51785
|
-
import
|
|
51833
|
+
import crypto40 from "crypto";
|
|
51786
51834
|
import fs6 from "fs";
|
|
51787
51835
|
import path7 from "path";
|
|
51788
51836
|
var REQUIRED_SKILLS = ["canonry", "aero"];
|
|
@@ -52013,7 +52061,7 @@ function isInstalled(dir) {
|
|
|
52013
52061
|
}
|
|
52014
52062
|
function hashInstalledFile(filePath) {
|
|
52015
52063
|
try {
|
|
52016
|
-
return
|
|
52064
|
+
return crypto40.createHash("sha256").update(fs6.readFileSync(filePath)).digest("hex");
|
|
52017
52065
|
} catch {
|
|
52018
52066
|
return void 0;
|
|
52019
52067
|
}
|
|
@@ -54086,7 +54134,7 @@ async function doctorRoutes(app, opts) {
|
|
|
54086
54134
|
}
|
|
54087
54135
|
|
|
54088
54136
|
// ../api-routes/src/discovery/routes.ts
|
|
54089
|
-
import
|
|
54137
|
+
import crypto41 from "crypto";
|
|
54090
54138
|
import { and as and42, desc as desc23, eq as eq53, gte as gte12, inArray as inArray17, isNull as isNull4, or as or10 } from "drizzle-orm";
|
|
54091
54139
|
var MAX_INFLIGHT_DISCOVERY_AGE_MS = 2 * 60 * 60 * 1e3;
|
|
54092
54140
|
async function discoveryRoutes(app, opts) {
|
|
@@ -54152,8 +54200,8 @@ async function discoveryRoutes(app, opts) {
|
|
|
54152
54200
|
if (existing && existing.runId) {
|
|
54153
54201
|
return { reused: true, sessionId: existing.id, runId: existing.runId };
|
|
54154
54202
|
}
|
|
54155
|
-
const sessionId =
|
|
54156
|
-
const runId =
|
|
54203
|
+
const sessionId = crypto41.randomUUID();
|
|
54204
|
+
const runId = crypto41.randomUUID();
|
|
54157
54205
|
tx.insert(discoverySessions).values({
|
|
54158
54206
|
id: sessionId,
|
|
54159
54207
|
projectId: project.id,
|
|
@@ -54407,7 +54455,7 @@ async function discoveryRoutes(app, opts) {
|
|
|
54407
54455
|
app.db.transaction((tx) => {
|
|
54408
54456
|
for (const query of promotedQueries) {
|
|
54409
54457
|
tx.insert(queries).values({
|
|
54410
|
-
id:
|
|
54458
|
+
id: crypto41.randomUUID(),
|
|
54411
54459
|
projectId: project.id,
|
|
54412
54460
|
query,
|
|
54413
54461
|
provenance,
|
|
@@ -54416,7 +54464,7 @@ async function discoveryRoutes(app, opts) {
|
|
|
54416
54464
|
}
|
|
54417
54465
|
for (const domain of promotedCompetitors) {
|
|
54418
54466
|
tx.insert(competitors).values({
|
|
54419
|
-
id:
|
|
54467
|
+
id: crypto41.randomUUID(),
|
|
54420
54468
|
projectId: project.id,
|
|
54421
54469
|
domain,
|
|
54422
54470
|
provenance,
|
|
@@ -54506,7 +54554,7 @@ function selectEligibleCompetitors(competitorMap, competitorTypes) {
|
|
|
54506
54554
|
}
|
|
54507
54555
|
|
|
54508
54556
|
// ../api-routes/src/discovery/orchestrate.ts
|
|
54509
|
-
import
|
|
54557
|
+
import crypto42 from "crypto";
|
|
54510
54558
|
import { eq as eq54 } from "drizzle-orm";
|
|
54511
54559
|
var DEFAULT_MAX_PROBES = 100;
|
|
54512
54560
|
var ABSOLUTE_MAX_PROBES = 500;
|
|
@@ -54674,7 +54722,7 @@ async function executeDiscovery(opts) {
|
|
|
54674
54722
|
probeRows.push({ citedDomains: probe.citedDomains, bucket });
|
|
54675
54723
|
buckets[bucket]++;
|
|
54676
54724
|
return {
|
|
54677
|
-
id:
|
|
54725
|
+
id: crypto42.randomUUID(),
|
|
54678
54726
|
sessionId: opts.sessionId,
|
|
54679
54727
|
projectId: opts.project.id,
|
|
54680
54728
|
query: probedCanonicals[index2],
|
|
@@ -54726,7 +54774,7 @@ function upsertDomainClassifications(db, projectId, sessionId, competitorMap) {
|
|
|
54726
54774
|
const domain = hostOf(entry.domain) ?? "";
|
|
54727
54775
|
if (!domain) continue;
|
|
54728
54776
|
db.insert(domainClassifications).values({
|
|
54729
|
-
id:
|
|
54777
|
+
id: crypto42.randomUUID(),
|
|
54730
54778
|
projectId,
|
|
54731
54779
|
domain,
|
|
54732
54780
|
competitorType: entry.competitorType,
|
|
@@ -54766,7 +54814,7 @@ function dedupeStrings(input) {
|
|
|
54766
54814
|
}
|
|
54767
54815
|
|
|
54768
54816
|
// ../api-routes/src/technical-aeo.ts
|
|
54769
|
-
import
|
|
54817
|
+
import crypto43 from "crypto";
|
|
54770
54818
|
import { and as and43, asc as asc10, count, desc as desc24, eq as eq55, inArray as inArray18, lt as lt7 } from "drizzle-orm";
|
|
54771
54819
|
var SURFACEABLE_STATUSES = [RunStatuses.completed, RunStatuses.partial];
|
|
54772
54820
|
function emptyScore(projectName) {
|
|
@@ -54902,7 +54950,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
54902
54950
|
return { runId: existing.id, status: existing.status };
|
|
54903
54951
|
}
|
|
54904
54952
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
54905
|
-
const runId =
|
|
54953
|
+
const runId = crypto43.randomUUID();
|
|
54906
54954
|
app.db.insert(runs).values({
|
|
54907
54955
|
id: runId,
|
|
54908
54956
|
projectId: project.id,
|
|
@@ -54920,7 +54968,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
54920
54968
|
}
|
|
54921
54969
|
|
|
54922
54970
|
// ../api-routes/src/research.ts
|
|
54923
|
-
import
|
|
54971
|
+
import crypto44 from "crypto";
|
|
54924
54972
|
import { and as and44, desc as desc25, eq as eq56 } from "drizzle-orm";
|
|
54925
54973
|
var sameLocation = (a, b) => a.label === b.label && a.city === b.city && a.region === b.region && a.country === b.country && a.timezone === b.timezone;
|
|
54926
54974
|
async function researchRoutes(app, opts) {
|
|
@@ -54947,7 +54995,7 @@ async function researchRoutes(app, opts) {
|
|
|
54947
54995
|
if (!adapter.modelValidationPattern.test(resolvedModel)) throw validationError(`Invalid resolved model "${resolvedModel}" for provider "${providerName}".`, { provider: providerName, model: resolvedModel, hint: adapter.modelValidationHint });
|
|
54948
54996
|
if (new Set(input.queries.map((query) => query.toLocaleLowerCase())).size !== input.queries.length) throw validationError("Research queries must be unique within a batch.");
|
|
54949
54997
|
const normalized = { queries: input.queries, provider: providerName, model: requestedModel, location: location ?? null };
|
|
54950
|
-
const requestHash2 =
|
|
54998
|
+
const requestHash2 = crypto44.createHash("sha256").update(JSON.stringify(normalized)).digest("hex");
|
|
54951
54999
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
54952
55000
|
const decision = app.db.transaction((tx) => {
|
|
54953
55001
|
if (input.idempotencyKey) {
|
|
@@ -54957,9 +55005,9 @@ async function researchRoutes(app, opts) {
|
|
|
54957
55005
|
return { reused: true, id: existing.id, shouldDispatch: existing.status === ResearchRunStatuses.queued };
|
|
54958
55006
|
}
|
|
54959
55007
|
}
|
|
54960
|
-
const id =
|
|
55008
|
+
const id = crypto44.randomUUID();
|
|
54961
55009
|
tx.insert(researchRuns).values({ id, projectId: project.id, status: ResearchRunStatuses.queued, provider: providerName, requestedModel, resolvedModel, location: location ?? null, totalQueries: input.queries.length, idempotencyKey: input.idempotencyKey ?? null, requestHash: input.idempotencyKey ? requestHash2 : null, createdAt: now }).run();
|
|
54962
|
-
for (const [position, query] of input.queries.entries()) tx.insert(researchRunQueries).values({ id:
|
|
55010
|
+
for (const [position, query] of input.queries.entries()) tx.insert(researchRunQueries).values({ id: crypto44.randomUUID(), researchRunId: id, position, queryText: query, status: ResearchQueryStatuses.queued, requestedModel, resolvedModel, groundingSources: [], citedDomains: [], searchQueries: [], createdAt: now }).run();
|
|
54963
55011
|
writeAuditLog(tx, { projectId: project.id, actor: "api", action: "research.created", entityType: "research_run", entityId: id });
|
|
54964
55012
|
return { reused: false, id, shouldDispatch: true };
|
|
54965
55013
|
});
|
|
@@ -55376,7 +55424,7 @@ function buildTrafficSourceValidators(opts) {
|
|
|
55376
55424
|
}
|
|
55377
55425
|
|
|
55378
55426
|
// src/intelligence-service.ts
|
|
55379
|
-
import
|
|
55427
|
+
import crypto45 from "crypto";
|
|
55380
55428
|
|
|
55381
55429
|
// src/logger.ts
|
|
55382
55430
|
var IS_TTY = process.stdout.isTTY === true;
|
|
@@ -56017,7 +56065,7 @@ var IntelligenceService = class {
|
|
|
56017
56065
|
}).run();
|
|
56018
56066
|
}
|
|
56019
56067
|
tx.insert(healthSnapshots).values({
|
|
56020
|
-
id:
|
|
56068
|
+
id: crypto45.randomUUID(),
|
|
56021
56069
|
projectId,
|
|
56022
56070
|
runId,
|
|
56023
56071
|
overallCitedRate: String(result.health.overallCitedRate),
|
|
@@ -4084,7 +4084,12 @@ var measurementOverviewResponseSchema = z5.object({
|
|
|
4084
4084
|
)
|
|
4085
4085
|
}).strict(),
|
|
4086
4086
|
properties: measurementCursorPageSchema(measurementPropertyRowSchema),
|
|
4087
|
-
/**
|
|
4087
|
+
/**
|
|
4088
|
+
* Outcome split over the whole RESULT SET, not the page — so paging through
|
|
4089
|
+
* does not move it. It narrows with `search` exactly as `properties.totalEstimate`
|
|
4090
|
+
* does, because both are computed from the same filtered rows; with no search
|
|
4091
|
+
* that result set is the entire scope.
|
|
4092
|
+
*/
|
|
4088
4093
|
outcomes: measurementOutcomeCountsSchema,
|
|
4089
4094
|
flags: z5.object({ total: z5.number().int().nonnegative() }).strict(),
|
|
4090
4095
|
namedShareOfVoice: measurementNamedShareOfVoiceSchema.optional()
|
package/dist/cli.js
CHANGED
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
showFirstRunNotice,
|
|
31
31
|
trackCliCommandFinished,
|
|
32
32
|
trackEvent
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-JOP2DGXL.js";
|
|
34
34
|
import {
|
|
35
35
|
CliError,
|
|
36
36
|
EXIT_SYSTEM_ERROR,
|
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
saveConfigPatch,
|
|
51
51
|
systemError,
|
|
52
52
|
usageError
|
|
53
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-ANSQ6JNO.js";
|
|
54
54
|
import {
|
|
55
55
|
apiKeys,
|
|
56
56
|
createClient,
|
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
projects,
|
|
59
59
|
queries,
|
|
60
60
|
renderReportHtml
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-KRMLGFY3.js";
|
|
62
62
|
import {
|
|
63
63
|
AdsDeliverySnapshotStatuses,
|
|
64
64
|
AdsHistoricalCampaignRollupStatuses,
|
|
@@ -122,7 +122,7 @@ import {
|
|
|
122
122
|
providerQuotaPolicySchema,
|
|
123
123
|
resolveProviderInput,
|
|
124
124
|
winnabilityClassSchema
|
|
125
|
-
} from "./chunk-
|
|
125
|
+
} from "./chunk-NNW7TJUZ.js";
|
|
126
126
|
|
|
127
127
|
// src/cli.ts
|
|
128
128
|
import { pathToFileURL } from "url";
|
|
@@ -13163,6 +13163,8 @@ import fs14 from "fs";
|
|
|
13163
13163
|
import path11 from "path";
|
|
13164
13164
|
var CANONRY_PLUGIN_ID = "canonry@canonry";
|
|
13165
13165
|
var REQUIRED_SKILLS = ["canonry", "aero"];
|
|
13166
|
+
var AGENT_PLUGINS_SCHEMA = "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json";
|
|
13167
|
+
var AGENT_PLUGINS_MCP_SCHEMA = "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json";
|
|
13166
13168
|
function parseSemver(version) {
|
|
13167
13169
|
const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9a-z.-]+))?(?:\+[0-9a-z.-]+)?$/i.exec(version);
|
|
13168
13170
|
if (!match) return null;
|
|
@@ -13254,6 +13256,27 @@ function readCodexPluginConfigured(filePath) {
|
|
|
13254
13256
|
}
|
|
13255
13257
|
}
|
|
13256
13258
|
function verifiedPluginVersion(root, client) {
|
|
13259
|
+
if (client === "codex" && fs14.existsSync(path11.join(root, "plugin.json"))) {
|
|
13260
|
+
const manifest2 = readJson(path11.join(root, "plugin.json"));
|
|
13261
|
+
if (manifest2 && typeof manifest2 === "object") {
|
|
13262
|
+
const plugin2 = manifest2;
|
|
13263
|
+
if (plugin2.$schema === AGENT_PLUGINS_SCHEMA) {
|
|
13264
|
+
if (plugin2.name !== "canonry" || typeof plugin2.version !== "string" || !parseSemver(plugin2.version)) {
|
|
13265
|
+
return null;
|
|
13266
|
+
}
|
|
13267
|
+
const mcp2 = readJson(path11.join(root, "mcp.json"));
|
|
13268
|
+
if (!mcp2 || typeof mcp2 !== "object") return null;
|
|
13269
|
+
const portableMcp = mcp2;
|
|
13270
|
+
if (portableMcp.$schema !== AGENT_PLUGINS_MCP_SCHEMA || portableMcp.mcpServers?.canonry?.type !== "stdio" || portableMcp.mcpServers.canonry.command !== "canonry-mcp") {
|
|
13271
|
+
return null;
|
|
13272
|
+
}
|
|
13273
|
+
return REQUIRED_SKILLS.every((name) => fs14.existsSync(path11.join(root, "skills", name, "SKILL.md"))) ? plugin2.version : null;
|
|
13274
|
+
}
|
|
13275
|
+
if (typeof plugin2.$schema === "string" && plugin2.$schema.startsWith("https://agent-plugins.org/schemas/")) {
|
|
13276
|
+
return null;
|
|
13277
|
+
}
|
|
13278
|
+
}
|
|
13279
|
+
}
|
|
13257
13280
|
const manifestDir = client === "claude-code" ? ".claude-plugin" : ".codex-plugin";
|
|
13258
13281
|
const manifest = readJson(path11.join(root, manifestDir, "plugin.json"));
|
|
13259
13282
|
if (!manifest || typeof manifest !== "object") return null;
|