@canonry/canonry 7.25.0 → 7.43.2

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 (41) hide show
  1. package/README.md +3 -2
  2. package/assets/agent-workspace/skills/canonry/references/aeo-analysis.md +24 -0
  3. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +219 -6
  4. package/assets/agent-workspace/skills/canonry/references/server-side-traffic.md +14 -2
  5. package/assets/assets/{AuditHistoryPanel-B-9DLSmD.js → AuditHistoryPanel-C5oZsvsR.js} +1 -1
  6. package/assets/assets/{BacklinksPage-DPssWU5-.js → BacklinksPage-CF5sGSTQ.js} +1 -1
  7. package/assets/assets/{HistoryPage-BAPUoHjI.js → HistoryPage-DumL6cl5.js} +1 -1
  8. package/assets/assets/{MeasurementPropertyPage-aTs5l1OV.js → MeasurementPropertyPage-DCegOp_w.js} +3 -3
  9. package/assets/assets/ProjectPage-CWDk48Y6.js +8 -0
  10. package/assets/assets/RunsPage-Bb1VMWYu.js +1 -0
  11. package/assets/assets/{SettingsPage-Oo861eRm.js → SettingsPage-CHGh169l.js} +1 -1
  12. package/assets/assets/{SiteHealthSection-BMdk3Och.js → SiteHealthSection-bGzH9m9-.js} +3 -3
  13. package/assets/assets/{TrafficPage-Ciot_0lN.js → TrafficPage-cfnEZ2Mu.js} +1 -1
  14. package/assets/assets/{TrafficSourceDetailPage-D7tWadfJ.js → TrafficSourceDetailPage-BQS0MAXE.js} +1 -1
  15. package/assets/assets/{extract-error-message-Bb4azvlK.js → extract-error-message-IWhACkO_.js} +1 -1
  16. package/assets/assets/index-BDY3-V1S.js +86 -0
  17. package/assets/assets/{react-sigma_core.esm.min-C-Y9Z74U.js → react-sigma_core.esm.min-BQt189AI.js} +1 -1
  18. package/assets/assets/{v2-overview-adapter-D2S25ivE.js → v2-overview-adapter-ZC3VuoTT.js} +1 -1
  19. package/assets/index.html +1 -1
  20. package/dist/{chunk-PKQF7BV2.js → chunk-65BHDVYO.js} +5650 -4002
  21. package/dist/{chunk-NOA7KJDB.js → chunk-BPFRGC7K.js} +3 -3
  22. package/dist/{chunk-I3546GTK.js → chunk-BWR5MNL5.js} +2 -2
  23. package/dist/chunk-C2I7M3B2.js +22948 -0
  24. package/dist/{chunk-PFEQWGJN.js → chunk-E43JM3QV.js} +11444 -10397
  25. package/dist/chunk-HGMYEDAQ.js +79 -0
  26. package/dist/{chunk-BMBHREYM.js → chunk-KOIOZ7QW.js} +195 -20
  27. package/dist/{chunk-6AOIFHC6.js → chunk-LYKDNJXR.js} +163 -107
  28. package/dist/chunk-WRUKKEGR.js +562 -0
  29. package/dist/chunk-WU2BRWXY.js +546 -0
  30. package/dist/{chunk-NX257AKC.js → chunk-WXX3NL4C.js} +108 -41
  31. package/dist/cli-catalog-J3O6W726.js +15 -0
  32. package/dist/cli-commands-QST2CPDG.js +15 -0
  33. package/dist/cli.js +136 -22502
  34. package/dist/{demo-server-RUZWYXSW.js → demo-server-KA7DWTY6.js} +5 -4
  35. package/dist/index.js +7 -6
  36. package/dist/{intelligence-service-TYSVXO3S.js → intelligence-service-LHZZTJPH.js} +2 -2
  37. package/dist/mcp.js +30 -15
  38. package/package.json +6 -6
  39. package/assets/assets/ProjectPage-sVY1ETmt.js +0 -8
  40. package/assets/assets/RunsPage-D0q7ifK3.js +0 -1
  41. package/assets/assets/index-ClA5Nf2V.js +0 -86
@@ -0,0 +1,79 @@
1
+ // src/support-links.ts
2
+ var CANONRY_DISCORD_URL = "https://discord.gg/jnJ2H2z5Xh";
3
+ var CANONRY_ISSUES_URL = "https://github.com/Canonry/canonry/issues";
4
+
5
+ // src/cli-error.ts
6
+ function isMachineFormat(format) {
7
+ return format === "json" || format === "jsonl";
8
+ }
9
+ var EXIT_USER_ERROR = 1;
10
+ var EXIT_SYSTEM_ERROR = 2;
11
+ var CliError = class extends Error {
12
+ code;
13
+ displayMessage;
14
+ details;
15
+ exitCode;
16
+ constructor(options) {
17
+ super(options.message);
18
+ this.name = "CliError";
19
+ this.code = options.code;
20
+ this.displayMessage = options.displayMessage;
21
+ this.details = options.details;
22
+ this.exitCode = options.exitCode ?? EXIT_USER_ERROR;
23
+ }
24
+ };
25
+ function usageError(displayMessage, options) {
26
+ const firstLine = displayMessage.split("\n", 1)[0] ?? "Error: invalid command usage";
27
+ return new CliError({
28
+ code: "CLI_USAGE_ERROR",
29
+ message: options?.message ?? firstLine.replace(/^Error:\s*/, ""),
30
+ displayMessage,
31
+ details: options?.details
32
+ });
33
+ }
34
+ function isEndpointMissing(err) {
35
+ if (!(err instanceof CliError)) return false;
36
+ const status = err.details?.httpStatus;
37
+ return status === 404 || status === 405;
38
+ }
39
+ function systemError(message, options) {
40
+ return new CliError({
41
+ code: "CLI_SYSTEM_ERROR",
42
+ message,
43
+ displayMessage: options?.displayMessage,
44
+ details: options?.details,
45
+ exitCode: EXIT_SYSTEM_ERROR
46
+ });
47
+ }
48
+ function printCliError(err, format) {
49
+ if (isMachineFormat(format)) {
50
+ const envelope = err instanceof CliError ? { error: { code: err.code, message: err.message, ...err.details ? { details: err.details } : {} } } : { error: { code: "CLI_ERROR", message: err instanceof Error ? err.message : "An unexpected error occurred" } };
51
+ console.error(JSON.stringify(envelope, null, format === "jsonl" ? 0 : 2));
52
+ return;
53
+ }
54
+ if (err instanceof CliError && err.displayMessage) {
55
+ console.error(err.displayMessage);
56
+ } else if (err instanceof Error) {
57
+ console.error(`Error: ${err.message}`);
58
+ } else {
59
+ console.error("An unexpected error occurred");
60
+ }
61
+ const unexpected = !(err instanceof CliError) || err.exitCode === EXIT_SYSTEM_ERROR;
62
+ if (unexpected && process.stderr.isTTY) {
63
+ console.error(`
64
+ Need help? Run 'canonry support' or ask in the Canonry Discord: ${CANONRY_DISCORD_URL}`);
65
+ }
66
+ }
67
+
68
+ export {
69
+ CANONRY_DISCORD_URL,
70
+ CANONRY_ISSUES_URL,
71
+ isMachineFormat,
72
+ EXIT_USER_ERROR,
73
+ EXIT_SYSTEM_ERROR,
74
+ CliError,
75
+ usageError,
76
+ isEndpointMissing,
77
+ systemError,
78
+ printCliError
79
+ };
@@ -1,11 +1,14 @@
1
+ import {
2
+ PACKAGE_VERSION,
3
+ canonryMcpTools,
4
+ toolOperationAccess
5
+ } from "./chunk-LYKDNJXR.js";
1
6
  import {
2
7
  CliError,
3
8
  EXIT_SYSTEM_ERROR,
4
9
  EXIT_USER_ERROR,
5
- PACKAGE_VERSION,
6
- canonryMcpTools,
7
10
  isMachineFormat
8
- } from "./chunk-6AOIFHC6.js";
11
+ } from "./chunk-HGMYEDAQ.js";
9
12
  import {
10
13
  AGENT_PROVIDER_IDS,
11
14
  CANONRY_NPM_PACKAGE_URL,
@@ -13,8 +16,11 @@ import {
13
16
  DEFAULT_VIEWER_RESEARCH_DAILY_RUN_LIMIT,
14
17
  OPERATIONAL_LOG_FIELDS_HEADER,
15
18
  OPERATIONAL_LOG_OPT_IN_CONTEXT_FIELDS,
19
+ OPERATION_ACCESS_HEADER,
20
+ OperationAccesses,
16
21
  RESEARCH_RUN_SCOPE,
17
22
  SKILL_MANIFEST_FILENAME,
23
+ STORED_ONLY_HEADER,
18
24
  SkillsClients,
19
25
  USAGE_TELEMETRY_HEADERS,
20
26
  agentPluginClientLabel,
@@ -31,8 +37,10 @@ import {
31
37
  isRetiredAgentProviderId,
32
38
  isSensitiveDiagnosticQueryKey,
33
39
  isStrictSemver,
40
+ matchOperationTemplate,
34
41
  normalizeAgentSlug,
35
42
  normalizeTelemetryStatus,
43
+ operationAccess,
36
44
  operationalLogListReadSchema,
37
45
  providerBatchConfigSchema,
38
46
  providerPricingSchema,
@@ -49,7 +57,7 @@ import {
49
57
  skillsClientSchema,
50
58
  upgradeCaveatFor,
51
59
  upgradeCommandFor
52
- } from "./chunk-PFEQWGJN.js";
60
+ } from "./chunk-E43JM3QV.js";
53
61
 
54
62
  // src/config.ts
55
63
  import fs from "fs";
@@ -1505,6 +1513,22 @@ var getApiV1ProjectsByName = (options) => {
1505
1513
  ...options
1506
1514
  });
1507
1515
  };
1516
+ var patchApiV1ProjectsByName = (options) => {
1517
+ return (options.client ?? client).patch({
1518
+ security: [
1519
+ {
1520
+ scheme: "bearer",
1521
+ type: "http"
1522
+ }
1523
+ ],
1524
+ url: "/api/v1/projects/{name}",
1525
+ ...options,
1526
+ headers: {
1527
+ "Content-Type": "application/json",
1528
+ ...options.headers
1529
+ }
1530
+ });
1531
+ };
1508
1532
  var putApiV1ProjectsByName = (options) => {
1509
1533
  return (options.client ?? client).put({
1510
1534
  security: [
@@ -2949,6 +2973,34 @@ var getApiV1ProjectsByNameAnalyticsCompetitors = (options) => {
2949
2973
  ...options
2950
2974
  });
2951
2975
  };
2976
+ var getApiV1ProjectsByNameCompetitorSuggestions = (options) => {
2977
+ return (options.client ?? client).get({
2978
+ security: [
2979
+ {
2980
+ scheme: "bearer",
2981
+ type: "http"
2982
+ }
2983
+ ],
2984
+ url: "/api/v1/projects/{name}/competitor-suggestions",
2985
+ ...options
2986
+ });
2987
+ };
2988
+ var postApiV1ProjectsByNameCompetitorChangesPreview = (options) => {
2989
+ return (options.client ?? client).post({
2990
+ security: [
2991
+ {
2992
+ scheme: "bearer",
2993
+ type: "http"
2994
+ }
2995
+ ],
2996
+ url: "/api/v1/projects/{name}/competitor-changes/preview",
2997
+ ...options,
2998
+ headers: {
2999
+ "Content-Type": "application/json",
3000
+ ...options.headers
3001
+ }
3002
+ });
3003
+ };
2952
3004
  var getApiV1ProjectsByNameRuns = (options) => {
2953
3005
  return (options.client ?? client).get({
2954
3006
  security: [
@@ -3057,6 +3109,22 @@ var postApiV1Apply = (options) => {
3057
3109
  }
3058
3110
  });
3059
3111
  };
3112
+ var postApiV1ApplyPreview = (options) => {
3113
+ return (options.client ?? client).post({
3114
+ security: [
3115
+ {
3116
+ scheme: "bearer",
3117
+ type: "http"
3118
+ }
3119
+ ],
3120
+ url: "/api/v1/apply/preview",
3121
+ ...options,
3122
+ headers: {
3123
+ "Content-Type": "application/json",
3124
+ ...options.headers
3125
+ }
3126
+ });
3127
+ };
3060
3128
  var getApiV1ProjectsByNameHistory = (options) => {
3061
3129
  return (options.client ?? client).get({
3062
3130
  security: [
@@ -5245,6 +5313,18 @@ var getApiV1ProjectsByNameGaProperties = (options) => {
5245
5313
  ...options
5246
5314
  });
5247
5315
  };
5316
+ var getApiV1ProjectsByNameGaAcquisition = (options) => {
5317
+ return (options.client ?? client).get({
5318
+ security: [
5319
+ {
5320
+ scheme: "bearer",
5321
+ type: "http"
5322
+ }
5323
+ ],
5324
+ url: "/api/v1/projects/{name}/ga/acquisition",
5325
+ ...options
5326
+ });
5327
+ };
5248
5328
  var getApiV1ProjectsByNameGaMeasurementAnalysis = (options) => {
5249
5329
  return (options.client ?? client).get({
5250
5330
  security: [
@@ -5629,6 +5709,18 @@ var getApiV1Doctor = (options) => {
5629
5709
  ...options
5630
5710
  });
5631
5711
  };
5712
+ var getApiV1Status = (options) => {
5713
+ return (options?.client ?? client).get({
5714
+ security: [
5715
+ {
5716
+ scheme: "bearer",
5717
+ type: "http"
5718
+ }
5719
+ ],
5720
+ url: "/api/v1/status",
5721
+ ...options
5722
+ });
5723
+ };
5632
5724
  var getApiV1ProjectsByNameDoctor = (options) => {
5633
5725
  return (options.client ?? client).get({
5634
5726
  security: [
@@ -5977,6 +6069,18 @@ var getApiV1ProjectsByNameTrafficReferralAssessment = (options) => {
5977
6069
  ...options
5978
6070
  });
5979
6071
  };
6072
+ var getApiV1ProjectsByNameTrafficSamples = (options) => {
6073
+ return (options.client ?? client).get({
6074
+ security: [
6075
+ {
6076
+ scheme: "bearer",
6077
+ type: "http"
6078
+ }
6079
+ ],
6080
+ url: "/api/v1/projects/{name}/traffic/samples",
6081
+ ...options
6082
+ });
6083
+ };
5980
6084
  var getApiV1ProjectsByNameTrafficEvents = (options) => {
5981
6085
  return (options.client ?? client).get({
5982
6086
  security: [
@@ -6477,6 +6581,30 @@ function runWithUsageTags(client2, tags, fn) {
6477
6581
  if (!(client2 instanceof ApiClient)) return fn();
6478
6582
  return usageTagStore.run(tags, fn);
6479
6583
  }
6584
+ function classifyStoredOnlyRequest(method, url) {
6585
+ const operation = matchOperationTemplate(method, url);
6586
+ const separator = operation.indexOf(" ");
6587
+ return {
6588
+ operation,
6589
+ access: operationAccess(operation.slice(0, separator), operation.slice(separator + 1), OperationAccesses.live)
6590
+ };
6591
+ }
6592
+ function storedOnlyRequestHeaders(method, url) {
6593
+ if (!["1", "true"].includes((process.env.CANONRY_STORED_ONLY ?? "").toLowerCase())) return {};
6594
+ const { operation, access } = classifyStoredOnlyRequest(method, url);
6595
+ if (access !== OperationAccesses.stored) {
6596
+ throw new CliError({
6597
+ code: "STORED_ONLY_REFUSED",
6598
+ message: `Stored-only mode refuses ${access} operation ${operation}`,
6599
+ details: { operation, access },
6600
+ exitCode: EXIT_USER_ERROR
6601
+ });
6602
+ }
6603
+ return { [STORED_ONLY_HEADER]: "1" };
6604
+ }
6605
+ function storedOnlyProbeHeaders() {
6606
+ return ["1", "true"].includes((process.env.CANONRY_STORED_ONLY ?? "").toLowerCase()) ? { [STORED_ONLY_HEADER]: "1" } : {};
6607
+ }
6480
6608
  var SAFE_CLIENT_NAME = /^\w[\w./-]{0,127}$/;
6481
6609
  var SAFE_ACTOR_SESSION = /^\w[\w.:-]{0,127}$/;
6482
6610
  function safeClientName(value) {
@@ -6548,6 +6676,7 @@ var ApiClient = class {
6548
6676
  };
6549
6677
  this.heyClient = createClient2({ baseUrl: this.originUrl, apiKey: this.apiKey, headers: this.requestHeaders });
6550
6678
  this.heyClient.interceptors.request.use((request) => {
6679
+ for (const [key, value] of Object.entries(storedOnlyRequestHeaders(request.method, request.url.toString()))) request.headers.set(key, value);
6551
6680
  const tags = usageTagStore.getStore();
6552
6681
  if (tags?.mcpTool) request.headers.set(USAGE_TELEMETRY_HEADERS.mcpTool, tags.mcpTool);
6553
6682
  if (tags?.mcpCall) request.headers.set(USAGE_TELEMETRY_HEADERS.mcpCall, tags.mcpCall);
@@ -6569,6 +6698,7 @@ var ApiClient = class {
6569
6698
  try {
6570
6699
  const origin = new URL(this.originUrl).origin;
6571
6700
  const res = await fetch(`${origin}/health`, {
6701
+ headers: storedOnlyProbeHeaders(),
6572
6702
  signal: AbortSignal.timeout(2e3)
6573
6703
  });
6574
6704
  if (res.ok) {
@@ -6626,7 +6756,7 @@ var ApiClient = class {
6626
6756
  if (traceEnabled) {
6627
6757
  const durMs = Date.now() - traceStart;
6628
6758
  process.stderr.write(
6629
- `[trace] ${result.request.method} ${redactRequestTarget(result.request.url)} \u2192 ${result.response.status} (${durMs}ms)
6759
+ `[trace] ${result.request.method} ${redactRequestTarget(result.request.url)} \u2192 ${result.response.status} (${durMs}ms) access=${result.response.headers.get(OPERATION_ACCESS_HEADER) ?? "unknown"}
6630
6760
  `
6631
6761
  );
6632
6762
  }
@@ -6729,10 +6859,13 @@ var ApiClient = class {
6729
6859
  * and releases the response when done.
6730
6860
  */
6731
6861
  async streamPost(path3, body, signal) {
6862
+ const candidateUrl = `${this.originUrl}/api/v1${path3}`;
6863
+ const storedOnlyHeaders = storedOnlyRequestHeaders("POST", candidateUrl);
6732
6864
  await this.probeBasePath();
6733
6865
  const url = `${this.originUrl}/api/v1${path3}`;
6734
6866
  const headers = {
6735
6867
  ...this.requestHeaders,
6868
+ ...storedOnlyHeaders,
6736
6869
  "Content-Type": "application/json",
6737
6870
  Accept: "text/event-stream"
6738
6871
  };
@@ -6772,6 +6905,11 @@ var ApiClient = class {
6772
6905
  () => putApiV1ProjectsByName({ client: this.heyClient, path: { name }, body })
6773
6906
  );
6774
6907
  }
6908
+ async patchProject(name, body) {
6909
+ return this.invoke(
6910
+ () => patchApiV1ProjectsByName({ client: this.heyClient, path: { name }, body })
6911
+ );
6912
+ }
6775
6913
  async listProjects() {
6776
6914
  return this.invoke(() => getApiV1Projects({ client: this.heyClient }));
6777
6915
  }
@@ -6786,19 +6924,26 @@ var ApiClient = class {
6786
6924
  () => getApiV1ProjectsByNameDeletePreview({ client: this.heyClient, path: { name } })
6787
6925
  );
6788
6926
  }
6789
- async getStatus(project) {
6927
+ async getStatus(opts) {
6790
6928
  return this.invoke(
6791
- () => getApiV1ProjectsByName({ client: this.heyClient, path: { name: project } })
6929
+ () => getApiV1Status({ client: this.heyClient, query: { project: opts?.project, problems: opts?.problems } })
6792
6930
  );
6793
6931
  }
6794
- async getExport(project) {
6932
+ async getExport(project, opts) {
6795
6933
  return this.invoke(
6796
- () => getApiV1ProjectsByNameExport({ client: this.heyClient, path: { name: project } })
6934
+ () => getApiV1ProjectsByNameExport({
6935
+ client: this.heyClient,
6936
+ path: { name: project },
6937
+ query: { includeSecrets: opts?.includeSecrets }
6938
+ })
6797
6939
  );
6798
6940
  }
6799
6941
  async apply(config) {
6800
6942
  return this.invoke(() => postApiV1Apply({ client: this.heyClient, body: config }));
6801
6943
  }
6944
+ async previewApply(config) {
6945
+ return this.invoke(() => postApiV1ApplyPreview({ client: this.heyClient, body: config }));
6946
+ }
6802
6947
  async getProjectOverview(project, opts) {
6803
6948
  return this.invoke(
6804
6949
  () => getApiV1ProjectsByNameOverview({
@@ -6834,10 +6979,11 @@ var ApiClient = class {
6834
6979
  if (opts.until) params.set("until", opts.until);
6835
6980
  if (opts.includeProbes) params.set("includeProbes", "true");
6836
6981
  const url = `${this.originUrl}/api/v1/projects/${encodeURIComponent(project)}/results/export?${params.toString()}`;
6982
+ const storedOnlyHeaders = storedOnlyRequestHeaders("GET", url);
6837
6983
  let res;
6838
6984
  try {
6839
6985
  res = await fetch(url, {
6840
- headers: { ...this.requestHeaders }
6986
+ headers: { ...this.requestHeaders, ...storedOnlyHeaders }
6841
6987
  });
6842
6988
  } catch (err) {
6843
6989
  const message = describeError(err);
@@ -6892,8 +7038,9 @@ var ApiClient = class {
6892
7038
  () => deleteApiV1ProjectsByNameQueries({ client: this.heyClient, path: { name: project }, body: { queries } })
6893
7039
  );
6894
7040
  }
7041
+ /** Appends (existing texts are skipped) and returns the project's full query list, each row with its `queryClass`. */
6895
7042
  async appendQueries(project, queries) {
6896
- await this.invoke(
7043
+ return this.invoke(
6897
7044
  () => postApiV1ProjectsByNameQueries({ client: this.heyClient, path: { name: project }, body: { queries } })
6898
7045
  );
6899
7046
  }
@@ -6940,13 +7087,27 @@ var ApiClient = class {
6940
7087
  () => getApiV1ProjectsByNameCompetitors({ client: this.heyClient, path: { name: project } })
6941
7088
  );
6942
7089
  }
7090
+ async suggestCompetitors(project, query = {}) {
7091
+ return this.invoke(
7092
+ () => getApiV1ProjectsByNameCompetitorSuggestions({
7093
+ client: this.heyClient,
7094
+ path: { name: project },
7095
+ query
7096
+ })
7097
+ );
7098
+ }
7099
+ async previewCompetitorChange(project, request) {
7100
+ return this.invoke(
7101
+ () => postApiV1ProjectsByNameCompetitorChangesPreview({ client: this.heyClient, path: { name: project }, body: request })
7102
+ );
7103
+ }
6943
7104
  /** Each entry is a domain or `{ domain, aliases }`; stated aliases are added to that competitor's list. */
6944
- async appendCompetitors(project, competitors) {
7105
+ async appendCompetitors(project, competitors, options) {
6945
7106
  return this.invoke(
6946
7107
  () => postApiV1ProjectsByNameCompetitors({
6947
7108
  client: this.heyClient,
6948
7109
  path: { name: project },
6949
- body: { competitors }
7110
+ body: { competitors, ...options?.acknowledgeBulkAdd !== void 0 ? { acknowledgeBulkAdd: options.acknowledgeBulkAdd } : {} }
6950
7111
  })
6951
7112
  );
6952
7113
  }
@@ -7518,13 +7679,13 @@ var ApiClient = class {
7518
7679
  })
7519
7680
  );
7520
7681
  }
7521
- async listRuns(project, limit, kind, status, excludeKind, excludeKinds) {
7682
+ async listRuns(project, limit, kind, status, excludeKind, excludeKinds, since) {
7522
7683
  return this.invoke(
7523
7684
  () => getApiV1ProjectsByNameRuns({
7524
7685
  client: this.heyClient,
7525
7686
  path: { name: project },
7526
7687
  // Filters arrive as free CLI strings; the server validates them against the enums.
7527
- query: { limit, kind, status, excludeKind, excludeKinds }
7688
+ query: { limit, kind, status, excludeKind, excludeKinds, since }
7528
7689
  })
7529
7690
  );
7530
7691
  }
@@ -7640,6 +7801,7 @@ var ApiClient = class {
7640
7801
  * never run the CLI about a newer release.
7641
7802
  */
7642
7803
  async getServerUpdateAvailable() {
7804
+ if (storedOnlyProbeHeaders()[STORED_ONLY_HEADER]) return null;
7643
7805
  try {
7644
7806
  await this.probeBasePath();
7645
7807
  const res = await fetch(`${this.originUrl}/health`, { signal: AbortSignal.timeout(2e3) });
@@ -8652,6 +8814,9 @@ var ApiClient = class {
8652
8814
  () => getApiV1ProjectsByNameGaProperties({ client: this.heyClient, path: { name: project } })
8653
8815
  );
8654
8816
  }
8817
+ async gaAcquisition(project, query) {
8818
+ return this.invoke(() => getApiV1ProjectsByNameGaAcquisition({ client: this.heyClient, path: { name: project }, query }));
8819
+ }
8655
8820
  async gaMeasurementAnalysis(project, params) {
8656
8821
  return this.invoke(
8657
8822
  () => getApiV1ProjectsByNameGaMeasurementAnalysis({
@@ -8851,6 +9016,9 @@ var ApiClient = class {
8851
9016
  query
8852
9017
  }));
8853
9018
  }
9019
+ async trafficListSamples(project, query) {
9020
+ return this.invoke(() => getApiV1ProjectsByNameTrafficSamples({ client: this.heyClient, path: { name: project }, query }));
9021
+ }
8854
9022
  async trafficListEvents(project, params) {
8855
9023
  return this.invoke(
8856
9024
  () => getApiV1ProjectsByNameTrafficEvents({
@@ -9883,6 +10051,7 @@ var DynamicToolCatalog = class {
9883
10051
  eager: this.eager,
9884
10052
  loadedToolkits: [...this.loaded].sort(),
9885
10053
  coreTools: this.entries.filter((entry) => entry.tool.tier === "core").map((entry) => entry.tool.name),
10054
+ liveTools: this.entries.filter((entry) => entry.tool.tier === "core" && toolOperationAccess(entry.tool) === OperationAccesses.live).map((entry) => entry.tool.name),
9886
10055
  toolkits: CANONRY_MCP_TOOLKITS.map((toolkit) => this.toolkitEntry(toolkit)).filter((entry) => entry.toolCount > 0),
9887
10056
  usage: this.eager ? "All tools available on this connection are already loaded. Use their listed schemas; tool visibility does not grant server permissions." : "Call canonry_load_toolkit with one of the toolkit names listed in `toolkits[].name` to register its tools for the rest of this session. Wait for its response before calling any newly enabled tool."
9888
10057
  };
@@ -9896,6 +10065,7 @@ var DynamicToolCatalog = class {
9896
10065
  whenToLoad: toolkit.whenToLoad,
9897
10066
  toolCount: tools.length,
9898
10067
  tools,
10068
+ liveTools: this.entries.filter((entry) => entry.tool.tier === toolkit.name && toolOperationAccess(entry.tool) === OperationAccesses.live).map((entry) => entry.tool.name),
9899
10069
  loaded: this.loaded.has(toolkit.name)
9900
10070
  };
9901
10071
  }
@@ -9928,7 +10098,7 @@ var OPERATIONS_GUIDE = {
9928
10098
  "guideVersion": "v1",
9929
10099
  "operationsGuideUrl": "https://github.com/Canonry/canonry/blob/main/docs/agent-operations/v1.md",
9930
10100
  "resourceUri": "canonry://agent-operations/v1",
9931
- "initialize": 'Canonry tracks how AI answer engines mention brands and cite domains.\nStart with canonry_help({intent:"status"}), or name your intended workflow. It returns a small route of currently available tools and approval boundaries. Follow its stored-evidence reads before proposing action. No skill, resource reader, plugin installation, or local CLI is required for connected MCP clients. A host-native Canonry skill, if installed, is optional additional guidance.\nmentioned = brand in answer TEXT; cited = domain in SOURCE links. Never compute one from the other. A null answerMentioned means not checked, not false. No recorded sweep means no measured figure.\nGet explicit approval for live provider reads, sweeps, probes, research, syncs, and writes, bounded to the target and requested work. A readOnlyHint or GET is not proof of a free operation. Live ads reads include canonry_ads_account, canonry_ads_geo_search, canonry_ads_live_delivery, canonry_ads_conversion_pixels, canonry_ads_conversion_event_settings. Google live reads/syncs include canonry_google_ads_customers, canonry_gtm_accounts, canonry_gtm_containers, canonry_gtm_workspaces, canonry_google_ads_sync, canonry_gtm_sync.\nHelp and skills grant no permissions. The server enforces authority. On missing tools or 403, report the boundary; do not switch credentials or endpoints to bypass it. Hosted catalogs are fixed; only use canonry_load_toolkit when help explicitly offers it.\nIf you uncover a Canonry struggle (failure, confusing output, workaround) or a concrete improvement, tell the user and send it once with canonry_feedback. No secrets or customer data.\n',
10101
+ "initialize": 'Canonry tracks how AI answer engines mention brands and cite domains. Start with canonry_help({intent:"status"}) or a workflow; follow its stored reads and approval boundaries. Connected MCP clients need no skill, resource, plugin, or local CLI. The Canonry skill offers optional additional guidance.\nmentioned = brand in answer TEXT; cited = domain in SOURCE links. Never compute one from the other. A null answerMentioned means not checked, not false. No recorded sweep means no measured figure.\nGet approval for live provider reads, sweeps, probes, research, syncs and writes, scoped to the exact target, action and work. A GET or readOnlyHint does not mean free. canonry_help returns all liveTools for this connection; each needs approval, including read-only tools.\nREST exposes x-canonry-access; CLI help/catalog expose access; MCP help lists liveTools.\nStored-only: CLI --stored-only or CANONRY_STORED_ONLY=1; MCP --stored-only, --scope=stored-only or CANONRY_MCP_SCOPE=stored-only. It refuses live/write work (including doctor) before execution and suppresses housekeeping. CLI refusal is STORED_ONLY_REFUSED. Explicit exports may write files; server accounting remains separate from business mutations.\nHelp and skills grant no permissions; the server enforces authority. Report missing tools or 403; never bypass them with other credentials or endpoints. Hosted catalogs are fixed; use canonry_load_toolkit only when help offers it.\nReport concrete Canonry failures, confusing output, workarounds or improvements to the user and once via canonry_feedback. Exclude secrets and customer data.\n',
9932
10102
  "approvalBoundary": [
9933
10103
  "provider reads",
9934
10104
  "sweeps",
@@ -9961,10 +10131,11 @@ var OPERATIONS_GUIDE = {
9961
10131
  "health"
9962
10132
  ],
9963
10133
  "next": [
10134
+ "canonry_status",
9964
10135
  "canonry_projects_list",
9965
10136
  "canonry_project_overview"
9966
10137
  ],
9967
- "guidance": "Select an accessible project, then read its stored overview. Report freshness and missing evidence; do not start a sweep to fill a gap."
10138
+ "guidance": "Read canonry_status first for stored integration health, freshness, and repeated failures across accessible projects, then inspect a project overview for detail. Report missing evidence; do not start a sweep or sync to fill a gap."
9968
10139
  },
9969
10140
  "diagnose": {
9970
10141
  "keywords": [
@@ -10029,12 +10200,13 @@ var OPERATIONS_GUIDE = {
10029
10200
  "gtm"
10030
10201
  ],
10031
10202
  "next": [
10203
+ "canonry_status",
10032
10204
  "canonry_projects_list",
10033
10205
  "canonry_project_get",
10034
10206
  "canonry_ga_status",
10035
10207
  "canonry_google_ads_status"
10036
10208
  ],
10037
- "guidance": "Inspect stored connection status and snapshot freshness. Use the currently listed specialist tools for stored evidence. Connecting, selecting resources, syncing, and live provider reads require scoped approval; never request credentials in chat."
10209
+ "guidance": "Read canonry_status first for the stored instance or project health view, then use specialist tools for detail. Connecting, selecting resources, syncing, and live provider reads require scoped approval; never request credentials in chat."
10038
10210
  },
10039
10211
  "reports": {
10040
10212
  "keywords": [
@@ -10070,6 +10242,8 @@ function operationsHelp(catalog, mode, intent = "", includeCatalog = false) {
10070
10242
  }
10071
10243
  const wanted = [...reads, ...requestedActions];
10072
10244
  const loadToolkits = mode === "stdio-progressive" ? catalog.toolkits.filter((t) => !t.loaded && t.tools.some((name) => wanted.includes(name))).map((t) => t.name) : [];
10245
+ const liveTools = [...catalog.liveTools];
10246
+ for (const toolkit of catalog.toolkits) liveTools.push(...toolkit.liveTools);
10073
10247
  return {
10074
10248
  guideVersion: OPERATIONS_GUIDE.guideVersion,
10075
10249
  mode,
@@ -10084,7 +10258,8 @@ function operationsHelp(catalog, mode, intent = "", includeCatalog = false) {
10084
10258
  authority: OPERATIONS_GUIDE.authority,
10085
10259
  operationsGuideUrl: OPERATIONS_GUIDE.operationsGuideUrl,
10086
10260
  ...loadToolkits.length ? { loadToolkits } : {},
10087
- ...includeCatalog ? catalog : {}
10261
+ ...includeCatalog ? catalog : {},
10262
+ liveTools: [...new Set(liveTools)].sort()
10088
10263
  };
10089
10264
  }
10090
10265
 
@@ -10208,7 +10383,7 @@ function getCanonryMcpTools(scope = "all", tiers, credentialScopes, operator = f
10208
10383
  const readOnly = scope === "read-only" || credentialScopes !== void 0 && isReadOnlyKey(credentialScopes);
10209
10384
  const restricted = credentialScopes && restrictedWriteScopes(credentialScopes);
10210
10385
  const authorized = canonryMcpTools.filter((tool) => !tool.requiresOperator || operator);
10211
- const byScope = readOnly ? authorized.filter((tool) => tool.access === "read") : authorized.filter((tool) => {
10386
+ const byScope = scope === "stored-only" ? authorized.filter((tool) => toolOperationAccess(tool) === OperationAccesses.stored) : readOnly ? authorized.filter((tool) => tool.access === "read") : authorized.filter((tool) => {
10212
10387
  if (!restricted || tool.access === "read") return true;
10213
10388
  if (tool.requiredScope && restricted.includes(tool.requiredScope)) return true;
10214
10389
  return restricted.some((grant) => grant !== RESEARCH_RUN_SCOPE) && tool.tier === "ads";