@ainyc/canonry 4.193.2 → 4.195.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/README.md +1 -1
- package/assets/agent-workspace/skills/canonry/SKILL.md +81 -1
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +41 -0
- package/assets/assets/{AuditHistoryPanel-BBXiKuD1.js → AuditHistoryPanel-vWUtVXOI.js} +1 -1
- package/assets/assets/{BacklinksPage-CE_-DKWO.js → BacklinksPage-CSzuMEuv.js} +1 -1
- package/assets/assets/{HistoryPage-D-l4jMt5.js → HistoryPage-DtCTQ7CQ.js} +1 -1
- package/assets/assets/{MeasurementPropertyPage-fCJm3sW6.js → MeasurementPropertyPage-B7gTMWNs.js} +1 -1
- package/assets/assets/{ProjectPage-Cxrd8lZM.js → ProjectPage-Bsm0_jUY.js} +1 -1
- package/assets/assets/{RunRow-C2kmB04V.js → RunRow-D5k4Rdo4.js} +1 -1
- package/assets/assets/{RunsPage-B73hjh_l.js → RunsPage-DIXBB2Om.js} +1 -1
- package/assets/assets/{SettingsPage-Ba30Jfnn.js → SettingsPage-wYhBm6Az.js} +1 -1
- package/assets/assets/{SiteHealthSection-mjpxy6N9.js → SiteHealthSection-YebzsgDh.js} +3 -3
- package/assets/assets/{TrafficPage-BZ8H_c8u.js → TrafficPage-DtnSRFO8.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-sCUyzPpH.js → TrafficSourceDetailPage-DYQ6mpYq.js} +1 -1
- package/assets/assets/{extract-error-message-G-MvSIBA.js → extract-error-message-BdChrkmo.js} +1 -1
- package/assets/assets/{index-CSktlkUv.js → index-C_E2NRYY.js} +26 -26
- package/assets/assets/{react-sigma_core.esm.min-CgN2Dnvk.js → react-sigma_core.esm.min-sKWUk_tG.js} +1 -1
- package/assets/assets/{v2-overview-adapter-OmeP2l8O.js → v2-overview-adapter-CkPt-sRK.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-5CXUV3ZX.js → chunk-3WODA4JF.js} +288 -7
- package/dist/{chunk-24JHDZ7H.js → chunk-B2XM6AQ6.js} +318 -33
- package/dist/{chunk-KJJMIWVD.js → chunk-H3RVNMOO.js} +91 -38
- package/dist/{chunk-LIMWYFHS.js → chunk-LJKAB4CX.js} +2 -2
- package/dist/{chunk-Q5KGSOT7.js → chunk-UMU3IBXM.js} +1231 -484
- package/dist/cli.js +252 -156
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-6ORSU2M6.js → intelligence-service-MGQRJW4V.js} +2 -2
- package/dist/mcp.js +4 -4
- package/package.json +10 -10
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
adsOperationReconcileRequestSchema,
|
|
22
22
|
adsPauseRequestSchema,
|
|
23
23
|
adsUnresolvedOperationListQuerySchema,
|
|
24
|
+
apiKeyDtoSchema,
|
|
24
25
|
backlinkSourceSchema,
|
|
25
26
|
canonicalizeGtmAccountId,
|
|
26
27
|
canonicalizeGtmResourceSelection,
|
|
@@ -38,8 +39,10 @@ import {
|
|
|
38
39
|
googleAdsMetricsWindowSchema,
|
|
39
40
|
gscPerformanceOrderBySchema,
|
|
40
41
|
isReadOnlyKey,
|
|
42
|
+
isSensitiveDiagnosticQueryKey,
|
|
41
43
|
keywordBatchRequestSchema,
|
|
42
44
|
keywordGenerateRequestSchema,
|
|
45
|
+
logQuerySchema,
|
|
43
46
|
measurementChangesQuerySchema,
|
|
44
47
|
measurementDataQualityQuerySchema,
|
|
45
48
|
measurementDiscoveryRequestSchema,
|
|
@@ -79,12 +82,15 @@ import {
|
|
|
79
82
|
measurementQueryTemplateApplyRequestSchema,
|
|
80
83
|
measurementQueryTemplateUpsertRequestSchema,
|
|
81
84
|
measurementQuestionResultQuerySchema,
|
|
85
|
+
normalizeTelemetryStatus,
|
|
82
86
|
notificationCreateRequestSchema,
|
|
83
87
|
notificationEventSchema,
|
|
88
|
+
operationalLogListDtoSchema,
|
|
84
89
|
organicEvidencePeriodSchema,
|
|
85
90
|
projectConfigSchema,
|
|
86
91
|
projectUpsertRequestSchema,
|
|
87
92
|
providerQuotaPolicySchema,
|
|
93
|
+
providerSummaryEntryDtoSchema,
|
|
88
94
|
queryBatchRequestSchema,
|
|
89
95
|
queryGenerateRequestSchema,
|
|
90
96
|
queryTrackingCommitRequestSchema,
|
|
@@ -97,15 +103,19 @@ import {
|
|
|
97
103
|
runListFilterQuerySchema,
|
|
98
104
|
runTriggerRequestSchema,
|
|
99
105
|
schedulableRunKindSchema,
|
|
106
|
+
scheduleDtoSchema,
|
|
100
107
|
scheduleUpsertRequestSchema,
|
|
108
|
+
settingsDtoSchema,
|
|
101
109
|
skillsClientSchema,
|
|
110
|
+
snapshotRequestInputSchema,
|
|
111
|
+
telemetryStatusDtoSchema,
|
|
102
112
|
trafficConnectCloudRunRequestSchema,
|
|
103
113
|
trafficConnectVercelRequestSchema,
|
|
104
114
|
trafficConnectWordpressRequestSchema,
|
|
105
115
|
trafficEventKindSchema,
|
|
106
116
|
trafficSeriesGranularitySchema,
|
|
107
117
|
visibilityReportRequestSchema
|
|
108
|
-
} from "./chunk-
|
|
118
|
+
} from "./chunk-3WODA4JF.js";
|
|
109
119
|
|
|
110
120
|
// src/cli-error.ts
|
|
111
121
|
function isMachineFormat(format) {
|
|
@@ -592,6 +602,58 @@ function configExists() {
|
|
|
592
602
|
return fs.existsSync(getConfigPath());
|
|
593
603
|
}
|
|
594
604
|
|
|
605
|
+
// src/client-reliability.ts
|
|
606
|
+
function parseRetryAfterMs(header, now = Date.now()) {
|
|
607
|
+
if (!header) return void 0;
|
|
608
|
+
const value = header.trim();
|
|
609
|
+
if (!value) return void 0;
|
|
610
|
+
if (/^\d+(?:\.\d+)?$/.test(value)) {
|
|
611
|
+
const delayMs2 = Number(value) * 1e3;
|
|
612
|
+
return Number.isFinite(delayMs2) && delayMs2 >= 0 && delayMs2 <= Number.MAX_SAFE_INTEGER ? delayMs2 : void 0;
|
|
613
|
+
}
|
|
614
|
+
if (!/^[a-z]{3},\s/i.test(value)) return void 0;
|
|
615
|
+
const target = Date.parse(value);
|
|
616
|
+
if (!Number.isFinite(target)) return void 0;
|
|
617
|
+
const delayMs = Math.max(0, target - now);
|
|
618
|
+
return Number.isSafeInteger(delayMs) ? delayMs : void 0;
|
|
619
|
+
}
|
|
620
|
+
function httpErrorDetails(serverDetails, response) {
|
|
621
|
+
const retryAfterMs = parseRetryAfterMs(response.headers.get("retry-after"));
|
|
622
|
+
const requestId = response.headers.get("x-request-id") ?? response.headers.get("request-id");
|
|
623
|
+
return {
|
|
624
|
+
...serverDetails && typeof serverDetails === "object" && !Array.isArray(serverDetails) ? serverDetails : {},
|
|
625
|
+
httpStatus: response.status,
|
|
626
|
+
...retryAfterMs === void 0 ? {} : { retryAfterMs },
|
|
627
|
+
...requestId ? { requestId } : {}
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
function isConnectionFailure(message) {
|
|
631
|
+
return message.includes("fetch failed") || message.includes("ECONNREFUSED") || message.includes("connect ECONNREFUSED");
|
|
632
|
+
}
|
|
633
|
+
function connectionFailureMessage(target) {
|
|
634
|
+
return `Could not connect to canonry server at ${redactRequestTarget(target)}. Check that this URL is reachable and the server is running. For a local Canonry instance, start it with "canonry serve" (or "canonry serve &" to run in background).`;
|
|
635
|
+
}
|
|
636
|
+
function redactRequestTarget(target) {
|
|
637
|
+
try {
|
|
638
|
+
const url = new URL(target);
|
|
639
|
+
url.username = "";
|
|
640
|
+
url.password = "";
|
|
641
|
+
for (const key of [...url.searchParams.keys()]) {
|
|
642
|
+
if (isSensitiveDiagnosticQueryKey(key)) {
|
|
643
|
+
url.searchParams.set(key, "<redacted>");
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
return url.toString();
|
|
647
|
+
} catch {
|
|
648
|
+
return target.replace(/\/\/[^/@]*@/, "//");
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// src/package-version.ts
|
|
653
|
+
import { createRequire } from "module";
|
|
654
|
+
var _require = createRequire(import.meta.url);
|
|
655
|
+
var PACKAGE_VERSION = _require("../package.json").version;
|
|
656
|
+
|
|
595
657
|
// ../api-client-generated/src/generated/core/bodySerializer.gen.ts
|
|
596
658
|
var jsonBodySerializer = {
|
|
597
659
|
bodySerializer: (body) => JSON.stringify(
|
|
@@ -2929,6 +2991,22 @@ var putApiV1SettingsProvidersByName = (options) => {
|
|
|
2929
2991
|
}
|
|
2930
2992
|
});
|
|
2931
2993
|
};
|
|
2994
|
+
var putApiV1SettingsGoogle = (options) => {
|
|
2995
|
+
return (options.client ?? client).put({
|
|
2996
|
+
security: [
|
|
2997
|
+
{
|
|
2998
|
+
scheme: "bearer",
|
|
2999
|
+
type: "http"
|
|
3000
|
+
}
|
|
3001
|
+
],
|
|
3002
|
+
url: "/api/v1/settings/google",
|
|
3003
|
+
...options,
|
|
3004
|
+
headers: {
|
|
3005
|
+
"Content-Type": "application/json",
|
|
3006
|
+
...options.headers
|
|
3007
|
+
}
|
|
3008
|
+
});
|
|
3009
|
+
};
|
|
2932
3010
|
var getApiV1Keys = (options) => {
|
|
2933
3011
|
return (options?.client ?? client).get({
|
|
2934
3012
|
security: [
|
|
@@ -3077,6 +3155,30 @@ var putApiV1ProjectsByNameSchedule = (options) => {
|
|
|
3077
3155
|
}
|
|
3078
3156
|
});
|
|
3079
3157
|
};
|
|
3158
|
+
var getApiV1ProjectsByNameSchedules = (options) => {
|
|
3159
|
+
return (options.client ?? client).get({
|
|
3160
|
+
security: [
|
|
3161
|
+
{
|
|
3162
|
+
scheme: "bearer",
|
|
3163
|
+
type: "http"
|
|
3164
|
+
}
|
|
3165
|
+
],
|
|
3166
|
+
url: "/api/v1/projects/{name}/schedules",
|
|
3167
|
+
...options
|
|
3168
|
+
});
|
|
3169
|
+
};
|
|
3170
|
+
var getApiV1NotificationsEvents = (options) => {
|
|
3171
|
+
return (options?.client ?? client).get({
|
|
3172
|
+
security: [
|
|
3173
|
+
{
|
|
3174
|
+
scheme: "bearer",
|
|
3175
|
+
type: "http"
|
|
3176
|
+
}
|
|
3177
|
+
],
|
|
3178
|
+
url: "/api/v1/notifications/events",
|
|
3179
|
+
...options
|
|
3180
|
+
});
|
|
3181
|
+
};
|
|
3080
3182
|
var getApiV1ProjectsByNameNotifications = (options) => {
|
|
3081
3183
|
return (options.client ?? client).get({
|
|
3082
3184
|
security: [
|
|
@@ -3129,6 +3231,18 @@ var postApiV1ProjectsByNameNotificationsByIdTest = (options) => {
|
|
|
3129
3231
|
...options
|
|
3130
3232
|
});
|
|
3131
3233
|
};
|
|
3234
|
+
var getApiV1OperationsLogs = (options) => {
|
|
3235
|
+
return (options?.client ?? client).get({
|
|
3236
|
+
security: [
|
|
3237
|
+
{
|
|
3238
|
+
scheme: "bearer",
|
|
3239
|
+
type: "http"
|
|
3240
|
+
}
|
|
3241
|
+
],
|
|
3242
|
+
url: "/api/v1/operations/logs",
|
|
3243
|
+
...options
|
|
3244
|
+
});
|
|
3245
|
+
};
|
|
3132
3246
|
var getApiV1Telemetry = (options) => {
|
|
3133
3247
|
return (options?.client ?? client).get({
|
|
3134
3248
|
security: [
|
|
@@ -5900,10 +6014,18 @@ function createClient2(opts) {
|
|
|
5900
6014
|
}
|
|
5901
6015
|
|
|
5902
6016
|
// src/client.ts
|
|
5903
|
-
|
|
6017
|
+
var SAFE_CLIENT_NAME = /^\w[\w./-]{0,127}$/;
|
|
6018
|
+
var SAFE_ACTOR_SESSION = /^\w[\w.:-]{0,127}$/;
|
|
6019
|
+
function safeClientName(value) {
|
|
6020
|
+
return value && SAFE_CLIENT_NAME.test(value) ? value : `canonry-cli/${PACKAGE_VERSION}`;
|
|
6021
|
+
}
|
|
6022
|
+
function safeActorSession(value) {
|
|
6023
|
+
return value && SAFE_ACTOR_SESSION.test(value) ? value : void 0;
|
|
6024
|
+
}
|
|
6025
|
+
function createApiClient(opts = {}) {
|
|
5904
6026
|
const config = loadConfig();
|
|
5905
6027
|
const basePathResolved = !!config.basePath || "CANONRY_BASE_PATH" in process.env;
|
|
5906
|
-
return new ApiClient(config.apiUrl, config.apiKey, { skipProbe: basePathResolved });
|
|
6028
|
+
return new ApiClient(config.apiUrl, config.apiKey, { ...opts, skipProbe: basePathResolved || opts.skipProbe });
|
|
5907
6029
|
}
|
|
5908
6030
|
var ApiClient = class {
|
|
5909
6031
|
originUrl;
|
|
@@ -5911,6 +6033,7 @@ var ApiClient = class {
|
|
|
5911
6033
|
probePromise = null;
|
|
5912
6034
|
probeSkipped;
|
|
5913
6035
|
heyClient;
|
|
6036
|
+
requestHeaders;
|
|
5914
6037
|
/** Tracks the base URL most recently applied to `heyClient` so probe-driven updates only re-configure when something actually changed. */
|
|
5915
6038
|
heyClientBaseUrl;
|
|
5916
6039
|
constructor(baseUrl, apiKey, opts) {
|
|
@@ -5918,7 +6041,13 @@ var ApiClient = class {
|
|
|
5918
6041
|
this.apiKey = apiKey;
|
|
5919
6042
|
this.probeSkipped = opts?.skipProbe ?? false;
|
|
5920
6043
|
this.heyClientBaseUrl = this.originUrl;
|
|
5921
|
-
|
|
6044
|
+
const actorSession = safeActorSession(opts?.actorSession);
|
|
6045
|
+
this.requestHeaders = {
|
|
6046
|
+
authorization: `Bearer ${this.apiKey}`,
|
|
6047
|
+
"user-agent": safeClientName(opts?.clientName),
|
|
6048
|
+
...actorSession ? { "x-canonry-actor-session": actorSession } : {}
|
|
6049
|
+
};
|
|
6050
|
+
this.heyClient = createClient2({ baseUrl: this.originUrl, apiKey: this.apiKey, headers: this.requestHeaders });
|
|
5922
6051
|
}
|
|
5923
6052
|
/**
|
|
5924
6053
|
* On first API call, probe /health to auto-discover basePath when the user
|
|
@@ -5953,7 +6082,7 @@ var ApiClient = class {
|
|
|
5953
6082
|
/** Apply the probe's discovered base URL to `heyClient` if it changed since last call. */
|
|
5954
6083
|
refreshHeyClientBaseUrl() {
|
|
5955
6084
|
if (this.originUrl !== this.heyClientBaseUrl) {
|
|
5956
|
-
this.heyClient.setConfig({ baseUrl: this.originUrl, headers:
|
|
6085
|
+
this.heyClient.setConfig({ baseUrl: this.originUrl, headers: this.requestHeaders });
|
|
5957
6086
|
this.heyClientBaseUrl = this.originUrl;
|
|
5958
6087
|
}
|
|
5959
6088
|
}
|
|
@@ -5977,10 +6106,10 @@ var ApiClient = class {
|
|
|
5977
6106
|
process.stderr.write(`[trace] (sdk-call) \u2192 ERROR (${Date.now() - traceStart}ms): ${msg}
|
|
5978
6107
|
`);
|
|
5979
6108
|
}
|
|
5980
|
-
if (
|
|
6109
|
+
if (isConnectionFailure(msg)) {
|
|
5981
6110
|
throw new CliError({
|
|
5982
6111
|
code: "CONNECTION_ERROR",
|
|
5983
|
-
message:
|
|
6112
|
+
message: connectionFailureMessage(this.originUrl),
|
|
5984
6113
|
exitCode: EXIT_SYSTEM_ERROR
|
|
5985
6114
|
});
|
|
5986
6115
|
}
|
|
@@ -5989,7 +6118,7 @@ var ApiClient = class {
|
|
|
5989
6118
|
if (traceEnabled) {
|
|
5990
6119
|
const durMs = Date.now() - traceStart;
|
|
5991
6120
|
process.stderr.write(
|
|
5992
|
-
`[trace] ${result.request.method} ${result.request.url} \u2192 ${result.response.status} (${durMs}ms)
|
|
6121
|
+
`[trace] ${result.request.method} ${redactRequestTarget(result.request.url)} \u2192 ${result.response.status} (${durMs}ms)
|
|
5993
6122
|
`
|
|
5994
6123
|
);
|
|
5995
6124
|
}
|
|
@@ -5997,17 +6126,17 @@ var ApiClient = class {
|
|
|
5997
6126
|
if (result.response.ok && contentType?.toLowerCase().startsWith("text/html")) {
|
|
5998
6127
|
throw new CliError({
|
|
5999
6128
|
code: "UNEXPECTED_RESPONSE_FORMAT",
|
|
6000
|
-
message: `Expected a JSON response from the canonry API at ${result.request.url}, but received ${contentType} (HTTP ${result.response.status}). Check the server URL and base path.`,
|
|
6129
|
+
message: `Expected a JSON response from the canonry API at ${redactRequestTarget(result.request.url)}, but received ${contentType} (HTTP ${result.response.status}). Check the server URL and base path.`,
|
|
6001
6130
|
exitCode: EXIT_SYSTEM_ERROR,
|
|
6002
6131
|
details: {
|
|
6003
|
-
requestUrl: result.request.url,
|
|
6132
|
+
requestUrl: redactRequestTarget(result.request.url),
|
|
6004
6133
|
contentType,
|
|
6005
6134
|
httpStatus: result.response.status
|
|
6006
6135
|
}
|
|
6007
6136
|
});
|
|
6008
6137
|
}
|
|
6009
6138
|
if (result.error !== void 0 && result.error !== null) {
|
|
6010
|
-
const errorObj = typeof result.error === "object" &&
|
|
6139
|
+
const errorObj = typeof result.error === "object" && "error" in result.error && typeof result.error.error === "object" && result.error.error !== null ? result.error.error : null;
|
|
6011
6140
|
const msg = errorObj?.message ? String(errorObj.message) : `HTTP ${result.response.status}: ${result.response.statusText}`;
|
|
6012
6141
|
const code = errorObj?.code ? String(errorObj.code) : "API_ERROR";
|
|
6013
6142
|
const exitCode = result.response.status >= 500 ? EXIT_SYSTEM_ERROR : EXIT_USER_ERROR;
|
|
@@ -6015,7 +6144,7 @@ var ApiClient = class {
|
|
|
6015
6144
|
code,
|
|
6016
6145
|
message: msg,
|
|
6017
6146
|
exitCode,
|
|
6018
|
-
details:
|
|
6147
|
+
details: httpErrorDetails(errorObj?.details, result.response)
|
|
6019
6148
|
});
|
|
6020
6149
|
}
|
|
6021
6150
|
return result.data;
|
|
@@ -6080,7 +6209,7 @@ var ApiClient = class {
|
|
|
6080
6209
|
await this.probeBasePath();
|
|
6081
6210
|
const url = `${this.originUrl}/api/v1${path3}`;
|
|
6082
6211
|
const headers = {
|
|
6083
|
-
|
|
6212
|
+
...this.requestHeaders,
|
|
6084
6213
|
"Content-Type": "application/json",
|
|
6085
6214
|
Accept: "text/event-stream"
|
|
6086
6215
|
};
|
|
@@ -6090,10 +6219,10 @@ var ApiClient = class {
|
|
|
6090
6219
|
} catch (err) {
|
|
6091
6220
|
if (err instanceof CliError) throw err;
|
|
6092
6221
|
const msg = describeError(err);
|
|
6093
|
-
if (
|
|
6222
|
+
if (isConnectionFailure(msg)) {
|
|
6094
6223
|
throw new CliError({
|
|
6095
6224
|
code: "CONNECTION_ERROR",
|
|
6096
|
-
message:
|
|
6225
|
+
message: connectionFailureMessage(this.originUrl),
|
|
6097
6226
|
exitCode: EXIT_SYSTEM_ERROR
|
|
6098
6227
|
});
|
|
6099
6228
|
}
|
|
@@ -6110,7 +6239,7 @@ var ApiClient = class {
|
|
|
6110
6239
|
const msg = errorObj?.message ? String(errorObj.message) : `HTTP ${res.status}: ${res.statusText}`;
|
|
6111
6240
|
const code = errorObj?.code ? String(errorObj.code) : "API_ERROR";
|
|
6112
6241
|
const exitCode = res.status >= 500 ? EXIT_SYSTEM_ERROR : EXIT_USER_ERROR;
|
|
6113
|
-
throw new CliError({ code, message: msg, exitCode, details:
|
|
6242
|
+
throw new CliError({ code, message: msg, exitCode, details: httpErrorDetails(errorObj?.details, res) });
|
|
6114
6243
|
}
|
|
6115
6244
|
return res;
|
|
6116
6245
|
}
|
|
@@ -6961,16 +7090,32 @@ var ApiClient = class {
|
|
|
6961
7090
|
() => putApiV1SettingsProvidersByName({ client: this.heyClient, path: { name }, body })
|
|
6962
7091
|
);
|
|
6963
7092
|
}
|
|
7093
|
+
async updateGoogleSettings(body) {
|
|
7094
|
+
return this.invoke(
|
|
7095
|
+
() => putApiV1SettingsGoogle({ client: this.heyClient, body })
|
|
7096
|
+
);
|
|
7097
|
+
}
|
|
6964
7098
|
async createSnapshot(body) {
|
|
6965
7099
|
return this.invoke(() => postApiV1Snapshot({ client: this.heyClient, body }));
|
|
6966
7100
|
}
|
|
6967
7101
|
async getTelemetry() {
|
|
6968
|
-
return this.invoke(() => getApiV1Telemetry({ client: this.heyClient }));
|
|
7102
|
+
return normalizeTelemetryStatus(await this.invoke(() => getApiV1Telemetry({ client: this.heyClient })));
|
|
7103
|
+
}
|
|
7104
|
+
async listOperationalLogs(query = {}) {
|
|
7105
|
+
return this.invoke(() => getApiV1OperationsLogs({ client: this.heyClient, query }));
|
|
6969
7106
|
}
|
|
6970
7107
|
async updateTelemetry(enabled) {
|
|
6971
|
-
return this.invoke(() => putApiV1Telemetry({ client: this.heyClient, body: { enabled } }));
|
|
7108
|
+
return normalizeTelemetryStatus(await this.invoke(() => putApiV1Telemetry({ client: this.heyClient, body: { enabled } })));
|
|
6972
7109
|
}
|
|
6973
7110
|
// ── Schedules / notifications / locations ───────────────────────────────
|
|
7111
|
+
async listSchedules(project) {
|
|
7112
|
+
return this.invoke(
|
|
7113
|
+
() => getApiV1ProjectsByNameSchedules({ client: this.heyClient, path: { name: project } })
|
|
7114
|
+
);
|
|
7115
|
+
}
|
|
7116
|
+
async listNotificationEvents() {
|
|
7117
|
+
return this.invoke(() => getApiV1NotificationsEvents({ client: this.heyClient }));
|
|
7118
|
+
}
|
|
6974
7119
|
async putSchedule(project, body) {
|
|
6975
7120
|
return this.invoke(
|
|
6976
7121
|
() => putApiV1ProjectsByNameSchedule({
|
|
@@ -8790,11 +8935,6 @@ var ApiClient = class {
|
|
|
8790
8935
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8791
8936
|
import { z as z5 } from "zod";
|
|
8792
8937
|
|
|
8793
|
-
// src/package-version.ts
|
|
8794
|
-
import { createRequire } from "module";
|
|
8795
|
-
var _require = createRequire(import.meta.url);
|
|
8796
|
-
var PACKAGE_VERSION = _require("../package.json").version;
|
|
8797
|
-
|
|
8798
8938
|
// src/mcp/tool-registry.ts
|
|
8799
8939
|
import { z as z4 } from "zod";
|
|
8800
8940
|
|
|
@@ -9478,6 +9618,8 @@ var scheduleReadInputSchema = z4.object({
|
|
|
9478
9618
|
project: projectNameSchema,
|
|
9479
9619
|
kind: schedulableRunKindSchema.optional().describe('Schedulable run kind. Defaults to "answer-visibility" if omitted.')
|
|
9480
9620
|
});
|
|
9621
|
+
var scheduleListOutputSchema = z4.object({ items: z4.array(scheduleDtoSchema) });
|
|
9622
|
+
var notificationEventsOutputSchema = z4.object({ items: z4.array(notificationEventSchema) });
|
|
9481
9623
|
var agentWebhookAttachInputSchema = z4.object({
|
|
9482
9624
|
project: projectNameSchema,
|
|
9483
9625
|
url: z4.string().url()
|
|
@@ -10274,6 +10416,30 @@ var canonryMcpTools = [
|
|
|
10274
10416
|
openApiOperations: ["GET /api/v1/projects/{name}/schedule"],
|
|
10275
10417
|
handler: (client2, input) => client2.getSchedule(input.project, input.kind)
|
|
10276
10418
|
}),
|
|
10419
|
+
defineTool({
|
|
10420
|
+
name: "canonry_schedules_list",
|
|
10421
|
+
title: "List project schedules",
|
|
10422
|
+
description: "List every stored schedule for a Canonry project, including each schedulable run kind. This reads configuration only and never starts work.",
|
|
10423
|
+
access: "read",
|
|
10424
|
+
tier: "setup",
|
|
10425
|
+
inputSchema: projectInputSchema,
|
|
10426
|
+
outputSchema: scheduleListOutputSchema,
|
|
10427
|
+
annotations: readAnnotations(),
|
|
10428
|
+
openApiOperations: ["GET /api/v1/projects/{name}/schedules"],
|
|
10429
|
+
handler: (client2, input) => client2.listSchedules(input.project)
|
|
10430
|
+
}),
|
|
10431
|
+
defineTool({
|
|
10432
|
+
name: "canonry_notification_events",
|
|
10433
|
+
title: "List notification event types",
|
|
10434
|
+
description: "List the supported stored notification event names. This is a static capability read; it does not send, test, or change notifications.",
|
|
10435
|
+
access: "read",
|
|
10436
|
+
tier: "setup",
|
|
10437
|
+
inputSchema: emptyInputSchema,
|
|
10438
|
+
outputSchema: notificationEventsOutputSchema,
|
|
10439
|
+
annotations: readAnnotations(),
|
|
10440
|
+
openApiOperations: ["GET /api/v1/notifications/events"],
|
|
10441
|
+
handler: (client2) => client2.listNotificationEvents()
|
|
10442
|
+
}),
|
|
10277
10443
|
defineTool({
|
|
10278
10444
|
name: "canonry_backlinks_latest_release",
|
|
10279
10445
|
title: "Discover latest Common Crawl release",
|
|
@@ -10318,10 +10484,73 @@ var canonryMcpTools = [
|
|
|
10318
10484
|
access: "read",
|
|
10319
10485
|
tier: "core",
|
|
10320
10486
|
inputSchema: emptyInputSchema,
|
|
10487
|
+
outputSchema: settingsDtoSchema,
|
|
10321
10488
|
annotations: readAnnotations(),
|
|
10322
10489
|
openApiOperations: ["GET /api/v1/settings"],
|
|
10323
10490
|
handler: (client2) => client2.getSettings()
|
|
10324
10491
|
}),
|
|
10492
|
+
defineTool({
|
|
10493
|
+
name: "canonry_key_self",
|
|
10494
|
+
title: "Get current API key identity",
|
|
10495
|
+
description: "Read safe metadata for the credential backing this MCP connection, including its scopes, project reach, and derived read-only status. It never exposes the bearer token or stored hash and does not grant mutation access.",
|
|
10496
|
+
access: "read",
|
|
10497
|
+
tier: "core",
|
|
10498
|
+
inputSchema: emptyInputSchema,
|
|
10499
|
+
outputSchema: apiKeyDtoSchema,
|
|
10500
|
+
annotations: readAnnotations(),
|
|
10501
|
+
openApiOperations: ["GET /api/v1/keys/self"],
|
|
10502
|
+
handler: (client2) => client2.getApiKeySelf()
|
|
10503
|
+
}),
|
|
10504
|
+
defineTool({
|
|
10505
|
+
name: "canonry_logs_list",
|
|
10506
|
+
title: "Read runtime logs",
|
|
10507
|
+
description: "Read bounded, redacted runtime logs, including application and HTTP failures. Filter by actor, request, run, project, level, module, or time. Inspect retention, retentionPolicy, dropped, and captureErrors for coverage; file-backed hosts retain logs across restarts. Separate from audit history. Requires instance-wide logs.read (or wildcard), and an admin role for user sessions; project-scoped keys are refused even with a project filter. Cursors expire on retention eviction; reuse with the same filters. No provider calls.",
|
|
10508
|
+
access: "read",
|
|
10509
|
+
tier: "setup",
|
|
10510
|
+
inputSchema: logQuerySchema,
|
|
10511
|
+
outputSchema: operationalLogListDtoSchema,
|
|
10512
|
+
annotations: readAnnotations(false),
|
|
10513
|
+
openApiOperations: ["GET /api/v1/operations/logs"],
|
|
10514
|
+
handler: async (client2, input) => client2.listOperationalLogs(input)
|
|
10515
|
+
}),
|
|
10516
|
+
defineTool({
|
|
10517
|
+
name: "canonry_telemetry_update",
|
|
10518
|
+
title: "Update server telemetry preference",
|
|
10519
|
+
description: "Set the connected server telemetry preference with explicit approval and settings.write. Returns effective state including environment overrides. Does not change the agent machine configuration.",
|
|
10520
|
+
access: "write",
|
|
10521
|
+
requiredScope: "settings.write",
|
|
10522
|
+
tier: "setup",
|
|
10523
|
+
inputSchema: z4.object({ enabled: z4.boolean() }).strict(),
|
|
10524
|
+
outputSchema: telemetryStatusDtoSchema,
|
|
10525
|
+
annotations: writeAnnotations({ idempotentHint: true }),
|
|
10526
|
+
openApiOperations: ["PUT /api/v1/telemetry"],
|
|
10527
|
+
handler: async (client2, input) => client2.updateTelemetry(input.enabled)
|
|
10528
|
+
}),
|
|
10529
|
+
defineTool({
|
|
10530
|
+
name: "canonry_provider_settings_update",
|
|
10531
|
+
title: "Update non-secret provider settings",
|
|
10532
|
+
description: "Change model or quota for an already-configured provider, with explicit approval and settings.write. Preserves existing credentials. Does not accept API keys, base URLs, or credential rotation; use the secure operator setup flow for those.",
|
|
10533
|
+
access: "write",
|
|
10534
|
+
requiredScope: "settings.write",
|
|
10535
|
+
tier: "setup",
|
|
10536
|
+
inputSchema: z4.object({ provider: z4.string().min(1), model: z4.string().trim().min(1).optional(), quota: providerQuotaPolicySchema.partial().strict().optional() }).strict().refine((input) => input.model !== void 0 || input.quota !== void 0 && Object.keys(input.quota).length > 0, "Provide a model or at least one quota field"),
|
|
10537
|
+
outputSchema: providerSummaryEntryDtoSchema,
|
|
10538
|
+
annotations: writeAnnotations({ idempotentHint: true }),
|
|
10539
|
+
openApiOperations: ["PUT /api/v1/settings/providers/{name}"],
|
|
10540
|
+
handler: async (client2, { provider, ...request }) => client2.updateProvider(provider, request)
|
|
10541
|
+
}),
|
|
10542
|
+
defineTool({
|
|
10543
|
+
name: "canonry_telemetry_get",
|
|
10544
|
+
title: "Get telemetry status",
|
|
10545
|
+
description: "Read the server telemetry status and effective reason. This safe settings read does not change telemetry collection.",
|
|
10546
|
+
access: "read",
|
|
10547
|
+
tier: "setup",
|
|
10548
|
+
inputSchema: emptyInputSchema,
|
|
10549
|
+
outputSchema: telemetryStatusDtoSchema,
|
|
10550
|
+
annotations: readAnnotations(),
|
|
10551
|
+
openApiOperations: ["GET /api/v1/telemetry"],
|
|
10552
|
+
handler: (client2) => client2.getTelemetry()
|
|
10553
|
+
}),
|
|
10325
10554
|
defineTool({
|
|
10326
10555
|
name: "canonry_google_connections_list",
|
|
10327
10556
|
title: "List Google connections",
|
|
@@ -10828,6 +11057,17 @@ var canonryMcpTools = [
|
|
|
10828
11057
|
openApiOperations: ["POST /api/v1/projects/{name}/traffic/sources/{id}/reset"],
|
|
10829
11058
|
handler: (client2, input) => client2.trafficReset(input.project, input.sourceId)
|
|
10830
11059
|
}),
|
|
11060
|
+
defineTool({
|
|
11061
|
+
name: "canonry_snapshot",
|
|
11062
|
+
title: "Generate a prospect snapshot",
|
|
11063
|
+
description: "Generate a one-shot AI perception report for a company and domain without creating a project. Spends provider quota and fetches the site. Optional providers and providerMode constrain both answers and analysis; omitted selection uses all configured providers. Browser-only selection requires manual queries.",
|
|
11064
|
+
access: "write",
|
|
11065
|
+
tier: "discovery",
|
|
11066
|
+
inputSchema: snapshotRequestInputSchema,
|
|
11067
|
+
annotations: writeAnnotations({ idempotentHint: false, openWorldHint: true }),
|
|
11068
|
+
openApiOperations: ["POST /api/v1/snapshot"],
|
|
11069
|
+
handler: (client2, input) => client2.createSnapshot(input)
|
|
11070
|
+
}),
|
|
10831
11071
|
defineTool({
|
|
10832
11072
|
name: "canonry_project_upsert",
|
|
10833
11073
|
title: "Create or replace project",
|
|
@@ -12398,6 +12638,7 @@ import { ZodError } from "zod";
|
|
|
12398
12638
|
function jsonToolResult(value) {
|
|
12399
12639
|
const result = value === void 0 ? { ok: true } : value;
|
|
12400
12640
|
return {
|
|
12641
|
+
structuredContent: toStructuredContent(result),
|
|
12401
12642
|
content: [
|
|
12402
12643
|
{
|
|
12403
12644
|
type: "text",
|
|
@@ -12407,16 +12648,23 @@ function jsonToolResult(value) {
|
|
|
12407
12648
|
};
|
|
12408
12649
|
}
|
|
12409
12650
|
function errorToolResult(error) {
|
|
12651
|
+
const envelope = toCanonryErrorEnvelope(error);
|
|
12410
12652
|
return {
|
|
12411
12653
|
isError: true,
|
|
12654
|
+
structuredContent: envelope,
|
|
12412
12655
|
content: [
|
|
12413
12656
|
{
|
|
12414
12657
|
type: "text",
|
|
12415
|
-
text: JSON.stringify(
|
|
12658
|
+
text: JSON.stringify(envelope, null, 2)
|
|
12416
12659
|
}
|
|
12417
12660
|
]
|
|
12418
12661
|
};
|
|
12419
12662
|
}
|
|
12663
|
+
function toStructuredContent(value) {
|
|
12664
|
+
if (Array.isArray(value)) return { items: value };
|
|
12665
|
+
if (value !== null && typeof value === "object") return value;
|
|
12666
|
+
return { value };
|
|
12667
|
+
}
|
|
12420
12668
|
async function withToolErrors(handler) {
|
|
12421
12669
|
try {
|
|
12422
12670
|
return jsonToolResult(await handler());
|
|
@@ -12585,8 +12833,8 @@ var CANONRY_MCP_TOOLKITS = [
|
|
|
12585
12833
|
{
|
|
12586
12834
|
name: "discovery",
|
|
12587
12835
|
title: "Query discovery and research",
|
|
12588
|
-
description: "
|
|
12589
|
-
whenToLoad: "Load
|
|
12836
|
+
description: "Find queries expands an ICP into a promotable tracked-query basket; research queries runs saved free-form experiments against one API model. Research never adds queries to tracking. Prospect snapshots generate a company report without creating a project.",
|
|
12837
|
+
whenToLoad: "Load for prospect snapshots, ICP-led candidates for a tracked basket, or research into free-form queries, model answers, sources, and location effects without changing tracking."
|
|
12590
12838
|
}
|
|
12591
12839
|
];
|
|
12592
12840
|
function isCanonryMcpToolkitName(value) {
|
|
@@ -12702,6 +12950,23 @@ var OPERATIONS_GUIDE = {
|
|
|
12702
12950
|
"approvalRule": "Get explicit approval for the exact target, action, and bounded provider work before crossing a boundary. Existing approval covers only its stated scope; stop on refusal or ambiguous results.",
|
|
12703
12951
|
"authority": "Guidance and tool visibility are not permission grants. Server-side roles, scopes, project boundaries, quotas, and approval receipts remain authoritative. Never bypass a refusal with different credentials or endpoints.",
|
|
12704
12952
|
"workflows": {
|
|
12953
|
+
"operations": {
|
|
12954
|
+
"keywords": [
|
|
12955
|
+
"operations",
|
|
12956
|
+
"permissions",
|
|
12957
|
+
"settings",
|
|
12958
|
+
"telemetry",
|
|
12959
|
+
"logs",
|
|
12960
|
+
"configuration"
|
|
12961
|
+
],
|
|
12962
|
+
"next": [
|
|
12963
|
+
"canonry_key_self",
|
|
12964
|
+
"canonry_settings_get",
|
|
12965
|
+
"canonry_telemetry_get",
|
|
12966
|
+
"canonry_logs_list"
|
|
12967
|
+
],
|
|
12968
|
+
"guidance": "Inspect current credential and server state before proposing changes. Runtime logs require instance-wide logs.read; inspect retention, dropped, and captureErrors before drawing conclusions. File-backed hosts retain bounded redacted logs across restarts. Logs are separate from audit history. Respect a 403; never substitute credentials to bypass it. Settings writes require settings.write and explicit approval."
|
|
12969
|
+
},
|
|
12705
12970
|
"status": {
|
|
12706
12971
|
"keywords": [
|
|
12707
12972
|
"status",
|
|
@@ -12730,6 +12995,21 @@ var OPERATIONS_GUIDE = {
|
|
|
12730
12995
|
],
|
|
12731
12996
|
"guidance": "Compare stored history in the same project, period, provider/model, location, and query-class scope. Separate observed changes from possible causes; propose any live verification for approval."
|
|
12732
12997
|
},
|
|
12998
|
+
"prospecting": {
|
|
12999
|
+
"keywords": [
|
|
13000
|
+
"prospect",
|
|
13001
|
+
"prospects",
|
|
13002
|
+
"prospecting",
|
|
13003
|
+
"snapshot"
|
|
13004
|
+
],
|
|
13005
|
+
"next": [
|
|
13006
|
+
"canonry_settings_get"
|
|
13007
|
+
],
|
|
13008
|
+
"actions": [
|
|
13009
|
+
"canonry_snapshot"
|
|
13010
|
+
],
|
|
13011
|
+
"guidance": "Inspect stored provider settings, then agree on the company, domain, providers, and queries. Snapshot generation spends quota and fetches the site; approval must cover that work. No project is required. Use the snapshot action only when offered by this connection; its absence does not grant permission to bypass access restrictions."
|
|
13012
|
+
},
|
|
12733
13013
|
"measurement": {
|
|
12734
13014
|
"keywords": [
|
|
12735
13015
|
"measurement",
|
|
@@ -12783,7 +13063,7 @@ var OPERATIONS_GUIDE = {
|
|
|
12783
13063
|
"guidance": "Read the stored report for the selected project and period. Retain evidence dates, scope, sample sizes, missing data, and separate mention/citation signals; do not generate fresh runs implicitly."
|
|
12784
13064
|
}
|
|
12785
13065
|
},
|
|
12786
|
-
"markdown": "# Canonry Operations Guide v1\n\nCanonry is an agent-first AI visibility platform. MCP is the universal entry\npoint for connected agents. Host-native skills are optional upgrades, not a\nprerequisite or a permission mechanism.\n\n## Connect and choose a route\n\nRead the initialization guidance, then call `canonry_help` with an `intent`:\n`status`, `diagnose`, `measurement`, `integrations`, `reports`, or a short task\ndescription. Select an accessible project with `canonry_projects_list` before\nusing its exact name in project tools. Inspect each listed tool's input schema;\nhelp suggests tool names, not invented arguments or authorization.\n\nHelp returns a versioned, compact route: connection `mode`, available `next`\ntools, workflow guidance, approval boundaries, and this guide's URL. It performs\nno provider calls, reads no project data, and changes no permissions.\n`includeCatalog: true` additionally returns toolkit details when needed.\n\nHosted connections use a fixed catalog. Help only suggests tools offered by that\nconnection; it never tells a hosted agent to dynamically load a toolkit. A\nprogressive local stdio connection may return `loadToolkits`: call\n`canonry_load_toolkit` with one returned name, await it, then call help again.\nLoading only changes local tool discovery, never server authority.\n\nThe optional `canonry://agent-operations/v1` MCP resource contains this same\nguide. If the host cannot read resources or open links, continue through help.\nDo not install a plugin, local runtime, or skill merely to use connected MCP.\nAn installed Codex or Claude Canonry skill contains a generated copy of this\nguide plus links to host-native references. It does not replace runtime help.\n\n## Vocabulary and evidence\n\n- **Mentioned** means the brand appears in answer text. **Cited** means its\n domain appears in source links. Either, both, or neither can occur; never\n compute one signal from the other.\n- `answerMentioned: null` means not checked, not false. Missing runs and empty\n populations mean no measurement, not zero visibility.\n- Preserve project, time window, provider, requested/served model, location,\n sample size, and query class when comparing evidence. Use server-returned\n metrics; do not invent a score from incompatible populations.\n- Simple projects and Advanced portfolios share the workflow. For Advanced\n results, preserve Property, Target, market, plan revision, and class scope.\n Groups organize navigation; do not infer an unrequested fan-out.\n- Research is isolated evidence, not tracked measurement. A probe still spends\n quota and persists evidence but is excluded from normal tracking metrics.\n\n## Workflows\n\n**Status:** read the stored overview and freshness first. Say when evidence is\nmissing instead of silently creating it.\n\n**Diagnose:** inspect stored history and comparable evidence. Explain what\nchanged separately from why it might have changed. A hypothesis is not a\nmeasured cause. Propose bounded verification if stored evidence is insufficient.\n\n**Measurement:** inspect the existing setup and results before proposing edits.\nKeep research, query tracking, plan publication, and sweep execution separate.\nFor direct research, submit the final editable query text in one context. For a\nreviewed batch, submit each explicit destination with its final text and one\nidempotency key. Pattern substitution happens in the client before either\nrequest; choosing a market or Property records a destination only and never\nrewrites a query or creates an automatic fan-out. `research.run` does not\nauthorize saving patterns, changing tracking, publishing plans, or settings.\nUse a supported preview where available, inspect its exact destination and\nrevision, then seek approval for the actual change. A preview may itself require\nwrite permission; never treat a dry-run flag as a universal safety guarantee.\n\n**Integrations:** inspect stored connection state and snapshot freshness first.\nProvider configuration evidence does not prove a browser event fired or a\nconversion was recorded. Connection, resource selection, refresh/sync, and live\nreads are separate actions. Credentials belong in the operator's secure setup\nflow, never in chat, tool arguments, reports, or public guidance.\n\n**Reports:** use saved evidence for the requested period and scope. Keep mention\nand citation signals separate, include dates and sample sizes, and state missing\nor stale inputs. For Advanced Property mention rankings, use\n`canonry_measurement_portfolio_summary` and its `mentionRanking.strongest`,\n`.weakest`, and `.excluded` lists. It defaults to non-brand questions; state the\nreturned class and report branded results separately. An unavailable portfolio\naggregate does not invalidate available Property mention rates. Flag excluded\nProperties individually; do not silently replace mention ranking with citation\nranking. Keep sample sizes and ties visible. Preparing a report does not\nauthorize new measurement.\n\n## Authority and approval\n\nStart with stored evidence. Before a live provider read, sweep, probe, research\nrun, sync, write, or externally visible action, obtain approval covering its\nexact target, action, and bounded work. Approval already given for that exact\noperation need not be asked for again, but does not extend to more projects,\nlarger batches, retries with new identities, or recurring work.\n\nHTTP GET and MCP `readOnlyHint` describe aspects of an operation, not its cost\nor permission. Provider discovery, account reads, and live diagnostics may\nconsume quota even when labeled read-only. If the tool's effect is unclear,\ninspect its description and request direction before calling it.\n\nAuthentication, role/scope checks, project restrictions, quotas, and guarded\napproval receipts are enforced by the server. Help, skills, resources, and tool\nvisibility cannot grant authority. Never change credentials, endpoints, or\nproject identifiers to work around a missing tool or a `403` response.\n\nFor guarded ads writes, inspect unresolved operation receipts before retrying.\nUse the receipt's supported recovery action; do not replay a mutation under a\nnew identity. An executor cannot create or widen its own human approval grant.\nOn ambiguous results, exhausted bounds, or refusal, stop and report what is\nknown and what permission or operator action is needed.\n\n## Version and source\n\nThis public, versioned document is the source for initialization guidance,\nintent routes, the optional resource, and generated Canonry `SKILL.md` files.\nGuide v1 may receive compatible clarifications; incompatible routing contracts\nrequire a new guide version. The running server's help describes its actual\ncatalog and remains usable without fetching this document.\n"
|
|
13066
|
+
"markdown": "# Canonry Operations Guide v1\n\nCanonry is an agent-first AI visibility platform. MCP is the universal entry\npoint for connected agents. Host-native skills are optional upgrades, not a\nprerequisite or a permission mechanism.\n\n## Connect and choose a route\n\nRead the initialization guidance, then call `canonry_help` with an `intent`:\n`status`, `diagnose`, `operations`, `prospecting`, `measurement`, `integrations`,\n`reports`, or a short task\ndescription. Select an accessible project with `canonry_projects_list` before\nusing its exact name in project tools. Inspect each listed tool's input schema;\nhelp suggests tool names, not invented arguments or authorization.\n\nHelp returns a versioned, compact route: connection `mode`, available `next`\ntools, workflow guidance, approval boundaries, and this guide's URL. It performs\nno provider calls, reads no project data, and changes no permissions.\n`next` lists stored reads. Optional `actions` lists loaded tools for work that\nrequires approval; listing an action does not authorize or execute it.\n`includeCatalog: true` additionally returns toolkit details when needed.\n\nHosted connections use a fixed catalog. Help only suggests tools offered by that\nconnection; it never tells a hosted agent to dynamically load a toolkit. A\nprogressive local stdio connection may return `loadToolkits`: call\n`canonry_load_toolkit` with one returned name, await it, then call help again.\nLoading only changes local tool discovery, never server authority.\n\nThe optional `canonry://agent-operations/v1` MCP resource contains this same\nguide. If the host cannot read resources or open links, continue through help.\nDo not install a plugin, local runtime, or skill merely to use connected MCP.\nAn installed Codex or Claude Canonry skill contains a generated copy of this\nguide plus links to host-native references. It does not replace runtime help.\n\n## Vocabulary and evidence\n\n- **Mentioned** means the brand appears in answer text. **Cited** means its\n domain appears in source links. Either, both, or neither can occur; never\n compute one signal from the other.\n- `answerMentioned: null` means not checked, not false. Missing runs and empty\n populations mean no measurement, not zero visibility.\n- Preserve project, time window, provider, requested/served model, location,\n sample size, and query class when comparing evidence. Use server-returned\n metrics; do not invent a score from incompatible populations.\n- Simple projects and Advanced portfolios share the workflow. For Advanced\n results, preserve Property, Target, market, plan revision, and class scope.\n Groups organize navigation; do not infer an unrequested fan-out.\n- Research is isolated evidence, not tracked measurement. A probe still spends\n quota and persists evidence but is excluded from normal tracking metrics.\n\n## Workflows\n\n**Status:** read the stored overview and freshness first. Say when evidence is\nmissing instead of silently creating it.\n\n**Diagnose:** inspect stored history and comparable evidence. Explain what\nchanged separately from why it might have changed. A hypothesis is not a\nmeasured cause. Propose bounded verification if stored evidence is insufficient.\n\n**Prospecting:** generate a one-shot company snapshot without creating a project.\nInspect stored provider settings first. Agree on the company, domain, selected\nproviders, and queries before starting the quota-spending snapshot action.\nBrowser-only selection requires manual queries. Progressive stdio help offers\nthe discovery toolkit when this connection permits snapshots; load it, then\ncall help again. Fixed catalogs offer only already available actions. Read-only\nand restricted connections must not bypass missing snapshot access.\n\n**Measurement:** inspect the existing setup and results before proposing edits.\nKeep research, query tracking, plan publication, and sweep execution separate.\nFor direct research, submit the final editable query text in one context. For a\nreviewed batch, submit each explicit destination with its final text and one\nidempotency key. Pattern substitution happens in the client before either\nrequest; choosing a market or Property records a destination only and never\nrewrites a query or creates an automatic fan-out. `research.run` does not\nauthorize saving patterns, changing tracking, publishing plans, or settings.\nUse a supported preview where available, inspect its exact destination and\nrevision, then seek approval for the actual change. A preview may itself require\nwrite permission; never treat a dry-run flag as a universal safety guarantee.\n\n**Integrations:** inspect stored connection state and snapshot freshness first.\nProvider configuration evidence does not prove a browser event fired or a\nconversion was recorded. Connection, resource selection, refresh/sync, and live\nreads are separate actions. Credentials belong in the operator's secure setup\nflow, never in chat, tool arguments, reports, or public guidance.\n\n**Reports:** use saved evidence for the requested period and scope. Keep mention\nand citation signals separate, include dates and sample sizes, and state missing\nor stale inputs. For Advanced Property mention rankings, use\n`canonry_measurement_portfolio_summary` and its `mentionRanking.strongest`,\n`.weakest`, and `.excluded` lists. It defaults to non-brand questions; state the\nreturned class and report branded results separately. An unavailable portfolio\naggregate does not invalidate available Property mention rates. Flag excluded\nProperties individually; do not silently replace mention ranking with citation\nranking. Keep sample sizes and ties visible. Preparing a report does not\nauthorize new measurement.\n\n## Authority and approval\n\n### Agent operations\n\nUse `canonry_key_self` to inspect the current credential's scopes and project\nboundary without exposing its token. `canonry_settings_get` and\n`canonry_telemetry_get` describe the connected server, not the agent's local\nmachine. Telemetry reports configured preference, effective state, and any\nenvironment override; inspecting status never creates an anonymous identifier.\nAfter approval, `canonry_telemetry_update` changes that preference and\n`canonry_provider_settings_update` changes an already-configured provider's\nmodel/quota. Both require `settings.write`; neither accepts credentials.\n\n`canonry_logs_list` reads bounded, redacted runtime events from both the\napplication logger and Fastify request/error logging. It requires an\ninstance-wide `logs.read` grant (or wildcard), and\nadmin role for signed-in users. Project-scoped keys cannot use it, even with a\nproject filter. A `logs.read`-only key is read-only automatically, without a\nsecond `read` marker. Named `*.read` scopes cannot grant mutations; an explicit\nwrite grant is needed and remains subject to its route gates. Returned messages\nare sanitized and bounded; raw request or response bodies, headers, cookies,\nprovider payloads, and stacks are not\npart of the queryable surface. The same secret-redaction policy runs before\nconsole output and storage. Do not deliberately log secrets: redaction is a\ndefense in depth, not permission to put credentials into diagnostic strings.\nOpaque escaped payloads containing secret assignments are omitted when safe\npartial masking cannot be guaranteed; correlate their retained error codes and IDs.\n\nFile-backed hosts retain runtime logs in SQLite across restarts, bounded to\n10,000 events and seven days. In-memory hosts report `retention: \"process\"`.\nFilter by `actor`, `requestId`, `runId`, `projectId`, `module`, `level`, or an\ninclusive `since`/`until` interval. Keep filters unchanged when resuming an\nopaque cursor; retention eviction can invalidate it. Inspect `retentionPolicy`,\n`captureErrors`, `dropped`, `truncated`, and `retention` before drawing\nconclusions. Missing logs are not proof that an action did not happen. Use\n`canonry_project_history` or `canonry_history_global` for persistent audit events;\noffset pages have deterministic ordering but are not snapshots of concurrent writes.\n\nAudit `actor` comes from authenticated identity (`user:<id>` or `api-key:<id>`),\nnot a caller-supplied header. A delegated MCP credential records its originating\nuser as actor and the actual credential in `credentialId`. `requestId` correlates\nHTTP events; `userAgent` and `actorSession` are bounded, untrusted client hints,\nnever identity or permission grants. Older audit rows are not backfilled with\nidentities the server cannot prove.\n\nBoth shipped HTTP hosts issue restart-safe UUID request IDs and return them in\n`x-request-id`. Use that value to correlate a CLI/API failure with log entries;\nHTTP diagnostics retain the method and route template, not raw URL parameters.\nRequest-bound loggers retain completion attribution, while generic background\ncontinuations stop inheriting caller identity after the response completes.\nCapture covers the owning server process after initialization, not arbitrary\nconsole output, other worker processes, or host/container logs. Run one server\ninstance per process and database, as required by the single-tenant deployment\nmodel; this is not a cross-tenant or distributed log collector.\n\nFor CLI use, settings reads are remote. Google setup and telemetry retain their\nlocal defaults: pass `--target server` explicitly to configure the connected\nserver. `schedule list <project>` lists all schedule kinds, and\n`notify events --target server` discovers the server's event catalog.\n\nMCP returns legacy text JSON plus structured results. Objects keep their shape;\narrays use `{items: [...]}` in `structuredContent`, and scalars use `{value: ...}`.\nErrors preserve the existing envelope and CLI exit codes: HTTP 4xx (including\n429 policy limits) use exit 1; HTTP 5xx use exit 2. Server-provided `Retry-After`\nand request IDs are exposed as `retryAfterMs` and `requestId` when available;\nclients do not infer retryability from HTTP 429 or retry automatically.\nFor a write with an ambiguous outcome, inspect saved state or its receipt before\nretrying; a retry hint is not proof that repeating a write is safe.\n\n### Action boundaries\n\nStart with stored evidence. Before a live provider read, sweep, probe, research\nrun, sync, write, or externally visible action, obtain approval covering its\nexact target, action, and bounded work. Approval already given for that exact\noperation need not be asked for again, but does not extend to more projects,\nlarger batches, retries with new identities, or recurring work.\n\nHTTP GET and MCP `readOnlyHint` describe aspects of an operation, not its cost\nor permission. Provider discovery, account reads, and live diagnostics may\nconsume quota even when labeled read-only. If the tool's effect is unclear,\ninspect its description and request direction before calling it.\n\nAuthentication, role/scope checks, project restrictions, quotas, and guarded\napproval receipts are enforced by the server. Help, skills, resources, and tool\nvisibility cannot grant authority. Never change credentials, endpoints, or\nproject identifiers to work around a missing tool or a `403` response.\n\nFor guarded ads writes, inspect unresolved operation receipts before retrying.\nUse the receipt's supported recovery action; do not replay a mutation under a\nnew identity. An executor cannot create or widen its own human approval grant.\nOn ambiguous results, exhausted bounds, or refusal, stop and report what is\nknown and what permission or operator action is needed.\n\n## Version and source\n\nThis public, versioned document is the source for initialization guidance,\nintent routes, the optional resource, and generated Canonry `SKILL.md` files.\nGuide v1 may receive compatible clarifications; incompatible routing contracts\nrequire a new guide version. The running server's help describes its actual\ncatalog and remains usable without fetching this document.\n"
|
|
12787
13067
|
};
|
|
12788
13068
|
|
|
12789
13069
|
// src/mcp/operations-guide.ts
|
|
@@ -12793,11 +13073,14 @@ function operationsHelp(catalog, mode, intent = "", includeCatalog = false) {
|
|
|
12793
13073
|
const workflow = workflows.find((name) => OPERATIONS_GUIDE.workflows[name].keywords.some((word) => words.has(word))) ?? "status";
|
|
12794
13074
|
const route = OPERATIONS_GUIDE.workflows[workflow];
|
|
12795
13075
|
const available = /* @__PURE__ */ new Set([...catalog.coreTools, ...catalog.toolkits.filter((t) => t.loaded).flatMap((t) => t.tools)]);
|
|
12796
|
-
const
|
|
12797
|
-
|
|
13076
|
+
const reads = route.next;
|
|
13077
|
+
const requestedActions = "actions" in route ? route.actions : [];
|
|
13078
|
+
const next = reads.filter((name) => available.has(name)).slice(0, 4);
|
|
13079
|
+
const actions = requestedActions.filter((name) => available.has(name));
|
|
13080
|
+
if (reads.includes("canonry_projects_list") && next.length < 2 && available.has("canonry_project_overview") && !next.includes("canonry_project_overview")) {
|
|
12798
13081
|
next.push("canonry_project_overview");
|
|
12799
13082
|
}
|
|
12800
|
-
const wanted =
|
|
13083
|
+
const wanted = [...reads, ...requestedActions];
|
|
12801
13084
|
const loadToolkits = mode === "stdio-progressive" ? catalog.toolkits.filter((t) => !t.loaded && t.tools.some((name) => wanted.includes(name))).map((t) => t.name) : [];
|
|
12802
13085
|
return {
|
|
12803
13086
|
guideVersion: OPERATIONS_GUIDE.guideVersion,
|
|
@@ -12805,6 +13088,7 @@ function operationsHelp(catalog, mode, intent = "", includeCatalog = false) {
|
|
|
12805
13088
|
scope: catalog.scope,
|
|
12806
13089
|
workflow,
|
|
12807
13090
|
next,
|
|
13091
|
+
...actions.length ? { actions } : {},
|
|
12808
13092
|
workflows,
|
|
12809
13093
|
guidance: route.guidance,
|
|
12810
13094
|
approvalBoundary: OPERATIONS_GUIDE.approvalBoundary,
|
|
@@ -12822,7 +13106,7 @@ function createCanonryMcpServer(options = {}) {
|
|
|
12822
13106
|
}
|
|
12823
13107
|
var SERVER_INSTRUCTIONS = OPERATIONS_GUIDE.initialize;
|
|
12824
13108
|
function createCanonryMcpServerWithCatalog(options = {}) {
|
|
12825
|
-
const clientFactory = options.clientFactory ?? createApiClient;
|
|
13109
|
+
const clientFactory = options.clientFactory ?? (() => createApiClient({ clientName: "canonry-mcp" }));
|
|
12826
13110
|
const client2 = clientFactory();
|
|
12827
13111
|
const scope = options.scope ?? "all";
|
|
12828
13112
|
const server = new McpServer({
|
|
@@ -12842,6 +13126,7 @@ function createCanonryMcpServerWithCatalog(options = {}) {
|
|
|
12842
13126
|
title: tool.title,
|
|
12843
13127
|
description: tool.description,
|
|
12844
13128
|
inputSchema: tool.inputSchema,
|
|
13129
|
+
outputSchema: tool.outputSchema,
|
|
12845
13130
|
annotations: tool.annotations
|
|
12846
13131
|
},
|
|
12847
13132
|
async (input) => withToolErrors(async () => {
|
|
@@ -12867,7 +13152,7 @@ var loadToolkitInputSchema = z5.object({
|
|
|
12867
13152
|
name: z5.enum(CANONRY_MCP_TOOLKIT_NAMES).describe("Toolkit name. List options with canonry_help.")
|
|
12868
13153
|
});
|
|
12869
13154
|
var helpInputSchema = z5.object({
|
|
12870
|
-
intent: z5.string().max(200).optional().describe("Workflow (status, diagnose, measurement, integrations, reports) or a short task description."),
|
|
13155
|
+
intent: z5.string().max(200).optional().describe("Workflow (status, diagnose, prospecting, measurement, integrations, reports) or a short task description."),
|
|
12871
13156
|
includeCatalog: z5.boolean().optional().describe("Include full toolkit details. Omit for a compact, actionable route.")
|
|
12872
13157
|
});
|
|
12873
13158
|
function registerMetaTools(server, catalog, opts) {
|
|
@@ -12875,7 +13160,7 @@ function registerMetaTools(server, catalog, opts) {
|
|
|
12875
13160
|
"canonry_help",
|
|
12876
13161
|
{
|
|
12877
13162
|
title: "Guide a Canonry workflow",
|
|
12878
|
-
description: "Start here: route an intent to available stored-evidence tools,
|
|
13163
|
+
description: "Start here: route an intent to available stored-evidence tools, separately listed actions requiring approval, and workflow guidance. No provider calls or installation required. Optionally include full toolkit details.",
|
|
12879
13164
|
inputSchema: helpInputSchema.shape,
|
|
12880
13165
|
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
|
|
12881
13166
|
},
|