@ainyc/canonry 1.37.0 → 1.37.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/assets/{index-BZX6FEZ4.css → index-CM92zXYn.css} +1 -1
- package/assets/assets/{index-DR4zYsnw.js → index-Du9ZvTq9.js} +55 -55
- package/assets/index.html +2 -2
- package/dist/{chunk-5MOWJJND.js → chunk-U2ZNKIWK.js} +69 -56
- package/dist/cli.js +6 -2
- package/dist/index.js +1 -1
- package/package.json +5 -5
package/assets/index.html
CHANGED
|
@@ -12,8 +12,8 @@
|
|
|
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-
|
|
16
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
15
|
+
<script type="module" crossorigin src="./assets/index-Du9ZvTq9.js"></script>
|
|
16
|
+
<link rel="stylesheet" crossorigin href="./assets/index-CM92zXYn.css">
|
|
17
17
|
</head>
|
|
18
18
|
<body>
|
|
19
19
|
<div id="root"></div>
|
|
@@ -10387,19 +10387,11 @@ async function apiRoutes(app, opts) {
|
|
|
10387
10387
|
// ../provider-gemini/src/normalize.ts
|
|
10388
10388
|
import { GoogleGenAI } from "@google/genai";
|
|
10389
10389
|
var DEFAULT_MODEL = "gemini-3-flash";
|
|
10390
|
-
var VALIDATION_PATTERN = /^gemini-/;
|
|
10391
10390
|
function isVertexConfig(config) {
|
|
10392
10391
|
return !!config.vertexProject;
|
|
10393
10392
|
}
|
|
10394
10393
|
function resolveModel(config) {
|
|
10395
|
-
|
|
10396
|
-
if (!m) return DEFAULT_MODEL;
|
|
10397
|
-
if (VALIDATION_PATTERN.test(m)) return m;
|
|
10398
|
-
const backend = isVertexConfig(config) ? "Vertex AI" : "AI Studio";
|
|
10399
|
-
console.warn(
|
|
10400
|
-
`[provider-gemini] Invalid model name "${m}" \u2014 this provider uses the Gemini ${backend} API which only accepts "gemini-*" model names. Falling back to ${DEFAULT_MODEL}.`
|
|
10401
|
-
);
|
|
10402
|
-
return DEFAULT_MODEL;
|
|
10394
|
+
return config.model || DEFAULT_MODEL;
|
|
10403
10395
|
}
|
|
10404
10396
|
function createClient2(config) {
|
|
10405
10397
|
if (isVertexConfig(config)) {
|
|
@@ -10413,6 +10405,9 @@ function createClient2(config) {
|
|
|
10413
10405
|
return new GoogleGenAI({ apiKey: config.apiKey });
|
|
10414
10406
|
}
|
|
10415
10407
|
function validateConfig(config) {
|
|
10408
|
+
if ("vertexProject" in config && config.vertexProject !== void 0 && config.vertexProject.trim().length === 0) {
|
|
10409
|
+
return { ok: false, provider: "gemini", message: "missing Vertex AI project ID" };
|
|
10410
|
+
}
|
|
10416
10411
|
if (isVertexConfig(config)) {
|
|
10417
10412
|
const model2 = resolveModel(config);
|
|
10418
10413
|
return {
|
|
@@ -10426,11 +10421,10 @@ function validateConfig(config) {
|
|
|
10426
10421
|
return { ok: false, provider: "gemini", message: "missing api key" };
|
|
10427
10422
|
}
|
|
10428
10423
|
const model = resolveModel(config);
|
|
10429
|
-
const warning = config.model && !VALIDATION_PATTERN.test(config.model) ? ` (invalid model "${config.model}" replaced with default)` : "";
|
|
10430
10424
|
return {
|
|
10431
10425
|
ok: true,
|
|
10432
10426
|
provider: "gemini",
|
|
10433
|
-
message:
|
|
10427
|
+
message: "config valid",
|
|
10434
10428
|
model
|
|
10435
10429
|
};
|
|
10436
10430
|
}
|
|
@@ -10623,12 +10617,14 @@ var geminiAdapter = {
|
|
|
10623
10617
|
displayName: "Gemini",
|
|
10624
10618
|
mode: "api",
|
|
10625
10619
|
keyUrl: "https://aistudio.google.com/apikey",
|
|
10620
|
+
// Upstream model list: https://ai.google.dev/gemini-api/docs/models
|
|
10626
10621
|
modelRegistry: {
|
|
10627
10622
|
defaultModel: "gemini-3-flash",
|
|
10628
|
-
validationPattern:
|
|
10629
|
-
validationHint:
|
|
10623
|
+
validationPattern: /./,
|
|
10624
|
+
validationHint: "any valid Google model name (e.g. gemini-3-flash, learnlm-1.5-pro-experimental)",
|
|
10630
10625
|
knownModels: [
|
|
10631
10626
|
{ id: "gemini-3.1-pro-preview", displayName: "Gemini 3.1 Pro (Preview)", tier: "flagship" },
|
|
10627
|
+
{ id: "gemini-3-flash", displayName: "Gemini 3 Flash", tier: "standard" },
|
|
10632
10628
|
{ id: "gemini-3-flash-preview", displayName: "Gemini 3 Flash (Preview)", tier: "standard" },
|
|
10633
10629
|
{ id: "gemini-3.1-flash-lite-preview", displayName: "Gemini 3.1 Flash-Lite (Preview)", tier: "economy" },
|
|
10634
10630
|
{ id: "gemini-2.5-flash", displayName: "Gemini 2.5 Flash", tier: "standard" }
|
|
@@ -10791,13 +10787,15 @@ function extractResponseText(response) {
|
|
|
10791
10787
|
}
|
|
10792
10788
|
function extractGroundingSources(response) {
|
|
10793
10789
|
const sources = [];
|
|
10790
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10794
10791
|
try {
|
|
10795
10792
|
for (const item of response.output) {
|
|
10796
10793
|
if (item.type === "message") {
|
|
10797
10794
|
for (const content of item.content) {
|
|
10798
10795
|
if (content.type === "output_text" && content.annotations) {
|
|
10799
10796
|
for (const annotation of content.annotations) {
|
|
10800
|
-
if (annotation.type === "url_citation") {
|
|
10797
|
+
if (annotation.type === "url_citation" && !seen.has(annotation.url)) {
|
|
10798
|
+
seen.add(annotation.url);
|
|
10801
10799
|
sources.push({
|
|
10802
10800
|
uri: annotation.url,
|
|
10803
10801
|
title: annotation.title ?? ""
|
|
@@ -10817,7 +10815,10 @@ function extractSearchQueries2(response) {
|
|
|
10817
10815
|
try {
|
|
10818
10816
|
for (const item of response.output) {
|
|
10819
10817
|
if (item.type === "web_search_call" && "query" in item) {
|
|
10820
|
-
|
|
10818
|
+
const query = item.query;
|
|
10819
|
+
if (typeof query === "string" && query.length > 0) {
|
|
10820
|
+
queries.push(query);
|
|
10821
|
+
}
|
|
10821
10822
|
}
|
|
10822
10823
|
}
|
|
10823
10824
|
} catch {
|
|
@@ -10889,10 +10890,11 @@ var openaiAdapter = {
|
|
|
10889
10890
|
displayName: "OpenAI",
|
|
10890
10891
|
mode: "api",
|
|
10891
10892
|
keyUrl: "https://platform.openai.com/api-keys",
|
|
10893
|
+
// Upstream model list: https://platform.openai.com/docs/models
|
|
10892
10894
|
modelRegistry: {
|
|
10893
10895
|
defaultModel: "gpt-5.4",
|
|
10894
|
-
validationPattern:
|
|
10895
|
-
validationHint: "
|
|
10896
|
+
validationPattern: /./,
|
|
10897
|
+
validationHint: "any valid OpenAI model name (e.g. gpt-5.4, o3, chatgpt-4o-latest)",
|
|
10896
10898
|
knownModels: [
|
|
10897
10899
|
{ id: "gpt-5.4", displayName: "GPT-5.4", tier: "flagship" },
|
|
10898
10900
|
{ id: "gpt-5.4-pro", displayName: "GPT-5.4 Pro", tier: "flagship" },
|
|
@@ -10961,24 +10963,37 @@ var openaiAdapter = {
|
|
|
10961
10963
|
// ../provider-claude/src/normalize.ts
|
|
10962
10964
|
import Anthropic from "@anthropic-ai/sdk";
|
|
10963
10965
|
var DEFAULT_MODEL3 = "claude-sonnet-4-6";
|
|
10966
|
+
var VALIDATION_PATTERN = /^claude-/;
|
|
10967
|
+
function resolveModel2(config) {
|
|
10968
|
+
const m = config.model;
|
|
10969
|
+
if (!m) return DEFAULT_MODEL3;
|
|
10970
|
+
if (VALIDATION_PATTERN.test(m)) return m;
|
|
10971
|
+
console.warn(
|
|
10972
|
+
`[provider-claude] Invalid model name "${m}" \u2014 this provider uses the Anthropic API which only accepts "claude-*" model names. Falling back to ${DEFAULT_MODEL3}.`
|
|
10973
|
+
);
|
|
10974
|
+
return DEFAULT_MODEL3;
|
|
10975
|
+
}
|
|
10964
10976
|
function validateConfig3(config) {
|
|
10965
10977
|
if (!config.apiKey || config.apiKey.length === 0) {
|
|
10966
10978
|
return { ok: false, provider: "claude", message: "missing api key" };
|
|
10967
10979
|
}
|
|
10980
|
+
const model = resolveModel2(config);
|
|
10981
|
+
const warning = config.model && !VALIDATION_PATTERN.test(config.model) ? ` (invalid model "${config.model}" replaced with default)` : "";
|
|
10968
10982
|
return {
|
|
10969
10983
|
ok: true,
|
|
10970
10984
|
provider: "claude",
|
|
10971
|
-
message:
|
|
10972
|
-
model
|
|
10985
|
+
message: `config valid${warning}`,
|
|
10986
|
+
model
|
|
10973
10987
|
};
|
|
10974
10988
|
}
|
|
10975
10989
|
async function healthcheck3(config) {
|
|
10976
10990
|
const validation = validateConfig3(config);
|
|
10977
10991
|
if (!validation.ok) return validation;
|
|
10978
10992
|
try {
|
|
10993
|
+
const model = resolveModel2(config);
|
|
10979
10994
|
const client = new Anthropic({ apiKey: config.apiKey });
|
|
10980
10995
|
const response = await client.messages.create({
|
|
10981
|
-
model
|
|
10996
|
+
model,
|
|
10982
10997
|
max_tokens: 32,
|
|
10983
10998
|
messages: [{ role: "user", content: 'Say "ok"' }]
|
|
10984
10999
|
});
|
|
@@ -10987,19 +11002,19 @@ async function healthcheck3(config) {
|
|
|
10987
11002
|
ok: text2.length > 0,
|
|
10988
11003
|
provider: "claude",
|
|
10989
11004
|
message: text2.length > 0 ? "claude api key verified" : "empty response from claude",
|
|
10990
|
-
model
|
|
11005
|
+
model
|
|
10991
11006
|
};
|
|
10992
11007
|
} catch (err) {
|
|
10993
11008
|
return {
|
|
10994
11009
|
ok: false,
|
|
10995
11010
|
provider: "claude",
|
|
10996
11011
|
message: err instanceof Error ? err.message : String(err),
|
|
10997
|
-
model: config
|
|
11012
|
+
model: resolveModel2(config)
|
|
10998
11013
|
};
|
|
10999
11014
|
}
|
|
11000
11015
|
}
|
|
11001
11016
|
async function executeTrackedQuery3(input) {
|
|
11002
|
-
const model = input.config
|
|
11017
|
+
const model = resolveModel2(input.config);
|
|
11003
11018
|
const client = new Anthropic({ apiKey: input.config.apiKey });
|
|
11004
11019
|
const webSearchTool = {
|
|
11005
11020
|
type: "web_search_20250305",
|
|
@@ -11121,7 +11136,7 @@ function extractDomainFromUri3(uri) {
|
|
|
11121
11136
|
}
|
|
11122
11137
|
}
|
|
11123
11138
|
async function generateText3(prompt, config) {
|
|
11124
|
-
const model = config
|
|
11139
|
+
const model = resolveModel2(config);
|
|
11125
11140
|
const client = new Anthropic({ apiKey: config.apiKey });
|
|
11126
11141
|
const response = await client.messages.create({
|
|
11127
11142
|
model,
|
|
@@ -11151,6 +11166,7 @@ var claudeAdapter = {
|
|
|
11151
11166
|
displayName: "Claude",
|
|
11152
11167
|
mode: "api",
|
|
11153
11168
|
keyUrl: "https://platform.claude.com/settings/keys",
|
|
11169
|
+
// Upstream model list: https://platform.claude.com/docs/en/about-claude/models/overview
|
|
11154
11170
|
modelRegistry: {
|
|
11155
11171
|
defaultModel: "claude-sonnet-4-6",
|
|
11156
11172
|
validationPattern: /^claude-/,
|
|
@@ -11860,7 +11876,7 @@ function normalizeResult5(raw) {
|
|
|
11860
11876
|
}
|
|
11861
11877
|
|
|
11862
11878
|
// ../provider-cdp/src/adapter.ts
|
|
11863
|
-
var
|
|
11879
|
+
var connectionPool = /* @__PURE__ */ new Map();
|
|
11864
11880
|
function getConnection(config) {
|
|
11865
11881
|
if (!config.cdpEndpoint) {
|
|
11866
11882
|
throw new CDPProviderError("CDP_CONNECTION_REFUSED", "CDP endpoint not configured");
|
|
@@ -11871,14 +11887,13 @@ function getConnection(config) {
|
|
|
11871
11887
|
const parts = endpoint.split(":");
|
|
11872
11888
|
if (parts.length >= 1 && parts[0]) host = parts[0];
|
|
11873
11889
|
if (parts.length >= 2 && parts[1]) port = parseInt(parts[1], 10) || 9222;
|
|
11874
|
-
|
|
11875
|
-
|
|
11876
|
-
|
|
11877
|
-
|
|
11878
|
-
|
|
11879
|
-
sharedConnection = new CDPConnectionManager(host, port);
|
|
11890
|
+
const key = `${host}:${port}`;
|
|
11891
|
+
let conn = connectionPool.get(key);
|
|
11892
|
+
if (!conn) {
|
|
11893
|
+
conn = new CDPConnectionManager(host, port);
|
|
11894
|
+
connectionPool.set(key, conn);
|
|
11880
11895
|
}
|
|
11881
|
-
return
|
|
11896
|
+
return conn;
|
|
11882
11897
|
}
|
|
11883
11898
|
function getScreenshotDir2() {
|
|
11884
11899
|
return path4.join(os3.homedir(), ".canonry", "screenshots");
|
|
@@ -12124,6 +12139,7 @@ var perplexityAdapter = {
|
|
|
12124
12139
|
displayName: "Perplexity",
|
|
12125
12140
|
mode: "api",
|
|
12126
12141
|
keyUrl: "https://www.perplexity.ai/settings/api",
|
|
12142
|
+
// Upstream model list: https://docs.perplexity.ai/guides/model-cards
|
|
12127
12143
|
modelRegistry: {
|
|
12128
12144
|
defaultModel: "sonar",
|
|
12129
12145
|
validationPattern: /^sonar/,
|
|
@@ -12352,7 +12368,7 @@ import crypto18 from "crypto";
|
|
|
12352
12368
|
import fs4 from "fs";
|
|
12353
12369
|
import path5 from "path";
|
|
12354
12370
|
import os4 from "os";
|
|
12355
|
-
import { and as and6, eq as eq17, inArray as inArray3 } from "drizzle-orm";
|
|
12371
|
+
import { and as and6, eq as eq17, inArray as inArray3, sql as sql5 } from "drizzle-orm";
|
|
12356
12372
|
|
|
12357
12373
|
// src/logger.ts
|
|
12358
12374
|
var IS_TTY = process.stdout.isTTY === true;
|
|
@@ -12514,12 +12530,12 @@ var JobRunner = class {
|
|
|
12514
12530
|
} else if (locationOverride) {
|
|
12515
12531
|
runLocation = locationOverride;
|
|
12516
12532
|
} else {
|
|
12517
|
-
const projectLocations =
|
|
12533
|
+
const projectLocations = parseJsonColumn(project.locations, []);
|
|
12518
12534
|
if (project.defaultLocation && projectLocations.length > 0) {
|
|
12519
12535
|
runLocation = projectLocations.find((l) => l.label === project.defaultLocation);
|
|
12520
12536
|
}
|
|
12521
12537
|
}
|
|
12522
|
-
const projectProviders = providerOverride ??
|
|
12538
|
+
const projectProviders = providerOverride ?? parseJsonColumn(project.providers, []);
|
|
12523
12539
|
activeProviders = this.registry.getForProject(projectProviders);
|
|
12524
12540
|
if (activeProviders.length === 0) {
|
|
12525
12541
|
throw new Error("No providers configured. Add at least one provider API key.");
|
|
@@ -12530,7 +12546,7 @@ var JobRunner = class {
|
|
|
12530
12546
|
const competitorDomains = projectCompetitors.map((c) => c.domain);
|
|
12531
12547
|
const allDomains = effectiveDomains({
|
|
12532
12548
|
canonicalDomain: project.canonicalDomain,
|
|
12533
|
-
ownedDomains:
|
|
12549
|
+
ownedDomains: parseJsonColumn(project.ownedDomains, [])
|
|
12534
12550
|
});
|
|
12535
12551
|
const executionContext = {
|
|
12536
12552
|
providerCount: activeProviders.length,
|
|
@@ -12741,22 +12757,19 @@ var JobRunner = class {
|
|
|
12741
12757
|
}
|
|
12742
12758
|
}
|
|
12743
12759
|
incrementUsage(scope, metric, count) {
|
|
12744
|
-
const now = /* @__PURE__ */ new Date();
|
|
12745
|
-
const period = now.
|
|
12746
|
-
|
|
12747
|
-
|
|
12748
|
-
|
|
12749
|
-
|
|
12750
|
-
|
|
12751
|
-
|
|
12752
|
-
|
|
12753
|
-
|
|
12754
|
-
|
|
12755
|
-
|
|
12756
|
-
|
|
12757
|
-
updatedAt: now.toISOString()
|
|
12758
|
-
}).run();
|
|
12759
|
-
}
|
|
12760
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12761
|
+
const period = now.slice(0, 10);
|
|
12762
|
+
this.db.insert(usageCounters).values({
|
|
12763
|
+
id: crypto18.randomUUID(),
|
|
12764
|
+
scope,
|
|
12765
|
+
period,
|
|
12766
|
+
metric,
|
|
12767
|
+
count,
|
|
12768
|
+
updatedAt: now
|
|
12769
|
+
}).onConflictDoUpdate({
|
|
12770
|
+
target: [usageCounters.scope, usageCounters.period, usageCounters.metric],
|
|
12771
|
+
set: { count: sql5`${usageCounters.count} + ${count}`, updatedAt: now }
|
|
12772
|
+
}).run();
|
|
12760
12773
|
}
|
|
12761
12774
|
flushProviderUsage(projectId, providerDispatchCounts) {
|
|
12762
12775
|
for (const [providerName, count] of providerDispatchCounts.entries()) {
|
|
@@ -12957,7 +12970,7 @@ function matchesBrandKey(candidateKey, brandKeys) {
|
|
|
12957
12970
|
|
|
12958
12971
|
// src/gsc-sync.ts
|
|
12959
12972
|
import crypto19 from "crypto";
|
|
12960
|
-
import { eq as eq18, and as and7, sql as
|
|
12973
|
+
import { eq as eq18, and as and7, sql as sql6 } from "drizzle-orm";
|
|
12961
12974
|
var log2 = createLogger("GscSync");
|
|
12962
12975
|
function formatDate2(d) {
|
|
12963
12976
|
return d.toISOString().split("T")[0];
|
|
@@ -13011,8 +13024,8 @@ async function executeGscSync(db, runId, projectId, opts) {
|
|
|
13011
13024
|
db.delete(gscSearchData).where(
|
|
13012
13025
|
and7(
|
|
13013
13026
|
eq18(gscSearchData.projectId, projectId),
|
|
13014
|
-
|
|
13015
|
-
|
|
13027
|
+
sql6`${gscSearchData.date} >= ${startDate}`,
|
|
13028
|
+
sql6`${gscSearchData.date} <= ${endDate}`
|
|
13016
13029
|
)
|
|
13017
13030
|
).run();
|
|
13018
13031
|
const batchSize = 500;
|
|
@@ -13471,7 +13484,7 @@ var Scheduler = class {
|
|
|
13471
13484
|
nextRunAt,
|
|
13472
13485
|
updatedAt: now
|
|
13473
13486
|
}).where(eq20(schedules.id, currentSchedule.id)).run();
|
|
13474
|
-
const scheduleProviders =
|
|
13487
|
+
const scheduleProviders = parseJsonColumn(currentSchedule.providers, []);
|
|
13475
13488
|
const providers = scheduleProviders.length > 0 ? scheduleProviders : void 0;
|
|
13476
13489
|
log4.info("run.triggered", { runId, projectName: project.name, providers: providers ?? "all" });
|
|
13477
13490
|
this.callbacks.onRunCreated(runId, projectId, providers);
|
package/dist/cli.js
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
setGoogleAuthConfig,
|
|
27
27
|
showFirstRunNotice,
|
|
28
28
|
trackEvent
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-U2ZNKIWK.js";
|
|
30
30
|
|
|
31
31
|
// src/cli.ts
|
|
32
32
|
import { pathToFileURL } from "url";
|
|
@@ -1698,7 +1698,11 @@ async function addCompetitors(project, domains, format) {
|
|
|
1698
1698
|
}, null, 2));
|
|
1699
1699
|
return;
|
|
1700
1700
|
}
|
|
1701
|
-
|
|
1701
|
+
if (addedDomains.length === 0) {
|
|
1702
|
+
console.log(`No new competitors added to "${project}" (all already tracked).`);
|
|
1703
|
+
} else {
|
|
1704
|
+
console.log(`Added ${addedDomains.length} competitor(s) to "${project}".`);
|
|
1705
|
+
}
|
|
1702
1706
|
}
|
|
1703
1707
|
async function listCompetitors(project, format) {
|
|
1704
1708
|
const client = getClient4();
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainyc/canonry",
|
|
3
|
-
"version": "1.37.
|
|
3
|
+
"version": "1.37.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The ultimate open-source AEO monitoring tool - track how answer engines cite your domain",
|
|
6
6
|
"license": "FSL-1.1-ALv2",
|
|
@@ -55,17 +55,17 @@
|
|
|
55
55
|
"tsup": "^8.5.1",
|
|
56
56
|
"tsx": "^4.19.0",
|
|
57
57
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
58
|
-
"@ainyc/canonry-config": "0.0.0",
|
|
59
58
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
59
|
+
"@ainyc/canonry-integration-google": "0.0.0",
|
|
60
60
|
"@ainyc/canonry-db": "0.0.0",
|
|
61
|
+
"@ainyc/canonry-config": "0.0.0",
|
|
61
62
|
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
62
|
-
"@ainyc/canonry-integration-google": "0.0.0",
|
|
63
63
|
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
64
64
|
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
65
|
+
"@ainyc/canonry-provider-local": "0.0.0",
|
|
66
|
+
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
65
67
|
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
66
68
|
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
67
|
-
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
68
|
-
"@ainyc/canonry-provider-local": "0.0.0",
|
|
69
69
|
"@ainyc/canonry-provider-perplexity": "0.0.0"
|
|
70
70
|
},
|
|
71
71
|
"scripts": {
|