@ainyc/canonry 4.44.1 → 4.45.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.
|
@@ -322,6 +322,8 @@ var ApiClient = class {
|
|
|
322
322
|
"Accept": "application/json",
|
|
323
323
|
...serializedBody != null ? { "Content-Type": "application/json" } : {}
|
|
324
324
|
};
|
|
325
|
+
const traceEnabled = process.env.CANONRY_TRACE === "1";
|
|
326
|
+
const traceStart = traceEnabled ? Date.now() : 0;
|
|
325
327
|
let res;
|
|
326
328
|
try {
|
|
327
329
|
res = await fetch(url, {
|
|
@@ -330,6 +332,11 @@ var ApiClient = class {
|
|
|
330
332
|
body: serializedBody
|
|
331
333
|
});
|
|
332
334
|
} catch (err) {
|
|
335
|
+
if (traceEnabled) {
|
|
336
|
+
const durMs = Date.now() - traceStart;
|
|
337
|
+
process.stderr.write(`[trace] ${method} ${url} \u2192 ERROR (${durMs}ms)
|
|
338
|
+
`);
|
|
339
|
+
}
|
|
333
340
|
if (err instanceof CliError) throw err;
|
|
334
341
|
const msg = err instanceof Error ? err.message : String(err);
|
|
335
342
|
if (msg.includes("fetch failed") || msg.includes("ECONNREFUSED") || msg.includes("connect ECONNREFUSED")) {
|
|
@@ -362,6 +369,11 @@ var ApiClient = class {
|
|
|
362
369
|
}
|
|
363
370
|
});
|
|
364
371
|
}
|
|
372
|
+
if (traceEnabled) {
|
|
373
|
+
const durMs = Date.now() - traceStart;
|
|
374
|
+
process.stderr.write(`[trace] ${method} ${url} \u2192 ${res.status} (${durMs}ms)
|
|
375
|
+
`);
|
|
376
|
+
}
|
|
365
377
|
if (res.status === 204) {
|
|
366
378
|
return void 0;
|
|
367
379
|
}
|
package/dist/cli.js
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
setTelemetrySource,
|
|
22
22
|
showFirstRunNotice,
|
|
23
23
|
trackEvent
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-G2HQOLPK.js";
|
|
25
25
|
import {
|
|
26
26
|
CliError,
|
|
27
27
|
EXIT_SYSTEM_ERROR,
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
saveConfig,
|
|
38
38
|
saveConfigPatch,
|
|
39
39
|
usageError
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-GRFMZ7PD.js";
|
|
41
41
|
import {
|
|
42
42
|
apiKeys,
|
|
43
43
|
createClient,
|
|
@@ -117,6 +117,7 @@ function withGlobalOptions(options) {
|
|
|
117
117
|
const base = options ? { ...options } : {};
|
|
118
118
|
if (!("format" in base)) base.format = { type: "string" };
|
|
119
119
|
if (!("dry-run" in base)) base["dry-run"] = { type: "boolean" };
|
|
120
|
+
if (!("trace" in base)) base.trace = { type: "boolean" };
|
|
120
121
|
return base;
|
|
121
122
|
}
|
|
122
123
|
function toFormat(value, fallbackFormat) {
|
|
@@ -189,6 +190,9 @@ Usage: ${spec.usage}`, {
|
|
|
189
190
|
}
|
|
190
191
|
});
|
|
191
192
|
}
|
|
193
|
+
if (values.trace === true) {
|
|
194
|
+
process.env.CANONRY_TRACE = "1";
|
|
195
|
+
}
|
|
192
196
|
const dryRunRequested = values["dry-run"] === true;
|
|
193
197
|
if (dryRunRequested && !spec.supportsDryRun) {
|
|
194
198
|
throw usageError(
|
|
@@ -1988,6 +1992,10 @@ var DISCOVER_CLI_COMMANDS = [
|
|
|
1988
1992
|
|
|
1989
1993
|
// src/commands/doctor.ts
|
|
1990
1994
|
async function doctorCommand(opts) {
|
|
1995
|
+
if (opts.all) {
|
|
1996
|
+
await runDoctorAll(opts);
|
|
1997
|
+
return;
|
|
1998
|
+
}
|
|
1991
1999
|
const client = createApiClient();
|
|
1992
2000
|
const report = await client.runDoctor({
|
|
1993
2001
|
project: opts.project,
|
|
@@ -2011,6 +2019,60 @@ async function doctorCommand(opts) {
|
|
|
2011
2019
|
});
|
|
2012
2020
|
}
|
|
2013
2021
|
}
|
|
2022
|
+
async function runDoctorAll(opts) {
|
|
2023
|
+
const client = createApiClient();
|
|
2024
|
+
const projects2 = await client.listProjects();
|
|
2025
|
+
const [globalReport, ...projectReports] = await Promise.all([
|
|
2026
|
+
client.runDoctor({ checkIds: opts.checks }),
|
|
2027
|
+
...projects2.map((p) => client.runDoctor({ project: p.name, checkIds: opts.checks }))
|
|
2028
|
+
]);
|
|
2029
|
+
const byKey = { __global__: globalReport };
|
|
2030
|
+
projects2.forEach((p, i) => {
|
|
2031
|
+
byKey[p.name] = projectReports[i];
|
|
2032
|
+
});
|
|
2033
|
+
if (opts.format === "json") {
|
|
2034
|
+
console.log(JSON.stringify(byKey, null, 2));
|
|
2035
|
+
} else {
|
|
2036
|
+
printAllHumanReport(byKey, projects2.map((p) => p.name));
|
|
2037
|
+
}
|
|
2038
|
+
const totalFail = globalReport.summary.fail + projectReports.reduce((s, r) => s + r.summary.fail, 0);
|
|
2039
|
+
if (totalFail > 0) {
|
|
2040
|
+
const failedByScope = {};
|
|
2041
|
+
if (globalReport.summary.fail > 0) {
|
|
2042
|
+
failedByScope.__global__ = globalReport.checks.filter((c) => c.status === CheckStatuses.fail).map((c) => c.id);
|
|
2043
|
+
}
|
|
2044
|
+
projects2.forEach((p, i) => {
|
|
2045
|
+
const failed = projectReports[i].checks.filter((c) => c.status === CheckStatuses.fail).map((c) => c.id);
|
|
2046
|
+
if (failed.length > 0) failedByScope[p.name] = failed;
|
|
2047
|
+
});
|
|
2048
|
+
throw new CliError({
|
|
2049
|
+
code: "DOCTOR_CHECKS_FAILED",
|
|
2050
|
+
message: `${totalFail} check${totalFail === 1 ? "" : "s"} failed across ${Object.keys(failedByScope).length} scope${Object.keys(failedByScope).length === 1 ? "" : "s"}`,
|
|
2051
|
+
exitCode: EXIT_USER_ERROR,
|
|
2052
|
+
details: { failed: failedByScope }
|
|
2053
|
+
});
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
function printAllHumanReport(byKey, projectNames) {
|
|
2057
|
+
const scopes = ["__global__", ...projectNames];
|
|
2058
|
+
console.log(`
|
|
2059
|
+
canonry doctor \u2014 all scopes (${scopes.length})
|
|
2060
|
+
`);
|
|
2061
|
+
for (const key of scopes) {
|
|
2062
|
+
const report = byKey[key];
|
|
2063
|
+
const label = key === "__global__" ? "global" : `project "${key}"`;
|
|
2064
|
+
const s = report.summary;
|
|
2065
|
+
const tag = s.fail > 0 ? "[FAIL]" : s.warn > 0 ? "[WARN]" : "[OK] ";
|
|
2066
|
+
console.log(` ${tag} ${label.padEnd(28)} ${s.ok} ok, ${s.warn} warn, ${s.fail} fail, ${s.skipped} skipped`);
|
|
2067
|
+
if (s.fail > 0) {
|
|
2068
|
+
const failedIds = report.checks.filter((c) => c.status === CheckStatuses.fail).map((c) => `${c.id} \u2014 ${c.summary}`);
|
|
2069
|
+
for (const line of failedIds) {
|
|
2070
|
+
console.log(` \u2717 ${line}`);
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
console.log();
|
|
2075
|
+
}
|
|
2014
2076
|
function statusBadge(status) {
|
|
2015
2077
|
switch (status) {
|
|
2016
2078
|
case CheckStatuses.ok:
|
|
@@ -2052,19 +2114,21 @@ ${header}`);
|
|
|
2052
2114
|
}
|
|
2053
2115
|
|
|
2054
2116
|
// src/cli-commands/doctor.ts
|
|
2055
|
-
var USAGE = "canonry doctor [--project <name
|
|
2117
|
+
var USAGE = "canonry doctor [--project <name>|--all] [--check <id>...] [--format json]";
|
|
2056
2118
|
var DOCTOR_CLI_COMMANDS = [
|
|
2057
2119
|
{
|
|
2058
2120
|
path: ["doctor"],
|
|
2059
2121
|
usage: USAGE,
|
|
2060
2122
|
options: {
|
|
2061
2123
|
project: stringOption(),
|
|
2062
|
-
check: multiStringOption()
|
|
2124
|
+
check: multiStringOption(),
|
|
2125
|
+
all: { type: "boolean" }
|
|
2063
2126
|
},
|
|
2064
2127
|
allowPositionals: false,
|
|
2065
2128
|
run: async (input) => {
|
|
2066
2129
|
await doctorCommand({
|
|
2067
2130
|
project: getString(input.values, "project"),
|
|
2131
|
+
all: getBoolean(input.values, "all"),
|
|
2068
2132
|
checks: getStringArray(input.values, "check"),
|
|
2069
2133
|
format: input.format
|
|
2070
2134
|
});
|
|
@@ -2748,6 +2812,108 @@ var GA_CLI_COMMANDS = [
|
|
|
2748
2812
|
}
|
|
2749
2813
|
];
|
|
2750
2814
|
|
|
2815
|
+
// src/commands/get.ts
|
|
2816
|
+
var SOURCE_FETCHERS = {
|
|
2817
|
+
overview: async (project) => createApiClient().getProjectOverview(project),
|
|
2818
|
+
doctor: async (project) => createApiClient().runDoctor({ project }),
|
|
2819
|
+
runs: async (project) => createApiClient().listRuns(project),
|
|
2820
|
+
queries: async (project) => createApiClient().listQueries(project),
|
|
2821
|
+
competitors: async (project) => createApiClient().listCompetitors(project)
|
|
2822
|
+
};
|
|
2823
|
+
var GET_SOURCES = ["overview", "doctor", "runs", "queries", "competitors"];
|
|
2824
|
+
async function getCommand(opts) {
|
|
2825
|
+
const source = opts.from ?? "overview";
|
|
2826
|
+
if (!GET_SOURCES.includes(source)) {
|
|
2827
|
+
throw new CliError({
|
|
2828
|
+
code: "INVALID_GET_SOURCE",
|
|
2829
|
+
message: `Unknown --from value "${opts.from}". Valid: ${GET_SOURCES.join(", ")}.`,
|
|
2830
|
+
exitCode: EXIT_USER_ERROR,
|
|
2831
|
+
details: { from: opts.from, valid: [...GET_SOURCES] }
|
|
2832
|
+
});
|
|
2833
|
+
}
|
|
2834
|
+
const payload = await SOURCE_FETCHERS[source](opts.project);
|
|
2835
|
+
const leaf = walkPath(payload, opts.path);
|
|
2836
|
+
if (leaf === void 0) {
|
|
2837
|
+
throw new CliError({
|
|
2838
|
+
code: "PATH_NOT_FOUND",
|
|
2839
|
+
message: `Path "${opts.path}" not found in ${source} response for project "${opts.project}".`,
|
|
2840
|
+
exitCode: EXIT_USER_ERROR,
|
|
2841
|
+
details: { project: opts.project, path: opts.path, from: source }
|
|
2842
|
+
});
|
|
2843
|
+
}
|
|
2844
|
+
if (opts.format === "json") {
|
|
2845
|
+
console.log(JSON.stringify(leaf, null, 2));
|
|
2846
|
+
return;
|
|
2847
|
+
}
|
|
2848
|
+
if (typeof leaf === "string") {
|
|
2849
|
+
console.log(leaf);
|
|
2850
|
+
} else if (typeof leaf === "number" || typeof leaf === "boolean" || leaf === null) {
|
|
2851
|
+
console.log(String(leaf));
|
|
2852
|
+
} else {
|
|
2853
|
+
console.log(JSON.stringify(leaf, null, 2));
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
function walkPath(value, path10) {
|
|
2857
|
+
if (!path10 || path10 === ".") return value;
|
|
2858
|
+
const segments = path10.split(".").flatMap((part) => {
|
|
2859
|
+
const tokens = [];
|
|
2860
|
+
let i = 0;
|
|
2861
|
+
const bracketStart = part.indexOf("[");
|
|
2862
|
+
if (bracketStart === -1) {
|
|
2863
|
+
tokens.push(part);
|
|
2864
|
+
} else {
|
|
2865
|
+
if (bracketStart > 0) tokens.push(part.slice(0, bracketStart));
|
|
2866
|
+
i = bracketStart;
|
|
2867
|
+
while (i < part.length) {
|
|
2868
|
+
if (part[i] === "[") {
|
|
2869
|
+
const end = part.indexOf("]", i);
|
|
2870
|
+
if (end === -1) return [part];
|
|
2871
|
+
tokens.push(part.slice(i, end + 1));
|
|
2872
|
+
i = end + 1;
|
|
2873
|
+
} else {
|
|
2874
|
+
i++;
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
return tokens;
|
|
2879
|
+
});
|
|
2880
|
+
let cursor = value;
|
|
2881
|
+
for (const segment of segments) {
|
|
2882
|
+
if (cursor === null || cursor === void 0) return void 0;
|
|
2883
|
+
if (segment.startsWith("[") && segment.endsWith("]")) {
|
|
2884
|
+
const idx = Number.parseInt(segment.slice(1, -1), 10);
|
|
2885
|
+
if (Number.isNaN(idx) || !Array.isArray(cursor)) return void 0;
|
|
2886
|
+
cursor = cursor[idx];
|
|
2887
|
+
continue;
|
|
2888
|
+
}
|
|
2889
|
+
if (typeof cursor !== "object") return void 0;
|
|
2890
|
+
cursor = cursor[segment];
|
|
2891
|
+
}
|
|
2892
|
+
return cursor;
|
|
2893
|
+
}
|
|
2894
|
+
|
|
2895
|
+
// src/cli-commands/get.ts
|
|
2896
|
+
var USAGE2 = `canonry get <project> <path> [--from ${GET_SOURCES.join("|")}] [--format json]`;
|
|
2897
|
+
var GET_CLI_COMMANDS = [
|
|
2898
|
+
{
|
|
2899
|
+
path: ["get"],
|
|
2900
|
+
usage: USAGE2,
|
|
2901
|
+
options: {
|
|
2902
|
+
from: stringOption()
|
|
2903
|
+
},
|
|
2904
|
+
run: async (input) => {
|
|
2905
|
+
const project = requireProject(input, "get", USAGE2);
|
|
2906
|
+
const path10 = requirePositional(input, 1, {
|
|
2907
|
+
command: "get",
|
|
2908
|
+
usage: USAGE2,
|
|
2909
|
+
message: 'path is required (e.g. "scores.mentionShare.value")'
|
|
2910
|
+
});
|
|
2911
|
+
const from = getString(input.values, "from");
|
|
2912
|
+
await getCommand({ project, path: path10, from, format: input.format });
|
|
2913
|
+
}
|
|
2914
|
+
}
|
|
2915
|
+
];
|
|
2916
|
+
|
|
2751
2917
|
// src/commands/traffic.ts
|
|
2752
2918
|
function getClient6() {
|
|
2753
2919
|
return createApiClient();
|
|
@@ -5056,6 +5222,9 @@ function cursorConfigPath() {
|
|
|
5056
5222
|
function codexConfigPath() {
|
|
5057
5223
|
return homeRelative(".codex", "config.toml");
|
|
5058
5224
|
}
|
|
5225
|
+
function claudeCodeProjectConfigPath() {
|
|
5226
|
+
return path.join(process.cwd(), ".mcp.json");
|
|
5227
|
+
}
|
|
5059
5228
|
var SUPPORTED_MCP_CLIENTS = [
|
|
5060
5229
|
{
|
|
5061
5230
|
id: "claude-desktop",
|
|
@@ -5064,6 +5233,13 @@ var SUPPORTED_MCP_CLIENTS = [
|
|
|
5064
5233
|
configPath: claudeDesktopConfigPath,
|
|
5065
5234
|
installSupported: true
|
|
5066
5235
|
},
|
|
5236
|
+
{
|
|
5237
|
+
id: "claude-code",
|
|
5238
|
+
label: "Claude Code",
|
|
5239
|
+
format: "json-mcp-servers",
|
|
5240
|
+
configPath: claudeCodeProjectConfigPath,
|
|
5241
|
+
installSupported: true
|
|
5242
|
+
},
|
|
5067
5243
|
{
|
|
5068
5244
|
id: "cursor",
|
|
5069
5245
|
label: "Cursor",
|
|
@@ -5188,7 +5364,7 @@ async function installMcp(opts) {
|
|
|
5188
5364
|
snippet,
|
|
5189
5365
|
message: `Auto-install is not supported for ${client.label}. Add the snippet below to ${configPath}.`
|
|
5190
5366
|
};
|
|
5191
|
-
emitInstallResult(result2, opts.format);
|
|
5367
|
+
if (!opts.silent) emitInstallResult(result2, opts.format);
|
|
5192
5368
|
return result2;
|
|
5193
5369
|
}
|
|
5194
5370
|
const containerKey = client.format === "json-context-servers" ? "context_servers" : "mcpServers";
|
|
@@ -5204,7 +5380,7 @@ async function installMcp(opts) {
|
|
|
5204
5380
|
status: "already-installed",
|
|
5205
5381
|
message: `${client.label} already has a "${serverName}" entry pointing to canonry-mcp.`
|
|
5206
5382
|
};
|
|
5207
|
-
emitInstallResult(result2, opts.format);
|
|
5383
|
+
if (!opts.silent) emitInstallResult(result2, opts.format);
|
|
5208
5384
|
return result2;
|
|
5209
5385
|
}
|
|
5210
5386
|
const status = existingEntry ? "updated" : "installed";
|
|
@@ -5218,7 +5394,7 @@ async function installMcp(opts) {
|
|
|
5218
5394
|
snippet: renderClientSnippet(client, serverName, entry),
|
|
5219
5395
|
message: `Would ${status === "installed" ? "install" : "update"} "${serverName}" in ${configPath}.`
|
|
5220
5396
|
};
|
|
5221
|
-
emitInstallResult(result2, opts.format);
|
|
5397
|
+
if (!opts.silent) emitInstallResult(result2, opts.format);
|
|
5222
5398
|
return result2;
|
|
5223
5399
|
}
|
|
5224
5400
|
const backupPath = backupConfigIfPresent(configPath);
|
|
@@ -5236,7 +5412,7 @@ async function installMcp(opts) {
|
|
|
5236
5412
|
backupPath,
|
|
5237
5413
|
message: `${status === "installed" ? "Installed" : "Updated"} "${serverName}" in ${client.label} at ${configPath}. Restart ${client.label} to load it.`
|
|
5238
5414
|
};
|
|
5239
|
-
emitInstallResult(result, opts.format);
|
|
5415
|
+
if (!opts.silent) emitInstallResult(result, opts.format);
|
|
5240
5416
|
return result;
|
|
5241
5417
|
}
|
|
5242
5418
|
async function printMcpConfig(opts) {
|
|
@@ -6327,24 +6503,24 @@ async function runReportCommand(project, opts = {}) {
|
|
|
6327
6503
|
}
|
|
6328
6504
|
|
|
6329
6505
|
// src/cli-commands/report.ts
|
|
6330
|
-
var
|
|
6506
|
+
var USAGE3 = "canonry report <project> [--audience agency|client] [--output <path>] [--format json]";
|
|
6331
6507
|
function parseAudience(value) {
|
|
6332
6508
|
if (value === void 0) return void 0;
|
|
6333
6509
|
if (value === "agency" || value === "client") return value;
|
|
6334
6510
|
throw usageError(`Error: --audience must be "agency" or "client"
|
|
6335
6511
|
|
|
6336
|
-
Usage: ${
|
|
6512
|
+
Usage: ${USAGE3}`);
|
|
6337
6513
|
}
|
|
6338
6514
|
var REPORT_CLI_COMMANDS = [
|
|
6339
6515
|
{
|
|
6340
6516
|
path: ["report"],
|
|
6341
|
-
usage:
|
|
6517
|
+
usage: USAGE3,
|
|
6342
6518
|
options: {
|
|
6343
6519
|
audience: { type: "string" },
|
|
6344
6520
|
output: { type: "string", short: "o" }
|
|
6345
6521
|
},
|
|
6346
6522
|
run: async (input) => {
|
|
6347
|
-
const project = requireProject(input, "report",
|
|
6523
|
+
const project = requireProject(input, "report", USAGE3);
|
|
6348
6524
|
await runReportCommand(project, {
|
|
6349
6525
|
format: input.format,
|
|
6350
6526
|
audience: parseAudience(getString(input.values, "audience")),
|
|
@@ -7579,7 +7755,7 @@ var PdfWriter = class {
|
|
|
7579
7755
|
}
|
|
7580
7756
|
this.y -= headerHeight + 4;
|
|
7581
7757
|
for (const row of rows) {
|
|
7582
|
-
const lineCounts = row.map((
|
|
7758
|
+
const lineCounts = row.map((cell2, index) => wrapText(this.regular, cell2, 9, columnWidths[index] - 8).length);
|
|
7583
7759
|
const rowHeight = Math.max(18, Math.max(...lineCounts) * 11 + 6);
|
|
7584
7760
|
this.ensureSpace(rowHeight + 4);
|
|
7585
7761
|
let cellX = MARGIN;
|
|
@@ -8066,6 +8242,45 @@ async function showOverview(project, opts) {
|
|
|
8066
8242
|
}
|
|
8067
8243
|
renderHuman(overview);
|
|
8068
8244
|
}
|
|
8245
|
+
async function showAllOverviews(opts) {
|
|
8246
|
+
const client = createApiClient();
|
|
8247
|
+
const projects2 = await client.listProjects();
|
|
8248
|
+
if (projects2.length === 0) {
|
|
8249
|
+
if (opts.format === "json") {
|
|
8250
|
+
console.log("[]");
|
|
8251
|
+
return;
|
|
8252
|
+
}
|
|
8253
|
+
console.log("No projects configured. Add one with `canonry project create`.");
|
|
8254
|
+
return;
|
|
8255
|
+
}
|
|
8256
|
+
const overviews = await Promise.all(
|
|
8257
|
+
projects2.map(
|
|
8258
|
+
(p) => client.getProjectOverview(p.name, { location: opts.location, since: opts.since })
|
|
8259
|
+
)
|
|
8260
|
+
);
|
|
8261
|
+
if (opts.format === "json") {
|
|
8262
|
+
console.log(JSON.stringify(overviews, null, 2));
|
|
8263
|
+
return;
|
|
8264
|
+
}
|
|
8265
|
+
console.log(`
|
|
8266
|
+
Overviews (${overviews.length} project${overviews.length === 1 ? "" : "s"}):
|
|
8267
|
+
`);
|
|
8268
|
+
const cols = { project: 20, mention: 10, cited: 10, share: 18, queries: 10 };
|
|
8269
|
+
console.log(` ${cell("Project", cols.project)}${cell("Mention", cols.mention)}${cell("Cited", cols.cited)}${cell("Share", cols.share)}${cell("Queries", cols.queries)}Latest run`);
|
|
8270
|
+
for (const ov of overviews) {
|
|
8271
|
+
const project = ov.project.displayName || ov.project.name;
|
|
8272
|
+
const queries2 = `${ov.queryCounts.citedQueries}/${ov.queryCounts.totalQueries}`;
|
|
8273
|
+
const latest = ov.latestRun.run?.finishedAt ?? ov.latestRun.run?.createdAt ?? "\u2014";
|
|
8274
|
+
console.log(
|
|
8275
|
+
` ${cell(project, cols.project)}${cell(ov.scores.mention.value, cols.mention)}${cell(ov.scores.visibility.value, cols.cited)}${cell(ov.scores.mentionShare.value, cols.share)}${cell(queries2, cols.queries)}${latest}`
|
|
8276
|
+
);
|
|
8277
|
+
}
|
|
8278
|
+
console.log();
|
|
8279
|
+
}
|
|
8280
|
+
function cell(value, width) {
|
|
8281
|
+
if (value.length >= width) return `${value.slice(0, width - 1)} `;
|
|
8282
|
+
return value.padEnd(width);
|
|
8283
|
+
}
|
|
8069
8284
|
function renderHuman(overview) {
|
|
8070
8285
|
const {
|
|
8071
8286
|
project: meta,
|
|
@@ -8369,16 +8584,23 @@ var INTELLIGENCE_CLI_COMMANDS = [
|
|
|
8369
8584
|
},
|
|
8370
8585
|
{
|
|
8371
8586
|
path: ["overview"],
|
|
8372
|
-
usage: "canonry overview <project
|
|
8587
|
+
usage: "canonry overview <project>|--all [--location <label>] [--since <iso>] [--format json]",
|
|
8373
8588
|
options: {
|
|
8374
8589
|
location: { type: "string" },
|
|
8375
|
-
since: { type: "string" }
|
|
8590
|
+
since: { type: "string" },
|
|
8591
|
+
all: { type: "boolean" }
|
|
8376
8592
|
},
|
|
8593
|
+
allowPositionals: true,
|
|
8377
8594
|
run: async (input) => {
|
|
8378
|
-
const usage = "canonry overview <project
|
|
8379
|
-
const
|
|
8595
|
+
const usage = "canonry overview <project>|--all [--location <label>] [--since <iso>] [--format json]";
|
|
8596
|
+
const all = getBoolean(input.values, "all");
|
|
8380
8597
|
const location = getString(input.values, "location");
|
|
8381
8598
|
const since = getString(input.values, "since");
|
|
8599
|
+
if (all) {
|
|
8600
|
+
await showAllOverviews({ format: input.format, location, since });
|
|
8601
|
+
return;
|
|
8602
|
+
}
|
|
8603
|
+
const project = requireProject(input, "overview", usage);
|
|
8382
8604
|
await showOverview(project, { format: input.format, location, since });
|
|
8383
8605
|
}
|
|
8384
8606
|
},
|
|
@@ -9141,6 +9363,26 @@ async function initCommand(opts) {
|
|
|
9141
9363
|
skillsTip = 'Run "canonry skills install" in a project directory to add the canonry + Aero playbook to .claude/skills/ and .codex/skills/.';
|
|
9142
9364
|
}
|
|
9143
9365
|
}
|
|
9366
|
+
let mcpSummary;
|
|
9367
|
+
let mcpTip;
|
|
9368
|
+
if (!opts?.skipMcp) {
|
|
9369
|
+
const mcpTarget = opts?.skillsDir ?? process.cwd();
|
|
9370
|
+
if (cwdLooksLikeProject(mcpTarget)) {
|
|
9371
|
+
try {
|
|
9372
|
+
const previousCwd = process.cwd();
|
|
9373
|
+
try {
|
|
9374
|
+
if (opts?.skillsDir) process.chdir(opts.skillsDir);
|
|
9375
|
+
mcpSummary = await installMcp({ client: "claude-code", silent: true });
|
|
9376
|
+
} finally {
|
|
9377
|
+
process.chdir(previousCwd);
|
|
9378
|
+
}
|
|
9379
|
+
} catch (err) {
|
|
9380
|
+
mcpTip = `MCP auto-install failed: ${err instanceof Error ? err.message : String(err)}. Run "canonry mcp install --client claude-code" manually.`;
|
|
9381
|
+
}
|
|
9382
|
+
} else {
|
|
9383
|
+
mcpTip = 'Run "canonry mcp install --client claude-code" in a project directory to register the canonry MCP server in `.mcp.json` for Claude Code sessions.';
|
|
9384
|
+
}
|
|
9385
|
+
}
|
|
9144
9386
|
const nextSteps = buildNextSteps();
|
|
9145
9387
|
if (format === "json") {
|
|
9146
9388
|
console.log(JSON.stringify({
|
|
@@ -9153,6 +9395,8 @@ async function initCommand(opts) {
|
|
|
9153
9395
|
googleConfigured: !!google,
|
|
9154
9396
|
skills: skillsSummary,
|
|
9155
9397
|
skillsTip,
|
|
9398
|
+
mcp: mcpSummary,
|
|
9399
|
+
mcpTip,
|
|
9156
9400
|
nextSteps
|
|
9157
9401
|
}, null, 2));
|
|
9158
9402
|
} else {
|
|
@@ -9168,6 +9412,13 @@ ${skillsSummary.message}`);
|
|
|
9168
9412
|
}
|
|
9169
9413
|
if (skillsTip) console.log(`
|
|
9170
9414
|
${skillsTip}`);
|
|
9415
|
+
if (mcpSummary) {
|
|
9416
|
+
console.log(`
|
|
9417
|
+
MCP server "${mcpSummary.serverName}" ${mcpSummary.status} for Claude Code at ${mcpSummary.configPath}.`);
|
|
9418
|
+
console.log("Claude Code sessions opened in this directory will pick it up automatically.");
|
|
9419
|
+
}
|
|
9420
|
+
if (mcpTip) console.log(`
|
|
9421
|
+
${mcpTip}`);
|
|
9171
9422
|
}
|
|
9172
9423
|
let agentLLM;
|
|
9173
9424
|
const agentProvider = opts?.agentProvider;
|
|
@@ -9466,7 +9717,7 @@ function applyServerEnv(values) {
|
|
|
9466
9717
|
var SYSTEM_CLI_COMMANDS = [
|
|
9467
9718
|
{
|
|
9468
9719
|
path: ["init"],
|
|
9469
|
-
usage: "canonry init [--force] [--gemini-key <key>] [--openai-key <key>] [--claude-key <key>] [--perplexity-key <key>] [--local-url <url>] [--local-model <name>] [--local-key <key>] [--google-client-id <id>] [--google-client-secret <key>] [--skip-skills] [--skills-dir <path>] [--format json]",
|
|
9720
|
+
usage: "canonry init [--force] [--gemini-key <key>] [--openai-key <key>] [--claude-key <key>] [--perplexity-key <key>] [--local-url <url>] [--local-model <name>] [--local-key <key>] [--google-client-id <id>] [--google-client-secret <key>] [--skip-skills] [--skip-mcp] [--skills-dir <path>] [--format json]",
|
|
9470
9721
|
options: {
|
|
9471
9722
|
force: { type: "boolean", short: "f", default: false },
|
|
9472
9723
|
"gemini-key": stringOption(),
|
|
@@ -9479,6 +9730,7 @@ var SYSTEM_CLI_COMMANDS = [
|
|
|
9479
9730
|
"google-client-id": stringOption(),
|
|
9480
9731
|
"google-client-secret": stringOption(),
|
|
9481
9732
|
"skip-skills": { type: "boolean" },
|
|
9733
|
+
"skip-mcp": { type: "boolean" },
|
|
9482
9734
|
"skills-dir": stringOption()
|
|
9483
9735
|
},
|
|
9484
9736
|
allowPositionals: false,
|
|
@@ -9495,6 +9747,7 @@ var SYSTEM_CLI_COMMANDS = [
|
|
|
9495
9747
|
googleClientId: getString(input.values, "google-client-id"),
|
|
9496
9748
|
googleClientSecret: getString(input.values, "google-client-secret"),
|
|
9497
9749
|
skipSkills: getBoolean(input.values, "skip-skills"),
|
|
9750
|
+
skipMcp: getBoolean(input.values, "skip-mcp"),
|
|
9498
9751
|
skillsDir: getString(input.values, "skills-dir"),
|
|
9499
9752
|
format: input.format
|
|
9500
9753
|
});
|
|
@@ -11149,12 +11402,13 @@ var REGISTERED_CLI_COMMANDS = [
|
|
|
11149
11402
|
...AGENT_CLI_COMMANDS,
|
|
11150
11403
|
...DISCOVER_CLI_COMMANDS,
|
|
11151
11404
|
...DOCTOR_CLI_COMMANDS,
|
|
11405
|
+
...GET_CLI_COMMANDS,
|
|
11152
11406
|
...MCP_CLI_COMMANDS
|
|
11153
11407
|
];
|
|
11154
11408
|
|
|
11155
11409
|
// src/cli.ts
|
|
11156
11410
|
import { createRequire as createRequire2 } from "module";
|
|
11157
|
-
var
|
|
11411
|
+
var USAGE4 = `
|
|
11158
11412
|
cnry \u2014 AEO monitoring CLI ('canonry' also works)
|
|
11159
11413
|
|
|
11160
11414
|
Usage: cnry <command> [options]
|
|
@@ -11216,7 +11470,7 @@ function extractFormat(cmdArgs) {
|
|
|
11216
11470
|
}
|
|
11217
11471
|
async function runCli(args = process.argv.slice(2)) {
|
|
11218
11472
|
if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
|
|
11219
|
-
console.log(
|
|
11473
|
+
console.log(USAGE4);
|
|
11220
11474
|
return 0;
|
|
11221
11475
|
}
|
|
11222
11476
|
if (args.includes("--version") || args.includes("-v")) {
|
package/dist/index.js
CHANGED
package/dist/mcp.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainyc/canonry",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.45.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",
|
|
@@ -61,22 +61,22 @@
|
|
|
61
61
|
"tsup": "^8.5.1",
|
|
62
62
|
"tsx": "^4.19.0",
|
|
63
63
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
64
|
-
"@ainyc/canonry-db": "0.0.0",
|
|
65
|
-
"@ainyc/canonry-intelligence": "0.0.0",
|
|
66
64
|
"@ainyc/canonry-config": "0.0.0",
|
|
67
65
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
68
|
-
"@ainyc/canonry-
|
|
66
|
+
"@ainyc/canonry-db": "0.0.0",
|
|
69
67
|
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
68
|
+
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
69
|
+
"@ainyc/canonry-intelligence": "0.0.0",
|
|
70
70
|
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
71
|
-
"@ainyc/canonry-integration-google": "0.0.0",
|
|
72
71
|
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
73
|
-
"@ainyc/canonry-integration-
|
|
72
|
+
"@ainyc/canonry-integration-google": "0.0.0",
|
|
74
73
|
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
75
74
|
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
76
|
-
"@ainyc/canonry-provider-local": "0.0.0",
|
|
77
|
-
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
78
75
|
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
79
|
-
"@ainyc/canonry-provider-perplexity": "0.0.0"
|
|
76
|
+
"@ainyc/canonry-provider-perplexity": "0.0.0",
|
|
77
|
+
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
78
|
+
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
79
|
+
"@ainyc/canonry-provider-local": "0.0.0"
|
|
80
80
|
},
|
|
81
81
|
"scripts": {
|
|
82
82
|
"build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",
|