@ainyc/canonry 4.96.0 → 4.97.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +1 -0
- package/assets/assets/{BacklinksPage-BiuaXwM3.js → BacklinksPage-BI9BtHjp.js} +1 -1
- package/assets/assets/{ChartPrimitives-C7jCdApm.js → ChartPrimitives-BcjGunGr.js} +1 -1
- package/assets/assets/ProjectPage-BdoberYt.js +6 -0
- package/assets/assets/{RunRow-DLn-qaBh.js → RunRow-BT2kpdQR.js} +1 -1
- package/assets/assets/{RunsPage-BArLwd1T.js → RunsPage-BAgZuX7j.js} +1 -1
- package/assets/assets/{SettingsPage-BJmzcMsh.js → SettingsPage-BvKcpivM.js} +1 -1
- package/assets/assets/{TrafficPage-DqG9hcNu.js → TrafficPage-BdGOZv1e.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-yW5pdgrM.js → TrafficSourceDetailPage-C_N2D9xy.js} +1 -1
- package/assets/assets/{arrow-left-BUhA2bZu.js → arrow-left-C8Fbup8X.js} +1 -1
- package/assets/assets/{extract-error-message-D2vzFSUQ.js → extract-error-message-C29K35Gm.js} +1 -1
- package/assets/assets/index-BGfyt3LX.js +210 -0
- package/assets/assets/{index-DiykVUPr.css → index-BsZNCwg8.css} +1 -1
- package/assets/assets/{trash-2-C94CCTsF.js → trash-2-DWLIELE_.js} +1 -1
- package/assets/assets/{vendor-markdown-DK7fbRNb.js → vendor-markdown-6dwjPOKK.js} +1 -1
- package/assets/assets/{vendor-radix-B57xfQbP.js → vendor-radix-CQ77EO2y.js} +1 -1
- package/assets/assets/{vendor-recharts-ClRVR6aX.js → vendor-recharts-C9EZkgbP.js} +1 -1
- package/assets/assets/vendor-tanstack-Be8JdV5M.js +1 -0
- package/assets/index.html +6 -6
- package/dist/{chunk-CEYDMSQO.js → chunk-E2FDXNMW.js} +53 -7
- package/dist/{chunk-ROLTZPV7.js → chunk-NUGGUQH3.js} +13 -7
- package/dist/{chunk-IFB43PRW.js → chunk-SRJ5IGNK.js} +14 -6
- package/dist/{chunk-CNTBEUVE.js → chunk-TXNKKTFD.js} +90 -60
- package/dist/cli.js +19 -6
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-SJKUVFZ6.js → intelligence-service-DC2TD7RR.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +8 -8
- package/assets/assets/ProjectPage-BHo6vIlj.js +0 -6
- package/assets/assets/index-afT0D_K8.js +0 -210
- package/assets/assets/vendor-tanstack-Dq7p98wZ.js +0 -1
|
@@ -180,6 +180,7 @@ import {
|
|
|
180
180
|
notImplemented,
|
|
181
181
|
notificationDtoSchema,
|
|
182
182
|
parseInclusiveEndMs,
|
|
183
|
+
parseReportPeriodDays,
|
|
183
184
|
parseRunError,
|
|
184
185
|
parseWindow,
|
|
185
186
|
pickClusterRepresentative,
|
|
@@ -198,6 +199,7 @@ import {
|
|
|
198
199
|
registrableDomain,
|
|
199
200
|
reportActionCategoryLabel,
|
|
200
201
|
reportActionTone,
|
|
202
|
+
reportComparisonWindowDays,
|
|
201
203
|
reportConfidenceLabel,
|
|
202
204
|
reportHorizonLabel,
|
|
203
205
|
reportSeverityLabel,
|
|
@@ -261,7 +263,7 @@ import {
|
|
|
261
263
|
wordpressSchemaDeployResultDtoSchema,
|
|
262
264
|
wordpressSchemaStatusResultDtoSchema,
|
|
263
265
|
wordpressStatusDtoSchema
|
|
264
|
-
} from "./chunk-
|
|
266
|
+
} from "./chunk-E2FDXNMW.js";
|
|
265
267
|
|
|
266
268
|
// src/intelligence-service.ts
|
|
267
269
|
import { eq as eq37, desc as desc18, asc as asc5, and as and27, ne as ne5, or as or5, inArray as inArray14, gte as gte7, lte as lte4 } from "drizzle-orm";
|
|
@@ -1301,6 +1303,7 @@ var adsConnections = sqliteTable("ads_connections", {
|
|
|
1301
1303
|
timezone: text("timezone"),
|
|
1302
1304
|
status: text("status"),
|
|
1303
1305
|
lastSyncedAt: text("last_synced_at"),
|
|
1306
|
+
conversionTrackingConfigured: integer("conversion_tracking_configured", { mode: "boolean" }).notNull().default(false),
|
|
1304
1307
|
createdAt: text("created_at").notNull(),
|
|
1305
1308
|
updatedAt: text("updated_at").notNull()
|
|
1306
1309
|
}, (table) => [
|
|
@@ -1364,6 +1367,7 @@ var adsInsightsDaily = sqliteTable("ads_insights_daily", {
|
|
|
1364
1367
|
impressions: integer("impressions").notNull().default(0),
|
|
1365
1368
|
clicks: integer("clicks").notNull().default(0),
|
|
1366
1369
|
spendMicros: integer("spend_micros").notNull().default(0),
|
|
1370
|
+
conversions: integer("conversions").notNull().default(0),
|
|
1367
1371
|
syncRunId: text("sync_run_id").references(() => runs.id, { onDelete: "set null" })
|
|
1368
1372
|
}, (table) => [
|
|
1369
1373
|
uniqueIndex("uniq_ads_insights_daily").on(table.projectId, table.level, table.entityId, table.date),
|
|
@@ -3199,6 +3203,14 @@ var MIGRATION_VERSIONS = [
|
|
|
3199
3203
|
)`,
|
|
3200
3204
|
`CREATE INDEX IF NOT EXISTS idx_gbp_attributes_loc ON gbp_attributes_snapshots(project_id, location_name, synced_at)`
|
|
3201
3205
|
]
|
|
3206
|
+
},
|
|
3207
|
+
{
|
|
3208
|
+
version: 83,
|
|
3209
|
+
name: "ads-insights-conversions",
|
|
3210
|
+
statements: [
|
|
3211
|
+
`ALTER TABLE ads_insights_daily ADD COLUMN conversions INTEGER NOT NULL DEFAULT 0`,
|
|
3212
|
+
`ALTER TABLE ads_connections ADD COLUMN conversion_tracking_configured INTEGER NOT NULL DEFAULT 0`
|
|
3213
|
+
]
|
|
3202
3214
|
}
|
|
3203
3215
|
];
|
|
3204
3216
|
function rebuildBacklinkTableWithSource(tx, table) {
|
|
@@ -10135,18 +10147,17 @@ function renderRateDeltaTile(label, delta, unit) {
|
|
|
10135
10147
|
<div class="delta">${deltaText}</div>
|
|
10136
10148
|
</div>`;
|
|
10137
10149
|
}
|
|
10138
|
-
function renderTrafficDeltaTile(label, delta, countLabel) {
|
|
10150
|
+
function renderTrafficDeltaTile(label, delta, countLabel, comparisonWindowDays) {
|
|
10139
10151
|
if (!delta) {
|
|
10140
10152
|
return `<div class="metric"><div class="label">${escapeHtml(label)}</div><div class="value">\u2014</div><div class="delta">Not enough trend data</div></div>`;
|
|
10141
10153
|
}
|
|
10142
|
-
const deltaText = formatWindowCountDelta(delta, countLabel, `vs prior ${
|
|
10154
|
+
const deltaText = formatWindowCountDelta(delta, countLabel, `vs prior ${comparisonWindowDays} days`);
|
|
10143
10155
|
return `<div class="metric">
|
|
10144
10156
|
<div class="label">${escapeHtml(label)}</div>
|
|
10145
10157
|
<div class="value ${deltaToneClass(delta.direction)}">${formatNumber(delta.current)} <span style="font-size:14px;font-weight:500;">${deltaArrow(delta.direction)}</span></div>
|
|
10146
10158
|
<div class="delta">${deltaText}</div>
|
|
10147
10159
|
</div>`;
|
|
10148
10160
|
}
|
|
10149
|
-
var WHATS_CHANGED_PERIOD_DAYS = 14;
|
|
10150
10161
|
function renderProviderMovements(movements, audience) {
|
|
10151
10162
|
const meaningful = movements.filter((m) => m.direction !== "flat");
|
|
10152
10163
|
if (meaningful.length === 0) return "";
|
|
@@ -10213,8 +10224,8 @@ function renderWhatsChanged(report, audience) {
|
|
|
10213
10224
|
${renderRateDeltaTile(isClient ? "AI links to your website" : "Citation rate", w.citationRate, "%")}
|
|
10214
10225
|
${renderRateDeltaTile(isClient ? "AI mentions your name" : "Mention rate", w.mentionRate, "%")}
|
|
10215
10226
|
${renderRateDeltaTile(isClient ? "Questions AI answered with you" : "Cited queries", w.citedQueryCount, "count")}
|
|
10216
|
-
${renderTrafficDeltaTile(isClient ? "Visitors from Google" : "GSC clicks", w.gscClicksDelta, isClient ? "visits" : "clicks")}
|
|
10217
|
-
${renderTrafficDeltaTile(isClient ? "Visitors from AI tools" : "AI referral sessions", w.aiReferralsDelta, isClient ? "visits" : "sessions")}
|
|
10227
|
+
${renderTrafficDeltaTile(isClient ? "Visitors from Google" : "GSC clicks", w.gscClicksDelta, isClient ? "visits" : "clicks", w.comparisonWindowDays)}
|
|
10228
|
+
${renderTrafficDeltaTile(isClient ? "Visitors from AI tools" : "AI referral sessions", w.aiReferralsDelta, isClient ? "visits" : "sessions", w.comparisonWindowDays)}
|
|
10218
10229
|
</div>`;
|
|
10219
10230
|
const movements = renderProviderMovements(w.providerMovements, audience);
|
|
10220
10231
|
const winsHeading = isClient ? "What got better" : "Wins";
|
|
@@ -10679,33 +10690,36 @@ function renderAiReferrals(report) {
|
|
|
10679
10690
|
</div>`
|
|
10680
10691
|
);
|
|
10681
10692
|
}
|
|
10682
|
-
function serverActivityHeading(audience, hasData) {
|
|
10693
|
+
function serverActivityHeading(audience, hasData, windowDays) {
|
|
10683
10694
|
const isClient = audience === "client";
|
|
10684
10695
|
return {
|
|
10685
10696
|
id: "server-activity",
|
|
10686
10697
|
eyebrow: isClient ? "AI engine attention" : "Section 10",
|
|
10687
10698
|
title: "AI Visibility \u2014 Server-Side",
|
|
10688
|
-
intro: isClient ? hasData ?
|
|
10699
|
+
intro: isClient ? hasData ? `What AI engines actually do in your server logs over the last ${windowDays} days \u2014 the other half of citations.` : "Live telemetry from your server logs." : "What AI engines actually do in your server logs \u2014 direct evidence, complementary to citations (which measure what they say)."
|
|
10689
10700
|
};
|
|
10690
10701
|
}
|
|
10691
10702
|
function renderServerActivity(report, audience) {
|
|
10692
10703
|
const sa = report.serverActivity;
|
|
10693
10704
|
const isClient = audience === "client";
|
|
10705
|
+
const windowDays = report.meta.periodDays;
|
|
10706
|
+
const windowLabel = `${windowDays}d`;
|
|
10707
|
+
const priorWindowLabel = `vs prior ${windowDays} days`;
|
|
10694
10708
|
if (!sa) {
|
|
10695
10709
|
if (isClient) return "";
|
|
10696
10710
|
return section(
|
|
10697
|
-
serverActivityHeading("agency", false),
|
|
10711
|
+
serverActivityHeading("agency", false, windowDays),
|
|
10698
10712
|
renderEmpty("Connect a server-side traffic source to surface what AI engines do directly in your server logs \u2014 distinct from GA4 click-throughs.")
|
|
10699
10713
|
);
|
|
10700
10714
|
}
|
|
10701
10715
|
if (!sa.hasData) {
|
|
10702
10716
|
return section(
|
|
10703
|
-
serverActivityHeading(audience, false),
|
|
10717
|
+
serverActivityHeading(audience, false, windowDays),
|
|
10704
10718
|
renderEmpty(isClient ? "Your server-side traffic source is connected. Numbers will appear after the next sync." : "Source connected \u2014 collecting your first data. Numbers will appear after the next sync.")
|
|
10705
10719
|
);
|
|
10706
10720
|
}
|
|
10707
10721
|
const formatDelta = (d, suffix) => {
|
|
10708
|
-
const copy = formatDeltaCopy(d, suffix);
|
|
10722
|
+
const copy = formatDeltaCopy(d, suffix, priorWindowLabel);
|
|
10709
10723
|
if (!copy) return "";
|
|
10710
10724
|
return `<span class="tone-${deltaTone(d.deltaPct)}">${escapeHtml(copy)}</span>`;
|
|
10711
10725
|
};
|
|
@@ -10732,7 +10746,7 @@ function renderServerActivity(report, audience) {
|
|
|
10732
10746
|
<td class="numeric">${formatNumber(o.referralArrivals)}</td>
|
|
10733
10747
|
</tr>`).join("");
|
|
10734
10748
|
return section(
|
|
10735
|
-
serverActivityHeading("client", true),
|
|
10749
|
+
serverActivityHeading("client", true, windowDays),
|
|
10736
10750
|
`<div class="metric-grid">
|
|
10737
10751
|
<div class="metric">
|
|
10738
10752
|
<div class="label">AI bot requests observed</div>
|
|
@@ -10752,7 +10766,7 @@ function renderServerActivity(report, audience) {
|
|
|
10752
10766
|
</div>
|
|
10753
10767
|
${clientOperatorRows ? `<div class="chart-card"><h3>By AI tool</h3>
|
|
10754
10768
|
<table class="report-table">
|
|
10755
|
-
<thead><tr><th>AI tool</th><th class="numeric">Bot requests (
|
|
10769
|
+
<thead><tr><th>AI tool</th><th class="numeric">Bot requests (${windowLabel})</th><th class="numeric">User fetches (${windowLabel})</th><th class="numeric">Referral sessions</th></tr></thead>
|
|
10756
10770
|
<tbody>${clientOperatorRows}</tbody>
|
|
10757
10771
|
</table>
|
|
10758
10772
|
<p class="meta">Bot requests are bulk crawl (GPTBot, PerplexityBot, \u2026). User fetches are on-demand reads triggered by real users inside an AI surface (ChatGPT-User, Perplexity-User, \u2026). Verified means the request came from an IP the operator publishes as its own; unverified means the user-agent matched but the IP is not in a published range. User-fetch totals count both, since many genuine user fetches come from outside any published range.</p>
|
|
@@ -10793,28 +10807,28 @@ function renderServerActivity(report, audience) {
|
|
|
10793
10807
|
const trendChart = sa.dailyTrend.length > 0 ? renderLineChart(
|
|
10794
10808
|
sa.dailyTrend.map((d) => ({ x: d.date, y: d.verifiedCrawlerHits, label: d.date.slice(5) })),
|
|
10795
10809
|
COLORS.series[1],
|
|
10796
|
-
|
|
10810
|
+
`Verified crawler hits over time (last ${windowDays} days)`
|
|
10797
10811
|
) : "";
|
|
10798
10812
|
return section(
|
|
10799
|
-
serverActivityHeading("agency", true),
|
|
10813
|
+
serverActivityHeading("agency", true, windowDays),
|
|
10800
10814
|
`<div class="metric-grid">
|
|
10801
10815
|
<div class="metric">
|
|
10802
|
-
<div class="label">Verified crawler hits (
|
|
10816
|
+
<div class="label">Verified crawler hits (${windowLabel})</div>
|
|
10803
10817
|
<div class="value">${formatNumber(sa.verifiedCrawlerHits.current)}</div>
|
|
10804
10818
|
<div class="subtitle">${formatDelta(sa.verifiedCrawlerHits, "hits")}</div>
|
|
10805
10819
|
</div>
|
|
10806
10820
|
<div class="metric">
|
|
10807
|
-
<div class="label">Unverified crawler hits (
|
|
10821
|
+
<div class="label">Unverified crawler hits (${windowLabel})</div>
|
|
10808
10822
|
<div class="value">${formatNumber(sa.unverifiedCrawlerHits.current)}</div>
|
|
10809
10823
|
<div class="subtitle">${formatDelta(sa.unverifiedCrawlerHits, "hits")}</div>
|
|
10810
10824
|
</div>
|
|
10811
10825
|
<div class="metric">
|
|
10812
|
-
<div class="label">AI user-fetch hits (
|
|
10826
|
+
<div class="label">AI user-fetch hits (${windowLabel})</div>
|
|
10813
10827
|
<div class="value">${formatNumber(sa.aiUserFetchHits.current)}</div>
|
|
10814
10828
|
<div class="subtitle">${formatDelta(sa.aiUserFetchHits, "hits")}</div>
|
|
10815
10829
|
</div>
|
|
10816
10830
|
<div class="metric">
|
|
10817
|
-
<div class="label">AI-referral sessions (
|
|
10831
|
+
<div class="label">AI-referral sessions (${windowLabel})</div>
|
|
10818
10832
|
<div class="value">${formatNumber(sa.referralArrivals.current)}</div>
|
|
10819
10833
|
<div class="subtitle">${formatDelta(sa.referralArrivals, "sessions")}</div>
|
|
10820
10834
|
</div>
|
|
@@ -10823,12 +10837,12 @@ function renderServerActivity(report, audience) {
|
|
|
10823
10837
|
${operatorRows ? `<div class="chart-card"><h3>Per AI operator</h3>
|
|
10824
10838
|
<p class="meta">Verified means the request's source IP falls inside the operator's published range. Unverified bots claim the user-agent but the IP is not in a published range, so it could be the real bot or an imitator. User fetches are on-demand reads from an AI surface on behalf of a real user (ChatGPT-User, Perplexity-User, \u2026), disjoint from bulk crawl and counted whether or not the IP can be verified.</p>
|
|
10825
10839
|
<table class="report-table">
|
|
10826
|
-
<thead><tr><th>Operator</th><th class="numeric">Verified hits</th><th class="numeric">Unverified</th><th class="numeric">User fetches</th><th class="numeric">Referral sessions</th><th class="numeric"
|
|
10840
|
+
<thead><tr><th>Operator</th><th class="numeric">Verified hits</th><th class="numeric">Unverified</th><th class="numeric">User fetches</th><th class="numeric">Referral sessions</th><th class="numeric">${windowLabel} delta</th></tr></thead>
|
|
10827
10841
|
<tbody>${operatorRows}</tbody>
|
|
10828
10842
|
</table>
|
|
10829
10843
|
</div>` : ""}
|
|
10830
10844
|
${pathRows ? `<div class="chart-card"><h3>Top crawled paths</h3>
|
|
10831
|
-
<p class="meta">Pages AI bots fetched most often (verified only, last
|
|
10845
|
+
<p class="meta">Pages AI bots fetched most often (verified only, last ${windowLabel}).</p>
|
|
10832
10846
|
<table class="report-table">
|
|
10833
10847
|
<thead><tr><th>Path</th><th class="numeric">Verified hits</th><th class="numeric">Distinct operators</th></tr></thead>
|
|
10834
10848
|
<tbody>${pathRows}</tbody>
|
|
@@ -11308,7 +11322,7 @@ function renderReportHtml(report, opts = {}) {
|
|
|
11308
11322
|
<header class="header">
|
|
11309
11323
|
<div class="eyebrow">AI Visibility Report</div>
|
|
11310
11324
|
<h1>${escapeHtml(report.meta.project.displayName)}</h1>
|
|
11311
|
-
<div class="subtitle">${escapeHtml(report.meta.project.canonicalDomain)} \xB7 ${escapeHtml(report.meta.project.country)} / ${escapeHtml(report.meta.project.language.toUpperCase())}${renderHeaderLocationFragment(report.meta.location)} \xB7 Generated ${formatDate(report.meta.generatedAt)}</div>
|
|
11325
|
+
<div class="subtitle">${escapeHtml(report.meta.project.canonicalDomain)} \xB7 ${escapeHtml(report.meta.project.country)} / ${escapeHtml(report.meta.project.language.toUpperCase())}${renderHeaderLocationFragment(report.meta.location)} \xB7 Last ${report.meta.periodDays} days \xB7 Generated ${formatDate(report.meta.generatedAt)}</div>
|
|
11312
11326
|
</header>
|
|
11313
11327
|
${sections}
|
|
11314
11328
|
<footer class="footer">Generated by <a href="https://canonry.ai">canonry</a> \xB7 ${escapeHtml(formatIsoDate(report.meta.generatedAt))}</footer>
|
|
@@ -11324,10 +11338,8 @@ var TOP_LANDING_PAGES_LIMIT = 20;
|
|
|
11324
11338
|
var TOP_AI_REFERRAL_PAGES_LIMIT = 10;
|
|
11325
11339
|
var TOP_CAMPAIGN_LIMIT = 10;
|
|
11326
11340
|
var INSIGHT_LOOKBACK_RUNS = 5;
|
|
11327
|
-
var REPORT_WINDOW_DAYS = 30;
|
|
11328
|
-
var SERVER_ACTIVITY_HEADLINE_DAYS = 7;
|
|
11329
|
-
var SERVER_ACTIVITY_TREND_DAYS = 14;
|
|
11330
11341
|
var SERVER_ACTIVITY_TOP_PATHS_LIMIT = 10;
|
|
11342
|
+
var GA_WINDOW_SUMMARY_KEYS = { 7: "7d", 30: "30d", 90: "90d" };
|
|
11331
11343
|
function windowStartDate(endDate, windowDays) {
|
|
11332
11344
|
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(endDate);
|
|
11333
11345
|
if (!m) return endDate;
|
|
@@ -11373,12 +11385,12 @@ function loadQueryLookup(db, projectId) {
|
|
|
11373
11385
|
for (const row of rows) byId.set(row.id, row.query);
|
|
11374
11386
|
return { byId };
|
|
11375
11387
|
}
|
|
11376
|
-
function buildGscSection(db, projectId, projectBrandNames, canonicalDomain, trackedQueries) {
|
|
11388
|
+
function buildGscSection(db, projectId, projectBrandNames, canonicalDomain, trackedQueries, windowDays) {
|
|
11377
11389
|
const allRows = db.select().from(gscSearchData).where(eq14(gscSearchData.projectId, projectId)).all();
|
|
11378
11390
|
if (allRows.length === 0) return null;
|
|
11379
11391
|
let maxDate = "";
|
|
11380
11392
|
for (const r of allRows) if (r.date > maxDate) maxDate = r.date;
|
|
11381
|
-
const startDate = windowStartDate(maxDate,
|
|
11393
|
+
const startDate = windowStartDate(maxDate, windowDays);
|
|
11382
11394
|
const rows = allRows.filter((r) => r.date >= startDate && r.date <= maxDate);
|
|
11383
11395
|
if (rows.length === 0) return null;
|
|
11384
11396
|
let totalClicks = 0;
|
|
@@ -11445,19 +11457,20 @@ function buildGscSection(db, projectId, projectBrandNames, canonicalDomain, trac
|
|
|
11445
11457
|
gscButNotTracked
|
|
11446
11458
|
};
|
|
11447
11459
|
}
|
|
11448
|
-
function buildGaSection(db, projectId) {
|
|
11449
|
-
const
|
|
11460
|
+
function buildGaSection(db, projectId, windowDays) {
|
|
11461
|
+
const gaWindowKey = GA_WINDOW_SUMMARY_KEYS[windowDays];
|
|
11462
|
+
const windowSummary = gaWindowKey ? db.select().from(gaTrafficWindowSummaries).where(
|
|
11450
11463
|
and9(
|
|
11451
11464
|
eq14(gaTrafficWindowSummaries.projectId, projectId),
|
|
11452
|
-
eq14(gaTrafficWindowSummaries.windowKey,
|
|
11465
|
+
eq14(gaTrafficWindowSummaries.windowKey, gaWindowKey)
|
|
11453
11466
|
)
|
|
11454
|
-
).limit(1).get();
|
|
11467
|
+
).limit(1).get() : void 0;
|
|
11455
11468
|
const fallbackSummary = windowSummary ? null : db.select().from(gaTrafficSummaries).where(eq14(gaTrafficSummaries.projectId, projectId)).orderBy(desc7(gaTrafficSummaries.syncedAt)).limit(1).get();
|
|
11456
11469
|
const allSnapshotRows = db.select().from(gaTrafficSnapshots).where(eq14(gaTrafficSnapshots.projectId, projectId)).all();
|
|
11457
11470
|
if (!windowSummary && !fallbackSummary && allSnapshotRows.length === 0) return null;
|
|
11458
11471
|
let snapshotMaxDate = "";
|
|
11459
11472
|
for (const r of allSnapshotRows) if (r.date > snapshotMaxDate) snapshotMaxDate = r.date;
|
|
11460
|
-
const snapshotStartDate = snapshotMaxDate ? windowStartDate(snapshotMaxDate,
|
|
11473
|
+
const snapshotStartDate = snapshotMaxDate ? windowStartDate(snapshotMaxDate, windowDays) : "";
|
|
11461
11474
|
const snapshotRows = snapshotStartDate ? allSnapshotRows.filter((r) => r.date >= snapshotStartDate && r.date <= snapshotMaxDate) : allSnapshotRows;
|
|
11462
11475
|
const totalSessions = windowSummary?.totalSessions ?? fallbackSummary?.totalSessions ?? snapshotRows.reduce((s, r) => s + r.sessions, 0);
|
|
11463
11476
|
const totalUsers = windowSummary?.totalUsers ?? fallbackSummary?.totalUsers ?? snapshotRows.reduce((s, r) => s + r.users, 0);
|
|
@@ -11623,7 +11636,7 @@ function nonSubresourceReferralPathCondition() {
|
|
|
11623
11636
|
AND LOWER(${aiReferralEventsHourly.landingPathNormalized}) NOT LIKE '%.woff2'
|
|
11624
11637
|
`;
|
|
11625
11638
|
}
|
|
11626
|
-
function buildServerActivity(db, projectId) {
|
|
11639
|
+
function buildServerActivity(db, projectId, windowDays) {
|
|
11627
11640
|
const sourceRows = db.select({ id: trafficSources.id }).from(trafficSources).where(
|
|
11628
11641
|
and9(
|
|
11629
11642
|
eq14(trafficSources.projectId, projectId),
|
|
@@ -11633,9 +11646,9 @@ function buildServerActivity(db, projectId) {
|
|
|
11633
11646
|
if (sourceRows.length === 0) return null;
|
|
11634
11647
|
const now = /* @__PURE__ */ new Date();
|
|
11635
11648
|
const headlineEnd = now.toISOString();
|
|
11636
|
-
const headlineStartMs = now.getTime() -
|
|
11637
|
-
const priorStartMs = headlineStartMs -
|
|
11638
|
-
const trendStartMs =
|
|
11649
|
+
const headlineStartMs = now.getTime() - windowDays * 24 * 60 * 6e4;
|
|
11650
|
+
const priorStartMs = headlineStartMs - windowDays * 24 * 60 * 6e4;
|
|
11651
|
+
const trendStartMs = headlineStartMs;
|
|
11639
11652
|
const headlineStart = new Date(headlineStartMs).toISOString();
|
|
11640
11653
|
const priorStart = new Date(priorStartMs).toISOString();
|
|
11641
11654
|
const trendStart = new Date(trendStartMs).toISOString();
|
|
@@ -12419,8 +12432,6 @@ function buildAgencyDiagnostics(input) {
|
|
|
12419
12432
|
diagnostics
|
|
12420
12433
|
};
|
|
12421
12434
|
}
|
|
12422
|
-
var WHATS_CHANGED_PERIOD_DAYS2 = 14;
|
|
12423
|
-
var WHATS_CHANGED_MIN_TREND_POINTS = WHATS_CHANGED_PERIOD_DAYS2 * 2;
|
|
12424
12435
|
var RATE_REAL_MOVEMENT_THRESHOLD_PP = 3;
|
|
12425
12436
|
var COUNT_REAL_MOVEMENT_THRESHOLD = 0.5;
|
|
12426
12437
|
var WIN_REGRESSION_LIMIT = 5;
|
|
@@ -12429,10 +12440,10 @@ function rateDirection(delta, threshold = 0.5) {
|
|
|
12429
12440
|
if (delta < -threshold) return "down";
|
|
12430
12441
|
return "flat";
|
|
12431
12442
|
}
|
|
12432
|
-
function periodOverPeriodDelta(trend) {
|
|
12433
|
-
if (trend.length <
|
|
12434
|
-
const tail = trend.slice(-
|
|
12435
|
-
const prior = trend.slice(-
|
|
12443
|
+
function periodOverPeriodDelta(trend, halfWindow) {
|
|
12444
|
+
if (trend.length < halfWindow * 2) return null;
|
|
12445
|
+
const tail = trend.slice(-halfWindow);
|
|
12446
|
+
const prior = trend.slice(-halfWindow * 2, -halfWindow);
|
|
12436
12447
|
const current = tail.reduce((s, p) => s + p.value, 0);
|
|
12437
12448
|
const priorTotal = prior.reduce((s, p) => s + p.value, 0);
|
|
12438
12449
|
const deltaAbs = current - priorTotal;
|
|
@@ -12444,7 +12455,7 @@ function periodOverPeriodDelta(trend) {
|
|
|
12444
12455
|
direction: rateDirection(deltaAbs, 0)
|
|
12445
12456
|
};
|
|
12446
12457
|
}
|
|
12447
|
-
function buildWhatsChangedHeadline(citation, gscClicks, aiReferrals, enoughHistory, trendLength) {
|
|
12458
|
+
function buildWhatsChangedHeadline(citation, gscClicks, aiReferrals, enoughHistory, trendLength, comparisonWindowDays) {
|
|
12448
12459
|
if (!enoughHistory) {
|
|
12449
12460
|
return `Building baseline (${trendLength} of ${MIN_TREND_POINTS} checks completed). Trends appear after a few more checks.`;
|
|
12450
12461
|
}
|
|
@@ -12457,15 +12468,15 @@ function buildWhatsChangedHeadline(citation, gscClicks, aiReferrals, enoughHisto
|
|
|
12457
12468
|
}
|
|
12458
12469
|
if (aiReferrals && aiReferrals.direction !== "flat") {
|
|
12459
12470
|
const arrow = aiReferrals.direction === "up" ? "\u2191" : "\u2193";
|
|
12460
|
-
parts.push(`AI referrals ${arrow}${Math.abs(aiReferrals.deltaAbs)} sessions vs prior
|
|
12471
|
+
parts.push(`AI referrals ${arrow}${Math.abs(aiReferrals.deltaAbs)} sessions vs prior ${comparisonWindowDays} days`);
|
|
12461
12472
|
} else if (gscClicks && gscClicks.direction !== "flat") {
|
|
12462
12473
|
const arrow = gscClicks.direction === "up" ? "\u2191" : "\u2193";
|
|
12463
|
-
parts.push(`GSC clicks ${arrow}${Math.abs(gscClicks.deltaAbs)} vs prior
|
|
12474
|
+
parts.push(`GSC clicks ${arrow}${Math.abs(gscClicks.deltaAbs)} vs prior ${comparisonWindowDays} days`);
|
|
12464
12475
|
}
|
|
12465
12476
|
return parts.length > 0 ? `${parts.join(" \xB7 ")}.` : "No meaningful movement vs the prior period.";
|
|
12466
12477
|
}
|
|
12467
12478
|
function buildWhatsChanged(input) {
|
|
12468
|
-
const { citationsTrend, gsc, aiReferrals, insights: insightList } = input;
|
|
12479
|
+
const { citationsTrend, gsc, aiReferrals, insights: insightList, comparisonWindowDays } = input;
|
|
12469
12480
|
const baseline = isTrendBaseline(citationsTrend);
|
|
12470
12481
|
const latest = citationsTrend.at(-1);
|
|
12471
12482
|
const prior = citationsTrend.length >= 2 ? citationsTrend.at(-2) : null;
|
|
@@ -12502,8 +12513,8 @@ function buildWhatsChanged(input) {
|
|
|
12502
12513
|
}
|
|
12503
12514
|
providerMovements.sort((a, b) => Math.abs(b.deltaAbs) - Math.abs(a.deltaAbs));
|
|
12504
12515
|
}
|
|
12505
|
-
const gscClicksDelta = gsc ? periodOverPeriodDelta(gsc.trend.map((t) => ({ date: t.date, value: t.clicks }))) : null;
|
|
12506
|
-
const aiReferralsDelta = aiReferrals ? periodOverPeriodDelta(aiReferrals.trend.map((t) => ({ date: t.date, value: t.sessions }))) : null;
|
|
12516
|
+
const gscClicksDelta = gsc ? periodOverPeriodDelta(gsc.trend.map((t) => ({ date: t.date, value: t.clicks })), comparisonWindowDays) : null;
|
|
12517
|
+
const aiReferralsDelta = aiReferrals ? periodOverPeriodDelta(aiReferrals.trend.map((t) => ({ date: t.date, value: t.sessions })), comparisonWindowDays) : null;
|
|
12507
12518
|
const wins = insightList.filter((i) => i.type === "gain").slice(0, WIN_REGRESSION_LIMIT);
|
|
12508
12519
|
const regressions = insightList.filter((i) => i.type === "regression").slice(0, WIN_REGRESSION_LIMIT);
|
|
12509
12520
|
const headline = buildWhatsChangedHeadline(
|
|
@@ -12511,7 +12522,8 @@ function buildWhatsChanged(input) {
|
|
|
12511
12522
|
gscClicksDelta,
|
|
12512
12523
|
aiReferralsDelta,
|
|
12513
12524
|
enoughHistory,
|
|
12514
|
-
citationsTrend.length
|
|
12525
|
+
citationsTrend.length,
|
|
12526
|
+
comparisonWindowDays
|
|
12515
12527
|
);
|
|
12516
12528
|
return {
|
|
12517
12529
|
enoughHistory,
|
|
@@ -12521,14 +12533,16 @@ function buildWhatsChanged(input) {
|
|
|
12521
12533
|
citedQueryCount,
|
|
12522
12534
|
gscClicksDelta,
|
|
12523
12535
|
aiReferralsDelta,
|
|
12536
|
+
comparisonWindowDays,
|
|
12524
12537
|
providerMovements,
|
|
12525
12538
|
wins,
|
|
12526
12539
|
regressions
|
|
12527
12540
|
};
|
|
12528
12541
|
}
|
|
12529
|
-
function buildProjectReport(db, projectName) {
|
|
12542
|
+
function buildProjectReport(db, projectName, periodDays) {
|
|
12530
12543
|
const project = resolveProject(db, projectName);
|
|
12531
12544
|
const queryLookup = loadQueryLookup(db, project.id);
|
|
12545
|
+
const comparisonWindowDays = reportComparisonWindowDays(periodDays);
|
|
12532
12546
|
const allRuns = db.select().from(runs).where(and9(eq14(runs.projectId, project.id), notProbeRun())).orderBy(desc7(runs.createdAt), desc7(runs.id)).all();
|
|
12533
12547
|
const visibilityRuns = allRuns.filter((r) => r.kind === RunKinds["answer-visibility"]);
|
|
12534
12548
|
const completedVisRunGroups = groupRunsByCreatedAt(
|
|
@@ -12568,12 +12582,13 @@ function buildProjectReport(db, projectName) {
|
|
|
12568
12582
|
project.id,
|
|
12569
12583
|
projectBrandNames,
|
|
12570
12584
|
project.canonicalDomain,
|
|
12571
|
-
trackedQueries
|
|
12585
|
+
trackedQueries,
|
|
12586
|
+
periodDays
|
|
12572
12587
|
);
|
|
12573
|
-
const gaSection = buildGaSection(db, project.id);
|
|
12588
|
+
const gaSection = buildGaSection(db, project.id, periodDays);
|
|
12574
12589
|
const socialSection = buildSocialReferrals(db, project.id);
|
|
12575
12590
|
const aiReferralsSection = buildAiReferrals(db, project.id);
|
|
12576
|
-
const serverActivitySection = buildServerActivity(db, project.id);
|
|
12591
|
+
const serverActivitySection = buildServerActivity(db, project.id, periodDays);
|
|
12577
12592
|
const indexingHealthSection = buildIndexingHealth(db, project.id);
|
|
12578
12593
|
const citationsTrend = buildCitationsTrend(db, project.id, queryLookup, latestRunLocation);
|
|
12579
12594
|
const insightList = buildInsightList(db, project.id, latestRunLocation);
|
|
@@ -12592,7 +12607,8 @@ function buildProjectReport(db, projectName) {
|
|
|
12592
12607
|
citationsTrend,
|
|
12593
12608
|
gsc: gscSection,
|
|
12594
12609
|
aiReferrals: aiReferralsSection,
|
|
12595
|
-
insights: insightList
|
|
12610
|
+
insights: insightList,
|
|
12611
|
+
comparisonWindowDays
|
|
12596
12612
|
});
|
|
12597
12613
|
const totalQueryCount = queryLookup.byId.size;
|
|
12598
12614
|
const citedQueryIds = /* @__PURE__ */ new Set();
|
|
@@ -12708,7 +12724,8 @@ function buildProjectReport(db, projectName) {
|
|
|
12708
12724
|
location: reportLocation,
|
|
12709
12725
|
providerLocationHandling,
|
|
12710
12726
|
periodStart,
|
|
12711
|
-
periodEnd
|
|
12727
|
+
periodEnd,
|
|
12728
|
+
periodDays
|
|
12712
12729
|
},
|
|
12713
12730
|
executiveSummary,
|
|
12714
12731
|
citationScorecard,
|
|
@@ -12744,12 +12761,14 @@ function reportFilenameFor(project, generatedAt, audience) {
|
|
|
12744
12761
|
}
|
|
12745
12762
|
async function reportRoutes(app) {
|
|
12746
12763
|
app.get("/projects/:name/report", async (request, reply) => {
|
|
12747
|
-
const
|
|
12764
|
+
const periodDays = parseReportPeriodDays(request.query.period);
|
|
12765
|
+
const dto = buildProjectReport(app.db, request.params.name, periodDays);
|
|
12748
12766
|
return reply.send(dto);
|
|
12749
12767
|
});
|
|
12750
12768
|
app.get("/projects/:name/report.html", async (request, reply) => {
|
|
12751
12769
|
const audience = parseReportAudience(request.query.audience);
|
|
12752
|
-
const
|
|
12770
|
+
const periodDays = parseReportPeriodDays(request.query.period);
|
|
12771
|
+
const dto = buildProjectReport(app.db, request.params.name, periodDays);
|
|
12753
12772
|
const html = renderReportHtml(dto, { audience });
|
|
12754
12773
|
const filename = reportFilenameFor(dto.meta.project, dto.meta.generatedAt, audience);
|
|
12755
12774
|
reply.header("Content-Type", "text/html; charset=utf-8");
|
|
@@ -14109,6 +14128,12 @@ var analyticsWindowParameter = {
|
|
|
14109
14128
|
description: "Time window for analytics queries.",
|
|
14110
14129
|
schema: { type: "string", enum: ["7d", "30d", "90d", "all"] }
|
|
14111
14130
|
};
|
|
14131
|
+
var reportPeriodQueryParameter = {
|
|
14132
|
+
name: "period",
|
|
14133
|
+
in: "query",
|
|
14134
|
+
description: "Report window in days \u2014 one of 7, 14, 30, 90 (default 30). Scopes the GSC, GA4, and server-side AI activity sections and the period-over-period comparisons to this window.",
|
|
14135
|
+
schema: { type: "integer", enum: [7, 14, 30, 90] }
|
|
14136
|
+
};
|
|
14112
14137
|
var sinceQueryParameter = {
|
|
14113
14138
|
name: "since",
|
|
14114
14139
|
in: "query",
|
|
@@ -16843,7 +16868,7 @@ var routeCatalog = [
|
|
|
16843
16868
|
summary: "Aggregated canonical AEO report",
|
|
16844
16869
|
tags: ["report"],
|
|
16845
16870
|
description: "Bundles every section the canonry-report HTML output needs (executive summary, client summary, agency diagnostics, action plan, citation scorecard, competitor landscape \u2014 citation + mention landscapes, AI citation sources, GSC, GA4, social/AI referrals, indexing health, citations trend, insights, and recommended next steps) into a single canonical JSON payload. Backs `canonry report <project>` and MCP report reads.",
|
|
16846
|
-
parameters: [nameParameter],
|
|
16871
|
+
parameters: [nameParameter, reportPeriodQueryParameter],
|
|
16847
16872
|
responses: {
|
|
16848
16873
|
200: jsonResponse("Report returned.", "ProjectReportDto"),
|
|
16849
16874
|
404: errorResponse("Project not found.")
|
|
@@ -16855,7 +16880,7 @@ var routeCatalog = [
|
|
|
16855
16880
|
summary: "Standalone HTML AEO report",
|
|
16856
16881
|
tags: ["report"],
|
|
16857
16882
|
description: "Server-rendered self-contained HTML version of the project report. Same data as `/projects/{name}/report` (JSON), rendered through the canonry HTML report renderer in agency or client mode. Returns `text/html` with `Content-Disposition: attachment` so browsers download it as `canonry-report-<project>-<audience>-YYYY-MM-DD.html`. Open in a browser and Print \u2192 Save as PDF for a PDF copy.",
|
|
16858
|
-
parameters: [nameParameter, reportAudienceQueryParameter],
|
|
16883
|
+
parameters: [nameParameter, reportAudienceQueryParameter, reportPeriodQueryParameter],
|
|
16859
16884
|
responses: {
|
|
16860
16885
|
200: { description: "HTML report returned.", content: { "text/html": { schema: { type: "string" } } } },
|
|
16861
16886
|
404: errorResponse("Project not found.")
|
|
@@ -21512,7 +21537,8 @@ function statusDto(row) {
|
|
|
21512
21537
|
currencyCode: row.currencyCode,
|
|
21513
21538
|
timezone: row.timezone,
|
|
21514
21539
|
status: row.status,
|
|
21515
|
-
lastSyncedAt: row.lastSyncedAt
|
|
21540
|
+
lastSyncedAt: row.lastSyncedAt,
|
|
21541
|
+
conversionTrackingConfigured: row.conversionTrackingConfigured
|
|
21516
21542
|
};
|
|
21517
21543
|
}
|
|
21518
21544
|
function creativeDto(raw) {
|
|
@@ -21710,6 +21736,7 @@ async function adsRoutes(app, opts) {
|
|
|
21710
21736
|
impressions: row.impressions,
|
|
21711
21737
|
clicks: row.clicks,
|
|
21712
21738
|
spendMicros: row.spendMicros,
|
|
21739
|
+
conversions: row.conversions,
|
|
21713
21740
|
ctr: adsCtr(row.clicks, row.impressions),
|
|
21714
21741
|
cpcMicros: adsCpcMicros(row.spendMicros, row.clicks)
|
|
21715
21742
|
}));
|
|
@@ -21730,12 +21757,14 @@ async function adsRoutes(app, opts) {
|
|
|
21730
21757
|
let impressions = 0;
|
|
21731
21758
|
let clicks = 0;
|
|
21732
21759
|
let spendMicros = 0;
|
|
21760
|
+
let conversions = 0;
|
|
21733
21761
|
let fromDate = null;
|
|
21734
21762
|
let toDate = null;
|
|
21735
21763
|
for (const insight of campaignInsights) {
|
|
21736
21764
|
impressions += insight.impressions;
|
|
21737
21765
|
clicks += insight.clicks;
|
|
21738
21766
|
spendMicros += insight.spendMicros;
|
|
21767
|
+
conversions += insight.conversions;
|
|
21739
21768
|
if (fromDate === null || insight.date < fromDate) fromDate = insight.date;
|
|
21740
21769
|
if (toDate === null || insight.date > toDate) toDate = insight.date;
|
|
21741
21770
|
}
|
|
@@ -21752,6 +21781,7 @@ async function adsRoutes(app, opts) {
|
|
|
21752
21781
|
impressions,
|
|
21753
21782
|
clicks,
|
|
21754
21783
|
spendMicros,
|
|
21784
|
+
conversions,
|
|
21755
21785
|
ctr: adsCtr(clicks, impressions),
|
|
21756
21786
|
cpcMicros: adsCpcMicros(spendMicros, clicks)
|
|
21757
21787
|
}
|
package/dist/cli.js
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
setTelemetrySource,
|
|
28
28
|
showFirstRunNotice,
|
|
29
29
|
trackEvent
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-NUGGUQH3.js";
|
|
31
31
|
import {
|
|
32
32
|
CliError,
|
|
33
33
|
EXIT_SYSTEM_ERROR,
|
|
@@ -44,7 +44,7 @@ import {
|
|
|
44
44
|
saveConfig,
|
|
45
45
|
saveConfigPatch,
|
|
46
46
|
usageError
|
|
47
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-SRJ5IGNK.js";
|
|
48
48
|
import {
|
|
49
49
|
apiKeys,
|
|
50
50
|
createClient,
|
|
@@ -52,7 +52,7 @@ import {
|
|
|
52
52
|
projects,
|
|
53
53
|
queries,
|
|
54
54
|
renderReportHtml
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-TXNKKTFD.js";
|
|
56
56
|
import {
|
|
57
57
|
BacklinkSources,
|
|
58
58
|
CcReleaseSyncStatuses,
|
|
@@ -60,6 +60,7 @@ import {
|
|
|
60
60
|
CheckStatuses,
|
|
61
61
|
CitationStates,
|
|
62
62
|
READ_ONLY_SCOPE,
|
|
63
|
+
REPORT_PERIOD_OPTIONS,
|
|
63
64
|
RunStatuses,
|
|
64
65
|
TrafficEventKinds,
|
|
65
66
|
backlinkSourceSchema,
|
|
@@ -77,7 +78,7 @@ import {
|
|
|
77
78
|
providerQuotaPolicySchema,
|
|
78
79
|
resolveProviderInput,
|
|
79
80
|
winnabilityClassSchema
|
|
80
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-E2FDXNMW.js";
|
|
81
82
|
|
|
82
83
|
// src/cli.ts
|
|
83
84
|
import { pathToFileURL } from "url";
|
|
@@ -7868,7 +7869,7 @@ function defaultOutputPath(project, audience) {
|
|
|
7868
7869
|
}
|
|
7869
7870
|
async function runReportCommand(project, opts = {}) {
|
|
7870
7871
|
const client = createApiClient();
|
|
7871
|
-
const report = await client.getReport(project);
|
|
7872
|
+
const report = await client.getReport(project, opts.period !== void 0 ? { period: opts.period } : void 0);
|
|
7872
7873
|
const audience = opts.audience ?? "agency";
|
|
7873
7874
|
if (isMachineFormat(opts.format)) {
|
|
7874
7875
|
console.log(JSON.stringify(report, null, 2));
|
|
@@ -7885,12 +7886,22 @@ async function runReportCommand(project, opts = {}) {
|
|
|
7885
7886
|
}
|
|
7886
7887
|
|
|
7887
7888
|
// src/cli-commands/report.ts
|
|
7888
|
-
var USAGE3 = "canonry report <project> [--audience agency|client] [--output <path>] [--format json]";
|
|
7889
|
+
var USAGE3 = "canonry report <project> [--audience agency|client] [--period 7|14|30|90] [--output <path>] [--format json]";
|
|
7889
7890
|
function parseAudience(value) {
|
|
7890
7891
|
if (value === void 0) return void 0;
|
|
7891
7892
|
if (value === "agency" || value === "client") return value;
|
|
7892
7893
|
throw usageError(`Error: --audience must be "agency" or "client"
|
|
7893
7894
|
|
|
7895
|
+
Usage: ${USAGE3}`);
|
|
7896
|
+
}
|
|
7897
|
+
function parsePeriod(value) {
|
|
7898
|
+
if (value === void 0) return void 0;
|
|
7899
|
+
const n = Number(value);
|
|
7900
|
+
if (Number.isInteger(n) && REPORT_PERIOD_OPTIONS.includes(n)) {
|
|
7901
|
+
return n;
|
|
7902
|
+
}
|
|
7903
|
+
throw usageError(`Error: --period must be one of ${REPORT_PERIOD_OPTIONS.join(", ")}
|
|
7904
|
+
|
|
7894
7905
|
Usage: ${USAGE3}`);
|
|
7895
7906
|
}
|
|
7896
7907
|
var REPORT_CLI_COMMANDS = [
|
|
@@ -7899,6 +7910,7 @@ var REPORT_CLI_COMMANDS = [
|
|
|
7899
7910
|
usage: USAGE3,
|
|
7900
7911
|
options: {
|
|
7901
7912
|
audience: { type: "string" },
|
|
7913
|
+
period: { type: "string" },
|
|
7902
7914
|
output: { type: "string", short: "o" }
|
|
7903
7915
|
},
|
|
7904
7916
|
run: async (input) => {
|
|
@@ -7906,6 +7918,7 @@ var REPORT_CLI_COMMANDS = [
|
|
|
7906
7918
|
await runReportCommand(project, {
|
|
7907
7919
|
format: input.format,
|
|
7908
7920
|
audience: parseAudience(getString(input.values, "audience")),
|
|
7921
|
+
period: parsePeriod(getString(input.values, "period")),
|
|
7909
7922
|
output: getString(input.values, "output")
|
|
7910
7923
|
});
|
|
7911
7924
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createServer
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NUGGUQH3.js";
|
|
4
4
|
import {
|
|
5
5
|
loadConfig
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-SRJ5IGNK.js";
|
|
7
|
+
import "./chunk-TXNKKTFD.js";
|
|
8
|
+
import "./chunk-E2FDXNMW.js";
|
|
9
9
|
export {
|
|
10
10
|
createServer,
|
|
11
11
|
loadConfig
|
package/dist/mcp.js
CHANGED
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
PACKAGE_VERSION,
|
|
4
4
|
canonryMcpTools,
|
|
5
5
|
createApiClient
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-SRJ5IGNK.js";
|
|
7
7
|
import {
|
|
8
8
|
isReadOnlyKey
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-E2FDXNMW.js";
|
|
10
10
|
|
|
11
11
|
// src/mcp/cli.ts
|
|
12
12
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|