@ainyc/canonry 4.81.0 → 4.83.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/canonry/references/canonry-cli.md +4 -0
- package/assets/assets/{BacklinksPage-DHShKKpo.js → BacklinksPage-OrSg_iPA.js} +1 -1
- package/assets/assets/{ChartPrimitives-udHScxjY.js → ChartPrimitives-DPBhAT_r.js} +1 -1
- package/assets/assets/{ProjectPage-BsS1anh7.js → ProjectPage-CpMcEmtw.js} +1 -1
- package/assets/assets/{RunRow-CXyPHMVQ.js → RunRow-2Rty0BAH.js} +1 -1
- package/assets/assets/{RunsPage-BpQ_NpFt.js → RunsPage-B3ahqf8s.js} +1 -1
- package/assets/assets/{SettingsPage-1ep4ch7n.js → SettingsPage-BIjeI85q.js} +1 -1
- package/assets/assets/{TrafficPage-C3Hx-sE7.js → TrafficPage-DjGoj691.js} +1 -1
- package/assets/assets/{TrafficSourceDetailPage-B26n2R6G.js → TrafficSourceDetailPage-BgKG-2q3.js} +1 -1
- package/assets/assets/{arrow-left-Dc_IPJxw.js → arrow-left-Cf7wmru1.js} +1 -1
- package/assets/assets/{extract-error-message-B3PoKkHW.js → extract-error-message-CANxezte.js} +1 -1
- package/assets/assets/{index-DhdFTQkU.js → index-CGlPx_cu.js} +11 -11
- package/assets/assets/{trash-2-BQ69cGl0.js → trash-2-6nHJZrvy.js} +1 -1
- package/assets/index.html +1 -1
- package/dist/{chunk-GMT3YPLT.js → chunk-BNF3HXBW.js} +25 -1
- package/dist/{chunk-UAQ42NVJ.js → chunk-GOWH42QV.js} +50 -2
- package/dist/{chunk-VX5C7DK7.js → chunk-NRACXNI7.js} +15 -4
- package/dist/{chunk-6XOZSS3Y.js → chunk-Y3O3HBMN.js} +17 -1
- package/dist/cli.js +50 -17
- package/dist/index.js +4 -4
- package/dist/{intelligence-service-CAAQAKPN.js → intelligence-service-FHQM7YMA.js} +2 -2
- package/dist/mcp.js +23 -4
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c}from"./index-
|
|
1
|
+
import{c}from"./index-CGlPx_cu.js";const a=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],h=c("circle-check",a);const e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]],n=c("circle-question-mark",e);const o=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],s=c("download",o);const t=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],r=c("trash-2",t);export{h as C,s as D,r as T,n as a};
|
package/assets/index.html
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
|
|
13
13
|
<link rel="apple-touch-icon" href="./apple-touch-icon.png" />
|
|
14
14
|
<title>Canonry</title>
|
|
15
|
-
<script type="module" crossorigin src="./assets/index-
|
|
15
|
+
<script type="module" crossorigin src="./assets/index-CGlPx_cu.js"></script>
|
|
16
16
|
<link rel="modulepreload" crossorigin href="./assets/vendor-tanstack-Dq7p98wZ.js">
|
|
17
17
|
<link rel="modulepreload" crossorigin href="./assets/vendor-radix-B57xfQbP.js">
|
|
18
18
|
<link rel="modulepreload" crossorigin href="./assets/vendor-recharts-ClRVR6aX.js">
|
|
@@ -571,6 +571,16 @@ var auditLogEntrySchema = z3.object({
|
|
|
571
571
|
createdAt: z3.string()
|
|
572
572
|
});
|
|
573
573
|
|
|
574
|
+
// ../contracts/src/scopes.ts
|
|
575
|
+
var READ_ONLY_SCOPE = "read";
|
|
576
|
+
var WILDCARD_SCOPE = "*";
|
|
577
|
+
function grantsWrite(scope) {
|
|
578
|
+
return scope === WILDCARD_SCOPE || scope === "write" || scope.endsWith(".write");
|
|
579
|
+
}
|
|
580
|
+
function isReadOnlyKey(scopes) {
|
|
581
|
+
return scopes.includes(READ_ONLY_SCOPE) && !scopes.some(grantsWrite);
|
|
582
|
+
}
|
|
583
|
+
|
|
574
584
|
// ../contracts/src/api-keys.ts
|
|
575
585
|
import { z as z4 } from "zod";
|
|
576
586
|
var apiKeyDtoSchema = z4.object({
|
|
@@ -579,6 +589,13 @@ var apiKeyDtoSchema = z4.object({
|
|
|
579
589
|
/** First 9 chars of the raw token (`cnry_` + 4 hex). Safe to display. */
|
|
580
590
|
keyPrefix: z4.string(),
|
|
581
591
|
scopes: z4.array(z4.string()),
|
|
592
|
+
/**
|
|
593
|
+
* Server-derived convenience flag: `true` when this key is read-only (carries
|
|
594
|
+
* the `read` scope and no write-granting scope), in which case the API rejects
|
|
595
|
+
* every write HTTP method for it. Derived from `scopes` via `isReadOnlyKey`
|
|
596
|
+
* — surfaces don't recompute it (see the UI/CLI parity rule). Additive field.
|
|
597
|
+
*/
|
|
598
|
+
readOnly: z4.boolean(),
|
|
582
599
|
createdAt: z4.string(),
|
|
583
600
|
lastUsedAt: z4.string().nullable(),
|
|
584
601
|
revokedAt: z4.string().nullable()
|
|
@@ -1855,6 +1872,11 @@ var discoveryProbeDtoSchema = z17.object({
|
|
|
1855
1872
|
bucket: discoveryBucketSchema.nullable().default(null),
|
|
1856
1873
|
citationState: citationStateSchema,
|
|
1857
1874
|
citedDomains: z17.array(z17.string()).default([]),
|
|
1875
|
+
// Answer-text mention signal, independent of citationState. Tri-state: true
|
|
1876
|
+
// (named in the answer prose), false (probed, not named), null (unknown: a
|
|
1877
|
+
// legacy probe written before the engine computed it). Consumers must treat
|
|
1878
|
+
// null as unknown, never as false.
|
|
1879
|
+
answerMentioned: z17.boolean().nullable().default(null),
|
|
1858
1880
|
createdAt: z17.string()
|
|
1859
1881
|
});
|
|
1860
1882
|
var discoverySessionDtoSchema = z17.object({
|
|
@@ -4780,5 +4802,7 @@ export {
|
|
|
4780
4802
|
AI_ENGINE_SELF_DOMAINS,
|
|
4781
4803
|
VERTEX_AI_SEARCH_PROXY_DOMAIN,
|
|
4782
4804
|
AI_PROVIDER_INFRA_DOMAINS,
|
|
4783
|
-
escapeLikePattern
|
|
4805
|
+
escapeLikePattern,
|
|
4806
|
+
READ_ONLY_SCOPE,
|
|
4807
|
+
isReadOnlyKey
|
|
4784
4808
|
};
|
|
@@ -156,6 +156,7 @@ import {
|
|
|
156
156
|
hasLocationLabel,
|
|
157
157
|
indexingRequestResponseDtoSchema,
|
|
158
158
|
internalError,
|
|
159
|
+
isReadOnlyKey,
|
|
159
160
|
keywordDtoSchema,
|
|
160
161
|
keywordGenerateRequestSchema,
|
|
161
162
|
latestProjectRunDtoSchema,
|
|
@@ -245,7 +246,7 @@ import {
|
|
|
245
246
|
wordpressSchemaDeployResultDtoSchema,
|
|
246
247
|
wordpressSchemaStatusResultDtoSchema,
|
|
247
248
|
wordpressStatusDtoSchema
|
|
248
|
-
} from "./chunk-
|
|
249
|
+
} from "./chunk-BNF3HXBW.js";
|
|
249
250
|
|
|
250
251
|
// src/intelligence-service.ts
|
|
251
252
|
import { eq as eq36, desc as desc17, asc as asc5, and as and26, ne as ne5, or as or5, inArray as inArray13, gte as gte7, lte as lte4 } from "drizzle-orm";
|
|
@@ -1054,6 +1055,10 @@ var discoveryProbes = sqliteTable("discovery_probes", {
|
|
|
1054
1055
|
query: text("query").notNull(),
|
|
1055
1056
|
bucket: text("bucket"),
|
|
1056
1057
|
citationState: text("citation_state").notNull(),
|
|
1058
|
+
// Answer-text mention signal, independent of citationState. Tri-state: true
|
|
1059
|
+
// (named in the answer prose), false (probed, not named), null (legacy rows
|
|
1060
|
+
// written before this column / never computed). Mirrors querySnapshots.answerMentioned.
|
|
1061
|
+
answerMentioned: integer("answer_mentioned", { mode: "boolean" }),
|
|
1057
1062
|
citedDomains: text("cited_domains", { mode: "json" }).$type().notNull().default([]),
|
|
1058
1063
|
rawResponse: text("raw_response"),
|
|
1059
1064
|
createdAt: text("created_at").notNull()
|
|
@@ -3074,6 +3079,16 @@ var MIGRATION_VERSIONS = [
|
|
|
3074
3079
|
run: (tx) => {
|
|
3075
3080
|
addBacklinkSourceDiscriminator(tx);
|
|
3076
3081
|
}
|
|
3082
|
+
},
|
|
3083
|
+
{
|
|
3084
|
+
// Answer-text mention signal on discovery probes (independent of citation).
|
|
3085
|
+
// Nullable: pre-existing rows were written before the column / never had the
|
|
3086
|
+
// mention computed, so they read back as null (unknown) downstream.
|
|
3087
|
+
version: 79,
|
|
3088
|
+
name: "discovery-probes-answer-mentioned",
|
|
3089
|
+
statements: [
|
|
3090
|
+
`ALTER TABLE discovery_probes ADD COLUMN answer_mentioned INTEGER`
|
|
3091
|
+
]
|
|
3077
3092
|
}
|
|
3078
3093
|
];
|
|
3079
3094
|
function rebuildBacklinkTableWithSource(tx, table) {
|
|
@@ -5290,6 +5305,7 @@ import fs8 from "fs";
|
|
|
5290
5305
|
// ../api-routes/src/auth.ts
|
|
5291
5306
|
import crypto2 from "crypto";
|
|
5292
5307
|
import { eq } from "drizzle-orm";
|
|
5308
|
+
var WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
|
|
5293
5309
|
function requireScope(request, scope) {
|
|
5294
5310
|
const key = request.apiKey;
|
|
5295
5311
|
if (!key) return;
|
|
@@ -5357,6 +5373,9 @@ async function authPlugin(app, opts = {}) {
|
|
|
5357
5373
|
app.db.update(apiKeys).set({ lastUsedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq(apiKeys.id, key.id)).run();
|
|
5358
5374
|
const scopes = Array.isArray(key.scopes) ? key.scopes : [];
|
|
5359
5375
|
request.apiKey = { id: key.id, name: key.name, scopes };
|
|
5376
|
+
if (isReadOnlyKey(scopes) && WRITE_METHODS.has(request.method)) {
|
|
5377
|
+
throw forbidden("This API key is read-only and cannot perform write operations.");
|
|
5378
|
+
}
|
|
5360
5379
|
});
|
|
5361
5380
|
}
|
|
5362
5381
|
|
|
@@ -14431,6 +14450,17 @@ var routeCatalog = [
|
|
|
14431
14450
|
200: jsonResponse("Keys returned.", "ApiKeyListDto")
|
|
14432
14451
|
}
|
|
14433
14452
|
},
|
|
14453
|
+
{
|
|
14454
|
+
method: "get",
|
|
14455
|
+
path: "/api/v1/keys/self",
|
|
14456
|
+
summary: "Introspect the current API key",
|
|
14457
|
+
description: "Returns SAFE metadata for the key that authenticated this request, including the derived `readOnly` flag. Lets a caller (or the MCP adapter at startup) discover whether its configured key is read-only without listing every key on the instance. Ungated read \u2014 a read-only key can call it.",
|
|
14458
|
+
tags: ["keys"],
|
|
14459
|
+
responses: {
|
|
14460
|
+
200: jsonResponse("Current key returned.", "ApiKeyDto"),
|
|
14461
|
+
404: errorResponse("No key on the request (auth skipped).")
|
|
14462
|
+
}
|
|
14463
|
+
},
|
|
14434
14464
|
{
|
|
14435
14465
|
method: "post",
|
|
14436
14466
|
path: "/api/v1/keys",
|
|
@@ -17586,11 +17616,13 @@ import crypto12 from "crypto";
|
|
|
17586
17616
|
import { desc as desc9, eq as eq17 } from "drizzle-orm";
|
|
17587
17617
|
var KEYS_WRITE_SCOPE = "keys.write";
|
|
17588
17618
|
function toApiKeyDto(row) {
|
|
17619
|
+
const scopes = Array.isArray(row.scopes) ? row.scopes : [];
|
|
17589
17620
|
return {
|
|
17590
17621
|
id: row.id,
|
|
17591
17622
|
name: row.name,
|
|
17592
17623
|
keyPrefix: row.keyPrefix,
|
|
17593
|
-
scopes
|
|
17624
|
+
scopes,
|
|
17625
|
+
readOnly: isReadOnlyKey(scopes),
|
|
17594
17626
|
createdAt: row.createdAt,
|
|
17595
17627
|
lastUsedAt: row.lastUsedAt ?? null,
|
|
17596
17628
|
revokedAt: row.revokedAt ?? null
|
|
@@ -17601,6 +17633,17 @@ async function keysRoutes(app) {
|
|
|
17601
17633
|
const rows = app.db.select().from(apiKeys).orderBy(desc9(apiKeys.createdAt)).all();
|
|
17602
17634
|
return { keys: rows.map(toApiKeyDto) };
|
|
17603
17635
|
});
|
|
17636
|
+
app.get("/keys/self", async (request) => {
|
|
17637
|
+
const id = request.apiKey?.id;
|
|
17638
|
+
if (!id) {
|
|
17639
|
+
throw notFound("API key", "self");
|
|
17640
|
+
}
|
|
17641
|
+
const row = app.db.select().from(apiKeys).where(eq17(apiKeys.id, id)).get();
|
|
17642
|
+
if (!row) {
|
|
17643
|
+
throw notFound("API key", id);
|
|
17644
|
+
}
|
|
17645
|
+
return toApiKeyDto(row);
|
|
17646
|
+
});
|
|
17604
17647
|
app.post("/keys", async (request) => {
|
|
17605
17648
|
requireScope(request, KEYS_WRITE_SCOPE);
|
|
17606
17649
|
const parsed = createApiKeyRequestSchema.safeParse(request.body);
|
|
@@ -17636,6 +17679,7 @@ async function keysRoutes(app) {
|
|
|
17636
17679
|
name,
|
|
17637
17680
|
keyPrefix,
|
|
17638
17681
|
scopes: effectiveScopes,
|
|
17682
|
+
readOnly: isReadOnlyKey(effectiveScopes),
|
|
17639
17683
|
createdAt: now,
|
|
17640
17684
|
lastUsedAt: null,
|
|
17641
17685
|
revokedAt: null,
|
|
@@ -32749,6 +32793,9 @@ function serializeProbe(row) {
|
|
|
32749
32793
|
bucket: bucketParsed?.success ? bucketParsed.data : null,
|
|
32750
32794
|
citationState: stateParsed.success ? stateParsed.data : "not-cited",
|
|
32751
32795
|
citedDomains: row.citedDomains,
|
|
32796
|
+
// Boolean-mode column already reads back as boolean | null; a legacy row
|
|
32797
|
+
// written before the column is null (unknown), never coerced to false.
|
|
32798
|
+
answerMentioned: row.answerMentioned ?? null,
|
|
32752
32799
|
createdAt: row.createdAt
|
|
32753
32800
|
};
|
|
32754
32801
|
}
|
|
@@ -32865,6 +32912,7 @@ async function executeDiscovery(opts) {
|
|
|
32865
32912
|
query,
|
|
32866
32913
|
bucket,
|
|
32867
32914
|
citationState: probe.citationState,
|
|
32915
|
+
answerMentioned: probe.answerMentioned,
|
|
32868
32916
|
citedDomains: probe.citedDomains,
|
|
32869
32917
|
rawResponse: JSON.stringify(probe.rawResponse),
|
|
32870
32918
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
loadConfig,
|
|
10
10
|
loadConfigRaw,
|
|
11
11
|
saveConfigPatch
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-Y3O3HBMN.js";
|
|
13
13
|
import {
|
|
14
14
|
CC_CACHE_DIR,
|
|
15
15
|
DUCKDB_SPEC,
|
|
@@ -104,7 +104,7 @@ import {
|
|
|
104
104
|
siteAuditPages,
|
|
105
105
|
siteAuditSnapshots,
|
|
106
106
|
usageCounters
|
|
107
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-GOWH42QV.js";
|
|
108
108
|
import {
|
|
109
109
|
AGENT_MEMORY_VALUE_MAX_BYTES,
|
|
110
110
|
AGENT_PROVIDER_IDS,
|
|
@@ -160,7 +160,7 @@ import {
|
|
|
160
160
|
validationError,
|
|
161
161
|
winnabilityClassLabel,
|
|
162
162
|
withRetry
|
|
163
|
-
} from "./chunk-
|
|
163
|
+
} from "./chunk-BNF3HXBW.js";
|
|
164
164
|
|
|
165
165
|
// src/telemetry.ts
|
|
166
166
|
import crypto from "crypto";
|
|
@@ -5376,9 +5376,14 @@ async function executeDiscoveryRun(opts) {
|
|
|
5376
5376
|
canonicalDomain: projectRow.canonicalDomain,
|
|
5377
5377
|
ownedDomains: projectRow.ownedDomains
|
|
5378
5378
|
});
|
|
5379
|
+
const brandNames = effectiveBrandNames({
|
|
5380
|
+
displayName: projectRow.displayName,
|
|
5381
|
+
aliases: projectRow.aliases
|
|
5382
|
+
});
|
|
5379
5383
|
const project = {
|
|
5380
5384
|
id: projectRow.id,
|
|
5381
5385
|
name: projectRow.name,
|
|
5386
|
+
brandNames,
|
|
5382
5387
|
canonicalDomains,
|
|
5383
5388
|
competitorDomains: projectCompetitors
|
|
5384
5389
|
};
|
|
@@ -5466,9 +5471,15 @@ function buildDefaultDeps(registry) {
|
|
|
5466
5471
|
const normalized = adapter.normalizeResult(raw);
|
|
5467
5472
|
const canonical = new Set(input.project.canonicalDomains.map((d) => d.toLowerCase()));
|
|
5468
5473
|
const isCited = normalized.citedDomains.some((d) => canonical.has(d.toLowerCase()));
|
|
5474
|
+
const answerMentioned = determineAnswerMentioned(
|
|
5475
|
+
normalized.answerText,
|
|
5476
|
+
input.project.brandNames ?? [],
|
|
5477
|
+
input.project.canonicalDomains
|
|
5478
|
+
);
|
|
5469
5479
|
return {
|
|
5470
5480
|
citationState: isCited ? "cited" : "not-cited",
|
|
5471
5481
|
citedDomains: normalized.citedDomains,
|
|
5482
|
+
answerMentioned,
|
|
5472
5483
|
rawResponse: raw.rawResponse
|
|
5473
5484
|
};
|
|
5474
5485
|
},
|
|
@@ -6278,7 +6289,7 @@ function readStoredGroundingSources(rawResponse) {
|
|
|
6278
6289
|
return result;
|
|
6279
6290
|
}
|
|
6280
6291
|
async function backfillInsightsCommand(project, opts) {
|
|
6281
|
-
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-
|
|
6292
|
+
const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-FHQM7YMA.js");
|
|
6282
6293
|
const config = loadConfig();
|
|
6283
6294
|
const db = createClient(config.database);
|
|
6284
6295
|
migrate(db);
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
trafficConnectVercelRequestSchema,
|
|
24
24
|
trafficConnectWordpressRequestSchema,
|
|
25
25
|
trafficEventKindSchema
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-BNF3HXBW.js";
|
|
27
27
|
|
|
28
28
|
// src/config.ts
|
|
29
29
|
import fs from "fs";
|
|
@@ -1606,6 +1606,18 @@ var postApiV1Keys = (options) => {
|
|
|
1606
1606
|
}
|
|
1607
1607
|
});
|
|
1608
1608
|
};
|
|
1609
|
+
var getApiV1KeysSelf = (options) => {
|
|
1610
|
+
return (options?.client ?? client).get({
|
|
1611
|
+
security: [
|
|
1612
|
+
{
|
|
1613
|
+
scheme: "bearer",
|
|
1614
|
+
type: "http"
|
|
1615
|
+
}
|
|
1616
|
+
],
|
|
1617
|
+
url: "/api/v1/keys/self",
|
|
1618
|
+
...options
|
|
1619
|
+
});
|
|
1620
|
+
};
|
|
1609
1621
|
var postApiV1KeysByIdRevoke = (options) => {
|
|
1610
1622
|
return (options.client ?? client).post({
|
|
1611
1623
|
security: [
|
|
@@ -4042,6 +4054,10 @@ var ApiClient = class {
|
|
|
4042
4054
|
async listApiKeys() {
|
|
4043
4055
|
return this.invoke(() => getApiV1Keys({ client: this.heyClient }));
|
|
4044
4056
|
}
|
|
4057
|
+
/** Introspect the CURRENT key (the one this client authenticates with). */
|
|
4058
|
+
async getApiKeySelf() {
|
|
4059
|
+
return this.invoke(() => getApiV1KeysSelf({ client: this.heyClient }));
|
|
4060
|
+
}
|
|
4045
4061
|
async createApiKey(body) {
|
|
4046
4062
|
return this.invoke(() => postApiV1Keys({ client: this.heyClient, body }));
|
|
4047
4063
|
}
|
package/dist/cli.js
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
setTelemetrySource,
|
|
28
28
|
showFirstRunNotice,
|
|
29
29
|
trackEvent
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-NRACXNI7.js";
|
|
31
31
|
import {
|
|
32
32
|
CliError,
|
|
33
33
|
EXIT_SYSTEM_ERROR,
|
|
@@ -44,7 +44,7 @@ import {
|
|
|
44
44
|
saveConfig,
|
|
45
45
|
saveConfigPatch,
|
|
46
46
|
usageError
|
|
47
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-Y3O3HBMN.js";
|
|
48
48
|
import {
|
|
49
49
|
apiKeys,
|
|
50
50
|
createClient,
|
|
@@ -52,13 +52,14 @@ import {
|
|
|
52
52
|
projects,
|
|
53
53
|
queries,
|
|
54
54
|
renderReportHtml
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-GOWH42QV.js";
|
|
56
56
|
import {
|
|
57
57
|
BacklinkSources,
|
|
58
58
|
CcReleaseSyncStatuses,
|
|
59
59
|
CheckScopes,
|
|
60
60
|
CheckStatuses,
|
|
61
61
|
CitationStates,
|
|
62
|
+
READ_ONLY_SCOPE,
|
|
62
63
|
RunStatuses,
|
|
63
64
|
TrafficEventKinds,
|
|
64
65
|
backlinkSourceSchema,
|
|
@@ -75,7 +76,7 @@ import {
|
|
|
75
76
|
providerQuotaPolicySchema,
|
|
76
77
|
resolveProviderInput,
|
|
77
78
|
winnabilityClassSchema
|
|
78
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-BNF3HXBW.js";
|
|
79
80
|
|
|
80
81
|
// src/cli.ts
|
|
81
82
|
import { pathToFileURL } from "url";
|
|
@@ -1901,11 +1902,12 @@ function printSessionDetail(session) {
|
|
|
1901
1902
|
if (session.probes && session.probes.length > 0) {
|
|
1902
1903
|
const sorted = [...session.probes].sort((a, b) => (a.bucket ?? "").localeCompare(b.bucket ?? ""));
|
|
1903
1904
|
console.log(`
|
|
1904
|
-
Probes (${session.probes.length})
|
|
1905
|
+
Probes (${session.probes.length}): (cell = [citation][mention]; C=cited c=not, M=mentioned m=not, \u2013=no data)`);
|
|
1905
1906
|
for (const p of sorted) {
|
|
1906
1907
|
const bucket = (p.bucket ?? "\u2013").padEnd(15);
|
|
1907
|
-
const
|
|
1908
|
-
|
|
1908
|
+
const citationGlyph = p.citationState === CitationStates.cited ? "C" : "c";
|
|
1909
|
+
const mentionGlyph = typeof p.answerMentioned === "boolean" ? p.answerMentioned ? "M" : "m" : "\u2013";
|
|
1910
|
+
console.log(` [${citationGlyph}${mentionGlyph}] ${bucket} ${p.query}`);
|
|
1909
1911
|
}
|
|
1910
1912
|
}
|
|
1911
1913
|
}
|
|
@@ -5640,9 +5642,18 @@ async function listApiKeys(format) {
|
|
|
5640
5642
|
}
|
|
5641
5643
|
}
|
|
5642
5644
|
async function createApiKey(opts) {
|
|
5645
|
+
const explicitScopes = opts.scopes && opts.scopes.length > 0 ? opts.scopes : void 0;
|
|
5646
|
+
if (opts.readOnly && explicitScopes) {
|
|
5647
|
+
throw new CliError({
|
|
5648
|
+
code: "CLI_USAGE_ERROR",
|
|
5649
|
+
message: "--read-only cannot be combined with --scope",
|
|
5650
|
+
displayMessage: 'Error: --read-only cannot be combined with --scope (it already implies the "read" scope).'
|
|
5651
|
+
});
|
|
5652
|
+
}
|
|
5643
5653
|
const client = getClient11();
|
|
5644
5654
|
const body = { name: opts.name };
|
|
5645
|
-
|
|
5655
|
+
const scopes = opts.readOnly ? [READ_ONLY_SCOPE] : explicitScopes;
|
|
5656
|
+
if (scopes) body.scopes = scopes;
|
|
5646
5657
|
const created = await client.createApiKey(body);
|
|
5647
5658
|
if (isMachineFormat(opts.format)) {
|
|
5648
5659
|
console.log(JSON.stringify(created, null, 2));
|
|
@@ -5650,11 +5661,24 @@ async function createApiKey(opts) {
|
|
|
5650
5661
|
}
|
|
5651
5662
|
console.log(`API key "${created.name}" created.
|
|
5652
5663
|
`);
|
|
5653
|
-
console.log(` Key:
|
|
5654
|
-
console.log(` Prefix:
|
|
5655
|
-
console.log(` Scopes:
|
|
5664
|
+
console.log(` Key: ${created.key}`);
|
|
5665
|
+
console.log(` Prefix: ${created.keyPrefix}`);
|
|
5666
|
+
console.log(` Scopes: ${created.scopes.join(", ")}`);
|
|
5667
|
+
console.log(` Read-only: ${created.readOnly ? "yes" : "no"}`);
|
|
5656
5668
|
console.log("\nSave this now \u2014 it will not be shown again.");
|
|
5657
5669
|
}
|
|
5670
|
+
async function showApiKeySelf(format) {
|
|
5671
|
+
const client = getClient11();
|
|
5672
|
+
const key = await client.getApiKeySelf();
|
|
5673
|
+
if (isMachineFormat(format)) {
|
|
5674
|
+
console.log(JSON.stringify(key, null, 2));
|
|
5675
|
+
return;
|
|
5676
|
+
}
|
|
5677
|
+
console.log(`API key "${key.name}" (${key.keyPrefix})`);
|
|
5678
|
+
console.log(` Scopes: ${key.scopes.join(", ")}`);
|
|
5679
|
+
console.log(` Read-only: ${key.readOnly ? "yes" : "no"}`);
|
|
5680
|
+
console.log(` Status: ${keyStatus(key)}`);
|
|
5681
|
+
}
|
|
5658
5682
|
async function revokeApiKey(id, format) {
|
|
5659
5683
|
const client = getClient11();
|
|
5660
5684
|
const key = await client.revokeApiKey(id);
|
|
@@ -5676,15 +5700,16 @@ var KEYS_CLI_COMMANDS = [
|
|
|
5676
5700
|
},
|
|
5677
5701
|
{
|
|
5678
5702
|
path: ["key", "create"],
|
|
5679
|
-
usage: "canonry key create --name <name> [--scope <s> ...] [--format json]",
|
|
5703
|
+
usage: "canonry key create --name <name> [--read-only | --scope <s> ...] [--format json]",
|
|
5680
5704
|
options: {
|
|
5681
5705
|
name: stringOption(),
|
|
5682
|
-
scope: multiStringOption()
|
|
5706
|
+
scope: multiStringOption(),
|
|
5707
|
+
"read-only": { type: "boolean" }
|
|
5683
5708
|
},
|
|
5684
5709
|
run: async (input) => {
|
|
5685
5710
|
const name = requireStringOption(input, "name", {
|
|
5686
5711
|
command: "key.create",
|
|
5687
|
-
usage: "canonry key create --name <name> [--scope <s> ...] [--format json]",
|
|
5712
|
+
usage: "canonry key create --name <name> [--read-only | --scope <s> ...] [--format json]",
|
|
5688
5713
|
message: "--name is required"
|
|
5689
5714
|
});
|
|
5690
5715
|
const raw = getStringArray(input.values, "scope") ?? [];
|
|
@@ -5692,10 +5717,18 @@ var KEYS_CLI_COMMANDS = [
|
|
|
5692
5717
|
await createApiKey({
|
|
5693
5718
|
name,
|
|
5694
5719
|
scopes: scopes.length > 0 ? scopes : void 0,
|
|
5720
|
+
readOnly: getBoolean(input.values, "read-only"),
|
|
5695
5721
|
format: input.format
|
|
5696
5722
|
});
|
|
5697
5723
|
}
|
|
5698
5724
|
},
|
|
5725
|
+
{
|
|
5726
|
+
path: ["key", "whoami"],
|
|
5727
|
+
usage: "canonry key whoami [--format json]",
|
|
5728
|
+
run: async (input) => {
|
|
5729
|
+
await showApiKeySelf(input.format);
|
|
5730
|
+
}
|
|
5731
|
+
},
|
|
5699
5732
|
{
|
|
5700
5733
|
path: ["key", "revoke"],
|
|
5701
5734
|
usage: "canonry key revoke <id> [--format json]",
|
|
@@ -5710,12 +5743,12 @@ var KEYS_CLI_COMMANDS = [
|
|
|
5710
5743
|
},
|
|
5711
5744
|
{
|
|
5712
5745
|
path: ["key"],
|
|
5713
|
-
usage: "canonry key <list|create|revoke>",
|
|
5746
|
+
usage: "canonry key <list|create|revoke|whoami>",
|
|
5714
5747
|
run: async (input) => {
|
|
5715
5748
|
unknownSubcommand(input.positionals[0], {
|
|
5716
5749
|
command: "key",
|
|
5717
|
-
usage: "canonry key <list|create|revoke>",
|
|
5718
|
-
available: ["list", "create", "revoke"]
|
|
5750
|
+
usage: "canonry key <list|create|revoke|whoami>",
|
|
5751
|
+
available: ["list", "create", "revoke", "whoami"]
|
|
5719
5752
|
});
|
|
5720
5753
|
}
|
|
5721
5754
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createServer
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NRACXNI7.js";
|
|
4
4
|
import {
|
|
5
5
|
loadConfig
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-Y3O3HBMN.js";
|
|
7
|
+
import "./chunk-GOWH42QV.js";
|
|
8
|
+
import "./chunk-BNF3HXBW.js";
|
|
9
9
|
export {
|
|
10
10
|
createServer,
|
|
11
11
|
loadConfig
|
package/dist/mcp.js
CHANGED
|
@@ -3,8 +3,10 @@ import {
|
|
|
3
3
|
PACKAGE_VERSION,
|
|
4
4
|
canonryMcpTools,
|
|
5
5
|
createApiClient
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import
|
|
6
|
+
} from "./chunk-Y3O3HBMN.js";
|
|
7
|
+
import {
|
|
8
|
+
isReadOnlyKey
|
|
9
|
+
} from "./chunk-BNF3HXBW.js";
|
|
8
10
|
|
|
9
11
|
// src/mcp/cli.ts
|
|
10
12
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -363,9 +365,25 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
363
365
|
}
|
|
364
366
|
throw error;
|
|
365
367
|
}
|
|
366
|
-
const
|
|
368
|
+
const client = createApiClient();
|
|
369
|
+
const scope = await resolveEffectiveScope(client, options.scope);
|
|
370
|
+
const server = createCanonryMcpServer({ scope, eager: options.eager, clientFactory: () => client });
|
|
367
371
|
await server.connect(new StdioServerTransport());
|
|
368
372
|
}
|
|
373
|
+
async function resolveEffectiveScope(client, flagScope) {
|
|
374
|
+
if (flagScope === "read-only") return "read-only";
|
|
375
|
+
try {
|
|
376
|
+
const self = await client.getApiKeySelf();
|
|
377
|
+
if (isReadOnlyKey(self.scopes)) {
|
|
378
|
+
process.stderr.write(
|
|
379
|
+
"canonry-mcp: configured API key is read-only \u2014 restricting to read tools.\n"
|
|
380
|
+
);
|
|
381
|
+
return "read-only";
|
|
382
|
+
}
|
|
383
|
+
} catch {
|
|
384
|
+
}
|
|
385
|
+
return flagScope;
|
|
386
|
+
}
|
|
369
387
|
function parseCliOptions(argv, env = process.env) {
|
|
370
388
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
371
389
|
throw new HelpRequested();
|
|
@@ -419,5 +437,6 @@ export {
|
|
|
419
437
|
HELP_TEXT,
|
|
420
438
|
HelpRequested,
|
|
421
439
|
main,
|
|
422
|
-
parseCliOptions
|
|
440
|
+
parseCliOptions,
|
|
441
|
+
resolveEffectiveScope
|
|
423
442
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainyc/canonry",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.83.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Agent-first open-source AEO operating platform - track how answer engines cite your domain",
|
|
6
6
|
"license": "FSL-1.1-ALv2",
|
|
@@ -62,19 +62,19 @@
|
|
|
62
62
|
"@types/node-cron": "^3.0.11",
|
|
63
63
|
"tsup": "^8.5.1",
|
|
64
64
|
"tsx": "^4.19.0",
|
|
65
|
+
"@ainyc/canonry-config": "0.0.0",
|
|
65
66
|
"@ainyc/canonry-api-client": "0.0.0",
|
|
66
67
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
67
|
-
"@ainyc/canonry-config": "0.0.0",
|
|
68
68
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
69
69
|
"@ainyc/canonry-db": "0.0.0",
|
|
70
|
-
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
71
70
|
"@ainyc/canonry-integration-openai-ads": "0.0.0",
|
|
72
|
-
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
73
71
|
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
72
|
+
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
73
|
+
"@ainyc/canonry-integration-commoncrawl": "0.0.0",
|
|
74
74
|
"@ainyc/canonry-integration-google": "0.0.0",
|
|
75
|
+
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
75
76
|
"@ainyc/canonry-integration-google-business-profile": "0.0.0",
|
|
76
77
|
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
77
|
-
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
78
78
|
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
79
79
|
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
80
80
|
"@ainyc/canonry-provider-claude": "0.0.0",
|