@ainyc/canonry 4.33.0 → 4.34.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.
|
@@ -123,7 +123,14 @@ var runs = sqliteTable("runs", {
|
|
|
123
123
|
var querySnapshots = sqliteTable("query_snapshots", {
|
|
124
124
|
id: text("id").primaryKey(),
|
|
125
125
|
runId: text("run_id").notNull().references(() => runs.id, { onDelete: "cascade" }),
|
|
126
|
-
|
|
126
|
+
// `query_id` is nullable + `ON DELETE SET NULL` so historical snapshots
|
|
127
|
+
// outlive their queries row. Pre-v58 this FK cascaded — deleting a tracked
|
|
128
|
+
// query (PUT /queries replace, individual delete, `canonry apply` dropping
|
|
129
|
+
// one) silently wiped the entire citation history for that query. With SET
|
|
130
|
+
// NULL the snapshot survives; `queryText` keeps it self-describing when
|
|
131
|
+
// the queries row is gone.
|
|
132
|
+
queryId: text("query_id").references(() => queries.id, { onDelete: "set null" }),
|
|
133
|
+
queryText: text("query_text"),
|
|
127
134
|
provider: text("provider").notNull().default("gemini"),
|
|
128
135
|
model: text("model"),
|
|
129
136
|
citationState: text("citation_state").notNull(),
|
|
@@ -1804,6 +1811,80 @@ var MIGRATION_VERSIONS = [
|
|
|
1804
1811
|
statements: [
|
|
1805
1812
|
`ALTER TABLE runs ADD COLUMN queries TEXT`
|
|
1806
1813
|
]
|
|
1814
|
+
},
|
|
1815
|
+
{
|
|
1816
|
+
version: 58,
|
|
1817
|
+
name: "snapshots-preserve-on-query-delete",
|
|
1818
|
+
// The legacy `query_snapshots.query_id` FK was `ON DELETE CASCADE`, so a
|
|
1819
|
+
// routine basket edit (PUT /queries replace, individual delete, `canonry
|
|
1820
|
+
// apply` dropping a query) silently destroyed every historical citation
|
|
1821
|
+
// snapshot for the removed queries — the regression history, transitions,
|
|
1822
|
+
// and competitor-overlap evidence that are canonry's whole value.
|
|
1823
|
+
//
|
|
1824
|
+
// Fix: rebuild `query_snapshots` with `query_id` nullable + `ON DELETE
|
|
1825
|
+
// SET NULL`, and add a denormalized `query_text` column populated from
|
|
1826
|
+
// `queries.query` via the join. SQLite can't change FK or NOT NULL in
|
|
1827
|
+
// place — same canonical table-rebuild pattern v53 used. All statements
|
|
1828
|
+
// run inside the migration runner's single transaction.
|
|
1829
|
+
//
|
|
1830
|
+
// `run_id` keeps `ON DELETE CASCADE` — deleting a run legitimately
|
|
1831
|
+
// removes its snapshots. Indexes are recreated on the renamed table.
|
|
1832
|
+
statements: [
|
|
1833
|
+
`CREATE TABLE IF NOT EXISTS query_snapshots_v58 (
|
|
1834
|
+
id TEXT PRIMARY KEY,
|
|
1835
|
+
run_id TEXT NOT NULL REFERENCES runs(id) ON DELETE CASCADE,
|
|
1836
|
+
query_id TEXT REFERENCES queries(id) ON DELETE SET NULL,
|
|
1837
|
+
query_text TEXT,
|
|
1838
|
+
provider TEXT NOT NULL DEFAULT 'gemini',
|
|
1839
|
+
model TEXT,
|
|
1840
|
+
citation_state TEXT NOT NULL,
|
|
1841
|
+
answer_mentioned INTEGER,
|
|
1842
|
+
answer_text TEXT,
|
|
1843
|
+
cited_domains TEXT NOT NULL DEFAULT '[]',
|
|
1844
|
+
competitor_overlap TEXT NOT NULL DEFAULT '[]',
|
|
1845
|
+
recommended_competitors TEXT NOT NULL DEFAULT '[]',
|
|
1846
|
+
location TEXT,
|
|
1847
|
+
screenshot_path TEXT,
|
|
1848
|
+
raw_response TEXT,
|
|
1849
|
+
created_at TEXT NOT NULL
|
|
1850
|
+
)`,
|
|
1851
|
+
// Backfill `query_text` from joined queries.query so existing snapshots
|
|
1852
|
+
// stay readable even if their query is later deleted.
|
|
1853
|
+
//
|
|
1854
|
+
// IMPORTANT: we use `q.id` (the JOINED queries.id), not `qs.query_id`.
|
|
1855
|
+
// Production DBs may already contain snapshots whose `qs.query_id`
|
|
1856
|
+
// dangles — a queries row was hard-deleted at some point without
|
|
1857
|
+
// cascading (PRAGMA foreign_keys was OFF, or pre-FK schema). Copying
|
|
1858
|
+
// `qs.query_id` directly would re-introduce those dangling refs into
|
|
1859
|
+
// the new table, which now validates them at INSERT (the new FK still
|
|
1860
|
+
// requires query_id values to match queries.id when non-null). Reading
|
|
1861
|
+
// through the LEFT JOIN forces every value to be either a valid `q.id`
|
|
1862
|
+
// or NULL — pre-existing orphans land with NULL `query_id` / NULL
|
|
1863
|
+
// `query_text`, preserving the snapshot row instead of failing the
|
|
1864
|
+
// migration. The May 2026 azcoatings DB had 459 such pre-existing
|
|
1865
|
+
// orphans; without this guard, migrate() throws SQLITE_CONSTRAINT_FOREIGNKEY.
|
|
1866
|
+
`INSERT INTO query_snapshots_v58 (
|
|
1867
|
+
id, run_id, query_id, query_text, provider, model, citation_state,
|
|
1868
|
+
answer_mentioned, answer_text, cited_domains, competitor_overlap,
|
|
1869
|
+
recommended_competitors, location, screenshot_path, raw_response,
|
|
1870
|
+
created_at
|
|
1871
|
+
)
|
|
1872
|
+
SELECT qs.id, qs.run_id, q.id, q.query, qs.provider, qs.model,
|
|
1873
|
+
qs.citation_state, qs.answer_mentioned, qs.answer_text,
|
|
1874
|
+
qs.cited_domains, qs.competitor_overlap, qs.recommended_competitors,
|
|
1875
|
+
qs.location, qs.screenshot_path, qs.raw_response, qs.created_at
|
|
1876
|
+
FROM query_snapshots qs
|
|
1877
|
+
LEFT JOIN queries q ON q.id = qs.query_id`,
|
|
1878
|
+
`DROP TABLE query_snapshots`,
|
|
1879
|
+
`ALTER TABLE query_snapshots_v58 RENAME TO query_snapshots`,
|
|
1880
|
+
// Recreate the indexes that didn't survive the rename.
|
|
1881
|
+
`CREATE INDEX IF NOT EXISTS idx_snapshots_run ON query_snapshots(run_id)`,
|
|
1882
|
+
`CREATE INDEX IF NOT EXISTS idx_snapshots_query ON query_snapshots(query_id)`,
|
|
1883
|
+
`CREATE INDEX IF NOT EXISTS idx_snapshots_citation_state ON query_snapshots(citation_state)`,
|
|
1884
|
+
`CREATE INDEX IF NOT EXISTS idx_snapshots_provider_model ON query_snapshots(provider, model)`,
|
|
1885
|
+
`CREATE INDEX IF NOT EXISTS idx_snapshots_location ON query_snapshots(location)`,
|
|
1886
|
+
`CREATE INDEX IF NOT EXISTS idx_snapshots_created_at ON query_snapshots(created_at)`
|
|
1887
|
+
]
|
|
1807
1888
|
}
|
|
1808
1889
|
];
|
|
1809
1890
|
function isDuplicateColumnError(err) {
|
|
@@ -1987,6 +2068,11 @@ function pickGroupRepresentative(group) {
|
|
|
1987
2068
|
return best;
|
|
1988
2069
|
}
|
|
1989
2070
|
|
|
2071
|
+
// ../db/src/snapshot-helpers.ts
|
|
2072
|
+
function filterTrackedSnapshots(rows) {
|
|
2073
|
+
return rows.filter((r) => r.queryId !== null);
|
|
2074
|
+
}
|
|
2075
|
+
|
|
1990
2076
|
// ../intelligence/src/regressions.ts
|
|
1991
2077
|
function detectRegressions(currentRun, previousRun) {
|
|
1992
2078
|
const regressions = [];
|
|
@@ -3707,6 +3793,7 @@ export {
|
|
|
3707
3793
|
migrate,
|
|
3708
3794
|
groupRunsByCreatedAt,
|
|
3709
3795
|
pickGroupRepresentative,
|
|
3796
|
+
filterTrackedSnapshots,
|
|
3710
3797
|
isBlogShapedQuery,
|
|
3711
3798
|
buildInventory,
|
|
3712
3799
|
buildContentTargetRows,
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
discoverySessions,
|
|
45
45
|
dropLegacyCredentialColumns,
|
|
46
46
|
extractLegacyCredentials,
|
|
47
|
+
filterTrackedSnapshots,
|
|
47
48
|
gaAiReferrals,
|
|
48
49
|
gaSocialReferrals,
|
|
49
50
|
gaTrafficSnapshots,
|
|
@@ -70,7 +71,7 @@ import {
|
|
|
70
71
|
schedules,
|
|
71
72
|
trafficSources,
|
|
72
73
|
usageCounters
|
|
73
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-7256SFYT.js";
|
|
74
75
|
import {
|
|
75
76
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
76
77
|
AGENT_PROVIDER_IDS,
|
|
@@ -2292,7 +2293,7 @@ async function analyticsRoutes(app) {
|
|
|
2292
2293
|
});
|
|
2293
2294
|
}
|
|
2294
2295
|
const runIds = projectRuns.map((r) => r.id);
|
|
2295
|
-
const rawSnapshots = app.db.select({
|
|
2296
|
+
const rawSnapshots = filterTrackedSnapshots(app.db.select({
|
|
2296
2297
|
runId: querySnapshots.runId,
|
|
2297
2298
|
queryId: querySnapshots.queryId,
|
|
2298
2299
|
provider: querySnapshots.provider,
|
|
@@ -2300,7 +2301,7 @@ async function analyticsRoutes(app) {
|
|
|
2300
2301
|
answerMentioned: querySnapshots.answerMentioned,
|
|
2301
2302
|
answerText: querySnapshots.answerText,
|
|
2302
2303
|
createdAt: querySnapshots.createdAt
|
|
2303
|
-
}).from(querySnapshots).where(inArray2(querySnapshots.runId, runIds)).all();
|
|
2304
|
+
}).from(querySnapshots).where(inArray2(querySnapshots.runId, runIds)).all());
|
|
2304
2305
|
const allSnapshots = rawSnapshots.map((s) => ({
|
|
2305
2306
|
...s,
|
|
2306
2307
|
resolvedMentioned: resolveSnapshotAnswerMentioned(s, project)
|
|
@@ -2339,13 +2340,13 @@ async function analyticsRoutes(app) {
|
|
|
2339
2340
|
const runIdToCreatedAt = new Map(windowRuns.map((r) => [r.id, r.createdAt]));
|
|
2340
2341
|
const consistencyMap = /* @__PURE__ */ new Map();
|
|
2341
2342
|
if (windowRunIds.length > 0) {
|
|
2342
|
-
const allWindowSnaps = app.db.select({
|
|
2343
|
+
const allWindowSnaps = filterTrackedSnapshots(app.db.select({
|
|
2343
2344
|
queryId: querySnapshots.queryId,
|
|
2344
2345
|
runId: querySnapshots.runId,
|
|
2345
2346
|
citationState: querySnapshots.citationState,
|
|
2346
2347
|
answerMentioned: querySnapshots.answerMentioned,
|
|
2347
2348
|
answerText: querySnapshots.answerText
|
|
2348
|
-
}).from(querySnapshots).where(inArray2(querySnapshots.runId, windowRunIds)).all();
|
|
2349
|
+
}).from(querySnapshots).where(inArray2(querySnapshots.runId, windowRunIds)).all());
|
|
2349
2350
|
for (const s of allWindowSnaps) {
|
|
2350
2351
|
const timePoint = runIdToCreatedAt.get(s.runId) ?? s.runId;
|
|
2351
2352
|
let entry = consistencyMap.get(s.queryId);
|
|
@@ -2358,7 +2359,7 @@ async function analyticsRoutes(app) {
|
|
|
2358
2359
|
if (resolveSnapshotAnswerMentioned(s, project)) entry.mentionedRuns.add(timePoint);
|
|
2359
2360
|
}
|
|
2360
2361
|
}
|
|
2361
|
-
const rawSnapshots = app.db.select({
|
|
2362
|
+
const rawSnapshots = filterTrackedSnapshots(app.db.select({
|
|
2362
2363
|
queryId: querySnapshots.queryId,
|
|
2363
2364
|
query: queries.query,
|
|
2364
2365
|
provider: querySnapshots.provider,
|
|
@@ -2366,7 +2367,7 @@ async function analyticsRoutes(app) {
|
|
|
2366
2367
|
answerMentioned: querySnapshots.answerMentioned,
|
|
2367
2368
|
answerText: querySnapshots.answerText,
|
|
2368
2369
|
competitorOverlap: querySnapshots.competitorOverlap
|
|
2369
|
-
}).from(querySnapshots).leftJoin(queries, eq10(querySnapshots.queryId, queries.id)).where(inArray2(querySnapshots.runId, latestGroupRunIds)).all();
|
|
2370
|
+
}).from(querySnapshots).leftJoin(queries, eq10(querySnapshots.queryId, queries.id)).where(inArray2(querySnapshots.runId, latestGroupRunIds)).all());
|
|
2370
2371
|
const snapshots = rawSnapshots.map((s) => ({
|
|
2371
2372
|
...s,
|
|
2372
2373
|
resolvedMentioned: resolveSnapshotAnswerMentioned(s, project)
|
|
@@ -5173,7 +5174,7 @@ function buildCandidateQueries(opts) {
|
|
|
5173
5174
|
const queryRows = opts.db.select({ id: queries.id, text: queries.query }).from(queries).where(eq12(queries.projectId, opts.projectId)).all();
|
|
5174
5175
|
const queryIdByText = new Map(queryRows.map((r) => [r.text, r.id]));
|
|
5175
5176
|
const candidateQueryIds = opts.candidateQueryStrings.map((q) => queryIdByText.get(q)).filter((id) => Boolean(id));
|
|
5176
|
-
const snapshotRows = opts.db.select().from(querySnapshots).where(inArray4(querySnapshots.runId, opts.recentRunIds)).all().filter((r) => candidateQueryIds.includes(r.queryId));
|
|
5177
|
+
const snapshotRows = filterTrackedSnapshots(opts.db.select().from(querySnapshots).where(inArray4(querySnapshots.runId, opts.recentRunIds)).all()).filter((r) => candidateQueryIds.includes(r.queryId));
|
|
5177
5178
|
const snapshotsByQuery = /* @__PURE__ */ new Map();
|
|
5178
5179
|
for (const row of snapshotRows) {
|
|
5179
5180
|
const list = snapshotsByQuery.get(row.queryId) ?? [];
|
|
@@ -5392,7 +5393,7 @@ function loadSnapshotsForRun(db, runId) {
|
|
|
5392
5393
|
function loadSnapshotsForRunIds(db, runIds) {
|
|
5393
5394
|
if (runIds.length === 0) return [];
|
|
5394
5395
|
const rows = db.select().from(querySnapshots).where(inArray5(querySnapshots.runId, [...runIds])).all();
|
|
5395
|
-
return rows.map((r) => ({
|
|
5396
|
+
return rows.filter((r) => r.queryId !== null).map((r) => ({
|
|
5396
5397
|
id: r.id,
|
|
5397
5398
|
runId: r.runId,
|
|
5398
5399
|
queryId: r.queryId,
|
|
@@ -6761,8 +6762,9 @@ async function citationRoutes(app) {
|
|
|
6761
6762
|
if (rawSnapshots.length === 0) {
|
|
6762
6763
|
return reply.send(emptyCitationVisibility("no-runs-yet"));
|
|
6763
6764
|
}
|
|
6764
|
-
const snapshots = rawSnapshots.map((s) => ({
|
|
6765
|
+
const snapshots = rawSnapshots.filter((s) => s.queryId !== null).map((s) => ({
|
|
6765
6766
|
...s,
|
|
6767
|
+
queryId: s.queryId,
|
|
6766
6768
|
runCreatedAt: runCreatedAt.get(s.runId) ?? s.createdAt
|
|
6767
6769
|
}));
|
|
6768
6770
|
const projectCompetitors = app.db.select({ domain: competitors.domain }).from(competitors).where(eq14(competitors.projectId, project.id)).all().map((c) => normalizeDomain2(c.domain)).filter((d) => d.length > 0);
|
|
@@ -6998,7 +7000,7 @@ async function compositeRoutes(app) {
|
|
|
6998
7000
|
const limit = clampSearchLimit(request.query.limit);
|
|
6999
7001
|
const escaped = escapeLikePattern(rawQuery);
|
|
7000
7002
|
const pattern = `%${escaped}%`;
|
|
7001
|
-
const snapshotMatches = app.db.select({
|
|
7003
|
+
const snapshotMatches = filterTrackedSnapshots(app.db.select({
|
|
7002
7004
|
id: querySnapshots.id,
|
|
7003
7005
|
runId: querySnapshots.runId,
|
|
7004
7006
|
queryId: querySnapshots.queryId,
|
|
@@ -7020,7 +7022,7 @@ async function compositeRoutes(app) {
|
|
|
7020
7022
|
like(queries.query, pattern)
|
|
7021
7023
|
)
|
|
7022
7024
|
)
|
|
7023
|
-
).orderBy(desc7(querySnapshots.createdAt)).limit(limit + 1).all();
|
|
7025
|
+
).orderBy(desc7(querySnapshots.createdAt)).limit(limit + 1).all());
|
|
7024
7026
|
const insightMatches = app.db.select().from(insights).where(
|
|
7025
7027
|
and6(
|
|
7026
7028
|
eq15(insights.projectId, project.id),
|
|
@@ -7094,7 +7096,7 @@ function summarizeRun(run) {
|
|
|
7094
7096
|
function loadSnapshotsByRunIds(app, runIds) {
|
|
7095
7097
|
const result = /* @__PURE__ */ new Map();
|
|
7096
7098
|
if (runIds.length === 0) return result;
|
|
7097
|
-
const rows = app.db.select({
|
|
7099
|
+
const rows = filterTrackedSnapshots(app.db.select({
|
|
7098
7100
|
runId: querySnapshots.runId,
|
|
7099
7101
|
queryId: querySnapshots.queryId,
|
|
7100
7102
|
provider: querySnapshots.provider,
|
|
@@ -7102,7 +7104,7 @@ function loadSnapshotsByRunIds(app, runIds) {
|
|
|
7102
7104
|
citationState: querySnapshots.citationState,
|
|
7103
7105
|
competitorOverlap: querySnapshots.competitorOverlap,
|
|
7104
7106
|
citedDomains: querySnapshots.citedDomains
|
|
7105
|
-
}).from(querySnapshots).where(inArray7(querySnapshots.runId, [...runIds])).all();
|
|
7107
|
+
}).from(querySnapshots).where(inArray7(querySnapshots.runId, [...runIds])).all());
|
|
7106
7108
|
for (const row of rows) {
|
|
7107
7109
|
const list = result.get(row.runId) ?? [];
|
|
7108
7110
|
list.push({
|
|
@@ -10388,7 +10390,7 @@ var routeCatalog = [
|
|
|
10388
10390
|
method: "post",
|
|
10389
10391
|
path: "/api/v1/projects/{name}/discover/run",
|
|
10390
10392
|
summary: "Start a tracked-basket discovery session",
|
|
10391
|
-
description: 'Kicks off a discovery session for the project. The pipeline: ICP description \u2192 Gemini grounded seed prompt \u2192 embed + cluster (cosine \u2265 0.85 by default) \u2192 pick canonical representatives \u2192 probe each canonical via Gemini grounding \u2192 classify into cited / aspirational / wasted-surface \u2192 aggregate competitor map. Returns immediately with `{ runId, sessionId, status: "running" }`; the actual work runs in the background. Poll `GET /projects/{name}/discover/sessions/{id}` until `status` is `completed` or `failed`.',
|
|
10393
|
+
description: 'Kicks off a discovery session for the project. The pipeline: ICP description \u2192 Gemini grounded seed prompt \u2192 embed + cluster (cosine \u2265 0.85 by default) \u2192 pick canonical representatives \u2192 probe each canonical via Gemini grounding \u2192 classify into cited / aspirational / wasted-surface \u2192 aggregate competitor map. Returns immediately with `{ runId, sessionId, status: "running", consolidated }`; the actual work runs in the background. Poll `GET /projects/{name}/discover/sessions/{id}` until `status` is `completed` or `failed`. Concurrent/duplicate requests for the same (project, ICP) are consolidated onto a single in-flight session: the response carries `consolidated: true` and `200 OK` instead of `201`, and the request\'s `dedupThreshold` / `maxProbes` are ignored (the in-flight session keeps its original config).',
|
|
10392
10394
|
tags: ["discovery"],
|
|
10393
10395
|
parameters: [nameParameter],
|
|
10394
10396
|
requestBody: {
|
|
@@ -10412,7 +10414,8 @@ var routeCatalog = [
|
|
|
10412
10414
|
}
|
|
10413
10415
|
},
|
|
10414
10416
|
responses: {
|
|
10415
|
-
|
|
10417
|
+
200: { description: "An in-flight session with the same project + ICP was reused; returns { runId, sessionId, status, consolidated: true }. The request's dedupThreshold / maxProbes are ignored." },
|
|
10418
|
+
201: { description: "New discovery session enqueued; returns { runId, sessionId, status, consolidated: false }." },
|
|
10416
10419
|
400: { description: "Missing or invalid ICP / parameters." },
|
|
10417
10420
|
404: { description: "Project not found." }
|
|
10418
10421
|
}
|
|
@@ -13510,7 +13513,7 @@ async function cdpRoutes(app, opts) {
|
|
|
13510
13513
|
const err = notFound("Run", runId);
|
|
13511
13514
|
return reply.code(err.statusCode).send(err.toJSON());
|
|
13512
13515
|
}
|
|
13513
|
-
const snapshots = app.db.select({
|
|
13516
|
+
const snapshots = filterTrackedSnapshots(app.db.select({
|
|
13514
13517
|
id: querySnapshots.id,
|
|
13515
13518
|
queryId: querySnapshots.queryId,
|
|
13516
13519
|
provider: querySnapshots.provider,
|
|
@@ -13518,7 +13521,7 @@ async function cdpRoutes(app, opts) {
|
|
|
13518
13521
|
citedDomains: querySnapshots.citedDomains,
|
|
13519
13522
|
screenshotPath: querySnapshots.screenshotPath,
|
|
13520
13523
|
rawResponse: querySnapshots.rawResponse
|
|
13521
|
-
}).from(querySnapshots).where(eq20(querySnapshots.runId, runId)).all();
|
|
13524
|
+
}).from(querySnapshots).where(eq20(querySnapshots.runId, runId)).all());
|
|
13522
13525
|
const queryRows = app.db.select({ id: queries.id, query: queries.query }).from(queries).where(eq20(queries.projectId, project.id)).all();
|
|
13523
13526
|
const queryMap = new Map(queryRows.map((q) => [q.id, q.query]));
|
|
13524
13527
|
const byQuery = /* @__PURE__ */ new Map();
|
|
@@ -20009,7 +20012,8 @@ async function doctorRoutes(app, opts) {
|
|
|
20009
20012
|
|
|
20010
20013
|
// ../api-routes/src/discovery/routes.ts
|
|
20011
20014
|
import crypto21 from "crypto";
|
|
20012
|
-
import {
|
|
20015
|
+
import { and as and16, desc as desc13, eq as eq25, gte as gte4, inArray as inArray8 } from "drizzle-orm";
|
|
20016
|
+
var MAX_INFLIGHT_DISCOVERY_AGE_MS = 2 * 60 * 60 * 1e3;
|
|
20013
20017
|
async function discoveryRoutes(app, opts) {
|
|
20014
20018
|
app.post("/projects/:name/discover/run", async (request, reply) => {
|
|
20015
20019
|
const project = resolveProject(app.db, request.params.name);
|
|
@@ -20038,9 +20042,23 @@ async function discoveryRoutes(app, opts) {
|
|
|
20038
20042
|
});
|
|
20039
20043
|
}
|
|
20040
20044
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
20041
|
-
const
|
|
20042
|
-
const
|
|
20043
|
-
|
|
20045
|
+
const ageFloorIso = new Date(Date.now() - MAX_INFLIGHT_DISCOVERY_AGE_MS).toISOString();
|
|
20046
|
+
const decision = app.db.transaction((tx) => {
|
|
20047
|
+
const existing = tx.select({ id: discoverySessions.id, runId: discoverySessions.runId }).from(discoverySessions).where(and16(
|
|
20048
|
+
eq25(discoverySessions.projectId, project.id),
|
|
20049
|
+
eq25(discoverySessions.icpDescription, icpDescription),
|
|
20050
|
+
inArray8(discoverySessions.status, [
|
|
20051
|
+
DiscoverySessionStatuses.queued,
|
|
20052
|
+
DiscoverySessionStatuses.seeding,
|
|
20053
|
+
DiscoverySessionStatuses.probing
|
|
20054
|
+
]),
|
|
20055
|
+
gte4(discoverySessions.createdAt, ageFloorIso)
|
|
20056
|
+
)).orderBy(desc13(discoverySessions.createdAt)).get();
|
|
20057
|
+
if (existing && existing.runId) {
|
|
20058
|
+
return { reused: true, sessionId: existing.id, runId: existing.runId };
|
|
20059
|
+
}
|
|
20060
|
+
const sessionId = crypto21.randomUUID();
|
|
20061
|
+
const runId = crypto21.randomUUID();
|
|
20044
20062
|
tx.insert(discoverySessions).values({
|
|
20045
20063
|
id: sessionId,
|
|
20046
20064
|
projectId: project.id,
|
|
@@ -20066,17 +20084,31 @@ async function discoveryRoutes(app, opts) {
|
|
|
20066
20084
|
entityType: "discovery_session",
|
|
20067
20085
|
entityId: sessionId
|
|
20068
20086
|
});
|
|
20087
|
+
return { reused: false, sessionId, runId };
|
|
20069
20088
|
});
|
|
20089
|
+
if (decision.reused) {
|
|
20090
|
+
return reply.status(200).send({
|
|
20091
|
+
runId: decision.runId,
|
|
20092
|
+
sessionId: decision.sessionId,
|
|
20093
|
+
status: "running",
|
|
20094
|
+
consolidated: true
|
|
20095
|
+
});
|
|
20096
|
+
}
|
|
20070
20097
|
opts.onDiscoveryRunRequested({
|
|
20071
|
-
runId,
|
|
20072
|
-
sessionId,
|
|
20098
|
+
runId: decision.runId,
|
|
20099
|
+
sessionId: decision.sessionId,
|
|
20073
20100
|
projectId: project.id,
|
|
20074
20101
|
icpDescription,
|
|
20075
20102
|
dedupThreshold: parsed.data.dedupThreshold,
|
|
20076
20103
|
maxProbes: parsed.data.maxProbes,
|
|
20077
20104
|
locations
|
|
20078
20105
|
});
|
|
20079
|
-
return reply.status(201).send({
|
|
20106
|
+
return reply.status(201).send({
|
|
20107
|
+
runId: decision.runId,
|
|
20108
|
+
sessionId: decision.sessionId,
|
|
20109
|
+
status: "running",
|
|
20110
|
+
consolidated: false
|
|
20111
|
+
});
|
|
20080
20112
|
});
|
|
20081
20113
|
app.get(
|
|
20082
20114
|
"/projects/:name/discover/sessions",
|
|
@@ -23328,7 +23360,7 @@ import crypto24 from "crypto";
|
|
|
23328
23360
|
import fs7 from "fs";
|
|
23329
23361
|
import path9 from "path";
|
|
23330
23362
|
import os5 from "os";
|
|
23331
|
-
import { and as
|
|
23363
|
+
import { and as and17, eq as eq27, inArray as inArray9, sql as sql10 } from "drizzle-orm";
|
|
23332
23364
|
|
|
23333
23365
|
// src/run-telemetry.ts
|
|
23334
23366
|
import crypto23 from "crypto";
|
|
@@ -23669,7 +23701,7 @@ var JobRunner = class {
|
|
|
23669
23701
|
this.registry = registry;
|
|
23670
23702
|
}
|
|
23671
23703
|
recoverStaleRuns() {
|
|
23672
|
-
const stale = this.db.select({ id: runs.id, status: runs.status }).from(runs).where(
|
|
23704
|
+
const stale = this.db.select({ id: runs.id, status: runs.status }).from(runs).where(inArray9(runs.status, ["running", "queued"])).all();
|
|
23673
23705
|
if (stale.length === 0) return;
|
|
23674
23706
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
23675
23707
|
for (const run of stale) {
|
|
@@ -23707,7 +23739,7 @@ var JobRunner = class {
|
|
|
23707
23739
|
throw new Error(`Run ${runId} is not executable from status '${existingRun.status}'`);
|
|
23708
23740
|
}
|
|
23709
23741
|
if (existingRun.status === "queued") {
|
|
23710
|
-
this.db.update(runs).set({ status: "running", startedAt: now }).where(
|
|
23742
|
+
this.db.update(runs).set({ status: "running", startedAt: now }).where(and17(eq27(runs.id, runId), eq27(runs.status, "queued"))).run();
|
|
23711
23743
|
}
|
|
23712
23744
|
this.throwIfRunCancelled(runId);
|
|
23713
23745
|
const project = this.db.select().from(projects).where(eq27(projects.id, projectId)).get();
|
|
@@ -23732,7 +23764,7 @@ var JobRunner = class {
|
|
|
23732
23764
|
}
|
|
23733
23765
|
log.info("run.dispatch", { runId, providerCount: activeProviders.length, providers: activeProviders.map((p) => p.adapter.name) });
|
|
23734
23766
|
const scopedQueryNames = parseJsonColumn(existingRun.queries, null);
|
|
23735
|
-
projectQueries = scopedQueryNames ? this.db.select().from(queries).where(
|
|
23767
|
+
projectQueries = scopedQueryNames ? this.db.select().from(queries).where(and17(eq27(queries.projectId, projectId), inArray9(queries.query, scopedQueryNames))).all() : this.db.select().from(queries).where(eq27(queries.projectId, projectId)).all();
|
|
23736
23768
|
const projectCompetitors = this.db.select().from(competitors).where(eq27(competitors.projectId, projectId)).all();
|
|
23737
23769
|
const competitorDomains = projectCompetitors.map((c) => c.domain);
|
|
23738
23770
|
const allDomains = effectiveDomains({
|
|
@@ -23821,6 +23853,7 @@ var JobRunner = class {
|
|
|
23821
23853
|
id: snapshotId,
|
|
23822
23854
|
runId,
|
|
23823
23855
|
queryId: q.id,
|
|
23856
|
+
queryText: q.query,
|
|
23824
23857
|
provider: providerName,
|
|
23825
23858
|
model: raw.model,
|
|
23826
23859
|
citationState,
|
|
@@ -23844,6 +23877,7 @@ var JobRunner = class {
|
|
|
23844
23877
|
id: crypto24.randomUUID(),
|
|
23845
23878
|
runId,
|
|
23846
23879
|
queryId: q.id,
|
|
23880
|
+
queryText: q.query,
|
|
23847
23881
|
provider: providerName,
|
|
23848
23882
|
model: raw.model,
|
|
23849
23883
|
citationState,
|
|
@@ -24068,7 +24102,7 @@ function buildPhases(input) {
|
|
|
24068
24102
|
|
|
24069
24103
|
// src/gsc-sync.ts
|
|
24070
24104
|
import crypto25 from "crypto";
|
|
24071
|
-
import { eq as eq28, and as
|
|
24105
|
+
import { eq as eq28, and as and18, sql as sql11 } from "drizzle-orm";
|
|
24072
24106
|
var log2 = createLogger("GscSync");
|
|
24073
24107
|
function formatDate3(d) {
|
|
24074
24108
|
return d.toISOString().split("T")[0];
|
|
@@ -24120,7 +24154,7 @@ async function executeGscSync(db, runId, projectId, opts) {
|
|
|
24120
24154
|
});
|
|
24121
24155
|
log2.info("fetch.complete", { runId, projectId, rowCount: rows.length });
|
|
24122
24156
|
db.delete(gscSearchData).where(
|
|
24123
|
-
|
|
24157
|
+
and18(
|
|
24124
24158
|
eq28(gscSearchData.projectId, projectId),
|
|
24125
24159
|
sql11`${gscSearchData.date} >= ${startDate}`,
|
|
24126
24160
|
sql11`${gscSearchData.date} <= ${endDate}`
|
|
@@ -24209,7 +24243,7 @@ async function executeGscSync(db, runId, projectId, opts) {
|
|
|
24209
24243
|
}
|
|
24210
24244
|
}
|
|
24211
24245
|
const snapshotDate = formatDate3(/* @__PURE__ */ new Date());
|
|
24212
|
-
db.delete(gscCoverageSnapshots).where(
|
|
24246
|
+
db.delete(gscCoverageSnapshots).where(and18(eq28(gscCoverageSnapshots.projectId, projectId), eq28(gscCoverageSnapshots.date, snapshotDate))).run();
|
|
24213
24247
|
db.insert(gscCoverageSnapshots).values({
|
|
24214
24248
|
id: crypto25.randomUUID(),
|
|
24215
24249
|
projectId,
|
|
@@ -24232,7 +24266,7 @@ async function executeGscSync(db, runId, projectId, opts) {
|
|
|
24232
24266
|
|
|
24233
24267
|
// src/gsc-inspect-sitemap.ts
|
|
24234
24268
|
import crypto26 from "crypto";
|
|
24235
|
-
import { eq as eq29, and as
|
|
24269
|
+
import { eq as eq29, and as and19 } from "drizzle-orm";
|
|
24236
24270
|
|
|
24237
24271
|
// src/sitemap-parser.ts
|
|
24238
24272
|
var log3 = createLogger("SitemapParser");
|
|
@@ -24448,7 +24482,7 @@ async function executeInspectSitemap(db, runId, projectId, opts) {
|
|
|
24448
24482
|
}
|
|
24449
24483
|
}
|
|
24450
24484
|
const snapshotDate = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
24451
|
-
db.delete(gscCoverageSnapshots).where(
|
|
24485
|
+
db.delete(gscCoverageSnapshots).where(and19(eq29(gscCoverageSnapshots.projectId, projectId), eq29(gscCoverageSnapshots.date, snapshotDate))).run();
|
|
24452
24486
|
db.insert(gscCoverageSnapshots).values({
|
|
24453
24487
|
id: crypto26.randomUUID(),
|
|
24454
24488
|
projectId,
|
|
@@ -24659,7 +24693,7 @@ async function executeBingInspectSitemap(db, runId, projectId, opts) {
|
|
|
24659
24693
|
// src/commoncrawl-sync.ts
|
|
24660
24694
|
import crypto28 from "crypto";
|
|
24661
24695
|
import path10 from "path";
|
|
24662
|
-
import { and as
|
|
24696
|
+
import { and as and20, eq as eq31, sql as sql12 } from "drizzle-orm";
|
|
24663
24697
|
var log6 = createLogger("CommonCrawlSync");
|
|
24664
24698
|
var INSERT_CHUNK_SIZE = 1e4;
|
|
24665
24699
|
function defaultDeps() {
|
|
@@ -24850,7 +24884,7 @@ function computeSummary(rows) {
|
|
|
24850
24884
|
// src/backlink-extract.ts
|
|
24851
24885
|
import crypto29 from "crypto";
|
|
24852
24886
|
import fs8 from "fs";
|
|
24853
|
-
import { and as
|
|
24887
|
+
import { and as and21, desc as desc15, eq as eq32 } from "drizzle-orm";
|
|
24854
24888
|
var log7 = createLogger("BacklinkExtract");
|
|
24855
24889
|
function defaultDeps2() {
|
|
24856
24890
|
return {
|
|
@@ -24896,7 +24930,7 @@ async function executeBacklinkExtract(db, runId, projectId, opts = {}) {
|
|
|
24896
24930
|
const targetDomain = project.canonicalDomain;
|
|
24897
24931
|
db.transaction((tx) => {
|
|
24898
24932
|
tx.delete(backlinkDomains).where(
|
|
24899
|
-
|
|
24933
|
+
and21(eq32(backlinkDomains.projectId, projectId), eq32(backlinkDomains.release, release))
|
|
24900
24934
|
).run();
|
|
24901
24935
|
if (rows.length > 0) {
|
|
24902
24936
|
const values = rows.map((r) => ({
|
|
@@ -25313,7 +25347,7 @@ var ProviderRegistry = class {
|
|
|
25313
25347
|
|
|
25314
25348
|
// src/scheduler.ts
|
|
25315
25349
|
import cron from "node-cron";
|
|
25316
|
-
import { and as
|
|
25350
|
+
import { and as and22, eq as eq34 } from "drizzle-orm";
|
|
25317
25351
|
var log9 = createLogger("Scheduler");
|
|
25318
25352
|
function taskKey(projectId, kind) {
|
|
25319
25353
|
return `${projectId}::${kind}`;
|
|
@@ -25358,7 +25392,7 @@ var Scheduler = class {
|
|
|
25358
25392
|
this.stopTask(key, existing, "Stopped");
|
|
25359
25393
|
this.tasks.delete(key);
|
|
25360
25394
|
}
|
|
25361
|
-
const schedule = this.db.select().from(schedules).where(
|
|
25395
|
+
const schedule = this.db.select().from(schedules).where(and22(eq34(schedules.projectId, projectId), eq34(schedules.kind, kind))).get();
|
|
25362
25396
|
if (schedule && schedule.enabled === 1) {
|
|
25363
25397
|
this.registerCronTask(schedule);
|
|
25364
25398
|
}
|
|
@@ -25482,7 +25516,7 @@ var Scheduler = class {
|
|
|
25482
25516
|
};
|
|
25483
25517
|
|
|
25484
25518
|
// src/notifier.ts
|
|
25485
|
-
import { eq as eq35, desc as desc16, and as
|
|
25519
|
+
import { eq as eq35, desc as desc16, and as and23, inArray as inArray10, or as or4 } from "drizzle-orm";
|
|
25486
25520
|
import crypto31 from "crypto";
|
|
25487
25521
|
var log10 = createLogger("Notifier");
|
|
25488
25522
|
var Notifier = class {
|
|
@@ -25589,7 +25623,7 @@ var Notifier = class {
|
|
|
25589
25623
|
computeTransitions(runId, projectId) {
|
|
25590
25624
|
const thisRun = this.db.select().from(runs).where(eq35(runs.id, runId)).get();
|
|
25591
25625
|
if (!thisRun) return [];
|
|
25592
|
-
const groupSiblings = this.db.select().from(runs).where(
|
|
25626
|
+
const groupSiblings = this.db.select().from(runs).where(and23(
|
|
25593
25627
|
eq35(runs.projectId, projectId),
|
|
25594
25628
|
eq35(runs.kind, thisRun.kind),
|
|
25595
25629
|
eq35(runs.createdAt, thisRun.createdAt)
|
|
@@ -25615,7 +25649,7 @@ var Notifier = class {
|
|
|
25615
25649
|
);
|
|
25616
25650
|
const RECENT_FETCH_LIMIT = Math.max(8, locationCount * 4);
|
|
25617
25651
|
const recentRuns = this.db.select().from(runs).where(
|
|
25618
|
-
|
|
25652
|
+
and23(
|
|
25619
25653
|
eq35(runs.projectId, projectId),
|
|
25620
25654
|
eq35(runs.kind, thisRun.kind),
|
|
25621
25655
|
or4(eq35(runs.status, "completed"), eq35(runs.status, "partial"))
|
|
@@ -25635,19 +25669,21 @@ var Notifier = class {
|
|
|
25635
25669
|
provider: querySnapshots.provider,
|
|
25636
25670
|
location: querySnapshots.location,
|
|
25637
25671
|
citationState: querySnapshots.citationState
|
|
25638
|
-
}).from(querySnapshots).leftJoin(queries, eq35(querySnapshots.queryId, queries.id)).where(
|
|
25672
|
+
}).from(querySnapshots).leftJoin(queries, eq35(querySnapshots.queryId, queries.id)).where(inArray10(querySnapshots.runId, currentRunIds)).all();
|
|
25639
25673
|
const previousSnapshots = this.db.select({
|
|
25640
25674
|
queryId: querySnapshots.queryId,
|
|
25641
25675
|
provider: querySnapshots.provider,
|
|
25642
25676
|
location: querySnapshots.location,
|
|
25643
25677
|
citationState: querySnapshots.citationState
|
|
25644
|
-
}).from(querySnapshots).where(
|
|
25678
|
+
}).from(querySnapshots).where(inArray10(querySnapshots.runId, previousRunIds)).all();
|
|
25645
25679
|
const prevMap = /* @__PURE__ */ new Map();
|
|
25646
25680
|
for (const s of previousSnapshots) {
|
|
25681
|
+
if (s.queryId == null) continue;
|
|
25647
25682
|
prevMap.set(`${s.queryId}:${s.provider}:${s.location ?? ""}`, s.citationState);
|
|
25648
25683
|
}
|
|
25649
25684
|
const transitions = [];
|
|
25650
25685
|
for (const s of currentSnapshots) {
|
|
25686
|
+
if (s.queryId == null) continue;
|
|
25651
25687
|
const key = `${s.queryId}:${s.provider}:${s.location ?? ""}`;
|
|
25652
25688
|
const prevState = prevMap.get(key);
|
|
25653
25689
|
if (prevState && prevState !== s.citationState) {
|
|
@@ -26152,7 +26188,7 @@ function resolveSessionProviderAndModel(config, opts) {
|
|
|
26152
26188
|
|
|
26153
26189
|
// src/agent/memory-store.ts
|
|
26154
26190
|
import crypto32 from "crypto";
|
|
26155
|
-
import { and as
|
|
26191
|
+
import { and as and24, desc as desc17, eq as eq37, like as like2, sql as sql13 } from "drizzle-orm";
|
|
26156
26192
|
var COMPACTION_KEY_PREFIX = "compaction:";
|
|
26157
26193
|
var COMPACTION_NOTES_PER_SESSION = 3;
|
|
26158
26194
|
function rowToDto2(row) {
|
|
@@ -26197,12 +26233,12 @@ function upsertMemoryEntry(db, args) {
|
|
|
26197
26233
|
updatedAt: now
|
|
26198
26234
|
}
|
|
26199
26235
|
}).run();
|
|
26200
|
-
const row = db.select().from(agentMemory).where(
|
|
26236
|
+
const row = db.select().from(agentMemory).where(and24(eq37(agentMemory.projectId, args.projectId), eq37(agentMemory.key, args.key))).get();
|
|
26201
26237
|
if (!row) throw new Error("memory upsert produced no row");
|
|
26202
26238
|
return rowToDto2(row);
|
|
26203
26239
|
}
|
|
26204
26240
|
function deleteMemoryEntry(db, projectId, key) {
|
|
26205
|
-
const result = db.delete(agentMemory).where(
|
|
26241
|
+
const result = db.delete(agentMemory).where(and24(eq37(agentMemory.projectId, projectId), eq37(agentMemory.key, key))).run();
|
|
26206
26242
|
const changes = result.changes ?? 0;
|
|
26207
26243
|
return changes > 0;
|
|
26208
26244
|
}
|
|
@@ -26231,7 +26267,7 @@ function writeCompactionNote(db, args) {
|
|
|
26231
26267
|
}).run();
|
|
26232
26268
|
const sessionPrefix = `${COMPACTION_KEY_PREFIX}${args.sessionId}:`;
|
|
26233
26269
|
const existing = tx.select({ id: agentMemory.id, updatedAt: agentMemory.updatedAt }).from(agentMemory).where(
|
|
26234
|
-
|
|
26270
|
+
and24(
|
|
26235
26271
|
eq37(agentMemory.projectId, args.projectId),
|
|
26236
26272
|
like2(agentMemory.key, `${sessionPrefix}%`)
|
|
26237
26273
|
)
|
|
@@ -26240,7 +26276,7 @@ function writeCompactionNote(db, args) {
|
|
|
26240
26276
|
if (stale.length > 0) {
|
|
26241
26277
|
tx.delete(agentMemory).where(sql13`${agentMemory.id} IN (${sql13.join(stale.map((s) => sql13`${s}`), sql13`, `)})`).run();
|
|
26242
26278
|
}
|
|
26243
|
-
const row = tx.select().from(agentMemory).where(
|
|
26279
|
+
const row = tx.select().from(agentMemory).where(and24(eq37(agentMemory.projectId, args.projectId), eq37(agentMemory.key, key))).get();
|
|
26244
26280
|
if (row) inserted = rowToDto2(row);
|
|
26245
26281
|
});
|
|
26246
26282
|
if (!inserted) throw new Error("compaction note write produced no row");
|
package/dist/cli.js
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
setTelemetrySource,
|
|
21
21
|
showFirstRunNotice,
|
|
22
22
|
trackEvent
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-7AF6B3L6.js";
|
|
24
24
|
import {
|
|
25
25
|
CliError,
|
|
26
26
|
EXIT_SYSTEM_ERROR,
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
queries,
|
|
50
50
|
querySnapshots,
|
|
51
51
|
runs
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-7256SFYT.js";
|
|
53
53
|
import {
|
|
54
54
|
CcReleaseSyncStatuses,
|
|
55
55
|
CheckScopes,
|
|
@@ -623,7 +623,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
623
623
|
return result;
|
|
624
624
|
}
|
|
625
625
|
async function backfillInsightsCommand(project, opts) {
|
|
626
|
-
const { IntelligenceService } = await import("./intelligence-service-
|
|
626
|
+
const { IntelligenceService } = await import("./intelligence-service-3P2DMYRR.js");
|
|
627
627
|
const config = loadConfig();
|
|
628
628
|
const db = createClient(config.database);
|
|
629
629
|
migrate(db);
|
|
@@ -2020,10 +2020,17 @@ Sessions already started (recover with \`canonry discover show ${project} <id>\`
|
|
|
2020
2020
|
}
|
|
2021
2021
|
for (const { angle, start } of runs2) {
|
|
2022
2022
|
if (angle) console.log(`[${angle}]`);
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2023
|
+
if (start.consolidated) {
|
|
2024
|
+
console.log(`Reusing in-flight discovery session: ${start.sessionId}`);
|
|
2025
|
+
console.log(` Run: ${start.runId}`);
|
|
2026
|
+
console.log(` Status: ${start.status}`);
|
|
2027
|
+
console.log(` Tail: canonry discover show ${project} ${start.sessionId}`);
|
|
2028
|
+
} else {
|
|
2029
|
+
console.log(`Discovery run started: ${start.runId}`);
|
|
2030
|
+
console.log(` Session: ${start.sessionId}`);
|
|
2031
|
+
console.log(` Status: ${start.status}`);
|
|
2032
|
+
console.log(` Tail: canonry discover show ${project} ${start.sessionId}`);
|
|
2033
|
+
}
|
|
2027
2034
|
if (runs2.length > 1) console.log();
|
|
2028
2035
|
}
|
|
2029
2036
|
return;
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createServer
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-7AF6B3L6.js";
|
|
4
4
|
import {
|
|
5
5
|
loadConfig
|
|
6
6
|
} from "./chunk-5EBN7736.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-7256SFYT.js";
|
|
8
8
|
import "./chunk-XW3F5EEW.js";
|
|
9
9
|
export {
|
|
10
10
|
createServer,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainyc/canonry",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.34.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",
|
|
@@ -60,23 +60,23 @@
|
|
|
60
60
|
"@types/node-cron": "^3.0.11",
|
|
61
61
|
"tsup": "^8.5.1",
|
|
62
62
|
"tsx": "^4.19.0",
|
|
63
|
+
"@ainyc/canonry-config": "0.0.0",
|
|
63
64
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
64
65
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
65
|
-
"@ainyc/canonry-intelligence": "0.0.0",
|
|
66
66
|
"@ainyc/canonry-db": "0.0.0",
|
|
67
|
-
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
68
|
-
"@ainyc/canonry-config": "0.0.0",
|
|
69
67
|
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
70
|
-
"@ainyc/canonry-integration-
|
|
68
|
+
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
71
69
|
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
72
|
-
"@ainyc/canonry-
|
|
73
|
-
"@ainyc/canonry-
|
|
74
|
-
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
70
|
+
"@ainyc/canonry-intelligence": "0.0.0",
|
|
71
|
+
"@ainyc/canonry-integration-google": "0.0.0",
|
|
75
72
|
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
73
|
+
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
74
|
+
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
76
75
|
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
77
|
-
"@ainyc/canonry-provider-
|
|
76
|
+
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
77
|
+
"@ainyc/canonry-provider-local": "0.0.0",
|
|
78
78
|
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
79
|
-
"@ainyc/canonry-provider-
|
|
79
|
+
"@ainyc/canonry-provider-perplexity": "0.0.0"
|
|
80
80
|
},
|
|
81
81
|
"scripts": {
|
|
82
82
|
"build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",
|