@ainyc/canonry 4.100.0 → 4.100.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/assets/agent-workspace/skills/canonry/references/canonry-cli.md +0 -12
- package/assets/assets/{BacklinksPage-DWZdWEm3.js → BacklinksPage-v2RC8wlg.js} +1 -1
- package/assets/assets/{ChartPrimitives-C-ky5206.js → ChartPrimitives-B74e5pqn.js} +1 -1
- package/assets/assets/{ProjectPage-CpbFpi6J.js → ProjectPage-BCzS7TQn.js} +4 -4
- package/assets/assets/{RunRow-Bj-D4kZe.js → RunRow-BmVPjO-m.js} +1 -1
- package/assets/assets/{RunsPage-GktitsAV.js → RunsPage-CK5atXvL.js} +1 -1
- package/assets/assets/{SettingsPage-AsFLFDS3.js → SettingsPage-DarPFUPl.js} +1 -1
- package/assets/assets/{TrafficPage-Cf3uCkxs.js → TrafficPage-Ddnn_WqU.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-B5t7nf9C.js → TrafficSourceDetailPage-g08SKnwZ.js} +1 -1
- package/assets/assets/{arrow-left-CZFQuQO_.js → arrow-left-D39Vxasb.js} +1 -1
- package/assets/assets/{extract-error-message--bieZ2IX.js → extract-error-message-BiNWqBeh.js} +1 -1
- package/assets/assets/index-BCuWbxUj.css +1 -0
- package/assets/assets/index-Dd4J1VhB.js +210 -0
- package/assets/assets/{trash-2-sKO0k75f.js → trash-2-xh6gsnap.js} +1 -1
- package/assets/index.html +2 -2
- package/dist/{chunk-74SOIAIY.js → chunk-ALJSES3X.js} +4 -4
- package/dist/{chunk-UVIHWF45.js → chunk-IDI6LMYL.js} +1 -27
- package/dist/{chunk-ADLS64PG.js → chunk-JF7EXHGA.js} +0 -105
- package/dist/{chunk-SNHYRSUF.js → chunk-YBIT5O62.js} +12 -366
- package/dist/cli.js +4 -110
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-3CRNJLUZ.js → intelligence-service-TWCEKVKZ.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +9 -9
- package/assets/assets/index-9hI0ODQU.css +0 -1
- package/assets/assets/index-Cb2h7KkD.js +0 -210
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
DiscoveryBuckets,
|
|
19
19
|
DiscoveryCompetitorTypes,
|
|
20
20
|
DiscoverySessionStatuses,
|
|
21
|
-
PortfolioChangeTypes,
|
|
22
21
|
RunKinds,
|
|
23
22
|
RunStatuses,
|
|
24
23
|
RunTriggers,
|
|
@@ -132,7 +131,6 @@ import {
|
|
|
132
131
|
formatIsoDate,
|
|
133
132
|
formatNumber,
|
|
134
133
|
formatRatio,
|
|
135
|
-
formatRunErrorOneLine,
|
|
136
134
|
formatWindowCountDelta,
|
|
137
135
|
ga4AiReferralHistoryEntrySchema,
|
|
138
136
|
ga4SessionHistoryEntrySchema,
|
|
@@ -186,7 +184,6 @@ import {
|
|
|
186
184
|
parseRunError,
|
|
187
185
|
parseWindow,
|
|
188
186
|
pickClusterRepresentative,
|
|
189
|
-
portfolioDtoSchema,
|
|
190
187
|
projectConfigSchema,
|
|
191
188
|
projectDtoSchema,
|
|
192
189
|
projectOverviewDtoSchema,
|
|
@@ -266,10 +263,10 @@ import {
|
|
|
266
263
|
wordpressSchemaDeployResultDtoSchema,
|
|
267
264
|
wordpressSchemaStatusResultDtoSchema,
|
|
268
265
|
wordpressStatusDtoSchema
|
|
269
|
-
} from "./chunk-
|
|
266
|
+
} from "./chunk-JF7EXHGA.js";
|
|
270
267
|
|
|
271
268
|
// src/intelligence-service.ts
|
|
272
|
-
import { eq as eq37, desc as desc18, asc as
|
|
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";
|
|
273
270
|
|
|
274
271
|
// ../db/src/client.ts
|
|
275
272
|
import { mkdirSync } from "fs";
|
|
@@ -5048,233 +5045,6 @@ function buildRunHistory(runs2, snapshotsByRunId, limit = DEFAULT_RUN_HISTORY_LI
|
|
|
5048
5045
|
});
|
|
5049
5046
|
}
|
|
5050
5047
|
|
|
5051
|
-
// ../intelligence/src/portfolio-change-feed.ts
|
|
5052
|
-
var PORTFOLIO_CHANGE_FEED_LIMIT = 12;
|
|
5053
|
-
var TONE_SEVERITY = {
|
|
5054
|
-
negative: 0,
|
|
5055
|
-
caution: 1,
|
|
5056
|
-
positive: 2,
|
|
5057
|
-
neutral: 3
|
|
5058
|
-
};
|
|
5059
|
-
function pluralizeQueries(n) {
|
|
5060
|
-
return n === 1 ? "query" : "queries";
|
|
5061
|
-
}
|
|
5062
|
-
function pluralizeAnswers(n) {
|
|
5063
|
-
return n === 1 ? "answer" : "answers";
|
|
5064
|
-
}
|
|
5065
|
-
function affectedDetail(queries2, max = 3) {
|
|
5066
|
-
const list = queries2 ?? [];
|
|
5067
|
-
if (list.length === 0) return "";
|
|
5068
|
-
const shown = list.slice(0, max).map((q) => `"${q}"`).join(", ");
|
|
5069
|
-
const remaining = list.length - max;
|
|
5070
|
-
return remaining > 0 ? `${shown} +${remaining} more` : shown;
|
|
5071
|
-
}
|
|
5072
|
-
function buildProjectChanges(input) {
|
|
5073
|
-
const {
|
|
5074
|
-
projectName,
|
|
5075
|
-
projectSlug,
|
|
5076
|
-
citationMovement,
|
|
5077
|
-
mentionMovement,
|
|
5078
|
-
movementComparison,
|
|
5079
|
-
attentionItems,
|
|
5080
|
-
latestRun
|
|
5081
|
-
} = input;
|
|
5082
|
-
const href = `/projects/${encodeURIComponent(projectSlug)}`;
|
|
5083
|
-
const rows = [];
|
|
5084
|
-
if (!latestRun) {
|
|
5085
|
-
rows.push({
|
|
5086
|
-
id: `${projectSlug}:${PortfolioChangeTypes["project-never-run"]}`,
|
|
5087
|
-
projectName,
|
|
5088
|
-
projectSlug,
|
|
5089
|
-
changeType: PortfolioChangeTypes["project-never-run"],
|
|
5090
|
-
tone: "neutral",
|
|
5091
|
-
title: `${projectName} has no completed sweep yet`,
|
|
5092
|
-
detail: `${input.trackedQueryCount} ${pluralizeQueries(input.trackedQueryCount)} tracked \u2014 run a sweep to start measuring.`,
|
|
5093
|
-
occurredAt: input.projectCreatedAt,
|
|
5094
|
-
href,
|
|
5095
|
-
actionLabel: "Run sweep",
|
|
5096
|
-
comparable: false
|
|
5097
|
-
});
|
|
5098
|
-
return rows;
|
|
5099
|
-
}
|
|
5100
|
-
const { runId, occurredAt } = latestRun;
|
|
5101
|
-
const comparable = movementComparison.comparable;
|
|
5102
|
-
if (latestRun.status === RunStatuses.failed) {
|
|
5103
|
-
rows.push({
|
|
5104
|
-
id: `${projectSlug}:${PortfolioChangeTypes["run-failed"]}:${runId}`,
|
|
5105
|
-
projectName,
|
|
5106
|
-
projectSlug,
|
|
5107
|
-
changeType: PortfolioChangeTypes["run-failed"],
|
|
5108
|
-
tone: "negative",
|
|
5109
|
-
title: `${projectName} sweep failed`,
|
|
5110
|
-
detail: latestRun.error ? formatRunErrorOneLine(latestRun.error) : "The latest visibility sweep failed.",
|
|
5111
|
-
occurredAt,
|
|
5112
|
-
href,
|
|
5113
|
-
actionLabel: "View run",
|
|
5114
|
-
comparable
|
|
5115
|
-
});
|
|
5116
|
-
}
|
|
5117
|
-
if (comparable) {
|
|
5118
|
-
if (citationMovement.lost > 0) {
|
|
5119
|
-
rows.push({
|
|
5120
|
-
id: `${projectSlug}:${PortfolioChangeTypes["citation-lost"]}:${runId}`,
|
|
5121
|
-
projectName,
|
|
5122
|
-
projectSlug,
|
|
5123
|
-
changeType: PortfolioChangeTypes["citation-lost"],
|
|
5124
|
-
tone: "negative",
|
|
5125
|
-
title: `${projectName} lost ${citationMovement.lost} cited ${pluralizeQueries(citationMovement.lost)}`,
|
|
5126
|
-
detail: affectedDetail(citationMovement.lostQueries),
|
|
5127
|
-
occurredAt,
|
|
5128
|
-
href,
|
|
5129
|
-
actionLabel: "Open project",
|
|
5130
|
-
comparable: true
|
|
5131
|
-
});
|
|
5132
|
-
}
|
|
5133
|
-
if (citationMovement.gained > 0) {
|
|
5134
|
-
rows.push({
|
|
5135
|
-
id: `${projectSlug}:${PortfolioChangeTypes["citation-gained"]}:${runId}`,
|
|
5136
|
-
projectName,
|
|
5137
|
-
projectSlug,
|
|
5138
|
-
changeType: PortfolioChangeTypes["citation-gained"],
|
|
5139
|
-
tone: "positive",
|
|
5140
|
-
title: `${projectName} gained ${citationMovement.gained} cited ${pluralizeQueries(citationMovement.gained)}`,
|
|
5141
|
-
detail: affectedDetail(citationMovement.gainedQueries),
|
|
5142
|
-
occurredAt,
|
|
5143
|
-
href,
|
|
5144
|
-
actionLabel: "Open project",
|
|
5145
|
-
comparable: true
|
|
5146
|
-
});
|
|
5147
|
-
}
|
|
5148
|
-
if (mentionMovement.lost > 0) {
|
|
5149
|
-
const queries2 = affectedDetail(mentionMovement.lostQueries);
|
|
5150
|
-
rows.push({
|
|
5151
|
-
id: `${projectSlug}:${PortfolioChangeTypes["mention-lost"]}:${runId}`,
|
|
5152
|
-
projectName,
|
|
5153
|
-
projectSlug,
|
|
5154
|
-
changeType: PortfolioChangeTypes["mention-lost"],
|
|
5155
|
-
tone: "negative",
|
|
5156
|
-
title: `${projectName} dropped from ${mentionMovement.lost} ${pluralizeAnswers(mentionMovement.lost)}`,
|
|
5157
|
-
detail: queries2 ? `No longer mentioned for ${queries2}` : "",
|
|
5158
|
-
occurredAt,
|
|
5159
|
-
href,
|
|
5160
|
-
actionLabel: "Open project",
|
|
5161
|
-
comparable: true
|
|
5162
|
-
});
|
|
5163
|
-
}
|
|
5164
|
-
if (mentionMovement.gained > 0) {
|
|
5165
|
-
rows.push({
|
|
5166
|
-
id: `${projectSlug}:${PortfolioChangeTypes["mention-gained"]}:${runId}`,
|
|
5167
|
-
projectName,
|
|
5168
|
-
projectSlug,
|
|
5169
|
-
changeType: PortfolioChangeTypes["mention-gained"],
|
|
5170
|
-
tone: "positive",
|
|
5171
|
-
title: `${projectName} now mentioned in ${mentionMovement.gained} more ${pluralizeAnswers(mentionMovement.gained)}`,
|
|
5172
|
-
detail: affectedDetail(mentionMovement.gainedQueries),
|
|
5173
|
-
occurredAt,
|
|
5174
|
-
href,
|
|
5175
|
-
actionLabel: "Open project",
|
|
5176
|
-
comparable: true
|
|
5177
|
-
});
|
|
5178
|
-
}
|
|
5179
|
-
} else if (movementComparison.hasPreviousRun && movementComparison.querySetChanged) {
|
|
5180
|
-
rows.push({
|
|
5181
|
-
id: `${projectSlug}:${PortfolioChangeTypes["query-set-changed"]}:${runId}`,
|
|
5182
|
-
projectName,
|
|
5183
|
-
projectSlug,
|
|
5184
|
-
changeType: PortfolioChangeTypes["query-set-changed"],
|
|
5185
|
-
tone: "neutral",
|
|
5186
|
-
title: `${projectName} query set changed`,
|
|
5187
|
-
detail: `+${movementComparison.addedQueryCount} added \xB7 \u2212${movementComparison.removedQueryCount} removed since last sweep \u2014 movement compares the shared queries`,
|
|
5188
|
-
occurredAt,
|
|
5189
|
-
href,
|
|
5190
|
-
actionLabel: "Open project",
|
|
5191
|
-
comparable: false
|
|
5192
|
-
});
|
|
5193
|
-
}
|
|
5194
|
-
for (const item of attentionItems) {
|
|
5195
|
-
if (item.id.startsWith("insight_")) {
|
|
5196
|
-
const isCritical = item.tone === "negative";
|
|
5197
|
-
const changeType = isCritical ? PortfolioChangeTypes["insight-critical"] : PortfolioChangeTypes["insight-high"];
|
|
5198
|
-
rows.push({
|
|
5199
|
-
id: `${projectSlug}:${changeType}:${item.id}`,
|
|
5200
|
-
projectName,
|
|
5201
|
-
projectSlug,
|
|
5202
|
-
changeType,
|
|
5203
|
-
tone: item.tone,
|
|
5204
|
-
title: item.title,
|
|
5205
|
-
detail: item.detail,
|
|
5206
|
-
occurredAt,
|
|
5207
|
-
href,
|
|
5208
|
-
actionLabel: isCritical ? "Critical" : "High",
|
|
5209
|
-
comparable
|
|
5210
|
-
});
|
|
5211
|
-
} else if (item.id === "stale_visibility") {
|
|
5212
|
-
rows.push({
|
|
5213
|
-
id: `${projectSlug}:${PortfolioChangeTypes["stale-visibility"]}:${runId}`,
|
|
5214
|
-
projectName,
|
|
5215
|
-
projectSlug,
|
|
5216
|
-
changeType: PortfolioChangeTypes["stale-visibility"],
|
|
5217
|
-
tone: "caution",
|
|
5218
|
-
title: `${projectName} visibility data is stale`,
|
|
5219
|
-
detail: "Integration syncs have run since the last sweep.",
|
|
5220
|
-
occurredAt,
|
|
5221
|
-
href,
|
|
5222
|
-
actionLabel: "Re-sweep",
|
|
5223
|
-
comparable
|
|
5224
|
-
});
|
|
5225
|
-
}
|
|
5226
|
-
}
|
|
5227
|
-
return rows;
|
|
5228
|
-
}
|
|
5229
|
-
function resolveEmptyState(projectCount, comparableProjectCount) {
|
|
5230
|
-
if (comparableProjectCount === 0) {
|
|
5231
|
-
return {
|
|
5232
|
-
kind: "awaiting-second-sweep",
|
|
5233
|
-
title: "No changes to compare yet",
|
|
5234
|
-
detail: "Visibility movement appears after a second sweep."
|
|
5235
|
-
};
|
|
5236
|
-
}
|
|
5237
|
-
return {
|
|
5238
|
-
kind: "all-clear",
|
|
5239
|
-
title: "No changes since the last sweep",
|
|
5240
|
-
detail: `All ${projectCount} project${projectCount === 1 ? "" : "s"} held their mention and citation coverage.`
|
|
5241
|
-
};
|
|
5242
|
-
}
|
|
5243
|
-
function buildPortfolioChangeFeed(inputs, _nowIso) {
|
|
5244
|
-
const all = [];
|
|
5245
|
-
let comparableProjectCount = 0;
|
|
5246
|
-
let firstSweepProjectCount = 0;
|
|
5247
|
-
for (const input of inputs) {
|
|
5248
|
-
if (input.latestRun) {
|
|
5249
|
-
if (input.movementComparison.comparable) comparableProjectCount += 1;
|
|
5250
|
-
if (!input.movementComparison.hasPreviousRun) firstSweepProjectCount += 1;
|
|
5251
|
-
}
|
|
5252
|
-
all.push(...buildProjectChanges(input));
|
|
5253
|
-
}
|
|
5254
|
-
const byId = /* @__PURE__ */ new Map();
|
|
5255
|
-
for (const row of all) {
|
|
5256
|
-
if (!byId.has(row.id)) byId.set(row.id, row);
|
|
5257
|
-
}
|
|
5258
|
-
const deduped = [...byId.values()];
|
|
5259
|
-
deduped.sort((a, b) => {
|
|
5260
|
-
if (a.occurredAt !== b.occurredAt) return a.occurredAt < b.occurredAt ? 1 : -1;
|
|
5261
|
-
const severity = TONE_SEVERITY[a.tone] - TONE_SEVERITY[b.tone];
|
|
5262
|
-
if (severity !== 0) return severity;
|
|
5263
|
-
if (a.projectName !== b.projectName) return a.projectName < b.projectName ? -1 : 1;
|
|
5264
|
-
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
|
|
5265
|
-
});
|
|
5266
|
-
const changeFeedTotal = deduped.length;
|
|
5267
|
-
const changeFeed = deduped.slice(0, PORTFOLIO_CHANGE_FEED_LIMIT);
|
|
5268
|
-
const feedEmptyState = changeFeedTotal === 0 ? resolveEmptyState(inputs.length, comparableProjectCount) : null;
|
|
5269
|
-
return {
|
|
5270
|
-
changeFeed,
|
|
5271
|
-
changeFeedTotal,
|
|
5272
|
-
feedEmptyState,
|
|
5273
|
-
comparableProjectCount,
|
|
5274
|
-
firstSweepProjectCount
|
|
5275
|
-
};
|
|
5276
|
-
}
|
|
5277
|
-
|
|
5278
5048
|
// ../intelligence/src/provider-trends.ts
|
|
5279
5049
|
function buildProviderTrends(runs2, snapshotsByRunId, limit = 12) {
|
|
5280
5050
|
const recent = [...runs2].sort((a, b) => b.createdAt.localeCompare(a.createdAt)).slice(0, limit).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
@@ -13337,9 +13107,8 @@ async function visibilityStatsRoutes(app) {
|
|
|
13337
13107
|
}
|
|
13338
13108
|
|
|
13339
13109
|
// ../api-routes/src/composites.ts
|
|
13340
|
-
import { eq as eq17, and as and12,
|
|
13110
|
+
import { eq as eq17, and as and12, desc as desc9, sql as sql7, like as like2, or as or4, inArray as inArray9 } from "drizzle-orm";
|
|
13341
13111
|
var TOP_INSIGHT_LIMIT = 5;
|
|
13342
|
-
var PORTFOLIO_RECENT_RUNS_LIMIT = 8;
|
|
13343
13112
|
var SEARCH_HIT_HARD_LIMIT = 50;
|
|
13344
13113
|
var SEARCH_SNIPPET_RADIUS = 80;
|
|
13345
13114
|
var INTEGRATION_SYNC_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -13356,14 +13125,6 @@ async function compositeRoutes(app) {
|
|
|
13356
13125
|
const project = resolveProject(app.db, request.params.name);
|
|
13357
13126
|
const filterLocation = (request.query.location ?? "").trim() || null;
|
|
13358
13127
|
const sinceIso = parseSinceFilter(request.query.since);
|
|
13359
|
-
return reply.send(computeProjectOverview(project, { filterLocation, sinceIso }));
|
|
13360
|
-
});
|
|
13361
|
-
app.get("/portfolio", async (_request, reply) => {
|
|
13362
|
-
return reply.send(buildPortfolioOverview());
|
|
13363
|
-
});
|
|
13364
|
-
function computeProjectOverview(project, opts = {}) {
|
|
13365
|
-
const filterLocation = opts.filterLocation ?? null;
|
|
13366
|
-
const sinceIso = opts.sinceIso ?? null;
|
|
13367
13128
|
const allRunsRaw = app.db.select().from(runs).where(and12(eq17(runs.projectId, project.id), notProbeRun())).orderBy(desc9(runs.createdAt), desc9(runs.id)).all();
|
|
13368
13129
|
const allRuns = allRunsRaw.filter((r) => runMatchesFilters(r, filterLocation, sinceIso));
|
|
13369
13130
|
const totalRuns = allRuns.length;
|
|
@@ -13496,111 +13257,8 @@ async function compositeRoutes(app) {
|
|
|
13496
13257
|
dateRangeLabel: "All time",
|
|
13497
13258
|
contextLabel: `${project.country} / ${project.language.toUpperCase()}`
|
|
13498
13259
|
};
|
|
13499
|
-
return result;
|
|
13500
|
-
}
|
|
13501
|
-
function buildPortfolioOverview() {
|
|
13502
|
-
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13503
|
-
const projectRows = app.db.select().from(projects).orderBy(asc2(projects.name)).all();
|
|
13504
|
-
const trackedCountRows = app.db.select({ projectId: queries.projectId, total: sql7`COUNT(*)` }).from(queries).groupBy(queries.projectId).all();
|
|
13505
|
-
const trackedCountByProject = new Map(trackedCountRows.map((r) => [r.projectId, Number(r.total)]));
|
|
13506
|
-
const lastSweepRow = app.db.select({ createdAt: runs.createdAt, finishedAt: runs.finishedAt }).from(runs).where(and12(
|
|
13507
|
-
eq17(runs.kind, RunKinds["answer-visibility"]),
|
|
13508
|
-
notProbeRun(),
|
|
13509
|
-
inArray9(runs.status, [RunStatuses.completed, RunStatuses.partial])
|
|
13510
|
-
)).orderBy(desc9(runs.createdAt), desc9(runs.id)).limit(1).get();
|
|
13511
|
-
const lastSweepAt = lastSweepRow ? lastSweepRow.finishedAt ?? lastSweepRow.createdAt : null;
|
|
13512
|
-
const feedInputs = [];
|
|
13513
|
-
const projectRowDtos = [];
|
|
13514
|
-
const runHistoryById = /* @__PURE__ */ new Map();
|
|
13515
|
-
for (const projectRow of projectRows) {
|
|
13516
|
-
const overview = computeProjectOverview(projectRow);
|
|
13517
|
-
for (const point of overview.runHistory) runHistoryById.set(point.runId, point);
|
|
13518
|
-
const latestVisRunRow = app.db.select().from(runs).where(and12(
|
|
13519
|
-
eq17(runs.projectId, projectRow.id),
|
|
13520
|
-
eq17(runs.kind, RunKinds["answer-visibility"]),
|
|
13521
|
-
notProbeRun()
|
|
13522
|
-
)).orderBy(desc9(runs.createdAt), desc9(runs.id)).limit(1).get();
|
|
13523
|
-
const projectName = projectRow.displayName || projectRow.name;
|
|
13524
|
-
feedInputs.push({
|
|
13525
|
-
projectName,
|
|
13526
|
-
projectSlug: projectRow.name,
|
|
13527
|
-
citationMovement: overview.citationMovement,
|
|
13528
|
-
mentionMovement: overview.mentionMovement,
|
|
13529
|
-
movementComparison: overview.movementComparison,
|
|
13530
|
-
attentionItems: overview.attentionItems,
|
|
13531
|
-
latestRun: latestVisRunRow ? {
|
|
13532
|
-
runId: latestVisRunRow.id,
|
|
13533
|
-
status: latestVisRunRow.status,
|
|
13534
|
-
occurredAt: latestVisRunRow.finishedAt ?? latestVisRunRow.createdAt,
|
|
13535
|
-
error: parseRunError(latestVisRunRow.error)
|
|
13536
|
-
} : null,
|
|
13537
|
-
trackedQueryCount: trackedCountByProject.get(projectRow.id) ?? 0,
|
|
13538
|
-
projectCreatedAt: projectRow.createdAt
|
|
13539
|
-
});
|
|
13540
|
-
const mention = overview.scores.mention;
|
|
13541
|
-
projectRowDtos.push({
|
|
13542
|
-
projectSlug: projectRow.name,
|
|
13543
|
-
projectName,
|
|
13544
|
-
canonicalDomain: projectRow.canonicalDomain,
|
|
13545
|
-
mentionScore: mention.progress ?? 0,
|
|
13546
|
-
mentionTone: mention.tone,
|
|
13547
|
-
mentionedOfTotal: { mentioned: overview.queryCounts.mentionedQueries, total: overview.queryCounts.totalQueries },
|
|
13548
|
-
citedOfTotal: { cited: overview.queryCounts.citedQueries, total: overview.queryCounts.totalQueries },
|
|
13549
|
-
mentionDelta: {
|
|
13550
|
-
gained: overview.mentionMovement.gained,
|
|
13551
|
-
lost: overview.mentionMovement.lost,
|
|
13552
|
-
comparable: overview.movementComparison.comparable
|
|
13553
|
-
},
|
|
13554
|
-
citationDelta: {
|
|
13555
|
-
gained: overview.citationMovement.gained,
|
|
13556
|
-
lost: overview.citationMovement.lost,
|
|
13557
|
-
comparable: overview.movementComparison.comparable
|
|
13558
|
-
},
|
|
13559
|
-
competitorPressureLabel: overview.scores.competitorPressure.value,
|
|
13560
|
-
mentionTrend: mention.trend,
|
|
13561
|
-
lastRunAt: latestVisRunRow ? latestVisRunRow.finishedAt ?? latestVisRunRow.createdAt : null,
|
|
13562
|
-
hasEverRun: latestVisRunRow != null
|
|
13563
|
-
});
|
|
13564
|
-
}
|
|
13565
|
-
const feed = buildPortfolioChangeFeed(feedInputs, generatedAt);
|
|
13566
|
-
const projectById = new Map(projectRows.map((p) => [p.id, p]));
|
|
13567
|
-
const recentRunRows = app.db.select().from(runs).where(and12(eq17(runs.kind, RunKinds["answer-visibility"]), notProbeRun())).orderBy(desc9(runs.createdAt), desc9(runs.id)).limit(PORTFOLIO_RECENT_RUNS_LIMIT).all();
|
|
13568
|
-
const recentRuns = [];
|
|
13569
|
-
for (const run of recentRunRows) {
|
|
13570
|
-
const projectRow = projectById.get(run.projectId);
|
|
13571
|
-
if (!projectRow) continue;
|
|
13572
|
-
const point = runHistoryById.get(run.id);
|
|
13573
|
-
const countable = run.status === RunStatuses.completed || run.status === RunStatuses.partial;
|
|
13574
|
-
const error = parseRunError(run.error);
|
|
13575
|
-
recentRuns.push({
|
|
13576
|
-
runId: run.id,
|
|
13577
|
-
projectName: projectRow.displayName || projectRow.name,
|
|
13578
|
-
projectSlug: projectRow.name,
|
|
13579
|
-
kindLabel: "Answer visibility sweep",
|
|
13580
|
-
status: run.status,
|
|
13581
|
-
createdAt: run.createdAt,
|
|
13582
|
-
startedAt: run.startedAt ?? null,
|
|
13583
|
-
finishedAt: run.finishedAt ?? null,
|
|
13584
|
-
durationMs: run.startedAt && run.finishedAt ? new Date(run.finishedAt).getTime() - new Date(run.startedAt).getTime() : null,
|
|
13585
|
-
mentionedCount: countable && point ? point.mentionedCount : null,
|
|
13586
|
-
citedCount: countable && point ? point.citedCount : null,
|
|
13587
|
-
totalCount: countable && point ? point.totalCount : null,
|
|
13588
|
-
errorSummary: error ? formatRunErrorOneLine(error) : null
|
|
13589
|
-
});
|
|
13590
|
-
}
|
|
13591
|
-
return {
|
|
13592
|
-
generatedAt,
|
|
13593
|
-
lastSweepAt,
|
|
13594
|
-
projectCount: projectRows.length,
|
|
13595
|
-
comparableProjectCount: feed.comparableProjectCount,
|
|
13596
|
-
firstSweepProjectCount: feed.firstSweepProjectCount,
|
|
13597
|
-
changeFeed: feed.changeFeed,
|
|
13598
|
-
changeFeedTotal: feed.changeFeedTotal,
|
|
13599
|
-
feedEmptyState: feed.feedEmptyState,
|
|
13600
|
-
recentRuns,
|
|
13601
|
-
projects: projectRowDtos
|
|
13602
|
-
};
|
|
13603
|
-
}
|
|
13260
|
+
return reply.send(result);
|
|
13261
|
+
});
|
|
13604
13262
|
app.get("/projects/:name/search", async (request, reply) => {
|
|
13605
13263
|
const project = resolveProject(app.db, request.params.name);
|
|
13606
13264
|
const rawQuery = (request.query.q ?? "").trim();
|
|
@@ -14227,7 +13885,6 @@ var SCHEMA_TABLE = {
|
|
|
14227
13885
|
LatestProjectRunDto: latestProjectRunDtoSchema,
|
|
14228
13886
|
LocationContext: locationContextSchema,
|
|
14229
13887
|
NotificationDto: notificationDtoSchema,
|
|
14230
|
-
PortfolioDto: portfolioDtoSchema,
|
|
14231
13888
|
ProjectDto: projectDtoSchema,
|
|
14232
13889
|
ProjectOverviewDto: projectOverviewDtoSchema,
|
|
14233
13890
|
ProjectReportDto: projectReportDtoSchema,
|
|
@@ -17482,17 +17139,6 @@ var routeCatalog = [
|
|
|
17482
17139
|
404: errorResponse("Project not found.")
|
|
17483
17140
|
}
|
|
17484
17141
|
},
|
|
17485
|
-
{
|
|
17486
|
-
method: "get",
|
|
17487
|
-
path: "/api/v1/portfolio",
|
|
17488
|
-
summary: "Cross-project portfolio: what changed, recent runs, project state",
|
|
17489
|
-
description: 'One call for the dashboard Portfolio page and `canonry portfolio`. Returns a server-ordered "what changed" feed (citation/mention gains and losses over each project\'s comparable basket, failed sweeps, critical/high insight echoes, stale-visibility, query-set changes, and never-run projects \u2014 recency then severity), a timestamped recent-runs log with independent mention and cited result counts, and a per-project state table. Probe runs are excluded. `generatedAt` is the freshness anchor for every relative timestamp.',
|
|
17490
|
-
tags: ["intelligence"],
|
|
17491
|
-
parameters: [],
|
|
17492
|
-
responses: {
|
|
17493
|
-
200: jsonResponse("Portfolio overview returned.", "PortfolioDto")
|
|
17494
|
-
}
|
|
17495
|
-
},
|
|
17496
17142
|
{
|
|
17497
17143
|
method: "get",
|
|
17498
17144
|
path: "/api/v1/projects/{name}/overview",
|
|
@@ -21888,7 +21534,7 @@ async function googleRoutes(app, opts) {
|
|
|
21888
21534
|
|
|
21889
21535
|
// ../api-routes/src/ads.ts
|
|
21890
21536
|
import crypto19 from "crypto";
|
|
21891
|
-
import { eq as eq22, and as and15, asc as
|
|
21537
|
+
import { eq as eq22, and as and15, asc as asc2, gte as gte3, lte as lte2, inArray as inArray11 } from "drizzle-orm";
|
|
21892
21538
|
function statusDto(row) {
|
|
21893
21539
|
if (!row) return { connected: false };
|
|
21894
21540
|
return {
|
|
@@ -22089,7 +21735,7 @@ async function adsRoutes(app, opts) {
|
|
|
22089
21735
|
if (entityId) conditions.push(eq22(adsInsightsDaily.entityId, entityId));
|
|
22090
21736
|
if (from) conditions.push(gte3(adsInsightsDaily.date, from));
|
|
22091
21737
|
if (to) conditions.push(lte2(adsInsightsDaily.date, to));
|
|
22092
|
-
const rows = app.db.select().from(adsInsightsDaily).where(and15(...conditions)).orderBy(
|
|
21738
|
+
const rows = app.db.select().from(adsInsightsDaily).where(and15(...conditions)).orderBy(asc2(adsInsightsDaily.date)).all();
|
|
22093
21739
|
const dtoRows = rows.map((row) => ({
|
|
22094
21740
|
level: row.level,
|
|
22095
21741
|
entityId: row.entityId,
|
|
@@ -25498,7 +25144,7 @@ async function wordpressRoutes(app, opts) {
|
|
|
25498
25144
|
|
|
25499
25145
|
// ../api-routes/src/backlinks.ts
|
|
25500
25146
|
import crypto23 from "crypto";
|
|
25501
|
-
import { and as and20, asc as
|
|
25147
|
+
import { and as and20, asc as asc3, desc as desc14, eq as eq26, sql as sql10 } from "drizzle-orm";
|
|
25502
25148
|
|
|
25503
25149
|
// ../integration-commoncrawl/src/constants.ts
|
|
25504
25150
|
import os2 from "os";
|
|
@@ -26257,7 +25903,7 @@ async function backlinksRoutes(app, opts) {
|
|
|
26257
25903
|
async (request, reply) => {
|
|
26258
25904
|
const project = resolveProject(app.db, request.params.name);
|
|
26259
25905
|
const source = parseSourceParam(request.query.source);
|
|
26260
|
-
const rows = app.db.select().from(backlinkSummaries).where(and20(eq26(backlinkSummaries.projectId, project.id), eq26(backlinkSummaries.source, source))).orderBy(
|
|
25906
|
+
const rows = app.db.select().from(backlinkSummaries).where(and20(eq26(backlinkSummaries.projectId, project.id), eq26(backlinkSummaries.source, source))).orderBy(asc3(backlinkSummaries.queriedAt)).all();
|
|
26261
25907
|
const response = rows.map((r) => ({
|
|
26262
25908
|
release: r.release,
|
|
26263
25909
|
totalLinkingDomains: r.totalLinkingDomains,
|
|
@@ -34222,7 +33868,7 @@ function dedupeStrings(input) {
|
|
|
34222
33868
|
|
|
34223
33869
|
// ../api-routes/src/technical-aeo.ts
|
|
34224
33870
|
import crypto29 from "crypto";
|
|
34225
|
-
import { and as and26, asc as
|
|
33871
|
+
import { and as and26, asc as asc4, count, desc as desc17, eq as eq36, inArray as inArray13 } from "drizzle-orm";
|
|
34226
33872
|
var SURFACEABLE_STATUSES = [RunStatuses.completed, RunStatuses.partial];
|
|
34227
33873
|
function emptyScore(projectName) {
|
|
34228
33874
|
return {
|
|
@@ -34306,7 +33952,7 @@ async function technicalAeoRoutes(app, opts) {
|
|
|
34306
33952
|
const total = totalRow?.value ?? 0;
|
|
34307
33953
|
const limit = parsePositiveInt(request.query.limit, 100, 500);
|
|
34308
33954
|
const offset = parsePositiveInt(request.query.offset, 0, Number.MAX_SAFE_INTEGER);
|
|
34309
|
-
const orderBy = request.query.sort === "score-desc" ? desc17(siteAuditPages.overallScore) : request.query.sort === "url" ?
|
|
33955
|
+
const orderBy = request.query.sort === "score-desc" ? desc17(siteAuditPages.overallScore) : request.query.sort === "url" ? asc4(siteAuditPages.url) : asc4(siteAuditPages.overallScore);
|
|
34310
33956
|
const rows = app.db.select().from(siteAuditPages).where(where).orderBy(orderBy).limit(limit).offset(offset).all();
|
|
34311
33957
|
const pages = rows.map((row) => ({
|
|
34312
33958
|
url: row.url,
|
|
@@ -35241,7 +34887,7 @@ var IntelligenceService = class {
|
|
|
35241
34887
|
// Backfill must not replay probe runs as if they were real sweeps.
|
|
35242
34888
|
ne5(runs.trigger, RunTriggers.probe)
|
|
35243
34889
|
)
|
|
35244
|
-
).orderBy(
|
|
34890
|
+
).orderBy(asc5(runs.finishedAt)).all();
|
|
35245
34891
|
let startIdx = 0;
|
|
35246
34892
|
let endIdx = allRuns.length;
|
|
35247
34893
|
if (opts?.fromRunId) {
|
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-ALJSES3X.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-IDI6LMYL.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-YBIT5O62.js";
|
|
56
56
|
import {
|
|
57
57
|
BacklinkSources,
|
|
58
58
|
CcReleaseSyncStatuses,
|
|
@@ -72,14 +72,13 @@ import {
|
|
|
72
72
|
formatIsoDate,
|
|
73
73
|
formatMicros,
|
|
74
74
|
formatRatio,
|
|
75
|
-
formatRelativeTime,
|
|
76
75
|
formatRunErrorOneLine,
|
|
77
76
|
normalizeProjectAliases,
|
|
78
77
|
notificationEventSchema,
|
|
79
78
|
providerQuotaPolicySchema,
|
|
80
79
|
resolveProviderInput,
|
|
81
80
|
winnabilityClassSchema
|
|
82
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-JF7EXHGA.js";
|
|
83
82
|
|
|
84
83
|
// src/cli.ts
|
|
85
84
|
import { pathToFileURL } from "url";
|
|
@@ -9595,103 +9594,6 @@ function pct2(value) {
|
|
|
9595
9594
|
return `${(value * 100).toFixed(1)}%`;
|
|
9596
9595
|
}
|
|
9597
9596
|
|
|
9598
|
-
// src/commands/portfolio.ts
|
|
9599
|
-
async function showPortfolio(opts) {
|
|
9600
|
-
const client = createApiClient();
|
|
9601
|
-
const portfolio = await client.getPortfolio();
|
|
9602
|
-
if (isMachineFormat(opts.format)) {
|
|
9603
|
-
if (opts.format === "jsonl") {
|
|
9604
|
-
emitJsonl(portfolio.changeFeed);
|
|
9605
|
-
return;
|
|
9606
|
-
}
|
|
9607
|
-
console.log(JSON.stringify(portfolio, null, 2));
|
|
9608
|
-
return;
|
|
9609
|
-
}
|
|
9610
|
-
renderHuman2(portfolio);
|
|
9611
|
-
}
|
|
9612
|
-
function renderHuman2(p) {
|
|
9613
|
-
const now = p.generatedAt;
|
|
9614
|
-
const sweep = p.lastSweepAt ? formatRelativeTime(p.lastSweepAt, now) : "never";
|
|
9615
|
-
console.log(`
|
|
9616
|
-
Portfolio \xB7 ${p.projectCount} project${p.projectCount === 1 ? "" : "s"} \xB7 last sweep ${sweep}
|
|
9617
|
-
`);
|
|
9618
|
-
const moreLabel = p.changeFeedTotal > p.changeFeed.length ? ` (showing ${p.changeFeed.length} of ${p.changeFeedTotal})` : "";
|
|
9619
|
-
console.log(`What changed${moreLabel}:`);
|
|
9620
|
-
if (p.changeFeed.length === 0) {
|
|
9621
|
-
const empty = p.feedEmptyState;
|
|
9622
|
-
console.log(` ${empty ? `${empty.title} \u2014 ${empty.detail}` : "No changes."}`);
|
|
9623
|
-
} else {
|
|
9624
|
-
for (const c of p.changeFeed) {
|
|
9625
|
-
console.log(` ${changeGlyph(c.tone)} ${c.title} (${formatRelativeTime(c.occurredAt, now)})`);
|
|
9626
|
-
if (c.detail) console.log(` ${c.detail}`);
|
|
9627
|
-
}
|
|
9628
|
-
}
|
|
9629
|
-
console.log("\nRecent runs (M mentioned in answer \xB7 C cited in sources):");
|
|
9630
|
-
if (p.recentRuns.length === 0) {
|
|
9631
|
-
console.log(" Run history appears here after the first sweep.");
|
|
9632
|
-
} else {
|
|
9633
|
-
for (const r of p.recentRuns) {
|
|
9634
|
-
console.log(
|
|
9635
|
-
` ${pad(r.projectName, 20)} ${pad(runResult(r), 20)} ${pad(runWhen(r, now), 20)} ${runDuration(r)}`
|
|
9636
|
-
);
|
|
9637
|
-
}
|
|
9638
|
-
}
|
|
9639
|
-
console.log("\nProjects:");
|
|
9640
|
-
for (const proj of p.projects) {
|
|
9641
|
-
const mentioned = `M ${proj.mentionedOfTotal.mentioned}/${proj.mentionedOfTotal.total}`;
|
|
9642
|
-
const cited = `C ${proj.citedOfTotal.cited}/${proj.citedOfTotal.total}`;
|
|
9643
|
-
console.log(
|
|
9644
|
-
` ${pad(proj.projectSlug, 20)} ${String(proj.mentionScore).padStart(3)} ${pad(mentioned, 10)} ${pad(cited, 10)} ${projectDelta(proj)}`
|
|
9645
|
-
);
|
|
9646
|
-
}
|
|
9647
|
-
console.log();
|
|
9648
|
-
}
|
|
9649
|
-
function changeGlyph(tone) {
|
|
9650
|
-
switch (tone) {
|
|
9651
|
-
case "negative":
|
|
9652
|
-
return "v";
|
|
9653
|
-
case "positive":
|
|
9654
|
-
return "^";
|
|
9655
|
-
case "caution":
|
|
9656
|
-
return "!";
|
|
9657
|
-
case "neutral":
|
|
9658
|
-
return ".";
|
|
9659
|
-
}
|
|
9660
|
-
}
|
|
9661
|
-
function runResult(r) {
|
|
9662
|
-
if (r.status === "failed") return r.errorSummary ?? "failed";
|
|
9663
|
-
if (r.mentionedCount == null || r.citedCount == null || r.totalCount == null) return "\u2014";
|
|
9664
|
-
return `M ${r.mentionedCount}/${r.totalCount} \xB7 C ${r.citedCount}/${r.totalCount}`;
|
|
9665
|
-
}
|
|
9666
|
-
function runWhen(r, now) {
|
|
9667
|
-
const ts = r.finishedAt ?? r.startedAt ?? r.createdAt;
|
|
9668
|
-
const rel = formatRelativeTime(ts, now);
|
|
9669
|
-
if (r.status === "running") return `started ${rel}`;
|
|
9670
|
-
if (r.status === "queued") return `queued ${rel}`;
|
|
9671
|
-
return `finished ${rel}`;
|
|
9672
|
-
}
|
|
9673
|
-
function runDuration(r) {
|
|
9674
|
-
if (r.durationMs == null) {
|
|
9675
|
-
return r.status === "running" ? "running" : r.status === "queued" ? "waiting" : "\u2014";
|
|
9676
|
-
}
|
|
9677
|
-
const seconds = Math.floor(r.durationMs / 1e3);
|
|
9678
|
-
if (seconds < 1) return "<1s";
|
|
9679
|
-
if (seconds < 60) return `${seconds}s`;
|
|
9680
|
-
return `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
|
|
9681
|
-
}
|
|
9682
|
-
function projectDelta(proj) {
|
|
9683
|
-
if (!proj.hasEverRun) return "never run";
|
|
9684
|
-
const parts = [];
|
|
9685
|
-
if (proj.mentionDelta.gained > 0) parts.push(`+${proj.mentionDelta.gained}`);
|
|
9686
|
-
if (proj.mentionDelta.lost > 0) parts.push(`-${proj.mentionDelta.lost}`);
|
|
9687
|
-
if (parts.length === 0) return proj.mentionDelta.comparable ? "no change" : "first sweep";
|
|
9688
|
-
return `${parts.join(" ")} mentioned${proj.mentionDelta.comparable ? "" : "*"}`;
|
|
9689
|
-
}
|
|
9690
|
-
function pad(value, width) {
|
|
9691
|
-
if (value.length >= width) return `${value.slice(0, width - 1)} `;
|
|
9692
|
-
return value.padEnd(width);
|
|
9693
|
-
}
|
|
9694
|
-
|
|
9695
9597
|
// src/commands/search.ts
|
|
9696
9598
|
async function searchProject(project, opts) {
|
|
9697
9599
|
const client = createApiClient();
|
|
@@ -9891,14 +9793,6 @@ var INTELLIGENCE_CLI_COMMANDS = [
|
|
|
9891
9793
|
await showOverview(project, { format: input.format, location, since });
|
|
9892
9794
|
}
|
|
9893
9795
|
},
|
|
9894
|
-
{
|
|
9895
|
-
path: ["portfolio"],
|
|
9896
|
-
usage: "canonry portfolio [--format json|jsonl]",
|
|
9897
|
-
options: {},
|
|
9898
|
-
run: async (input) => {
|
|
9899
|
-
await showPortfolio({ format: input.format });
|
|
9900
|
-
}
|
|
9901
|
-
},
|
|
9902
9796
|
{
|
|
9903
9797
|
path: ["search"],
|
|
9904
9798
|
usage: "canonry search <project> <query> [--limit <n>] [--format json]",
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createServer
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-ALJSES3X.js";
|
|
4
4
|
import {
|
|
5
5
|
loadConfig
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-IDI6LMYL.js";
|
|
7
|
+
import "./chunk-YBIT5O62.js";
|
|
8
|
+
import "./chunk-JF7EXHGA.js";
|
|
9
9
|
export {
|
|
10
10
|
createServer,
|
|
11
11
|
loadConfig
|