@ainyc/canonry 4.106.2 → 4.108.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/assets/{BacklinksPage-BheRgyA3.js → BacklinksPage-Dr6MK4h1.js} +1 -1
- package/assets/assets/{ChartPrimitives-BnYX5sRb.js → ChartPrimitives-DGO0EGqM.js} +1 -1
- package/assets/assets/{ProjectPage-Bd3YW6WQ.js → ProjectPage-fHczny77.js} +1 -1
- package/assets/assets/{RunRow-CZ1bXteZ.js → RunRow-Br6uOqD1.js} +1 -1
- package/assets/assets/{RunsPage-BBEuL03-.js → RunsPage-MMEhx2vt.js} +1 -1
- package/assets/assets/{SettingsPage-CJ6kyLmY.js → SettingsPage-BjZZODA1.js} +1 -1
- package/assets/assets/{TrafficPage-DPrsjoFM.js → TrafficPage-BtMtH6FT.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-EdC_c26M.js → TrafficSourceDetailPage-DFFGJsVC.js} +1 -1
- package/assets/assets/{arrow-left-B4_PxNUG.js → arrow-left-DDnYTDM6.js} +1 -1
- package/assets/assets/{extract-error-message-DoIzPHJI.js → extract-error-message-B0KSa98X.js} +1 -1
- package/assets/assets/{index-Dr2rxkFR.js → index-imKX6Edq.js} +46 -46
- package/assets/assets/{trash-2-C9Ebw5p4.js → trash-2-BODtOdNo.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-F3MKVMS5.js → chunk-45YSA7GH.js} +84 -13
- package/dist/{chunk-VGMTLUUM.js → chunk-EKGKGKID.js} +2 -1
- package/dist/{chunk-2AWATO4I.js → chunk-EMG4LIUJ.js} +18 -5
- package/dist/{chunk-VOR5ZTUU.js → chunk-IQX7XXJN.js} +71 -0
- package/dist/cli.js +13 -8
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-JGZU27U3.js → intelligence-service-YDPWS7OC.js} +2 -2
- package/dist/mcp.js +2 -2
- package/package.json +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c}from"./index-
|
|
1
|
+
import{c}from"./index-imKX6Edq.js";const a=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],h=c("circle-check",a);const e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]],n=c("circle-question-mark",e);const o=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],s=c("download",o);const t=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],r=c("trash-2",t);export{h as C,s as D,r as T,n as a};
|
package/assets/index.html
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
|
|
13
13
|
<link rel="apple-touch-icon" href="./apple-touch-icon.png" />
|
|
14
14
|
<title>Canonry</title>
|
|
15
|
-
<script type="module" crossorigin src="./assets/index-
|
|
15
|
+
<script type="module" crossorigin src="./assets/index-imKX6Edq.js"></script>
|
|
16
16
|
<link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-Be8JdV5M.js">
|
|
17
17
|
<link rel="modulepreload" crossorigin href="./assets/vendor-radix-CQ77EO2y.js">
|
|
18
18
|
<link rel="modulepreload" crossorigin href="./assets/vendor-recharts-C9EZkgbP.js">
|
|
@@ -125,6 +125,7 @@ import {
|
|
|
125
125
|
emptyCitationVisibility,
|
|
126
126
|
escapeLikePattern,
|
|
127
127
|
extractAnswerMentions,
|
|
128
|
+
filterBrandedSeedCandidates,
|
|
128
129
|
findDuplicateLocationLabels,
|
|
129
130
|
forbidden,
|
|
130
131
|
formatAverageDelta,
|
|
@@ -183,6 +184,7 @@ import {
|
|
|
183
184
|
notFound,
|
|
184
185
|
notImplemented,
|
|
185
186
|
notificationDtoSchema,
|
|
187
|
+
orderLocationsDefaultFirst,
|
|
186
188
|
parseInclusiveEndMs,
|
|
187
189
|
parseReportPeriodDays,
|
|
188
190
|
parseRunError,
|
|
@@ -267,10 +269,10 @@ import {
|
|
|
267
269
|
wordpressSchemaDeployResultDtoSchema,
|
|
268
270
|
wordpressSchemaStatusResultDtoSchema,
|
|
269
271
|
wordpressStatusDtoSchema
|
|
270
|
-
} from "./chunk-
|
|
272
|
+
} from "./chunk-IQX7XXJN.js";
|
|
271
273
|
|
|
272
274
|
// src/intelligence-service.ts
|
|
273
|
-
import { eq as eq38, desc as desc18, asc as asc6, and as and28, ne as ne5, or as
|
|
275
|
+
import { eq as eq38, desc as desc18, asc as asc6, and as and28, ne as ne5, or as or6, inArray as inArray14, gte as gte7, lte as lte4 } from "drizzle-orm";
|
|
274
276
|
|
|
275
277
|
// ../db/src/client.ts
|
|
276
278
|
import { mkdirSync } from "fs";
|
|
@@ -1141,6 +1143,15 @@ var discoverySessions = sqliteTable("discovery_sessions", {
|
|
|
1141
1143
|
// seed time; nullable for legacy sessions. No gate/warning math reads these.
|
|
1142
1144
|
seedFromAnswerCount: integer("seed_from_answer_count"),
|
|
1143
1145
|
seedFromGroundingCount: integer("seed_from_grounding_count"),
|
|
1146
|
+
// Diagnostics: raw candidates dropped by the branded self-query filter
|
|
1147
|
+
// before seed_count_raw was recorded. Nullable for legacy sessions.
|
|
1148
|
+
seedBrandFilteredCount: integer("seed_brand_filtered_count"),
|
|
1149
|
+
// Buyer definition the session was seeded with; part of session identity
|
|
1150
|
+
// for in-flight consolidation (same ICP + different buyer never reuses).
|
|
1151
|
+
buyerDescription: text("buyer_description"),
|
|
1152
|
+
// Resolved service areas the session was seeded/probed with; part of session
|
|
1153
|
+
// identity for in-flight consolidation. Null on legacy sessions.
|
|
1154
|
+
locations: text("locations", { mode: "json" }).$type(),
|
|
1144
1155
|
dedupThreshold: real("dedup_threshold"),
|
|
1145
1156
|
probeCount: integer("probe_count"),
|
|
1146
1157
|
citedCount: integer("cited_count"),
|
|
@@ -3390,6 +3401,37 @@ var MIGRATION_VERSIONS = [
|
|
|
3390
3401
|
`ALTER TABLE discovery_sessions ADD COLUMN seed_from_answer_count INTEGER`,
|
|
3391
3402
|
`ALTER TABLE discovery_sessions ADD COLUMN seed_from_grounding_count INTEGER`
|
|
3392
3403
|
]
|
|
3404
|
+
},
|
|
3405
|
+
{
|
|
3406
|
+
version: 89,
|
|
3407
|
+
name: "discovery-session-brand-filter-count",
|
|
3408
|
+
statements: [
|
|
3409
|
+
// Diagnostics: raw candidates dropped by the branded self-query filter
|
|
3410
|
+
// before seed_count_raw was recorded. Nullable — legacy sessions stay
|
|
3411
|
+
// null. Idempotent (the runner swallows the duplicate-column error).
|
|
3412
|
+
`ALTER TABLE discovery_sessions ADD COLUMN seed_brand_filtered_count INTEGER`
|
|
3413
|
+
]
|
|
3414
|
+
},
|
|
3415
|
+
{
|
|
3416
|
+
version: 90,
|
|
3417
|
+
name: "discovery-session-buyer-description",
|
|
3418
|
+
statements: [
|
|
3419
|
+
// Buyer definition the session was seeded with. Part of the in-flight
|
|
3420
|
+
// consolidation identity (a request with a different buyer must never
|
|
3421
|
+
// reuse another buyer's session) and auditability for seed provenance.
|
|
3422
|
+
`ALTER TABLE discovery_sessions ADD COLUMN buyer_description TEXT`
|
|
3423
|
+
]
|
|
3424
|
+
},
|
|
3425
|
+
{
|
|
3426
|
+
version: 91,
|
|
3427
|
+
name: "discovery-session-locations",
|
|
3428
|
+
statements: [
|
|
3429
|
+
// Resolved service areas the session was seeded/probed with. Part of the
|
|
3430
|
+
// in-flight consolidation identity (a different location subset never
|
|
3431
|
+
// reuses another geo's session) and seed/probe provenance. Nullable —
|
|
3432
|
+
// legacy sessions stay null.
|
|
3433
|
+
`ALTER TABLE discovery_sessions ADD COLUMN locations TEXT`
|
|
3434
|
+
]
|
|
3393
3435
|
}
|
|
3394
3436
|
];
|
|
3395
3437
|
function rebuildBacklinkTableWithSource(tx, table) {
|
|
@@ -3582,7 +3624,7 @@ function getAppliedVersion(db) {
|
|
|
3582
3624
|
function recordMigration(db, version, name) {
|
|
3583
3625
|
db.run(sql`INSERT OR IGNORE INTO _migrations (version, name) VALUES (${version}, ${name})`);
|
|
3584
3626
|
}
|
|
3585
|
-
function migrate(db) {
|
|
3627
|
+
function migrate(db, versions = MIGRATION_VERSIONS) {
|
|
3586
3628
|
db.transaction((tx) => {
|
|
3587
3629
|
normalizeLegacyQuerySchema(tx);
|
|
3588
3630
|
});
|
|
@@ -3591,7 +3633,7 @@ function migrate(db) {
|
|
|
3591
3633
|
db.run(sql.raw(statement));
|
|
3592
3634
|
}
|
|
3593
3635
|
const appliedVersion = getAppliedVersion(db);
|
|
3594
|
-
for (const mv of
|
|
3636
|
+
for (const mv of versions) {
|
|
3595
3637
|
if (mv.version <= appliedVersion) continue;
|
|
3596
3638
|
db.transaction((tx) => {
|
|
3597
3639
|
for (const statement of mv.statements) {
|
|
@@ -18056,6 +18098,7 @@ var routeCatalog = [
|
|
|
18056
18098
|
type: "object",
|
|
18057
18099
|
properties: {
|
|
18058
18100
|
icpDescription: { type: "string", description: "Free-text ICP. Required if the project does not have spec.icpDescription stored." },
|
|
18101
|
+
buyerDescription: { type: "string", description: "Who evaluates or buys the offering, separate from the ICP. When present, every generated seed query is anchored on this buyer and the seed prompt enforces buyer-fit." },
|
|
18059
18102
|
dedupThreshold: { type: "number", description: "Cosine similarity threshold for clustering. Defaults to 0.95." },
|
|
18060
18103
|
maxProbes: { type: "integer", description: "Max canonical queries to probe in this session. Default 100, hard cap 500." },
|
|
18061
18104
|
probeConcurrency: {
|
|
@@ -33729,7 +33772,7 @@ async function doctorRoutes(app, opts) {
|
|
|
33729
33772
|
|
|
33730
33773
|
// ../api-routes/src/discovery/routes.ts
|
|
33731
33774
|
import crypto27 from "crypto";
|
|
33732
|
-
import { and as and26, desc as desc16, eq as eq35, gte as gte6, inArray as inArray12 } from "drizzle-orm";
|
|
33775
|
+
import { and as and26, desc as desc16, eq as eq35, gte as gte6, inArray as inArray12, isNull, or as or5 } from "drizzle-orm";
|
|
33733
33776
|
var MAX_INFLIGHT_DISCOVERY_AGE_MS = 2 * 60 * 60 * 1e3;
|
|
33734
33777
|
async function discoveryRoutes(app, opts) {
|
|
33735
33778
|
app.post("/projects/:name/discover/run", async (request, reply) => {
|
|
@@ -33749,9 +33792,9 @@ async function discoveryRoutes(app, opts) {
|
|
|
33749
33792
|
"icpDescription is required. Pass it in the request body or store it on the project (spec.icpDescription)."
|
|
33750
33793
|
);
|
|
33751
33794
|
}
|
|
33752
|
-
const locations =
|
|
33753
|
-
project.locations,
|
|
33754
|
-
|
|
33795
|
+
const locations = orderLocationsDefaultFirst(
|
|
33796
|
+
resolveLocations(project.locations, parsed.data.locations),
|
|
33797
|
+
project.defaultLocation
|
|
33755
33798
|
);
|
|
33756
33799
|
if (!opts.onDiscoveryRunRequested) {
|
|
33757
33800
|
throw validationError("Discovery is not available on this deployment.", {
|
|
@@ -33764,6 +33807,20 @@ async function discoveryRoutes(app, opts) {
|
|
|
33764
33807
|
const existing = tx.select({ id: discoverySessions.id, runId: discoverySessions.runId }).from(discoverySessions).where(and26(
|
|
33765
33808
|
eq35(discoverySessions.projectId, project.id),
|
|
33766
33809
|
eq35(discoverySessions.icpDescription, icpDescription),
|
|
33810
|
+
// Buyer is part of session identity: it changes the seed prompt's
|
|
33811
|
+
// semantics, so a request with a different (or no) buyer must start
|
|
33812
|
+
// its own session, never adopt another buyer's probes.
|
|
33813
|
+
parsed.data.buyerDescription == null ? isNull(discoverySessions.buyerDescription) : eq35(discoverySessions.buyerDescription, parsed.data.buyerDescription),
|
|
33814
|
+
// Locations are identity too: a different service-area subset seeds
|
|
33815
|
+
// and probes a different geo, so it must never reuse another geo's
|
|
33816
|
+
// session. resolveLocations is deterministic (project-config order),
|
|
33817
|
+
// so equal subsets always serialize identically. Legacy in-flight
|
|
33818
|
+
// rows (pre-91) carry NULL: on a NO-location project that geo is
|
|
33819
|
+
// unambiguous (always []), so NULL matches; on a project WITH
|
|
33820
|
+
// locations a NULL row's subset is unknowable, so it conservatively
|
|
33821
|
+
// never reuses — a one-time, bounded (2h window) non-reuse after
|
|
33822
|
+
// upgrade, never a wrong reuse.
|
|
33823
|
+
locations.length === 0 ? or5(isNull(discoverySessions.locations), eq35(discoverySessions.locations, locations)) : eq35(discoverySessions.locations, locations),
|
|
33767
33824
|
inArray12(discoverySessions.status, [
|
|
33768
33825
|
DiscoverySessionStatuses.queued,
|
|
33769
33826
|
DiscoverySessionStatuses.seeding,
|
|
@@ -33782,6 +33839,8 @@ async function discoveryRoutes(app, opts) {
|
|
|
33782
33839
|
runId,
|
|
33783
33840
|
status: DiscoverySessionStatuses.queued,
|
|
33784
33841
|
icpDescription,
|
|
33842
|
+
buyerDescription: parsed.data.buyerDescription ?? null,
|
|
33843
|
+
locations,
|
|
33785
33844
|
dedupThreshold: parsed.data.dedupThreshold,
|
|
33786
33845
|
competitorMap: [],
|
|
33787
33846
|
createdAt: now
|
|
@@ -33816,6 +33875,7 @@ async function discoveryRoutes(app, opts) {
|
|
|
33816
33875
|
sessionId: decision.sessionId,
|
|
33817
33876
|
projectId: project.id,
|
|
33818
33877
|
icpDescription,
|
|
33878
|
+
buyerDescription: parsed.data.buyerDescription,
|
|
33819
33879
|
dedupThreshold: parsed.data.dedupThreshold,
|
|
33820
33880
|
maxProbes: parsed.data.maxProbes,
|
|
33821
33881
|
probeConcurrency: parsed.data.probeConcurrency,
|
|
@@ -34070,6 +34130,9 @@ function serializeSession(row) {
|
|
|
34070
34130
|
seedCount: row.seedCount ?? null,
|
|
34071
34131
|
seedFromAnswerCount: row.seedFromAnswerCount ?? null,
|
|
34072
34132
|
seedFromGroundingCount: row.seedFromGroundingCount ?? null,
|
|
34133
|
+
seedBrandFilteredCount: row.seedBrandFilteredCount ?? null,
|
|
34134
|
+
buyerDescription: row.buyerDescription ?? null,
|
|
34135
|
+
locations: row.locations ?? null,
|
|
34073
34136
|
dedupThreshold: row.dedupThreshold ?? null,
|
|
34074
34137
|
probeCount: row.probeCount ?? null,
|
|
34075
34138
|
citedCount: row.citedCount ?? null,
|
|
@@ -34176,9 +34239,15 @@ async function executeDiscovery(opts) {
|
|
|
34176
34239
|
const seedResult = await opts.deps.seed({
|
|
34177
34240
|
project: opts.project,
|
|
34178
34241
|
icpDescription: opts.icpDescription,
|
|
34242
|
+
buyerDescription: opts.buyerDescription,
|
|
34179
34243
|
locations: opts.locations ?? []
|
|
34180
34244
|
});
|
|
34181
|
-
const
|
|
34245
|
+
const { kept: unbrandedCandidates, droppedBranded } = filterBrandedSeedCandidates({
|
|
34246
|
+
candidates: seedResult.candidates,
|
|
34247
|
+
brandNames: opts.project.brandNames ?? [],
|
|
34248
|
+
canonicalDomains: opts.project.canonicalDomains
|
|
34249
|
+
});
|
|
34250
|
+
const rawCandidates = dedupeStrings(unbrandedCandidates);
|
|
34182
34251
|
const seedCountRaw = rawCandidates.length;
|
|
34183
34252
|
const canonicals = await pickCanonicals(
|
|
34184
34253
|
rawCandidates,
|
|
@@ -34201,12 +34270,14 @@ async function executeDiscovery(opts) {
|
|
|
34201
34270
|
// the seed dep does not report the split. Not consumed by any gate.
|
|
34202
34271
|
seedFromAnswerCount: seedResult.fromAnswerCount ?? null,
|
|
34203
34272
|
seedFromGroundingCount: seedResult.fromGroundingCount ?? null,
|
|
34273
|
+
seedBrandFilteredCount: droppedBranded.length,
|
|
34204
34274
|
warning
|
|
34205
34275
|
}).where(eq36(discoverySessions.id, opts.sessionId)).run();
|
|
34276
|
+
const probeLocation = opts.locations?.[0];
|
|
34206
34277
|
const probeResults = await mapWithConcurrency(
|
|
34207
34278
|
probedCanonicals,
|
|
34208
34279
|
probeConcurrency,
|
|
34209
|
-
(query) => opts.deps.probe({ project: opts.project, query })
|
|
34280
|
+
(query) => opts.deps.probe({ project: opts.project, query, location: probeLocation })
|
|
34210
34281
|
);
|
|
34211
34282
|
const probeRows = [];
|
|
34212
34283
|
const buckets = { cited: 0, aspirational: 0, "wasted-surface": 0 };
|
|
@@ -35025,7 +35096,7 @@ var IntelligenceService = class {
|
|
|
35025
35096
|
const recentRuns = this.db.select().from(runs).where(
|
|
35026
35097
|
and28(
|
|
35027
35098
|
eq38(runs.projectId, projectId),
|
|
35028
|
-
|
|
35099
|
+
or6(eq38(runs.status, "completed"), eq38(runs.status, "partial")),
|
|
35029
35100
|
// Defensive: RunCoordinator already skips probes before this is
|
|
35030
35101
|
// called, but if a future call site invokes analyzeAndPersist
|
|
35031
35102
|
// directly for a probe, probes still must not pollute the
|
|
@@ -35328,7 +35399,7 @@ var IntelligenceService = class {
|
|
|
35328
35399
|
const allRuns = this.db.select().from(runs).where(
|
|
35329
35400
|
and28(
|
|
35330
35401
|
eq38(runs.projectId, project.id),
|
|
35331
|
-
|
|
35402
|
+
or6(eq38(runs.status, "completed"), eq38(runs.status, "partial")),
|
|
35332
35403
|
// Backfill must not replay probe runs as if they were real sweeps.
|
|
35333
35404
|
ne5(runs.trigger, RunTriggers.probe)
|
|
35334
35405
|
)
|
|
@@ -35506,7 +35577,7 @@ var IntelligenceService = class {
|
|
|
35506
35577
|
and28(
|
|
35507
35578
|
eq38(runs.projectId, projectId),
|
|
35508
35579
|
eq38(runs.kind, RunKinds["answer-visibility"]),
|
|
35509
|
-
|
|
35580
|
+
or6(eq38(runs.status, "completed"), eq38(runs.status, "partial")),
|
|
35510
35581
|
// Defensive — see top of file.
|
|
35511
35582
|
ne5(runs.trigger, RunTriggers.probe)
|
|
35512
35583
|
)
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
trafficConnectVercelRequestSchema,
|
|
26
26
|
trafficConnectWordpressRequestSchema,
|
|
27
27
|
trafficEventKindSchema
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-IQX7XXJN.js";
|
|
29
29
|
|
|
30
30
|
// src/config.ts
|
|
31
31
|
import fs from "fs";
|
|
@@ -5565,6 +5565,7 @@ var discoveryRunInputSchema = z2.object({
|
|
|
5565
5565
|
// Stronger descriptions for the LLM. The base Zod schema enforces the
|
|
5566
5566
|
// upper bound; this just clarifies the meaning of each knob.
|
|
5567
5567
|
icpDescription: z2.string().min(1).optional().describe("Free-text ICP description. If omitted, the project must already have spec.icpDescription stored."),
|
|
5568
|
+
buyerDescription: z2.string().min(1).optional().describe("Who evaluates or buys the offering, separate from the ICP. When present, every generated query is anchored on this buyer."),
|
|
5568
5569
|
dedupThreshold: z2.number().min(0).max(1).optional().describe("Cosine similarity threshold for clustering seed candidates. Defaults to 0.85. Lower values dedupe more aggressively."),
|
|
5569
5570
|
maxProbes: z2.number().int().positive().max(DISCOVERY_MAX_PROBES_CAP).optional().describe(`Max canonical queries to probe in this session. Default 100, hard cap ${DISCOVERY_MAX_PROBES_CAP}.`),
|
|
5570
5571
|
probeConcurrency: z2.number().int().min(1).max(DISCOVERY_PROBE_CONCURRENCY_CAP).optional().describe(`How many probes may run in parallel. Default 1 (strictly serial), hard cap ${DISCOVERY_PROBE_CONCURRENCY_CAP}. Probe rows are persisted in canonical order regardless of concurrency, so this only shortens wall-clock time.`)
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
loadConfig,
|
|
11
11
|
loadConfigRaw,
|
|
12
12
|
saveConfigPatch
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-EKGKGKID.js";
|
|
14
14
|
import {
|
|
15
15
|
CC_CACHE_DIR,
|
|
16
16
|
DUCKDB_SPEC,
|
|
@@ -115,7 +115,7 @@ import {
|
|
|
115
115
|
siteAuditPages,
|
|
116
116
|
siteAuditSnapshots,
|
|
117
117
|
usageCounters
|
|
118
|
-
} from "./chunk-
|
|
118
|
+
} from "./chunk-45YSA7GH.js";
|
|
119
119
|
import {
|
|
120
120
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
121
121
|
AGENT_PROVIDER_IDS,
|
|
@@ -178,7 +178,7 @@ import {
|
|
|
178
178
|
validationError,
|
|
179
179
|
winnabilityClassLabel,
|
|
180
180
|
withRetry
|
|
181
|
-
} from "./chunk-
|
|
181
|
+
} from "./chunk-IQX7XXJN.js";
|
|
182
182
|
|
|
183
183
|
// src/telemetry.ts
|
|
184
184
|
import crypto from "crypto";
|
|
@@ -5572,6 +5572,7 @@ async function executeDiscoveryRun(opts) {
|
|
|
5572
5572
|
sessionId: opts.sessionId,
|
|
5573
5573
|
project,
|
|
5574
5574
|
icpDescription: opts.icpDescription,
|
|
5575
|
+
buyerDescription: opts.buyerDescription,
|
|
5575
5576
|
dedupThreshold: opts.dedupThreshold,
|
|
5576
5577
|
maxProbes: opts.maxProbes,
|
|
5577
5578
|
probeConcurrency: opts.probeConcurrency,
|
|
@@ -5648,7 +5649,10 @@ function buildDefaultDeps(registry) {
|
|
|
5648
5649
|
{
|
|
5649
5650
|
query: input.query,
|
|
5650
5651
|
canonicalDomains: input.project.canonicalDomains,
|
|
5651
|
-
competitorDomains: input.project.competitorDomains
|
|
5652
|
+
competitorDomains: input.project.competitorDomains,
|
|
5653
|
+
// Same geo mechanism as sweeps: the provider renders the location
|
|
5654
|
+
// into the prompt so the probe measures from the buyer's area.
|
|
5655
|
+
...input.location ? { location: input.location } : {}
|
|
5652
5656
|
},
|
|
5653
5657
|
cfg
|
|
5654
5658
|
);
|
|
@@ -5765,11 +5769,17 @@ function buildLocationConstraint(locations) {
|
|
|
5765
5769
|
function buildSeedPrompt(input) {
|
|
5766
5770
|
const locationConstraint = buildLocationConstraint(input.locations ?? []);
|
|
5767
5771
|
const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
|
|
5772
|
+
const buyer = input.buyerDescription?.trim() ?? "";
|
|
5773
|
+
const brandIdentities = [...input.project.brandNames ?? [], ...input.project.canonicalDomains];
|
|
5768
5774
|
return [
|
|
5769
5775
|
"You are an AEO (Answer Engine Optimization) analyst expanding a tracked-query basket for a customer.",
|
|
5770
5776
|
"",
|
|
5771
5777
|
`Customer: ${input.project.name} (domains: ${input.project.canonicalDomains.join(", ")})`,
|
|
5772
5778
|
`ICP: ${input.icpDescription}`,
|
|
5779
|
+
...buyer ? [
|
|
5780
|
+
`Buyer: ${buyer}`,
|
|
5781
|
+
"Every query must be one this buyer would plausibly type into an answer engine. Skip queries only an industry insider, investor, or job seeker would ask."
|
|
5782
|
+
] : [],
|
|
5773
5783
|
...locationConstraint.length > 0 ? ["", ...locationConstraint] : [],
|
|
5774
5784
|
"",
|
|
5775
5785
|
"Brainstorm queries a member of this ICP would type into an AI answer engine (Gemini, ChatGPT, Perplexity). Generate candidates across the five intent buckets below \u2014 these are SEMANTICALLY DISTINCT search intents, not stylistic variants. A query should fit one bucket cleanly. Diversity across buckets is the point: it keeps the list from collapsing into near-synonyms of a single intent.",
|
|
@@ -5780,6 +5790,8 @@ function buildSeedPrompt(input) {
|
|
|
5780
5790
|
' 4. Comparative \u2014 the searcher is weighing named alternatives head-to-head. Templates: "X vs Y", "X or Y for Z", "alternatives to X".',
|
|
5781
5791
|
' 5. Transactional \u2014 the searcher is ready to act on a purchase or booking. Templates: "book X", "X pricing", "X discount code", "buy X online".',
|
|
5782
5792
|
"",
|
|
5793
|
+
`Hard rule: NEVER include the customer's own brand name or domain (${brandIdentities.join(", ") || input.project.name}) in any query. A buyer who already knows the business by name is out of scope for this list; the goal is queries where the customer must EARN the mention. Naming competitors or directories is fine (Navigational queries should target directories and platforms, never the customer).`,
|
|
5794
|
+
"",
|
|
5783
5795
|
`Generate EXACTLY ${QUERIES_PER_INTENT_BUCKET} queries per bucket \u2014 ${QUERIES_PER_INTENT_BUCKET * 5} total. Return ONE query per line. Plain text only \u2014 no numbering, bullets, quotes, bucket labels, or commentary.`
|
|
5784
5796
|
].join("\n");
|
|
5785
5797
|
}
|
|
@@ -6473,7 +6485,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
6473
6485
|
return result;
|
|
6474
6486
|
}
|
|
6475
6487
|
async function backfillInsightsCommand(project, opts) {
|
|
6476
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
6488
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-YDPWS7OC.js");
|
|
6477
6489
|
const config = loadConfig();
|
|
6478
6490
|
const db = createClient(config.database);
|
|
6479
6491
|
migrate(db);
|
|
@@ -11938,6 +11950,7 @@ async function createServer(opts) {
|
|
|
11938
11950
|
sessionId: input.sessionId,
|
|
11939
11951
|
projectId: input.projectId,
|
|
11940
11952
|
icpDescription: input.icpDescription,
|
|
11953
|
+
buyerDescription: input.buyerDescription,
|
|
11941
11954
|
dedupThreshold: input.dedupThreshold,
|
|
11942
11955
|
maxProbes: input.maxProbes,
|
|
11943
11956
|
probeConcurrency: input.probeConcurrency,
|
|
@@ -169,6 +169,12 @@ function hasLocationLabel(locations, label) {
|
|
|
169
169
|
if (!label) return true;
|
|
170
170
|
return locations.some((location) => location.label === label);
|
|
171
171
|
}
|
|
172
|
+
function orderLocationsDefaultFirst(locations, defaultLabel) {
|
|
173
|
+
if (!defaultLabel) return [...locations];
|
|
174
|
+
const index = locations.findIndex((l) => l.label === defaultLabel);
|
|
175
|
+
if (index <= 0) return [...locations];
|
|
176
|
+
return [locations[index], ...locations.slice(0, index), ...locations.slice(index + 1)];
|
|
177
|
+
}
|
|
172
178
|
function resolveLocations(projectLocations, requestedLabels) {
|
|
173
179
|
const normalizedRequest = (requestedLabels ?? []).map((label) => label.trim()).filter((label) => label.length > 0);
|
|
174
180
|
if (normalizedRequest.length === 0) return [...projectLocations];
|
|
@@ -2186,6 +2192,19 @@ var discoverySessionDtoSchema = z17.object({
|
|
|
2186
2192
|
*/
|
|
2187
2193
|
seedFromAnswerCount: z17.number().int().nullable().optional(),
|
|
2188
2194
|
seedFromGroundingCount: z17.number().int().nullable().optional(),
|
|
2195
|
+
/**
|
|
2196
|
+
* Diagnostics: how many raw seed candidates were dropped by the branded
|
|
2197
|
+
* self-query filter before seedCountRaw was recorded (the customer's own
|
|
2198
|
+
* brand or domain in the query text). Null on legacy sessions. Purely
|
|
2199
|
+
* additive: no gate or warning reads it.
|
|
2200
|
+
*/
|
|
2201
|
+
seedBrandFilteredCount: z17.number().int().nullable().optional(),
|
|
2202
|
+
/** Buyer definition the session was seeded with (part of session identity
|
|
2203
|
+
* for in-flight consolidation). Null on legacy / no-buyer sessions. */
|
|
2204
|
+
buyerDescription: z17.string().nullable().optional(),
|
|
2205
|
+
/** Resolved service areas the session was seeded/probed with (part of
|
|
2206
|
+
* session identity for in-flight consolidation). Null on legacy sessions. */
|
|
2207
|
+
locations: z17.array(locationContextSchema).nullable().optional(),
|
|
2189
2208
|
dedupThreshold: z17.number().nullable().optional(),
|
|
2190
2209
|
probeCount: z17.number().int().nullable().optional(),
|
|
2191
2210
|
citedCount: z17.number().int().nullable().default(null),
|
|
@@ -2219,8 +2238,58 @@ function seedCollapseWarning(input) {
|
|
|
2219
2238
|
const noun = canonicalCount === 1 ? "query" : "queries";
|
|
2220
2239
|
return `Seed dedup collapsed ${seedCountRaw} raw candidates into ${canonicalCount} canonical ${noun} at threshold ${dedupThreshold}. Distinct intents were likely merged into one cluster; re-run with a higher --dedup-threshold.`;
|
|
2221
2240
|
}
|
|
2241
|
+
function filterBrandedSeedCandidates(input) {
|
|
2242
|
+
const tokens = brandMatchTokens(input.brandNames, input.canonicalDomains);
|
|
2243
|
+
if (tokens.length === 0) return { kept: [...input.candidates], droppedBranded: [] };
|
|
2244
|
+
const kept = [];
|
|
2245
|
+
const droppedBranded = [];
|
|
2246
|
+
for (const candidate of input.candidates) {
|
|
2247
|
+
const normalized = normalizeForBrandMatch(candidate);
|
|
2248
|
+
if (tokens.some((token) => containsWholeToken(normalized, token))) droppedBranded.push(candidate);
|
|
2249
|
+
else kept.push(candidate);
|
|
2250
|
+
}
|
|
2251
|
+
return { kept, droppedBranded };
|
|
2252
|
+
}
|
|
2253
|
+
function normalizeForBrandMatch(text) {
|
|
2254
|
+
return text.toLowerCase().replace(/\s+/g, " ").trim();
|
|
2255
|
+
}
|
|
2256
|
+
function brandMatchTokens(brandNames, canonicalDomains) {
|
|
2257
|
+
const tokens = /* @__PURE__ */ new Set();
|
|
2258
|
+
for (const name of brandNames) {
|
|
2259
|
+
const normalized = normalizeForBrandMatch(name);
|
|
2260
|
+
if (normalized.length < 3) continue;
|
|
2261
|
+
tokens.add(normalized);
|
|
2262
|
+
const squashed = normalized.replace(/[^a-z0-9]/g, "");
|
|
2263
|
+
if (squashed.length >= 4 && squashed !== normalized) tokens.add(squashed);
|
|
2264
|
+
}
|
|
2265
|
+
for (const domain of canonicalDomains) {
|
|
2266
|
+
const host = hostOf(domain) ?? normalizeForBrandMatch(domain).replace(/^www\./, "");
|
|
2267
|
+
if (!host) continue;
|
|
2268
|
+
tokens.add(host);
|
|
2269
|
+
tokens.add(`www.${host}`);
|
|
2270
|
+
}
|
|
2271
|
+
return [...tokens];
|
|
2272
|
+
}
|
|
2273
|
+
function containsWholeToken(normalized, token) {
|
|
2274
|
+
let index = normalized.indexOf(token);
|
|
2275
|
+
while (index !== -1) {
|
|
2276
|
+
const before = index === 0 ? " " : normalized[index - 1];
|
|
2277
|
+
const afterIndex = index + token.length;
|
|
2278
|
+
const after = afterIndex >= normalized.length ? " " : normalized[afterIndex];
|
|
2279
|
+
if (!/[a-z0-9]/.test(before) && !/[a-z0-9]/.test(after)) return true;
|
|
2280
|
+
index = normalized.indexOf(token, index + 1);
|
|
2281
|
+
}
|
|
2282
|
+
return false;
|
|
2283
|
+
}
|
|
2222
2284
|
var discoveryRunRequestSchema = z17.object({
|
|
2223
2285
|
icpDescription: z17.string().min(1).optional(),
|
|
2286
|
+
/**
|
|
2287
|
+
* Who evaluates or buys the offering, separate from what is sold
|
|
2288
|
+
* (icpDescription). When present, the seed prompt anchors every generated
|
|
2289
|
+
* query on this buyer, so discovery selects buyer-fit demand instead of
|
|
2290
|
+
* generic provider comparisons.
|
|
2291
|
+
*/
|
|
2292
|
+
buyerDescription: z17.string().min(1).optional(),
|
|
2224
2293
|
dedupThreshold: z17.number().min(0).max(1).optional(),
|
|
2225
2294
|
maxProbes: z17.number().int().positive().max(DISCOVERY_MAX_PROBES_CAP).optional(),
|
|
2226
2295
|
/**
|
|
@@ -5531,6 +5600,7 @@ export {
|
|
|
5531
5600
|
runtimeStateMissing,
|
|
5532
5601
|
findDuplicateLocationLabels,
|
|
5533
5602
|
hasLocationLabel,
|
|
5603
|
+
orderLocationsDefaultFirst,
|
|
5534
5604
|
resolveLocations,
|
|
5535
5605
|
projectUpsertRequestSchema,
|
|
5536
5606
|
projectDtoSchema,
|
|
@@ -5660,6 +5730,7 @@ export {
|
|
|
5660
5730
|
DISCOVERY_DEFAULT_PROBE_CONCURRENCY,
|
|
5661
5731
|
DISCOVERY_DEFAULT_DEDUP_THRESHOLD,
|
|
5662
5732
|
seedCollapseWarning,
|
|
5733
|
+
filterBrandedSeedCandidates,
|
|
5663
5734
|
discoveryRunRequestSchema,
|
|
5664
5735
|
discoveryPromoteRequestSchema,
|
|
5665
5736
|
discoveryPromotePreviewSchema,
|
package/dist/cli.js
CHANGED
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
setTelemetrySource,
|
|
30
30
|
showFirstRunNotice,
|
|
31
31
|
trackEvent
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-EMG4LIUJ.js";
|
|
33
33
|
import {
|
|
34
34
|
CliError,
|
|
35
35
|
EXIT_SYSTEM_ERROR,
|
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
saveConfig,
|
|
47
47
|
saveConfigPatch,
|
|
48
48
|
usageError
|
|
49
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-EKGKGKID.js";
|
|
50
50
|
import {
|
|
51
51
|
apiKeys,
|
|
52
52
|
createClient,
|
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
projects,
|
|
55
55
|
queries,
|
|
56
56
|
renderReportHtml
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-45YSA7GH.js";
|
|
58
58
|
import {
|
|
59
59
|
BacklinkSources,
|
|
60
60
|
CcReleaseSyncStatuses,
|
|
@@ -80,7 +80,7 @@ import {
|
|
|
80
80
|
providerQuotaPolicySchema,
|
|
81
81
|
resolveProviderInput,
|
|
82
82
|
winnabilityClassSchema
|
|
83
|
-
} from "./chunk-
|
|
83
|
+
} from "./chunk-IQX7XXJN.js";
|
|
84
84
|
|
|
85
85
|
// src/cli.ts
|
|
86
86
|
import { pathToFileURL } from "url";
|
|
@@ -1655,6 +1655,7 @@ function getClient4() {
|
|
|
1655
1655
|
function buildRunBody(opts, icpDescription) {
|
|
1656
1656
|
const body = {};
|
|
1657
1657
|
if (icpDescription) body.icpDescription = icpDescription;
|
|
1658
|
+
if (opts.buyer !== void 0 && opts.buyer.trim() !== "") body.buyerDescription = opts.buyer;
|
|
1658
1659
|
if (opts.dedupThreshold !== void 0) body.dedupThreshold = opts.dedupThreshold;
|
|
1659
1660
|
if (opts.maxProbes !== void 0) body.maxProbes = opts.maxProbes;
|
|
1660
1661
|
if (opts.probeConcurrency !== void 0) body.probeConcurrency = opts.probeConcurrency;
|
|
@@ -2057,9 +2058,10 @@ Usage: ${usage}`,
|
|
|
2057
2058
|
var DISCOVER_CLI_COMMANDS = [
|
|
2058
2059
|
{
|
|
2059
2060
|
path: ["discover", "run"],
|
|
2060
|
-
usage: 'canonry discover run <project> [--icp "..."] [--icp-angle "..."] [--locations michigan,florida] [--dedup-threshold 0.95] [--max-probes 100] [--probe-concurrency 3] [--wait] [--format json]',
|
|
2061
|
+
usage: 'canonry discover run <project> [--icp "..."] [--buyer "..."] [--icp-angle "..."] [--locations michigan,florida] [--dedup-threshold 0.95] [--max-probes 100] [--probe-concurrency 3] [--wait] [--format json]',
|
|
2061
2062
|
options: {
|
|
2062
2063
|
icp: stringOption(),
|
|
2064
|
+
buyer: stringOption(),
|
|
2063
2065
|
"icp-angle": multiStringOption(),
|
|
2064
2066
|
locations: multiStringOption(),
|
|
2065
2067
|
"dedup-threshold": stringOption(),
|
|
@@ -2068,10 +2070,11 @@ var DISCOVER_CLI_COMMANDS = [
|
|
|
2068
2070
|
wait: { type: "boolean", default: false }
|
|
2069
2071
|
},
|
|
2070
2072
|
run: async (input) => {
|
|
2071
|
-
const usage = 'canonry discover run <project> [--icp "..."] [--icp-angle "..."] [--locations michigan,florida] [--dedup-threshold 0.95] [--max-probes 100] [--probe-concurrency 3] [--wait] [--format json]';
|
|
2073
|
+
const usage = 'canonry discover run <project> [--icp "..."] [--buyer "..."] [--icp-angle "..."] [--locations michigan,florida] [--dedup-threshold 0.95] [--max-probes 100] [--probe-concurrency 3] [--wait] [--format json]';
|
|
2072
2074
|
const project = requireProject(input, "discover.run", usage);
|
|
2073
2075
|
await discoverRun(project, {
|
|
2074
2076
|
icp: getString(input.values, "icp"),
|
|
2077
|
+
buyer: getString(input.values, "buyer"),
|
|
2075
2078
|
icpAngles: getStringArray(input.values, "icp-angle"),
|
|
2076
2079
|
locations: parseLocationsOption(input.values),
|
|
2077
2080
|
dedupThreshold: parseFloatOption(input.values, "dedup-threshold", usage),
|
|
@@ -2092,9 +2095,10 @@ var DISCOVER_CLI_COMMANDS = [
|
|
|
2092
2095
|
},
|
|
2093
2096
|
{
|
|
2094
2097
|
path: ["discover", "seed"],
|
|
2095
|
-
usage: 'canonry discover seed <project> [--icp "..."] [--icp-angle "..."] [--locations michigan,florida] [--dedup-threshold 0.95] [--max-probes 100] [--probe-concurrency 3] [--wait] [--format json]',
|
|
2098
|
+
usage: 'canonry discover seed <project> [--icp "..."] [--buyer "..."] [--icp-angle "..."] [--locations michigan,florida] [--dedup-threshold 0.95] [--max-probes 100] [--probe-concurrency 3] [--wait] [--format json]',
|
|
2096
2099
|
options: {
|
|
2097
2100
|
icp: stringOption(),
|
|
2101
|
+
buyer: stringOption(),
|
|
2098
2102
|
"icp-angle": multiStringOption(),
|
|
2099
2103
|
locations: multiStringOption(),
|
|
2100
2104
|
"dedup-threshold": stringOption(),
|
|
@@ -2103,10 +2107,11 @@ var DISCOVER_CLI_COMMANDS = [
|
|
|
2103
2107
|
wait: { type: "boolean", default: false }
|
|
2104
2108
|
},
|
|
2105
2109
|
run: async (input) => {
|
|
2106
|
-
const usage = 'canonry discover seed <project> [--icp "..."] [--icp-angle "..."] [--locations michigan,florida] [--dedup-threshold 0.95] [--max-probes 100] [--probe-concurrency 3] [--wait] [--format json]';
|
|
2110
|
+
const usage = 'canonry discover seed <project> [--icp "..."] [--buyer "..."] [--icp-angle "..."] [--locations michigan,florida] [--dedup-threshold 0.95] [--max-probes 100] [--probe-concurrency 3] [--wait] [--format json]';
|
|
2107
2111
|
const project = requireProject(input, "discover.seed", usage);
|
|
2108
2112
|
await discoverSeed(project, {
|
|
2109
2113
|
icp: getString(input.values, "icp"),
|
|
2114
|
+
buyer: getString(input.values, "buyer"),
|
|
2110
2115
|
icpAngles: getStringArray(input.values, "icp-angle"),
|
|
2111
2116
|
locations: parseLocationsOption(input.values),
|
|
2112
2117
|
dedupThreshold: parseFloatOption(input.values, "dedup-threshold", usage),
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createServer
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-EMG4LIUJ.js";
|
|
4
4
|
import {
|
|
5
5
|
loadConfig
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-EKGKGKID.js";
|
|
7
|
+
import "./chunk-45YSA7GH.js";
|
|
8
|
+
import "./chunk-IQX7XXJN.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-EKGKGKID.js";
|
|
7
7
|
import {
|
|
8
8
|
isReadOnlyKey
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-IQX7XXJN.js";
|
|
10
10
|
|
|
11
11
|
// src/mcp/cli.ts
|
|
12
12
|
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.
|
|
3
|
+
"version": "4.108.0",
|
|
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",
|
|
@@ -66,26 +66,26 @@
|
|
|
66
66
|
"tsup": "^8.5.1",
|
|
67
67
|
"tsx": "^4.19.0",
|
|
68
68
|
"@ainyc/canonry-api-client": "0.0.0",
|
|
69
|
-
"@ainyc/canonry-api-routes": "0.0.0",
|
|
70
|
-
"@ainyc/canonry-db": "0.0.0",
|
|
71
69
|
"@ainyc/canonry-config": "0.0.0",
|
|
70
|
+
"@ainyc/canonry-api-routes": "0.0.0",
|
|
72
71
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
72
|
+
"@ainyc/canonry-db": "0.0.0",
|
|
73
73
|
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
74
74
|
"@ainyc/canonry-integration-openai-ads": "0.0.0",
|
|
75
75
|
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
76
76
|
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
77
77
|
"@ainyc/canonry-integration-google": "0.0.0",
|
|
78
|
-
"@ainyc/canonry-integration-google-business-profile": "0.0.0",
|
|
79
78
|
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
80
79
|
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
80
|
+
"@ainyc/canonry-integration-google-business-profile": "0.0.0",
|
|
81
|
+
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
81
82
|
"@ainyc/canonry-intelligence": "0.0.0",
|
|
82
83
|
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
83
|
-
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
84
|
-
"@ainyc/canonry-provider-local": "0.0.0",
|
|
85
84
|
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
86
|
-
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
87
85
|
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
88
|
-
"@ainyc/canonry-provider-perplexity": "0.0.0"
|
|
86
|
+
"@ainyc/canonry-provider-perplexity": "0.0.0",
|
|
87
|
+
"@ainyc/canonry-provider-local": "0.0.0",
|
|
88
|
+
"@ainyc/canonry-provider-openai": "0.0.0"
|
|
89
89
|
},
|
|
90
90
|
"scripts": {
|
|
91
91
|
"build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",
|