@canonry/canonry 7.18.1 → 7.20.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/assets/agent-workspace/skills/aero/references/agent-operations.md +14 -0
- package/assets/agent-workspace/skills/canonry/SKILL.md +14 -0
- package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +33 -1
- package/assets/assets/AuditHistoryPanel-C0vj3liH.js +1 -0
- package/assets/assets/{BacklinksPage-BT3j4tQK.js → BacklinksPage-TnDsI9Wu.js} +1 -1
- package/assets/assets/{HistoryPage-BHV_3wbQ.js → HistoryPage-DEEC3g6M.js} +1 -1
- package/assets/assets/MeasurementPropertyPage-MT4tFOwx.js +4 -0
- package/assets/assets/ProjectPage-NI-bjpfN.js +8 -0
- package/assets/assets/{RunsPage-Cx5yMuzN.js → RunsPage-GIKqPu0J.js} +1 -1
- package/assets/assets/{SettingsPage-DrZ-eswp.js → SettingsPage-DLFwSj4J.js} +1 -1
- package/assets/assets/{SiteHealthSection-XOUI_75e.js → SiteHealthSection-CYG9IMh5.js} +3 -3
- package/assets/assets/{TrafficPage-DciX-fl5.js → TrafficPage-oOxDmxQq.js} +3 -3
- package/assets/assets/{TrafficSourceDetailPage-D1_lnRoS.js → TrafficSourceDetailPage-BGrwpVvM.js} +1 -1
- package/assets/assets/{extract-error-message-Cw5pcZtv.js → extract-error-message-DRDQFsgG.js} +1 -1
- package/assets/assets/{index-DIA9jvMi.js → index-B_2gPTCa.js} +36 -36
- package/assets/assets/{react-sigma_core.esm.min-Cc8jHlvQ.js → react-sigma_core.esm.min-DzDqz7hq.js} +1 -1
- package/assets/assets/v2-overview-adapter-BHzFliuj.js +1 -0
- package/assets/index.html +1 -1
- package/dist/{chunk-U7D7LNVJ.js → chunk-222NAFTY.js} +2 -2
- package/dist/{chunk-COQOQYRZ.js → chunk-46JZR2IV.js} +145 -31
- package/dist/{chunk-EAAM47H6.js → chunk-5IXQAOVK.js} +18 -3
- package/dist/{chunk-JUOFNJLV.js → chunk-6H2BC5EY.js} +3 -3
- package/dist/{chunk-PRL6UQ7L.js → chunk-KF7LRHGJ.js} +368 -211
- package/dist/{chunk-X2S7D3MN.js → chunk-MRKV43TV.js} +139 -7
- package/dist/{chunk-JMC7CEJB.js → chunk-NDQOCFJQ.js} +61 -43
- package/dist/cli.js +229 -45
- package/dist/{demo-server-XWRIXME5.js → demo-server-32PU7BM6.js} +4 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -6
- package/dist/{intelligence-service-332S7D7Y.js → intelligence-service-256DQBVR.js} +2 -2
- package/dist/mcp.js +4 -4
- package/package.json +13 -13
- package/assets/assets/AuditHistoryPanel-RAYlf3B4.js +0 -1
- package/assets/assets/MeasurementPropertyPage-9UFPKw-i.js +0 -1
- package/assets/assets/ProjectPage-C1_-qiHw.js +0 -8
- package/assets/assets/v2-overview-adapter-Ca5F20Kr.js +0 -1
|
@@ -42,6 +42,7 @@ var ProviderNames = {
|
|
|
42
42
|
};
|
|
43
43
|
var providerNameSchema = z2.string().min(1);
|
|
44
44
|
var providerModelsSchema = z2.record(z2.string(), z2.string().trim().min(1));
|
|
45
|
+
var API_PROVIDER_NAMES = ["gemini", "openai", "claude", "perplexity", "muse", "local"];
|
|
45
46
|
var apiProviderNameSchema = z2.string().min(1);
|
|
46
47
|
function isBrowserProvider(name) {
|
|
47
48
|
return name.startsWith("cdp:");
|
|
@@ -3855,7 +3856,7 @@ var measurementOverviewResponseSchema = z6.object({
|
|
|
3855
3856
|
/** Fields omitted from the compact projection; omission never means an empty result. */
|
|
3856
3857
|
detailsOmitted: z6.array(z6.string()).optional()
|
|
3857
3858
|
}).strict();
|
|
3858
|
-
var measurementEvidenceShapeSchema = z6.enum(["sources", "answers"]);
|
|
3859
|
+
var measurementEvidenceShapeSchema = z6.enum(["sources", "answers", "other-queries"]);
|
|
3859
3860
|
var MeasurementEvidenceShapes = measurementEvidenceShapeSchema.enum;
|
|
3860
3861
|
var MEASUREMENT_EVIDENCE_DEFAULT_SHAPE = MeasurementEvidenceShapes.sources;
|
|
3861
3862
|
var measurementPropertyEvidenceQuerySchema = z6.object({
|
|
@@ -10688,8 +10689,19 @@ var visibilityReportSummarySchema = z24.object({
|
|
|
10688
10689
|
if (value.bothSignals + value.mentionedOnly + value.citedOnly + value.neither + value.notMeasured !== value.total) {
|
|
10689
10690
|
ctx.addIssue({ code: z24.ZodIssueCode.custom, message: "Outcome partition must sum to total" });
|
|
10690
10691
|
}
|
|
10691
|
-
})
|
|
10692
|
-
|
|
10692
|
+
}),
|
|
10693
|
+
/**
|
|
10694
|
+
* Of `outcomes.notMeasured`, the Properties whose mention was measured and
|
|
10695
|
+
* whose citation is unknown only because an answer's source list was partly
|
|
10696
|
+
* saved (`unchecked`). It says why those Properties read not measured, and is
|
|
10697
|
+
* a subset, never an extra bucket. Present only when at least one is.
|
|
10698
|
+
*/
|
|
10699
|
+
notMeasuredUnchecked: z24.number().int().positive().optional()
|
|
10700
|
+
}).strict().superRefine((value, ctx) => {
|
|
10701
|
+
if (value.notMeasuredUnchecked !== void 0 && value.notMeasuredUnchecked > value.outcomes.notMeasured) {
|
|
10702
|
+
ctx.addIssue({ code: z24.ZodIssueCode.custom, path: ["notMeasuredUnchecked"], message: "notMeasuredUnchecked is a subset of outcomes.notMeasured" });
|
|
10703
|
+
}
|
|
10704
|
+
});
|
|
10693
10705
|
var visibilityReportTrendPointSchema = z24.object({
|
|
10694
10706
|
runId: nonBlankIdSchema,
|
|
10695
10707
|
createdAt: dateTimeSchema,
|
|
@@ -10720,7 +10732,27 @@ var visibilityReportQueryRowSchema = z24.object({
|
|
|
10720
10732
|
marketKeys: z24.array(nonBlankIdSchema).optional(),
|
|
10721
10733
|
answerCount: z24.number().int().nonnegative(),
|
|
10722
10734
|
mentionCoverage: visibilityReportRateSchema,
|
|
10723
|
-
citationCoverage: visibilityReportRateSchema
|
|
10735
|
+
citationCoverage: visibilityReportRateSchema,
|
|
10736
|
+
/**
|
|
10737
|
+
* Answers in this row whose source list was only partly saved, so they are in
|
|
10738
|
+
* neither side of `citationCoverage` (its `unchecked`, or the reason a
|
|
10739
|
+
* one-answer rate is unavailable). Their saved links still show what they
|
|
10740
|
+
* cited: `citedAnswers` of them cite one of the row's Properties, and
|
|
10741
|
+
* `citedTargetKeys` names which. That is evidence, never a rate. Absent when
|
|
10742
|
+
* every answer's sources were fully saved.
|
|
10743
|
+
*/
|
|
10744
|
+
uncheckedSources: z24.object({
|
|
10745
|
+
answers: z24.number().int().positive(),
|
|
10746
|
+
citedAnswers: z24.number().int().nonnegative(),
|
|
10747
|
+
citedTargetKeys: z24.array(nonBlankIdSchema)
|
|
10748
|
+
}).strict().superRefine((value, ctx) => {
|
|
10749
|
+
if (value.citedAnswers > value.answers) {
|
|
10750
|
+
ctx.addIssue({ code: z24.ZodIssueCode.custom, path: ["citedAnswers"], message: "citedAnswers cannot exceed answers" });
|
|
10751
|
+
}
|
|
10752
|
+
if (value.citedAnswers === 0 !== (value.citedTargetKeys.length === 0)) {
|
|
10753
|
+
ctx.addIssue({ code: z24.ZodIssueCode.custom, path: ["citedTargetKeys"], message: "citedTargetKeys is empty exactly when no saved link cites a Property" });
|
|
10754
|
+
}
|
|
10755
|
+
}).optional()
|
|
10724
10756
|
}).strict();
|
|
10725
10757
|
var visibilityReportEvidenceRowSchema = z24.object({
|
|
10726
10758
|
answerId: nonBlankIdSchema,
|
|
@@ -11442,6 +11474,28 @@ var measurementAnswerEvidenceSchema = z26.object({
|
|
|
11442
11474
|
historical: z26.boolean(),
|
|
11443
11475
|
evidenceComplete: z26.boolean()
|
|
11444
11476
|
}).strict();
|
|
11477
|
+
var measurementOtherQuerySourceSchema = z26.object({
|
|
11478
|
+
sourceUrl: z26.string(),
|
|
11479
|
+
normalizedUrl: z26.string().nullable(),
|
|
11480
|
+
matchedUrlIds: z26.array(z26.string().trim().min(1))
|
|
11481
|
+
}).strict();
|
|
11482
|
+
var measurementOtherQueryCitationSchema = z26.object({
|
|
11483
|
+
observationId: z26.string().trim().min(1),
|
|
11484
|
+
expectedSlotId: z26.string().trim().min(1),
|
|
11485
|
+
executionId: z26.string().trim().min(1),
|
|
11486
|
+
provider: providerNameSchema,
|
|
11487
|
+
queryText: z26.string().trim().min(1),
|
|
11488
|
+
location: z26.string().nullable(),
|
|
11489
|
+
queryClass: z26.enum(["branded", "non-brand"]),
|
|
11490
|
+
assignedTargetKeys: z26.array(measurementV2StableKeySchema).min(1),
|
|
11491
|
+
/** Only this Property's pages; other links in the answer are not listed. */
|
|
11492
|
+
sources: z26.array(measurementOtherQuerySourceSchema).min(1),
|
|
11493
|
+
/** Always the FULL count of this Property's cited pages in the answer. */
|
|
11494
|
+
sourceCount: z26.number().int().positive(),
|
|
11495
|
+
sourcesTruncated: z26.boolean(),
|
|
11496
|
+
/** False when the engine's source list was only partly saved. */
|
|
11497
|
+
evidenceComplete: z26.boolean()
|
|
11498
|
+
}).strict();
|
|
11445
11499
|
var measurementReportDiagnosticsSchema = z26.object({
|
|
11446
11500
|
bridgedObservationIds: z26.array(z26.string()),
|
|
11447
11501
|
historicalObservationIds: z26.array(z26.string()),
|
|
@@ -11483,10 +11537,12 @@ var measurementPropertyEvidenceResponseSchema = z26.object({
|
|
|
11483
11537
|
completedAt: z26.string().datetime().optional()
|
|
11484
11538
|
}).strict(),
|
|
11485
11539
|
evidence: measurementCursorPageSchema(measurementAttributionEvidenceSchema).optional(),
|
|
11486
|
-
answers: measurementCursorPageSchema(measurementAnswerEvidenceSchema).optional()
|
|
11540
|
+
answers: measurementCursorPageSchema(measurementAnswerEvidenceSchema).optional(),
|
|
11541
|
+
/** Served for `shape=other-queries`: citations of this Property's pages outside its own queries. */
|
|
11542
|
+
otherQueries: measurementCursorPageSchema(measurementOtherQueryCitationSchema).optional()
|
|
11487
11543
|
}).strict().refine(
|
|
11488
|
-
(response) => response.evidence
|
|
11489
|
-
{ message: "Exactly one of evidence or
|
|
11544
|
+
(response) => [response.evidence, response.answers, response.otherQueries].filter((page) => page !== void 0).length === 1,
|
|
11545
|
+
{ message: "Exactly one of evidence, answers or otherQueries is present, naming the shape that was served." }
|
|
11490
11546
|
);
|
|
11491
11547
|
|
|
11492
11548
|
// ../contracts/src/run-fill.ts
|
|
@@ -12983,6 +13039,57 @@ var measurementDraftApplyGroupMembershipResponseSchema = measurementDraftMutatio
|
|
|
12983
13039
|
unchangedMemberships: z30.number().int().nonnegative()
|
|
12984
13040
|
}).strict();
|
|
12985
13041
|
|
|
13042
|
+
// ../contracts/src/measurement-target-names.ts
|
|
13043
|
+
function measurementNameWords(value) {
|
|
13044
|
+
return value.normalize("NFKC").toLowerCase().match(/[\p{L}\p{N}]+/gu) ?? [];
|
|
13045
|
+
}
|
|
13046
|
+
function measurementNameKey(value) {
|
|
13047
|
+
return measurementNameWords(value).join("\0");
|
|
13048
|
+
}
|
|
13049
|
+
function qualifiedNameIncludesName(qualifiedName, names) {
|
|
13050
|
+
const qualifiedKey = measurementNameKey(qualifiedName);
|
|
13051
|
+
return names.map(measurementNameKey).filter(Boolean).some((nameKey) => nameKey !== qualifiedKey && `\0${qualifiedKey}\0`.includes(`\0${nameKey}\0`));
|
|
13052
|
+
}
|
|
13053
|
+
var MEASUREMENT_TARGET_NAME_MIN_KEY_LENGTH = MIN_DOMAIN_BRAND_KEY_LENGTH;
|
|
13054
|
+
var MeasurementTargetNameIssueCodes = {
|
|
13055
|
+
/** Under the name floor: short tokens match unrelated words. */
|
|
13056
|
+
short: "target-name-short",
|
|
13057
|
+
/** No project brand name in it: other places with the same name can match. */
|
|
13058
|
+
withoutBrand: "target-name-without-brand",
|
|
13059
|
+
/** A qualified name with no stored name inside it; publishing refuses it. */
|
|
13060
|
+
qualifiedWithoutName: "target-qualified-name-without-name"
|
|
13061
|
+
};
|
|
13062
|
+
function measurementTargetNameIssues(input) {
|
|
13063
|
+
const brands = usableBrandAliases(input.brandNames);
|
|
13064
|
+
const brandMatcher = brands.length > 0 ? compileBrandAliases(brands) : null;
|
|
13065
|
+
const issues = [];
|
|
13066
|
+
input.aliases.forEach((value, index) => {
|
|
13067
|
+
if (!value.trim()) return;
|
|
13068
|
+
if (brandKeyFromText(value).length < MEASUREMENT_TARGET_NAME_MIN_KEY_LENGTH) {
|
|
13069
|
+
issues.push({ code: MeasurementTargetNameIssueCodes.short, field: "aliases", index, value });
|
|
13070
|
+
} else if (brandMatcher !== null && !matcherMatchesText(brandMatcher, value)) {
|
|
13071
|
+
issues.push({ code: MeasurementTargetNameIssueCodes.withoutBrand, field: "aliases", index, value });
|
|
13072
|
+
}
|
|
13073
|
+
});
|
|
13074
|
+
input.identityAliases?.forEach((value, index) => {
|
|
13075
|
+
if (!value.trim()) return;
|
|
13076
|
+
if (!qualifiedNameIncludesName(value, input.aliases)) {
|
|
13077
|
+
issues.push({ code: MeasurementTargetNameIssueCodes.qualifiedWithoutName, field: "identityAliases", index, value });
|
|
13078
|
+
}
|
|
13079
|
+
});
|
|
13080
|
+
return issues;
|
|
13081
|
+
}
|
|
13082
|
+
function measurementTargetNameIssueMessage(issue) {
|
|
13083
|
+
switch (issue.code) {
|
|
13084
|
+
case MeasurementTargetNameIssueCodes.short:
|
|
13085
|
+
return `"${issue.value.trim()}" is too short to match safely. A name needs at least ${MEASUREMENT_TARGET_NAME_MIN_KEY_LENGTH} letters or numbers, or it can match unrelated words in an answer.`;
|
|
13086
|
+
case MeasurementTargetNameIssueCodes.withoutBrand:
|
|
13087
|
+
return `"${issue.value.trim()}" does not include your brand name, so answers about other places with this name can count for this property.`;
|
|
13088
|
+
case MeasurementTargetNameIssueCodes.qualifiedWithoutName:
|
|
13089
|
+
return `"${issue.value.trim()}" must include one of this property's names plus more words, such as a street or city. Publishing is refused until it does.`;
|
|
13090
|
+
}
|
|
13091
|
+
}
|
|
13092
|
+
|
|
12986
13093
|
// ../contracts/src/model-pointers.ts
|
|
12987
13094
|
import { z as z31 } from "zod";
|
|
12988
13095
|
|
|
@@ -15064,6 +15171,19 @@ var providerSummaryEntryDtoSchema = z40.object({
|
|
|
15064
15171
|
/** Whether Vertex AI is configured for this provider (Gemini only). */
|
|
15065
15172
|
vertexConfigured: z40.boolean().optional()
|
|
15066
15173
|
});
|
|
15174
|
+
var providerReloadRequestSchema = z40.object({
|
|
15175
|
+
configPath: z40.string().min(1).max(4096).optional(),
|
|
15176
|
+
databasePath: z40.string().min(1).max(4096).optional()
|
|
15177
|
+
}).strict().refine(
|
|
15178
|
+
(input) => input.configPath === void 0 === (input.databasePath === void 0),
|
|
15179
|
+
"configPath and databasePath must be supplied together"
|
|
15180
|
+
);
|
|
15181
|
+
var providerReloadErrorReasonSchema = z40.enum(["install-identity-mismatch"]);
|
|
15182
|
+
var ProviderReloadErrorReasons = providerReloadErrorReasonSchema.enum;
|
|
15183
|
+
var providerReloadResponseDtoSchema = z40.object({
|
|
15184
|
+
reloaded: z40.literal(true),
|
|
15185
|
+
providers: z40.array(providerSummaryEntryDtoSchema)
|
|
15186
|
+
});
|
|
15067
15187
|
var providerCatalogEntryDtoSchema = z40.object({
|
|
15068
15188
|
name: z40.string(),
|
|
15069
15189
|
displayName: z40.string(),
|
|
@@ -21708,6 +21828,8 @@ var UI_ACTIONS = [
|
|
|
21708
21828
|
"notification.save",
|
|
21709
21829
|
"notification.test",
|
|
21710
21830
|
"measurement_plan.publish",
|
|
21831
|
+
/** A Property's names or qualified names were saved into the measurement draft. */
|
|
21832
|
+
"property_names.save",
|
|
21711
21833
|
"discovery.run",
|
|
21712
21834
|
"api_key.create",
|
|
21713
21835
|
"api_key.revoke",
|
|
@@ -21806,6 +21928,7 @@ var UI_ROUTE_FIXED_CHILDREN = /* @__PURE__ */ new Set([
|
|
|
21806
21928
|
"locations/discover",
|
|
21807
21929
|
"notifications/events",
|
|
21808
21930
|
"operations/logs",
|
|
21931
|
+
"providers/reload",
|
|
21809
21932
|
"queries/generate",
|
|
21810
21933
|
"queries/replace-preview",
|
|
21811
21934
|
"runs/latest",
|
|
@@ -22529,6 +22652,7 @@ export {
|
|
|
22529
22652
|
RetrievalContracts,
|
|
22530
22653
|
providerQuotaPolicySchema,
|
|
22531
22654
|
ProviderNames,
|
|
22655
|
+
API_PROVIDER_NAMES,
|
|
22532
22656
|
isBrowserProvider,
|
|
22533
22657
|
resolveProviderInput,
|
|
22534
22658
|
locationContextSchema,
|
|
@@ -22998,6 +23122,11 @@ export {
|
|
|
22998
23122
|
measurementDraftPreviewGroupMembershipResponseSchema,
|
|
22999
23123
|
measurementDraftApplyGroupMembershipRequestSchema,
|
|
23000
23124
|
measurementDraftApplyGroupMembershipResponseSchema,
|
|
23125
|
+
measurementNameWords,
|
|
23126
|
+
measurementNameKey,
|
|
23127
|
+
qualifiedNameIncludesName,
|
|
23128
|
+
measurementTargetNameIssues,
|
|
23129
|
+
measurementTargetNameIssueMessage,
|
|
23001
23130
|
formatPercent,
|
|
23002
23131
|
formatIsoDate,
|
|
23003
23132
|
formatIsoDateInTimeZone,
|
|
@@ -23111,6 +23240,9 @@ export {
|
|
|
23111
23240
|
LlmCapabilities,
|
|
23112
23241
|
LLM_CAPABILITIES,
|
|
23113
23242
|
providerSummaryEntryDtoSchema,
|
|
23243
|
+
providerReloadRequestSchema,
|
|
23244
|
+
ProviderReloadErrorReasons,
|
|
23245
|
+
providerReloadResponseDtoSchema,
|
|
23114
23246
|
integrationSettingsSummaryDtoSchema,
|
|
23115
23247
|
settingsDtoSchema,
|
|
23116
23248
|
ProviderBatchRequestOutcomes,
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
PACKAGE_VERSION,
|
|
6
6
|
canonryMcpTools,
|
|
7
7
|
isMachineFormat
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-5IXQAOVK.js";
|
|
9
9
|
import {
|
|
10
10
|
AGENT_PROVIDER_IDS,
|
|
11
11
|
CANONRY_NPM_PACKAGE_URL,
|
|
@@ -36,7 +36,6 @@ import {
|
|
|
36
36
|
operationalLogListReadSchema,
|
|
37
37
|
providerBatchConfigSchema,
|
|
38
38
|
providerPricingSchema,
|
|
39
|
-
providerQuotaPolicySchema,
|
|
40
39
|
resolveProviderModel,
|
|
41
40
|
restrictedWriteScopes,
|
|
42
41
|
schedulableRunKindSchema,
|
|
@@ -50,7 +49,7 @@ import {
|
|
|
50
49
|
skillsClientSchema,
|
|
51
50
|
upgradeCaveatFor,
|
|
52
51
|
upgradeCommandFor
|
|
53
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-MRKV43TV.js";
|
|
54
53
|
|
|
55
54
|
// src/config.ts
|
|
56
55
|
import fs from "fs";
|
|
@@ -153,6 +152,26 @@ var envSchema = z2.object({
|
|
|
153
152
|
CANONRY_RESEARCH_ALLOW_VIEWERS: z2.string().optional(),
|
|
154
153
|
CANONRY_RESEARCH_VIEWER_DAILY_RUN_LIMIT: z2.coerce.number().int().positive().default(DEFAULT_VIEWER_RESEARCH_DAILY_RUN_LIMIT)
|
|
155
154
|
});
|
|
155
|
+
var BOOTSTRAP_PROVIDER_DEFAULT_MODELS = {
|
|
156
|
+
gemini: "gemini-flash-latest",
|
|
157
|
+
openai: "gpt-5.4",
|
|
158
|
+
claude: "claude-sonnet-4-6",
|
|
159
|
+
perplexity: resolveProviderModel("perplexity", "fast"),
|
|
160
|
+
muse: "muse-spark-1.3",
|
|
161
|
+
local: "llama3"
|
|
162
|
+
};
|
|
163
|
+
var BOOTSTRAP_PROVIDER_DEFAULT_QUOTA = {
|
|
164
|
+
maxConcurrency: 2,
|
|
165
|
+
maxRequestsPerMinute: 10,
|
|
166
|
+
maxRequestsPerDay: 500
|
|
167
|
+
};
|
|
168
|
+
function withBootstrapProviderDefaults(name, entry) {
|
|
169
|
+
return {
|
|
170
|
+
...entry,
|
|
171
|
+
model: entry.model ?? BOOTSTRAP_PROVIDER_DEFAULT_MODELS[name],
|
|
172
|
+
quota: entry.quota ?? { ...BOOTSTRAP_PROVIDER_DEFAULT_QUOTA }
|
|
173
|
+
};
|
|
174
|
+
}
|
|
156
175
|
var bootstrapEnvSchema = z2.object({
|
|
157
176
|
CANONRY_API_KEY: z2.string().optional(),
|
|
158
177
|
CANONRY_API_URL: z2.string().optional(),
|
|
@@ -186,13 +205,9 @@ function getBootstrapEnv(source, overrides) {
|
|
|
186
205
|
if (parsed.GEMINI_API_KEY || parsed.GEMINI_VERTEX_PROJECT) {
|
|
187
206
|
providers.gemini = {
|
|
188
207
|
apiKey: parsed.GEMINI_API_KEY ?? "",
|
|
189
|
-
model: parsed.GEMINI_MODEL ||
|
|
208
|
+
model: parsed.GEMINI_MODEL || void 0,
|
|
190
209
|
baseUrl: parsed.GEMINI_BASE_URL,
|
|
191
|
-
quota:
|
|
192
|
-
maxConcurrency: 2,
|
|
193
|
-
maxRequestsPerMinute: 10,
|
|
194
|
-
maxRequestsPerDay: 500
|
|
195
|
-
}),
|
|
210
|
+
quota: void 0,
|
|
196
211
|
vertexProject: parsed.GEMINI_VERTEX_PROJECT,
|
|
197
212
|
vertexRegion: parsed.GEMINI_VERTEX_REGION,
|
|
198
213
|
vertexCredentials: parsed.GEMINI_VERTEX_CREDENTIALS
|
|
@@ -201,60 +216,41 @@ function getBootstrapEnv(source, overrides) {
|
|
|
201
216
|
if (parsed.OPENAI_API_KEY) {
|
|
202
217
|
providers.openai = {
|
|
203
218
|
apiKey: parsed.OPENAI_API_KEY,
|
|
204
|
-
model: parsed.OPENAI_MODEL ||
|
|
219
|
+
model: parsed.OPENAI_MODEL || void 0,
|
|
205
220
|
baseUrl: parsed.OPENAI_BASE_URL,
|
|
206
|
-
quota:
|
|
207
|
-
maxConcurrency: 2,
|
|
208
|
-
maxRequestsPerMinute: 10,
|
|
209
|
-
maxRequestsPerDay: 500
|
|
210
|
-
})
|
|
221
|
+
quota: void 0
|
|
211
222
|
};
|
|
212
223
|
}
|
|
213
224
|
if (parsed.ANTHROPIC_API_KEY) {
|
|
214
225
|
providers.claude = {
|
|
215
226
|
apiKey: parsed.ANTHROPIC_API_KEY,
|
|
216
|
-
model: parsed.ANTHROPIC_MODEL ||
|
|
217
|
-
quota:
|
|
218
|
-
maxConcurrency: 2,
|
|
219
|
-
maxRequestsPerMinute: 10,
|
|
220
|
-
maxRequestsPerDay: 500
|
|
221
|
-
})
|
|
227
|
+
model: parsed.ANTHROPIC_MODEL || void 0,
|
|
228
|
+
quota: void 0
|
|
222
229
|
};
|
|
223
230
|
}
|
|
224
231
|
if (parsed.PERPLEXITY_API_KEY) {
|
|
225
232
|
providers.perplexity = {
|
|
226
233
|
apiKey: parsed.PERPLEXITY_API_KEY,
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
maxRequestsPerMinute: 10,
|
|
231
|
-
maxRequestsPerDay: 500
|
|
232
|
-
})
|
|
234
|
+
// A retired Sonar name resolves to the Agent API preset that now answers.
|
|
235
|
+
model: parsed.PERPLEXITY_MODEL ? resolveProviderModel("perplexity", parsed.PERPLEXITY_MODEL) : void 0,
|
|
236
|
+
quota: void 0
|
|
233
237
|
};
|
|
234
238
|
}
|
|
235
239
|
const museKey = parsed.MUSE_API_KEY?.trim();
|
|
236
240
|
if (museKey) {
|
|
237
241
|
providers.muse = {
|
|
238
242
|
apiKey: museKey,
|
|
239
|
-
model: parsed.MUSE_MODEL?.trim() ||
|
|
243
|
+
model: parsed.MUSE_MODEL?.trim() || void 0,
|
|
240
244
|
baseUrl: parsed.MUSE_BASE_URL?.trim() || void 0,
|
|
241
|
-
quota:
|
|
242
|
-
maxConcurrency: 2,
|
|
243
|
-
maxRequestsPerMinute: 10,
|
|
244
|
-
maxRequestsPerDay: 500
|
|
245
|
-
})
|
|
245
|
+
quota: void 0
|
|
246
246
|
};
|
|
247
247
|
}
|
|
248
248
|
if (parsed.LOCAL_BASE_URL) {
|
|
249
249
|
providers.local = {
|
|
250
250
|
baseUrl: parsed.LOCAL_BASE_URL,
|
|
251
251
|
apiKey: parsed.LOCAL_API_KEY,
|
|
252
|
-
model: parsed.LOCAL_MODEL ||
|
|
253
|
-
quota:
|
|
254
|
-
maxConcurrency: 2,
|
|
255
|
-
maxRequestsPerMinute: 10,
|
|
256
|
-
maxRequestsPerDay: 500
|
|
257
|
-
})
|
|
252
|
+
model: parsed.LOCAL_MODEL || void 0,
|
|
253
|
+
quota: void 0
|
|
258
254
|
};
|
|
259
255
|
}
|
|
260
256
|
return {
|
|
@@ -380,8 +376,7 @@ function getConfigDir() {
|
|
|
380
376
|
function getConfigPath() {
|
|
381
377
|
return path.join(getConfigDir(), "config.yaml");
|
|
382
378
|
}
|
|
383
|
-
function loadConfig() {
|
|
384
|
-
const configPath = getConfigPath();
|
|
379
|
+
function loadConfig(configPath = getConfigPath()) {
|
|
385
380
|
if (!fs.existsSync(configPath)) {
|
|
386
381
|
throw new Error(
|
|
387
382
|
`Config not found at ${configPath}.
|
|
@@ -3176,6 +3171,22 @@ var putApiV1SettingsProvidersByName = (options) => {
|
|
|
3176
3171
|
}
|
|
3177
3172
|
});
|
|
3178
3173
|
};
|
|
3174
|
+
var postApiV1SettingsProvidersReload = (options) => {
|
|
3175
|
+
return (options?.client ?? client).post({
|
|
3176
|
+
security: [
|
|
3177
|
+
{
|
|
3178
|
+
scheme: "bearer",
|
|
3179
|
+
type: "http"
|
|
3180
|
+
}
|
|
3181
|
+
],
|
|
3182
|
+
url: "/api/v1/settings/providers/reload",
|
|
3183
|
+
...options,
|
|
3184
|
+
headers: {
|
|
3185
|
+
"Content-Type": "application/json",
|
|
3186
|
+
...options?.headers
|
|
3187
|
+
}
|
|
3188
|
+
});
|
|
3189
|
+
};
|
|
3179
3190
|
var putApiV1SettingsGoogle = (options) => {
|
|
3180
3191
|
return (options.client ?? client).put({
|
|
3181
3192
|
security: [
|
|
@@ -6572,7 +6583,8 @@ var ApiClient = class {
|
|
|
6572
6583
|
throw new CliError({
|
|
6573
6584
|
code: "CONNECTION_ERROR",
|
|
6574
6585
|
message: connectionFailureMessage(this.originUrl),
|
|
6575
|
-
exitCode: EXIT_SYSTEM_ERROR
|
|
6586
|
+
exitCode: EXIT_SYSTEM_ERROR,
|
|
6587
|
+
details: { connectionUnavailable: true }
|
|
6576
6588
|
});
|
|
6577
6589
|
}
|
|
6578
6590
|
throw new CliError({ code: "CONNECTION_ERROR", message: msg, exitCode: EXIT_SYSTEM_ERROR });
|
|
@@ -7634,6 +7646,11 @@ var ApiClient = class {
|
|
|
7634
7646
|
() => putApiV1SettingsGoogle({ client: this.heyClient, body })
|
|
7635
7647
|
);
|
|
7636
7648
|
}
|
|
7649
|
+
async reloadProviders(body = {}, signal) {
|
|
7650
|
+
return this.invoke(
|
|
7651
|
+
() => postApiV1SettingsProvidersReload({ client: this.heyClient, body, signal })
|
|
7652
|
+
);
|
|
7653
|
+
}
|
|
7637
7654
|
async createSnapshot(body) {
|
|
7638
7655
|
return this.invoke(() => postApiV1Snapshot({ client: this.heyClient, body }));
|
|
7639
7656
|
}
|
|
@@ -10000,7 +10017,7 @@ var OPERATIONS_GUIDE = {
|
|
|
10000
10017
|
"guidance": "Build the requested summary from stored project overview, organic evidence, and the relevant visibility, measurement, integration, or traffic reads. Retain evidence dates, scope, sample sizes, missing data, and separate mention/citation signals; do not generate fresh runs implicitly."
|
|
10001
10018
|
}
|
|
10002
10019
|
},
|
|
10003
|
-
"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. Compact `nextCursor` completes only `pageList`; use `list` to enumerate\none ranking, markets, observed names or cited domains, preserving filters.\nFirst-page sibling lists are bounded summaries. Keep sample sizes and ties\nvisible. Preparing a report does not\nauthorize new measurement.\n\n## Authority and approval\n\n### Agent operations\n\nUse `canonry_key_self` (CLI `canonry key whoami --format json`) to inspect the\ncurrent credential's scopes, project boundary, and host-derived `operator`\nauthority without exposing its token. Missing `operator` means unapproved.\n`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.\nServer telemetry reads and updates additionally require operator authority.\nOrdinary audit-history reads omit internal telemetry events and their state.\n\nOperator authority is deny-by-default and separate from customer admin roles.\nThe deployment owner must approve a dedicated, instance-wide API key's ID in\nthe server environment variable `CANONRY_OPERATOR_KEY_IDS` (comma-separated IDs),\nthen restart the server. Empty/unset approves nobody; wildcards are invalid.\nKeep the bearer private to internal operators; never approve a customer-held or\nshared proxy/bootstrap key. Use `logs.read` for read-only diagnostics, adding\n`settings.write` only when telemetry control is required. Ordinary key creation,\naccount roles, OAuth consent, and caller headers cannot grant operator status.\nRevoking an approved key invalidates it immediately. Host enrollment is a trust\nbootstrap step, intentionally unavailable through customer-facing APIs.\nAPI, CLI, and MCP enforce the same boundary; MCP hides internal tools unless\nthe server confirms operator authority, including in explicit read-only mode.\nProject analytics, research, and normal project permissions are unchanged.\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 a host-approved direct bearer.\nBrowser sessions, OAuth/delegated credentials, customer admins, and project-scoped\nkeys cannot use it, even with a project filter or a matching allowlist ID.\nA `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"
|
|
10020
|
+
"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**Setup:** Page Health needs no answer-engine provider; AI Visibility does.\nAfter a Page Health result on an install with no provider (a `NO_PROVIDER`\nnotice, or doctor's `providers.none-configured`), propose AI Visibility setup\nas the next step. The operator adds the provider key in the dashboard or in\ntheir own terminal; never ask for it in chat.\nRerunning `canonry bootstrap` after a provider change reloads saved provider\nsettings on a matching running local server and reports whether they became\nactive. If the server is offline, start it to apply the saved settings. For an\nexplicit reload of the connected server's own config, use\n`canonry settings reload-providers` or `canonry_providers_reload` with install\nadministrator authority. Remote servers are never reloaded automatically by\nbootstrap, and a local server that belongs to another install is left alone.\nPorts and database settings still need a restart.\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. Compact `nextCursor` completes only `pageList`; use `list` to enumerate\none ranking, markets, observed names or cited domains, preserving filters.\nFirst-page sibling lists are bounded summaries. Keep sample sizes and ties\nvisible. Preparing a report does not\nauthorize new measurement.\n\n## Authority and approval\n\n### Agent operations\n\nUse `canonry_key_self` (CLI `canonry key whoami --format json`) to inspect the\ncurrent credential's scopes, project boundary, and host-derived `operator`\nauthority without exposing its token. Missing `operator` means unapproved.\n`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.\nServer telemetry reads and updates additionally require operator authority.\nOrdinary audit-history reads omit internal telemetry events and their state.\n\nOperator authority is deny-by-default and separate from customer admin roles.\nThe deployment owner must approve a dedicated, instance-wide API key's ID in\nthe server environment variable `CANONRY_OPERATOR_KEY_IDS` (comma-separated IDs),\nthen restart the server. Empty/unset approves nobody; wildcards are invalid.\nKeep the bearer private to internal operators; never approve a customer-held or\nshared proxy/bootstrap key. Use `logs.read` for read-only diagnostics, adding\n`settings.write` only when telemetry control is required. Ordinary key creation,\naccount roles, OAuth consent, and caller headers cannot grant operator status.\nRevoking an approved key invalidates it immediately. Host enrollment is a trust\nbootstrap step, intentionally unavailable through customer-facing APIs.\nAPI, CLI, and MCP enforce the same boundary; MCP hides internal tools unless\nthe server confirms operator authority, including in explicit read-only mode.\nProject analytics, research, and normal project permissions are unchanged.\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 a host-approved direct bearer.\nBrowser sessions, OAuth/delegated credentials, customer admins, and project-scoped\nkeys cannot use it, even with a project filter or a matching allowlist ID.\nA `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"
|
|
10004
10021
|
};
|
|
10005
10022
|
|
|
10006
10023
|
// src/mcp/operations-guide.ts
|
|
@@ -10561,6 +10578,7 @@ export {
|
|
|
10561
10578
|
sentimentInstallReadiness,
|
|
10562
10579
|
dashboardManagedRunKindsSchema,
|
|
10563
10580
|
resolveOperatorApiKeyIds,
|
|
10581
|
+
withBootstrapProviderDefaults,
|
|
10564
10582
|
getBootstrapEnv,
|
|
10565
10583
|
providerConfigFromEntry,
|
|
10566
10584
|
adapterSupportsBatch,
|