@ainyc/canonry 2.5.1 → 2.8.2
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 +23 -2
- package/assets/assets/{index-agELvqT1.js → index-U1lA1GKP.js} +102 -102
- package/assets/index.html +1 -1
- package/bin/canonry-mcp.mjs +2 -0
- package/dist/chunk-FPZUQADO.js +2152 -0
- package/dist/{chunk-CFS35BKX.js → chunk-MGBXRWLX.js} +368 -2196
- package/dist/chunk-MLKGABMK.js +9 -0
- package/dist/{chunk-32YTAZBL.js → chunk-PYHANJ3B.js} +3 -5
- package/dist/cli.js +505 -91
- package/dist/index.js +6 -3
- package/dist/{intelligence-service-U7YQ4NXV.js → intelligence-service-2ZABHNR4.js} +2 -1
- package/dist/mcp.js +848 -0
- package/package.json +7 -5
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node --import tsx
|
|
2
|
+
import {
|
|
3
|
+
coerceAgentProvider,
|
|
4
|
+
computeCompetitorOverlap,
|
|
5
|
+
createServer,
|
|
6
|
+
determineCitationState,
|
|
7
|
+
extractRecommendedCompetitors,
|
|
8
|
+
formatAuditFactorScore,
|
|
9
|
+
getOrCreateAnonymousId,
|
|
10
|
+
isFirstRun,
|
|
11
|
+
isTelemetryEnabled,
|
|
12
|
+
listAgentProviders,
|
|
13
|
+
reparseStoredResult,
|
|
14
|
+
reparseStoredResult2,
|
|
15
|
+
reparseStoredResult3,
|
|
16
|
+
reparseStoredResult4,
|
|
17
|
+
setGoogleAuthConfig,
|
|
18
|
+
showFirstRunNotice,
|
|
19
|
+
trackEvent
|
|
20
|
+
} from "./chunk-MGBXRWLX.js";
|
|
2
21
|
import {
|
|
3
22
|
CcReleaseSyncStatuses,
|
|
4
23
|
CliError,
|
|
@@ -6,39 +25,22 @@ import {
|
|
|
6
25
|
ProviderNames,
|
|
7
26
|
RunKinds,
|
|
8
27
|
RunStatuses,
|
|
9
|
-
coerceAgentProvider,
|
|
10
|
-
computeCompetitorOverlap,
|
|
11
28
|
configExists,
|
|
12
29
|
createApiClient,
|
|
13
|
-
createServer,
|
|
14
30
|
determineAnswerMentioned,
|
|
15
|
-
determineCitationState,
|
|
16
31
|
effectiveDomains,
|
|
17
|
-
extractRecommendedCompetitors,
|
|
18
|
-
formatAuditFactorScore,
|
|
19
32
|
getConfigDir,
|
|
20
33
|
getConfigPath,
|
|
21
|
-
getOrCreateAnonymousId,
|
|
22
34
|
isEndpointMissing,
|
|
23
|
-
isFirstRun,
|
|
24
|
-
isTelemetryEnabled,
|
|
25
|
-
listAgentProviders,
|
|
26
35
|
loadConfig,
|
|
27
36
|
notificationEventSchema,
|
|
28
37
|
printCliError,
|
|
29
38
|
providerQuotaPolicySchema,
|
|
30
|
-
reparseStoredResult,
|
|
31
|
-
reparseStoredResult2,
|
|
32
|
-
reparseStoredResult3,
|
|
33
|
-
reparseStoredResult4,
|
|
34
39
|
resolveProviderInput,
|
|
35
40
|
saveConfig,
|
|
36
41
|
saveConfigPatch,
|
|
37
|
-
setGoogleAuthConfig,
|
|
38
|
-
showFirstRunNotice,
|
|
39
|
-
trackEvent,
|
|
40
42
|
usageError
|
|
41
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-FPZUQADO.js";
|
|
42
44
|
import {
|
|
43
45
|
apiKeys,
|
|
44
46
|
competitors,
|
|
@@ -48,7 +50,8 @@ import {
|
|
|
48
50
|
projects,
|
|
49
51
|
querySnapshots,
|
|
50
52
|
runs
|
|
51
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-PYHANJ3B.js";
|
|
54
|
+
import "./chunk-MLKGABMK.js";
|
|
52
55
|
|
|
53
56
|
// src/cli.ts
|
|
54
57
|
import { pathToFileURL } from "url";
|
|
@@ -58,9 +61,9 @@ import { parseArgs } from "util";
|
|
|
58
61
|
function commandId(spec) {
|
|
59
62
|
return spec.path.join(".");
|
|
60
63
|
}
|
|
61
|
-
function matchesPath(args,
|
|
62
|
-
if (args.length <
|
|
63
|
-
return
|
|
64
|
+
function matchesPath(args, path8) {
|
|
65
|
+
if (args.length < path8.length) return false;
|
|
66
|
+
return path8.every((segment, index) => args[index] === segment);
|
|
64
67
|
}
|
|
65
68
|
function withFormatOption(options) {
|
|
66
69
|
if (!options) {
|
|
@@ -295,7 +298,7 @@ async function backfillAnswerVisibilityCommand(opts) {
|
|
|
295
298
|
console.log(` Errors: ${providerErrors}`);
|
|
296
299
|
}
|
|
297
300
|
async function backfillInsightsCommand(project, opts) {
|
|
298
|
-
const { IntelligenceService } = await import("./intelligence-service-
|
|
301
|
+
const { IntelligenceService } = await import("./intelligence-service-2ZABHNR4.js");
|
|
299
302
|
const config = loadConfig();
|
|
300
303
|
const db = createClient(config.database);
|
|
301
304
|
migrate(db);
|
|
@@ -1566,9 +1569,9 @@ async function gaConnect(project, opts) {
|
|
|
1566
1569
|
propertyId: opts.propertyId
|
|
1567
1570
|
};
|
|
1568
1571
|
if (opts.keyFile) {
|
|
1569
|
-
const
|
|
1572
|
+
const fs9 = await import("fs");
|
|
1570
1573
|
try {
|
|
1571
|
-
const content =
|
|
1574
|
+
const content = fs9.readFileSync(opts.keyFile, "utf-8");
|
|
1572
1575
|
JSON.parse(content);
|
|
1573
1576
|
body.keyJson = content;
|
|
1574
1577
|
} catch (e) {
|
|
@@ -2184,13 +2187,15 @@ async function addCompetitors(project, domains, format) {
|
|
|
2184
2187
|
const client = getClient5();
|
|
2185
2188
|
const existing = await client.listCompetitors(project);
|
|
2186
2189
|
const existingDomains = existing.map((c) => c.domain);
|
|
2187
|
-
const
|
|
2188
|
-
const
|
|
2189
|
-
await client.
|
|
2190
|
+
const existingSet = new Set(existingDomains);
|
|
2191
|
+
const requested = new Set(uniqueStrings(domains));
|
|
2192
|
+
const current = await client.appendCompetitors(project, domains);
|
|
2193
|
+
const currentDomains = current.map((c) => c.domain);
|
|
2194
|
+
const addedDomains = currentDomains.filter((domain) => requested.has(domain) && !existingSet.has(domain));
|
|
2190
2195
|
if (format === "json") {
|
|
2191
2196
|
console.log(JSON.stringify({
|
|
2192
2197
|
project,
|
|
2193
|
-
domains:
|
|
2198
|
+
domains: currentDomains,
|
|
2194
2199
|
addedDomains,
|
|
2195
2200
|
addedCount: addedDomains.length
|
|
2196
2201
|
}, null, 2));
|
|
@@ -2202,6 +2207,35 @@ async function addCompetitors(project, domains, format) {
|
|
|
2202
2207
|
console.log(`Added ${addedDomains.length} competitor(s) to "${project}".`);
|
|
2203
2208
|
}
|
|
2204
2209
|
}
|
|
2210
|
+
async function removeCompetitors(project, domains, format) {
|
|
2211
|
+
const client = getClient5();
|
|
2212
|
+
const existing = await client.listCompetitors(project);
|
|
2213
|
+
const existingDomains = existing.map((c) => c.domain);
|
|
2214
|
+
const requested = new Set(uniqueStrings(domains));
|
|
2215
|
+
const current = await client.deleteCompetitors(project, domains);
|
|
2216
|
+
const currentSet = new Set(current.map((c) => c.domain));
|
|
2217
|
+
const removedDomains = existingDomains.filter((domain) => requested.has(domain) && !currentSet.has(domain));
|
|
2218
|
+
if (format === "json") {
|
|
2219
|
+
console.log(JSON.stringify({
|
|
2220
|
+
project,
|
|
2221
|
+
domains: current.map((c) => c.domain),
|
|
2222
|
+
removedDomains,
|
|
2223
|
+
removedCount: removedDomains.length
|
|
2224
|
+
}, null, 2));
|
|
2225
|
+
return;
|
|
2226
|
+
}
|
|
2227
|
+
console.log(`Removed ${removedDomains.length} competitor(s) from "${project}".`);
|
|
2228
|
+
}
|
|
2229
|
+
function uniqueStrings(values) {
|
|
2230
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2231
|
+
const result = [];
|
|
2232
|
+
for (const value of values) {
|
|
2233
|
+
if (seen.has(value)) continue;
|
|
2234
|
+
seen.add(value);
|
|
2235
|
+
result.push(value);
|
|
2236
|
+
}
|
|
2237
|
+
return result;
|
|
2238
|
+
}
|
|
2205
2239
|
async function listCompetitors(project, format) {
|
|
2206
2240
|
const client = getClient5();
|
|
2207
2241
|
const comps = await client.listCompetitors(project);
|
|
@@ -2240,6 +2274,42 @@ var COMPETITOR_CLI_COMMANDS = [
|
|
|
2240
2274
|
await addCompetitors(project, domains, input.format);
|
|
2241
2275
|
}
|
|
2242
2276
|
},
|
|
2277
|
+
{
|
|
2278
|
+
path: ["competitor", "remove"],
|
|
2279
|
+
usage: "canonry competitor remove <project> <domain...> [--format json]",
|
|
2280
|
+
run: async (input) => {
|
|
2281
|
+
const project = requireProject(input, "competitor.remove", "canonry competitor remove <project> <domain...> [--format json]");
|
|
2282
|
+
const domains = input.positionals.slice(1);
|
|
2283
|
+
if (domains.length === 0) {
|
|
2284
|
+
throw usageError("Error: project name and at least one domain required\nUsage: canonry competitor remove <project> <domain...> [--format json]", {
|
|
2285
|
+
message: "project name and at least one domain required",
|
|
2286
|
+
details: {
|
|
2287
|
+
command: "competitor.remove",
|
|
2288
|
+
usage: "canonry competitor remove <project> <domain...> [--format json]"
|
|
2289
|
+
}
|
|
2290
|
+
});
|
|
2291
|
+
}
|
|
2292
|
+
await removeCompetitors(project, domains, input.format);
|
|
2293
|
+
}
|
|
2294
|
+
},
|
|
2295
|
+
{
|
|
2296
|
+
path: ["competitor", "delete"],
|
|
2297
|
+
usage: "canonry competitor delete <project> <domain...> [--format json]",
|
|
2298
|
+
run: async (input) => {
|
|
2299
|
+
const project = requireProject(input, "competitor.delete", "canonry competitor delete <project> <domain...> [--format json]");
|
|
2300
|
+
const domains = input.positionals.slice(1);
|
|
2301
|
+
if (domains.length === 0) {
|
|
2302
|
+
throw usageError("Error: project name and at least one domain required\nUsage: canonry competitor delete <project> <domain...> [--format json]", {
|
|
2303
|
+
message: "project name and at least one domain required",
|
|
2304
|
+
details: {
|
|
2305
|
+
command: "competitor.delete",
|
|
2306
|
+
usage: "canonry competitor delete <project> <domain...> [--format json]"
|
|
2307
|
+
}
|
|
2308
|
+
});
|
|
2309
|
+
}
|
|
2310
|
+
await removeCompetitors(project, domains, input.format);
|
|
2311
|
+
}
|
|
2312
|
+
},
|
|
2243
2313
|
{
|
|
2244
2314
|
path: ["competitor", "list"],
|
|
2245
2315
|
usage: "canonry competitor list <project> [--format json]",
|
|
@@ -2250,12 +2320,12 @@ var COMPETITOR_CLI_COMMANDS = [
|
|
|
2250
2320
|
},
|
|
2251
2321
|
{
|
|
2252
2322
|
path: ["competitor"],
|
|
2253
|
-
usage: "canonry competitor <add|list> <project> [args]",
|
|
2323
|
+
usage: "canonry competitor <add|remove|delete|list> <project> [args]",
|
|
2254
2324
|
run: async (input) => {
|
|
2255
2325
|
unknownSubcommand(input.positionals[0], {
|
|
2256
2326
|
command: "competitor",
|
|
2257
|
-
usage: "canonry competitor <add|list> <project> [args]",
|
|
2258
|
-
available: ["add", "list"]
|
|
2327
|
+
usage: "canonry competitor <add|remove|delete|list> <project> [args]",
|
|
2328
|
+
available: ["add", "remove", "delete", "list"]
|
|
2259
2329
|
});
|
|
2260
2330
|
}
|
|
2261
2331
|
}
|
|
@@ -3121,6 +3191,19 @@ async function addKeywords(project, keywords, format) {
|
|
|
3121
3191
|
}
|
|
3122
3192
|
console.log(`Added ${keywords.length} key phrase(s) to "${project}".`);
|
|
3123
3193
|
}
|
|
3194
|
+
async function replaceKeywords(project, keywords, format) {
|
|
3195
|
+
const client = getClient7();
|
|
3196
|
+
await client.putKeywords(project, keywords);
|
|
3197
|
+
if (format === "json") {
|
|
3198
|
+
console.log(JSON.stringify({
|
|
3199
|
+
project,
|
|
3200
|
+
keywords,
|
|
3201
|
+
replacedCount: keywords.length
|
|
3202
|
+
}, null, 2));
|
|
3203
|
+
return;
|
|
3204
|
+
}
|
|
3205
|
+
console.log(`Set ${keywords.length} key phrase(s) for "${project}".`);
|
|
3206
|
+
}
|
|
3124
3207
|
async function removeKeywords(project, keywords, format) {
|
|
3125
3208
|
const client = getClient7();
|
|
3126
3209
|
const existing = await client.listKeywords(project);
|
|
@@ -3249,6 +3332,24 @@ var KEYWORD_CLI_COMMANDS = [
|
|
|
3249
3332
|
await addKeywords(project, keywords, input.format);
|
|
3250
3333
|
}
|
|
3251
3334
|
},
|
|
3335
|
+
{
|
|
3336
|
+
path: ["keyword", "replace"],
|
|
3337
|
+
usage: "canonry keyword replace <project> <kw...> [--format json]",
|
|
3338
|
+
run: async (input) => {
|
|
3339
|
+
const project = requireProject(input, "keyword.replace", "canonry keyword replace <project> <kw...> [--format json]");
|
|
3340
|
+
const keywords = input.positionals.slice(1);
|
|
3341
|
+
if (keywords.length === 0) {
|
|
3342
|
+
throw usageError("Error: project name and at least one key phrase required\nUsage: canonry keyword replace <project> <kw...> [--format json]", {
|
|
3343
|
+
message: "project name and at least one key phrase required",
|
|
3344
|
+
details: {
|
|
3345
|
+
command: "keyword.replace",
|
|
3346
|
+
usage: "canonry keyword replace <project> <kw...> [--format json]"
|
|
3347
|
+
}
|
|
3348
|
+
});
|
|
3349
|
+
}
|
|
3350
|
+
await replaceKeywords(project, keywords, input.format);
|
|
3351
|
+
}
|
|
3352
|
+
},
|
|
3252
3353
|
{
|
|
3253
3354
|
path: ["keyword", "remove"],
|
|
3254
3355
|
usage: "canonry keyword remove <project> <kw...> [--format json]",
|
|
@@ -3338,12 +3439,324 @@ var KEYWORD_CLI_COMMANDS = [
|
|
|
3338
3439
|
},
|
|
3339
3440
|
{
|
|
3340
3441
|
path: ["keyword"],
|
|
3341
|
-
usage: "canonry keyword <add|remove|delete|list|import|generate> <project> [args]",
|
|
3442
|
+
usage: "canonry keyword <add|replace|remove|delete|list|import|generate> <project> [args]",
|
|
3342
3443
|
run: async (input) => {
|
|
3343
3444
|
unknownSubcommand(input.positionals[0], {
|
|
3344
3445
|
command: "keyword",
|
|
3345
|
-
usage: "canonry keyword <add|remove|delete|list|import|generate> <project> [args]",
|
|
3346
|
-
available: ["add", "remove", "delete", "list", "import", "generate"]
|
|
3446
|
+
usage: "canonry keyword <add|replace|remove|delete|list|import|generate> <project> [args]",
|
|
3447
|
+
available: ["add", "replace", "remove", "delete", "list", "import", "generate"]
|
|
3448
|
+
});
|
|
3449
|
+
}
|
|
3450
|
+
}
|
|
3451
|
+
];
|
|
3452
|
+
|
|
3453
|
+
// src/commands/mcp.ts
|
|
3454
|
+
import fs2 from "fs";
|
|
3455
|
+
import path2 from "path";
|
|
3456
|
+
import { createRequire } from "module";
|
|
3457
|
+
|
|
3458
|
+
// src/mcp-clients.ts
|
|
3459
|
+
import os from "os";
|
|
3460
|
+
import path from "path";
|
|
3461
|
+
var CLAUDE_DESKTOP_CONFIG_FILENAME = "claude_desktop_config.json";
|
|
3462
|
+
function homeRelative(...segments) {
|
|
3463
|
+
return path.join(os.homedir(), ...segments);
|
|
3464
|
+
}
|
|
3465
|
+
function claudeDesktopConfigPath() {
|
|
3466
|
+
switch (process.platform) {
|
|
3467
|
+
case "darwin":
|
|
3468
|
+
return homeRelative("Library", "Application Support", "Claude", CLAUDE_DESKTOP_CONFIG_FILENAME);
|
|
3469
|
+
case "win32": {
|
|
3470
|
+
const appData = process.env.APPDATA ?? homeRelative("AppData", "Roaming");
|
|
3471
|
+
return path.join(appData, "Claude", CLAUDE_DESKTOP_CONFIG_FILENAME);
|
|
3472
|
+
}
|
|
3473
|
+
default:
|
|
3474
|
+
return homeRelative(".config", "Claude", CLAUDE_DESKTOP_CONFIG_FILENAME);
|
|
3475
|
+
}
|
|
3476
|
+
}
|
|
3477
|
+
function cursorConfigPath() {
|
|
3478
|
+
return homeRelative(".cursor", "mcp.json");
|
|
3479
|
+
}
|
|
3480
|
+
function codexConfigPath() {
|
|
3481
|
+
return homeRelative(".codex", "config.toml");
|
|
3482
|
+
}
|
|
3483
|
+
var SUPPORTED_MCP_CLIENTS = [
|
|
3484
|
+
{
|
|
3485
|
+
id: "claude-desktop",
|
|
3486
|
+
label: "Claude Desktop",
|
|
3487
|
+
format: "json-mcp-servers",
|
|
3488
|
+
configPath: claudeDesktopConfigPath,
|
|
3489
|
+
installSupported: true
|
|
3490
|
+
},
|
|
3491
|
+
{
|
|
3492
|
+
id: "cursor",
|
|
3493
|
+
label: "Cursor",
|
|
3494
|
+
format: "json-mcp-servers",
|
|
3495
|
+
configPath: cursorConfigPath,
|
|
3496
|
+
installSupported: true
|
|
3497
|
+
},
|
|
3498
|
+
{
|
|
3499
|
+
id: "codex",
|
|
3500
|
+
label: "Codex CLI",
|
|
3501
|
+
format: "toml-mcp-servers",
|
|
3502
|
+
configPath: codexConfigPath,
|
|
3503
|
+
installSupported: false
|
|
3504
|
+
}
|
|
3505
|
+
];
|
|
3506
|
+
function findMcpClient(id) {
|
|
3507
|
+
return SUPPORTED_MCP_CLIENTS.find((client) => client.id === id);
|
|
3508
|
+
}
|
|
3509
|
+
function listMcpClientIds() {
|
|
3510
|
+
return SUPPORTED_MCP_CLIENTS.map((client) => client.id);
|
|
3511
|
+
}
|
|
3512
|
+
|
|
3513
|
+
// src/commands/mcp.ts
|
|
3514
|
+
var _require = createRequire(import.meta.url);
|
|
3515
|
+
function resolveCanonryMcpBin() {
|
|
3516
|
+
const packageJsonPath = _require.resolve("../package.json");
|
|
3517
|
+
const packageRoot = path2.dirname(packageJsonPath);
|
|
3518
|
+
const pkg = _require("../package.json");
|
|
3519
|
+
const relativeBin = pkg.bin?.["canonry-mcp"];
|
|
3520
|
+
if (!relativeBin) {
|
|
3521
|
+
throw new CliError({
|
|
3522
|
+
code: "INTERNAL_ERROR",
|
|
3523
|
+
message: "Could not resolve canonry-mcp bin path from package.json",
|
|
3524
|
+
exitCode: 2
|
|
3525
|
+
});
|
|
3526
|
+
}
|
|
3527
|
+
return path2.resolve(packageRoot, relativeBin);
|
|
3528
|
+
}
|
|
3529
|
+
function buildEntry(opts) {
|
|
3530
|
+
const target = opts.binPath ?? resolveCanonryMcpBin();
|
|
3531
|
+
const flagArgs = opts.readOnly ? ["--read-only"] : [];
|
|
3532
|
+
const platform = opts.platform ?? process.platform;
|
|
3533
|
+
if (platform === "win32" && target.toLowerCase().endsWith(".mjs")) {
|
|
3534
|
+
return { command: "node", args: [target, ...flagArgs] };
|
|
3535
|
+
}
|
|
3536
|
+
return { command: target, args: flagArgs };
|
|
3537
|
+
}
|
|
3538
|
+
function entryArgs(entry) {
|
|
3539
|
+
return Array.isArray(entry.args) ? entry.args : [];
|
|
3540
|
+
}
|
|
3541
|
+
function entriesEqual(a, b) {
|
|
3542
|
+
if (a.command !== b.command) return false;
|
|
3543
|
+
const aArgs = entryArgs(a);
|
|
3544
|
+
const bArgs = entryArgs(b);
|
|
3545
|
+
return aArgs.length === bArgs.length && aArgs.every((arg, i) => arg === bArgs[i]);
|
|
3546
|
+
}
|
|
3547
|
+
function renderJsonSnippet(serverName, entry, format) {
|
|
3548
|
+
const key = format === "json-context-servers" ? "context_servers" : "mcpServers";
|
|
3549
|
+
return JSON.stringify({ [key]: { [serverName]: entry } }, null, 2);
|
|
3550
|
+
}
|
|
3551
|
+
function renderTomlSnippet(serverName, entry) {
|
|
3552
|
+
const argsLine = entry.args.length ? `args = [${entry.args.map((arg) => JSON.stringify(arg)).join(", ")}]` : "args = []";
|
|
3553
|
+
return [`[mcp_servers.${serverName}]`, `command = ${JSON.stringify(entry.command)}`, argsLine, ""].join("\n");
|
|
3554
|
+
}
|
|
3555
|
+
function renderClientSnippet(client, serverName, entry) {
|
|
3556
|
+
if (client.format === "toml-mcp-servers") return renderTomlSnippet(serverName, entry);
|
|
3557
|
+
return renderJsonSnippet(serverName, entry, client.format);
|
|
3558
|
+
}
|
|
3559
|
+
function readJsonConfig(configPath) {
|
|
3560
|
+
if (!fs2.existsSync(configPath)) return {};
|
|
3561
|
+
const raw = fs2.readFileSync(configPath, "utf-8").trim();
|
|
3562
|
+
if (!raw) return {};
|
|
3563
|
+
try {
|
|
3564
|
+
const parsed = JSON.parse(raw);
|
|
3565
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
3566
|
+
throw new Error("Config root must be a JSON object");
|
|
3567
|
+
}
|
|
3568
|
+
return parsed;
|
|
3569
|
+
} catch (err) {
|
|
3570
|
+
throw new CliError({
|
|
3571
|
+
code: "VALIDATION_ERROR",
|
|
3572
|
+
message: `Failed to parse ${configPath}: ${err instanceof Error ? err.message : String(err)}`,
|
|
3573
|
+
exitCode: 1,
|
|
3574
|
+
details: { configPath }
|
|
3575
|
+
});
|
|
3576
|
+
}
|
|
3577
|
+
}
|
|
3578
|
+
function writeJsonConfig(configPath, value) {
|
|
3579
|
+
fs2.mkdirSync(path2.dirname(configPath), { recursive: true });
|
|
3580
|
+
fs2.writeFileSync(configPath, `${JSON.stringify(value, null, 2)}
|
|
3581
|
+
`, "utf-8");
|
|
3582
|
+
}
|
|
3583
|
+
function backupConfigIfPresent(configPath) {
|
|
3584
|
+
if (!fs2.existsSync(configPath)) return void 0;
|
|
3585
|
+
const backupPath = `${configPath}.canonry.bak`;
|
|
3586
|
+
fs2.copyFileSync(configPath, backupPath);
|
|
3587
|
+
return backupPath;
|
|
3588
|
+
}
|
|
3589
|
+
function findClientOrThrow(id) {
|
|
3590
|
+
const client = findMcpClient(id);
|
|
3591
|
+
if (client) return client;
|
|
3592
|
+
throw new CliError({
|
|
3593
|
+
code: "VALIDATION_ERROR",
|
|
3594
|
+
message: `Unknown MCP client "${id}". Supported: ${listMcpClientIds().join(", ")}`,
|
|
3595
|
+
exitCode: 1,
|
|
3596
|
+
details: { client: id, supportedClients: listMcpClientIds() }
|
|
3597
|
+
});
|
|
3598
|
+
}
|
|
3599
|
+
async function installMcp(opts) {
|
|
3600
|
+
const client = findClientOrThrow(opts.client);
|
|
3601
|
+
const serverName = opts.name?.trim() || "canonry";
|
|
3602
|
+
const configPath = opts.configPath ?? client.configPath();
|
|
3603
|
+
const entry = buildEntry({ binPath: opts.binPath, readOnly: opts.readOnly, platform: opts.platform });
|
|
3604
|
+
if (!client.installSupported) {
|
|
3605
|
+
const snippet = renderClientSnippet(client, serverName, entry);
|
|
3606
|
+
const result2 = {
|
|
3607
|
+
client: client.id,
|
|
3608
|
+
configPath,
|
|
3609
|
+
serverName,
|
|
3610
|
+
entry,
|
|
3611
|
+
status: "snippet-only",
|
|
3612
|
+
snippet,
|
|
3613
|
+
message: `Auto-install is not supported for ${client.label}. Add the snippet below to ${configPath}.`
|
|
3614
|
+
};
|
|
3615
|
+
emitInstallResult(result2, opts.format);
|
|
3616
|
+
return result2;
|
|
3617
|
+
}
|
|
3618
|
+
const containerKey = client.format === "json-context-servers" ? "context_servers" : "mcpServers";
|
|
3619
|
+
const existing = readJsonConfig(configPath);
|
|
3620
|
+
const existingContainer = existing[containerKey] ?? {};
|
|
3621
|
+
const existingEntry = existingContainer[serverName];
|
|
3622
|
+
if (existingEntry && entriesEqual(existingEntry, entry)) {
|
|
3623
|
+
const result2 = {
|
|
3624
|
+
client: client.id,
|
|
3625
|
+
configPath,
|
|
3626
|
+
serverName,
|
|
3627
|
+
entry,
|
|
3628
|
+
status: "already-installed",
|
|
3629
|
+
message: `${client.label} already has a "${serverName}" entry pointing to canonry-mcp.`
|
|
3630
|
+
};
|
|
3631
|
+
emitInstallResult(result2, opts.format);
|
|
3632
|
+
return result2;
|
|
3633
|
+
}
|
|
3634
|
+
const status = existingEntry ? "updated" : "installed";
|
|
3635
|
+
if (opts.dryRun) {
|
|
3636
|
+
const result2 = {
|
|
3637
|
+
client: client.id,
|
|
3638
|
+
configPath,
|
|
3639
|
+
serverName,
|
|
3640
|
+
entry,
|
|
3641
|
+
status: "dry-run",
|
|
3642
|
+
snippet: renderClientSnippet(client, serverName, entry),
|
|
3643
|
+
message: `Would ${status === "installed" ? "install" : "update"} "${serverName}" in ${configPath}.`
|
|
3644
|
+
};
|
|
3645
|
+
emitInstallResult(result2, opts.format);
|
|
3646
|
+
return result2;
|
|
3647
|
+
}
|
|
3648
|
+
const backupPath = backupConfigIfPresent(configPath);
|
|
3649
|
+
const next = {
|
|
3650
|
+
...existing,
|
|
3651
|
+
[containerKey]: { ...existingContainer, [serverName]: entry }
|
|
3652
|
+
};
|
|
3653
|
+
writeJsonConfig(configPath, next);
|
|
3654
|
+
const result = {
|
|
3655
|
+
client: client.id,
|
|
3656
|
+
configPath,
|
|
3657
|
+
serverName,
|
|
3658
|
+
entry,
|
|
3659
|
+
status,
|
|
3660
|
+
backupPath,
|
|
3661
|
+
message: `${status === "installed" ? "Installed" : "Updated"} "${serverName}" in ${client.label} at ${configPath}. Restart ${client.label} to load it.`
|
|
3662
|
+
};
|
|
3663
|
+
emitInstallResult(result, opts.format);
|
|
3664
|
+
return result;
|
|
3665
|
+
}
|
|
3666
|
+
async function printMcpConfig(opts) {
|
|
3667
|
+
const client = findClientOrThrow(opts.client);
|
|
3668
|
+
const serverName = opts.name?.trim() || "canonry";
|
|
3669
|
+
const entry = buildEntry({ binPath: opts.binPath, readOnly: opts.readOnly, platform: opts.platform });
|
|
3670
|
+
const snippet = renderClientSnippet(client, serverName, entry);
|
|
3671
|
+
if (opts.format === "json") {
|
|
3672
|
+
console.log(JSON.stringify({
|
|
3673
|
+
client: client.id,
|
|
3674
|
+
configPath: client.configPath(),
|
|
3675
|
+
serverName,
|
|
3676
|
+
entry,
|
|
3677
|
+
snippet
|
|
3678
|
+
}, null, 2));
|
|
3679
|
+
return;
|
|
3680
|
+
}
|
|
3681
|
+
console.log(`# ${client.label} \u2014 paste into ${client.configPath()}`);
|
|
3682
|
+
console.log(snippet);
|
|
3683
|
+
}
|
|
3684
|
+
function emitInstallResult(result, format) {
|
|
3685
|
+
if (format === "json") {
|
|
3686
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3687
|
+
return;
|
|
3688
|
+
}
|
|
3689
|
+
console.log(result.message);
|
|
3690
|
+
if (result.backupPath) console.log(`Backup: ${result.backupPath}`);
|
|
3691
|
+
if (result.snippet && (result.status === "snippet-only" || result.status === "dry-run")) {
|
|
3692
|
+
console.log();
|
|
3693
|
+
console.log(result.snippet);
|
|
3694
|
+
}
|
|
3695
|
+
}
|
|
3696
|
+
|
|
3697
|
+
// src/cli-commands/mcp.ts
|
|
3698
|
+
var CLIENT_LIST = listMcpClientIds().join("|");
|
|
3699
|
+
var MCP_CLI_COMMANDS = [
|
|
3700
|
+
{
|
|
3701
|
+
path: ["mcp", "install"],
|
|
3702
|
+
usage: `canonry mcp install --client ${CLIENT_LIST} [--name <server>] [--read-only] [--dry-run] [--config-path <path>] [--format json]`,
|
|
3703
|
+
options: {
|
|
3704
|
+
client: stringOption(),
|
|
3705
|
+
name: stringOption(),
|
|
3706
|
+
"read-only": { type: "boolean" },
|
|
3707
|
+
"dry-run": { type: "boolean" },
|
|
3708
|
+
"config-path": stringOption()
|
|
3709
|
+
},
|
|
3710
|
+
run: async (input) => {
|
|
3711
|
+
const usage = `canonry mcp install --client ${CLIENT_LIST} [--name <server>] [--read-only] [--dry-run] [--config-path <path>] [--format json]`;
|
|
3712
|
+
const client = requireStringOption(input, "client", {
|
|
3713
|
+
command: "mcp.install",
|
|
3714
|
+
usage,
|
|
3715
|
+
message: "--client is required",
|
|
3716
|
+
details: { flag: "client", supportedClients: listMcpClientIds() }
|
|
3717
|
+
});
|
|
3718
|
+
await installMcp({
|
|
3719
|
+
client,
|
|
3720
|
+
name: getString(input.values, "name"),
|
|
3721
|
+
readOnly: getBoolean(input.values, "read-only"),
|
|
3722
|
+
dryRun: getBoolean(input.values, "dry-run"),
|
|
3723
|
+
configPath: getString(input.values, "config-path"),
|
|
3724
|
+
format: input.format
|
|
3725
|
+
});
|
|
3726
|
+
}
|
|
3727
|
+
},
|
|
3728
|
+
{
|
|
3729
|
+
path: ["mcp", "config"],
|
|
3730
|
+
usage: `canonry mcp config --client ${CLIENT_LIST} [--name <server>] [--read-only] [--format json]`,
|
|
3731
|
+
options: {
|
|
3732
|
+
client: stringOption(),
|
|
3733
|
+
name: stringOption(),
|
|
3734
|
+
"read-only": { type: "boolean" }
|
|
3735
|
+
},
|
|
3736
|
+
run: async (input) => {
|
|
3737
|
+
const usage = `canonry mcp config --client ${CLIENT_LIST} [--name <server>] [--read-only] [--format json]`;
|
|
3738
|
+
const client = requireStringOption(input, "client", {
|
|
3739
|
+
command: "mcp.config",
|
|
3740
|
+
usage,
|
|
3741
|
+
message: "--client is required",
|
|
3742
|
+
details: { flag: "client", supportedClients: listMcpClientIds() }
|
|
3743
|
+
});
|
|
3744
|
+
await printMcpConfig({
|
|
3745
|
+
client,
|
|
3746
|
+
name: getString(input.values, "name"),
|
|
3747
|
+
readOnly: getBoolean(input.values, "read-only"),
|
|
3748
|
+
format: input.format
|
|
3749
|
+
});
|
|
3750
|
+
}
|
|
3751
|
+
},
|
|
3752
|
+
{
|
|
3753
|
+
path: ["mcp"],
|
|
3754
|
+
usage: "canonry mcp <install|config> [args]",
|
|
3755
|
+
run: async (input) => {
|
|
3756
|
+
unknownSubcommand(input.positionals[0], {
|
|
3757
|
+
command: "mcp",
|
|
3758
|
+
usage: "canonry mcp <install|config> [args]",
|
|
3759
|
+
available: ["install", "config"]
|
|
3347
3760
|
});
|
|
3348
3761
|
}
|
|
3349
3762
|
}
|
|
@@ -3517,13 +3930,13 @@ var NOTIFY_CLI_COMMANDS = [
|
|
|
3517
3930
|
];
|
|
3518
3931
|
|
|
3519
3932
|
// src/commands/apply.ts
|
|
3520
|
-
import
|
|
3933
|
+
import fs3 from "fs";
|
|
3521
3934
|
import { parseAllDocuments } from "yaml";
|
|
3522
3935
|
async function applyConfigFile(filePath) {
|
|
3523
|
-
if (!
|
|
3936
|
+
if (!fs3.existsSync(filePath)) {
|
|
3524
3937
|
throw new Error(`File not found: ${filePath}`);
|
|
3525
3938
|
}
|
|
3526
|
-
const content =
|
|
3939
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
3527
3940
|
const docs = parseAllDocuments(content);
|
|
3528
3941
|
const client = createApiClient();
|
|
3529
3942
|
const errors = [];
|
|
@@ -4967,12 +5380,12 @@ Usage: canonry settings provider ${name} --api-key <key> [--model <model>] [--ma
|
|
|
4967
5380
|
];
|
|
4968
5381
|
|
|
4969
5382
|
// src/commands/snapshot.ts
|
|
4970
|
-
import
|
|
4971
|
-
import
|
|
5383
|
+
import fs5 from "fs";
|
|
5384
|
+
import path4 from "path";
|
|
4972
5385
|
|
|
4973
5386
|
// src/snapshot-pdf.ts
|
|
4974
|
-
import
|
|
4975
|
-
import
|
|
5387
|
+
import fs4 from "fs";
|
|
5388
|
+
import path3 from "path";
|
|
4976
5389
|
import { PDFDocument, StandardFonts, rgb } from "pdf-lib";
|
|
4977
5390
|
var PAGE_WIDTH = 612;
|
|
4978
5391
|
var PAGE_HEIGHT = 792;
|
|
@@ -5181,9 +5594,9 @@ async function writeSnapshotPdf(report, outputPath) {
|
|
|
5181
5594
|
renderCompetitors(pdf, report);
|
|
5182
5595
|
renderQueries(pdf, report);
|
|
5183
5596
|
const bytes = await doc.save();
|
|
5184
|
-
const resolvedPath =
|
|
5185
|
-
|
|
5186
|
-
|
|
5597
|
+
const resolvedPath = path3.resolve(outputPath);
|
|
5598
|
+
fs4.mkdirSync(path3.dirname(resolvedPath), { recursive: true });
|
|
5599
|
+
fs4.writeFileSync(resolvedPath, bytes);
|
|
5187
5600
|
return resolvedPath;
|
|
5188
5601
|
}
|
|
5189
5602
|
function renderCover(pdf, report) {
|
|
@@ -5341,9 +5754,9 @@ Markdown saved: ${savedMdPath}`);
|
|
|
5341
5754
|
PDF saved: ${savedPdfPath}`);
|
|
5342
5755
|
}
|
|
5343
5756
|
function writeSnapshotMarkdown(report, outputPath) {
|
|
5344
|
-
const resolvedPath =
|
|
5345
|
-
|
|
5346
|
-
|
|
5757
|
+
const resolvedPath = path4.resolve(outputPath);
|
|
5758
|
+
fs5.mkdirSync(path4.dirname(resolvedPath), { recursive: true });
|
|
5759
|
+
fs5.writeFileSync(resolvedPath, formatSnapshotMarkdown(report), "utf-8");
|
|
5347
5760
|
return resolvedPath;
|
|
5348
5761
|
}
|
|
5349
5762
|
function formatSnapshotMarkdown(report) {
|
|
@@ -5652,7 +6065,7 @@ var INTELLIGENCE_CLI_COMMANDS = [
|
|
|
5652
6065
|
|
|
5653
6066
|
// src/commands/bootstrap.ts
|
|
5654
6067
|
import crypto from "crypto";
|
|
5655
|
-
import
|
|
6068
|
+
import path5 from "path";
|
|
5656
6069
|
import { eq as eq2 } from "drizzle-orm";
|
|
5657
6070
|
|
|
5658
6071
|
// ../config/src/index.ts
|
|
@@ -5799,7 +6212,7 @@ async function bootstrapCommand(_opts) {
|
|
|
5799
6212
|
);
|
|
5800
6213
|
}
|
|
5801
6214
|
const configDir = getConfigDir();
|
|
5802
|
-
const databasePath = env.databasePath ||
|
|
6215
|
+
const databasePath = env.databasePath || path5.join(configDir, "data.db");
|
|
5803
6216
|
const existing = configExists();
|
|
5804
6217
|
const existingConfig = existing ? loadConfig() : void 0;
|
|
5805
6218
|
let rawApiKey;
|
|
@@ -5869,10 +6282,10 @@ async function bootstrapCommand(_opts) {
|
|
|
5869
6282
|
|
|
5870
6283
|
// src/commands/daemon.ts
|
|
5871
6284
|
import { spawn } from "child_process";
|
|
5872
|
-
import
|
|
5873
|
-
import
|
|
6285
|
+
import fs6 from "fs";
|
|
6286
|
+
import path6 from "path";
|
|
5874
6287
|
function getPidPath() {
|
|
5875
|
-
return
|
|
6288
|
+
return path6.join(getConfigDir(), "canonry.pid");
|
|
5876
6289
|
}
|
|
5877
6290
|
function isProcessAlive(pid) {
|
|
5878
6291
|
try {
|
|
@@ -5899,8 +6312,8 @@ async function waitForReady(host, port, maxMs = 1e4) {
|
|
|
5899
6312
|
async function startDaemon(opts) {
|
|
5900
6313
|
const pidPath = getPidPath();
|
|
5901
6314
|
const format = opts.format ?? "text";
|
|
5902
|
-
if (
|
|
5903
|
-
const existingPid = parseInt(
|
|
6315
|
+
if (fs6.existsSync(pidPath)) {
|
|
6316
|
+
const existingPid = parseInt(fs6.readFileSync(pidPath, "utf-8").trim(), 10);
|
|
5904
6317
|
if (!isNaN(existingPid) && isProcessAlive(existingPid)) {
|
|
5905
6318
|
throw new CliError({
|
|
5906
6319
|
code: "DAEMON_ALREADY_RUNNING",
|
|
@@ -5911,9 +6324,9 @@ async function startDaemon(opts) {
|
|
|
5911
6324
|
}
|
|
5912
6325
|
});
|
|
5913
6326
|
}
|
|
5914
|
-
|
|
6327
|
+
fs6.unlinkSync(pidPath);
|
|
5915
6328
|
}
|
|
5916
|
-
const cliPath =
|
|
6329
|
+
const cliPath = path6.resolve(new URL(import.meta.url).pathname);
|
|
5917
6330
|
const inSourceMode = new URL(import.meta.url).pathname.endsWith(".ts");
|
|
5918
6331
|
const args = inSourceMode ? ["--import", "tsx", cliPath, "serve"] : [cliPath, "serve"];
|
|
5919
6332
|
if (opts.port) args.push("--port", opts.port);
|
|
@@ -5932,10 +6345,10 @@ async function startDaemon(opts) {
|
|
|
5932
6345
|
});
|
|
5933
6346
|
}
|
|
5934
6347
|
const configDir = getConfigDir();
|
|
5935
|
-
if (!
|
|
5936
|
-
|
|
6348
|
+
if (!fs6.existsSync(configDir)) {
|
|
6349
|
+
fs6.mkdirSync(configDir, { recursive: true });
|
|
5937
6350
|
}
|
|
5938
|
-
|
|
6351
|
+
fs6.writeFileSync(pidPath, String(child.pid), "utf-8");
|
|
5939
6352
|
const port = opts.port ?? "4100";
|
|
5940
6353
|
const host = opts.host ?? "127.0.0.1";
|
|
5941
6354
|
if (format !== "json") {
|
|
@@ -5944,7 +6357,7 @@ async function startDaemon(opts) {
|
|
|
5944
6357
|
const ready = await waitForReady(host, port);
|
|
5945
6358
|
if (!ready) {
|
|
5946
6359
|
try {
|
|
5947
|
-
|
|
6360
|
+
fs6.unlinkSync(pidPath);
|
|
5948
6361
|
} catch {
|
|
5949
6362
|
}
|
|
5950
6363
|
throw new CliError({
|
|
@@ -5976,7 +6389,7 @@ async function startDaemon(opts) {
|
|
|
5976
6389
|
}
|
|
5977
6390
|
function stopDaemon(format = "text") {
|
|
5978
6391
|
const pidPath = getPidPath();
|
|
5979
|
-
if (!
|
|
6392
|
+
if (!fs6.existsSync(pidPath)) {
|
|
5980
6393
|
if (format === "json") {
|
|
5981
6394
|
console.log(JSON.stringify({
|
|
5982
6395
|
stopped: false,
|
|
@@ -5987,7 +6400,7 @@ function stopDaemon(format = "text") {
|
|
|
5987
6400
|
console.log("Canonry is not running (no PID file found)");
|
|
5988
6401
|
return;
|
|
5989
6402
|
}
|
|
5990
|
-
const pid = parseInt(
|
|
6403
|
+
const pid = parseInt(fs6.readFileSync(pidPath, "utf-8").trim(), 10);
|
|
5991
6404
|
if (isNaN(pid)) {
|
|
5992
6405
|
if (format === "json") {
|
|
5993
6406
|
console.log(JSON.stringify({
|
|
@@ -5998,7 +6411,7 @@ function stopDaemon(format = "text") {
|
|
|
5998
6411
|
} else {
|
|
5999
6412
|
console.error("Invalid PID file. Removing it.");
|
|
6000
6413
|
}
|
|
6001
|
-
|
|
6414
|
+
fs6.unlinkSync(pidPath);
|
|
6002
6415
|
return;
|
|
6003
6416
|
}
|
|
6004
6417
|
if (!isProcessAlive(pid)) {
|
|
@@ -6012,12 +6425,12 @@ function stopDaemon(format = "text") {
|
|
|
6012
6425
|
} else {
|
|
6013
6426
|
console.log(`Canonry is not running (stale PID: ${pid}). Cleaning up.`);
|
|
6014
6427
|
}
|
|
6015
|
-
|
|
6428
|
+
fs6.unlinkSync(pidPath);
|
|
6016
6429
|
return;
|
|
6017
6430
|
}
|
|
6018
6431
|
try {
|
|
6019
6432
|
process.kill(pid, "SIGTERM");
|
|
6020
|
-
|
|
6433
|
+
fs6.unlinkSync(pidPath);
|
|
6021
6434
|
if (format === "json") {
|
|
6022
6435
|
console.log(JSON.stringify({
|
|
6023
6436
|
stopped: true,
|
|
@@ -6041,9 +6454,9 @@ function stopDaemon(format = "text") {
|
|
|
6041
6454
|
|
|
6042
6455
|
// src/commands/init.ts
|
|
6043
6456
|
import crypto2 from "crypto";
|
|
6044
|
-
import
|
|
6457
|
+
import fs7 from "fs";
|
|
6045
6458
|
import readline from "readline";
|
|
6046
|
-
import
|
|
6459
|
+
import path7 from "path";
|
|
6047
6460
|
function prompt(question) {
|
|
6048
6461
|
const rl = readline.createInterface({
|
|
6049
6462
|
input: process.stdin,
|
|
@@ -6089,8 +6502,8 @@ async function initCommand(opts) {
|
|
|
6089
6502
|
return void 0;
|
|
6090
6503
|
}
|
|
6091
6504
|
const configDir = getConfigDir();
|
|
6092
|
-
if (!
|
|
6093
|
-
|
|
6505
|
+
if (!fs7.existsSync(configDir)) {
|
|
6506
|
+
fs7.mkdirSync(configDir, { recursive: true });
|
|
6094
6507
|
}
|
|
6095
6508
|
const bootstrapEnv = getBootstrapEnv(process.env, {
|
|
6096
6509
|
GEMINI_API_KEY: opts?.geminiKey,
|
|
@@ -6205,7 +6618,7 @@ async function initCommand(opts) {
|
|
|
6205
6618
|
const rawApiKey = `cnry_${crypto2.randomBytes(16).toString("hex")}`;
|
|
6206
6619
|
const keyHash = crypto2.createHash("sha256").update(rawApiKey).digest("hex");
|
|
6207
6620
|
const keyPrefix = rawApiKey.slice(0, 9);
|
|
6208
|
-
const databasePath =
|
|
6621
|
+
const databasePath = path7.join(configDir, "data.db");
|
|
6209
6622
|
const db = createClient(databasePath);
|
|
6210
6623
|
migrate(db);
|
|
6211
6624
|
db.insert(apiKeys).values({
|
|
@@ -6599,7 +7012,7 @@ var SYSTEM_CLI_COMMANDS = [
|
|
|
6599
7012
|
];
|
|
6600
7013
|
|
|
6601
7014
|
// src/cli-commands/wordpress.ts
|
|
6602
|
-
import
|
|
7015
|
+
import fs8 from "fs";
|
|
6603
7016
|
|
|
6604
7017
|
// src/commands/wordpress.ts
|
|
6605
7018
|
function getClient18() {
|
|
@@ -6835,12 +7248,12 @@ async function wordpressSetMeta(project, body) {
|
|
|
6835
7248
|
printPageDetail(result);
|
|
6836
7249
|
}
|
|
6837
7250
|
async function wordpressBulkSetMeta(project, opts) {
|
|
6838
|
-
const
|
|
6839
|
-
const
|
|
6840
|
-
const filePath =
|
|
7251
|
+
const fs9 = await import("fs/promises");
|
|
7252
|
+
const path8 = await import("path");
|
|
7253
|
+
const filePath = path8.resolve(opts.from);
|
|
6841
7254
|
let raw;
|
|
6842
7255
|
try {
|
|
6843
|
-
raw = await
|
|
7256
|
+
raw = await fs9.readFile(filePath, "utf8");
|
|
6844
7257
|
} catch {
|
|
6845
7258
|
throw new CliError({
|
|
6846
7259
|
code: "FILE_READ_ERROR",
|
|
@@ -6937,13 +7350,13 @@ async function wordpressSetSchema(project, body) {
|
|
|
6937
7350
|
printManualAssist(`Schema update for "${body.slug}"`, result);
|
|
6938
7351
|
}
|
|
6939
7352
|
async function wordpressSchemaDeploy(project, opts) {
|
|
6940
|
-
const
|
|
6941
|
-
const
|
|
7353
|
+
const fs9 = await import("fs/promises");
|
|
7354
|
+
const path8 = await import("path");
|
|
6942
7355
|
const yaml = await import("yaml").catch(() => null);
|
|
6943
|
-
const filePath =
|
|
7356
|
+
const filePath = path8.resolve(opts.profile);
|
|
6944
7357
|
let raw;
|
|
6945
7358
|
try {
|
|
6946
|
-
raw = await
|
|
7359
|
+
raw = await fs9.readFile(filePath, "utf8");
|
|
6947
7360
|
} catch {
|
|
6948
7361
|
throw new CliError({
|
|
6949
7362
|
code: "FILE_READ_ERROR",
|
|
@@ -7048,13 +7461,13 @@ async function wordpressOnboard(project, opts) {
|
|
|
7048
7461
|
}
|
|
7049
7462
|
let profileData;
|
|
7050
7463
|
if (opts.profile) {
|
|
7051
|
-
const
|
|
7052
|
-
const
|
|
7464
|
+
const fs9 = await import("fs/promises");
|
|
7465
|
+
const path8 = await import("path");
|
|
7053
7466
|
const yaml = await import("yaml").catch(() => null);
|
|
7054
|
-
const filePath =
|
|
7467
|
+
const filePath = path8.resolve(opts.profile);
|
|
7055
7468
|
let raw;
|
|
7056
7469
|
try {
|
|
7057
|
-
raw = await
|
|
7470
|
+
raw = await fs9.readFile(filePath, "utf8");
|
|
7058
7471
|
} catch {
|
|
7059
7472
|
throw new CliError({
|
|
7060
7473
|
code: "FILE_READ_ERROR",
|
|
@@ -7203,7 +7616,7 @@ function resolveContent(input, command, usage, options) {
|
|
|
7203
7616
|
}
|
|
7204
7617
|
if (contentFile) {
|
|
7205
7618
|
try {
|
|
7206
|
-
return
|
|
7619
|
+
return fs8.readFileSync(contentFile, "utf-8");
|
|
7207
7620
|
} catch (error) {
|
|
7208
7621
|
const message = error instanceof Error ? error.message : String(error);
|
|
7209
7622
|
throw usageError(`Error: could not read --content-file "${contentFile}": ${message}`, {
|
|
@@ -8139,11 +8552,12 @@ var REGISTERED_CLI_COMMANDS = [
|
|
|
8139
8552
|
...CDP_CLI_COMMANDS,
|
|
8140
8553
|
...GA_CLI_COMMANDS,
|
|
8141
8554
|
...INTELLIGENCE_CLI_COMMANDS,
|
|
8142
|
-
...AGENT_CLI_COMMANDS
|
|
8555
|
+
...AGENT_CLI_COMMANDS,
|
|
8556
|
+
...MCP_CLI_COMMANDS
|
|
8143
8557
|
];
|
|
8144
8558
|
|
|
8145
8559
|
// src/cli.ts
|
|
8146
|
-
import { createRequire } from "module";
|
|
8560
|
+
import { createRequire as createRequire2 } from "module";
|
|
8147
8561
|
var USAGE = `
|
|
8148
8562
|
canonry \u2014 AEO monitoring CLI
|
|
8149
8563
|
|
|
@@ -8157,8 +8571,8 @@ Setup:
|
|
|
8157
8571
|
|
|
8158
8572
|
Projects:
|
|
8159
8573
|
project Create, update, list, show, delete projects
|
|
8160
|
-
keyword Add, remove, list, import, generate key phrases
|
|
8161
|
-
competitor Add, list competitors
|
|
8574
|
+
keyword Add, replace, remove, list, import, generate key phrases
|
|
8575
|
+
competitor Add, remove, list competitors
|
|
8162
8576
|
|
|
8163
8577
|
Monitoring:
|
|
8164
8578
|
run Trigger visibility sweeps
|
|
@@ -8195,8 +8609,8 @@ Global options:
|
|
|
8195
8609
|
|
|
8196
8610
|
Run 'canonry <command> --help' for details on a specific command.
|
|
8197
8611
|
`.trim();
|
|
8198
|
-
var
|
|
8199
|
-
var { version: VERSION } =
|
|
8612
|
+
var _require2 = createRequire2(import.meta.url);
|
|
8613
|
+
var { version: VERSION } = _require2("../package.json");
|
|
8200
8614
|
function extractFormat(cmdArgs) {
|
|
8201
8615
|
const idx = cmdArgs.indexOf("--format");
|
|
8202
8616
|
if (idx !== -1 && cmdArgs[idx + 1] === "json") return "json";
|