@ainyc/canonry 4.81.0 → 4.82.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +4 -0
  2. package/assets/assets/{BacklinksPage-DHShKKpo.js → BacklinksPage-CHclt-pq.js} +1 -1
  3. package/assets/assets/{ChartPrimitives-udHScxjY.js → ChartPrimitives-2Ub4vNWe.js} +1 -1
  4. package/assets/assets/{ProjectPage-BsS1anh7.js → ProjectPage-UPmHfuxR.js} +1 -1
  5. package/assets/assets/{RunRow-CXyPHMVQ.js → RunRow-rUL1UeA3.js} +1 -1
  6. package/assets/assets/{RunsPage-BpQ_NpFt.js → RunsPage-BQpHfUJf.js} +1 -1
  7. package/assets/assets/{SettingsPage-1ep4ch7n.js → SettingsPage-DjTJlr_1.js} +1 -1
  8. package/assets/assets/{TrafficPage-C3Hx-sE7.js → TrafficPage-D7rv3BrH.js} +1 -1
  9. package/assets/assets/{TrafficSourceDetailPage-B26n2R6G.js → TrafficSourceDetailPage-BysyuH2H.js} +1 -1
  10. package/assets/assets/{arrow-left-Dc_IPJxw.js → arrow-left-CR_FGlkE.js} +1 -1
  11. package/assets/assets/{extract-error-message-B3PoKkHW.js → extract-error-message-BKkAbWNp.js} +1 -1
  12. package/assets/assets/{index-DhdFTQkU.js → index-DzzTt20n.js} +11 -11
  13. package/assets/assets/{trash-2-BQ69cGl0.js → trash-2-uSttujvh.js} +1 -1
  14. package/assets/index.html +1 -1
  15. package/dist/{chunk-UAQ42NVJ.js → chunk-IEUTAQUF.js} +32 -2
  16. package/dist/{chunk-6XOZSS3Y.js → chunk-JLAD6CYH.js} +17 -1
  17. package/dist/{chunk-GMT3YPLT.js → chunk-KPSFRSS7.js} +20 -1
  18. package/dist/{chunk-VX5C7DK7.js → chunk-NSZ3D3MM.js} +4 -4
  19. package/dist/cli.js +46 -14
  20. package/dist/index.js +4 -4
  21. package/dist/{intelligence-service-CAAQAKPN.js → intelligence-service-2UUJ3YGI.js} +2 -2
  22. package/dist/mcp.js +23 -4
  23. package/package.json +9 -9
@@ -1 +1 @@
1
- import{c}from"./index-DhdFTQkU.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};
1
+ import{c}from"./index-DzzTt20n.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-DhdFTQkU.js"></script>
15
+ <script type="module" crossorigin src="./assets/index-DzzTt20n.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">
@@ -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-GMT3YPLT.js";
249
+ } from "./chunk-KPSFRSS7.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";
@@ -5290,6 +5291,7 @@ import fs8 from "fs";
5290
5291
  // ../api-routes/src/auth.ts
5291
5292
  import crypto2 from "crypto";
5292
5293
  import { eq } from "drizzle-orm";
5294
+ var WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
5293
5295
  function requireScope(request, scope) {
5294
5296
  const key = request.apiKey;
5295
5297
  if (!key) return;
@@ -5357,6 +5359,9 @@ async function authPlugin(app, opts = {}) {
5357
5359
  app.db.update(apiKeys).set({ lastUsedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq(apiKeys.id, key.id)).run();
5358
5360
  const scopes = Array.isArray(key.scopes) ? key.scopes : [];
5359
5361
  request.apiKey = { id: key.id, name: key.name, scopes };
5362
+ if (isReadOnlyKey(scopes) && WRITE_METHODS.has(request.method)) {
5363
+ throw forbidden("This API key is read-only and cannot perform write operations.");
5364
+ }
5360
5365
  });
5361
5366
  }
5362
5367
 
@@ -14431,6 +14436,17 @@ var routeCatalog = [
14431
14436
  200: jsonResponse("Keys returned.", "ApiKeyListDto")
14432
14437
  }
14433
14438
  },
14439
+ {
14440
+ method: "get",
14441
+ path: "/api/v1/keys/self",
14442
+ summary: "Introspect the current API key",
14443
+ 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.",
14444
+ tags: ["keys"],
14445
+ responses: {
14446
+ 200: jsonResponse("Current key returned.", "ApiKeyDto"),
14447
+ 404: errorResponse("No key on the request (auth skipped).")
14448
+ }
14449
+ },
14434
14450
  {
14435
14451
  method: "post",
14436
14452
  path: "/api/v1/keys",
@@ -17586,11 +17602,13 @@ import crypto12 from "crypto";
17586
17602
  import { desc as desc9, eq as eq17 } from "drizzle-orm";
17587
17603
  var KEYS_WRITE_SCOPE = "keys.write";
17588
17604
  function toApiKeyDto(row) {
17605
+ const scopes = Array.isArray(row.scopes) ? row.scopes : [];
17589
17606
  return {
17590
17607
  id: row.id,
17591
17608
  name: row.name,
17592
17609
  keyPrefix: row.keyPrefix,
17593
- scopes: Array.isArray(row.scopes) ? row.scopes : [],
17610
+ scopes,
17611
+ readOnly: isReadOnlyKey(scopes),
17594
17612
  createdAt: row.createdAt,
17595
17613
  lastUsedAt: row.lastUsedAt ?? null,
17596
17614
  revokedAt: row.revokedAt ?? null
@@ -17601,6 +17619,17 @@ async function keysRoutes(app) {
17601
17619
  const rows = app.db.select().from(apiKeys).orderBy(desc9(apiKeys.createdAt)).all();
17602
17620
  return { keys: rows.map(toApiKeyDto) };
17603
17621
  });
17622
+ app.get("/keys/self", async (request) => {
17623
+ const id = request.apiKey?.id;
17624
+ if (!id) {
17625
+ throw notFound("API key", "self");
17626
+ }
17627
+ const row = app.db.select().from(apiKeys).where(eq17(apiKeys.id, id)).get();
17628
+ if (!row) {
17629
+ throw notFound("API key", id);
17630
+ }
17631
+ return toApiKeyDto(row);
17632
+ });
17604
17633
  app.post("/keys", async (request) => {
17605
17634
  requireScope(request, KEYS_WRITE_SCOPE);
17606
17635
  const parsed = createApiKeyRequestSchema.safeParse(request.body);
@@ -17636,6 +17665,7 @@ async function keysRoutes(app) {
17636
17665
  name,
17637
17666
  keyPrefix,
17638
17667
  scopes: effectiveScopes,
17668
+ readOnly: isReadOnlyKey(effectiveScopes),
17639
17669
  createdAt: now,
17640
17670
  lastUsedAt: null,
17641
17671
  revokedAt: null,
@@ -23,7 +23,7 @@ import {
23
23
  trafficConnectVercelRequestSchema,
24
24
  trafficConnectWordpressRequestSchema,
25
25
  trafficEventKindSchema
26
- } from "./chunk-GMT3YPLT.js";
26
+ } from "./chunk-KPSFRSS7.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
  }
@@ -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()
@@ -4780,5 +4797,7 @@ export {
4780
4797
  AI_ENGINE_SELF_DOMAINS,
4781
4798
  VERTEX_AI_SEARCH_PROXY_DOMAIN,
4782
4799
  AI_PROVIDER_INFRA_DOMAINS,
4783
- escapeLikePattern
4800
+ escapeLikePattern,
4801
+ READ_ONLY_SCOPE,
4802
+ isReadOnlyKey
4784
4803
  };
@@ -9,7 +9,7 @@ import {
9
9
  loadConfig,
10
10
  loadConfigRaw,
11
11
  saveConfigPatch
12
- } from "./chunk-6XOZSS3Y.js";
12
+ } from "./chunk-JLAD6CYH.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-UAQ42NVJ.js";
107
+ } from "./chunk-IEUTAQUF.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-GMT3YPLT.js";
163
+ } from "./chunk-KPSFRSS7.js";
164
164
 
165
165
  // src/telemetry.ts
166
166
  import crypto from "crypto";
@@ -6278,7 +6278,7 @@ function readStoredGroundingSources(rawResponse) {
6278
6278
  return result;
6279
6279
  }
6280
6280
  async function backfillInsightsCommand(project, opts) {
6281
- const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-CAAQAKPN.js");
6281
+ const { IntelligenceService: IntelligenceService2 } = await import("./intelligence-service-2UUJ3YGI.js");
6282
6282
  const config = loadConfig();
6283
6283
  const db = createClient(config.database);
6284
6284
  migrate(db);
package/dist/cli.js CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  setTelemetrySource,
28
28
  showFirstRunNotice,
29
29
  trackEvent
30
- } from "./chunk-VX5C7DK7.js";
30
+ } from "./chunk-NSZ3D3MM.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-6XOZSS3Y.js";
47
+ } from "./chunk-JLAD6CYH.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-UAQ42NVJ.js";
55
+ } from "./chunk-IEUTAQUF.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-GMT3YPLT.js";
79
+ } from "./chunk-KPSFRSS7.js";
79
80
 
80
81
  // src/cli.ts
81
82
  import { pathToFileURL } from "url";
@@ -5640,9 +5641,18 @@ async function listApiKeys(format) {
5640
5641
  }
5641
5642
  }
5642
5643
  async function createApiKey(opts) {
5644
+ const explicitScopes = opts.scopes && opts.scopes.length > 0 ? opts.scopes : void 0;
5645
+ if (opts.readOnly && explicitScopes) {
5646
+ throw new CliError({
5647
+ code: "CLI_USAGE_ERROR",
5648
+ message: "--read-only cannot be combined with --scope",
5649
+ displayMessage: 'Error: --read-only cannot be combined with --scope (it already implies the "read" scope).'
5650
+ });
5651
+ }
5643
5652
  const client = getClient11();
5644
5653
  const body = { name: opts.name };
5645
- if (opts.scopes && opts.scopes.length > 0) body.scopes = opts.scopes;
5654
+ const scopes = opts.readOnly ? [READ_ONLY_SCOPE] : explicitScopes;
5655
+ if (scopes) body.scopes = scopes;
5646
5656
  const created = await client.createApiKey(body);
5647
5657
  if (isMachineFormat(opts.format)) {
5648
5658
  console.log(JSON.stringify(created, null, 2));
@@ -5650,11 +5660,24 @@ async function createApiKey(opts) {
5650
5660
  }
5651
5661
  console.log(`API key "${created.name}" created.
5652
5662
  `);
5653
- console.log(` Key: ${created.key}`);
5654
- console.log(` Prefix: ${created.keyPrefix}`);
5655
- console.log(` Scopes: ${created.scopes.join(", ")}`);
5663
+ console.log(` Key: ${created.key}`);
5664
+ console.log(` Prefix: ${created.keyPrefix}`);
5665
+ console.log(` Scopes: ${created.scopes.join(", ")}`);
5666
+ console.log(` Read-only: ${created.readOnly ? "yes" : "no"}`);
5656
5667
  console.log("\nSave this now \u2014 it will not be shown again.");
5657
5668
  }
5669
+ async function showApiKeySelf(format) {
5670
+ const client = getClient11();
5671
+ const key = await client.getApiKeySelf();
5672
+ if (isMachineFormat(format)) {
5673
+ console.log(JSON.stringify(key, null, 2));
5674
+ return;
5675
+ }
5676
+ console.log(`API key "${key.name}" (${key.keyPrefix})`);
5677
+ console.log(` Scopes: ${key.scopes.join(", ")}`);
5678
+ console.log(` Read-only: ${key.readOnly ? "yes" : "no"}`);
5679
+ console.log(` Status: ${keyStatus(key)}`);
5680
+ }
5658
5681
  async function revokeApiKey(id, format) {
5659
5682
  const client = getClient11();
5660
5683
  const key = await client.revokeApiKey(id);
@@ -5676,15 +5699,16 @@ var KEYS_CLI_COMMANDS = [
5676
5699
  },
5677
5700
  {
5678
5701
  path: ["key", "create"],
5679
- usage: "canonry key create --name <name> [--scope <s> ...] [--format json]",
5702
+ usage: "canonry key create --name <name> [--read-only | --scope <s> ...] [--format json]",
5680
5703
  options: {
5681
5704
  name: stringOption(),
5682
- scope: multiStringOption()
5705
+ scope: multiStringOption(),
5706
+ "read-only": { type: "boolean" }
5683
5707
  },
5684
5708
  run: async (input) => {
5685
5709
  const name = requireStringOption(input, "name", {
5686
5710
  command: "key.create",
5687
- usage: "canonry key create --name <name> [--scope <s> ...] [--format json]",
5711
+ usage: "canonry key create --name <name> [--read-only | --scope <s> ...] [--format json]",
5688
5712
  message: "--name is required"
5689
5713
  });
5690
5714
  const raw = getStringArray(input.values, "scope") ?? [];
@@ -5692,10 +5716,18 @@ var KEYS_CLI_COMMANDS = [
5692
5716
  await createApiKey({
5693
5717
  name,
5694
5718
  scopes: scopes.length > 0 ? scopes : void 0,
5719
+ readOnly: getBoolean(input.values, "read-only"),
5695
5720
  format: input.format
5696
5721
  });
5697
5722
  }
5698
5723
  },
5724
+ {
5725
+ path: ["key", "whoami"],
5726
+ usage: "canonry key whoami [--format json]",
5727
+ run: async (input) => {
5728
+ await showApiKeySelf(input.format);
5729
+ }
5730
+ },
5699
5731
  {
5700
5732
  path: ["key", "revoke"],
5701
5733
  usage: "canonry key revoke <id> [--format json]",
@@ -5710,12 +5742,12 @@ var KEYS_CLI_COMMANDS = [
5710
5742
  },
5711
5743
  {
5712
5744
  path: ["key"],
5713
- usage: "canonry key <list|create|revoke>",
5745
+ usage: "canonry key <list|create|revoke|whoami>",
5714
5746
  run: async (input) => {
5715
5747
  unknownSubcommand(input.positionals[0], {
5716
5748
  command: "key",
5717
- usage: "canonry key <list|create|revoke>",
5718
- available: ["list", "create", "revoke"]
5749
+ usage: "canonry key <list|create|revoke|whoami>",
5750
+ available: ["list", "create", "revoke", "whoami"]
5719
5751
  });
5720
5752
  }
5721
5753
  }
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createServer
3
- } from "./chunk-VX5C7DK7.js";
3
+ } from "./chunk-NSZ3D3MM.js";
4
4
  import {
5
5
  loadConfig
6
- } from "./chunk-6XOZSS3Y.js";
7
- import "./chunk-UAQ42NVJ.js";
8
- import "./chunk-GMT3YPLT.js";
6
+ } from "./chunk-JLAD6CYH.js";
7
+ import "./chunk-IEUTAQUF.js";
8
+ import "./chunk-KPSFRSS7.js";
9
9
  export {
10
10
  createServer,
11
11
  loadConfig
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  IntelligenceService
3
- } from "./chunk-UAQ42NVJ.js";
4
- import "./chunk-GMT3YPLT.js";
3
+ } from "./chunk-IEUTAQUF.js";
4
+ import "./chunk-KPSFRSS7.js";
5
5
  export {
6
6
  IntelligenceService
7
7
  };
package/dist/mcp.js CHANGED
@@ -3,8 +3,10 @@ import {
3
3
  PACKAGE_VERSION,
4
4
  canonryMcpTools,
5
5
  createApiClient
6
- } from "./chunk-6XOZSS3Y.js";
7
- import "./chunk-GMT3YPLT.js";
6
+ } from "./chunk-JLAD6CYH.js";
7
+ import {
8
+ isReadOnlyKey
9
+ } from "./chunk-KPSFRSS7.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 server = createCanonryMcpServer({ scope: options.scope, eager: options.eager });
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.81.0",
3
+ "version": "4.82.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,27 +62,27 @@
62
62
  "@types/node-cron": "^3.0.11",
63
63
  "tsup": "^8.5.1",
64
64
  "tsx": "^4.19.0",
65
- "@ainyc/canonry-api-client": "0.0.0",
66
65
  "@ainyc/canonry-api-routes": "0.0.0",
66
+ "@ainyc/canonry-api-client": "0.0.0",
67
67
  "@ainyc/canonry-config": "0.0.0",
68
- "@ainyc/canonry-contracts": "0.0.0",
69
68
  "@ainyc/canonry-db": "0.0.0",
69
+ "@ainyc/canonry-contracts": "0.0.0",
70
70
  "@ainyc/canonry-integration-bing": "0.0.0",
71
71
  "@ainyc/canonry-integration-openai-ads": "0.0.0",
72
- "@ainyc/canonry-integration-commoncrawl": "0.0.0",
73
72
  "@ainyc/canonry-integration-cloud-run": "0.0.0",
73
+ "@ainyc/canonry-integration-commoncrawl": "0.0.0",
74
74
  "@ainyc/canonry-integration-google": "0.0.0",
75
75
  "@ainyc/canonry-integration-google-business-profile": "0.0.0",
76
- "@ainyc/canonry-integration-traffic": "0.0.0",
77
76
  "@ainyc/canonry-integration-google-places": "0.0.0",
78
- "@ainyc/canonry-integration-wordpress": "0.0.0",
77
+ "@ainyc/canonry-integration-traffic": "0.0.0",
78
+ "@ainyc/canonry-intelligence": "0.0.0",
79
79
  "@ainyc/canonry-provider-cdp": "0.0.0",
80
+ "@ainyc/canonry-integration-wordpress": "0.0.0",
80
81
  "@ainyc/canonry-provider-claude": "0.0.0",
81
82
  "@ainyc/canonry-provider-gemini": "0.0.0",
82
- "@ainyc/canonry-intelligence": "0.0.0",
83
83
  "@ainyc/canonry-provider-local": "0.0.0",
84
- "@ainyc/canonry-provider-openai": "0.0.0",
85
- "@ainyc/canonry-provider-perplexity": "0.0.0"
84
+ "@ainyc/canonry-provider-perplexity": "0.0.0",
85
+ "@ainyc/canonry-provider-openai": "0.0.0"
86
86
  },
87
87
  "scripts": {
88
88
  "build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",