@ainyc/canonry 4.100.1 → 4.102.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 (24) hide show
  1. package/README.md +4 -1
  2. package/assets/assets/{BacklinksPage-v2RC8wlg.js → BacklinksPage-lXt19SLR.js} +1 -1
  3. package/assets/assets/{ChartPrimitives-B74e5pqn.js → ChartPrimitives-C-sLgrDV.js} +1 -1
  4. package/assets/assets/ProjectPage-wtvaWIRA.js +7 -0
  5. package/assets/assets/{RunRow-BmVPjO-m.js → RunRow-Db32k-uH.js} +1 -1
  6. package/assets/assets/{RunsPage-CK5atXvL.js → RunsPage-DwW3Mely.js} +1 -1
  7. package/assets/assets/{SettingsPage-DarPFUPl.js → SettingsPage-gXn6OGsu.js} +1 -1
  8. package/assets/assets/{TrafficPage-Ddnn_WqU.js → TrafficPage-I49ci4gj.js} +1 -1
  9. package/assets/assets/{TrafficSourceDetailPage-g08SKnwZ.js → TrafficSourceDetailPage-BCvLztx9.js} +1 -1
  10. package/assets/assets/{arrow-left-D39Vxasb.js → arrow-left-BpA06YY0.js} +1 -1
  11. package/assets/assets/{extract-error-message-BiNWqBeh.js → extract-error-message-BZSIQ5iV.js} +1 -1
  12. package/assets/assets/{index-Dd4J1VhB.js → index-DSSLug80.js} +64 -64
  13. package/assets/assets/{trash-2-xh6gsnap.js → trash-2-CLkUNdvb.js} +1 -1
  14. package/assets/index.html +1 -1
  15. package/dist/{chunk-IDI6LMYL.js → chunk-2FUODJQR.js} +6 -2
  16. package/dist/{chunk-ALJSES3X.js → chunk-3PVCILSN.js} +565 -51
  17. package/dist/{chunk-YBIT5O62.js → chunk-B2H2RRIT.js} +927 -614
  18. package/dist/{chunk-JF7EXHGA.js → chunk-EOQXB63S.js} +30 -2
  19. package/dist/cli.js +44 -11
  20. package/dist/index.js +4 -4
  21. package/dist/{intelligence-service-TWCEKVKZ.js → intelligence-service-RC4BY5HF.js} +2 -2
  22. package/dist/mcp.js +2 -2
  23. package/package.json +10 -10
  24. package/assets/assets/ProjectPage-BCzS7TQn.js +0 -6
@@ -589,6 +589,11 @@ var apiKeyDtoSchema = z4.object({
589
589
  /** First 9 chars of the raw token (`cnry_` + 4 hex). Safe to display. */
590
590
  keyPrefix: z4.string(),
591
591
  scopes: z4.array(z4.string()),
592
+ /**
593
+ * The project this key is scoped to, or `null` for a full-instance key. A
594
+ * scoped key may only read/write its own project (enforced server-side).
595
+ */
596
+ projectId: z4.string().nullable(),
592
597
  /**
593
598
  * Server-derived convenience flag: `true` when this key is read-only (carries
594
599
  * the `read` scope and no write-granting scope), in which case the API rejects
@@ -610,7 +615,13 @@ var createApiKeyRequestSchema = z4.object({
610
615
  * what `canonry init` writes for the root key). When provided it must be a
611
616
  * non-empty list — an empty array would mint a key that can do nothing.
612
617
  */
613
- scopes: z4.array(z4.string()).min(1).optional()
618
+ scopes: z4.array(z4.string()).min(1).optional(),
619
+ /**
620
+ * Bind the new key to a SINGLE project (by project id). Omit for a
621
+ * full-instance key (the default). A scoped key may only read/write that
622
+ * project; the server validates the id exists at creation time.
623
+ */
624
+ projectId: z4.string().optional()
614
625
  });
615
626
  var createdApiKeyDtoSchema = apiKeyDtoSchema.extend({
616
627
  key: z4.string()
@@ -2531,6 +2542,11 @@ var providerMetricSchema = z19.object({
2531
2542
  mentionRate: z19.number(),
2532
2543
  mentionedCount: z19.number().int()
2533
2544
  });
2545
+ var mentionShareBucketMetricSchema = z19.object({
2546
+ rate: z19.number().nullable(),
2547
+ projectMentionSnapshots: z19.number().int().nonnegative(),
2548
+ competitorMentionSnapshots: z19.number().int().nonnegative()
2549
+ });
2534
2550
  var timeBucketSchema = z19.object({
2535
2551
  startDate: z19.string(),
2536
2552
  endDate: z19.string(),
@@ -2540,6 +2556,7 @@ var timeBucketSchema = z19.object({
2540
2556
  queryCount: z19.number().int(),
2541
2557
  mentionRate: z19.number(),
2542
2558
  mentionedCount: z19.number().int(),
2559
+ mentionShare: mentionShareBucketMetricSchema,
2543
2560
  byProvider: z19.record(z19.string(), providerMetricSchema)
2544
2561
  });
2545
2562
  var queryChangeEventSchema = z19.object({
@@ -5372,6 +5389,16 @@ function buildEmbedClientConfig(resolved) {
5372
5389
  return client;
5373
5390
  }
5374
5391
 
5392
+ // ../contracts/src/telemetry.ts
5393
+ var GHOST_TELEMETRY_TEST_LOCATIONS = /* @__PURE__ */ new Set(["nyc", "lax", "chi"]);
5394
+ function isGhostTelemetryEvent(eventName, properties) {
5395
+ if (eventName !== "run.completed" && eventName !== "run.aborted") return false;
5396
+ if (!properties) return false;
5397
+ if (properties.providerCount !== 0) return false;
5398
+ const location = typeof properties.location === "string" ? properties.location.trim().toLowerCase() : "";
5399
+ return GHOST_TELEMETRY_TEST_LOCATIONS.has(location);
5400
+ }
5401
+
5375
5402
  export {
5376
5403
  __export,
5377
5404
  apiKeyDtoSchema,
@@ -5680,5 +5707,6 @@ export {
5680
5707
  splitList,
5681
5708
  parseOriginList,
5682
5709
  frameAncestorsHeaderValue,
5683
- buildEmbedClientConfig
5710
+ buildEmbedClientConfig,
5711
+ isGhostTelemetryEvent
5684
5712
  };
package/dist/cli.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node --import tsx
2
2
  import {
3
+ AERO_TOOL_PROFILES,
3
4
  backfillAiReferralPaths,
4
5
  backfillAiReferralPathsCommand,
5
6
  backfillAnswerMentionsCommand,
@@ -18,6 +19,7 @@ import {
18
19
  getMissingUserSkillsNudge,
19
20
  getOrCreateAnonymousId,
20
21
  installSkills,
22
+ isAeroToolProfile,
21
23
  isFirstRun,
22
24
  isTelemetryEnabled,
23
25
  listAgentProviders,
@@ -27,7 +29,7 @@ import {
27
29
  setTelemetrySource,
28
30
  showFirstRunNotice,
29
31
  trackEvent
30
- } from "./chunk-ALJSES3X.js";
32
+ } from "./chunk-3PVCILSN.js";
31
33
  import {
32
34
  CliError,
33
35
  EXIT_SYSTEM_ERROR,
@@ -44,7 +46,7 @@ import {
44
46
  saveConfig,
45
47
  saveConfigPatch,
46
48
  usageError
47
- } from "./chunk-IDI6LMYL.js";
49
+ } from "./chunk-2FUODJQR.js";
48
50
  import {
49
51
  apiKeys,
50
52
  createClient,
@@ -52,7 +54,7 @@ import {
52
54
  projects,
53
55
  queries,
54
56
  renderReportHtml
55
- } from "./chunk-YBIT5O62.js";
57
+ } from "./chunk-B2H2RRIT.js";
56
58
  import {
57
59
  BacklinkSources,
58
60
  CcReleaseSyncStatuses,
@@ -78,7 +80,7 @@ import {
78
80
  providerQuotaPolicySchema,
79
81
  resolveProviderInput,
80
82
  winnabilityClassSchema
81
- } from "./chunk-JF7EXHGA.js";
83
+ } from "./chunk-EOQXB63S.js";
82
84
 
83
85
  // src/cli.ts
84
86
  import { pathToFileURL } from "url";
@@ -5759,6 +5761,10 @@ async function createApiKey(opts) {
5759
5761
  const body = { name: opts.name };
5760
5762
  const scopes = opts.readOnly ? [READ_ONLY_SCOPE] : explicitScopes;
5761
5763
  if (scopes) body.scopes = scopes;
5764
+ if (opts.project) {
5765
+ const proj = await client.getProject(opts.project);
5766
+ body.projectId = proj.id;
5767
+ }
5762
5768
  const created = await client.createApiKey(body);
5763
5769
  if (isMachineFormat(opts.format)) {
5764
5770
  console.log(JSON.stringify(created, null, 2));
@@ -5770,6 +5776,7 @@ async function createApiKey(opts) {
5770
5776
  console.log(` Prefix: ${created.keyPrefix}`);
5771
5777
  console.log(` Scopes: ${created.scopes.join(", ")}`);
5772
5778
  console.log(` Read-only: ${created.readOnly ? "yes" : "no"}`);
5779
+ console.log(` Project: ${opts.project ?? "(full instance)"}`);
5773
5780
  console.log("\nSave this now \u2014 it will not be shown again.");
5774
5781
  }
5775
5782
  async function showApiKeySelf(format) {
@@ -5805,16 +5812,17 @@ var KEYS_CLI_COMMANDS = [
5805
5812
  },
5806
5813
  {
5807
5814
  path: ["key", "create"],
5808
- usage: "canonry key create --name <name> [--read-only | --scope <s> ...] [--format json]",
5815
+ usage: "canonry key create --name <name> [--read-only | --scope <s> ...] [--project <name>] [--format json]",
5809
5816
  options: {
5810
5817
  name: stringOption(),
5811
5818
  scope: multiStringOption(),
5812
- "read-only": { type: "boolean" }
5819
+ "read-only": { type: "boolean" },
5820
+ project: stringOption()
5813
5821
  },
5814
5822
  run: async (input) => {
5815
5823
  const name = requireStringOption(input, "name", {
5816
5824
  command: "key.create",
5817
- usage: "canonry key create --name <name> [--read-only | --scope <s> ...] [--format json]",
5825
+ usage: "canonry key create --name <name> [--read-only | --scope <s> ...] [--project <name>] [--format json]",
5818
5826
  message: "--name is required"
5819
5827
  });
5820
5828
  const raw = getStringArray(input.values, "scope") ?? [];
@@ -5823,6 +5831,7 @@ var KEYS_CLI_COMMANDS = [
5823
5831
  name,
5824
5832
  scopes: scopes.length > 0 ? scopes : void 0,
5825
5833
  readOnly: getBoolean(input.values, "read-only"),
5834
+ project: getString(input.values, "project"),
5826
5835
  format: input.format
5827
5836
  });
5828
5837
  }
@@ -10554,6 +10563,7 @@ var DEFAULT_AGENT_MODELS = {
10554
10563
  };
10555
10564
  async function initCommand(opts) {
10556
10565
  const format = opts?.format ?? "text";
10566
+ const primaryNextStep = "canonry serve";
10557
10567
  if (!isMachineFormat(format)) {
10558
10568
  console.log("Initializing canonry...\n");
10559
10569
  }
@@ -10754,6 +10764,7 @@ async function initCommand(opts) {
10754
10764
  skillsTip,
10755
10765
  mcp: mcpSummary,
10756
10766
  mcpTip,
10767
+ primaryNextStep,
10757
10768
  nextSteps
10758
10769
  }, null, 2));
10759
10770
  } else {
@@ -10802,6 +10813,7 @@ ${mcpTip}`);
10802
10813
  }
10803
10814
  if (!isMachineFormat(format)) {
10804
10815
  showFirstRunNotice();
10816
+ console.log("\nNext: canonry serve to open the dashboard, or canonry settings provider gemini --api-key <key> to configure Gemini.");
10805
10817
  console.log("\nNext steps:");
10806
10818
  for (const line of nextSteps) {
10807
10819
  console.log(` ${line}`);
@@ -10827,6 +10839,7 @@ function buildNextSteps() {
10827
10839
  "",
10828
10840
  " The wizard walks through project \u2192 queries \u2192 competitors \u2192 first sweep",
10829
10841
  " in 5 guided steps and shows your first results inline.",
10842
+ " For remote/exposed hosts, complete dashboard password setup from loopback first.",
10830
10843
  "",
10831
10844
  "Prefer the terminal? The same flow as CLI commands:",
10832
10845
  "",
@@ -10914,6 +10927,10 @@ Received ${signal}, stopping server...`);
10914
10927
  } else {
10915
10928
  console.log(`
10916
10929
  Canonry server running at ${url}`);
10930
+ console.log(`Open ${url}/setup to finish onboarding and run your first visibility check.`);
10931
+ if (host === "0.0.0.0") {
10932
+ console.log("First-run dashboard password setup is unauthenticated only on loopback; complete setup from this machine first or use a bearer cnry_... key.");
10933
+ }
10917
10934
  console.log("Press Ctrl+C to stop.\n");
10918
10935
  const nudge = getMissingUserSkillsNudge(process.env.HOME);
10919
10936
  if (nudge) process.stderr.write(`${nudge.message}
@@ -12662,7 +12679,8 @@ async function agentAsk(opts) {
12662
12679
  prompt: opts.prompt,
12663
12680
  provider: opts.provider,
12664
12681
  modelId: opts.modelId,
12665
- scope: opts.scope ?? "all"
12682
+ scope: opts.scope ?? "all",
12683
+ ...opts.profile ? { profile: opts.profile } : {}
12666
12684
  },
12667
12685
  controller.signal
12668
12686
  );
@@ -12928,14 +12946,15 @@ var AGENT_ASK_SCOPES = ["all", "read-only"];
12928
12946
  var AGENT_CLI_COMMANDS = [
12929
12947
  {
12930
12948
  path: ["agent", "ask"],
12931
- usage: `canonry agent ask <project> "<prompt>" [--provider ${listAgentProviders().join("|")}] [--model <id>] [--scope all|read-only] [--format json]`,
12949
+ usage: `canonry agent ask <project> "<prompt>" [--provider ${listAgentProviders().join("|")}] [--model <id>] [--scope all|read-only] [--profile default|ads-operator] [--format json]`,
12932
12950
  options: {
12933
12951
  provider: stringOption(),
12934
12952
  model: stringOption(),
12935
- scope: stringOption()
12953
+ scope: stringOption(),
12954
+ profile: stringOption()
12936
12955
  },
12937
12956
  run: async (input) => {
12938
- const usage = `canonry agent ask <project> "<prompt>" [--provider ${listAgentProviders().join("|")}] [--model <id>] [--scope all|read-only] [--format json]`;
12957
+ const usage = `canonry agent ask <project> "<prompt>" [--provider ${listAgentProviders().join("|")}] [--model <id>] [--scope all|read-only] [--profile default|ads-operator] [--format json]`;
12939
12958
  const project = requireProject(input, "agent.ask", usage);
12940
12959
  const prompt2 = input.positionals.slice(1).join(" ").trim();
12941
12960
  if (!prompt2) {
@@ -12974,12 +12993,26 @@ Usage: ${usage}`, {
12974
12993
  }
12975
12994
  });
12976
12995
  }
12996
+ const profileInput = getString(input.values, "profile");
12997
+ if (profileInput && !isAeroToolProfile(profileInput)) {
12998
+ throw usageError(`Error: --profile must be one of: ${AERO_TOOL_PROFILES.join(", ")}
12999
+ Usage: ${usage}`, {
13000
+ message: `--profile must be one of: ${AERO_TOOL_PROFILES.join(", ")}`,
13001
+ details: {
13002
+ command: "agent.ask",
13003
+ usage,
13004
+ profile: profileInput,
13005
+ validProfiles: AERO_TOOL_PROFILES
13006
+ }
13007
+ });
13008
+ }
12977
13009
  await agentAsk({
12978
13010
  project,
12979
13011
  prompt: prompt2,
12980
13012
  provider: coerceAgentProvider(providerInput),
12981
13013
  modelId: getString(input.values, "model"),
12982
13014
  scope: scopeInput,
13015
+ profile: profileInput,
12983
13016
  format: input.format
12984
13017
  });
12985
13018
  }
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-ALJSES3X.js";
3
+ } from "./chunk-3PVCILSN.js";
4
4
  import {
5
5
  loadConfig
6
- } from "./chunk-IDI6LMYL.js";
7
- import "./chunk-YBIT5O62.js";
8
- import "./chunk-JF7EXHGA.js";
6
+ } from "./chunk-2FUODJQR.js";
7
+ import "./chunk-B2H2RRIT.js";
8
+ import "./chunk-EOQXB63S.js";
9
9
  export {
10
10
  createServer,
11
11
  loadConfig
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-YBIT5O62.js";
4
- import "./chunk-JF7EXHGA.js";
3
+ } from "./chunk-B2H2RRIT.js";
4
+ import "./chunk-EOQXB63S.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-IDI6LMYL.js";
6
+ } from "./chunk-2FUODJQR.js";
7
7
  import {
8
8
  isReadOnlyKey
9
- } from "./chunk-JF7EXHGA.js";
9
+ } from "./chunk-EOQXB63S.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": "@ainyc/canonry",
3
- "version": "4.100.1",
3
+ "version": "4.102.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",
@@ -63,32 +63,32 @@
63
63
  "tsup": "^8.5.1",
64
64
  "tsx": "^4.19.0",
65
65
  "@ainyc/canonry-api-client": "0.0.0",
66
+ "@ainyc/canonry-contracts": "0.0.0",
66
67
  "@ainyc/canonry-config": "0.0.0",
67
- "@ainyc/canonry-api-routes": "0.0.0",
68
68
  "@ainyc/canonry-db": "0.0.0",
69
+ "@ainyc/canonry-integration-cloud-run": "0.0.0",
69
70
  "@ainyc/canonry-integration-bing": "0.0.0",
70
71
  "@ainyc/canonry-integration-openai-ads": "0.0.0",
71
- "@ainyc/canonry-contracts": "0.0.0",
72
- "@ainyc/canonry-integration-commoncrawl": "0.0.0",
73
- "@ainyc/canonry-integration-cloud-run": "0.0.0",
74
- "@ainyc/canonry-integration-google-business-profile": "0.0.0",
75
72
  "@ainyc/canonry-integration-google": "0.0.0",
76
- "@ainyc/canonry-integration-traffic": "0.0.0",
73
+ "@ainyc/canonry-integration-google-business-profile": "0.0.0",
77
74
  "@ainyc/canonry-integration-google-places": "0.0.0",
75
+ "@ainyc/canonry-integration-traffic": "0.0.0",
76
+ "@ainyc/canonry-integration-commoncrawl": "0.0.0",
78
77
  "@ainyc/canonry-integration-wordpress": "0.0.0",
78
+ "@ainyc/canonry-api-routes": "0.0.0",
79
79
  "@ainyc/canonry-intelligence": "0.0.0",
80
- "@ainyc/canonry-provider-cdp": "0.0.0",
81
80
  "@ainyc/canonry-provider-claude": "0.0.0",
82
81
  "@ainyc/canonry-provider-local": "0.0.0",
83
- "@ainyc/canonry-provider-gemini": "0.0.0",
84
82
  "@ainyc/canonry-provider-openai": "0.0.0",
83
+ "@ainyc/canonry-provider-gemini": "0.0.0",
84
+ "@ainyc/canonry-provider-cdp": "0.0.0",
85
85
  "@ainyc/canonry-provider-perplexity": "0.0.0"
86
86
  },
87
87
  "scripts": {
88
88
  "build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",
89
89
  "build:web": "tsx build-web.ts",
90
90
  "typecheck": "tsc --noEmit -p tsconfig.json",
91
- "test": "vitest run",
91
+ "test": "vitest run --config ../../vitest.package.config.ts",
92
92
  "lint": "eslint src/ test/"
93
93
  }
94
94
  }