@ainyc/canonry 4.72.0 → 4.72.3
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/aeo-analysis.md +1 -1
- package/dist/{chunk-XYX447L2.js → chunk-HSX32G47.js} +26 -12
- package/dist/{chunk-SJI6JGPN.js → chunk-JXFNERK4.js} +18 -5
- package/dist/{chunk-ZISXWFQA.js → chunk-SIB4NMEH.js} +4 -4
- package/dist/{chunk-NYZSY5QJ.js → chunk-ZUBBADMR.js} +1 -1
- package/dist/cli.js +4 -4
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-YOZOOYUI.js → intelligence-service-ZW3ARLJT.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +10 -10
|
@@ -53,7 +53,7 @@ Shows which source categories AI models cite for your queries. Helps identify:
|
|
|
53
53
|
- Content format opportunities (FAQ, how-to, comparison pages)
|
|
54
54
|
|
|
55
55
|
### Winnability gate + briefs (`canonry content targets|map|brief`)
|
|
56
|
-
Every content target carries a deterministic `winnabilityClass`: **ownable** (worth writing for) or **ceded** (the cited surface is dominated by aggregators/OTAs or editorial media
|
|
56
|
+
Every content target carries a deterministic `winnabilityClass`: **ownable** (worth writing for) or **ceded** (the cited surface is dominated by aggregators/OTAs or editorial media, a head term first-party content cannot realistically win). It is derived (no LLM) by classifying each cited domain through the shared surface classifier (own > tracked competitor > stored discovery class > static allow-list), so well-known aggregators/editorial cede immediately, no discovery run required. **`canonry discover run`** improves recall for niche domains the allow-list misses; a target only fails open to `ownable` when none of its cited surface is recognized. `canonry doctor --project <project> --check content.winnability.coverage` reports recognized-coverage of the cited surface and, when the project has no ICP, nudges you to set one (discovery needs it).
|
|
57
57
|
- `canonry content targets <project> --ownable` — the winnable shortlist (ownable rows sort first by default).
|
|
58
58
|
- `canonry content map <project>` — the winnability map: which cited surfaces are ceded vs the ranked ownable targets.
|
|
59
59
|
- `canonry content brief <project> <targetRef>` — synthesize a structured brief (angle, why-winnable, schema hookup) for an **ownable** target. Ceded targets are rejected — don't chase them.
|
|
@@ -65,6 +65,7 @@ import {
|
|
|
65
65
|
citationStateSchema,
|
|
66
66
|
citationStateToCited,
|
|
67
67
|
citationVisibilityResponseSchema,
|
|
68
|
+
classifyCitedSurface,
|
|
68
69
|
classifySkillFile,
|
|
69
70
|
classifySurfaceFromCategory,
|
|
70
71
|
clusterByCosine,
|
|
@@ -222,7 +223,7 @@ import {
|
|
|
222
223
|
wordpressSchemaDeployResultDtoSchema,
|
|
223
224
|
wordpressSchemaStatusResultDtoSchema,
|
|
224
225
|
wordpressStatusDtoSchema
|
|
225
|
-
} from "./chunk-
|
|
226
|
+
} from "./chunk-JXFNERK4.js";
|
|
226
227
|
|
|
227
228
|
// src/intelligence-service.ts
|
|
228
229
|
import { eq as eq32, desc as desc16, asc as asc3, and as and23, ne as ne5, or as or5, inArray as inArray11, gte as gte6, lte as lte3 } from "drizzle-orm";
|
|
@@ -3636,7 +3637,12 @@ function buildContentTargetRows(input) {
|
|
|
3636
3637
|
gscAvgPosition: cq.gscPosition,
|
|
3637
3638
|
organicSessions: input.gaTrafficByPage.get(ourPage.url) ?? 0
|
|
3638
3639
|
} : null;
|
|
3639
|
-
const
|
|
3640
|
+
const surfaceClasses = classifyCitedSurface(
|
|
3641
|
+
cq.citedSurfaceDomains,
|
|
3642
|
+
{ projectDomains: [input.ownDomain], competitorDomains: input.competitors },
|
|
3643
|
+
input.domainClasses
|
|
3644
|
+
);
|
|
3645
|
+
const { winnabilityClass, winnability } = deriveWinnabilityClass(cq.citedSurfaceDomains, surfaceClasses);
|
|
3640
3646
|
rows.push({
|
|
3641
3647
|
targetRef,
|
|
3642
3648
|
query: cq.query,
|
|
@@ -27676,6 +27682,7 @@ async function listVercelTrafficEvents(options) {
|
|
|
27676
27682
|
|
|
27677
27683
|
// ../integration-vercel/src/drain.ts
|
|
27678
27684
|
var MIN_SUB_WINDOW_MS = 1e3;
|
|
27685
|
+
var INITIAL_SUB_WINDOW_MS = 5 * 6e4;
|
|
27679
27686
|
var FLOOR_SLICE_MAX_PAGES = 1e3;
|
|
27680
27687
|
var FLOOR_CONGESTION_PROBE_INTERVAL = 60;
|
|
27681
27688
|
var RETENTION_PROBE_WINDOW_MS = 6e4;
|
|
@@ -27730,7 +27737,7 @@ async function drainVercelTrafficEvents(options) {
|
|
|
27730
27737
|
return { events, subWindowCount: 0, effectiveStartMs: startMs, retentionClamped: false, truncatedSliceCount: 0, truncatedSliceStartsMs: [], drainedThroughMs: startMs, deadlineReached: false };
|
|
27731
27738
|
}
|
|
27732
27739
|
let cursorMs = startMs;
|
|
27733
|
-
let spanMs = endMs - startMs;
|
|
27740
|
+
let spanMs = Math.min(endMs - startMs, INITIAL_SUB_WINDOW_MS);
|
|
27734
27741
|
let subWindowCount = 0;
|
|
27735
27742
|
let effectiveStartMs = startMs;
|
|
27736
27743
|
let retentionClamped = false;
|
|
@@ -27772,7 +27779,7 @@ async function drainVercelTrafficEvents(options) {
|
|
|
27772
27779
|
retentionClamped = retainedStartMs > cursorMs;
|
|
27773
27780
|
cursorMs = retainedStartMs;
|
|
27774
27781
|
effectiveStartMs = retainedStartMs;
|
|
27775
|
-
spanMs = Math.max(endMs - cursorMs, MIN_SUB_WINDOW_MS);
|
|
27782
|
+
spanMs = Math.max(Math.min(endMs - cursorMs, INITIAL_SUB_WINDOW_MS), MIN_SUB_WINDOW_MS);
|
|
27776
27783
|
continue;
|
|
27777
27784
|
}
|
|
27778
27785
|
throw error;
|
|
@@ -29666,23 +29673,30 @@ var winnabilityCoverageCheck = {
|
|
|
29666
29673
|
}
|
|
29667
29674
|
};
|
|
29668
29675
|
}
|
|
29669
|
-
const
|
|
29670
|
-
|
|
29676
|
+
const surfaceClasses = classifyCitedSurface(
|
|
29677
|
+
citedDomains.map((domain) => ({ domain })),
|
|
29678
|
+
{ projectDomains: [input.ownDomain], competitorDomains: input.competitors },
|
|
29679
|
+
input.domainClasses
|
|
29680
|
+
);
|
|
29681
|
+
const coveredDomains = citedDomains.filter((domain) => surfaceClasses.has(domain));
|
|
29682
|
+
const unclassifiedDomains = citedDomains.filter((domain) => !surfaceClasses.has(domain));
|
|
29671
29683
|
const coverage = coveredDomains.length / citedDomains.length;
|
|
29672
29684
|
const details = {
|
|
29673
29685
|
citedSurfaceDomainCount: citedDomains.length,
|
|
29674
|
-
classifiedDomainCount: input.domainClasses.size,
|
|
29675
29686
|
coveredDomainCount: coveredDomains.length,
|
|
29687
|
+
classifiedDomainCount: input.domainClasses.size,
|
|
29676
29688
|
coverage,
|
|
29677
29689
|
threshold: WINNABILITY_COVERAGE_WARN_THRESHOLD,
|
|
29678
29690
|
unclassifiedDomains: unclassifiedDomains.slice(0, UNCLASSIFIED_DOMAIN_SAMPLE_LIMIT)
|
|
29679
29691
|
};
|
|
29692
|
+
const hasIcp = Boolean(project.icpDescription && project.icpDescription.trim().length > 0);
|
|
29693
|
+
const discoverRemediation = hasIcp ? `Run \`canonry discover run ${ctx.project.name} --wait\` to classify the unrecognized domains before relying on ownable/ceded content targets.` : `This project has no ICP, which discovery requires. Run \`canonry discover run ${ctx.project.name} --icp "<who the project sells to>" --wait\` (or set \`spec.icpDescription\`) to classify the unrecognized domains.`;
|
|
29680
29694
|
if (coveredDomains.length === 0) {
|
|
29681
29695
|
return {
|
|
29682
29696
|
status: CheckStatuses.warn,
|
|
29683
29697
|
code: "content.winnability.no-classifications",
|
|
29684
|
-
summary: `0 of ${citedDomains.length} cited-surface domain(s)
|
|
29685
|
-
remediation:
|
|
29698
|
+
summary: `0 of ${citedDomains.length} cited-surface domain(s) are recognized (own/competitor/aggregator/editorial); the winnability gate is failing open.`,
|
|
29699
|
+
remediation: discoverRemediation,
|
|
29686
29700
|
details
|
|
29687
29701
|
};
|
|
29688
29702
|
}
|
|
@@ -29690,15 +29704,15 @@ var winnabilityCoverageCheck = {
|
|
|
29690
29704
|
return {
|
|
29691
29705
|
status: CheckStatuses.warn,
|
|
29692
29706
|
code: "content.winnability.low-coverage",
|
|
29693
|
-
summary: `${coveredDomains.length} of ${citedDomains.length} cited-surface domain(s)
|
|
29694
|
-
remediation:
|
|
29707
|
+
summary: `${coveredDomains.length} of ${citedDomains.length} cited-surface domain(s) recognized (${percent(coverage)}%); the winnability gate may miss ceded surfaces in the unrecognized tail.`,
|
|
29708
|
+
remediation: discoverRemediation,
|
|
29695
29709
|
details
|
|
29696
29710
|
};
|
|
29697
29711
|
}
|
|
29698
29712
|
return {
|
|
29699
29713
|
status: CheckStatuses.ok,
|
|
29700
29714
|
code: "content.winnability.covered",
|
|
29701
|
-
summary: `${coveredDomains.length} of ${citedDomains.length} cited-surface domain(s)
|
|
29715
|
+
summary: `${coveredDomains.length} of ${citedDomains.length} cited-surface domain(s) recognized (${percent(coverage)}%); the winnability gate is active.`,
|
|
29702
29716
|
remediation: null,
|
|
29703
29717
|
details
|
|
29704
29718
|
};
|
|
@@ -1898,6 +1898,18 @@ function classifySurfaceFromCategory(domain, category, context, storedClass) {
|
|
|
1898
1898
|
return SurfaceClasses.other;
|
|
1899
1899
|
}
|
|
1900
1900
|
}
|
|
1901
|
+
function classifyCitedSurface(domains, context, storedClasses) {
|
|
1902
|
+
const out = /* @__PURE__ */ new Map();
|
|
1903
|
+
for (const { domain } of domains) {
|
|
1904
|
+
if (out.has(domain)) continue;
|
|
1905
|
+
const stored = storedClasses?.get(domain);
|
|
1906
|
+
const storedClass = stored ? surfaceClassFromCompetitorType(stored) : void 0;
|
|
1907
|
+
const { category } = categorizeSource(domain);
|
|
1908
|
+
const cls = classifySurfaceFromCategory(domain, category, context, storedClass);
|
|
1909
|
+
if (cls !== SurfaceClasses.other) out.set(domain, cls);
|
|
1910
|
+
}
|
|
1911
|
+
return out;
|
|
1912
|
+
}
|
|
1901
1913
|
|
|
1902
1914
|
// ../contracts/src/analytics.ts
|
|
1903
1915
|
var metricsWindowSchema = z18.enum(["7d", "30d", "90d", "all"]);
|
|
@@ -2575,17 +2587,17 @@ function winnabilityClassLabel(winnabilityClass) {
|
|
|
2575
2587
|
}
|
|
2576
2588
|
}
|
|
2577
2589
|
var CEDED_SURFACE_THRESHOLD = 0.6;
|
|
2578
|
-
function deriveWinnabilityClass(citedSurfaceDomains,
|
|
2579
|
-
const hasCoverage = citedSurfaceDomains.some((d) =>
|
|
2580
|
-
if (citedSurfaceDomains.length === 0 ||
|
|
2590
|
+
function deriveWinnabilityClass(citedSurfaceDomains, surfaceClasses, threshold = CEDED_SURFACE_THRESHOLD) {
|
|
2591
|
+
const hasCoverage = citedSurfaceDomains.some((d) => surfaceClasses.has(d.domain));
|
|
2592
|
+
if (citedSurfaceDomains.length === 0 || surfaceClasses.size === 0 || !hasCoverage) {
|
|
2581
2593
|
return { winnabilityClass: WinnabilityClasses.ownable, winnability: null };
|
|
2582
2594
|
}
|
|
2583
2595
|
let total = 0;
|
|
2584
2596
|
let ceded = 0;
|
|
2585
2597
|
for (const { domain, citationCount } of citedSurfaceDomains) {
|
|
2586
2598
|
total += citationCount;
|
|
2587
|
-
const cls =
|
|
2588
|
-
if (cls ===
|
|
2599
|
+
const cls = surfaceClasses.get(domain);
|
|
2600
|
+
if (cls === SurfaceClasses["ota-aggregator"] || cls === SurfaceClasses["editorial-media"]) {
|
|
2589
2601
|
ceded += citationCount;
|
|
2590
2602
|
}
|
|
2591
2603
|
}
|
|
@@ -4331,6 +4343,7 @@ export {
|
|
|
4331
4343
|
surfaceClassLabel,
|
|
4332
4344
|
surfaceClassFromCompetitorType,
|
|
4333
4345
|
classifySurfaceFromCategory,
|
|
4346
|
+
classifyCitedSurface,
|
|
4334
4347
|
brandMetricsDtoSchema,
|
|
4335
4348
|
sourceBreakdownDtoSchema,
|
|
4336
4349
|
parseWindow,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
loadConfig,
|
|
10
10
|
loadConfigRaw,
|
|
11
11
|
saveConfigPatch
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-ZUBBADMR.js";
|
|
13
13
|
import {
|
|
14
14
|
CC_CACHE_DIR,
|
|
15
15
|
DUCKDB_SPEC,
|
|
@@ -95,7 +95,7 @@ import {
|
|
|
95
95
|
runs,
|
|
96
96
|
schedules,
|
|
97
97
|
usageCounters
|
|
98
|
-
} from "./chunk-
|
|
98
|
+
} from "./chunk-HSX32G47.js";
|
|
99
99
|
import {
|
|
100
100
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
101
101
|
AGENT_PROVIDER_IDS,
|
|
@@ -145,7 +145,7 @@ import {
|
|
|
145
145
|
validationError,
|
|
146
146
|
winnabilityClassLabel,
|
|
147
147
|
withRetry
|
|
148
|
-
} from "./chunk-
|
|
148
|
+
} from "./chunk-JXFNERK4.js";
|
|
149
149
|
|
|
150
150
|
// src/telemetry.ts
|
|
151
151
|
import crypto from "crypto";
|
|
@@ -5620,7 +5620,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
5620
5620
|
return result;
|
|
5621
5621
|
}
|
|
5622
5622
|
async function backfillInsightsCommand(project, opts) {
|
|
5623
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
5623
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-ZW3ARLJT.js");
|
|
5624
5624
|
const config = loadConfig();
|
|
5625
5625
|
const db = createClient(config.database);
|
|
5626
5626
|
migrate(db);
|
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-SIB4NMEH.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-ZUBBADMR.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-HSX32G47.js";
|
|
56
56
|
import {
|
|
57
57
|
CcReleaseSyncStatuses,
|
|
58
58
|
CheckScopes,
|
|
@@ -71,7 +71,7 @@ import {
|
|
|
71
71
|
providerQuotaPolicySchema,
|
|
72
72
|
resolveProviderInput,
|
|
73
73
|
winnabilityClassSchema
|
|
74
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-JXFNERK4.js";
|
|
75
75
|
|
|
76
76
|
// src/cli.ts
|
|
77
77
|
import { pathToFileURL } from "url";
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createServer
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-SIB4NMEH.js";
|
|
4
4
|
import {
|
|
5
5
|
loadConfig
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-ZUBBADMR.js";
|
|
7
|
+
import "./chunk-HSX32G47.js";
|
|
8
|
+
import "./chunk-JXFNERK4.js";
|
|
9
9
|
export {
|
|
10
10
|
createServer,
|
|
11
11
|
loadConfig
|
package/dist/mcp.js
CHANGED
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
PACKAGE_VERSION,
|
|
4
4
|
canonryMcpTools,
|
|
5
5
|
createApiClient
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-ZUBBADMR.js";
|
|
7
|
+
import "./chunk-JXFNERK4.js";
|
|
8
8
|
|
|
9
9
|
// src/mcp/cli.ts
|
|
10
10
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainyc/canonry",
|
|
3
|
-
"version": "4.72.
|
|
3
|
+
"version": "4.72.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Agent-first open-source AEO operating platform - track how answer engines cite your domain",
|
|
6
6
|
"license": "FSL-1.1-ALv2",
|
|
@@ -63,25 +63,25 @@
|
|
|
63
63
|
"tsup": "^8.5.1",
|
|
64
64
|
"tsx": "^4.19.0",
|
|
65
65
|
"@ainyc/canonry-api-client": "0.0.0",
|
|
66
|
+
"@ainyc/canonry-config": "0.0.0",
|
|
66
67
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
67
68
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
68
69
|
"@ainyc/canonry-db": "0.0.0",
|
|
69
|
-
"@ainyc/canonry-config": "0.0.0",
|
|
70
|
-
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
71
|
-
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
72
70
|
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
73
71
|
"@ainyc/canonry-integration-google": "0.0.0",
|
|
74
|
-
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
75
|
-
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
76
72
|
"@ainyc/canonry-integration-google-business-profile": "0.0.0",
|
|
73
|
+
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
74
|
+
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
75
|
+
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
77
76
|
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
77
|
+
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
78
|
+
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
79
|
+
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
78
80
|
"@ainyc/canonry-intelligence": "0.0.0",
|
|
79
81
|
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
80
82
|
"@ainyc/canonry-provider-local": "0.0.0",
|
|
81
|
-
"@ainyc/canonry-provider-
|
|
82
|
-
"@ainyc/canonry-provider-perplexity": "0.0.0"
|
|
83
|
-
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
84
|
-
"@ainyc/canonry-provider-openai": "0.0.0"
|
|
83
|
+
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
84
|
+
"@ainyc/canonry-provider-perplexity": "0.0.0"
|
|
85
85
|
},
|
|
86
86
|
"scripts": {
|
|
87
87
|
"build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",
|