@ainyc/canonry 3.6.4 → 4.1.3
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 +10 -10
- package/assets/agent-workspace/AGENTS.md +4 -4
- package/assets/agent-workspace/USER.md +1 -1
- package/assets/agent-workspace/skills/aero/SKILL.md +4 -4
- package/assets/agent-workspace/skills/aero/references/memory-patterns.md +3 -3
- package/assets/agent-workspace/skills/aero/references/orchestration.md +6 -6
- package/assets/agent-workspace/skills/aero/references/regression-playbook.md +7 -7
- package/assets/agent-workspace/skills/aero/references/reporting.md +8 -8
- package/assets/agent-workspace/skills/aero/soul.md +1 -1
- package/assets/agent-workspace/skills/canonry-setup/SKILL.md +5 -5
- package/assets/agent-workspace/skills/canonry-setup/references/aeo-analysis.md +15 -15
- package/assets/agent-workspace/skills/canonry-setup/references/canonry-cli.md +8 -8
- package/assets/assets/index-BbhhYPML.js +302 -0
- package/assets/assets/index-D7T5wSBj.css +1 -0
- package/assets/index.html +2 -2
- package/dist/{chunk-GP2P2WPS.js → chunk-AXMSAMKN.js} +113 -50
- package/dist/{chunk-JMVBV3AT.js → chunk-JV6X6AFT.js} +725 -474
- package/dist/{chunk-RQMOJEJT.js → chunk-KCETXLDF.js} +106 -16
- package/dist/{chunk-O7EVT3AF.js → chunk-O5JZQUPX.js} +71 -33
- package/dist/cli.js +484 -203
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-NL4BG3SM.js → intelligence-service-WPY4PDBU.js} +2 -2
- package/dist/mcp.js +4 -4
- package/package.json +8 -8
- package/assets/assets/index-C9XiA1Ol.js +0 -302
- package/assets/assets/index-D3wFrrZA.css +0 -1
package/dist/cli.js
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
setGoogleAuthConfig,
|
|
19
19
|
showFirstRunNotice,
|
|
20
20
|
trackEvent
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-JV6X6AFT.js";
|
|
22
22
|
import {
|
|
23
23
|
CliError,
|
|
24
24
|
EXIT_SYSTEM_ERROR,
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
saveConfig,
|
|
34
34
|
saveConfigPatch,
|
|
35
35
|
usageError
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-KCETXLDF.js";
|
|
37
37
|
import {
|
|
38
38
|
apiKeys,
|
|
39
39
|
competitors,
|
|
@@ -45,11 +45,12 @@ import {
|
|
|
45
45
|
projects,
|
|
46
46
|
querySnapshots,
|
|
47
47
|
runs
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-AXMSAMKN.js";
|
|
49
49
|
import {
|
|
50
50
|
CcReleaseSyncStatuses,
|
|
51
51
|
CheckScopes,
|
|
52
52
|
CheckStatuses,
|
|
53
|
+
CitationStates,
|
|
53
54
|
CodingAgents,
|
|
54
55
|
ProviderNames,
|
|
55
56
|
RunKinds,
|
|
@@ -63,7 +64,7 @@ import {
|
|
|
63
64
|
providerQuotaPolicySchema,
|
|
64
65
|
resolveProviderInput,
|
|
65
66
|
skillsClientSchema
|
|
66
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-O5JZQUPX.js";
|
|
67
68
|
|
|
68
69
|
// src/cli.ts
|
|
69
70
|
import { pathToFileURL } from "url";
|
|
@@ -579,7 +580,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
579
580
|
return result;
|
|
580
581
|
}
|
|
581
582
|
async function backfillInsightsCommand(project, opts) {
|
|
582
|
-
const { IntelligenceService } = await import("./intelligence-service-
|
|
583
|
+
const { IntelligenceService } = await import("./intelligence-service-WPY4PDBU.js");
|
|
583
584
|
const config = loadConfig();
|
|
584
585
|
const db = createClient(config.database);
|
|
585
586
|
migrate(db);
|
|
@@ -2017,9 +2018,9 @@ async function gaConnect(project, opts) {
|
|
|
2017
2018
|
propertyId: opts.propertyId
|
|
2018
2019
|
};
|
|
2019
2020
|
if (opts.keyFile) {
|
|
2020
|
-
const
|
|
2021
|
+
const fs12 = await import("fs");
|
|
2021
2022
|
try {
|
|
2022
|
-
const content =
|
|
2023
|
+
const content = fs12.readFileSync(opts.keyFile, "utf-8");
|
|
2023
2024
|
JSON.parse(content);
|
|
2024
2025
|
body.keyJson = content;
|
|
2025
2026
|
} catch (e) {
|
|
@@ -3947,8 +3948,285 @@ var KEYWORD_CLI_COMMANDS = [
|
|
|
3947
3948
|
}
|
|
3948
3949
|
];
|
|
3949
3950
|
|
|
3950
|
-
// src/commands/
|
|
3951
|
+
// src/commands/query.ts
|
|
3951
3952
|
import fs2 from "fs";
|
|
3953
|
+
function getClient8() {
|
|
3954
|
+
return createApiClient();
|
|
3955
|
+
}
|
|
3956
|
+
async function addQueries(project, queries, format) {
|
|
3957
|
+
const client = getClient8();
|
|
3958
|
+
await client.appendQueries(project, queries);
|
|
3959
|
+
if (format === "json") {
|
|
3960
|
+
console.log(JSON.stringify({
|
|
3961
|
+
project,
|
|
3962
|
+
queries,
|
|
3963
|
+
addedCount: queries.length
|
|
3964
|
+
}, null, 2));
|
|
3965
|
+
return;
|
|
3966
|
+
}
|
|
3967
|
+
console.log(`Added ${queries.length} ${queries.length === 1 ? "query" : "queries"} to "${project}".`);
|
|
3968
|
+
}
|
|
3969
|
+
async function replaceQueries(project, queries, format) {
|
|
3970
|
+
const client = getClient8();
|
|
3971
|
+
await client.putQueries(project, queries);
|
|
3972
|
+
if (format === "json") {
|
|
3973
|
+
console.log(JSON.stringify({
|
|
3974
|
+
project,
|
|
3975
|
+
queries,
|
|
3976
|
+
replacedCount: queries.length
|
|
3977
|
+
}, null, 2));
|
|
3978
|
+
return;
|
|
3979
|
+
}
|
|
3980
|
+
console.log(`Set ${queries.length} ${queries.length === 1 ? "query" : "queries"} for "${project}".`);
|
|
3981
|
+
}
|
|
3982
|
+
async function removeQueries(project, queries, format) {
|
|
3983
|
+
const client = getClient8();
|
|
3984
|
+
const existing = await client.listQueries(project);
|
|
3985
|
+
const existingSet = new Set(existing.map((q) => q.query));
|
|
3986
|
+
const removedQueries = queries.filter((q) => existingSet.has(q));
|
|
3987
|
+
await client.deleteQueries(project, queries);
|
|
3988
|
+
if (format === "json") {
|
|
3989
|
+
console.log(JSON.stringify({
|
|
3990
|
+
project,
|
|
3991
|
+
queries,
|
|
3992
|
+
removedQueries,
|
|
3993
|
+
removedCount: removedQueries.length
|
|
3994
|
+
}, null, 2));
|
|
3995
|
+
return;
|
|
3996
|
+
}
|
|
3997
|
+
console.log(`Removed ${removedQueries.length} ${removedQueries.length === 1 ? "query" : "queries"} from "${project}".`);
|
|
3998
|
+
}
|
|
3999
|
+
async function listQueries(project, format) {
|
|
4000
|
+
const client = getClient8();
|
|
4001
|
+
const qs = await client.listQueries(project);
|
|
4002
|
+
if (format === "json") {
|
|
4003
|
+
console.log(JSON.stringify(qs, null, 2));
|
|
4004
|
+
return;
|
|
4005
|
+
}
|
|
4006
|
+
if (qs.length === 0) {
|
|
4007
|
+
console.log(`No queries found for "${project}".`);
|
|
4008
|
+
return;
|
|
4009
|
+
}
|
|
4010
|
+
console.log(`Queries for "${project}" (${qs.length}):
|
|
4011
|
+
`);
|
|
4012
|
+
for (const q of qs) {
|
|
4013
|
+
console.log(` ${q.query}`);
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
4016
|
+
async function importQueries(project, filePath, format) {
|
|
4017
|
+
if (!fs2.existsSync(filePath)) {
|
|
4018
|
+
throw new CliError({
|
|
4019
|
+
code: "QUERY_IMPORT_FILE_NOT_FOUND",
|
|
4020
|
+
message: `File not found: ${filePath}`,
|
|
4021
|
+
displayMessage: `Error: file not found: ${filePath}`,
|
|
4022
|
+
details: {
|
|
4023
|
+
project,
|
|
4024
|
+
filePath
|
|
4025
|
+
}
|
|
4026
|
+
});
|
|
4027
|
+
}
|
|
4028
|
+
const content = fs2.readFileSync(filePath, "utf-8");
|
|
4029
|
+
const queries = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
4030
|
+
if (queries.length === 0) {
|
|
4031
|
+
if (format === "json") {
|
|
4032
|
+
console.log(JSON.stringify({
|
|
4033
|
+
project,
|
|
4034
|
+
filePath,
|
|
4035
|
+
queries: [],
|
|
4036
|
+
importedCount: 0
|
|
4037
|
+
}, null, 2));
|
|
4038
|
+
return;
|
|
4039
|
+
}
|
|
4040
|
+
console.log("No queries found in file.");
|
|
4041
|
+
return;
|
|
4042
|
+
}
|
|
4043
|
+
const client = getClient8();
|
|
4044
|
+
await client.appendQueries(project, queries);
|
|
4045
|
+
if (format === "json") {
|
|
4046
|
+
console.log(JSON.stringify({
|
|
4047
|
+
project,
|
|
4048
|
+
filePath,
|
|
4049
|
+
queries,
|
|
4050
|
+
importedCount: queries.length
|
|
4051
|
+
}, null, 2));
|
|
4052
|
+
return;
|
|
4053
|
+
}
|
|
4054
|
+
console.log(`Imported ${queries.length} ${queries.length === 1 ? "query" : "queries"} to "${project}".`);
|
|
4055
|
+
}
|
|
4056
|
+
async function generateQueries(project, provider, opts) {
|
|
4057
|
+
const client = getClient8();
|
|
4058
|
+
const result = await client.generateQueries(project, provider, opts.count);
|
|
4059
|
+
const saved = Boolean(opts.save && result.queries.length > 0);
|
|
4060
|
+
if (opts.format !== "json") {
|
|
4061
|
+
console.log(`Generated ${result.queries.length} ${result.queries.length === 1 ? "query" : "queries"} using ${result.provider}:
|
|
4062
|
+
`);
|
|
4063
|
+
for (const q of result.queries) {
|
|
4064
|
+
console.log(` ${q}`);
|
|
4065
|
+
}
|
|
4066
|
+
if (result.queries.length > 0 && !saved) {
|
|
4067
|
+
console.log(`
|
|
4068
|
+
To add these, run: canonry query add ${project} <query>...`);
|
|
4069
|
+
}
|
|
4070
|
+
}
|
|
4071
|
+
if (saved) {
|
|
4072
|
+
await client.appendQueries(project, result.queries);
|
|
4073
|
+
if (opts.format !== "json") {
|
|
4074
|
+
console.log(`
|
|
4075
|
+
Saved ${result.queries.length} ${result.queries.length === 1 ? "query" : "queries"} to "${project}".`);
|
|
4076
|
+
}
|
|
4077
|
+
}
|
|
4078
|
+
if (opts.format === "json") {
|
|
4079
|
+
console.log(JSON.stringify({
|
|
4080
|
+
project,
|
|
4081
|
+
provider: result.provider,
|
|
4082
|
+
queries: result.queries,
|
|
4083
|
+
generatedCount: result.queries.length,
|
|
4084
|
+
saved,
|
|
4085
|
+
savedCount: saved ? result.queries.length : 0
|
|
4086
|
+
}, null, 2));
|
|
4087
|
+
}
|
|
4088
|
+
}
|
|
4089
|
+
|
|
4090
|
+
// src/cli-commands/query.ts
|
|
4091
|
+
var QUERY_CLI_COMMANDS = [
|
|
4092
|
+
{
|
|
4093
|
+
path: ["query", "add"],
|
|
4094
|
+
usage: "canonry query add <project> <query...> [--format json]",
|
|
4095
|
+
run: async (input) => {
|
|
4096
|
+
const project = requireProject(input, "query.add", "canonry query add <project> <query...> [--format json]");
|
|
4097
|
+
const queries = input.positionals.slice(1);
|
|
4098
|
+
if (queries.length === 0) {
|
|
4099
|
+
throw usageError("Error: project name and at least one query required\nUsage: canonry query add <project> <query...> [--format json]", {
|
|
4100
|
+
message: "project name and at least one query required",
|
|
4101
|
+
details: {
|
|
4102
|
+
command: "query.add",
|
|
4103
|
+
usage: "canonry query add <project> <query...> [--format json]"
|
|
4104
|
+
}
|
|
4105
|
+
});
|
|
4106
|
+
}
|
|
4107
|
+
await addQueries(project, queries, input.format);
|
|
4108
|
+
}
|
|
4109
|
+
},
|
|
4110
|
+
{
|
|
4111
|
+
path: ["query", "replace"],
|
|
4112
|
+
usage: "canonry query replace <project> <query...> [--format json]",
|
|
4113
|
+
run: async (input) => {
|
|
4114
|
+
const project = requireProject(input, "query.replace", "canonry query replace <project> <query...> [--format json]");
|
|
4115
|
+
const queries = input.positionals.slice(1);
|
|
4116
|
+
if (queries.length === 0) {
|
|
4117
|
+
throw usageError("Error: project name and at least one query required\nUsage: canonry query replace <project> <query...> [--format json]", {
|
|
4118
|
+
message: "project name and at least one query required",
|
|
4119
|
+
details: {
|
|
4120
|
+
command: "query.replace",
|
|
4121
|
+
usage: "canonry query replace <project> <query...> [--format json]"
|
|
4122
|
+
}
|
|
4123
|
+
});
|
|
4124
|
+
}
|
|
4125
|
+
await replaceQueries(project, queries, input.format);
|
|
4126
|
+
}
|
|
4127
|
+
},
|
|
4128
|
+
{
|
|
4129
|
+
path: ["query", "remove"],
|
|
4130
|
+
usage: "canonry query remove <project> <query...> [--format json]",
|
|
4131
|
+
run: async (input) => {
|
|
4132
|
+
const project = requireProject(input, "query.remove", "canonry query remove <project> <query...> [--format json]");
|
|
4133
|
+
const queries = input.positionals.slice(1);
|
|
4134
|
+
if (queries.length === 0) {
|
|
4135
|
+
throw usageError("Error: project name and at least one query required\nUsage: canonry query remove <project> <query...> [--format json]", {
|
|
4136
|
+
message: "project name and at least one query required",
|
|
4137
|
+
details: {
|
|
4138
|
+
command: "query.remove",
|
|
4139
|
+
usage: "canonry query remove <project> <query...> [--format json]"
|
|
4140
|
+
}
|
|
4141
|
+
});
|
|
4142
|
+
}
|
|
4143
|
+
await removeQueries(project, queries, input.format);
|
|
4144
|
+
}
|
|
4145
|
+
},
|
|
4146
|
+
{
|
|
4147
|
+
path: ["query", "delete"],
|
|
4148
|
+
usage: "canonry query delete <project> <query...> [--format json]",
|
|
4149
|
+
run: async (input) => {
|
|
4150
|
+
const project = requireProject(input, "query.delete", "canonry query delete <project> <query...> [--format json]");
|
|
4151
|
+
const queries = input.positionals.slice(1);
|
|
4152
|
+
if (queries.length === 0) {
|
|
4153
|
+
throw usageError("Error: project name and at least one query required\nUsage: canonry query delete <project> <query...> [--format json]", {
|
|
4154
|
+
message: "project name and at least one query required",
|
|
4155
|
+
details: {
|
|
4156
|
+
command: "query.delete",
|
|
4157
|
+
usage: "canonry query delete <project> <query...> [--format json]"
|
|
4158
|
+
}
|
|
4159
|
+
});
|
|
4160
|
+
}
|
|
4161
|
+
await removeQueries(project, queries, input.format);
|
|
4162
|
+
}
|
|
4163
|
+
},
|
|
4164
|
+
{
|
|
4165
|
+
path: ["query", "list"],
|
|
4166
|
+
usage: "canonry query list <project> [--format json]",
|
|
4167
|
+
run: async (input) => {
|
|
4168
|
+
const project = requireProject(input, "query.list", "canonry query list <project> [--format json]");
|
|
4169
|
+
await listQueries(project, input.format);
|
|
4170
|
+
}
|
|
4171
|
+
},
|
|
4172
|
+
{
|
|
4173
|
+
path: ["query", "import"],
|
|
4174
|
+
usage: "canonry query import <project> <file> [--format json]",
|
|
4175
|
+
run: async (input) => {
|
|
4176
|
+
const project = requireProject(input, "query.import", "canonry query import <project> <file> [--format json]");
|
|
4177
|
+
const filePath = requirePositional(input, 1, {
|
|
4178
|
+
command: "query.import",
|
|
4179
|
+
usage: "canonry query import <project> <file> [--format json]",
|
|
4180
|
+
message: "project name and file path required"
|
|
4181
|
+
});
|
|
4182
|
+
await importQueries(project, filePath, input.format);
|
|
4183
|
+
}
|
|
4184
|
+
},
|
|
4185
|
+
{
|
|
4186
|
+
path: ["query", "generate"],
|
|
4187
|
+
usage: "canonry query generate <project> --provider <name> [--count <n>] [--save] [--format json]",
|
|
4188
|
+
options: {
|
|
4189
|
+
provider: stringOption(),
|
|
4190
|
+
count: stringOption(),
|
|
4191
|
+
save: { type: "boolean", default: false }
|
|
4192
|
+
},
|
|
4193
|
+
run: async (input) => {
|
|
4194
|
+
const project = requireProject(
|
|
4195
|
+
input,
|
|
4196
|
+
"query.generate",
|
|
4197
|
+
"canonry query generate <project> --provider <name> [--count <n>] [--save] [--format json]"
|
|
4198
|
+
);
|
|
4199
|
+
const provider = requireStringOption(input, "provider", {
|
|
4200
|
+
command: "query.generate",
|
|
4201
|
+
usage: "canonry query generate <project> --provider <name> [--count <n>] [--save] [--format json]",
|
|
4202
|
+
message: "--provider is required (e.g. gemini, openai, claude, perplexity, local)"
|
|
4203
|
+
});
|
|
4204
|
+
await generateQueries(project, provider, {
|
|
4205
|
+
count: parseIntegerOption(input, "count", {
|
|
4206
|
+
command: "query.generate",
|
|
4207
|
+
usage: "canonry query generate <project> --provider <name> [--count <n>] [--save] [--format json]",
|
|
4208
|
+
message: "--count must be an integer"
|
|
4209
|
+
}),
|
|
4210
|
+
save: getBoolean(input.values, "save"),
|
|
4211
|
+
format: input.format
|
|
4212
|
+
});
|
|
4213
|
+
}
|
|
4214
|
+
},
|
|
4215
|
+
{
|
|
4216
|
+
path: ["query"],
|
|
4217
|
+
usage: "canonry query <add|replace|remove|delete|list|import|generate> <project> [args]",
|
|
4218
|
+
run: async (input) => {
|
|
4219
|
+
unknownSubcommand(input.positionals[0], {
|
|
4220
|
+
command: "query",
|
|
4221
|
+
usage: "canonry query <add|replace|remove|delete|list|import|generate> <project> [args]",
|
|
4222
|
+
available: ["add", "replace", "remove", "delete", "list", "import", "generate"]
|
|
4223
|
+
});
|
|
4224
|
+
}
|
|
4225
|
+
}
|
|
4226
|
+
];
|
|
4227
|
+
|
|
4228
|
+
// src/commands/mcp.ts
|
|
4229
|
+
import fs3 from "fs";
|
|
3952
4230
|
import path2 from "path";
|
|
3953
4231
|
import { createRequire } from "module";
|
|
3954
4232
|
|
|
@@ -4054,8 +4332,8 @@ function renderClientSnippet(client, serverName, entry) {
|
|
|
4054
4332
|
return renderJsonSnippet(serverName, entry, client.format);
|
|
4055
4333
|
}
|
|
4056
4334
|
function readJsonConfig(configPath) {
|
|
4057
|
-
if (!
|
|
4058
|
-
const raw =
|
|
4335
|
+
if (!fs3.existsSync(configPath)) return {};
|
|
4336
|
+
const raw = fs3.readFileSync(configPath, "utf-8").trim();
|
|
4059
4337
|
if (!raw) return {};
|
|
4060
4338
|
try {
|
|
4061
4339
|
const parsed = JSON.parse(raw);
|
|
@@ -4073,14 +4351,14 @@ function readJsonConfig(configPath) {
|
|
|
4073
4351
|
}
|
|
4074
4352
|
}
|
|
4075
4353
|
function writeJsonConfig(configPath, value) {
|
|
4076
|
-
|
|
4077
|
-
|
|
4354
|
+
fs3.mkdirSync(path2.dirname(configPath), { recursive: true });
|
|
4355
|
+
fs3.writeFileSync(configPath, `${JSON.stringify(value, null, 2)}
|
|
4078
4356
|
`, "utf-8");
|
|
4079
4357
|
}
|
|
4080
4358
|
function backupConfigIfPresent(configPath) {
|
|
4081
|
-
if (!
|
|
4359
|
+
if (!fs3.existsSync(configPath)) return void 0;
|
|
4082
4360
|
const backupPath = `${configPath}.canonry.bak`;
|
|
4083
|
-
|
|
4361
|
+
fs3.copyFileSync(configPath, backupPath);
|
|
4084
4362
|
return backupPath;
|
|
4085
4363
|
}
|
|
4086
4364
|
function findClientOrThrow(id) {
|
|
@@ -4260,11 +4538,11 @@ var MCP_CLI_COMMANDS = [
|
|
|
4260
4538
|
];
|
|
4261
4539
|
|
|
4262
4540
|
// src/commands/notify.ts
|
|
4263
|
-
function
|
|
4541
|
+
function getClient9() {
|
|
4264
4542
|
return createApiClient();
|
|
4265
4543
|
}
|
|
4266
4544
|
async function addNotification(project, opts) {
|
|
4267
|
-
const client =
|
|
4545
|
+
const client = getClient9();
|
|
4268
4546
|
const result = await client.createNotification(project, {
|
|
4269
4547
|
channel: "webhook",
|
|
4270
4548
|
url: opts.webhook,
|
|
@@ -4278,7 +4556,7 @@ async function addNotification(project, opts) {
|
|
|
4278
4556
|
printNotification(result);
|
|
4279
4557
|
}
|
|
4280
4558
|
async function listNotifications(project, format) {
|
|
4281
|
-
const client =
|
|
4559
|
+
const client = getClient9();
|
|
4282
4560
|
const results = await client.listNotifications(project);
|
|
4283
4561
|
if (format === "json") {
|
|
4284
4562
|
console.log(JSON.stringify(results, null, 2));
|
|
@@ -4296,7 +4574,7 @@ async function listNotifications(project, format) {
|
|
|
4296
4574
|
}
|
|
4297
4575
|
}
|
|
4298
4576
|
async function removeNotification(project, id, format) {
|
|
4299
|
-
const client =
|
|
4577
|
+
const client = getClient9();
|
|
4300
4578
|
await client.deleteNotification(project, id);
|
|
4301
4579
|
if (format === "json") {
|
|
4302
4580
|
console.log(JSON.stringify({ project, id, removed: true }, null, 2));
|
|
@@ -4305,7 +4583,7 @@ async function removeNotification(project, id, format) {
|
|
|
4305
4583
|
console.log(`Notification ${id} removed from "${project}"`);
|
|
4306
4584
|
}
|
|
4307
4585
|
async function testNotification(project, id, format) {
|
|
4308
|
-
const client =
|
|
4586
|
+
const client = getClient9();
|
|
4309
4587
|
const result = await client.testNotification(project, id);
|
|
4310
4588
|
if (format === "json") {
|
|
4311
4589
|
console.log(JSON.stringify({ project, id, ...result }, null, 2));
|
|
@@ -4318,10 +4596,10 @@ async function testNotification(project, id, format) {
|
|
|
4318
4596
|
}
|
|
4319
4597
|
}
|
|
4320
4598
|
var EVENT_DESCRIPTIONS = {
|
|
4321
|
-
"citation.lost": "A
|
|
4322
|
-
"citation.gained": "A
|
|
4323
|
-
"run.completed": "
|
|
4324
|
-
"run.failed": "
|
|
4599
|
+
"citation.lost": "A query lost its citation status",
|
|
4600
|
+
"citation.gained": "A query gained citation status",
|
|
4601
|
+
"run.completed": "An AEO sweep completed successfully",
|
|
4602
|
+
"run.failed": "An AEO sweep failed",
|
|
4325
4603
|
"insight.critical": "A critical-severity insight was generated",
|
|
4326
4604
|
"insight.high": "A high-severity insight was generated"
|
|
4327
4605
|
};
|
|
@@ -4427,13 +4705,13 @@ var NOTIFY_CLI_COMMANDS = [
|
|
|
4427
4705
|
];
|
|
4428
4706
|
|
|
4429
4707
|
// src/commands/apply.ts
|
|
4430
|
-
import
|
|
4708
|
+
import fs4 from "fs";
|
|
4431
4709
|
import { parseAllDocuments } from "yaml";
|
|
4432
4710
|
async function applyConfigFile(filePath) {
|
|
4433
|
-
if (!
|
|
4711
|
+
if (!fs4.existsSync(filePath)) {
|
|
4434
4712
|
throw new Error(`File not found: ${filePath}`);
|
|
4435
4713
|
}
|
|
4436
|
-
const content =
|
|
4714
|
+
const content = fs4.readFileSync(filePath, "utf-8");
|
|
4437
4715
|
const docs = parseAllDocuments(content);
|
|
4438
4716
|
const client = createApiClient();
|
|
4439
4717
|
const errors = [];
|
|
@@ -4496,11 +4774,11 @@ async function applyConfigs(filePaths, format) {
|
|
|
4496
4774
|
}
|
|
4497
4775
|
|
|
4498
4776
|
// src/commands/analytics.ts
|
|
4499
|
-
function
|
|
4777
|
+
function getClient10() {
|
|
4500
4778
|
return createApiClient();
|
|
4501
4779
|
}
|
|
4502
4780
|
async function showAnalytics(project, options) {
|
|
4503
|
-
const client =
|
|
4781
|
+
const client = getClient10();
|
|
4504
4782
|
const features = options.feature ? [options.feature] : ["metrics", "gaps", "sources"];
|
|
4505
4783
|
const results = {};
|
|
4506
4784
|
for (const feature of features) {
|
|
@@ -4571,19 +4849,19 @@ Brand Gap Analysis`);
|
|
|
4571
4849
|
if (data.gap.length > 0) {
|
|
4572
4850
|
console.log(`
|
|
4573
4851
|
Opportunity Gaps (competitors cited, you're not):`);
|
|
4574
|
-
for (const
|
|
4575
|
-
const competitors2 =
|
|
4576
|
-
const cons =
|
|
4577
|
-
console.log(` \u2022 ${
|
|
4852
|
+
for (const q of data.gap) {
|
|
4853
|
+
const competitors2 = q.competitorsCiting.join(", ");
|
|
4854
|
+
const cons = q.consistency.totalRuns > 0 ? ` [cited ${q.consistency.citedRuns}/${q.consistency.totalRuns} runs]` : "";
|
|
4855
|
+
console.log(` \u2022 ${q.query}${cons}`);
|
|
4578
4856
|
console.log(` Competitors: ${competitors2}`);
|
|
4579
4857
|
}
|
|
4580
4858
|
}
|
|
4581
4859
|
if (data.cited.length > 0) {
|
|
4582
4860
|
console.log(`
|
|
4583
|
-
Cited
|
|
4584
|
-
for (const
|
|
4585
|
-
const cons =
|
|
4586
|
-
console.log(` \u2713 ${
|
|
4861
|
+
Cited Queries:`);
|
|
4862
|
+
for (const q of data.cited) {
|
|
4863
|
+
const cons = q.consistency.totalRuns > 0 ? ` [${q.consistency.citedRuns}/${q.consistency.totalRuns} runs]` : "";
|
|
4864
|
+
console.log(` \u2713 ${q.query} (${q.providers.join(", ")})${cons}`);
|
|
4587
4865
|
}
|
|
4588
4866
|
}
|
|
4589
4867
|
}
|
|
@@ -4603,22 +4881,22 @@ Source Origin Breakdown`);
|
|
|
4603
4881
|
}
|
|
4604
4882
|
|
|
4605
4883
|
// src/commands/evidence.ts
|
|
4606
|
-
function
|
|
4884
|
+
function getClient11() {
|
|
4607
4885
|
return createApiClient();
|
|
4608
4886
|
}
|
|
4609
4887
|
async function showEvidence(project, format) {
|
|
4610
|
-
const client =
|
|
4888
|
+
const client = getClient11();
|
|
4611
4889
|
const timeline = await client.getTimeline(project);
|
|
4612
4890
|
if (format === "json") {
|
|
4613
4891
|
const enriched = timeline.map((entry) => ({
|
|
4614
4892
|
...entry,
|
|
4615
|
-
cited: entry.runs[entry.runs.length - 1]?.citationState ===
|
|
4893
|
+
cited: entry.runs[entry.runs.length - 1]?.citationState === CitationStates.cited
|
|
4616
4894
|
}));
|
|
4617
4895
|
console.log(JSON.stringify(enriched, null, 2));
|
|
4618
4896
|
return;
|
|
4619
4897
|
}
|
|
4620
4898
|
if (timeline.length === 0) {
|
|
4621
|
-
console.log('No
|
|
4899
|
+
console.log('No query evidence yet. Trigger a run first with "canonry run".');
|
|
4622
4900
|
return;
|
|
4623
4901
|
}
|
|
4624
4902
|
console.log(`Evidence: ${project}
|
|
@@ -4626,13 +4904,13 @@ async function showEvidence(project, format) {
|
|
|
4626
4904
|
for (const entry of timeline) {
|
|
4627
4905
|
const latest = entry.runs[entry.runs.length - 1];
|
|
4628
4906
|
if (!latest) continue;
|
|
4629
|
-
const state = latest.citationState ===
|
|
4907
|
+
const state = latest.citationState === CitationStates.cited ? "\u2713 cited" : "\u2717 not-cited";
|
|
4630
4908
|
const transition = latest.transition !== latest.citationState ? ` (${latest.transition})` : "";
|
|
4631
|
-
console.log(` ${state}${transition} ${entry.
|
|
4909
|
+
console.log(` ${state}${transition} ${entry.query}`);
|
|
4632
4910
|
}
|
|
4633
4911
|
console.log(`
|
|
4634
|
-
|
|
4635
|
-
const cited = timeline.filter((e) => e.runs[e.runs.length - 1]?.citationState ===
|
|
4912
|
+
Queries: ${timeline.length}`);
|
|
4913
|
+
const cited = timeline.filter((e) => e.runs[e.runs.length - 1]?.citationState === CitationStates.cited).length;
|
|
4636
4914
|
console.log(` Cited: ${cited} / ${timeline.length}`);
|
|
4637
4915
|
}
|
|
4638
4916
|
|
|
@@ -4667,11 +4945,11 @@ async function loadLatestRunForExport(client, project) {
|
|
|
4667
4945
|
}
|
|
4668
4946
|
|
|
4669
4947
|
// src/commands/history.ts
|
|
4670
|
-
function
|
|
4948
|
+
function getClient12() {
|
|
4671
4949
|
return createApiClient();
|
|
4672
4950
|
}
|
|
4673
4951
|
async function showHistory(project, format) {
|
|
4674
|
-
const client =
|
|
4952
|
+
const client = getClient12();
|
|
4675
4953
|
try {
|
|
4676
4954
|
const entries = await client.getHistory(project);
|
|
4677
4955
|
if (format === "json") {
|
|
@@ -4706,11 +4984,11 @@ async function showHistory(project, format) {
|
|
|
4706
4984
|
}
|
|
4707
4985
|
|
|
4708
4986
|
// src/commands/status.ts
|
|
4709
|
-
function
|
|
4987
|
+
function getClient13() {
|
|
4710
4988
|
return createApiClient();
|
|
4711
4989
|
}
|
|
4712
4990
|
async function showStatus(project, format) {
|
|
4713
|
-
const client =
|
|
4991
|
+
const client = getClient13();
|
|
4714
4992
|
const projectData = await client.getProject(project);
|
|
4715
4993
|
const latest = await getLatestRunSummary(client, project);
|
|
4716
4994
|
if (format === "json") {
|
|
@@ -4841,11 +5119,11 @@ var OPERATOR_CLI_COMMANDS = [
|
|
|
4841
5119
|
];
|
|
4842
5120
|
|
|
4843
5121
|
// src/commands/project.ts
|
|
4844
|
-
function
|
|
5122
|
+
function getClient14() {
|
|
4845
5123
|
return createApiClient();
|
|
4846
5124
|
}
|
|
4847
5125
|
async function createProject(name, opts) {
|
|
4848
|
-
const client =
|
|
5126
|
+
const client = getClient14();
|
|
4849
5127
|
const result = await client.putProject(name, {
|
|
4850
5128
|
displayName: opts.displayName,
|
|
4851
5129
|
canonicalDomain: opts.domain,
|
|
@@ -4860,7 +5138,7 @@ async function createProject(name, opts) {
|
|
|
4860
5138
|
console.log(`Project created: ${result.name} (${result.id})`);
|
|
4861
5139
|
}
|
|
4862
5140
|
async function listProjects(format) {
|
|
4863
|
-
const client =
|
|
5141
|
+
const client = getClient14();
|
|
4864
5142
|
const projects2 = await client.listProjects();
|
|
4865
5143
|
if (format === "json") {
|
|
4866
5144
|
console.log(JSON.stringify(projects2, null, 2));
|
|
@@ -4888,7 +5166,7 @@ async function listProjects(format) {
|
|
|
4888
5166
|
}
|
|
4889
5167
|
}
|
|
4890
5168
|
async function showProject(name, format) {
|
|
4891
|
-
const client =
|
|
5169
|
+
const client = getClient14();
|
|
4892
5170
|
const project = await client.getProject(name);
|
|
4893
5171
|
if (format === "json") {
|
|
4894
5172
|
console.log(JSON.stringify(project, null, 2));
|
|
@@ -4914,7 +5192,7 @@ async function showProject(name, format) {
|
|
|
4914
5192
|
if (project.updatedAt) console.log(` Updated: ${project.updatedAt}`);
|
|
4915
5193
|
}
|
|
4916
5194
|
async function updateProjectSettings(name, opts) {
|
|
4917
|
-
const client =
|
|
5195
|
+
const client = getClient14();
|
|
4918
5196
|
const project = await client.getProject(name);
|
|
4919
5197
|
let ownedDomains = opts.ownedDomains ?? project.ownedDomains ?? [];
|
|
4920
5198
|
if (opts.addOwnedDomain) {
|
|
@@ -4939,7 +5217,7 @@ async function updateProjectSettings(name, opts) {
|
|
|
4939
5217
|
console.log(`Project updated: ${result.name}`);
|
|
4940
5218
|
}
|
|
4941
5219
|
async function deleteProject(name, format) {
|
|
4942
|
-
const client =
|
|
5220
|
+
const client = getClient14();
|
|
4943
5221
|
await client.deleteProject(name);
|
|
4944
5222
|
if (format === "json") {
|
|
4945
5223
|
console.log(JSON.stringify({ name, deleted: true }, null, 2));
|
|
@@ -4948,7 +5226,7 @@ async function deleteProject(name, format) {
|
|
|
4948
5226
|
console.log(`Project deleted: ${name}`);
|
|
4949
5227
|
}
|
|
4950
5228
|
async function addLocation(project, opts) {
|
|
4951
|
-
const client =
|
|
5229
|
+
const client = getClient14();
|
|
4952
5230
|
const location = await client.addLocation(project, {
|
|
4953
5231
|
label: opts.label,
|
|
4954
5232
|
city: opts.city,
|
|
@@ -4963,7 +5241,7 @@ async function addLocation(project, opts) {
|
|
|
4963
5241
|
console.log(`Location added: ${opts.label} (${opts.city}, ${opts.region}, ${opts.country})`);
|
|
4964
5242
|
}
|
|
4965
5243
|
async function listLocations(project, format) {
|
|
4966
|
-
const client =
|
|
5244
|
+
const client = getClient14();
|
|
4967
5245
|
const result = await client.listLocations(project);
|
|
4968
5246
|
if (format === "json") {
|
|
4969
5247
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4989,7 +5267,7 @@ async function listLocations(project, format) {
|
|
|
4989
5267
|
}
|
|
4990
5268
|
}
|
|
4991
5269
|
async function removeLocation(project, label, format) {
|
|
4992
|
-
const client =
|
|
5270
|
+
const client = getClient14();
|
|
4993
5271
|
await client.removeLocation(project, label);
|
|
4994
5272
|
if (format === "json") {
|
|
4995
5273
|
console.log(JSON.stringify({ project, label, removed: true }, null, 2));
|
|
@@ -4998,7 +5276,7 @@ async function removeLocation(project, label, format) {
|
|
|
4998
5276
|
console.log(`Location removed: ${label}`);
|
|
4999
5277
|
}
|
|
5000
5278
|
async function setDefaultLocation(project, label, format) {
|
|
5001
|
-
const client =
|
|
5279
|
+
const client = getClient14();
|
|
5002
5280
|
const result = await client.setDefaultLocation(project, label);
|
|
5003
5281
|
if (format === "json") {
|
|
5004
5282
|
console.log(JSON.stringify({ project, ...result }, null, 2));
|
|
@@ -5177,7 +5455,7 @@ var PROJECT_CLI_COMMANDS = [
|
|
|
5177
5455
|
];
|
|
5178
5456
|
|
|
5179
5457
|
// src/commands/report.ts
|
|
5180
|
-
import
|
|
5458
|
+
import fs5 from "fs";
|
|
5181
5459
|
import path3 from "path";
|
|
5182
5460
|
function defaultOutputPath(project) {
|
|
5183
5461
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
@@ -5193,10 +5471,10 @@ async function runReportCommand(project, opts = {}) {
|
|
|
5193
5471
|
const html = renderReportHtml(report);
|
|
5194
5472
|
const targetPath = opts.output ? path3.resolve(opts.output) : defaultOutputPath(project);
|
|
5195
5473
|
const dir = path3.dirname(targetPath);
|
|
5196
|
-
if (!
|
|
5197
|
-
|
|
5474
|
+
if (!fs5.existsSync(dir)) {
|
|
5475
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
5198
5476
|
}
|
|
5199
|
-
|
|
5477
|
+
fs5.writeFileSync(targetPath, html, "utf-8");
|
|
5200
5478
|
console.log(`Report written to ${targetPath}`);
|
|
5201
5479
|
}
|
|
5202
5480
|
|
|
@@ -5220,12 +5498,12 @@ var REPORT_CLI_COMMANDS = [
|
|
|
5220
5498
|
];
|
|
5221
5499
|
|
|
5222
5500
|
// src/commands/run.ts
|
|
5223
|
-
function
|
|
5501
|
+
function getClient15() {
|
|
5224
5502
|
return createApiClient();
|
|
5225
5503
|
}
|
|
5226
5504
|
var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "partial", "failed", "cancelled"]);
|
|
5227
5505
|
async function triggerRun(project, opts) {
|
|
5228
|
-
const client =
|
|
5506
|
+
const client = getClient15();
|
|
5229
5507
|
const body = {};
|
|
5230
5508
|
if (opts?.provider) {
|
|
5231
5509
|
const providerInputs = opts.provider.split(",").map((s) => s.trim()).filter(Boolean);
|
|
@@ -5321,7 +5599,7 @@ async function triggerRun(project, opts) {
|
|
|
5321
5599
|
}
|
|
5322
5600
|
}
|
|
5323
5601
|
async function triggerRunAll(opts) {
|
|
5324
|
-
const client =
|
|
5602
|
+
const client = getClient15();
|
|
5325
5603
|
const projects2 = await client.listProjects();
|
|
5326
5604
|
if (projects2.length === 0) {
|
|
5327
5605
|
if (opts?.format === "json") {
|
|
@@ -5379,7 +5657,7 @@ async function triggerRunAll(opts) {
|
|
|
5379
5657
|
}
|
|
5380
5658
|
}
|
|
5381
5659
|
async function cancelRun(project, runId, format) {
|
|
5382
|
-
const client =
|
|
5660
|
+
const client = getClient15();
|
|
5383
5661
|
let targetId = runId;
|
|
5384
5662
|
if (!targetId) {
|
|
5385
5663
|
const runs2 = await client.listRuns(project);
|
|
@@ -5411,7 +5689,7 @@ To cancel by ID : canonry run cancel ${project} <run-id>`,
|
|
|
5411
5689
|
console.log(`Run ${result.id} cancelled.`);
|
|
5412
5690
|
}
|
|
5413
5691
|
async function showRun(id, format) {
|
|
5414
|
-
const client =
|
|
5692
|
+
const client = getClient15();
|
|
5415
5693
|
const run = await client.getRun(id);
|
|
5416
5694
|
if (format === "json") {
|
|
5417
5695
|
console.log(JSON.stringify(run, null, 2));
|
|
@@ -5420,7 +5698,7 @@ async function showRun(id, format) {
|
|
|
5420
5698
|
printRunDetail(run);
|
|
5421
5699
|
}
|
|
5422
5700
|
async function listRuns(project, opts) {
|
|
5423
|
-
const client =
|
|
5701
|
+
const client = getClient15();
|
|
5424
5702
|
const runs2 = await client.listRuns(project, opts?.limit);
|
|
5425
5703
|
if (opts?.format === "json") {
|
|
5426
5704
|
console.log(JSON.stringify(runs2, null, 2));
|
|
@@ -5473,11 +5751,12 @@ function printRunDetail(run) {
|
|
|
5473
5751
|
}
|
|
5474
5752
|
if (run.snapshots && run.snapshots.length > 0) {
|
|
5475
5753
|
console.log(`
|
|
5476
|
-
Snapshots: ${run.snapshots.length}`);
|
|
5754
|
+
Snapshots: ${run.snapshots.length} (cell = [citation][mention]; C=cited c=not, M=mentioned m=not, \u2013=no data)`);
|
|
5477
5755
|
for (const s of run.snapshots) {
|
|
5478
|
-
const
|
|
5756
|
+
const citationGlyph = s.citationState === CitationStates.cited ? "C" : "c";
|
|
5757
|
+
const mentionGlyph = typeof s.answerMentioned === "boolean" ? s.answerMentioned ? "M" : "m" : "\u2013";
|
|
5479
5758
|
const modelLabel = s.model ? ` (${s.model})` : "";
|
|
5480
|
-
console.log(` ${
|
|
5759
|
+
console.log(` [${citationGlyph}${mentionGlyph}] ${s.provider}${modelLabel} ${s.query}`);
|
|
5481
5760
|
}
|
|
5482
5761
|
}
|
|
5483
5762
|
}
|
|
@@ -5572,11 +5851,11 @@ var RUN_CLI_COMMANDS = [
|
|
|
5572
5851
|
];
|
|
5573
5852
|
|
|
5574
5853
|
// src/commands/schedule.ts
|
|
5575
|
-
function
|
|
5854
|
+
function getClient16() {
|
|
5576
5855
|
return createApiClient();
|
|
5577
5856
|
}
|
|
5578
5857
|
async function setSchedule(project, opts) {
|
|
5579
|
-
const client =
|
|
5858
|
+
const client = getClient16();
|
|
5580
5859
|
const body = {};
|
|
5581
5860
|
if (opts.preset) body.preset = opts.preset;
|
|
5582
5861
|
if (opts.cron) body.cron = opts.cron;
|
|
@@ -5591,7 +5870,7 @@ async function setSchedule(project, opts) {
|
|
|
5591
5870
|
printSchedule(result);
|
|
5592
5871
|
}
|
|
5593
5872
|
async function showSchedule(project, format) {
|
|
5594
|
-
const client =
|
|
5873
|
+
const client = getClient16();
|
|
5595
5874
|
const result = await client.getSchedule(project);
|
|
5596
5875
|
if (format === "json") {
|
|
5597
5876
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -5600,7 +5879,7 @@ async function showSchedule(project, format) {
|
|
|
5600
5879
|
printSchedule(result);
|
|
5601
5880
|
}
|
|
5602
5881
|
async function enableSchedule(project, format) {
|
|
5603
|
-
const client =
|
|
5882
|
+
const client = getClient16();
|
|
5604
5883
|
const current = await client.getSchedule(project);
|
|
5605
5884
|
const body = { timezone: current.timezone, enabled: true };
|
|
5606
5885
|
if (current.preset) body.preset = current.preset;
|
|
@@ -5614,7 +5893,7 @@ async function enableSchedule(project, format) {
|
|
|
5614
5893
|
console.log(`Schedule enabled for "${project}"`);
|
|
5615
5894
|
}
|
|
5616
5895
|
async function disableSchedule(project, format) {
|
|
5617
|
-
const client =
|
|
5896
|
+
const client = getClient16();
|
|
5618
5897
|
const current = await client.getSchedule(project);
|
|
5619
5898
|
const body = { timezone: current.timezone, enabled: false };
|
|
5620
5899
|
if (current.preset) body.preset = current.preset;
|
|
@@ -5628,7 +5907,7 @@ async function disableSchedule(project, format) {
|
|
|
5628
5907
|
console.log(`Schedule disabled for "${project}"`);
|
|
5629
5908
|
}
|
|
5630
5909
|
async function removeSchedule(project, format) {
|
|
5631
|
-
const client =
|
|
5910
|
+
const client = getClient16();
|
|
5632
5911
|
await client.deleteSchedule(project);
|
|
5633
5912
|
if (format === "json") {
|
|
5634
5913
|
console.log(JSON.stringify({ project, removed: true }, null, 2));
|
|
@@ -5735,11 +6014,11 @@ var SCHEDULE_CLI_COMMANDS = [
|
|
|
5735
6014
|
];
|
|
5736
6015
|
|
|
5737
6016
|
// src/commands/settings.ts
|
|
5738
|
-
function
|
|
6017
|
+
function getClient17() {
|
|
5739
6018
|
return createApiClient();
|
|
5740
6019
|
}
|
|
5741
6020
|
async function setProvider(name, opts) {
|
|
5742
|
-
const client =
|
|
6021
|
+
const client = getClient17();
|
|
5743
6022
|
const { format, ...payload } = opts;
|
|
5744
6023
|
const result = await client.updateProvider(name, payload);
|
|
5745
6024
|
if (format === "json") {
|
|
@@ -5755,7 +6034,7 @@ async function setProvider(name, opts) {
|
|
|
5755
6034
|
}
|
|
5756
6035
|
}
|
|
5757
6036
|
async function showSettings(format) {
|
|
5758
|
-
const client =
|
|
6037
|
+
const client = getClient17();
|
|
5759
6038
|
const config = loadConfig();
|
|
5760
6039
|
const settings = await client.getSettings();
|
|
5761
6040
|
if (format === "json") {
|
|
@@ -5927,7 +6206,7 @@ Usage: canonry settings provider ${name} --api-key <key> [--model <model>] [--ma
|
|
|
5927
6206
|
];
|
|
5928
6207
|
|
|
5929
6208
|
// src/commands/skills.ts
|
|
5930
|
-
import
|
|
6209
|
+
import fs6 from "fs";
|
|
5931
6210
|
import path4 from "path";
|
|
5932
6211
|
import { fileURLToPath } from "url";
|
|
5933
6212
|
var BUNDLED_SKILL_NAMES = ["canonry-setup", "aero"];
|
|
@@ -5939,7 +6218,7 @@ function resolveBundledSkillsRoot(pkgDir) {
|
|
|
5939
6218
|
path4.join(here, "../../../../skills")
|
|
5940
6219
|
];
|
|
5941
6220
|
for (const candidate of candidates) {
|
|
5942
|
-
if (BUNDLED_SKILL_NAMES.every((name) =>
|
|
6221
|
+
if (BUNDLED_SKILL_NAMES.every((name) => fs6.existsSync(path4.join(candidate, name, "SKILL.md")))) {
|
|
5943
6222
|
return candidate;
|
|
5944
6223
|
}
|
|
5945
6224
|
}
|
|
@@ -5962,13 +6241,13 @@ function getBundledSkills(pkgDir) {
|
|
|
5962
6241
|
return BUNDLED_SKILL_NAMES.map((name) => {
|
|
5963
6242
|
const skillDir = path4.join(root, name);
|
|
5964
6243
|
const skillFile = path4.join(skillDir, "SKILL.md");
|
|
5965
|
-
const content =
|
|
6244
|
+
const content = fs6.readFileSync(skillFile, "utf-8");
|
|
5966
6245
|
return { name, description: parseDescription(content), bundledPath: skillDir };
|
|
5967
6246
|
});
|
|
5968
6247
|
}
|
|
5969
6248
|
function walkRelative(dir, prefix = "") {
|
|
5970
6249
|
const out = [];
|
|
5971
|
-
for (const entry of
|
|
6250
|
+
for (const entry of fs6.readdirSync(dir, { withFileTypes: true })) {
|
|
5972
6251
|
const rel = prefix ? path4.join(prefix, entry.name) : entry.name;
|
|
5973
6252
|
const full = path4.join(dir, entry.name);
|
|
5974
6253
|
if (entry.isDirectory()) {
|
|
@@ -5980,28 +6259,28 @@ function walkRelative(dir, prefix = "") {
|
|
|
5980
6259
|
return out.sort();
|
|
5981
6260
|
}
|
|
5982
6261
|
function compareDirContent(srcDir, destDir) {
|
|
5983
|
-
if (!
|
|
5984
|
-
if (!
|
|
6262
|
+
if (!fs6.existsSync(destDir)) return "missing";
|
|
6263
|
+
if (!fs6.statSync(destDir).isDirectory()) return "different";
|
|
5985
6264
|
const srcFiles = walkRelative(srcDir);
|
|
5986
6265
|
const destFiles = walkRelative(destDir);
|
|
5987
6266
|
if (srcFiles.length !== destFiles.length) return "different";
|
|
5988
6267
|
for (let i = 0; i < srcFiles.length; i++) {
|
|
5989
6268
|
if (srcFiles[i] !== destFiles[i]) return "different";
|
|
5990
|
-
const srcBytes =
|
|
5991
|
-
const destBytes =
|
|
6269
|
+
const srcBytes = fs6.readFileSync(path4.join(srcDir, srcFiles[i]));
|
|
6270
|
+
const destBytes = fs6.readFileSync(path4.join(destDir, destFiles[i]));
|
|
5992
6271
|
if (!srcBytes.equals(destBytes)) return "different";
|
|
5993
6272
|
}
|
|
5994
6273
|
return "match";
|
|
5995
6274
|
}
|
|
5996
6275
|
function copyDirRecursive(src, dest) {
|
|
5997
|
-
|
|
5998
|
-
for (const entry of
|
|
6276
|
+
fs6.mkdirSync(dest, { recursive: true });
|
|
6277
|
+
for (const entry of fs6.readdirSync(src, { withFileTypes: true })) {
|
|
5999
6278
|
const srcPath = path4.join(src, entry.name);
|
|
6000
6279
|
const destPath = path4.join(dest, entry.name);
|
|
6001
6280
|
if (entry.isDirectory()) {
|
|
6002
6281
|
copyDirRecursive(srcPath, destPath);
|
|
6003
6282
|
} else if (entry.isFile()) {
|
|
6004
|
-
|
|
6283
|
+
fs6.copyFileSync(srcPath, destPath);
|
|
6005
6284
|
}
|
|
6006
6285
|
}
|
|
6007
6286
|
}
|
|
@@ -6026,7 +6305,7 @@ function installClaudeSkill(skill, targetDir, force) {
|
|
|
6026
6305
|
});
|
|
6027
6306
|
}
|
|
6028
6307
|
if (compare === "different") {
|
|
6029
|
-
|
|
6308
|
+
fs6.rmSync(targetPath, { recursive: true, force: true });
|
|
6030
6309
|
}
|
|
6031
6310
|
copyDirRecursive(skill.bundledPath, targetPath);
|
|
6032
6311
|
return {
|
|
@@ -6041,15 +6320,15 @@ function installCodexSymlink(skill, targetDir, force) {
|
|
|
6041
6320
|
const codexPath = path4.join(targetDir, ".codex", "skills", skill.name);
|
|
6042
6321
|
const claudePath = path4.join(targetDir, ".claude", "skills", skill.name);
|
|
6043
6322
|
const linkTarget = path4.relative(path4.dirname(codexPath), claudePath);
|
|
6044
|
-
|
|
6323
|
+
fs6.mkdirSync(path4.dirname(codexPath), { recursive: true });
|
|
6045
6324
|
let stat;
|
|
6046
6325
|
try {
|
|
6047
|
-
stat =
|
|
6326
|
+
stat = fs6.lstatSync(codexPath);
|
|
6048
6327
|
} catch {
|
|
6049
6328
|
stat = void 0;
|
|
6050
6329
|
}
|
|
6051
6330
|
if (stat?.isSymbolicLink()) {
|
|
6052
|
-
const existing =
|
|
6331
|
+
const existing = fs6.readlinkSync(codexPath);
|
|
6053
6332
|
if (existing === linkTarget) {
|
|
6054
6333
|
return {
|
|
6055
6334
|
skill: skill.name,
|
|
@@ -6067,8 +6346,8 @@ function installCodexSymlink(skill, targetDir, force) {
|
|
|
6067
6346
|
exitCode: 1
|
|
6068
6347
|
});
|
|
6069
6348
|
}
|
|
6070
|
-
|
|
6071
|
-
|
|
6349
|
+
fs6.unlinkSync(codexPath);
|
|
6350
|
+
fs6.symlinkSync(linkTarget, codexPath);
|
|
6072
6351
|
return {
|
|
6073
6352
|
skill: skill.name,
|
|
6074
6353
|
client: CodingAgents.codex,
|
|
@@ -6086,9 +6365,9 @@ function installCodexSymlink(skill, targetDir, force) {
|
|
|
6086
6365
|
exitCode: 1
|
|
6087
6366
|
});
|
|
6088
6367
|
}
|
|
6089
|
-
|
|
6368
|
+
fs6.rmSync(codexPath, { recursive: true, force: true });
|
|
6090
6369
|
}
|
|
6091
|
-
|
|
6370
|
+
fs6.symlinkSync(linkTarget, codexPath);
|
|
6092
6371
|
return {
|
|
6093
6372
|
skill: skill.name,
|
|
6094
6373
|
client: CodingAgents.codex,
|
|
@@ -6120,7 +6399,7 @@ async function installSkills(opts = {}) {
|
|
|
6120
6399
|
});
|
|
6121
6400
|
}
|
|
6122
6401
|
const skillsToInstall = allSkills.filter((s) => requestedNames.includes(s.name));
|
|
6123
|
-
|
|
6402
|
+
fs6.mkdirSync(targetDir, { recursive: true });
|
|
6124
6403
|
const results = [];
|
|
6125
6404
|
for (const skill of skillsToInstall) {
|
|
6126
6405
|
results.push(installClaudeSkill(skill, targetDir, force));
|
|
@@ -6221,11 +6500,11 @@ var SKILLS_CLI_COMMANDS = [
|
|
|
6221
6500
|
];
|
|
6222
6501
|
|
|
6223
6502
|
// src/commands/snapshot.ts
|
|
6224
|
-
import
|
|
6503
|
+
import fs8 from "fs";
|
|
6225
6504
|
import path6 from "path";
|
|
6226
6505
|
|
|
6227
6506
|
// src/snapshot-pdf.ts
|
|
6228
|
-
import
|
|
6507
|
+
import fs7 from "fs";
|
|
6229
6508
|
import path5 from "path";
|
|
6230
6509
|
import { PDFDocument, StandardFonts, rgb } from "pdf-lib";
|
|
6231
6510
|
var PAGE_WIDTH = 612;
|
|
@@ -6436,8 +6715,8 @@ async function writeSnapshotPdf(report, outputPath) {
|
|
|
6436
6715
|
renderQueries(pdf, report);
|
|
6437
6716
|
const bytes = await doc.save();
|
|
6438
6717
|
const resolvedPath = path5.resolve(outputPath);
|
|
6439
|
-
|
|
6440
|
-
|
|
6718
|
+
fs7.mkdirSync(path5.dirname(resolvedPath), { recursive: true });
|
|
6719
|
+
fs7.writeFileSync(resolvedPath, bytes);
|
|
6441
6720
|
return resolvedPath;
|
|
6442
6721
|
}
|
|
6443
6722
|
function renderCover(pdf, report) {
|
|
@@ -6453,7 +6732,7 @@ function renderCover(pdf, report) {
|
|
|
6453
6732
|
minute: "2-digit"
|
|
6454
6733
|
}));
|
|
6455
6734
|
pdf.keyValue("AEO Audit", `${report.audit.overallScore}/100 (${report.audit.overallGrade})`);
|
|
6456
|
-
pdf.keyValue("Visibility Gap", report.summary.visibilityGap);
|
|
6735
|
+
pdf.keyValue("Visibility Gap (Citations + Mentions)", report.summary.visibilityGap);
|
|
6457
6736
|
pdf.paragraph(report.profile.summary, { size: 11, color: INK, lineHeight: 16 });
|
|
6458
6737
|
pdf.rule();
|
|
6459
6738
|
}
|
|
@@ -6500,9 +6779,9 @@ function renderCompetitors(pdf, report) {
|
|
|
6500
6779
|
}
|
|
6501
6780
|
function renderQueries(pdf, report) {
|
|
6502
6781
|
pdf.heading("Provider Comparison");
|
|
6503
|
-
for (const
|
|
6504
|
-
pdf.subheading(query
|
|
6505
|
-
for (const result of
|
|
6782
|
+
for (const queryResult of report.queryResults) {
|
|
6783
|
+
pdf.subheading(queryResult.query, 11);
|
|
6784
|
+
for (const result of queryResult.providerResults) {
|
|
6506
6785
|
const status = result.error ? "error" : result.mentioned ? result.cited ? "mentioned and cited" : "mentioned" : "not mentioned";
|
|
6507
6786
|
const accuracy = result.describedAccurately === "not-mentioned" ? "" : `; accuracy: ${result.describedAccurately}`;
|
|
6508
6787
|
const competitors2 = result.recommendedCompetitors.length > 0 ? `; recommended instead: ${result.recommendedCompetitors.join(", ")}` : "";
|
|
@@ -6552,7 +6831,7 @@ function wrapText(font, text, size, maxWidth) {
|
|
|
6552
6831
|
}
|
|
6553
6832
|
|
|
6554
6833
|
// src/commands/snapshot.ts
|
|
6555
|
-
function
|
|
6834
|
+
function getClient18() {
|
|
6556
6835
|
return createApiClient();
|
|
6557
6836
|
}
|
|
6558
6837
|
function slugify(value) {
|
|
@@ -6563,11 +6842,11 @@ function autoOutputPath(companyName, ext) {
|
|
|
6563
6842
|
return `${slugify(companyName)}-snapshot-${date}.${ext}`;
|
|
6564
6843
|
}
|
|
6565
6844
|
async function createSnapshotReport(companyName, opts) {
|
|
6566
|
-
const client =
|
|
6845
|
+
const client = getClient18();
|
|
6567
6846
|
const report = await client.createSnapshot({
|
|
6568
6847
|
companyName,
|
|
6569
6848
|
domain: opts.domain,
|
|
6570
|
-
...opts.
|
|
6849
|
+
...opts.queries && opts.queries.length > 0 ? { queries: opts.queries } : {},
|
|
6571
6850
|
...opts.competitors && opts.competitors.length > 0 ? { competitors: opts.competitors } : {}
|
|
6572
6851
|
});
|
|
6573
6852
|
let savedMdPath;
|
|
@@ -6596,8 +6875,8 @@ PDF saved: ${savedPdfPath}`);
|
|
|
6596
6875
|
}
|
|
6597
6876
|
function writeSnapshotMarkdown(report, outputPath) {
|
|
6598
6877
|
const resolvedPath = path6.resolve(outputPath);
|
|
6599
|
-
|
|
6600
|
-
|
|
6878
|
+
fs8.mkdirSync(path6.dirname(resolvedPath), { recursive: true });
|
|
6879
|
+
fs8.writeFileSync(resolvedPath, formatSnapshotMarkdown(report), "utf-8");
|
|
6601
6880
|
return resolvedPath;
|
|
6602
6881
|
}
|
|
6603
6882
|
function formatSnapshotMarkdown(report) {
|
|
@@ -6608,7 +6887,7 @@ function formatSnapshotMarkdown(report) {
|
|
|
6608
6887
|
lines.push(`**Generated:** ${new Date(report.generatedAt).toLocaleString("en-US", { year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "2-digit" })}`);
|
|
6609
6888
|
lines.push(`**AEO Audit Score:** ${report.audit.overallScore}/100 (${report.audit.overallGrade})`);
|
|
6610
6889
|
lines.push("");
|
|
6611
|
-
lines.push("## Visibility Gap");
|
|
6890
|
+
lines.push("## Visibility Gap (Citations + Mentions)");
|
|
6612
6891
|
lines.push("");
|
|
6613
6892
|
lines.push(report.summary.visibilityGap);
|
|
6614
6893
|
lines.push("");
|
|
@@ -6640,12 +6919,12 @@ function formatSnapshotMarkdown(report) {
|
|
|
6640
6919
|
}
|
|
6641
6920
|
lines.push("## Provider Comparison");
|
|
6642
6921
|
lines.push("");
|
|
6643
|
-
for (const
|
|
6644
|
-
lines.push(`### "${query
|
|
6922
|
+
for (const queryResult of report.queryResults) {
|
|
6923
|
+
lines.push(`### "${queryResult.query}"`);
|
|
6645
6924
|
lines.push("");
|
|
6646
6925
|
lines.push("| Provider | Mentioned | Cited | Accuracy | Competitors Recommended |");
|
|
6647
6926
|
lines.push("|----------|-----------|-------|----------|------------------------|");
|
|
6648
|
-
for (const result of
|
|
6927
|
+
for (const result of queryResult.providerResults) {
|
|
6649
6928
|
if (result.error) {
|
|
6650
6929
|
lines.push(`| ${result.displayName} | ERROR | - | - | ${result.error} |`);
|
|
6651
6930
|
continue;
|
|
@@ -6696,11 +6975,11 @@ function formatSnapshotText(report) {
|
|
|
6696
6975
|
}
|
|
6697
6976
|
const providerWidth = Math.max(
|
|
6698
6977
|
8,
|
|
6699
|
-
...report.queryResults.flatMap((
|
|
6978
|
+
...report.queryResults.flatMap((queryResult) => queryResult.providerResults.map((result) => result.displayName.length))
|
|
6700
6979
|
);
|
|
6701
|
-
for (const
|
|
6702
|
-
lines.push(`"${query
|
|
6703
|
-
for (const result of
|
|
6980
|
+
for (const queryResult of report.queryResults) {
|
|
6981
|
+
lines.push(`"${queryResult.query}"`);
|
|
6982
|
+
for (const result of queryResult.providerResults) {
|
|
6704
6983
|
lines.push(` ${result.displayName.padEnd(providerWidth)} ${formatProviderLine(result)}`);
|
|
6705
6984
|
}
|
|
6706
6985
|
lines.push("");
|
|
@@ -6741,9 +7020,10 @@ function parseCsvOption(value) {
|
|
|
6741
7020
|
var SNAPSHOT_CLI_COMMANDS = [
|
|
6742
7021
|
{
|
|
6743
7022
|
path: ["snapshot"],
|
|
6744
|
-
usage: 'canonry snapshot <company-name> --domain <domain> [--phrases "a,b"] [--competitors "x,y"] [--md] [--output <path>] [--pdf] [--format table|json]',
|
|
7023
|
+
usage: 'canonry snapshot <company-name> --domain <domain> [--queries "a,b"] [--phrases "a,b" (legacy alias)] [--competitors "x,y"] [--md] [--output <path>] [--pdf] [--format table|json]',
|
|
6745
7024
|
options: {
|
|
6746
7025
|
domain: stringOption(),
|
|
7026
|
+
queries: stringOption(),
|
|
6747
7027
|
phrases: stringOption(),
|
|
6748
7028
|
competitors: stringOption(),
|
|
6749
7029
|
md: { type: "boolean" },
|
|
@@ -6751,7 +7031,7 @@ var SNAPSHOT_CLI_COMMANDS = [
|
|
|
6751
7031
|
output: stringOption()
|
|
6752
7032
|
},
|
|
6753
7033
|
run: async (input) => {
|
|
6754
|
-
const usage = 'canonry snapshot <company-name> --domain <domain> [--phrases "a,b"] [--competitors "x,y"] [--md] [--output <path>] [--pdf] [--format table|json]';
|
|
7034
|
+
const usage = 'canonry snapshot <company-name> --domain <domain> [--queries "a,b"] [--phrases "a,b" (legacy alias)] [--competitors "x,y"] [--md] [--output <path>] [--pdf] [--format table|json]';
|
|
6755
7035
|
const companyName = requirePositional(input, 0, {
|
|
6756
7036
|
command: "snapshot",
|
|
6757
7037
|
usage,
|
|
@@ -6768,7 +7048,7 @@ var SNAPSHOT_CLI_COMMANDS = [
|
|
|
6768
7048
|
const wantsMd = explicitMd || !!outputPath && !wantsPdf;
|
|
6769
7049
|
await createSnapshotReport(companyName, {
|
|
6770
7050
|
domain,
|
|
6771
|
-
|
|
7051
|
+
queries: parseCsvOption(getString(input.values, "queries") ?? getString(input.values, "phrases")),
|
|
6772
7052
|
competitors: parseCsvOption(getString(input.values, "competitors")),
|
|
6773
7053
|
md: wantsMd,
|
|
6774
7054
|
pdf: wantsPdf,
|
|
@@ -6867,7 +7147,7 @@ async function showOverview(project, opts) {
|
|
|
6867
7147
|
console.log(JSON.stringify(overview, null, 2));
|
|
6868
7148
|
return;
|
|
6869
7149
|
}
|
|
6870
|
-
const { project: meta, latestRun, health, topInsights,
|
|
7150
|
+
const { project: meta, latestRun, health, topInsights, queryCounts, providers, transitions } = overview;
|
|
6871
7151
|
console.log(`Overview: ${meta.displayName ?? meta.name} (${meta.name})
|
|
6872
7152
|
`);
|
|
6873
7153
|
console.log(` Domain: ${meta.canonicalDomain}`);
|
|
@@ -6882,7 +7162,7 @@ async function showOverview(project, opts) {
|
|
|
6882
7162
|
console.log("\n No runs yet.");
|
|
6883
7163
|
}
|
|
6884
7164
|
console.log(`
|
|
6885
|
-
|
|
7165
|
+
Queries cited: ${queryCounts.citedQueries}/${queryCounts.totalQueries} (${pct(queryCounts.citedRate)})`);
|
|
6886
7166
|
if (providers.length > 0) {
|
|
6887
7167
|
console.log(" Providers:");
|
|
6888
7168
|
for (const p of providers) {
|
|
@@ -6924,14 +7204,14 @@ async function searchProject(project, opts) {
|
|
|
6924
7204
|
}
|
|
6925
7205
|
for (const hit of result.hits) {
|
|
6926
7206
|
if (hit.kind === "snapshot") {
|
|
6927
|
-
console.log(` [snapshot] ${hit.
|
|
7207
|
+
console.log(` [snapshot] ${hit.query} (${hit.provider}, ${hit.citationState}) \u2014 ${hit.matchedField}`);
|
|
6928
7208
|
console.log(` ${hit.snippet}`);
|
|
6929
7209
|
console.log(` run=${hit.runId} at ${hit.createdAt}`);
|
|
6930
7210
|
} else {
|
|
6931
7211
|
const dismissed = hit.dismissed ? " [dismissed]" : "";
|
|
6932
7212
|
console.log(` [insight ${hit.severity.toUpperCase()}] ${hit.type} \u2014 ${hit.title}${dismissed}`);
|
|
6933
7213
|
console.log(` ${hit.snippet}`);
|
|
6934
|
-
console.log(`
|
|
7214
|
+
console.log(` query=${hit.query} at ${hit.createdAt}`);
|
|
6935
7215
|
}
|
|
6936
7216
|
console.log("");
|
|
6937
7217
|
}
|
|
@@ -6946,8 +7226,8 @@ async function showCitationVisibility(project, opts) {
|
|
|
6946
7226
|
return;
|
|
6947
7227
|
}
|
|
6948
7228
|
if (data.status === "no-data") {
|
|
6949
|
-
if (data.reason === "no-
|
|
6950
|
-
console.log("No
|
|
7229
|
+
if (data.reason === "no-queries") {
|
|
7230
|
+
console.log("No queries configured. Add some with `canonry query add`.");
|
|
6951
7231
|
} else {
|
|
6952
7232
|
console.log("No citation data yet \u2014 run a sweep first (canonry run <project>).");
|
|
6953
7233
|
}
|
|
@@ -6966,49 +7246,49 @@ function printSummary(data) {
|
|
|
6966
7246
|
providersCiting,
|
|
6967
7247
|
providersMentioning,
|
|
6968
7248
|
providersConfigured,
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
7249
|
+
totalQueries,
|
|
7250
|
+
queriesCitedAndMentioned,
|
|
7251
|
+
queriesCitedOnly,
|
|
7252
|
+
queriesMentionedOnly,
|
|
7253
|
+
queriesInvisible
|
|
6974
7254
|
} = data.summary;
|
|
6975
|
-
console.log("
|
|
7255
|
+
console.log("AEO visibility (citations + mentions)");
|
|
6976
7256
|
if (data.summary.latestRunAt) {
|
|
6977
7257
|
console.log(`Latest run: ${data.summary.latestRunAt}`);
|
|
6978
7258
|
}
|
|
6979
7259
|
console.log(`Cited in sources: ${providersCiting}/${providersConfigured} engines`);
|
|
6980
7260
|
console.log(`Mentioned in answers: ${providersMentioning}/${providersConfigured} engines`);
|
|
6981
7261
|
console.log("");
|
|
6982
|
-
console.log(`
|
|
6983
|
-
console.log(` cited + mentioned: ${
|
|
6984
|
-
console.log(` cited only: ${
|
|
6985
|
-
console.log(` mentioned only: ${
|
|
6986
|
-
console.log(` invisible: ${
|
|
7262
|
+
console.log(`Queries (${totalQueries} total):`);
|
|
7263
|
+
console.log(` cited + mentioned: ${queriesCitedAndMentioned}`);
|
|
7264
|
+
console.log(` cited only: ${queriesCitedOnly}`);
|
|
7265
|
+
console.log(` mentioned only: ${queriesMentionedOnly}`);
|
|
7266
|
+
console.log(` invisible: ${queriesInvisible}`);
|
|
6987
7267
|
}
|
|
6988
7268
|
function printCoverage(data) {
|
|
6989
|
-
if (data.
|
|
6990
|
-
console.log("No
|
|
7269
|
+
if (data.byQuery.length === 0) {
|
|
7270
|
+
console.log("No query coverage rows.");
|
|
6991
7271
|
return;
|
|
6992
7272
|
}
|
|
6993
7273
|
const providerSet = /* @__PURE__ */ new Set();
|
|
6994
|
-
for (const row of data.
|
|
7274
|
+
for (const row of data.byQuery) {
|
|
6995
7275
|
for (const p of row.providers) providerSet.add(p.provider);
|
|
6996
7276
|
}
|
|
6997
7277
|
const providerColumns = Array.from(providerSet).sort();
|
|
6998
7278
|
if (providerColumns.length === 0) {
|
|
6999
|
-
console.log("Per-
|
|
7000
|
-
for (const row of data.
|
|
7001
|
-
console.log(` ${row.
|
|
7279
|
+
console.log("Per-query coverage:");
|
|
7280
|
+
for (const row of data.byQuery) {
|
|
7281
|
+
console.log(` ${row.query.padEnd(35)} no snapshots`);
|
|
7002
7282
|
}
|
|
7003
7283
|
return;
|
|
7004
7284
|
}
|
|
7005
7285
|
const cellWidth = Math.max(6, ...providerColumns.map((p) => p.length));
|
|
7006
|
-
const
|
|
7007
|
-
const header = ["
|
|
7008
|
-
console.log("Per-
|
|
7286
|
+
const queryWidth = Math.max(7, ...data.byQuery.map((r) => r.query.length));
|
|
7287
|
+
const header = ["Query".padEnd(queryWidth), ...providerColumns.map((p) => p.padEnd(cellWidth)), "Cite", "Ment"].join(" ");
|
|
7288
|
+
console.log("Per-query coverage: (cell = [citation][mention]; C=cited c=not, M=mentioned m=not, \u2013=no data)");
|
|
7009
7289
|
console.log(header);
|
|
7010
7290
|
console.log("\u2500".repeat(header.length));
|
|
7011
|
-
for (const row of data.
|
|
7291
|
+
for (const row of data.byQuery) {
|
|
7012
7292
|
const cells = providerColumns.map((p) => {
|
|
7013
7293
|
const provider = row.providers.find((x) => x.provider === p);
|
|
7014
7294
|
if (!provider) return "\u2013".padEnd(cellWidth);
|
|
@@ -7018,16 +7298,16 @@ function printCoverage(data) {
|
|
|
7018
7298
|
});
|
|
7019
7299
|
const citeCol = `${row.citedCount}/${row.totalProviders}`;
|
|
7020
7300
|
const mentCol = `${row.mentionedCount}/${row.totalProviders}`;
|
|
7021
|
-
console.log([row.
|
|
7301
|
+
console.log([row.query.padEnd(queryWidth), ...cells, citeCol, mentCol].join(" "));
|
|
7022
7302
|
}
|
|
7023
7303
|
}
|
|
7024
7304
|
function printGaps2(data) {
|
|
7025
7305
|
console.log("Competitor gaps (not cited but a competitor is):");
|
|
7026
|
-
const
|
|
7306
|
+
const queryWidth = Math.max(7, ...data.competitorGaps.map((g) => g.query.length));
|
|
7027
7307
|
const providerWidth = Math.max(8, ...data.competitorGaps.map((g) => g.provider.length));
|
|
7028
7308
|
for (const gap of data.competitorGaps) {
|
|
7029
7309
|
console.log(
|
|
7030
|
-
` ${gap.
|
|
7310
|
+
` ${gap.query.padEnd(queryWidth)} ${gap.provider.padEnd(providerWidth)} ${gap.citingCompetitors.join(", ")}`
|
|
7031
7311
|
);
|
|
7032
7312
|
}
|
|
7033
7313
|
}
|
|
@@ -7469,7 +7749,7 @@ async function bootstrapCommand(_opts) {
|
|
|
7469
7749
|
|
|
7470
7750
|
// src/commands/daemon.ts
|
|
7471
7751
|
import { spawn } from "child_process";
|
|
7472
|
-
import
|
|
7752
|
+
import fs9 from "fs";
|
|
7473
7753
|
import path8 from "path";
|
|
7474
7754
|
function getPidPath() {
|
|
7475
7755
|
return path8.join(getConfigDir(), "canonry.pid");
|
|
@@ -7499,8 +7779,8 @@ async function waitForReady(host, port, maxMs = 1e4) {
|
|
|
7499
7779
|
async function startDaemon(opts) {
|
|
7500
7780
|
const pidPath = getPidPath();
|
|
7501
7781
|
const format = opts.format ?? "text";
|
|
7502
|
-
if (
|
|
7503
|
-
const existingPid = parseInt(
|
|
7782
|
+
if (fs9.existsSync(pidPath)) {
|
|
7783
|
+
const existingPid = parseInt(fs9.readFileSync(pidPath, "utf-8").trim(), 10);
|
|
7504
7784
|
if (!isNaN(existingPid) && isProcessAlive(existingPid)) {
|
|
7505
7785
|
throw new CliError({
|
|
7506
7786
|
code: "DAEMON_ALREADY_RUNNING",
|
|
@@ -7511,7 +7791,7 @@ async function startDaemon(opts) {
|
|
|
7511
7791
|
}
|
|
7512
7792
|
});
|
|
7513
7793
|
}
|
|
7514
|
-
|
|
7794
|
+
fs9.unlinkSync(pidPath);
|
|
7515
7795
|
}
|
|
7516
7796
|
const cliPath = path8.resolve(new URL(import.meta.url).pathname);
|
|
7517
7797
|
const inSourceMode = new URL(import.meta.url).pathname.endsWith(".ts");
|
|
@@ -7532,10 +7812,10 @@ async function startDaemon(opts) {
|
|
|
7532
7812
|
});
|
|
7533
7813
|
}
|
|
7534
7814
|
const configDir = getConfigDir();
|
|
7535
|
-
if (!
|
|
7536
|
-
|
|
7815
|
+
if (!fs9.existsSync(configDir)) {
|
|
7816
|
+
fs9.mkdirSync(configDir, { recursive: true });
|
|
7537
7817
|
}
|
|
7538
|
-
|
|
7818
|
+
fs9.writeFileSync(pidPath, String(child.pid), "utf-8");
|
|
7539
7819
|
const port = opts.port ?? "4100";
|
|
7540
7820
|
const host = opts.host ?? "127.0.0.1";
|
|
7541
7821
|
if (format !== "json") {
|
|
@@ -7544,7 +7824,7 @@ async function startDaemon(opts) {
|
|
|
7544
7824
|
const ready = await waitForReady(host, port);
|
|
7545
7825
|
if (!ready) {
|
|
7546
7826
|
try {
|
|
7547
|
-
|
|
7827
|
+
fs9.unlinkSync(pidPath);
|
|
7548
7828
|
} catch {
|
|
7549
7829
|
}
|
|
7550
7830
|
throw new CliError({
|
|
@@ -7576,7 +7856,7 @@ async function startDaemon(opts) {
|
|
|
7576
7856
|
}
|
|
7577
7857
|
function stopDaemon(format = "text") {
|
|
7578
7858
|
const pidPath = getPidPath();
|
|
7579
|
-
if (!
|
|
7859
|
+
if (!fs9.existsSync(pidPath)) {
|
|
7580
7860
|
if (format === "json") {
|
|
7581
7861
|
console.log(JSON.stringify({
|
|
7582
7862
|
stopped: false,
|
|
@@ -7587,7 +7867,7 @@ function stopDaemon(format = "text") {
|
|
|
7587
7867
|
console.log("Canonry is not running (no PID file found)");
|
|
7588
7868
|
return;
|
|
7589
7869
|
}
|
|
7590
|
-
const pid = parseInt(
|
|
7870
|
+
const pid = parseInt(fs9.readFileSync(pidPath, "utf-8").trim(), 10);
|
|
7591
7871
|
if (isNaN(pid)) {
|
|
7592
7872
|
if (format === "json") {
|
|
7593
7873
|
console.log(JSON.stringify({
|
|
@@ -7598,7 +7878,7 @@ function stopDaemon(format = "text") {
|
|
|
7598
7878
|
} else {
|
|
7599
7879
|
console.error("Invalid PID file. Removing it.");
|
|
7600
7880
|
}
|
|
7601
|
-
|
|
7881
|
+
fs9.unlinkSync(pidPath);
|
|
7602
7882
|
return;
|
|
7603
7883
|
}
|
|
7604
7884
|
if (!isProcessAlive(pid)) {
|
|
@@ -7612,12 +7892,12 @@ function stopDaemon(format = "text") {
|
|
|
7612
7892
|
} else {
|
|
7613
7893
|
console.log(`Canonry is not running (stale PID: ${pid}). Cleaning up.`);
|
|
7614
7894
|
}
|
|
7615
|
-
|
|
7895
|
+
fs9.unlinkSync(pidPath);
|
|
7616
7896
|
return;
|
|
7617
7897
|
}
|
|
7618
7898
|
try {
|
|
7619
7899
|
process.kill(pid, "SIGTERM");
|
|
7620
|
-
|
|
7900
|
+
fs9.unlinkSync(pidPath);
|
|
7621
7901
|
if (format === "json") {
|
|
7622
7902
|
console.log(JSON.stringify({
|
|
7623
7903
|
stopped: true,
|
|
@@ -7641,7 +7921,7 @@ function stopDaemon(format = "text") {
|
|
|
7641
7921
|
|
|
7642
7922
|
// src/commands/init.ts
|
|
7643
7923
|
import crypto2 from "crypto";
|
|
7644
|
-
import
|
|
7924
|
+
import fs10 from "fs";
|
|
7645
7925
|
import readline from "readline";
|
|
7646
7926
|
import path9 from "path";
|
|
7647
7927
|
function prompt(question) {
|
|
@@ -7665,7 +7945,7 @@ var PROJECT_MARKERS = [".git", "canonry.yaml", "canonry.yml", "package.json"];
|
|
|
7665
7945
|
function cwdLooksLikeProject(dir) {
|
|
7666
7946
|
const home = process.env.HOME ?? "";
|
|
7667
7947
|
if (home && path9.resolve(dir) === path9.resolve(home)) return false;
|
|
7668
|
-
return PROJECT_MARKERS.some((marker) =>
|
|
7948
|
+
return PROJECT_MARKERS.some((marker) => fs10.existsSync(path9.join(dir, marker)));
|
|
7669
7949
|
}
|
|
7670
7950
|
var DEFAULT_AGENT_MODELS = {
|
|
7671
7951
|
anthropic: "anthropic/claude-sonnet-4-6",
|
|
@@ -7695,8 +7975,8 @@ async function initCommand(opts) {
|
|
|
7695
7975
|
return void 0;
|
|
7696
7976
|
}
|
|
7697
7977
|
const configDir = getConfigDir();
|
|
7698
|
-
if (!
|
|
7699
|
-
|
|
7978
|
+
if (!fs10.existsSync(configDir)) {
|
|
7979
|
+
fs10.mkdirSync(configDir, { recursive: true });
|
|
7700
7980
|
}
|
|
7701
7981
|
const bootstrapEnv = getBootstrapEnv(process.env, {
|
|
7702
7982
|
GEMINI_API_KEY: opts?.geminiKey,
|
|
@@ -8259,10 +8539,10 @@ var SYSTEM_CLI_COMMANDS = [
|
|
|
8259
8539
|
];
|
|
8260
8540
|
|
|
8261
8541
|
// src/cli-commands/wordpress.ts
|
|
8262
|
-
import
|
|
8542
|
+
import fs11 from "fs";
|
|
8263
8543
|
|
|
8264
8544
|
// src/commands/wordpress.ts
|
|
8265
|
-
function
|
|
8545
|
+
function getClient19() {
|
|
8266
8546
|
return createApiClient();
|
|
8267
8547
|
}
|
|
8268
8548
|
function printJson2(value) {
|
|
@@ -8409,7 +8689,7 @@ async function wordpressConnect(project, opts) {
|
|
|
8409
8689
|
details: { project }
|
|
8410
8690
|
});
|
|
8411
8691
|
}
|
|
8412
|
-
const client =
|
|
8692
|
+
const client = getClient19();
|
|
8413
8693
|
const result = await client.wordpressConnect(project, {
|
|
8414
8694
|
url: opts.url,
|
|
8415
8695
|
stagingUrl: opts.stagingUrl,
|
|
@@ -8426,7 +8706,7 @@ async function wordpressConnect(project, opts) {
|
|
|
8426
8706
|
printWordpressStatus(project, result);
|
|
8427
8707
|
}
|
|
8428
8708
|
async function wordpressDisconnect(project, format) {
|
|
8429
|
-
const client =
|
|
8709
|
+
const client = getClient19();
|
|
8430
8710
|
await client.wordpressDisconnect(project);
|
|
8431
8711
|
if (format === "json") {
|
|
8432
8712
|
printJson2({ project, disconnected: true });
|
|
@@ -8435,7 +8715,7 @@ async function wordpressDisconnect(project, format) {
|
|
|
8435
8715
|
console.log(`WordPress disconnected from project "${project}".`);
|
|
8436
8716
|
}
|
|
8437
8717
|
async function wordpressStatus(project, format) {
|
|
8438
|
-
const client =
|
|
8718
|
+
const client = getClient19();
|
|
8439
8719
|
const result = await client.wordpressStatus(project);
|
|
8440
8720
|
if (format === "json") {
|
|
8441
8721
|
printJson2(result);
|
|
@@ -8444,7 +8724,7 @@ async function wordpressStatus(project, format) {
|
|
|
8444
8724
|
printWordpressStatus(project, result);
|
|
8445
8725
|
}
|
|
8446
8726
|
async function wordpressPages(project, opts) {
|
|
8447
|
-
const client =
|
|
8727
|
+
const client = getClient19();
|
|
8448
8728
|
const result = await client.wordpressPages(project, opts.env);
|
|
8449
8729
|
if (opts.format === "json") {
|
|
8450
8730
|
printJson2(result);
|
|
@@ -8453,7 +8733,7 @@ async function wordpressPages(project, opts) {
|
|
|
8453
8733
|
printPages(project, result.env, result.pages);
|
|
8454
8734
|
}
|
|
8455
8735
|
async function wordpressPage(project, slug, opts) {
|
|
8456
|
-
const client =
|
|
8736
|
+
const client = getClient19();
|
|
8457
8737
|
const result = await client.wordpressPage(project, slug, opts.env);
|
|
8458
8738
|
if (opts.format === "json") {
|
|
8459
8739
|
printJson2(result);
|
|
@@ -8462,7 +8742,7 @@ async function wordpressPage(project, slug, opts) {
|
|
|
8462
8742
|
printPageDetail(result);
|
|
8463
8743
|
}
|
|
8464
8744
|
async function wordpressCreatePage(project, body) {
|
|
8465
|
-
const client =
|
|
8745
|
+
const client = getClient19();
|
|
8466
8746
|
const result = await client.wordpressCreatePage(project, body);
|
|
8467
8747
|
if (body.format === "json") {
|
|
8468
8748
|
printJson2(result);
|
|
@@ -8473,7 +8753,7 @@ async function wordpressCreatePage(project, body) {
|
|
|
8473
8753
|
printPageDetail(result);
|
|
8474
8754
|
}
|
|
8475
8755
|
async function wordpressUpdatePage(project, body) {
|
|
8476
|
-
const client =
|
|
8756
|
+
const client = getClient19();
|
|
8477
8757
|
const result = await client.wordpressUpdatePage(project, body);
|
|
8478
8758
|
if (body.format === "json") {
|
|
8479
8759
|
printJson2(result);
|
|
@@ -8484,7 +8764,7 @@ async function wordpressUpdatePage(project, body) {
|
|
|
8484
8764
|
printPageDetail(result);
|
|
8485
8765
|
}
|
|
8486
8766
|
async function wordpressSetMeta(project, body) {
|
|
8487
|
-
const client =
|
|
8767
|
+
const client = getClient19();
|
|
8488
8768
|
const result = await client.wordpressSetMeta(project, body);
|
|
8489
8769
|
if (body.format === "json") {
|
|
8490
8770
|
printJson2(result);
|
|
@@ -8495,12 +8775,12 @@ async function wordpressSetMeta(project, body) {
|
|
|
8495
8775
|
printPageDetail(result);
|
|
8496
8776
|
}
|
|
8497
8777
|
async function wordpressBulkSetMeta(project, opts) {
|
|
8498
|
-
const
|
|
8778
|
+
const fs12 = await import("fs/promises");
|
|
8499
8779
|
const path10 = await import("path");
|
|
8500
8780
|
const filePath = path10.resolve(opts.from);
|
|
8501
8781
|
let raw;
|
|
8502
8782
|
try {
|
|
8503
|
-
raw = await
|
|
8783
|
+
raw = await fs12.readFile(filePath, "utf8");
|
|
8504
8784
|
} catch {
|
|
8505
8785
|
throw new CliError({
|
|
8506
8786
|
code: "FILE_READ_ERROR",
|
|
@@ -8534,7 +8814,7 @@ async function wordpressBulkSetMeta(project, opts) {
|
|
|
8534
8814
|
details: { path: filePath }
|
|
8535
8815
|
});
|
|
8536
8816
|
}
|
|
8537
|
-
const client =
|
|
8817
|
+
const client = getClient19();
|
|
8538
8818
|
const result = await client.wordpressBulkSetMeta(project, { entries, env: opts.env });
|
|
8539
8819
|
if (opts.format === "json") {
|
|
8540
8820
|
printJson2(result);
|
|
@@ -8577,7 +8857,7 @@ async function wordpressBulkSetMeta(project, opts) {
|
|
|
8577
8857
|
Total: ${applied.length} applied, ${skipped.length} skipped, ${manual.length} manual`);
|
|
8578
8858
|
}
|
|
8579
8859
|
async function wordpressSchema(project, slug, opts) {
|
|
8580
|
-
const client =
|
|
8860
|
+
const client = getClient19();
|
|
8581
8861
|
const result = await client.wordpressSchema(project, slug, opts.env);
|
|
8582
8862
|
if (opts.format === "json") {
|
|
8583
8863
|
printJson2(result);
|
|
@@ -8588,7 +8868,7 @@ async function wordpressSchema(project, slug, opts) {
|
|
|
8588
8868
|
printSchemaBlocks(result.blocks);
|
|
8589
8869
|
}
|
|
8590
8870
|
async function wordpressSetSchema(project, body) {
|
|
8591
|
-
const client =
|
|
8871
|
+
const client = getClient19();
|
|
8592
8872
|
const result = await client.wordpressSetSchema(project, body);
|
|
8593
8873
|
if (body.format === "json") {
|
|
8594
8874
|
printJson2(result);
|
|
@@ -8597,13 +8877,13 @@ async function wordpressSetSchema(project, body) {
|
|
|
8597
8877
|
printManualAssist(`Schema update for "${body.slug}"`, result);
|
|
8598
8878
|
}
|
|
8599
8879
|
async function wordpressSchemaDeploy(project, opts) {
|
|
8600
|
-
const
|
|
8880
|
+
const fs12 = await import("fs/promises");
|
|
8601
8881
|
const path10 = await import("path");
|
|
8602
8882
|
const yaml = await import("yaml").catch(() => null);
|
|
8603
8883
|
const filePath = path10.resolve(opts.profile);
|
|
8604
8884
|
let raw;
|
|
8605
8885
|
try {
|
|
8606
|
-
raw = await
|
|
8886
|
+
raw = await fs12.readFile(filePath, "utf8");
|
|
8607
8887
|
} catch {
|
|
8608
8888
|
throw new CliError({
|
|
8609
8889
|
code: "FILE_READ_ERROR",
|
|
@@ -8636,7 +8916,7 @@ async function wordpressSchemaDeploy(project, opts) {
|
|
|
8636
8916
|
details: { path: filePath }
|
|
8637
8917
|
});
|
|
8638
8918
|
}
|
|
8639
|
-
const client =
|
|
8919
|
+
const client = getClient19();
|
|
8640
8920
|
const result = await client.wordpressSchemaDeploy(project, { profile: parsed, env: opts.env });
|
|
8641
8921
|
if (opts.format === "json") {
|
|
8642
8922
|
printJson2(result);
|
|
@@ -8675,7 +8955,7 @@ async function wordpressSchemaDeploy(project, opts) {
|
|
|
8675
8955
|
Total: ${deployed} deployed, ${stripped} stripped, ${skipped} skipped, ${failed} failed`);
|
|
8676
8956
|
}
|
|
8677
8957
|
async function wordpressSchemaStatus(project, opts) {
|
|
8678
|
-
const client =
|
|
8958
|
+
const client = getClient19();
|
|
8679
8959
|
const result = await client.wordpressSchemaStatus(project, opts.env);
|
|
8680
8960
|
if (opts.format === "json") {
|
|
8681
8961
|
printJson2(result);
|
|
@@ -8708,13 +8988,13 @@ async function wordpressOnboard(project, opts) {
|
|
|
8708
8988
|
}
|
|
8709
8989
|
let profileData;
|
|
8710
8990
|
if (opts.profile) {
|
|
8711
|
-
const
|
|
8991
|
+
const fs12 = await import("fs/promises");
|
|
8712
8992
|
const path10 = await import("path");
|
|
8713
8993
|
const yaml = await import("yaml").catch(() => null);
|
|
8714
8994
|
const filePath = path10.resolve(opts.profile);
|
|
8715
8995
|
let raw;
|
|
8716
8996
|
try {
|
|
8717
|
-
raw = await
|
|
8997
|
+
raw = await fs12.readFile(filePath, "utf8");
|
|
8718
8998
|
} catch {
|
|
8719
8999
|
throw new CliError({
|
|
8720
9000
|
code: "FILE_READ_ERROR",
|
|
@@ -8734,7 +9014,7 @@ async function wordpressOnboard(project, opts) {
|
|
|
8734
9014
|
});
|
|
8735
9015
|
}
|
|
8736
9016
|
}
|
|
8737
|
-
const client =
|
|
9017
|
+
const client = getClient19();
|
|
8738
9018
|
const result = await client.wordpressOnboard(project, {
|
|
8739
9019
|
url: opts.url,
|
|
8740
9020
|
username: opts.user,
|
|
@@ -8759,7 +9039,7 @@ async function wordpressOnboard(project, opts) {
|
|
|
8759
9039
|
}
|
|
8760
9040
|
}
|
|
8761
9041
|
async function wordpressLlmsTxt(project, opts) {
|
|
8762
|
-
const client =
|
|
9042
|
+
const client = getClient19();
|
|
8763
9043
|
const result = await client.wordpressLlmsTxt(project, opts.env);
|
|
8764
9044
|
if (opts.format === "json") {
|
|
8765
9045
|
printJson2(result);
|
|
@@ -8770,7 +9050,7 @@ async function wordpressLlmsTxt(project, opts) {
|
|
|
8770
9050
|
console.log(result.content ?? "(not found)");
|
|
8771
9051
|
}
|
|
8772
9052
|
async function wordpressSetLlmsTxt(project, body) {
|
|
8773
|
-
const client =
|
|
9053
|
+
const client = getClient19();
|
|
8774
9054
|
const result = await client.wordpressSetLlmsTxt(project, body);
|
|
8775
9055
|
if (body.format === "json") {
|
|
8776
9056
|
printJson2(result);
|
|
@@ -8779,7 +9059,7 @@ async function wordpressSetLlmsTxt(project, body) {
|
|
|
8779
9059
|
printManualAssist(`llms.txt update for "${project}"`, result);
|
|
8780
9060
|
}
|
|
8781
9061
|
async function wordpressAudit(project, opts) {
|
|
8782
|
-
const client =
|
|
9062
|
+
const client = getClient19();
|
|
8783
9063
|
const result = await client.wordpressAudit(project, opts.env);
|
|
8784
9064
|
if (opts.format === "json") {
|
|
8785
9065
|
printJson2(result);
|
|
@@ -8793,7 +9073,7 @@ async function wordpressAudit(project, opts) {
|
|
|
8793
9073
|
printAuditIssues(result.issues);
|
|
8794
9074
|
}
|
|
8795
9075
|
async function wordpressDiff(project, slug, format) {
|
|
8796
|
-
const client =
|
|
9076
|
+
const client = getClient19();
|
|
8797
9077
|
const result = await client.wordpressDiff(project, slug);
|
|
8798
9078
|
if (format === "json") {
|
|
8799
9079
|
printJson2(result);
|
|
@@ -8802,7 +9082,7 @@ async function wordpressDiff(project, slug, format) {
|
|
|
8802
9082
|
printDiff(result);
|
|
8803
9083
|
}
|
|
8804
9084
|
async function wordpressStagingStatus(project, format) {
|
|
8805
|
-
const client =
|
|
9085
|
+
const client = getClient19();
|
|
8806
9086
|
const result = await client.wordpressStagingStatus(project);
|
|
8807
9087
|
if (format === "json") {
|
|
8808
9088
|
printJson2(result);
|
|
@@ -8816,7 +9096,7 @@ async function wordpressStagingStatus(project, format) {
|
|
|
8816
9096
|
console.log(` Admin URL: ${result.adminUrl}`);
|
|
8817
9097
|
}
|
|
8818
9098
|
async function wordpressStagingPush(project, format) {
|
|
8819
|
-
const client =
|
|
9099
|
+
const client = getClient19();
|
|
8820
9100
|
const result = await client.wordpressStagingPush(project);
|
|
8821
9101
|
if (format === "json") {
|
|
8822
9102
|
printJson2(result);
|
|
@@ -8863,7 +9143,7 @@ function resolveContent(input, command, usage, options) {
|
|
|
8863
9143
|
}
|
|
8864
9144
|
if (contentFile) {
|
|
8865
9145
|
try {
|
|
8866
|
-
return
|
|
9146
|
+
return fs11.readFileSync(contentFile, "utf-8");
|
|
8867
9147
|
} catch (error) {
|
|
8868
9148
|
const message = error instanceof Error ? error.message : String(error);
|
|
8869
9149
|
throw usageError(`Error: could not read --content-file "${contentFile}": ${message}`, {
|
|
@@ -9795,6 +10075,7 @@ var REGISTERED_CLI_COMMANDS = [
|
|
|
9795
10075
|
...SYSTEM_CLI_COMMANDS,
|
|
9796
10076
|
...PROJECT_CLI_COMMANDS,
|
|
9797
10077
|
...REPORT_CLI_COMMANDS,
|
|
10078
|
+
...QUERY_CLI_COMMANDS,
|
|
9798
10079
|
...KEYWORD_CLI_COMMANDS,
|
|
9799
10080
|
...COMPETITOR_CLI_COMMANDS,
|
|
9800
10081
|
...SETTINGS_CLI_COMMANDS,
|
|
@@ -9832,14 +10113,14 @@ Setup:
|
|
|
9832
10113
|
|
|
9833
10114
|
Projects:
|
|
9834
10115
|
project Create, update, list, show, delete projects
|
|
9835
|
-
|
|
10116
|
+
query Add, replace, remove, list, import, generate queries
|
|
9836
10117
|
competitor Add, remove, list competitors
|
|
9837
10118
|
|
|
9838
10119
|
Monitoring:
|
|
9839
10120
|
run Trigger visibility sweeps
|
|
9840
10121
|
snapshot One-shot AI perception report
|
|
9841
10122
|
status <project> Show project summary
|
|
9842
|
-
evidence <project> Show per-
|
|
10123
|
+
evidence <project> Show per-query results
|
|
9843
10124
|
analytics <project> Show analytics (metrics, gaps, sources)
|
|
9844
10125
|
insights <project> Show intelligence insights
|
|
9845
10126
|
health <project> Show citation health
|
|
@@ -9893,7 +10174,7 @@ async function runCli(args = process.argv.slice(2)) {
|
|
|
9893
10174
|
showFirstRunNotice();
|
|
9894
10175
|
getOrCreateAnonymousId();
|
|
9895
10176
|
}
|
|
9896
|
-
const SUBCOMMAND_COMMANDS = /* @__PURE__ */ new Set(["backfill", "project", "keyword", "competitor", "schedule", "notify", "settings", "telemetry", "google", "bing", "wordpress", "cdp"]);
|
|
10177
|
+
const SUBCOMMAND_COMMANDS = /* @__PURE__ */ new Set(["backfill", "project", "query", "keyword", "competitor", "schedule", "notify", "settings", "telemetry", "google", "bing", "wordpress", "cdp"]);
|
|
9897
10178
|
const MIXED_SUBCOMMANDS = {
|
|
9898
10179
|
insights: /* @__PURE__ */ new Set(["dismiss"]),
|
|
9899
10180
|
run: /* @__PURE__ */ new Set(["show", "cancel"])
|