@ainyc/canonry 4.180.6 → 4.180.8
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/README.md +4 -0
- package/assets/agent-workspace/skills/canonry/SKILL.md +13 -10
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +7 -6
- package/assets/assets/{AuditHistoryPanel-Cwgbldst.js → AuditHistoryPanel-qiuqNGvG.js} +1 -1
- package/assets/assets/{BacklinksPage-h08vP0Of.js → BacklinksPage-D-g5f0Xv.js} +1 -1
- package/assets/assets/{HistoryPage-Dwyad0V0.js → HistoryPage-q8_pCuOs.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-DOyOHeiU.js → MeasurementPropertyPage-C_wMjUZe.js} +1 -1
- package/assets/assets/ProjectPage-33THfDtC.js +9 -0
- package/assets/assets/{RunRow-CVl2cqfG.js → RunRow-D5hatdlY.js} +1 -1
- package/assets/assets/{RunsPage-zzN2iQbk.js → RunsPage-Bj2snMM3.js} +1 -1
- package/assets/assets/SettingsPage-Cf5YgyJv.js +1 -0
- package/assets/assets/SiteHealthSection-D8RLvMAE.js +4 -0
- package/assets/assets/TrafficPage-CotJ14le.js +1 -0
- package/assets/assets/{TrafficSourceDetailPage-BnbNPkis.js → TrafficSourceDetailPage-BcxYX-uq.js} +1 -1
- package/assets/assets/{extract-error-message-Ctp1FqW1.js → extract-error-message-Bxt42scd.js} +1 -1
- package/assets/assets/index-BlILyZJ5.js +86 -0
- package/assets/assets/index-DXCQf5s1.css +1 -0
- package/assets/assets/{react-sigma_core.esm.min-DwnhdseV.js → react-sigma_core.esm.min-DxZINEmi.js} +1 -1
- package/assets/index.html +2 -2
- package/dist/{chunk-XYTSKRO3.js → chunk-G7M2KM7Q.js} +2 -2
- package/dist/{chunk-VZO6CLHY.js → chunk-GFVZOVG3.js} +105 -64
- package/dist/{chunk-RXXZ5BU5.js → chunk-GN2G7VFK.js} +24 -1
- package/dist/{chunk-CWXPBQR5.js → chunk-IM4HFNGF.js} +7 -5
- package/dist/{chunk-WJFBNCVD.js → chunk-ZJ2VGTYU.js} +197 -95
- package/dist/cli.js +187 -96
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-MEPYXRBS.js → intelligence-service-IURLYRB3.js} +2 -2
- package/dist/mcp.js +3 -3
- package/package.json +10 -10
- package/assets/assets/ProjectPage-D9e_1Gpz.js +0 -9
- package/assets/assets/SettingsPage-qiQLOtpd.js +0 -1
- package/assets/assets/SiteHealthSection-R0MWiuZX.js +0 -4
- package/assets/assets/TrafficPage-CEA76iwx.js +0 -1
- package/assets/assets/index-BD8hYPvq.css +0 -1
- package/assets/assets/index-D-OGmIKF.js +0 -83
package/dist/cli.js
CHANGED
|
@@ -19,18 +19,20 @@ import {
|
|
|
19
19
|
getOrCreateAnonymousId,
|
|
20
20
|
isAeroToolProfile,
|
|
21
21
|
isFirstRun,
|
|
22
|
+
isLoopbackBindHost,
|
|
22
23
|
isTelemetryEnabled,
|
|
23
24
|
listAgentProviders,
|
|
24
25
|
setGoogleAuthConfig,
|
|
25
26
|
setTelemetrySource,
|
|
26
27
|
showFirstRunNotice,
|
|
27
28
|
trackCliCommandFinished,
|
|
28
|
-
trackEvent
|
|
29
|
-
|
|
29
|
+
trackEvent,
|
|
30
|
+
waitForServerRuntimeStartup
|
|
31
|
+
} from "./chunk-GFVZOVG3.js";
|
|
30
32
|
import {
|
|
31
33
|
autoSyncSkills,
|
|
32
34
|
formatAutoSyncNotice
|
|
33
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-G7M2KM7Q.js";
|
|
34
36
|
import {
|
|
35
37
|
CliError,
|
|
36
38
|
EXIT_SYSTEM_ERROR,
|
|
@@ -55,7 +57,7 @@ import {
|
|
|
55
57
|
saveConfigPatch,
|
|
56
58
|
systemError,
|
|
57
59
|
usageError
|
|
58
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-IM4HFNGF.js";
|
|
59
61
|
import {
|
|
60
62
|
CLOUDFLARE_WORKER_BINDINGS,
|
|
61
63
|
CLOUDFLARE_WORKER_GENERATED_MARKER,
|
|
@@ -69,7 +71,7 @@ import {
|
|
|
69
71
|
projects,
|
|
70
72
|
queries,
|
|
71
73
|
renderReportHtml
|
|
72
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-ZJ2VGTYU.js";
|
|
73
75
|
import {
|
|
74
76
|
AdsDeliverySnapshotStatuses,
|
|
75
77
|
AdsHistoricalCampaignRollupStatuses,
|
|
@@ -138,7 +140,7 @@ import {
|
|
|
138
140
|
providerQuotaPolicySchema,
|
|
139
141
|
resolveProviderInput,
|
|
140
142
|
winnabilityClassSchema
|
|
141
|
-
} from "./chunk-
|
|
143
|
+
} from "./chunk-GN2G7VFK.js";
|
|
142
144
|
|
|
143
145
|
// src/cli.ts
|
|
144
146
|
import { pathToFileURL } from "url";
|
|
@@ -184,6 +186,13 @@ import { parseArgs } from "util";
|
|
|
184
186
|
function commandId(spec) {
|
|
185
187
|
return spec.path.join(".");
|
|
186
188
|
}
|
|
189
|
+
function printCommandHelp(spec) {
|
|
190
|
+
console.log(`
|
|
191
|
+
Usage: ${spec.usage}
|
|
192
|
+
`);
|
|
193
|
+
if (spec.help) console.log(`${spec.help}
|
|
194
|
+
`);
|
|
195
|
+
}
|
|
187
196
|
function matchesPath(args, path13) {
|
|
188
197
|
if (args.length < path13.length) return false;
|
|
189
198
|
return path13.every((segment, index) => args[index] === segment);
|
|
@@ -222,9 +231,7 @@ async function dispatchRegisteredCommand(args, fallbackFormat, specs) {
|
|
|
222
231
|
const argsWithoutHelp = args.filter((a) => a !== "--help" && a !== "-h");
|
|
223
232
|
const exactMatch = [...specs].sort((a, b) => b.path.length - a.path.length).find((candidate) => matchesPath(argsWithoutHelp, candidate.path));
|
|
224
233
|
if (exactMatch && exactMatch.path.length > 1) {
|
|
225
|
-
|
|
226
|
-
Usage: ${exactMatch.usage}
|
|
227
|
-
`);
|
|
234
|
+
printCommandHelp(exactMatch);
|
|
228
235
|
return true;
|
|
229
236
|
}
|
|
230
237
|
const group = argsWithoutHelp[0];
|
|
@@ -236,9 +243,7 @@ Usage: ${exactMatch.usage}
|
|
|
236
243
|
}
|
|
237
244
|
const single = specs.find((s) => s.path.length === 1 && s.path[0] === group);
|
|
238
245
|
if (single) {
|
|
239
|
-
|
|
240
|
-
Usage: ${single.usage}
|
|
241
|
-
`);
|
|
246
|
+
printCommandHelp(single);
|
|
242
247
|
return true;
|
|
243
248
|
}
|
|
244
249
|
}
|
|
@@ -13866,6 +13871,7 @@ var CONTENT_CLI_COMMANDS = [
|
|
|
13866
13871
|
// src/commands/bootstrap.ts
|
|
13867
13872
|
import crypto from "crypto";
|
|
13868
13873
|
import path9 from "path";
|
|
13874
|
+
import { isDeepStrictEqual } from "util";
|
|
13869
13875
|
import { eq } from "drizzle-orm";
|
|
13870
13876
|
|
|
13871
13877
|
// ../config/src/index.ts
|
|
@@ -14011,36 +14017,40 @@ function getBootstrapEnv(source, overrides) {
|
|
|
14011
14017
|
}
|
|
14012
14018
|
|
|
14013
14019
|
// src/commands/bootstrap.ts
|
|
14014
|
-
|
|
14015
|
-
|
|
14016
|
-
|
|
14017
|
-
|
|
14018
|
-
|
|
14019
|
-
if (!hasProvider) {
|
|
14020
|
-
console.warn(
|
|
14021
|
-
"Warning: No provider env vars set (GEMINI_API_KEY, OPENAI_API_KEY, ANTHROPIC_API_KEY, PERPLEXITY_API_KEY, or LOCAL_BASE_URL). You can configure providers later via the dashboard."
|
|
14020
|
+
function persistedValue(value) {
|
|
14021
|
+
if (Array.isArray(value)) return value.map(persistedValue);
|
|
14022
|
+
if (value && typeof value === "object") {
|
|
14023
|
+
return Object.fromEntries(
|
|
14024
|
+
Object.entries(value).filter(([, entry]) => entry !== void 0).map(([key, entry]) => [key, persistedValue(entry)])
|
|
14022
14025
|
);
|
|
14023
14026
|
}
|
|
14027
|
+
return value;
|
|
14028
|
+
}
|
|
14029
|
+
async function bootstrapCommand(opts) {
|
|
14030
|
+
const format = opts?.format ?? "text";
|
|
14031
|
+
const env = getBootstrapEnv(process.env);
|
|
14032
|
+
const providers = env.providers;
|
|
14024
14033
|
const configDir = getConfigDir();
|
|
14025
|
-
const databasePath = env.databasePath || path9.join(configDir, "data.db");
|
|
14026
14034
|
const existing = configExists();
|
|
14027
14035
|
const existingConfig = existing ? loadConfig() : void 0;
|
|
14036
|
+
const existingRaw = existing ? loadConfigRaw() : null;
|
|
14037
|
+
const databasePath = env.databasePath || existingRaw?.database || path9.join(configDir, "data.db");
|
|
14028
14038
|
let rawApiKey;
|
|
14029
14039
|
let generatedApiKey;
|
|
14030
14040
|
if (env.apiKey) {
|
|
14031
14041
|
rawApiKey = env.apiKey;
|
|
14032
|
-
} else if (
|
|
14033
|
-
rawApiKey =
|
|
14042
|
+
} else if (existingRaw) {
|
|
14043
|
+
rawApiKey = existingRaw.apiKey;
|
|
14034
14044
|
} else {
|
|
14035
14045
|
generatedApiKey = `cnry_${crypto.randomBytes(16).toString("hex")}`;
|
|
14036
14046
|
rawApiKey = generatedApiKey;
|
|
14037
14047
|
}
|
|
14038
14048
|
const mergedProviders = { ...existingConfig?.providers };
|
|
14039
|
-
if (providers
|
|
14040
|
-
if (providers
|
|
14041
|
-
if (providers
|
|
14042
|
-
if (providers
|
|
14043
|
-
if (providers
|
|
14049
|
+
if (providers.gemini) mergedProviders.gemini = providers.gemini;
|
|
14050
|
+
if (providers.openai) mergedProviders.openai = providers.openai;
|
|
14051
|
+
if (providers.claude) mergedProviders.claude = providers.claude;
|
|
14052
|
+
if (providers.perplexity) mergedProviders.perplexity = providers.perplexity;
|
|
14053
|
+
if (providers.local) mergedProviders.local = providers.local;
|
|
14044
14054
|
if (env.googleClientId && !env.googleClientSecret || !env.googleClientId && env.googleClientSecret) {
|
|
14045
14055
|
console.warn("Warning: GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET must both be set to configure Google OAuth. Skipping Google auth config.");
|
|
14046
14056
|
}
|
|
@@ -14051,25 +14061,42 @@ async function bootstrapCommand(_opts) {
|
|
|
14051
14061
|
} : existingConfig?.google;
|
|
14052
14062
|
const keyHash = crypto.createHash("sha256").update(rawApiKey).digest("hex");
|
|
14053
14063
|
const keyPrefix = rawApiKey.slice(0, 9);
|
|
14054
|
-
const existingConfigKeyHash =
|
|
14064
|
+
const existingConfigKeyHash = existingRaw ? crypto.createHash("sha256").update(existingRaw.apiKey).digest("hex") : void 0;
|
|
14055
14065
|
const db = createClient(databasePath);
|
|
14056
14066
|
migrate(db);
|
|
14057
|
-
db.transaction((tx) => {
|
|
14067
|
+
const keyChanged = db.transaction((tx) => {
|
|
14068
|
+
let changed = false;
|
|
14058
14069
|
const rotatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
14059
|
-
const existingDefaults = tx.select({
|
|
14070
|
+
const existingDefaults = tx.select({
|
|
14071
|
+
id: apiKeys.id,
|
|
14072
|
+
keyHash: apiKeys.keyHash,
|
|
14073
|
+
keyPrefix: apiKeys.keyPrefix,
|
|
14074
|
+
scopes: apiKeys.scopes,
|
|
14075
|
+
projectId: apiKeys.projectId,
|
|
14076
|
+
lastUsedAt: apiKeys.lastUsedAt,
|
|
14077
|
+
revokedAt: apiKeys.revokedAt
|
|
14078
|
+
}).from(apiKeys).where(eq(apiKeys.name, "default")).all();
|
|
14060
14079
|
const existingDefault = existingDefaults.find((key) => key.keyHash === existingConfigKeyHash) ?? existingDefaults.at(0);
|
|
14061
14080
|
if (existingDefault) {
|
|
14062
|
-
|
|
14063
|
-
|
|
14064
|
-
|
|
14065
|
-
|
|
14066
|
-
|
|
14067
|
-
|
|
14068
|
-
|
|
14069
|
-
|
|
14081
|
+
const rotating = existingDefault.keyHash !== keyHash;
|
|
14082
|
+
const needsUpdate = rotating || existingDefault.keyPrefix !== keyPrefix || !isDeepStrictEqual(existingDefault.scopes, ["*"]) || existingDefault.projectId !== null || existingDefault.revokedAt !== null;
|
|
14083
|
+
if (needsUpdate) {
|
|
14084
|
+
tx.update(apiKeys).set({
|
|
14085
|
+
keyHash,
|
|
14086
|
+
keyPrefix,
|
|
14087
|
+
scopes: ["*"],
|
|
14088
|
+
projectId: null,
|
|
14089
|
+
...rotating ? { lastUsedAt: null } : {},
|
|
14090
|
+
revokedAt: null
|
|
14091
|
+
}).where(eq(apiKeys.id, existingDefault.id)).run();
|
|
14092
|
+
changed = true;
|
|
14093
|
+
}
|
|
14070
14094
|
for (const duplicate of existingDefaults) {
|
|
14071
14095
|
if (duplicate.id === existingDefault.id) continue;
|
|
14072
|
-
|
|
14096
|
+
if (duplicate.revokedAt === null) {
|
|
14097
|
+
tx.update(apiKeys).set({ revokedAt: rotatedAt }).where(eq(apiKeys.id, duplicate.id)).run();
|
|
14098
|
+
changed = true;
|
|
14099
|
+
}
|
|
14073
14100
|
}
|
|
14074
14101
|
} else {
|
|
14075
14102
|
tx.insert(apiKeys).values({
|
|
@@ -14080,29 +14107,41 @@ async function bootstrapCommand(_opts) {
|
|
|
14080
14107
|
scopes: ["*"],
|
|
14081
14108
|
createdAt: rotatedAt
|
|
14082
14109
|
}).run();
|
|
14110
|
+
changed = true;
|
|
14083
14111
|
}
|
|
14112
|
+
return changed;
|
|
14084
14113
|
});
|
|
14085
|
-
|
|
14086
|
-
|
|
14114
|
+
const apiUrl = env.apiUrl || existingRaw?.apiUrl || `http://127.0.0.1:${process.env.CANONRY_PORT || "4100"}`;
|
|
14115
|
+
const nextConfig = {
|
|
14116
|
+
...existingRaw,
|
|
14117
|
+
apiUrl,
|
|
14087
14118
|
database: databasePath,
|
|
14088
14119
|
apiKey: rawApiKey,
|
|
14089
14120
|
providers: mergedProviders,
|
|
14090
14121
|
google: mergedGoogle
|
|
14091
|
-
}
|
|
14122
|
+
};
|
|
14123
|
+
const configChanged = !existingRaw || existingRaw.apiUrl !== apiUrl || existingRaw.database !== databasePath || existingRaw.apiKey !== rawApiKey || !isDeepStrictEqual(persistedValue(existingRaw.providers ?? {}), persistedValue(mergedProviders)) || !isDeepStrictEqual(persistedValue(existingRaw.google), persistedValue(mergedGoogle));
|
|
14124
|
+
if (configChanged) saveConfig(nextConfig);
|
|
14125
|
+
const status = !existing ? "created" : configChanged || keyChanged ? "updated" : "unchanged";
|
|
14092
14126
|
if (format === "json") {
|
|
14093
14127
|
console.log(JSON.stringify({
|
|
14094
14128
|
bootstrapped: true,
|
|
14129
|
+
status,
|
|
14130
|
+
changed: status !== "unchanged",
|
|
14095
14131
|
configPath: getConfigPath(),
|
|
14096
14132
|
databasePath,
|
|
14097
|
-
apiUrl
|
|
14098
|
-
providers: Object.keys(mergedProviders
|
|
14133
|
+
apiUrl,
|
|
14134
|
+
providers: Object.keys(mergedProviders),
|
|
14099
14135
|
googleConfigured: !!mergedGoogle,
|
|
14100
14136
|
generatedApiKey
|
|
14101
14137
|
}, null, 2));
|
|
14102
14138
|
return;
|
|
14103
14139
|
}
|
|
14104
|
-
console.log(`Bootstrap
|
|
14140
|
+
console.log(`Bootstrap ${status}. Config: ${getConfigPath()}`);
|
|
14105
14141
|
console.log(`SQLite database path: ${databasePath}`);
|
|
14142
|
+
if (Object.keys(mergedProviders).length === 0) {
|
|
14143
|
+
console.log("Providers: none (Page Health works now; add one later to enable AI Visibility).");
|
|
14144
|
+
}
|
|
14106
14145
|
if (generatedApiKey) {
|
|
14107
14146
|
console.log(`API key: ${generatedApiKey}`);
|
|
14108
14147
|
}
|
|
@@ -14112,6 +14151,27 @@ async function bootstrapCommand(_opts) {
|
|
|
14112
14151
|
import { spawn as spawn2 } from "child_process";
|
|
14113
14152
|
import fs15 from "fs";
|
|
14114
14153
|
import path10 from "path";
|
|
14154
|
+
|
|
14155
|
+
// src/operator-url.ts
|
|
14156
|
+
function operatorHost(bindHost) {
|
|
14157
|
+
if (bindHost === "0.0.0.0") return "127.0.0.1";
|
|
14158
|
+
if (bindHost === "::" || bindHost === "[::]") return "::1";
|
|
14159
|
+
return bindHost;
|
|
14160
|
+
}
|
|
14161
|
+
function operatorHttpUrl(bindHost, port) {
|
|
14162
|
+
const host = operatorHost(bindHost);
|
|
14163
|
+
const bare = host.replace(/^\[|\]$/g, "");
|
|
14164
|
+
return `http://${bare.includes(":") ? `[${bare}]` : bare}:${port}`;
|
|
14165
|
+
}
|
|
14166
|
+
|
|
14167
|
+
// src/serve-endpoint.ts
|
|
14168
|
+
function resolveServePort(envPort, configPort) {
|
|
14169
|
+
const trimmed = envPort?.trim();
|
|
14170
|
+
if (trimmed) return parseInt(trimmed, 10);
|
|
14171
|
+
return configPort ?? 4100;
|
|
14172
|
+
}
|
|
14173
|
+
|
|
14174
|
+
// src/commands/daemon.ts
|
|
14115
14175
|
function getPidPath() {
|
|
14116
14176
|
return path10.join(getConfigDir(), "canonry.pid");
|
|
14117
14177
|
}
|
|
@@ -14125,7 +14185,7 @@ function isProcessAlive(pid) {
|
|
|
14125
14185
|
}
|
|
14126
14186
|
}
|
|
14127
14187
|
async function waitForReady(host, port, maxMs = 1e4) {
|
|
14128
|
-
const url =
|
|
14188
|
+
const url = `${operatorHttpUrl(host, port)}/health`;
|
|
14129
14189
|
const deadline = Date.now() + maxMs;
|
|
14130
14190
|
while (Date.now() < deadline) {
|
|
14131
14191
|
try {
|
|
@@ -14137,6 +14197,13 @@ async function waitForReady(host, port, maxMs = 1e4) {
|
|
|
14137
14197
|
}
|
|
14138
14198
|
return false;
|
|
14139
14199
|
}
|
|
14200
|
+
function resolveDaemonEndpoint(opts, env, configPort) {
|
|
14201
|
+
const portInput = opts.port || env.CANONRY_PORT;
|
|
14202
|
+
return {
|
|
14203
|
+
host: opts.host || env.CANONRY_HOST || "127.0.0.1",
|
|
14204
|
+
port: resolveServePort(portInput, configPort)
|
|
14205
|
+
};
|
|
14206
|
+
}
|
|
14140
14207
|
function buildServeForwardArgs(opts) {
|
|
14141
14208
|
const args = [];
|
|
14142
14209
|
if (opts.port) args.push("--port", opts.port);
|
|
@@ -14167,10 +14234,14 @@ async function startDaemon(opts) {
|
|
|
14167
14234
|
}
|
|
14168
14235
|
fs15.unlinkSync(pidPath);
|
|
14169
14236
|
}
|
|
14237
|
+
const config = loadConfig();
|
|
14238
|
+
const endpoint = resolveDaemonEndpoint(opts, process.env, config.port);
|
|
14239
|
+
const host = endpoint.host;
|
|
14240
|
+
const port = String(endpoint.port);
|
|
14170
14241
|
const cliPath = path10.resolve(new URL(import.meta.url).pathname);
|
|
14171
14242
|
const inSourceMode = new URL(import.meta.url).pathname.endsWith(".ts");
|
|
14172
14243
|
const args = inSourceMode ? ["--import", "tsx", cliPath, "serve"] : [cliPath, "serve"];
|
|
14173
|
-
args.push(...buildServeForwardArgs(opts));
|
|
14244
|
+
args.push(...buildServeForwardArgs({ ...opts, host, port }));
|
|
14174
14245
|
const child = spawn2(process.execPath, args, {
|
|
14175
14246
|
detached: true,
|
|
14176
14247
|
stdio: "ignore"
|
|
@@ -14188,13 +14259,15 @@ async function startDaemon(opts) {
|
|
|
14188
14259
|
fs15.mkdirSync(configDir, { recursive: true });
|
|
14189
14260
|
}
|
|
14190
14261
|
fs15.writeFileSync(pidPath, String(child.pid), "utf-8");
|
|
14191
|
-
const port = opts.port ?? "4100";
|
|
14192
|
-
const host = opts.host ?? "127.0.0.1";
|
|
14193
14262
|
if (!isMachineFormat(format)) {
|
|
14194
14263
|
process.stderr.write("Waiting for server to start...");
|
|
14195
14264
|
}
|
|
14196
14265
|
const ready = await waitForReady(host, port);
|
|
14197
14266
|
if (!ready) {
|
|
14267
|
+
try {
|
|
14268
|
+
child.kill("SIGTERM");
|
|
14269
|
+
} catch {
|
|
14270
|
+
}
|
|
14198
14271
|
try {
|
|
14199
14272
|
fs15.unlinkSync(pidPath);
|
|
14200
14273
|
} catch {
|
|
@@ -14213,7 +14286,7 @@ async function startDaemon(opts) {
|
|
|
14213
14286
|
if (!isMachineFormat(format)) {
|
|
14214
14287
|
process.stderr.write("\n");
|
|
14215
14288
|
}
|
|
14216
|
-
const url =
|
|
14289
|
+
const url = operatorHttpUrl(host, port);
|
|
14217
14290
|
if (isMachineFormat(format)) {
|
|
14218
14291
|
console.log(JSON.stringify({
|
|
14219
14292
|
started: true,
|
|
@@ -14490,7 +14563,7 @@ async function initCommand(opts) {
|
|
|
14490
14563
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
14491
14564
|
}).run();
|
|
14492
14565
|
saveConfig({
|
|
14493
|
-
apiUrl: `http://
|
|
14566
|
+
apiUrl: `http://127.0.0.1:${process.env.CANONRY_PORT || "4100"}`,
|
|
14494
14567
|
database: databasePath,
|
|
14495
14568
|
apiKey: rawApiKey,
|
|
14496
14569
|
providers,
|
|
@@ -14537,7 +14610,7 @@ async function initCommand(opts) {
|
|
|
14537
14610
|
initialized: true,
|
|
14538
14611
|
configPath: getConfigPath(),
|
|
14539
14612
|
databasePath,
|
|
14540
|
-
apiUrl: `http://
|
|
14613
|
+
apiUrl: `http://127.0.0.1:${process.env.CANONRY_PORT || "4100"}`,
|
|
14541
14614
|
apiKey: rawApiKey,
|
|
14542
14615
|
providers: providerNames,
|
|
14543
14616
|
googleConfigured: !!google,
|
|
@@ -14594,7 +14667,7 @@ ${mcpTip}`);
|
|
|
14594
14667
|
}
|
|
14595
14668
|
if (!isMachineFormat(format)) {
|
|
14596
14669
|
showFirstRunNotice();
|
|
14597
|
-
console.log("\nNext: canonry serve to
|
|
14670
|
+
console.log("\nNext: canonry serve to map your site and capture a Page Health baseline.");
|
|
14598
14671
|
console.log("\nNext steps:");
|
|
14599
14672
|
for (const line of nextSteps) {
|
|
14600
14673
|
console.log(` ${line}`);
|
|
@@ -14630,27 +14703,27 @@ ${mcpTip}`);
|
|
|
14630
14703
|
const answer = await prompt("\nStart the dashboard now? [Y/n]: ");
|
|
14631
14704
|
if (!/^n/i.test(answer.trim())) {
|
|
14632
14705
|
pendingServeHandoff = true;
|
|
14633
|
-
console.log("Handing off to the dashboard.
|
|
14706
|
+
console.log("Handing off to the dashboard. Map your site at /setup once it is up.");
|
|
14634
14707
|
}
|
|
14635
14708
|
}
|
|
14636
14709
|
return agentLLM;
|
|
14637
14710
|
}
|
|
14638
14711
|
function buildNextSteps() {
|
|
14639
14712
|
return [
|
|
14640
|
-
"1. Start the dashboard and open
|
|
14713
|
+
"1. Start the dashboard and open Page Health setup:",
|
|
14641
14714
|
" canonry serve",
|
|
14642
|
-
" \u2192 http://
|
|
14715
|
+
" \u2192 http://127.0.0.1:4100/setup",
|
|
14643
14716
|
"",
|
|
14644
|
-
"
|
|
14645
|
-
"
|
|
14717
|
+
" Map your public site and capture a persisted Page Health baseline.",
|
|
14718
|
+
" AI Visibility is optional and can be configured after Page Health.",
|
|
14646
14719
|
" For remote/exposed hosts, complete dashboard password setup from loopback first.",
|
|
14647
14720
|
"",
|
|
14648
14721
|
"Prefer the terminal? The same flow as CLI commands:",
|
|
14649
14722
|
"",
|
|
14650
14723
|
" a. canonry project create my-site --domain example.com --country US --language en",
|
|
14651
|
-
|
|
14652
|
-
" c. canonry
|
|
14653
|
-
" d. canonry
|
|
14724
|
+
" b. canonry technical-aeo run my-site --max-pages 100 --wait --format json",
|
|
14725
|
+
" c. canonry technical-aeo score my-site --format json",
|
|
14726
|
+
" d. canonry technical-aeo pages my-site --sort score-asc --limit 10 --format jsonl",
|
|
14654
14727
|
"",
|
|
14655
14728
|
'Tip: "canonry doctor" verifies your setup before you start.'
|
|
14656
14729
|
];
|
|
@@ -14869,10 +14942,8 @@ function detectCanonryAgentPlugin(opts = {}) {
|
|
|
14869
14942
|
}
|
|
14870
14943
|
|
|
14871
14944
|
// src/commands/serve.ts
|
|
14872
|
-
function
|
|
14873
|
-
|
|
14874
|
-
if (trimmed) return parseInt(trimmed, 10);
|
|
14875
|
-
return configPort ?? 4100;
|
|
14945
|
+
function shouldWarnAboutRemoteSetup(host) {
|
|
14946
|
+
return !isLoopbackBindHost(host);
|
|
14876
14947
|
}
|
|
14877
14948
|
async function serveCommand(format = "text") {
|
|
14878
14949
|
const config = loadConfig();
|
|
@@ -14911,26 +14982,29 @@ async function serveCommand(format = "text") {
|
|
|
14911
14982
|
codexHome: process.env.CODEX_HOME
|
|
14912
14983
|
});
|
|
14913
14984
|
const app = await createServer({ config, db, host, getAgentPluginState });
|
|
14914
|
-
let
|
|
14915
|
-
const shutdown = (signal) => {
|
|
14916
|
-
if (shuttingDown) return;
|
|
14917
|
-
shuttingDown = true;
|
|
14918
|
-
if (format === "text") {
|
|
14919
|
-
console.log(`
|
|
14920
|
-
Received ${signal}, stopping server...`);
|
|
14921
|
-
}
|
|
14922
|
-
closeWithIdleSweep(app).then(() => {
|
|
14923
|
-
process.exit(0);
|
|
14924
|
-
}).catch((err) => {
|
|
14925
|
-
console.error("Error during shutdown:", err);
|
|
14926
|
-
process.exit(1);
|
|
14927
|
-
});
|
|
14928
|
-
};
|
|
14929
|
-
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
14930
|
-
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
14985
|
+
let listening = false;
|
|
14931
14986
|
try {
|
|
14932
14987
|
await app.listen({ host, port });
|
|
14933
|
-
|
|
14988
|
+
await waitForServerRuntimeStartup(app);
|
|
14989
|
+
listening = true;
|
|
14990
|
+
let shuttingDown = false;
|
|
14991
|
+
const shutdown = (signal) => {
|
|
14992
|
+
if (shuttingDown) return;
|
|
14993
|
+
shuttingDown = true;
|
|
14994
|
+
if (format === "text") {
|
|
14995
|
+
console.log(`
|
|
14996
|
+
Received ${signal}, stopping server...`);
|
|
14997
|
+
}
|
|
14998
|
+
closeWithIdleSweep(app).then(() => {
|
|
14999
|
+
process.exit(0);
|
|
15000
|
+
}).catch((err) => {
|
|
15001
|
+
console.error("Error during shutdown:", err);
|
|
15002
|
+
process.exit(1);
|
|
15003
|
+
});
|
|
15004
|
+
};
|
|
15005
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
15006
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
15007
|
+
const url = operatorHttpUrl(host, port);
|
|
14934
15008
|
if (isMachineFormat(format)) {
|
|
14935
15009
|
console.log(JSON.stringify({
|
|
14936
15010
|
started: true,
|
|
@@ -14941,8 +15015,8 @@ Received ${signal}, stopping server...`);
|
|
|
14941
15015
|
} else {
|
|
14942
15016
|
console.log(`
|
|
14943
15017
|
Canonry server running at ${url}`);
|
|
14944
|
-
console.log(`Open ${url}/setup to
|
|
14945
|
-
if (host
|
|
15018
|
+
console.log(`Open ${url}/setup to map your site and run your first Page Health scan.`);
|
|
15019
|
+
if (shouldWarnAboutRemoteSetup(host)) {
|
|
14946
15020
|
console.log("First-run dashboard password setup is unauthenticated only on loopback; complete setup from this machine first or use a bearer cnry_... key.");
|
|
14947
15021
|
}
|
|
14948
15022
|
console.log("Press Ctrl+C to stop.\n");
|
|
@@ -14960,6 +15034,17 @@ Canonry server running at ${url}`);
|
|
|
14960
15034
|
});
|
|
14961
15035
|
} catch (err) {
|
|
14962
15036
|
const message = describeError(err);
|
|
15037
|
+
if (listening) {
|
|
15038
|
+
process.stderr.write(`warning: server started but post-startup reporting failed: ${message}
|
|
15039
|
+
`);
|
|
15040
|
+
return;
|
|
15041
|
+
}
|
|
15042
|
+
try {
|
|
15043
|
+
await closeWithIdleSweep(app);
|
|
15044
|
+
} catch (closeErr) {
|
|
15045
|
+
process.stderr.write(`warning: failed to close server after startup error: ${describeError(closeErr)}
|
|
15046
|
+
`);
|
|
15047
|
+
}
|
|
14963
15048
|
throw new CliError({
|
|
14964
15049
|
code: "SERVE_START_FAILED",
|
|
14965
15050
|
message: `Failed to start server: ${message}`,
|
|
@@ -15016,7 +15101,7 @@ function telemetryCommand(subcommand, format = "text") {
|
|
|
15016
15101
|
console.log(JSON.stringify(payload, null, 2));
|
|
15017
15102
|
return;
|
|
15018
15103
|
}
|
|
15019
|
-
console.log('Telemetry: enabled (no config yet \u2014 run "canonry
|
|
15104
|
+
console.log('Telemetry: enabled (no config yet \u2014 run "canonry bootstrap" first)');
|
|
15020
15105
|
return;
|
|
15021
15106
|
}
|
|
15022
15107
|
const config = loadConfig();
|
|
@@ -15041,8 +15126,8 @@ function telemetryCommand(subcommand, format = "text") {
|
|
|
15041
15126
|
if (!configExists()) {
|
|
15042
15127
|
throw new CliError({
|
|
15043
15128
|
code: "CONFIG_REQUIRED",
|
|
15044
|
-
message: 'No config found. Run "canonry
|
|
15045
|
-
displayMessage: 'No config found. Run "canonry
|
|
15129
|
+
message: 'No config found. Run "canonry bootstrap" first.',
|
|
15130
|
+
displayMessage: 'No config found. Run "canonry bootstrap" first.',
|
|
15046
15131
|
details: {
|
|
15047
15132
|
command: "telemetry.enable"
|
|
15048
15133
|
}
|
|
@@ -15065,8 +15150,8 @@ function telemetryCommand(subcommand, format = "text") {
|
|
|
15065
15150
|
if (!configExists()) {
|
|
15066
15151
|
throw new CliError({
|
|
15067
15152
|
code: "CONFIG_REQUIRED",
|
|
15068
|
-
message: 'No config found. Run "canonry
|
|
15069
|
-
displayMessage: 'No config found. Run "canonry
|
|
15153
|
+
message: 'No config found. Run "canonry bootstrap" first.',
|
|
15154
|
+
displayMessage: 'No config found. Run "canonry bootstrap" first.',
|
|
15070
15155
|
details: {
|
|
15071
15156
|
command: "telemetry.disable"
|
|
15072
15157
|
}
|
|
@@ -15156,14 +15241,16 @@ var SYSTEM_CLI_COMMANDS = [
|
|
|
15156
15241
|
},
|
|
15157
15242
|
{
|
|
15158
15243
|
path: ["bootstrap"],
|
|
15159
|
-
usage: "canonry bootstrap [--
|
|
15244
|
+
usage: "canonry bootstrap [--format json]",
|
|
15245
|
+
help: "Create or reconcile the local config, SQLite database, and default API key from supported environment variables. Provider credentials are optional. Safe to rerun: existing settings are preserved and the result reports created, updated, or unchanged. The legacy --force/-f flag is accepted but has no effect.",
|
|
15160
15246
|
options: {
|
|
15247
|
+
// Compatibility for scripts written before bootstrap became idempotent.
|
|
15248
|
+
// Keep this out of usage: the flag is unnecessary and has no behavior.
|
|
15161
15249
|
force: { type: "boolean", short: "f", default: false }
|
|
15162
15250
|
},
|
|
15163
15251
|
allowPositionals: false,
|
|
15164
15252
|
run: async (input) => {
|
|
15165
15253
|
await bootstrapCommand({
|
|
15166
|
-
force: getBoolean(input.values, "force"),
|
|
15167
15254
|
format: input.format
|
|
15168
15255
|
});
|
|
15169
15256
|
}
|
|
@@ -18784,17 +18871,21 @@ function buildSetupNudgeLine(input) {
|
|
|
18784
18871
|
// src/cli.ts
|
|
18785
18872
|
import { createRequire as createRequire2 } from "module";
|
|
18786
18873
|
var USAGE6 = `
|
|
18787
|
-
cnry \u2014
|
|
18874
|
+
cnry \u2014 Page Health and AI visibility CLI ('canonry' also works)
|
|
18788
18875
|
|
|
18789
18876
|
Usage: cnry <command> [options]
|
|
18790
18877
|
|
|
18791
18878
|
Setup:
|
|
18792
|
-
|
|
18793
|
-
bootstrap Bootstrap config/database from env vars
|
|
18879
|
+
bootstrap Create local config/database (no provider required)
|
|
18794
18880
|
serve Start the local server (foreground)
|
|
18795
18881
|
start / stop Start/stop as a background daemon
|
|
18882
|
+
init Optional interactive provider/OAuth provisioning
|
|
18796
18883
|
skills List or install bundled agent skills (claude/codex)
|
|
18797
18884
|
|
|
18885
|
+
Page Health:
|
|
18886
|
+
technical-aeo Crawl, score, and inspect site health evidence
|
|
18887
|
+
doctor Diagnose runtime and integration health
|
|
18888
|
+
|
|
18798
18889
|
Projects:
|
|
18799
18890
|
project Create, update, list, show, delete projects
|
|
18800
18891
|
query Add, replace, remove, list, import, generate queries
|
package/dist/index.js
CHANGED
|
@@ -3,12 +3,12 @@ import {
|
|
|
3
3
|
createGoogleMarketingCredentialStore,
|
|
4
4
|
createGoogleMarketingRuntime,
|
|
5
5
|
createServer
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-GFVZOVG3.js";
|
|
7
7
|
import {
|
|
8
8
|
loadConfig
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-IM4HFNGF.js";
|
|
10
|
+
import "./chunk-ZJ2VGTYU.js";
|
|
11
|
+
import "./chunk-GN2G7VFK.js";
|
|
12
12
|
export {
|
|
13
13
|
GoogleMarketingRuntimeError,
|
|
14
14
|
createGoogleMarketingCredentialStore,
|
package/dist/mcp.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
autoSyncSkills
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-G7M2KM7Q.js";
|
|
4
4
|
import {
|
|
5
5
|
createApiClient,
|
|
6
6
|
createCanonryMcpServer
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-IM4HFNGF.js";
|
|
8
8
|
import {
|
|
9
9
|
isReadOnlyKey
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-GN2G7VFK.js";
|
|
11
11
|
|
|
12
12
|
// src/mcp/cli.ts
|
|
13
13
|
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.180.
|
|
3
|
+
"version": "4.180.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Self-hosted AI visibility (AEO) platform: track how ChatGPT, Claude, Gemini, and Perplexity cite your domain, join it with Search Console, GA4, server-side traffic, and paid media, and fix what you find through agent tools (CLI, REST, MCP). Local SQLite.",
|
|
6
6
|
"license": "FSL-1.1-ALv2",
|
|
@@ -71,30 +71,30 @@
|
|
|
71
71
|
"tsup": "^8.5.1",
|
|
72
72
|
"tsx": "^4.19.0",
|
|
73
73
|
"@ainyc/canonry-api-client": "0.0.0",
|
|
74
|
-
"@ainyc/canonry-config": "0.0.0",
|
|
75
74
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
76
|
-
"@ainyc/canonry-
|
|
75
|
+
"@ainyc/canonry-config": "0.0.0",
|
|
77
76
|
"@ainyc/canonry-db": "0.0.0",
|
|
77
|
+
"@ainyc/canonry-contracts": "0.0.0",
|
|
78
78
|
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
79
79
|
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
80
|
-
"@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
|
|
81
80
|
"@ainyc/canonry-integration-cloudflare-queue": "0.0.0",
|
|
81
|
+
"@ainyc/canonry-integration-cloudflare-worker": "0.0.0",
|
|
82
82
|
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
83
83
|
"@ainyc/canonry-integration-google": "0.0.0",
|
|
84
|
-
"@ainyc/canonry-integration-google-business-profile": "0.0.0",
|
|
85
|
-
"@ainyc/canonry-integration-google-ads": "0.0.0",
|
|
86
84
|
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
85
|
+
"@ainyc/canonry-integration-google-ads": "0.0.0",
|
|
87
86
|
"@ainyc/canonry-integration-google-tag-manager": "0.0.0",
|
|
87
|
+
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
88
88
|
"@ainyc/canonry-integration-openai-ads": "0.0.0",
|
|
89
|
+
"@ainyc/canonry-integration-google-business-profile": "0.0.0",
|
|
89
90
|
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
90
|
-
"@ainyc/canonry-
|
|
91
|
+
"@ainyc/canonry-intelligence": "0.0.0",
|
|
91
92
|
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
92
93
|
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
93
94
|
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
94
|
-
"@ainyc/canonry-
|
|
95
|
-
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
95
|
+
"@ainyc/canonry-provider-local": "0.0.0",
|
|
96
96
|
"@ainyc/canonry-provider-perplexity": "0.0.0",
|
|
97
|
-
"@ainyc/canonry-provider-
|
|
97
|
+
"@ainyc/canonry-provider-openai": "0.0.0"
|
|
98
98
|
},
|
|
99
99
|
"scripts": {
|
|
100
100
|
"build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",
|