@ainyc/canonry 1.5.1 → 1.7.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/index-Cgb-VMub.js +205 -0
- package/assets/index.html +1 -1
- package/dist/{chunk-CKC26GOH.js → chunk-2QG7TZ4A.js} +11 -2
- package/dist/cli.js +88 -33
- package/dist/index.js +1 -1
- package/package.json +4 -4
- package/assets/assets/index-OtrziEv9.js +0 -205
package/assets/index.html
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
content="Canonry is the AINYC monitoring dashboard for answer visibility and technical readiness."
|
|
9
9
|
/>
|
|
10
10
|
<title>Canonry</title>
|
|
11
|
-
<script type="module" crossorigin src="/assets/index-
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-Cgb-VMub.js"></script>
|
|
12
12
|
<link rel="stylesheet" crossorigin href="/assets/index-BxWGYuSH.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
@@ -23,14 +23,23 @@ function loadConfig() {
|
|
|
23
23
|
const configPath = getConfigPath();
|
|
24
24
|
if (!fs.existsSync(configPath)) {
|
|
25
25
|
throw new Error(
|
|
26
|
-
`Config not found at ${configPath}.
|
|
26
|
+
`Config not found at ${configPath}.
|
|
27
|
+
Run "canonry init" to set up interactively, or "canonry init --gemini-key <key>" for non-interactive setup.
|
|
28
|
+
For CI/Docker, use "canonry bootstrap" with env vars (GEMINI_API_KEY, OPENAI_API_KEY, ANTHROPIC_API_KEY).`
|
|
27
29
|
);
|
|
28
30
|
}
|
|
29
31
|
const raw = fs.readFileSync(configPath, "utf-8");
|
|
30
32
|
const parsed = parse(raw);
|
|
31
33
|
if (!parsed.apiUrl || !parsed.database || !parsed.apiKey) {
|
|
34
|
+
const missing = [
|
|
35
|
+
!parsed.apiUrl && "apiUrl",
|
|
36
|
+
!parsed.database && "database",
|
|
37
|
+
!parsed.apiKey && "apiKey"
|
|
38
|
+
].filter(Boolean).join(", ");
|
|
32
39
|
throw new Error(
|
|
33
|
-
`Invalid config at ${configPath}
|
|
40
|
+
`Invalid config at ${configPath} \u2014 missing: ${missing}.
|
|
41
|
+
These fields are auto-generated. Run "canonry init" (or "canonry init --gemini-key <key>" for non-interactive setup) to create a valid config.
|
|
42
|
+
Do not write config.yaml by hand; use "canonry init" or "canonry bootstrap" instead.`
|
|
34
43
|
);
|
|
35
44
|
}
|
|
36
45
|
if (parsed.geminiApiKey && !parsed.providers?.gemini) {
|
package/dist/cli.js
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
saveConfig,
|
|
16
16
|
showFirstRunNotice,
|
|
17
17
|
trackEvent
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-2QG7TZ4A.js";
|
|
19
19
|
|
|
20
20
|
// src/cli.ts
|
|
21
21
|
import { parseArgs } from "util";
|
|
@@ -66,8 +66,9 @@ var bootstrapEnvSchema = z.object({
|
|
|
66
66
|
LOCAL_API_KEY: z.string().optional(),
|
|
67
67
|
LOCAL_MODEL: z.string().optional()
|
|
68
68
|
});
|
|
69
|
-
function getBootstrapEnv(source) {
|
|
70
|
-
const
|
|
69
|
+
function getBootstrapEnv(source, overrides) {
|
|
70
|
+
const filtered = overrides ? Object.fromEntries(Object.entries(overrides).filter(([, v]) => v != null)) : {};
|
|
71
|
+
const parsed = bootstrapEnvSchema.parse({ ...source, ...filtered });
|
|
71
72
|
const providers = {};
|
|
72
73
|
if (parsed.GEMINI_API_KEY) {
|
|
73
74
|
providers.gemini = {
|
|
@@ -210,29 +211,45 @@ async function initCommand(opts) {
|
|
|
210
211
|
if (!fs.existsSync(configDir)) {
|
|
211
212
|
fs.mkdirSync(configDir, { recursive: true });
|
|
212
213
|
}
|
|
214
|
+
const envProviders = getBootstrapEnv(process.env, {
|
|
215
|
+
GEMINI_API_KEY: opts?.geminiKey,
|
|
216
|
+
OPENAI_API_KEY: opts?.openaiKey,
|
|
217
|
+
ANTHROPIC_API_KEY: opts?.claudeKey,
|
|
218
|
+
LOCAL_BASE_URL: opts?.localUrl,
|
|
219
|
+
LOCAL_MODEL: opts?.localModel,
|
|
220
|
+
LOCAL_API_KEY: opts?.localKey
|
|
221
|
+
}).providers;
|
|
222
|
+
const nonInteractive = !!(envProviders.gemini || envProviders.openai || envProviders.claude || envProviders.local);
|
|
213
223
|
const providers = {};
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
224
|
+
if (nonInteractive) {
|
|
225
|
+
Object.assign(providers, envProviders);
|
|
226
|
+
} else {
|
|
227
|
+
console.log("Configure AI providers (at least one required):\n");
|
|
228
|
+
console.log("Tip: For non-interactive setup, pass --gemini-key, --openai-key,");
|
|
229
|
+
console.log("--claude-key flags or set GEMINI_API_KEY, OPENAI_API_KEY,");
|
|
230
|
+
console.log('ANTHROPIC_API_KEY env vars. Or use "canonry bootstrap".\n');
|
|
231
|
+
const geminiApiKey = await prompt("Gemini API key (press Enter to skip): ");
|
|
232
|
+
if (geminiApiKey) {
|
|
233
|
+
const geminiModel = await prompt(" Gemini model [gemini-2.5-flash]: ") || "gemini-2.5-flash";
|
|
234
|
+
providers.gemini = { apiKey: geminiApiKey, model: geminiModel, quota: DEFAULT_QUOTA };
|
|
235
|
+
}
|
|
236
|
+
const openaiApiKey = await prompt("OpenAI API key (press Enter to skip): ");
|
|
237
|
+
if (openaiApiKey) {
|
|
238
|
+
const openaiModel = await prompt(" OpenAI model [gpt-4o]: ") || "gpt-4o";
|
|
239
|
+
providers.openai = { apiKey: openaiApiKey, model: openaiModel, quota: DEFAULT_QUOTA };
|
|
240
|
+
}
|
|
241
|
+
const claudeApiKey = await prompt("Anthropic API key (press Enter to skip): ");
|
|
242
|
+
if (claudeApiKey) {
|
|
243
|
+
const claudeModel = await prompt(" Claude model [claude-sonnet-4-6]: ") || "claude-sonnet-4-6";
|
|
244
|
+
providers.claude = { apiKey: claudeApiKey, model: claudeModel, quota: DEFAULT_QUOTA };
|
|
245
|
+
}
|
|
246
|
+
console.log("\nLocal LLM (Ollama, LM Studio, llama.cpp, vLLM \u2014 any OpenAI-compatible API):");
|
|
247
|
+
const localBaseUrl = await prompt("Local LLM base URL (press Enter to skip, e.g. http://localhost:11434/v1): ");
|
|
248
|
+
if (localBaseUrl) {
|
|
249
|
+
const localModel = await prompt(" Model name [llama3]: ") || "llama3";
|
|
250
|
+
const localApiKey = await prompt(" API key (press Enter if not needed): ") || void 0;
|
|
251
|
+
providers.local = { baseUrl: localBaseUrl, apiKey: localApiKey, model: localModel, quota: DEFAULT_QUOTA };
|
|
252
|
+
}
|
|
236
253
|
}
|
|
237
254
|
const hasProvider = providers.gemini || providers.openai || providers.claude || providers.local;
|
|
238
255
|
if (!hasProvider) {
|
|
@@ -313,11 +330,22 @@ var ApiClient = class {
|
|
|
313
330
|
"Authorization": `Bearer ${this.apiKey}`,
|
|
314
331
|
"Content-Type": "application/json"
|
|
315
332
|
};
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
333
|
+
let res;
|
|
334
|
+
try {
|
|
335
|
+
res = await fetch(url, {
|
|
336
|
+
method,
|
|
337
|
+
headers,
|
|
338
|
+
body: body != null ? JSON.stringify(body) : void 0
|
|
339
|
+
});
|
|
340
|
+
} catch (err) {
|
|
341
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
342
|
+
if (msg.includes("fetch failed") || msg.includes("ECONNREFUSED") || msg.includes("connect ECONNREFUSED")) {
|
|
343
|
+
throw new Error(
|
|
344
|
+
`Could not connect to canonry server at ${this.baseUrl.replace("/api/v1", "")}. Start it with "canonry serve" (or "canonry serve &" to run in background).`
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
throw err;
|
|
348
|
+
}
|
|
321
349
|
if (!res.ok) {
|
|
322
350
|
let errorBody;
|
|
323
351
|
try {
|
|
@@ -956,7 +984,8 @@ var USAGE = `
|
|
|
956
984
|
canonry \u2014 AEO monitoring CLI
|
|
957
985
|
|
|
958
986
|
Usage:
|
|
959
|
-
canonry init [--force] Initialize config and database
|
|
987
|
+
canonry init [--force] Initialize config and database (interactive)
|
|
988
|
+
canonry init --gemini-key <key> Initialize non-interactively (also reads env vars)
|
|
960
989
|
canonry bootstrap [--force] Bootstrap config/database from env vars
|
|
961
990
|
canonry serve Start the local server
|
|
962
991
|
canonry project create <name> Create a project
|
|
@@ -995,6 +1024,12 @@ Usage:
|
|
|
995
1024
|
canonry --version Show version
|
|
996
1025
|
|
|
997
1026
|
Options:
|
|
1027
|
+
--gemini-key <key> Gemini API key (or GEMINI_API_KEY env var)
|
|
1028
|
+
--openai-key <key> OpenAI API key (or OPENAI_API_KEY env var)
|
|
1029
|
+
--claude-key <key> Anthropic API key (or ANTHROPIC_API_KEY env var)
|
|
1030
|
+
--local-url <url> Local LLM base URL (or LOCAL_BASE_URL env var)
|
|
1031
|
+
--local-model <name> Local LLM model name (default: llama3)
|
|
1032
|
+
--local-key <key> Local LLM API key (or LOCAL_API_KEY env var)
|
|
998
1033
|
--port <port> Server port (default: 4100)
|
|
999
1034
|
--host <host> Server bind address (default: 127.0.0.1)
|
|
1000
1035
|
--domain <domain> Canonical domain for project create
|
|
@@ -1033,8 +1068,28 @@ async function main() {
|
|
|
1033
1068
|
try {
|
|
1034
1069
|
switch (command) {
|
|
1035
1070
|
case "init": {
|
|
1036
|
-
const
|
|
1037
|
-
|
|
1071
|
+
const { values: initValues } = parseArgs({
|
|
1072
|
+
args: args.slice(1),
|
|
1073
|
+
options: {
|
|
1074
|
+
force: { type: "boolean", short: "f", default: false },
|
|
1075
|
+
"gemini-key": { type: "string" },
|
|
1076
|
+
"openai-key": { type: "string" },
|
|
1077
|
+
"claude-key": { type: "string" },
|
|
1078
|
+
"local-url": { type: "string" },
|
|
1079
|
+
"local-model": { type: "string" },
|
|
1080
|
+
"local-key": { type: "string" }
|
|
1081
|
+
},
|
|
1082
|
+
allowPositionals: false
|
|
1083
|
+
});
|
|
1084
|
+
await initCommand({
|
|
1085
|
+
force: initValues.force,
|
|
1086
|
+
geminiKey: initValues["gemini-key"],
|
|
1087
|
+
openaiKey: initValues["openai-key"],
|
|
1088
|
+
claudeKey: initValues["claude-key"],
|
|
1089
|
+
localUrl: initValues["local-url"],
|
|
1090
|
+
localModel: initValues["local-model"],
|
|
1091
|
+
localKey: initValues["local-key"]
|
|
1092
|
+
});
|
|
1038
1093
|
break;
|
|
1039
1094
|
}
|
|
1040
1095
|
case "bootstrap": {
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainyc/canonry",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
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",
|
|
@@ -52,12 +52,12 @@
|
|
|
52
52
|
"tsup": "^8.5.1",
|
|
53
53
|
"tsx": "^4.19.0",
|
|
54
54
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
55
|
-
"@ainyc/canonry-config": "0.0.0",
|
|
56
55
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
57
|
-
"@ainyc/canonry-
|
|
56
|
+
"@ainyc/canonry-config": "0.0.0",
|
|
58
57
|
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
59
|
-
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
60
58
|
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
59
|
+
"@ainyc/canonry-db": "0.0.0",
|
|
60
|
+
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
61
61
|
"@ainyc/canonry-provider-local": "0.0.0"
|
|
62
62
|
},
|
|
63
63
|
"scripts": {
|