@ainyc/canonry 1.31.0 → 1.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/assets/index-BuSiyI7z.js +246 -0
- package/assets/index.html +1 -1
- package/dist/{chunk-YW4IZ34Z.js → chunk-5Q6LISDM.js} +187 -47
- package/dist/cli.js +217 -110
- package/dist/index.js +1 -1
- package/package.json +5 -5
- package/assets/assets/index-DmFB_uXa.js +0 -246
package/dist/cli.js
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
configExists,
|
|
5
5
|
createClient,
|
|
6
6
|
createServer,
|
|
7
|
+
determineAnswerMentioned,
|
|
7
8
|
effectiveDomains,
|
|
8
9
|
formatAuditFactorScore,
|
|
9
10
|
getConfigDir,
|
|
@@ -14,14 +15,18 @@ import {
|
|
|
14
15
|
loadConfig,
|
|
15
16
|
migrate,
|
|
16
17
|
notificationEventSchema,
|
|
18
|
+
parseJsonColumn,
|
|
19
|
+
projects,
|
|
17
20
|
providerQuotaPolicySchema,
|
|
21
|
+
querySnapshots,
|
|
18
22
|
resolveProviderInput,
|
|
23
|
+
runs,
|
|
19
24
|
saveConfig,
|
|
20
25
|
saveConfigPatch,
|
|
21
26
|
setGoogleAuthConfig,
|
|
22
27
|
showFirstRunNotice,
|
|
23
28
|
trackEvent
|
|
24
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-5Q6LISDM.js";
|
|
25
30
|
|
|
26
31
|
// src/cli.ts
|
|
27
32
|
import { pathToFileURL } from "url";
|
|
@@ -149,6 +154,185 @@ Usage: ${spec.usage}`, {
|
|
|
149
154
|
return true;
|
|
150
155
|
}
|
|
151
156
|
|
|
157
|
+
// src/commands/backfill.ts
|
|
158
|
+
import { eq, inArray } from "drizzle-orm";
|
|
159
|
+
var SNAPSHOT_BATCH_SIZE = 500;
|
|
160
|
+
async function backfillAnswerVisibilityCommand(opts) {
|
|
161
|
+
const config = loadConfig();
|
|
162
|
+
const db = createClient(config.database);
|
|
163
|
+
migrate(db);
|
|
164
|
+
const projectFilter = opts?.project?.trim();
|
|
165
|
+
const scopedProjects = projectFilter ? db.select().from(projects).where(eq(projects.name, projectFilter)).all() : db.select().from(projects).all();
|
|
166
|
+
let examined = 0;
|
|
167
|
+
let updated = 0;
|
|
168
|
+
let visible = 0;
|
|
169
|
+
if (scopedProjects.length > 0) {
|
|
170
|
+
const runRows = projectFilter ? db.select({ id: runs.id, projectId: runs.projectId }).from(runs).where(inArray(runs.projectId, scopedProjects.map((project) => project.id))).all() : db.select({ id: runs.id, projectId: runs.projectId }).from(runs).all();
|
|
171
|
+
const runIdsByProject = /* @__PURE__ */ new Map();
|
|
172
|
+
for (const run of runRows) {
|
|
173
|
+
const existing = runIdsByProject.get(run.projectId);
|
|
174
|
+
if (existing) existing.push(run.id);
|
|
175
|
+
else runIdsByProject.set(run.projectId, [run.id]);
|
|
176
|
+
}
|
|
177
|
+
for (const project of scopedProjects) {
|
|
178
|
+
const runIds = runIdsByProject.get(project.id) ?? [];
|
|
179
|
+
if (runIds.length === 0) continue;
|
|
180
|
+
for (let offset = 0; offset < runIds.length; offset += SNAPSHOT_BATCH_SIZE) {
|
|
181
|
+
const batchRunIds = runIds.slice(offset, offset + SNAPSHOT_BATCH_SIZE);
|
|
182
|
+
const snapshotRows = db.select({
|
|
183
|
+
id: querySnapshots.id,
|
|
184
|
+
answerMentioned: querySnapshots.answerMentioned,
|
|
185
|
+
answerText: querySnapshots.answerText
|
|
186
|
+
}).from(querySnapshots).where(inArray(querySnapshots.runId, batchRunIds)).all();
|
|
187
|
+
for (const snapshot of snapshotRows) {
|
|
188
|
+
examined++;
|
|
189
|
+
const nextValue = determineAnswerMentioned(
|
|
190
|
+
snapshot.answerText,
|
|
191
|
+
project.displayName,
|
|
192
|
+
effectiveDomains({
|
|
193
|
+
canonicalDomain: project.canonicalDomain,
|
|
194
|
+
ownedDomains: parseJsonColumn(project.ownedDomains, [])
|
|
195
|
+
})
|
|
196
|
+
);
|
|
197
|
+
if (nextValue) visible++;
|
|
198
|
+
if (snapshot.answerMentioned !== nextValue) {
|
|
199
|
+
db.update(querySnapshots).set({ answerMentioned: nextValue }).where(eq(querySnapshots.id, snapshot.id)).run();
|
|
200
|
+
updated++;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const result = {
|
|
207
|
+
project: projectFilter ?? null,
|
|
208
|
+
projects: scopedProjects.length,
|
|
209
|
+
examined,
|
|
210
|
+
updated,
|
|
211
|
+
visible
|
|
212
|
+
};
|
|
213
|
+
if (opts?.format === "json") {
|
|
214
|
+
console.log(JSON.stringify(result, null, 2));
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
console.log("Answer visibility backfill complete.\n");
|
|
218
|
+
if (projectFilter) {
|
|
219
|
+
console.log(` Project: ${projectFilter}`);
|
|
220
|
+
}
|
|
221
|
+
console.log(` Projects: ${scopedProjects.length}`);
|
|
222
|
+
console.log(` Examined: ${examined}`);
|
|
223
|
+
console.log(` Updated: ${updated}`);
|
|
224
|
+
console.log(` Visible: ${visible}`);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// src/cli-command-helpers.ts
|
|
228
|
+
function getString(values, key) {
|
|
229
|
+
const value = values[key];
|
|
230
|
+
return typeof value === "string" ? value : void 0;
|
|
231
|
+
}
|
|
232
|
+
function getBoolean(values, key) {
|
|
233
|
+
return values[key] === true;
|
|
234
|
+
}
|
|
235
|
+
function getStringArray(values, key) {
|
|
236
|
+
const value = values[key];
|
|
237
|
+
if (Array.isArray(value)) {
|
|
238
|
+
return value.filter((entry) => typeof entry === "string");
|
|
239
|
+
}
|
|
240
|
+
return void 0;
|
|
241
|
+
}
|
|
242
|
+
function requirePositional(input, index, config) {
|
|
243
|
+
const value = input.positionals[index];
|
|
244
|
+
if (value) return value;
|
|
245
|
+
throw usageError(`Error: ${config.message}
|
|
246
|
+
Usage: ${config.usage}`, {
|
|
247
|
+
message: config.message,
|
|
248
|
+
details: {
|
|
249
|
+
command: config.command,
|
|
250
|
+
usage: config.usage
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
function requireProject(input, command, usage, message = "project name is required") {
|
|
255
|
+
return requirePositional(input, 0, { command, usage, message });
|
|
256
|
+
}
|
|
257
|
+
function stringOption() {
|
|
258
|
+
return { type: "string" };
|
|
259
|
+
}
|
|
260
|
+
function multiStringOption() {
|
|
261
|
+
return { type: "string", multiple: true };
|
|
262
|
+
}
|
|
263
|
+
function requireStringOption(input, key, config) {
|
|
264
|
+
const value = getString(input.values, key);
|
|
265
|
+
if (value) return value;
|
|
266
|
+
throw usageError(`Error: ${config.message}
|
|
267
|
+
Usage: ${config.usage}`, {
|
|
268
|
+
message: config.message,
|
|
269
|
+
details: {
|
|
270
|
+
command: config.command,
|
|
271
|
+
usage: config.usage,
|
|
272
|
+
...config.details ?? {}
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
function parseIntegerOption(input, key, config) {
|
|
277
|
+
const value = getString(input.values, key);
|
|
278
|
+
if (!value) return void 0;
|
|
279
|
+
const parsed = Number.parseInt(value, 10);
|
|
280
|
+
if (!Number.isNaN(parsed)) {
|
|
281
|
+
return parsed;
|
|
282
|
+
}
|
|
283
|
+
throw usageError(`Error: ${config.message}
|
|
284
|
+
Usage: ${config.usage}`, {
|
|
285
|
+
message: config.message,
|
|
286
|
+
details: {
|
|
287
|
+
command: config.command,
|
|
288
|
+
usage: config.usage,
|
|
289
|
+
option: key,
|
|
290
|
+
value
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
function unknownSubcommand(subcommand, config) {
|
|
295
|
+
const resolved = subcommand ?? "(none)";
|
|
296
|
+
throw usageError(`Error: unknown ${config.command} subcommand: ${resolved}
|
|
297
|
+
Usage: ${config.usage}`, {
|
|
298
|
+
message: `unknown ${config.command} subcommand: ${resolved}`,
|
|
299
|
+
details: {
|
|
300
|
+
command: config.command,
|
|
301
|
+
usage: config.usage,
|
|
302
|
+
available: config.available
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// src/cli-commands/backfill.ts
|
|
308
|
+
var BACKFILL_CLI_COMMANDS = [
|
|
309
|
+
{
|
|
310
|
+
path: ["backfill", "answer-visibility"],
|
|
311
|
+
usage: "canonry backfill answer-visibility [--project <name>] [--format json]",
|
|
312
|
+
options: {
|
|
313
|
+
project: stringOption()
|
|
314
|
+
},
|
|
315
|
+
allowPositionals: false,
|
|
316
|
+
run: async (input) => {
|
|
317
|
+
await backfillAnswerVisibilityCommand({
|
|
318
|
+
project: getString(input.values, "project"),
|
|
319
|
+
format: input.format
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
path: ["backfill"],
|
|
325
|
+
usage: "canonry backfill <answer-visibility> [--project <name>] [--format json]",
|
|
326
|
+
run: async (input) => {
|
|
327
|
+
unknownSubcommand(input.positionals[0], {
|
|
328
|
+
command: "backfill",
|
|
329
|
+
usage: "canonry backfill <answer-visibility> [--project <name>] [--format json]",
|
|
330
|
+
available: ["answer-visibility"]
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
];
|
|
335
|
+
|
|
152
336
|
// src/client.ts
|
|
153
337
|
function createApiClient() {
|
|
154
338
|
const config = loadConfig();
|
|
@@ -855,86 +1039,6 @@ async function bingPerformance(project, format) {
|
|
|
855
1039
|
}
|
|
856
1040
|
}
|
|
857
1041
|
|
|
858
|
-
// src/cli-command-helpers.ts
|
|
859
|
-
function getString(values, key) {
|
|
860
|
-
const value = values[key];
|
|
861
|
-
return typeof value === "string" ? value : void 0;
|
|
862
|
-
}
|
|
863
|
-
function getBoolean(values, key) {
|
|
864
|
-
return values[key] === true;
|
|
865
|
-
}
|
|
866
|
-
function getStringArray(values, key) {
|
|
867
|
-
const value = values[key];
|
|
868
|
-
if (Array.isArray(value)) {
|
|
869
|
-
return value.filter((entry) => typeof entry === "string");
|
|
870
|
-
}
|
|
871
|
-
return void 0;
|
|
872
|
-
}
|
|
873
|
-
function requirePositional(input, index, config) {
|
|
874
|
-
const value = input.positionals[index];
|
|
875
|
-
if (value) return value;
|
|
876
|
-
throw usageError(`Error: ${config.message}
|
|
877
|
-
Usage: ${config.usage}`, {
|
|
878
|
-
message: config.message,
|
|
879
|
-
details: {
|
|
880
|
-
command: config.command,
|
|
881
|
-
usage: config.usage
|
|
882
|
-
}
|
|
883
|
-
});
|
|
884
|
-
}
|
|
885
|
-
function requireProject(input, command, usage, message = "project name is required") {
|
|
886
|
-
return requirePositional(input, 0, { command, usage, message });
|
|
887
|
-
}
|
|
888
|
-
function stringOption() {
|
|
889
|
-
return { type: "string" };
|
|
890
|
-
}
|
|
891
|
-
function multiStringOption() {
|
|
892
|
-
return { type: "string", multiple: true };
|
|
893
|
-
}
|
|
894
|
-
function requireStringOption(input, key, config) {
|
|
895
|
-
const value = getString(input.values, key);
|
|
896
|
-
if (value) return value;
|
|
897
|
-
throw usageError(`Error: ${config.message}
|
|
898
|
-
Usage: ${config.usage}`, {
|
|
899
|
-
message: config.message,
|
|
900
|
-
details: {
|
|
901
|
-
command: config.command,
|
|
902
|
-
usage: config.usage,
|
|
903
|
-
...config.details ?? {}
|
|
904
|
-
}
|
|
905
|
-
});
|
|
906
|
-
}
|
|
907
|
-
function parseIntegerOption(input, key, config) {
|
|
908
|
-
const value = getString(input.values, key);
|
|
909
|
-
if (!value) return void 0;
|
|
910
|
-
const parsed = Number.parseInt(value, 10);
|
|
911
|
-
if (!Number.isNaN(parsed)) {
|
|
912
|
-
return parsed;
|
|
913
|
-
}
|
|
914
|
-
throw usageError(`Error: ${config.message}
|
|
915
|
-
Usage: ${config.usage}`, {
|
|
916
|
-
message: config.message,
|
|
917
|
-
details: {
|
|
918
|
-
command: config.command,
|
|
919
|
-
usage: config.usage,
|
|
920
|
-
option: key,
|
|
921
|
-
value
|
|
922
|
-
}
|
|
923
|
-
});
|
|
924
|
-
}
|
|
925
|
-
function unknownSubcommand(subcommand, config) {
|
|
926
|
-
const resolved = subcommand ?? "(none)";
|
|
927
|
-
throw usageError(`Error: unknown ${config.command} subcommand: ${resolved}
|
|
928
|
-
Usage: ${config.usage}`, {
|
|
929
|
-
message: `unknown ${config.command} subcommand: ${resolved}`,
|
|
930
|
-
details: {
|
|
931
|
-
command: config.command,
|
|
932
|
-
usage: config.usage,
|
|
933
|
-
available: config.available
|
|
934
|
-
}
|
|
935
|
-
});
|
|
936
|
-
}
|
|
937
|
-
|
|
938
1042
|
// src/cli-commands/bing.ts
|
|
939
1043
|
var BING_CLI_COMMANDS = [
|
|
940
1044
|
{
|
|
@@ -3060,9 +3164,9 @@ async function exportProject(project, opts) {
|
|
|
3060
3164
|
const data = await client.getExport(project);
|
|
3061
3165
|
if (opts.includeResults) {
|
|
3062
3166
|
try {
|
|
3063
|
-
const
|
|
3064
|
-
if (
|
|
3065
|
-
const latestRun = await client.getRun(
|
|
3167
|
+
const runs2 = await client.listRuns(project);
|
|
3168
|
+
if (runs2.length > 0) {
|
|
3169
|
+
const latestRun = await client.getRun(runs2[runs2.length - 1].id);
|
|
3066
3170
|
data.results = latestRun;
|
|
3067
3171
|
}
|
|
3068
3172
|
} catch {
|
|
@@ -3121,13 +3225,13 @@ function getClient11() {
|
|
|
3121
3225
|
async function showStatus(project, format) {
|
|
3122
3226
|
const client = getClient11();
|
|
3123
3227
|
const projectData = await client.getProject(project);
|
|
3124
|
-
let
|
|
3228
|
+
let runs2 = [];
|
|
3125
3229
|
try {
|
|
3126
|
-
|
|
3230
|
+
runs2 = await client.listRuns(project);
|
|
3127
3231
|
} catch {
|
|
3128
3232
|
}
|
|
3129
3233
|
if (format === "json") {
|
|
3130
|
-
console.log(JSON.stringify({ project: projectData, runs }, null, 2));
|
|
3234
|
+
console.log(JSON.stringify({ project: projectData, runs: runs2 }, null, 2));
|
|
3131
3235
|
return;
|
|
3132
3236
|
}
|
|
3133
3237
|
console.log(`Status: ${projectData.displayName} (${projectData.name})
|
|
@@ -3135,8 +3239,8 @@ async function showStatus(project, format) {
|
|
|
3135
3239
|
console.log(` Domain: ${projectData.canonicalDomain}`);
|
|
3136
3240
|
console.log(` Country: ${projectData.country}`);
|
|
3137
3241
|
console.log(` Language: ${projectData.language}`);
|
|
3138
|
-
if (
|
|
3139
|
-
const latest =
|
|
3242
|
+
if (runs2.length > 0) {
|
|
3243
|
+
const latest = runs2[runs2.length - 1];
|
|
3140
3244
|
console.log(`
|
|
3141
3245
|
Latest run:`);
|
|
3142
3246
|
console.log(` ID: ${latest.id}`);
|
|
@@ -3146,7 +3250,7 @@ async function showStatus(project, format) {
|
|
|
3146
3250
|
console.log(` Finished: ${latest.finishedAt}`);
|
|
3147
3251
|
}
|
|
3148
3252
|
console.log(`
|
|
3149
|
-
Total runs: ${
|
|
3253
|
+
Total runs: ${runs2.length}`);
|
|
3150
3254
|
} else {
|
|
3151
3255
|
console.log('\n No runs yet. Use "canonry run" to trigger one.');
|
|
3152
3256
|
}
|
|
@@ -3247,27 +3351,27 @@ async function createProject(name, opts) {
|
|
|
3247
3351
|
}
|
|
3248
3352
|
async function listProjects(format) {
|
|
3249
3353
|
const client = getClient12();
|
|
3250
|
-
const
|
|
3354
|
+
const projects2 = await client.listProjects();
|
|
3251
3355
|
if (format === "json") {
|
|
3252
|
-
console.log(JSON.stringify(
|
|
3356
|
+
console.log(JSON.stringify(projects2, null, 2));
|
|
3253
3357
|
return;
|
|
3254
3358
|
}
|
|
3255
|
-
if (
|
|
3359
|
+
if (projects2.length === 0) {
|
|
3256
3360
|
console.log("No projects found.");
|
|
3257
3361
|
return;
|
|
3258
3362
|
}
|
|
3259
3363
|
console.log("Projects:\n");
|
|
3260
|
-
const nameWidth = Math.max(4, ...
|
|
3364
|
+
const nameWidth = Math.max(4, ...projects2.map((p) => p.name.length));
|
|
3261
3365
|
const domainLabel = (p) => {
|
|
3262
3366
|
const extra = Math.max(0, effectiveDomains(p).length - 1);
|
|
3263
3367
|
return extra > 0 ? `${p.canonicalDomain} (+${extra})` : p.canonicalDomain;
|
|
3264
3368
|
};
|
|
3265
|
-
const domainWidth = Math.max(6, ...
|
|
3369
|
+
const domainWidth = Math.max(6, ...projects2.map((p) => domainLabel(p).length));
|
|
3266
3370
|
console.log(
|
|
3267
3371
|
` ${"NAME".padEnd(nameWidth)} ${"DOMAIN".padEnd(domainWidth)} COUNTRY LANGUAGE`
|
|
3268
3372
|
);
|
|
3269
3373
|
console.log(` ${"\u2500".repeat(nameWidth)} ${"\u2500".repeat(domainWidth)} \u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`);
|
|
3270
|
-
for (const p of
|
|
3374
|
+
for (const p of projects2) {
|
|
3271
3375
|
console.log(
|
|
3272
3376
|
` ${p.name.padEnd(nameWidth)} ${domainLabel(p).padEnd(domainWidth)} ${p.country.padEnd(7)} ${p.language}`
|
|
3273
3377
|
);
|
|
@@ -3656,8 +3760,8 @@ async function triggerRun(project, opts) {
|
|
|
3656
3760
|
}
|
|
3657
3761
|
async function triggerRunAll(opts) {
|
|
3658
3762
|
const client = getClient13();
|
|
3659
|
-
const
|
|
3660
|
-
if (
|
|
3763
|
+
const projects2 = await client.listProjects();
|
|
3764
|
+
if (projects2.length === 0) {
|
|
3661
3765
|
if (opts?.format === "json") {
|
|
3662
3766
|
console.log("[]");
|
|
3663
3767
|
} else {
|
|
@@ -3672,7 +3776,7 @@ async function triggerRunAll(opts) {
|
|
|
3672
3776
|
body.providers = resolved.length > 0 ? resolved : providerInputs;
|
|
3673
3777
|
}
|
|
3674
3778
|
const results = [];
|
|
3675
|
-
for (const p of
|
|
3779
|
+
for (const p of projects2) {
|
|
3676
3780
|
try {
|
|
3677
3781
|
const run = await client.triggerRun(p.name, body);
|
|
3678
3782
|
results.push({ project: p.name, runId: run.id, status: run.status });
|
|
@@ -3710,8 +3814,8 @@ async function cancelRun(project, runId, format) {
|
|
|
3710
3814
|
const client = getClient13();
|
|
3711
3815
|
let targetId = runId;
|
|
3712
3816
|
if (!targetId) {
|
|
3713
|
-
const
|
|
3714
|
-
const active =
|
|
3817
|
+
const runs2 = await client.listRuns(project);
|
|
3818
|
+
const active = runs2.find((r) => r.status === "queued" || r.status === "running");
|
|
3715
3819
|
if (!active) {
|
|
3716
3820
|
throw new CliError({
|
|
3717
3821
|
code: "NO_ACTIVE_RUN",
|
|
@@ -3749,20 +3853,20 @@ async function showRun(id, format) {
|
|
|
3749
3853
|
}
|
|
3750
3854
|
async function listRuns(project, opts) {
|
|
3751
3855
|
const client = getClient13();
|
|
3752
|
-
const
|
|
3856
|
+
const runs2 = await client.listRuns(project, opts?.limit);
|
|
3753
3857
|
if (opts?.format === "json") {
|
|
3754
|
-
console.log(JSON.stringify(
|
|
3858
|
+
console.log(JSON.stringify(runs2, null, 2));
|
|
3755
3859
|
return;
|
|
3756
3860
|
}
|
|
3757
|
-
if (
|
|
3861
|
+
if (runs2.length === 0) {
|
|
3758
3862
|
console.log(`No runs found for "${project}".`);
|
|
3759
3863
|
return;
|
|
3760
3864
|
}
|
|
3761
|
-
console.log(`Runs for "${project}" (${
|
|
3865
|
+
console.log(`Runs for "${project}" (${runs2.length}):
|
|
3762
3866
|
`);
|
|
3763
3867
|
console.log(" ID STATUS KIND TRIGGER CREATED");
|
|
3764
3868
|
console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
3765
|
-
for (const run of
|
|
3869
|
+
for (const run of runs2) {
|
|
3766
3870
|
console.log(
|
|
3767
3871
|
` ${run.id} ${run.status.padEnd(10)} ${run.kind.padEnd(18)} ${run.trigger.padEnd(9)} ${run.createdAt}`
|
|
3768
3872
|
);
|
|
@@ -3796,7 +3900,7 @@ function printRunDetail(run) {
|
|
|
3796
3900
|
console.log(`
|
|
3797
3901
|
Snapshots: ${run.snapshots.length}`);
|
|
3798
3902
|
for (const s of run.snapshots) {
|
|
3799
|
-
const state = s.citationState === "cited" ? " cited " : " not-cited";
|
|
3903
|
+
const state = typeof s.answerMentioned === "boolean" ? s.answerMentioned ? " visible " : " not-vis " : s.citationState === "cited" ? " cited " : " not-cited";
|
|
3800
3904
|
const modelLabel = s.model ? ` (${s.model})` : "";
|
|
3801
3905
|
console.log(` ${state} ${s.provider}${modelLabel} ${s.keyword}`);
|
|
3802
3906
|
}
|
|
@@ -4701,7 +4805,7 @@ var SNAPSHOT_CLI_COMMANDS = [
|
|
|
4701
4805
|
// src/commands/bootstrap.ts
|
|
4702
4806
|
import crypto from "crypto";
|
|
4703
4807
|
import path2 from "path";
|
|
4704
|
-
import { eq } from "drizzle-orm";
|
|
4808
|
+
import { eq as eq2 } from "drizzle-orm";
|
|
4705
4809
|
|
|
4706
4810
|
// ../config/src/index.ts
|
|
4707
4811
|
import { z } from "zod";
|
|
@@ -4877,7 +4981,7 @@ async function bootstrapCommand(_opts) {
|
|
|
4877
4981
|
const keyPrefix = rawApiKey.slice(0, 9);
|
|
4878
4982
|
const db = createClient(databasePath);
|
|
4879
4983
|
migrate(db);
|
|
4880
|
-
db.delete(apiKeys).where(
|
|
4984
|
+
db.delete(apiKeys).where(eq2(apiKeys.name, "default")).run();
|
|
4881
4985
|
db.insert(apiKeys).values({
|
|
4882
4986
|
id: crypto.randomUUID(),
|
|
4883
4987
|
name: "default",
|
|
@@ -6642,6 +6746,7 @@ var WORDPRESS_CLI_COMMANDS = [
|
|
|
6642
6746
|
|
|
6643
6747
|
// src/cli-commands.ts
|
|
6644
6748
|
var REGISTERED_CLI_COMMANDS = [
|
|
6749
|
+
...BACKFILL_CLI_COMMANDS,
|
|
6645
6750
|
...SYSTEM_CLI_COMMANDS,
|
|
6646
6751
|
...PROJECT_CLI_COMMANDS,
|
|
6647
6752
|
...KEYWORD_CLI_COMMANDS,
|
|
@@ -6668,6 +6773,7 @@ Usage:
|
|
|
6668
6773
|
canonry init [--force] Initialize config and database (interactive)
|
|
6669
6774
|
canonry init --gemini-key <key> Initialize non-interactively (also reads env vars)
|
|
6670
6775
|
canonry bootstrap [--force] Bootstrap config/database from env vars
|
|
6776
|
+
canonry backfill answer-visibility Backfill answer-level visibility from stored answers
|
|
6671
6777
|
canonry serve Start the local server (foreground)
|
|
6672
6778
|
canonry start Start the server as a background daemon
|
|
6673
6779
|
canonry stop Stop the background daemon
|
|
@@ -6801,6 +6907,7 @@ Options:
|
|
|
6801
6907
|
--no-location Explicitly skip location context
|
|
6802
6908
|
--wait Wait for run to complete before returning
|
|
6803
6909
|
--all Run all projects (with 'run' command)
|
|
6910
|
+
--project <name> Restrict maintenance commands to a single project
|
|
6804
6911
|
--include-results Include results in export
|
|
6805
6912
|
--preset <preset> Schedule preset (daily, weekly, twice-daily, daily@HH, weekly@DAY)
|
|
6806
6913
|
--cron <expr> Cron expression for schedule
|
|
@@ -6839,7 +6946,7 @@ async function runCli(args = process.argv.slice(2)) {
|
|
|
6839
6946
|
showFirstRunNotice();
|
|
6840
6947
|
getOrCreateAnonymousId();
|
|
6841
6948
|
}
|
|
6842
|
-
const SUBCOMMAND_COMMANDS = /* @__PURE__ */ new Set(["project", "keyword", "competitor", "schedule", "notify", "settings", "telemetry", "google", "bing", "wordpress", "cdp"]);
|
|
6949
|
+
const SUBCOMMAND_COMMANDS = /* @__PURE__ */ new Set(["backfill", "project", "keyword", "competitor", "schedule", "notify", "settings", "telemetry", "google", "bing", "wordpress", "cdp"]);
|
|
6843
6950
|
const resolvedCommand = SUBCOMMAND_COMMANDS.has(command) && args[1] && !args[1].startsWith("-") ? `${command}.${args[1]}` : command;
|
|
6844
6951
|
if (command !== "telemetry") {
|
|
6845
6952
|
trackEvent("cli.command", { command: resolvedCommand });
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainyc/canonry",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.32.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The ultimate open-source AEO monitoring tool - track how answer engines cite your domain",
|
|
6
6
|
"license": "FSL-1.1-ALv2",
|
|
@@ -55,16 +55,16 @@
|
|
|
55
55
|
"tsup": "^8.5.1",
|
|
56
56
|
"tsx": "^4.19.0",
|
|
57
57
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
58
|
-
"@ainyc/canonry-contracts": "0.0.0",
|
|
59
58
|
"@ainyc/canonry-config": "0.0.0",
|
|
60
|
-
"@ainyc/canonry-
|
|
61
|
-
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
59
|
+
"@ainyc/canonry-contracts": "0.0.0",
|
|
62
60
|
"@ainyc/canonry-integration-google": "0.0.0",
|
|
61
|
+
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
62
|
+
"@ainyc/canonry-db": "0.0.0",
|
|
63
63
|
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
64
64
|
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
65
65
|
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
66
|
-
"@ainyc/canonry-provider-local": "0.0.0",
|
|
67
66
|
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
67
|
+
"@ainyc/canonry-provider-local": "0.0.0",
|
|
68
68
|
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
69
69
|
"@ainyc/canonry-provider-perplexity": "0.0.0"
|
|
70
70
|
},
|