@ainyc/canonry 4.36.0 → 4.40.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.
@@ -472,6 +472,13 @@ var ApiClient = class {
472
472
  async putQueries(project, queries) {
473
473
  await this.request("PUT", `/projects/${encodeURIComponent(project)}/queries`, { queries });
474
474
  }
475
+ async previewReplaceQueries(project, queries) {
476
+ return this.request(
477
+ "POST",
478
+ `/projects/${encodeURIComponent(project)}/queries/replace-preview`,
479
+ { queries }
480
+ );
481
+ }
475
482
  async listQueries(project) {
476
483
  return this.request("GET", `/projects/${encodeURIComponent(project)}/queries`);
477
484
  }
@@ -1995,6 +2002,17 @@ var canonryMcpTools = [
1995
2002
  await client.putQueries(input.project, uniqueStrings(input.request.queries));
1996
2003
  }
1997
2004
  }),
2005
+ defineTool({
2006
+ name: "canonry_queries_replace_preview",
2007
+ title: "Preview query replace",
2008
+ description: "Preview the impact of replacing a project's tracked query set: current vs proposed, added/removed/unchanged diff, and the count of snapshots that would detach (queryId \u2192 NULL; queryText preserved). Read-only.",
2009
+ access: "read",
2010
+ tier: "setup",
2011
+ inputSchema: queriesInputSchema,
2012
+ annotations: readAnnotations(),
2013
+ openApiOperations: ["POST /api/v1/projects/{name}/queries/replace-preview"],
2014
+ handler: (client, input) => client.previewReplaceQueries(input.project, uniqueStrings(input.request.queries))
2015
+ }),
1998
2016
  defineTool({
1999
2017
  name: "canonry_keywords_replace",
2000
2018
  title: "Replace keywords (legacy alias)",
package/dist/cli.js CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  setTelemetrySource,
22
22
  showFirstRunNotice,
23
23
  trackEvent
24
- } from "./chunk-F2G67CIU.js";
24
+ } from "./chunk-H6COOYA6.js";
25
25
  import {
26
26
  CliError,
27
27
  EXIT_SYSTEM_ERROR,
@@ -37,14 +37,14 @@ import {
37
37
  saveConfig,
38
38
  saveConfigPatch,
39
39
  usageError
40
- } from "./chunk-O7S623DL.js";
40
+ } from "./chunk-JS6KRBBZ.js";
41
41
  import {
42
42
  apiKeys,
43
43
  createClient,
44
44
  migrate,
45
45
  projects,
46
46
  queries
47
- } from "./chunk-JQQXMCQ7.js";
47
+ } from "./chunk-EWYUJ2DG.js";
48
48
  import {
49
49
  CcReleaseSyncStatuses,
50
50
  CheckScopes,
@@ -292,28 +292,32 @@ Usage: ${config.usage}`, {
292
292
  var BACKFILL_CLI_COMMANDS = [
293
293
  {
294
294
  path: ["backfill", "answer-visibility"],
295
- usage: "canonry backfill answer-visibility [--project <name>] [--format json]",
295
+ usage: "canonry backfill answer-visibility [--project <name>] [--dry-run] [--format json]",
296
296
  options: {
297
297
  project: stringOption()
298
298
  },
299
299
  allowPositionals: false,
300
+ supportsDryRun: true,
300
301
  run: async (input) => {
301
302
  await backfillAnswerVisibilityCommand({
302
303
  project: getString(input.values, "project"),
304
+ dryRun: input.dryRun,
303
305
  format: input.format
304
306
  });
305
307
  }
306
308
  },
307
309
  {
308
310
  path: ["backfill", "answer-mentions"],
309
- usage: "canonry backfill answer-mentions [--project <name>] [--format json]",
311
+ usage: "canonry backfill answer-mentions [--project <name>] [--dry-run] [--format json]",
310
312
  options: {
311
313
  project: stringOption()
312
314
  },
313
315
  allowPositionals: false,
316
+ supportsDryRun: true,
314
317
  run: async (input) => {
315
318
  await backfillAnswerMentionsCommand({
316
319
  project: getString(input.values, "project"),
320
+ dryRun: input.dryRun,
317
321
  format: input.format
318
322
  });
319
323
  }
@@ -4691,10 +4695,33 @@ async function addQueries(project, queries2, format) {
4691
4695
  }
4692
4696
  console.log(`Added ${queries2.length} ${queries2.length === 1 ? "query" : "queries"} to "${project}".`);
4693
4697
  }
4694
- async function replaceQueries(project, queries2, format) {
4698
+ async function replaceQueries(project, queries2, opts) {
4695
4699
  const client = getClient10();
4700
+ const isJson = opts?.format === "json";
4701
+ if (opts?.dryRun) {
4702
+ const preview = await client.previewReplaceQueries(project, queries2);
4703
+ if (isJson) {
4704
+ console.log(JSON.stringify({ dryRun: true, ...preview }, null, 2));
4705
+ return;
4706
+ }
4707
+ const { diff, snapshotImpact } = preview;
4708
+ console.log(`Query replace preview for "${project}":`);
4709
+ console.log(` Current: ${preview.current.length} ${preview.current.length === 1 ? "query" : "queries"}`);
4710
+ console.log(` Proposed: ${preview.proposed.length} ${preview.proposed.length === 1 ? "query" : "queries"}`);
4711
+ console.log(` Diff:`);
4712
+ console.log(` + added: ${diff.added.length}${diff.added.length ? ` (${diff.added.join(", ")})` : ""}`);
4713
+ console.log(` - removed: ${diff.removed.length}${diff.removed.length ? ` (${diff.removed.join(", ")})` : ""}`);
4714
+ console.log(` = unchanged: ${diff.unchanged.length}${diff.unchanged.length ? ` (${diff.unchanged.join(", ")})` : ""}`);
4715
+ console.log(` Snapshot impact:`);
4716
+ console.log(` Replace wipes every queries row and re-inserts with new IDs, so ALL`);
4717
+ console.log(` existing snapshots get detached (queryId \u2192 NULL; queryText preserved).`);
4718
+ console.log(` Snapshots affected: ${snapshotImpact.snapshotsDetached} across ${snapshotImpact.affectedQueries} ${snapshotImpact.affectedQueries === 1 ? "query" : "queries"}`);
4719
+ console.log(``);
4720
+ console.log(`No DB writes performed. Re-run without --dry-run to apply.`);
4721
+ return;
4722
+ }
4696
4723
  await client.putQueries(project, queries2);
4697
- if (format === "json") {
4724
+ if (isJson) {
4698
4725
  console.log(JSON.stringify({
4699
4726
  project,
4700
4727
  queries: queries2,
@@ -4834,20 +4861,21 @@ var QUERY_CLI_COMMANDS = [
4834
4861
  },
4835
4862
  {
4836
4863
  path: ["query", "replace"],
4837
- usage: "canonry query replace <project> <query...> [--format json]",
4864
+ usage: "canonry query replace <project> <query...> [--dry-run] [--format json]",
4865
+ supportsDryRun: true,
4838
4866
  run: async (input) => {
4839
- const project = requireProject(input, "query.replace", "canonry query replace <project> <query...> [--format json]");
4867
+ const project = requireProject(input, "query.replace", "canonry query replace <project> <query...> [--dry-run] [--format json]");
4840
4868
  const queries2 = input.positionals.slice(1);
4841
4869
  if (queries2.length === 0) {
4842
- throw usageError("Error: project name and at least one query required\nUsage: canonry query replace <project> <query...> [--format json]", {
4870
+ throw usageError("Error: project name and at least one query required\nUsage: canonry query replace <project> <query...> [--dry-run] [--format json]", {
4843
4871
  message: "project name and at least one query required",
4844
4872
  details: {
4845
4873
  command: "query.replace",
4846
- usage: "canonry query replace <project> <query...> [--format json]"
4874
+ usage: "canonry query replace <project> <query...> [--dry-run] [--format json]"
4847
4875
  }
4848
4876
  });
4849
4877
  }
4850
- await replaceQueries(project, queries2, input.format);
4878
+ await replaceQueries(project, queries2, { dryRun: input.dryRun, format: input.format });
4851
4879
  }
4852
4880
  },
4853
4881
  {
@@ -7256,6 +7284,31 @@ function emitInstallSummary(summary, format) {
7256
7284
  Target: ${summary.targetDir}`);
7257
7285
  console.log(summary.message);
7258
7286
  }
7287
+ function getMissingUserSkillsNudge(home) {
7288
+ if (!home) return null;
7289
+ const skillsBase = path4.join(home, ".claude", "skills");
7290
+ const installed = [];
7291
+ const missing = [];
7292
+ for (const name of BUNDLED_SKILL_NAMES) {
7293
+ const skillFile = path4.join(skillsBase, name, "SKILL.md");
7294
+ if (existsSafe(skillFile)) installed.push(name);
7295
+ else missing.push(name);
7296
+ }
7297
+ if (missing.length === 0) return null;
7298
+ const fix = missing.length === BUNDLED_SKILL_NAMES.length ? "canonry skills install --user" : `canonry skills install ${missing.join(" ")} --user`;
7299
+ return {
7300
+ message: `Tip: ${missing.join(" + ")} skill${missing.length === 1 ? "" : "s"} not installed in ~/.claude/skills/. Run \`${fix}\` so Claude/Codex sessions on this host auto-load the canonry reference docs.`,
7301
+ missing,
7302
+ installed
7303
+ };
7304
+ }
7305
+ function existsSafe(p) {
7306
+ try {
7307
+ return fs7.existsSync(p);
7308
+ } catch {
7309
+ return false;
7310
+ }
7311
+ }
7259
7312
  function parseSkillsClient(value) {
7260
7313
  if (!value) return SkillsClients.all;
7261
7314
  const parsed = skillsClientSchema.safeParse(value);
@@ -9171,6 +9224,9 @@ Received ${signal}, stopping server...`);
9171
9224
  console.log(`
9172
9225
  Canonry server running at ${url}`);
9173
9226
  console.log("Press Ctrl+C to stop.\n");
9227
+ const nudge = getMissingUserSkillsNudge(process.env.HOME);
9228
+ if (nudge) process.stderr.write(`${nudge.message}
9229
+ `);
9174
9230
  }
9175
9231
  setTelemetrySource("cli-server");
9176
9232
  const providerNames = Object.keys(config.providers ?? {}).filter(
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-F2G67CIU.js";
3
+ } from "./chunk-H6COOYA6.js";
4
4
  import {
5
5
  loadConfig
6
- } from "./chunk-O7S623DL.js";
7
- import "./chunk-JQQXMCQ7.js";
6
+ } from "./chunk-JS6KRBBZ.js";
7
+ import "./chunk-EWYUJ2DG.js";
8
8
  import "./chunk-XJVYVURK.js";
9
9
  export {
10
10
  createServer,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-JQQXMCQ7.js";
3
+ } from "./chunk-EWYUJ2DG.js";
4
4
  import "./chunk-XJVYVURK.js";
5
5
  export {
6
6
  IntelligenceService
package/dist/mcp.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  CliError,
3
3
  canonryMcpTools,
4
4
  createApiClient
5
- } from "./chunk-O7S623DL.js";
5
+ } from "./chunk-JS6KRBBZ.js";
6
6
  import "./chunk-XJVYVURK.js";
7
7
 
8
8
  // src/mcp/cli.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ainyc/canonry",
3
- "version": "4.36.0",
3
+ "version": "4.40.0",
4
4
  "type": "module",
5
5
  "description": "Agent-first open-source AEO operating platform - track how answer engines cite your domain",
6
6
  "license": "FSL-1.1-ALv2",
@@ -61,20 +61,20 @@
61
61
  "tsup": "^8.5.1",
62
62
  "tsx": "^4.19.0",
63
63
  "@ainyc/canonry-api-routes": "0.0.0",
64
+ "@ainyc/canonry-contracts": "0.0.0",
64
65
  "@ainyc/canonry-config": "0.0.0",
65
66
  "@ainyc/canonry-db": "0.0.0",
66
- "@ainyc/canonry-intelligence": "0.0.0",
67
67
  "@ainyc/canonry-integration-bing": "0.0.0",
68
+ "@ainyc/canonry-intelligence": "0.0.0",
68
69
  "@ainyc/canonry-integration-cloud-run": "0.0.0",
69
- "@ainyc/canonry-contracts": "0.0.0",
70
70
  "@ainyc/canonry-integration-commoncrawl": "0.0.0",
71
- "@ainyc/canonry-integration-traffic": "0.0.0",
72
71
  "@ainyc/canonry-integration-google": "0.0.0",
72
+ "@ainyc/canonry-integration-traffic": "0.0.0",
73
73
  "@ainyc/canonry-integration-wordpress": "0.0.0",
74
74
  "@ainyc/canonry-provider-cdp": "0.0.0",
75
75
  "@ainyc/canonry-provider-gemini": "0.0.0",
76
- "@ainyc/canonry-provider-claude": "0.0.0",
77
76
  "@ainyc/canonry-provider-local": "0.0.0",
77
+ "@ainyc/canonry-provider-claude": "0.0.0",
78
78
  "@ainyc/canonry-provider-openai": "0.0.0",
79
79
  "@ainyc/canonry-provider-perplexity": "0.0.0"
80
80
  },