@canonry/canonry 4.136.2 → 4.138.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.
Files changed (30) hide show
  1. package/README.md +2 -1
  2. package/assets/assets/{AuditHistoryPanel-DtUGiN21.js → AuditHistoryPanel-CIdoSKjP.js} +1 -1
  3. package/assets/assets/{BacklinksPage-BGwtmwfz.js → BacklinksPage-BYnzQLFq.js} +1 -1
  4. package/assets/assets/{ChartPrimitives-Df2UC1g3.js → ChartPrimitives-bx4p5MDx.js} +1 -1
  5. package/assets/assets/{HistoryPage-AtaMVEUx.js → HistoryPage-CjLb8TKY.js} +1 -1
  6. package/assets/assets/ProjectPage-C_bSGiLs.js +8 -0
  7. package/assets/assets/{RunRow-Cmf-5xVo.js → RunRow-D6W6D1BX.js} +1 -1
  8. package/assets/assets/{RunsPage-BAPy9Yri.js → RunsPage-CQT4lXFp.js} +1 -1
  9. package/assets/assets/{SettingsPage-BXO7WpTo.js → SettingsPage-DVQKzz6s.js} +1 -1
  10. package/assets/assets/{TrafficPage-IH-wiPu2.js → TrafficPage-BdocLgWw.js} +1 -1
  11. package/assets/assets/{TrafficSourceDetailPage-CTTN-P52.js → TrafficSourceDetailPage-CTZF_R9C.js} +1 -1
  12. package/assets/assets/{arrow-left-BwzAIeJ_.js → arrow-left-ClC65OiR.js} +1 -1
  13. package/assets/assets/extract-error-message-CsgTjzyj.js +1 -0
  14. package/assets/assets/index-BZgknVrZ.js +213 -0
  15. package/assets/assets/{index-CglduHCN.css → index-DY7GziwY.css} +1 -1
  16. package/assets/assets/{trash-2-C50OeBAV.js → trash-2-nr8RRH47.js} +1 -1
  17. package/assets/index.html +2 -2
  18. package/dist/{chunk-MXR3GI5L.js → chunk-3KGJ7BXW.js} +234 -16
  19. package/dist/{chunk-YVMQWVNY.js → chunk-GO24URVP.js} +187 -15
  20. package/dist/{chunk-SMFUCXHI.js → chunk-R3GAWKHM.js} +1 -1
  21. package/dist/{chunk-GGIRLRAY.js → chunk-RJ7OW6W6.js} +3076 -2904
  22. package/dist/cli.js +147 -33
  23. package/dist/index.d.ts +2 -0
  24. package/dist/index.js +4 -4
  25. package/dist/{intelligence-service-BD6BHTEJ.js → intelligence-service-5RJHJLYA.js} +2 -2
  26. package/dist/mcp.js +2 -2
  27. package/package.json +11 -11
  28. package/assets/assets/ProjectPage-OlBjxXNx.js +0 -8
  29. package/assets/assets/extract-error-message-BIcIoJLN.js +0 -1
  30. package/assets/assets/index-BPpSrJY0.js +0 -210
package/dist/cli.js CHANGED
@@ -28,8 +28,9 @@ import {
28
28
  setGoogleAuthConfig,
29
29
  setTelemetrySource,
30
30
  showFirstRunNotice,
31
+ trackCliCommandFinished,
31
32
  trackEvent
32
- } from "./chunk-MXR3GI5L.js";
33
+ } from "./chunk-3KGJ7BXW.js";
33
34
  import {
34
35
  CliError,
35
36
  EXIT_SYSTEM_ERROR,
@@ -46,7 +47,7 @@ import {
46
47
  saveConfig,
47
48
  saveConfigPatch,
48
49
  usageError
49
- } from "./chunk-SMFUCXHI.js";
50
+ } from "./chunk-R3GAWKHM.js";
50
51
  import {
51
52
  apiKeys,
52
53
  createClient,
@@ -54,7 +55,7 @@ import {
54
55
  projects,
55
56
  queries,
56
57
  renderReportHtml
57
- } from "./chunk-YVMQWVNY.js";
58
+ } from "./chunk-GO24URVP.js";
58
59
  import {
59
60
  AdsDeliverySnapshotStatuses,
60
61
  AdsHistoricalCampaignRollupStatuses,
@@ -100,7 +101,7 @@ import {
100
101
  providerQuotaPolicySchema,
101
102
  resolveProviderInput,
102
103
  winnabilityClassSchema
103
- } from "./chunk-GGIRLRAY.js";
104
+ } from "./chunk-RJ7OW6W6.js";
104
105
 
105
106
  // src/cli.ts
106
107
  import { pathToFileURL } from "url";
@@ -12394,6 +12395,20 @@ import crypto2 from "crypto";
12394
12395
  import fs13 from "fs";
12395
12396
  import readline from "readline";
12396
12397
  import path10 from "path";
12398
+ var pendingServeHandoff = false;
12399
+ function consumePendingServeHandoff() {
12400
+ const pending = pendingServeHandoff;
12401
+ pendingServeHandoff = false;
12402
+ return pending;
12403
+ }
12404
+ async function promptProviderApiKey(label, envVar, promptFn = prompt, env = process.env) {
12405
+ const fromEnv = env[envVar]?.trim();
12406
+ if (fromEnv) {
12407
+ const answer = await promptFn(`Found ${envVar} in your environment. Use it? [Y/n]: `);
12408
+ if (!/^n/i.test(answer.trim())) return fromEnv;
12409
+ }
12410
+ return promptFn(`${label} API key (press Enter to skip): `);
12411
+ }
12397
12412
  function prompt(question) {
12398
12413
  const rl = readline.createInterface({
12399
12414
  input: process.stdin,
@@ -12500,22 +12515,22 @@ async function initCommand(opts) {
12500
12515
  console.log("GEMINI_API_KEY, OPENAI_API_KEY, ANTHROPIC_API_KEY, PERPLEXITY_API_KEY,");
12501
12516
  console.log("GOOGLE_CLIENT_ID, and GOOGLE_CLIENT_SECRET env vars.");
12502
12517
  console.log('Or use "canonry bootstrap".\n');
12503
- const geminiApiKey = await prompt("Gemini API key (press Enter to skip): ");
12518
+ const geminiApiKey = await promptProviderApiKey("Gemini", "GEMINI_API_KEY");
12504
12519
  if (geminiApiKey) {
12505
12520
  const geminiModel = await prompt(" Gemini model [gemini-2.5-flash]: ") || "gemini-2.5-flash";
12506
12521
  providers.gemini = { apiKey: geminiApiKey, model: geminiModel, quota: DEFAULT_QUOTA };
12507
12522
  }
12508
- const openaiApiKey = await prompt("OpenAI API key (press Enter to skip): ");
12523
+ const openaiApiKey = await promptProviderApiKey("OpenAI", "OPENAI_API_KEY");
12509
12524
  if (openaiApiKey) {
12510
12525
  const openaiModel = await prompt(" OpenAI model [gpt-4o]: ") || "gpt-4o";
12511
12526
  providers.openai = { apiKey: openaiApiKey, model: openaiModel, quota: DEFAULT_QUOTA };
12512
12527
  }
12513
- const claudeApiKey = await prompt("Anthropic API key (press Enter to skip): ");
12528
+ const claudeApiKey = await promptProviderApiKey("Anthropic", "ANTHROPIC_API_KEY");
12514
12529
  if (claudeApiKey) {
12515
12530
  const claudeModel = await prompt(" Claude model [claude-sonnet-4-6]: ") || "claude-sonnet-4-6";
12516
12531
  providers.claude = { apiKey: claudeApiKey, model: claudeModel, quota: DEFAULT_QUOTA };
12517
12532
  }
12518
- const perplexityApiKey = await prompt("Perplexity API key (press Enter to skip): ");
12533
+ const perplexityApiKey = await promptProviderApiKey("Perplexity", "PERPLEXITY_API_KEY");
12519
12534
  if (perplexityApiKey) {
12520
12535
  const perplexityModel = await prompt(" Perplexity model [sonar]: ") || "sonar";
12521
12536
  providers.perplexity = { apiKey: perplexityApiKey, model: perplexityModel, quota: DEFAULT_QUOTA };
@@ -12684,16 +12699,39 @@ ${mcpTip}`);
12684
12699
  console.log(` ${line}`);
12685
12700
  }
12686
12701
  }
12687
- trackEvent("cli.init", {
12688
- providerCount: providerNames.length,
12689
- providers: providerNames,
12690
- setupState: encodeSetupState({
12691
- hasProvider: !!hasProvider,
12692
- hasGoogle: !!google,
12693
- hasAgent: !!agentLLM
12694
- }),
12695
- skillsInstalled: !!skillsSummary
12696
- });
12702
+ if (isTelemetryEnabled()) {
12703
+ const postInitSetupState = buildSetupState();
12704
+ trackEvent("cli.init", {
12705
+ providerCount: providerNames.length,
12706
+ providers: providerNames,
12707
+ ...postInitSetupState ? {
12708
+ setup_state: {
12709
+ ...postInitSetupState,
12710
+ // This snapshot represents a successfully completed init. The
12711
+ // anonymous ID is persisted inside trackEvent immediately after
12712
+ // properties are composed, so override the pre-send read here.
12713
+ is_first_run: false
12714
+ }
12715
+ } : {},
12716
+ googleConfigured: !!google,
12717
+ agentConfigured: !!agentLLM,
12718
+ // Deprecated compact field retained while existing telemetry reports
12719
+ // migrate to the structured setup_state object.
12720
+ setupState: encodeLegacySetupState({
12721
+ hasProvider: !!hasProvider,
12722
+ hasGoogle: !!google,
12723
+ hasAgent: !!agentLLM
12724
+ }),
12725
+ skillsInstalled: !!skillsSummary
12726
+ });
12727
+ }
12728
+ if (!isMachineFormat(format) && process.stdin.isTTY && process.stdout.isTTY) {
12729
+ const answer = await prompt("\nStart the dashboard now? [Y/n]: ");
12730
+ if (!/^n/i.test(answer.trim())) {
12731
+ pendingServeHandoff = true;
12732
+ console.log("Handing off to the dashboard. Finish setup at /setup once it is up.");
12733
+ }
12734
+ }
12697
12735
  return agentLLM;
12698
12736
  }
12699
12737
  function buildNextSteps() {
@@ -12716,7 +12754,7 @@ function buildNextSteps() {
12716
12754
  'Tip: "canonry doctor" verifies your setup before you start.'
12717
12755
  ];
12718
12756
  }
12719
- function encodeSetupState(state) {
12757
+ function encodeLegacySetupState(state) {
12720
12758
  const flags = [];
12721
12759
  if (state.hasProvider) flags.push("provider");
12722
12760
  if (state.hasGoogle) flags.push("google");
@@ -15340,6 +15378,25 @@ var REGISTERED_CLI_COMMANDS = [
15340
15378
  ...MCP_CLI_COMMANDS
15341
15379
  ];
15342
15380
 
15381
+ // src/setup-nudge.ts
15382
+ var NUDGE_EXEMPT_ROOTS = /* @__PURE__ */ new Set([
15383
+ "init",
15384
+ "serve",
15385
+ "bootstrap",
15386
+ "settings",
15387
+ "telemetry",
15388
+ "unknown"
15389
+ ]);
15390
+ function buildSetupNudgeLine(input) {
15391
+ if (input.machineFormat || !input.stderrIsTTY) return null;
15392
+ const [root = input.command] = input.command.split(".");
15393
+ if (NUDGE_EXEMPT_ROOTS.has(root)) return null;
15394
+ const setupState = input.getSetupState();
15395
+ if (!setupState) return null;
15396
+ if (setupState.provider_count > 0) return null;
15397
+ return "\n\u2192 No AI provider is configured, so answer sweeps cannot run yet.\n Finish setup in the dashboard: canonry serve\n Or by CLI: canonry settings provider gemini --api-key <key>\n";
15398
+ }
15399
+
15343
15400
  // src/cli.ts
15344
15401
  import { createRequire as createRequire2 } from "module";
15345
15402
  var USAGE6 = `
@@ -15406,6 +15463,45 @@ function extractFormat(cmdArgs) {
15406
15463
  if (value === "jsonl") return "jsonl";
15407
15464
  return "text";
15408
15465
  }
15466
+ function resolveCommandIdentifier(args, specs) {
15467
+ const spec = [...specs].sort((a, b) => b.path.length - a.path.length).find(
15468
+ (candidate) => candidate.path.every((segment, index) => args[index] === segment)
15469
+ );
15470
+ return spec?.path.join(".") ?? "unknown";
15471
+ }
15472
+ var TELEMETRY_ERROR_CODES = /* @__PURE__ */ new Set([
15473
+ "NOT_FOUND",
15474
+ "ALREADY_EXISTS",
15475
+ "VALIDATION_ERROR",
15476
+ "AUTH_REQUIRED",
15477
+ "AUTH_INVALID",
15478
+ "FORBIDDEN",
15479
+ "QUOTA_EXCEEDED",
15480
+ "PROVIDER_ERROR",
15481
+ "NO_PROVIDER",
15482
+ "NO_QUERIES",
15483
+ "RUN_IN_PROGRESS",
15484
+ "OPERATION_IN_PROGRESS",
15485
+ "UNSUPPORTED_KIND",
15486
+ "RUN_NOT_CANCELLABLE",
15487
+ "NOT_IMPLEMENTED",
15488
+ "INTERNAL_ERROR",
15489
+ "DELIVERY_FAILED",
15490
+ "AGENT_BUSY",
15491
+ "MISSING_DEPENDENCY",
15492
+ "RUNTIME_STATE_MISSING",
15493
+ "API_ERROR",
15494
+ "CLI_ERROR",
15495
+ "CLI_USAGE_ERROR",
15496
+ "CLI_SYSTEM_ERROR",
15497
+ "CONNECTION_ERROR",
15498
+ "UNEXPECTED_RESPONSE_FORMAT"
15499
+ ]);
15500
+ function telemetryErrorCode(err) {
15501
+ if (!(err instanceof CliError)) return "CLI_ERROR";
15502
+ if (TELEMETRY_ERROR_CODES.has(err.code)) return err.code;
15503
+ return typeof err.details?.httpStatus === "number" ? "API_ERROR" : "CLI_ERROR";
15504
+ }
15409
15505
  async function runCli(args = process.argv.slice(2)) {
15410
15506
  if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
15411
15507
  console.log(USAGE6);
@@ -15422,20 +15518,10 @@ async function runCli(args = process.argv.slice(2)) {
15422
15518
  showFirstRunNotice();
15423
15519
  getOrCreateAnonymousId();
15424
15520
  }
15425
- const SUBCOMMAND_COMMANDS = /* @__PURE__ */ new Set(["backfill", "project", "query", "keyword", "competitor", "schedule", "notify", "settings", "telemetry", "google", "bing", "wordpress", "cdp", "traffic"]);
15426
- const MIXED_SUBCOMMANDS = {
15427
- insights: /* @__PURE__ */ new Set(["dismiss"]),
15428
- run: /* @__PURE__ */ new Set(["show", "cancel"])
15429
- };
15430
- let resolvedCommand;
15431
- if (SUBCOMMAND_COMMANDS.has(command) && args[1] && !args[1].startsWith("-")) {
15432
- resolvedCommand = `${command}.${args[1]}`;
15433
- } else if (MIXED_SUBCOMMANDS[command] && args[1] && MIXED_SUBCOMMANDS[command].has(args[1])) {
15434
- resolvedCommand = `${command}.${args[1]}`;
15435
- } else {
15436
- resolvedCommand = command;
15437
- }
15438
- if (!isHelpRequest && command !== "telemetry") {
15521
+ const resolvedCommand = resolveCommandIdentifier(args, REGISTERED_CLI_COMMANDS);
15522
+ const shouldTrackCommand = !isHelpRequest && command !== "telemetry" && isTelemetryEnabled();
15523
+ const shouldTrackCommandStart = shouldTrackCommand && command !== "init";
15524
+ if (shouldTrackCommandStart) {
15439
15525
  detectAndTrackUpgrade();
15440
15526
  const setupState = buildSetupState();
15441
15527
  trackEvent("cli.command", {
@@ -15455,8 +15541,27 @@ async function runCli(args = process.argv.slice(2)) {
15455
15541
  );
15456
15542
  });
15457
15543
  }
15544
+ const commandStartedAt = Date.now();
15458
15545
  try {
15459
15546
  if (await dispatchRegisteredCommand(args, format, REGISTERED_CLI_COMMANDS)) {
15547
+ if (shouldTrackCommand) {
15548
+ trackCliCommandFinished({
15549
+ command: resolvedCommand,
15550
+ success: true,
15551
+ durationMs: Date.now() - commandStartedAt,
15552
+ setupState: buildSetupState()
15553
+ });
15554
+ }
15555
+ const nudge = buildSetupNudgeLine({
15556
+ command: resolvedCommand,
15557
+ machineFormat: isMachineFormat(format),
15558
+ stderrIsTTY: Boolean(process.stderr.isTTY),
15559
+ getSetupState: buildSetupState
15560
+ });
15561
+ if (nudge) process.stderr.write(nudge);
15562
+ if (consumePendingServeHandoff()) {
15563
+ await serveCommand(format);
15564
+ }
15460
15565
  return 0;
15461
15566
  }
15462
15567
  throw usageError(`Error: unknown command: ${command}
@@ -15468,6 +15573,15 @@ Run "cnry --help" for usage.`, {
15468
15573
  }
15469
15574
  });
15470
15575
  } catch (err) {
15576
+ if (shouldTrackCommand && command !== "init") {
15577
+ trackCliCommandFinished({
15578
+ command: resolvedCommand,
15579
+ success: false,
15580
+ durationMs: Date.now() - commandStartedAt,
15581
+ setupState: buildSetupState(),
15582
+ errorCode: telemetryErrorCode(err)
15583
+ });
15584
+ }
15471
15585
  printCliError(err, format);
15472
15586
  return err instanceof CliError ? err.exitCode : EXIT_SYSTEM_ERROR;
15473
15587
  }
package/dist/index.d.ts CHANGED
@@ -232,6 +232,8 @@ interface CanonryConfig {
232
232
  telemetry?: boolean;
233
233
  anonymousId?: string;
234
234
  lastSeenVersion?: string;
235
+ /** Set once when the first-activation notice has been shown; never unset. */
236
+ activationNoticeShown?: boolean;
235
237
  updateCheck?: boolean;
236
238
  lastUpdateCheckAt?: string;
237
239
  lastKnownLatestVersion?: string;
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-MXR3GI5L.js";
3
+ } from "./chunk-3KGJ7BXW.js";
4
4
  import {
5
5
  loadConfig
6
- } from "./chunk-SMFUCXHI.js";
7
- import "./chunk-YVMQWVNY.js";
8
- import "./chunk-GGIRLRAY.js";
6
+ } from "./chunk-R3GAWKHM.js";
7
+ import "./chunk-GO24URVP.js";
8
+ import "./chunk-RJ7OW6W6.js";
9
9
  export {
10
10
  createServer,
11
11
  loadConfig
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-YVMQWVNY.js";
4
- import "./chunk-GGIRLRAY.js";
3
+ } from "./chunk-GO24URVP.js";
4
+ import "./chunk-RJ7OW6W6.js";
5
5
  export {
6
6
  IntelligenceService
7
7
  };
package/dist/mcp.js CHANGED
@@ -3,10 +3,10 @@ import {
3
3
  PACKAGE_VERSION,
4
4
  canonryMcpTools,
5
5
  createApiClient
6
- } from "./chunk-SMFUCXHI.js";
6
+ } from "./chunk-R3GAWKHM.js";
7
7
  import {
8
8
  isReadOnlyKey
9
- } from "./chunk-GGIRLRAY.js";
9
+ } from "./chunk-RJ7OW6W6.js";
10
10
 
11
11
  // src/mcp/cli.ts
12
12
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonry/canonry",
3
- "version": "4.136.2",
3
+ "version": "4.138.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",
@@ -68,24 +68,24 @@
68
68
  "@ainyc/canonry-api-client": "0.0.0",
69
69
  "@ainyc/canonry-api-routes": "0.0.0",
70
70
  "@ainyc/canonry-config": "0.0.0",
71
- "@ainyc/canonry-contracts": "0.0.0",
72
71
  "@ainyc/canonry-db": "0.0.0",
73
72
  "@ainyc/canonry-integration-bing": "0.0.0",
74
- "@ainyc/canonry-integration-cloud-run": "0.0.0",
75
73
  "@ainyc/canonry-integration-openai-ads": "0.0.0",
76
- "@ainyc/canonry-integration-commoncrawl": "0.0.0",
77
- "@ainyc/canonry-integration-google-places": "0.0.0",
78
- "@ainyc/canonry-integration-google-business-profile": "0.0.0",
74
+ "@ainyc/canonry-contracts": "0.0.0",
75
+ "@ainyc/canonry-integration-cloud-run": "0.0.0",
79
76
  "@ainyc/canonry-integration-google": "0.0.0",
80
77
  "@ainyc/canonry-integration-traffic": "0.0.0",
81
- "@ainyc/canonry-provider-cdp": "0.0.0",
78
+ "@ainyc/canonry-integration-google-places": "0.0.0",
79
+ "@ainyc/canonry-integration-google-business-profile": "0.0.0",
80
+ "@ainyc/canonry-integration-commoncrawl": "0.0.0",
82
81
  "@ainyc/canonry-integration-wordpress": "0.0.0",
83
- "@ainyc/canonry-provider-claude": "0.0.0",
84
82
  "@ainyc/canonry-intelligence": "0.0.0",
85
- "@ainyc/canonry-provider-openai": "0.0.0",
86
- "@ainyc/canonry-provider-gemini": "0.0.0",
83
+ "@ainyc/canonry-provider-cdp": "0.0.0",
84
+ "@ainyc/canonry-provider-claude": "0.0.0",
87
85
  "@ainyc/canonry-provider-local": "0.0.0",
88
- "@ainyc/canonry-provider-perplexity": "0.0.0"
86
+ "@ainyc/canonry-provider-gemini": "0.0.0",
87
+ "@ainyc/canonry-provider-perplexity": "0.0.0",
88
+ "@ainyc/canonry-provider-openai": "0.0.0"
89
89
  },
90
90
  "scripts": {
91
91
  "build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",