@ainyc/canonry 4.50.0 → 4.51.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/assets/BacklinksPage-DIZCcqsP.js +1 -0
- package/assets/assets/ChartPrimitives-9Kx3gzQL.js +1 -0
- package/assets/assets/ProjectPage-R2cxJb5Y.js +6 -0
- package/assets/assets/RunRow-DqezNIUy.js +1 -0
- package/assets/assets/RunsPage-CfvTJ9Ny.js +1 -0
- package/assets/assets/SettingsPage-HfMGIa5v.js +1 -0
- package/assets/assets/TrafficPage-DV_Dvpl3.js +1 -0
- package/assets/assets/TrafficSourceDetailPage-lefreKBO.js +1 -0
- package/assets/assets/arrow-left-DpxpMUNt.js +1 -0
- package/assets/assets/index-DKBPD33e.js +210 -0
- package/assets/assets/{index-DOP3oQmw.css → index-DeGyEwik.css} +1 -1
- package/assets/assets/server-traffic-Bm8iKtXK.js +1 -0
- package/assets/assets/trash-2-CnBiLbiZ.js +1 -0
- package/assets/assets/{vendor-markdown-DN2199pt.js → vendor-markdown-DK7fbRNb.js} +1 -1
- package/assets/assets/{vendor-radix-Bvy4KXTI.js → vendor-radix-B57xfQbP.js} +1 -1
- package/assets/assets/{vendor-recharts-DPeiXMwW.js → vendor-recharts-DWvKDyBF.js} +1 -1
- package/assets/assets/vendor-tanstack-Dq7p98wZ.js +1 -0
- package/assets/index.html +6 -6
- package/dist/{chunk-QIG3TKL4.js → chunk-2ARCCG5E.js} +72 -1
- package/dist/{chunk-M4USKXJ4.js → chunk-DLDLDWH4.js} +128 -40
- package/dist/{chunk-MYDJ25GO.js → chunk-GGXU5VKI.js} +111 -77
- package/dist/{chunk-YVP5CTSV.js → chunk-JOKPYAEL.js} +2178 -1624
- package/dist/cli.js +6 -6
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-TY7IPRST.js → intelligence-service-XMZEWLCW.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +9 -9
- package/assets/assets/index-DVK0M62U.js +0 -214
- package/assets/assets/vendor-tanstack-DPXTJtWt.js +0 -1
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
categoryLabel,
|
|
11
11
|
determineAnswerMentioned,
|
|
12
12
|
normalizeProjectDomain
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-2ARCCG5E.js";
|
|
14
14
|
|
|
15
15
|
// src/intelligence-service.ts
|
|
16
16
|
import { eq, desc, asc, and, ne, or, inArray } from "drizzle-orm";
|
|
@@ -37,6 +37,7 @@ __export(schema_exports, {
|
|
|
37
37
|
bingUrlInspections: () => bingUrlInspections,
|
|
38
38
|
ccReleaseSyncs: () => ccReleaseSyncs,
|
|
39
39
|
competitors: () => competitors,
|
|
40
|
+
contentTargetDismissals: () => contentTargetDismissals,
|
|
40
41
|
crawlerEventsHourly: () => crawlerEventsHourly,
|
|
41
42
|
discoveryProbes: () => discoveryProbes,
|
|
42
43
|
discoverySessions: () => discoverySessions,
|
|
@@ -58,6 +59,7 @@ __export(schema_exports, {
|
|
|
58
59
|
queries: () => queries,
|
|
59
60
|
querySnapshots: () => querySnapshots,
|
|
60
61
|
rawEventSamples: () => rawEventSamples,
|
|
62
|
+
recommendationExplanations: () => recommendationExplanations,
|
|
61
63
|
runs: () => runs,
|
|
62
64
|
schedules: () => schedules,
|
|
63
65
|
trafficSources: () => trafficSources,
|
|
@@ -69,16 +71,16 @@ var projects = sqliteTable("projects", {
|
|
|
69
71
|
name: text("name").notNull().unique(),
|
|
70
72
|
displayName: text("display_name").notNull(),
|
|
71
73
|
canonicalDomain: text("canonical_domain").notNull(),
|
|
72
|
-
ownedDomains: text("owned_domains").notNull().default(
|
|
73
|
-
aliases: text("aliases").notNull().default(
|
|
74
|
+
ownedDomains: text("owned_domains", { mode: "json" }).$type().notNull().default([]),
|
|
75
|
+
aliases: text("aliases", { mode: "json" }).$type().notNull().default([]),
|
|
74
76
|
country: text("country").notNull(),
|
|
75
77
|
language: text("language").notNull(),
|
|
76
|
-
tags: text("tags").notNull().default(
|
|
77
|
-
labels: text("labels").notNull().default(
|
|
78
|
-
providers: text("providers").notNull().default(
|
|
79
|
-
locations: text("locations").notNull().default(
|
|
78
|
+
tags: text("tags", { mode: "json" }).$type().notNull().default([]),
|
|
79
|
+
labels: text("labels", { mode: "json" }).$type().notNull().default({}),
|
|
80
|
+
providers: text("providers", { mode: "json" }).$type().notNull().default([]),
|
|
81
|
+
locations: text("locations", { mode: "json" }).$type().notNull().default([]),
|
|
80
82
|
defaultLocation: text("default_location"),
|
|
81
|
-
autoExtractBacklinks: integer("auto_extract_backlinks").notNull().default(
|
|
83
|
+
autoExtractBacklinks: integer("auto_extract_backlinks", { mode: "boolean" }).notNull().default(false),
|
|
82
84
|
configSource: text("config_source").notNull().default("cli"),
|
|
83
85
|
configRevision: integer("config_revision").notNull().default(1),
|
|
84
86
|
icpDescription: text("icp_description"),
|
|
@@ -112,7 +114,7 @@ var runs = sqliteTable("runs", {
|
|
|
112
114
|
status: text("status").notNull().default("queued"),
|
|
113
115
|
trigger: text("trigger").notNull().default("manual"),
|
|
114
116
|
location: text("location"),
|
|
115
|
-
queries: text("queries"),
|
|
117
|
+
queries: text("queries", { mode: "json" }).$type(),
|
|
116
118
|
sourceId: text("source_id"),
|
|
117
119
|
startedAt: text("started_at"),
|
|
118
120
|
finishedAt: text("finished_at"),
|
|
@@ -139,9 +141,9 @@ var querySnapshots = sqliteTable("query_snapshots", {
|
|
|
139
141
|
citationState: text("citation_state").notNull(),
|
|
140
142
|
answerMentioned: integer("answer_mentioned", { mode: "boolean" }),
|
|
141
143
|
answerText: text("answer_text"),
|
|
142
|
-
citedDomains: text("cited_domains").notNull().default(
|
|
143
|
-
competitorOverlap: text("competitor_overlap").notNull().default(
|
|
144
|
-
recommendedCompetitors: text("recommended_competitors").notNull().default(
|
|
144
|
+
citedDomains: text("cited_domains", { mode: "json" }).$type().notNull().default([]),
|
|
145
|
+
competitorOverlap: text("competitor_overlap", { mode: "json" }).$type().notNull().default([]),
|
|
146
|
+
recommendedCompetitors: text("recommended_competitors", { mode: "json" }).$type().notNull().default([]),
|
|
145
147
|
location: text("location"),
|
|
146
148
|
screenshotPath: text("screenshot_path"),
|
|
147
149
|
rawResponse: text("raw_response"),
|
|
@@ -177,7 +179,7 @@ var apiKeys = sqliteTable("api_keys", {
|
|
|
177
179
|
name: text("name").notNull(),
|
|
178
180
|
keyHash: text("key_hash").notNull().unique(),
|
|
179
181
|
keyPrefix: text("key_prefix").notNull(),
|
|
180
|
-
scopes: text("scopes").notNull().default(
|
|
182
|
+
scopes: text("scopes", { mode: "json" }).$type().notNull().default(["*"]),
|
|
181
183
|
createdAt: text("created_at").notNull(),
|
|
182
184
|
lastUsedAt: text("last_used_at"),
|
|
183
185
|
revokedAt: text("revoked_at")
|
|
@@ -195,8 +197,8 @@ var schedules = sqliteTable("schedules", {
|
|
|
195
197
|
cronExpr: text("cron_expr").notNull(),
|
|
196
198
|
preset: text("preset"),
|
|
197
199
|
timezone: text("timezone").notNull().default("UTC"),
|
|
198
|
-
enabled: integer("enabled").notNull().default(
|
|
199
|
-
providers: text("providers").notNull().default(
|
|
200
|
+
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
|
|
201
|
+
providers: text("providers", { mode: "json" }).$type().notNull().default([]),
|
|
200
202
|
/** Optional traffic-source UUID for traffic-sync schedules. Null for other kinds. */
|
|
201
203
|
sourceId: text("source_id"),
|
|
202
204
|
lastRunAt: text("last_run_at"),
|
|
@@ -210,9 +212,9 @@ var notifications = sqliteTable("notifications", {
|
|
|
210
212
|
id: text("id").primaryKey(),
|
|
211
213
|
projectId: text("project_id").notNull().references(() => projects.id, { onDelete: "cascade" }),
|
|
212
214
|
channel: text("channel").notNull(),
|
|
213
|
-
config: text("config").notNull(),
|
|
215
|
+
config: text("config", { mode: "json" }).$type().notNull(),
|
|
214
216
|
webhookSecret: text("webhook_secret"),
|
|
215
|
-
enabled: integer("enabled").notNull().default(
|
|
217
|
+
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
|
|
216
218
|
createdAt: text("created_at").notNull(),
|
|
217
219
|
updatedAt: text("updated_at").notNull()
|
|
218
220
|
}, (table) => [
|
|
@@ -224,7 +226,7 @@ var googleConnections = sqliteTable("google_connections", {
|
|
|
224
226
|
connectionType: text("connection_type").notNull(),
|
|
225
227
|
propertyId: text("property_id"),
|
|
226
228
|
sitemapUrl: text("sitemap_url"),
|
|
227
|
-
scopes: text("scopes").notNull().default(
|
|
229
|
+
scopes: text("scopes", { mode: "json" }).$type().notNull().default([]),
|
|
228
230
|
createdAt: text("created_at").notNull(),
|
|
229
231
|
updatedAt: text("updated_at").notNull()
|
|
230
232
|
}, (table) => [
|
|
@@ -261,9 +263,9 @@ var gscUrlInspections = sqliteTable("gsc_url_inspections", {
|
|
|
261
263
|
robotsTxtState: text("robots_txt_state"),
|
|
262
264
|
crawlTime: text("crawl_time"),
|
|
263
265
|
lastCrawlResult: text("last_crawl_result"),
|
|
264
|
-
isMobileFriendly: integer("is_mobile_friendly"),
|
|
265
|
-
richResults: text("rich_results").notNull().default(
|
|
266
|
-
referringUrls: text("referring_urls").notNull().default(
|
|
266
|
+
isMobileFriendly: integer("is_mobile_friendly", { mode: "boolean" }),
|
|
267
|
+
richResults: text("rich_results", { mode: "json" }).$type().notNull().default([]),
|
|
268
|
+
referringUrls: text("referring_urls", { mode: "json" }).$type().notNull().default([]),
|
|
267
269
|
inspectedAt: text("inspected_at").notNull(),
|
|
268
270
|
createdAt: text("created_at").notNull()
|
|
269
271
|
}, (table) => [
|
|
@@ -278,7 +280,7 @@ var gscCoverageSnapshots = sqliteTable("gsc_coverage_snapshots", {
|
|
|
278
280
|
date: text("date").notNull(),
|
|
279
281
|
indexed: integer("indexed").notNull().default(0),
|
|
280
282
|
notIndexed: integer("not_indexed").notNull().default(0),
|
|
281
|
-
reasonBreakdown: text("reason_breakdown").notNull().default(
|
|
283
|
+
reasonBreakdown: text("reason_breakdown", { mode: "json" }).$type().notNull().default({}),
|
|
282
284
|
createdAt: text("created_at").notNull()
|
|
283
285
|
}, (table) => [
|
|
284
286
|
index("idx_gsc_coverage_snap_project_date").on(table.projectId, table.date),
|
|
@@ -311,7 +313,7 @@ var bingUrlInspections = sqliteTable("bing_url_inspections", {
|
|
|
311
313
|
projectId: text("project_id").notNull().references(() => projects.id, { onDelete: "cascade" }),
|
|
312
314
|
url: text("url").notNull(),
|
|
313
315
|
httpCode: integer("http_code"),
|
|
314
|
-
inIndex: integer("in_index"),
|
|
316
|
+
inIndex: integer("in_index", { mode: "boolean" }),
|
|
315
317
|
lastCrawledDate: text("last_crawled_date"),
|
|
316
318
|
inIndexDate: text("in_index_date"),
|
|
317
319
|
inspectedAt: text("inspected_at").notNull(),
|
|
@@ -472,8 +474,8 @@ var insights = sqliteTable("insights", {
|
|
|
472
474
|
title: text("title").notNull(),
|
|
473
475
|
query: text("query").notNull(),
|
|
474
476
|
provider: text("provider").notNull(),
|
|
475
|
-
recommendation: text("recommendation"),
|
|
476
|
-
cause: text("cause"),
|
|
477
|
+
recommendation: text("recommendation", { mode: "json" }).$type(),
|
|
478
|
+
cause: text("cause", { mode: "json" }).$type(),
|
|
477
479
|
dismissed: integer("dismissed", { mode: "boolean" }).notNull().default(false),
|
|
478
480
|
createdAt: text("created_at").notNull()
|
|
479
481
|
}, (table) => [
|
|
@@ -489,7 +491,7 @@ var healthSnapshots = sqliteTable("health_snapshots", {
|
|
|
489
491
|
overallCitedRate: text("overall_cited_rate").notNull(),
|
|
490
492
|
totalPairs: integer("total_pairs").notNull(),
|
|
491
493
|
citedPairs: integer("cited_pairs").notNull(),
|
|
492
|
-
providerBreakdown: text("provider_breakdown").notNull().default(
|
|
494
|
+
providerBreakdown: text("provider_breakdown", { mode: "json" }).$type().notNull().default({}),
|
|
493
495
|
createdAt: text("created_at").notNull()
|
|
494
496
|
}, (table) => [
|
|
495
497
|
index("idx_health_snapshots_project").on(table.projectId),
|
|
@@ -589,9 +591,9 @@ var trafficSources = sqliteTable("traffic_sources", {
|
|
|
589
591
|
// observed in the most recent successful sync. Bounded ring buffer used to
|
|
590
592
|
// dedupe across sync runs at the boundary timestamp where lastSyncedAt
|
|
591
593
|
// clamping alone leaves a small overlap window.
|
|
592
|
-
lastEventIds: text("last_event_ids"),
|
|
594
|
+
lastEventIds: text("last_event_ids", { mode: "json" }).$type(),
|
|
593
595
|
archivedAt: text("archived_at"),
|
|
594
|
-
configJson: text("config_json").notNull().default(
|
|
596
|
+
configJson: text("config_json", { mode: "json" }).$type().notNull().default({}),
|
|
595
597
|
createdAt: text("created_at").notNull(),
|
|
596
598
|
updatedAt: text("updated_at").notNull()
|
|
597
599
|
}, (table) => [
|
|
@@ -667,7 +669,7 @@ var rawEventSamples = sqliteTable("raw_event_samples", {
|
|
|
667
669
|
pathNormalized: text("path_normalized").notNull(),
|
|
668
670
|
status: integer("status"),
|
|
669
671
|
refererHost: text("referer_host"),
|
|
670
|
-
classifierDetailsJson: text("classifier_details_json").notNull().default(
|
|
672
|
+
classifierDetailsJson: text("classifier_details_json", { mode: "json" }).$type().notNull().default({}),
|
|
671
673
|
createdAt: text("created_at").notNull()
|
|
672
674
|
}, (table) => [
|
|
673
675
|
index("idx_raw_event_samples_project_ts").on(table.projectId, table.ts),
|
|
@@ -688,7 +690,7 @@ var discoverySessions = sqliteTable("discovery_sessions", {
|
|
|
688
690
|
citedCount: integer("cited_count"),
|
|
689
691
|
aspirationalCount: integer("aspirational_count"),
|
|
690
692
|
wastedCount: integer("wasted_count"),
|
|
691
|
-
competitorMap: text("competitor_map").notNull().default(
|
|
693
|
+
competitorMap: text("competitor_map", { mode: "json" }).$type().notNull().default([]),
|
|
692
694
|
error: text("error"),
|
|
693
695
|
startedAt: text("started_at"),
|
|
694
696
|
finishedAt: text("finished_at"),
|
|
@@ -704,13 +706,43 @@ var discoveryProbes = sqliteTable("discovery_probes", {
|
|
|
704
706
|
query: text("query").notNull(),
|
|
705
707
|
bucket: text("bucket"),
|
|
706
708
|
citationState: text("citation_state").notNull(),
|
|
707
|
-
citedDomains: text("cited_domains").notNull().default(
|
|
709
|
+
citedDomains: text("cited_domains", { mode: "json" }).$type().notNull().default([]),
|
|
708
710
|
rawResponse: text("raw_response"),
|
|
709
711
|
createdAt: text("created_at").notNull()
|
|
710
712
|
}, (table) => [
|
|
711
713
|
index("idx_discovery_probes_session").on(table.sessionId),
|
|
712
714
|
index("idx_discovery_probes_project").on(table.projectId)
|
|
713
715
|
]);
|
|
716
|
+
var contentTargetDismissals = sqliteTable("content_target_dismissals", {
|
|
717
|
+
id: text("id").primaryKey(),
|
|
718
|
+
projectId: text("project_id").notNull().references(() => projects.id, { onDelete: "cascade" }),
|
|
719
|
+
targetRef: text("target_ref").notNull(),
|
|
720
|
+
addressedUrl: text("addressed_url"),
|
|
721
|
+
note: text("note"),
|
|
722
|
+
dismissedAt: text("dismissed_at").notNull()
|
|
723
|
+
}, (table) => [
|
|
724
|
+
uniqueIndex("idx_content_target_dismissals_project_ref").on(table.projectId, table.targetRef),
|
|
725
|
+
index("idx_content_target_dismissals_project").on(table.projectId)
|
|
726
|
+
]);
|
|
727
|
+
var recommendationExplanations = sqliteTable("recommendation_explanations", {
|
|
728
|
+
id: text("id").primaryKey(),
|
|
729
|
+
projectId: text("project_id").notNull().references(() => projects.id, { onDelete: "cascade" }),
|
|
730
|
+
targetRef: text("target_ref").notNull(),
|
|
731
|
+
promptVersion: text("prompt_version").notNull(),
|
|
732
|
+
provider: text("provider").notNull(),
|
|
733
|
+
model: text("model").notNull(),
|
|
734
|
+
responseText: text("response_text").notNull(),
|
|
735
|
+
/** Estimated cost in millicents (1/100 of a cent) for audit; 0 if unknown. */
|
|
736
|
+
costMillicents: integer("cost_millicents").notNull().default(0),
|
|
737
|
+
generatedAt: text("generated_at").notNull()
|
|
738
|
+
}, (table) => [
|
|
739
|
+
uniqueIndex("idx_recommendation_explanations_unique").on(
|
|
740
|
+
table.projectId,
|
|
741
|
+
table.targetRef,
|
|
742
|
+
table.promptVersion
|
|
743
|
+
),
|
|
744
|
+
index("idx_recommendation_explanations_project").on(table.projectId)
|
|
745
|
+
]);
|
|
714
746
|
var migrationsTable = sqliteTable("_migrations", {
|
|
715
747
|
version: integer("version").primaryKey(),
|
|
716
748
|
name: text("name").notNull(),
|
|
@@ -1942,6 +1974,55 @@ var MIGRATION_VERSIONS = [
|
|
|
1942
1974
|
`CREATE INDEX IF NOT EXISTS idx_audit_log_project ON audit_log(project_id)`,
|
|
1943
1975
|
`CREATE INDEX IF NOT EXISTS idx_audit_log_created ON audit_log(created_at)`
|
|
1944
1976
|
]
|
|
1977
|
+
},
|
|
1978
|
+
{
|
|
1979
|
+
version: 61,
|
|
1980
|
+
name: "content-target-dismissals",
|
|
1981
|
+
// Persistent per-recommendation dismissal so users can mark a content
|
|
1982
|
+
// opportunity "addressed" after they ship the page. The orchestrator
|
|
1983
|
+
// recomputes opportunities on every report load from live GSC / GA
|
|
1984
|
+
// inventory; without persistent dismissal, a recommendation lingers
|
|
1985
|
+
// until the next sync surfaces the new page (days–weeks of lag).
|
|
1986
|
+
//
|
|
1987
|
+
// Keyed by `(project_id, target_ref)` where `target_ref` is the stable
|
|
1988
|
+
// hash that `computeTargetRef()` already produces — same value the
|
|
1989
|
+
// ContentTargetRowDto exposes, so the client passes back the ref it
|
|
1990
|
+
// sees.
|
|
1991
|
+
statements: [
|
|
1992
|
+
`CREATE TABLE IF NOT EXISTS content_target_dismissals (
|
|
1993
|
+
id TEXT PRIMARY KEY,
|
|
1994
|
+
project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
1995
|
+
target_ref TEXT NOT NULL,
|
|
1996
|
+
addressed_url TEXT,
|
|
1997
|
+
note TEXT,
|
|
1998
|
+
dismissed_at TEXT NOT NULL
|
|
1999
|
+
)`,
|
|
2000
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_content_target_dismissals_project_ref ON content_target_dismissals(project_id, target_ref)`,
|
|
2001
|
+
`CREATE INDEX IF NOT EXISTS idx_content_target_dismissals_project ON content_target_dismissals(project_id)`
|
|
2002
|
+
]
|
|
2003
|
+
},
|
|
2004
|
+
{
|
|
2005
|
+
version: 62,
|
|
2006
|
+
name: "recommendation-explanations",
|
|
2007
|
+
// LLM-generated rationale for content recommendations. Cached per
|
|
2008
|
+
// (project, target_ref, prompt_version) so repeat clicks are free.
|
|
2009
|
+
// Bumping the prompt version invalidates the cache forward without
|
|
2010
|
+
// touching the table.
|
|
2011
|
+
statements: [
|
|
2012
|
+
`CREATE TABLE IF NOT EXISTS recommendation_explanations (
|
|
2013
|
+
id TEXT PRIMARY KEY,
|
|
2014
|
+
project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
|
2015
|
+
target_ref TEXT NOT NULL,
|
|
2016
|
+
prompt_version TEXT NOT NULL,
|
|
2017
|
+
provider TEXT NOT NULL,
|
|
2018
|
+
model TEXT NOT NULL,
|
|
2019
|
+
response_text TEXT NOT NULL,
|
|
2020
|
+
cost_millicents INTEGER NOT NULL DEFAULT 0,
|
|
2021
|
+
generated_at TEXT NOT NULL
|
|
2022
|
+
)`,
|
|
2023
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_recommendation_explanations_unique ON recommendation_explanations(project_id, target_ref, prompt_version)`,
|
|
2024
|
+
`CREATE INDEX IF NOT EXISTS idx_recommendation_explanations_project ON recommendation_explanations(project_id)`
|
|
2025
|
+
]
|
|
1945
2026
|
}
|
|
1946
2027
|
];
|
|
1947
2028
|
function isDuplicateColumnError(err) {
|
|
@@ -2636,9 +2717,15 @@ function isBlogShaped(path) {
|
|
|
2636
2717
|
// ../intelligence/src/content-classifier.ts
|
|
2637
2718
|
var SEO_STRONG_THRESHOLD = 10;
|
|
2638
2719
|
var SEO_WEAK_THRESHOLD = 30;
|
|
2720
|
+
function isHomepageOnly(url) {
|
|
2721
|
+
if (url === "/" || url === "") return true;
|
|
2722
|
+
const stripped = url.split("?")[0].replace(/\/+$/, "");
|
|
2723
|
+
return stripped === "" || stripped === "/";
|
|
2724
|
+
}
|
|
2639
2725
|
function classifyContentAction(input) {
|
|
2640
2726
|
const { ourPage, ourPageInGroundingSources, ourPageHasSchema } = input;
|
|
2641
2727
|
if (!ourPage) return "create";
|
|
2728
|
+
if (isHomepageOnly(ourPage.url)) return "create";
|
|
2642
2729
|
if (ourPageInGroundingSources) {
|
|
2643
2730
|
if (ourPageHasSchema === false) return "add-schema";
|
|
2644
2731
|
return null;
|
|
@@ -2783,8 +2870,7 @@ function buildContentTargetRows(input) {
|
|
|
2783
2870
|
const targetRef = computeTargetRef({
|
|
2784
2871
|
projectId: input.projectId,
|
|
2785
2872
|
query: cq.query,
|
|
2786
|
-
action
|
|
2787
|
-
targetPage: ourPage?.url ?? null
|
|
2873
|
+
action
|
|
2788
2874
|
});
|
|
2789
2875
|
const winningCompetitor = pickTopCompetitor(cq.competitorGroundingUrls);
|
|
2790
2876
|
const ourBestPage = ourPage ? {
|
|
@@ -2936,7 +3022,7 @@ function pickTopCompetitor(competitors2) {
|
|
|
2936
3022
|
};
|
|
2937
3023
|
}
|
|
2938
3024
|
function computeTargetRef(input) {
|
|
2939
|
-
const key = [input.projectId, input.query, input.action
|
|
3025
|
+
const key = [input.projectId, input.query, input.action].join("|");
|
|
2940
3026
|
let hash = 0;
|
|
2941
3027
|
for (let i = 0; i < key.length; i++) {
|
|
2942
3028
|
hash = (hash << 5) - hash + key.charCodeAt(i) | 0;
|
|
@@ -4136,8 +4222,8 @@ var IntelligenceService = class {
|
|
|
4136
4222
|
title: insight.title,
|
|
4137
4223
|
query: insight.query,
|
|
4138
4224
|
provider: insight.provider,
|
|
4139
|
-
recommendation: insight.recommendation
|
|
4140
|
-
cause: insight.cause
|
|
4225
|
+
recommendation: insight.recommendation ?? null,
|
|
4226
|
+
cause: insight.cause ?? null,
|
|
4141
4227
|
dismissed: wasDismissed,
|
|
4142
4228
|
createdAt: insight.createdAt
|
|
4143
4229
|
}).run();
|
|
@@ -4149,7 +4235,7 @@ var IntelligenceService = class {
|
|
|
4149
4235
|
overallCitedRate: String(result.health.overallCitedRate),
|
|
4150
4236
|
totalPairs: result.health.totalPairs,
|
|
4151
4237
|
citedPairs: result.health.citedPairs,
|
|
4152
|
-
providerBreakdown:
|
|
4238
|
+
providerBreakdown: result.health.providerBreakdown,
|
|
4153
4239
|
createdAt: now
|
|
4154
4240
|
}).run();
|
|
4155
4241
|
});
|
|
@@ -4184,7 +4270,7 @@ var IntelligenceService = class {
|
|
|
4184
4270
|
const projectRow = this.db.select({ locations: projects.locations }).from(projects).where(eq(projects.id, projectId)).get();
|
|
4185
4271
|
const locationCount = Math.max(
|
|
4186
4272
|
1,
|
|
4187
|
-
|
|
4273
|
+
(projectRow?.locations ?? []).length
|
|
4188
4274
|
);
|
|
4189
4275
|
const ROWS_PER_GROUP_BUDGET = Math.max(2, locationCount);
|
|
4190
4276
|
const recentRunRows = this.db.select({ id: runs.id, createdAt: runs.createdAt }).from(runs).where(
|
|
@@ -4260,8 +4346,8 @@ var IntelligenceService = class {
|
|
|
4260
4346
|
orphanCount++;
|
|
4261
4347
|
continue;
|
|
4262
4348
|
}
|
|
4263
|
-
const domains =
|
|
4264
|
-
const competitors2 =
|
|
4349
|
+
const domains = r.citedDomains;
|
|
4350
|
+
const competitors2 = r.competitorOverlap;
|
|
4265
4351
|
snapshots.push({
|
|
4266
4352
|
query: resolvedQuery,
|
|
4267
4353
|
provider: r.provider,
|
|
@@ -4321,6 +4407,8 @@ export {
|
|
|
4321
4407
|
rawEventSamples,
|
|
4322
4408
|
discoverySessions,
|
|
4323
4409
|
discoveryProbes,
|
|
4410
|
+
contentTargetDismissals,
|
|
4411
|
+
recommendationExplanations,
|
|
4324
4412
|
createClient,
|
|
4325
4413
|
parseJsonColumn,
|
|
4326
4414
|
extractLegacyCredentials,
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
trafficConnectVercelRequestSchema,
|
|
23
23
|
trafficConnectWordpressRequestSchema,
|
|
24
24
|
trafficEventKindSchema
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-2ARCCG5E.js";
|
|
26
26
|
|
|
27
27
|
// src/config.ts
|
|
28
28
|
import fs from "fs";
|
|
@@ -3117,6 +3117,86 @@ var postApiV1ProjectsByNameDiscoverSessionsByIdPromote = (options) => {
|
|
|
3117
3117
|
}
|
|
3118
3118
|
});
|
|
3119
3119
|
};
|
|
3120
|
+
var deleteApiV1ProjectsByNameAgentTranscript = (options) => {
|
|
3121
|
+
return (options.client ?? client).delete({
|
|
3122
|
+
security: [
|
|
3123
|
+
{
|
|
3124
|
+
scheme: "bearer",
|
|
3125
|
+
type: "http"
|
|
3126
|
+
}
|
|
3127
|
+
],
|
|
3128
|
+
url: "/api/v1/projects/{name}/agent/transcript",
|
|
3129
|
+
...options
|
|
3130
|
+
});
|
|
3131
|
+
};
|
|
3132
|
+
var getApiV1ProjectsByNameAgentTranscript = (options) => {
|
|
3133
|
+
return (options.client ?? client).get({
|
|
3134
|
+
security: [
|
|
3135
|
+
{
|
|
3136
|
+
scheme: "bearer",
|
|
3137
|
+
type: "http"
|
|
3138
|
+
}
|
|
3139
|
+
],
|
|
3140
|
+
url: "/api/v1/projects/{name}/agent/transcript",
|
|
3141
|
+
...options
|
|
3142
|
+
});
|
|
3143
|
+
};
|
|
3144
|
+
var deleteApiV1ProjectsByNameAgentMemory = (options) => {
|
|
3145
|
+
return (options.client ?? client).delete({
|
|
3146
|
+
security: [
|
|
3147
|
+
{
|
|
3148
|
+
scheme: "bearer",
|
|
3149
|
+
type: "http"
|
|
3150
|
+
}
|
|
3151
|
+
],
|
|
3152
|
+
url: "/api/v1/projects/{name}/agent/memory",
|
|
3153
|
+
...options,
|
|
3154
|
+
headers: {
|
|
3155
|
+
"Content-Type": "application/json",
|
|
3156
|
+
...options.headers
|
|
3157
|
+
}
|
|
3158
|
+
});
|
|
3159
|
+
};
|
|
3160
|
+
var getApiV1ProjectsByNameAgentMemory = (options) => {
|
|
3161
|
+
return (options.client ?? client).get({
|
|
3162
|
+
security: [
|
|
3163
|
+
{
|
|
3164
|
+
scheme: "bearer",
|
|
3165
|
+
type: "http"
|
|
3166
|
+
}
|
|
3167
|
+
],
|
|
3168
|
+
url: "/api/v1/projects/{name}/agent/memory",
|
|
3169
|
+
...options
|
|
3170
|
+
});
|
|
3171
|
+
};
|
|
3172
|
+
var putApiV1ProjectsByNameAgentMemory = (options) => {
|
|
3173
|
+
return (options.client ?? client).put({
|
|
3174
|
+
security: [
|
|
3175
|
+
{
|
|
3176
|
+
scheme: "bearer",
|
|
3177
|
+
type: "http"
|
|
3178
|
+
}
|
|
3179
|
+
],
|
|
3180
|
+
url: "/api/v1/projects/{name}/agent/memory",
|
|
3181
|
+
...options,
|
|
3182
|
+
headers: {
|
|
3183
|
+
"Content-Type": "application/json",
|
|
3184
|
+
...options.headers
|
|
3185
|
+
}
|
|
3186
|
+
});
|
|
3187
|
+
};
|
|
3188
|
+
var getApiV1ProjectsByNameAgentProviders = (options) => {
|
|
3189
|
+
return (options.client ?? client).get({
|
|
3190
|
+
security: [
|
|
3191
|
+
{
|
|
3192
|
+
scheme: "bearer",
|
|
3193
|
+
type: "http"
|
|
3194
|
+
}
|
|
3195
|
+
],
|
|
3196
|
+
url: "/api/v1/projects/{name}/agent/providers",
|
|
3197
|
+
...options
|
|
3198
|
+
});
|
|
3199
|
+
};
|
|
3120
3200
|
|
|
3121
3201
|
// ../api-client-generated/src/index.ts
|
|
3122
3202
|
function createClient2(opts) {
|
|
@@ -3239,94 +3319,48 @@ var ApiClient = class {
|
|
|
3239
3319
|
}
|
|
3240
3320
|
return result.data;
|
|
3241
3321
|
}
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
const headers = {
|
|
3253
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
3254
|
-
Accept: "application/json",
|
|
3255
|
-
...serializedBody != null ? { "Content-Type": "application/json" } : {}
|
|
3256
|
-
};
|
|
3257
|
-
const traceEnabled = process.env.CANONRY_TRACE === "1";
|
|
3258
|
-
const traceStart = traceEnabled ? Date.now() : 0;
|
|
3259
|
-
let res;
|
|
3260
|
-
try {
|
|
3261
|
-
res = await fetch(url, { method, headers, body: serializedBody });
|
|
3262
|
-
} catch (err) {
|
|
3263
|
-
if (traceEnabled) {
|
|
3264
|
-
const durMs = Date.now() - traceStart;
|
|
3265
|
-
process.stderr.write(`[trace] ${method} ${url} \u2192 ERROR (${durMs}ms)
|
|
3266
|
-
`);
|
|
3267
|
-
}
|
|
3268
|
-
if (err instanceof CliError) throw err;
|
|
3269
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
3270
|
-
if (msg.includes("fetch failed") || msg.includes("ECONNREFUSED") || msg.includes("connect ECONNREFUSED")) {
|
|
3271
|
-
throw new CliError({
|
|
3272
|
-
code: "CONNECTION_ERROR",
|
|
3273
|
-
message: `Could not connect to canonry server at ${this.originUrl}. Start it with "canonry serve" (or "canonry serve &" to run in background).`,
|
|
3274
|
-
exitCode: EXIT_SYSTEM_ERROR
|
|
3275
|
-
});
|
|
3276
|
-
}
|
|
3277
|
-
throw new CliError({ code: "CONNECTION_ERROR", message: msg, exitCode: EXIT_SYSTEM_ERROR });
|
|
3278
|
-
}
|
|
3279
|
-
if (!res.ok) {
|
|
3280
|
-
let errorBody;
|
|
3281
|
-
try {
|
|
3282
|
-
errorBody = await res.json();
|
|
3283
|
-
} catch {
|
|
3284
|
-
errorBody = { error: { code: "UNKNOWN", message: res.statusText } };
|
|
3285
|
-
}
|
|
3286
|
-
const errorObj = errorBody && typeof errorBody === "object" && "error" in errorBody && errorBody.error && typeof errorBody.error === "object" ? errorBody.error : null;
|
|
3287
|
-
const msg = errorObj?.message ? String(errorObj.message) : `HTTP ${res.status}: ${res.statusText}`;
|
|
3288
|
-
const code = errorObj?.code ? String(errorObj.code) : "API_ERROR";
|
|
3289
|
-
const exitCode = res.status >= 500 ? EXIT_SYSTEM_ERROR : EXIT_USER_ERROR;
|
|
3290
|
-
throw new CliError({
|
|
3291
|
-
code,
|
|
3292
|
-
message: msg,
|
|
3293
|
-
exitCode,
|
|
3294
|
-
details: { ...errorObj?.details ?? {}, httpStatus: res.status }
|
|
3295
|
-
});
|
|
3296
|
-
}
|
|
3297
|
-
if (traceEnabled) {
|
|
3298
|
-
const durMs = Date.now() - traceStart;
|
|
3299
|
-
process.stderr.write(`[trace] ${method} ${url} \u2192 ${res.status} (${durMs}ms)
|
|
3300
|
-
`);
|
|
3301
|
-
}
|
|
3302
|
-
if (res.status === 204) return void 0;
|
|
3303
|
-
return await res.json();
|
|
3304
|
-
}
|
|
3305
|
-
// ── Agent (routes not in OpenAPI spec — raw request<T>) ─────────────────
|
|
3322
|
+
// ── Agent (canonry-local routes — SDK-typed since v4.50.0) ─────────────
|
|
3323
|
+
//
|
|
3324
|
+
// These endpoints live in `packages/canonry/src/agent/agent-routes.ts` and
|
|
3325
|
+
// are registered through `apiRoutes.registerAuthenticatedRoutes`, not the
|
|
3326
|
+
// shared `routeCatalog`. They appear in the OpenAPI spec only when the
|
|
3327
|
+
// caller passes `includeCanonryLocal: true` to `buildOpenApiDocument` —
|
|
3328
|
+
// which canonry's own server and the codegen both do, so they're in the
|
|
3329
|
+
// generated SDK and we route them through `invoke()` like every other
|
|
3330
|
+
// endpoint. The SSE `POST /agent/prompt` is intentionally not here — it
|
|
3331
|
+
// stays on `streamPost()` below since the SDK can't represent SSE cleanly.
|
|
3306
3332
|
async getAgentTranscript(project) {
|
|
3307
|
-
return this.
|
|
3333
|
+
return this.invoke(
|
|
3334
|
+
() => getApiV1ProjectsByNameAgentTranscript({ client: this.heyClient, path: { name: project } })
|
|
3335
|
+
);
|
|
3308
3336
|
}
|
|
3309
3337
|
async resetAgentTranscript(project) {
|
|
3310
|
-
await this.
|
|
3338
|
+
await this.invoke(
|
|
3339
|
+
() => deleteApiV1ProjectsByNameAgentTranscript({ client: this.heyClient, path: { name: project } })
|
|
3340
|
+
);
|
|
3311
3341
|
}
|
|
3312
3342
|
async listAgentProviders(project) {
|
|
3313
|
-
return this.
|
|
3343
|
+
return this.invoke(
|
|
3344
|
+
() => getApiV1ProjectsByNameAgentProviders({ client: this.heyClient, path: { name: project } })
|
|
3345
|
+
);
|
|
3314
3346
|
}
|
|
3315
3347
|
async listAgentMemory(project) {
|
|
3316
|
-
return this.
|
|
3348
|
+
return this.invoke(
|
|
3349
|
+
() => getApiV1ProjectsByNameAgentMemory({ client: this.heyClient, path: { name: project } })
|
|
3350
|
+
);
|
|
3317
3351
|
}
|
|
3318
3352
|
async setAgentMemory(project, body) {
|
|
3319
|
-
return this.
|
|
3320
|
-
|
|
3321
|
-
`/projects/${encodeURIComponent(project)}/agent/memory`,
|
|
3322
|
-
body
|
|
3353
|
+
return this.invoke(
|
|
3354
|
+
() => putApiV1ProjectsByNameAgentMemory({ client: this.heyClient, path: { name: project }, body })
|
|
3323
3355
|
);
|
|
3324
3356
|
}
|
|
3325
3357
|
async forgetAgentMemory(project, key) {
|
|
3326
|
-
return this.
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3358
|
+
return this.invoke(
|
|
3359
|
+
() => deleteApiV1ProjectsByNameAgentMemory({
|
|
3360
|
+
client: this.heyClient,
|
|
3361
|
+
path: { name: project },
|
|
3362
|
+
body: { key }
|
|
3363
|
+
})
|
|
3330
3364
|
);
|
|
3331
3365
|
}
|
|
3332
3366
|
/**
|