@ainyc/canonry 4.98.0 → 4.99.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/dist/{chunk-7COFPNMH.js → chunk-CEHD33NQ.js} +221 -22
- package/dist/{chunk-3TH54726.js → chunk-VQN74WWA.js} +26 -0
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +16 -0
- package/dist/index.js +2 -2
- package/dist/mcp.js +1 -1
- package/package.json +9 -9
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
loadConfig,
|
|
10
10
|
loadConfigRaw,
|
|
11
11
|
saveConfigPatch
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-VQN74WWA.js";
|
|
13
13
|
import {
|
|
14
14
|
CC_CACHE_DIR,
|
|
15
15
|
DUCKDB_SPEC,
|
|
@@ -8331,13 +8331,63 @@ function buildSkillDocTools() {
|
|
|
8331
8331
|
// src/agent/mcp-to-agent-tool.ts
|
|
8332
8332
|
import { Type as Type2 } from "@sinclair/typebox";
|
|
8333
8333
|
var MAX_TOOL_RESULT_CHARS = 2e4;
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
return
|
|
8334
|
+
var TRUNCATION_NOTE = "... (truncated \u2014 result too large)";
|
|
8335
|
+
function serializeResult(value) {
|
|
8336
|
+
return JSON.stringify(value, null, 2);
|
|
8337
|
+
}
|
|
8338
|
+
function largestArrayKey(obj) {
|
|
8339
|
+
let best;
|
|
8340
|
+
let bestLen = -1;
|
|
8341
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
8342
|
+
if (!Array.isArray(v)) continue;
|
|
8343
|
+
const len = serializeResult(v).length;
|
|
8344
|
+
if (len > bestLen) {
|
|
8345
|
+
bestLen = len;
|
|
8346
|
+
best = k;
|
|
8347
|
+
}
|
|
8348
|
+
}
|
|
8349
|
+
return best;
|
|
8350
|
+
}
|
|
8351
|
+
function trimRowsToFit(rows, render) {
|
|
8352
|
+
let kept = rows.slice();
|
|
8353
|
+
while (kept.length > 0 && render(kept).length > MAX_TOOL_RESULT_CHARS) {
|
|
8354
|
+
kept = kept.slice(0, -1);
|
|
8355
|
+
}
|
|
8356
|
+
return kept;
|
|
8357
|
+
}
|
|
8358
|
+
function truncateToolResult(details) {
|
|
8359
|
+
const full = serializeResult(details);
|
|
8360
|
+
if (full.length <= MAX_TOOL_RESULT_CHARS) return full;
|
|
8361
|
+
if (Array.isArray(details)) {
|
|
8362
|
+
const kept = trimRowsToFit(
|
|
8363
|
+
details,
|
|
8364
|
+
(rows) => serializeResult({ items: rows, __truncated: true, __omittedRows: details.length - rows.length })
|
|
8365
|
+
);
|
|
8366
|
+
return serializeResult({ items: kept, __truncated: true, __omittedRows: details.length - kept.length });
|
|
8367
|
+
}
|
|
8368
|
+
if (details && typeof details === "object") {
|
|
8369
|
+
const obj = details;
|
|
8370
|
+
const arrayKey = largestArrayKey(obj);
|
|
8371
|
+
if (arrayKey) {
|
|
8372
|
+
const rows = obj[arrayKey];
|
|
8373
|
+
const kept = trimRowsToFit(
|
|
8374
|
+
rows,
|
|
8375
|
+
(r) => serializeResult({ ...obj, [arrayKey]: r, __truncated: true, __omittedRows: rows.length - r.length })
|
|
8376
|
+
);
|
|
8377
|
+
const out = serializeResult({
|
|
8378
|
+
...obj,
|
|
8379
|
+
[arrayKey]: kept,
|
|
8380
|
+
__truncated: true,
|
|
8381
|
+
__omittedRows: rows.length - kept.length
|
|
8382
|
+
});
|
|
8383
|
+
if (out.length <= MAX_TOOL_RESULT_CHARS) return out;
|
|
8384
|
+
}
|
|
8385
|
+
}
|
|
8386
|
+
return full.slice(0, MAX_TOOL_RESULT_CHARS) + "\n" + TRUNCATION_NOTE;
|
|
8337
8387
|
}
|
|
8338
8388
|
function textResult2(details) {
|
|
8339
8389
|
return {
|
|
8340
|
-
content: [{ type: "text", text:
|
|
8390
|
+
content: [{ type: "text", text: truncateToolResult(details) }],
|
|
8341
8391
|
details
|
|
8342
8392
|
};
|
|
8343
8393
|
}
|
|
@@ -8404,13 +8454,31 @@ function loadAeroSystemPrompt(pkgDir) {
|
|
|
8404
8454
|
const skillDir = resolveAeroSkillDir(pkgDir);
|
|
8405
8455
|
const skillBody = fs7.readFileSync(path8.join(skillDir, "SKILL.md"), "utf-8");
|
|
8406
8456
|
const soulPath = path8.join(skillDir, "soul.md");
|
|
8407
|
-
|
|
8408
|
-
const soulBody = fs7.readFileSync(soulPath, "utf-8");
|
|
8409
|
-
return `${soulBody.trimEnd()}
|
|
8457
|
+
const base = fs7.existsSync(soulPath) ? `${fs7.readFileSync(soulPath, "utf-8").trimEnd()}
|
|
8410
8458
|
|
|
8411
8459
|
---
|
|
8412
8460
|
|
|
8413
|
-
${skillBody}
|
|
8461
|
+
${skillBody}` : skillBody;
|
|
8462
|
+
return appendSystemPromptExtras(base);
|
|
8463
|
+
}
|
|
8464
|
+
function appendSystemPromptExtras(base, env = process.env) {
|
|
8465
|
+
const inline = env.AERO_SYSTEM_PROMPT_APPEND?.trim();
|
|
8466
|
+
let fileBody = "";
|
|
8467
|
+
const filePath = env.AERO_SYSTEM_PROMPT_FILE?.trim();
|
|
8468
|
+
if (filePath) {
|
|
8469
|
+
try {
|
|
8470
|
+
fileBody = fs7.readFileSync(filePath, "utf-8").trim();
|
|
8471
|
+
} catch {
|
|
8472
|
+
fileBody = "";
|
|
8473
|
+
}
|
|
8474
|
+
}
|
|
8475
|
+
const extras = [inline, fileBody].filter((s) => !!s && s.length > 0);
|
|
8476
|
+
if (extras.length === 0) return base;
|
|
8477
|
+
return `${base.trimEnd()}
|
|
8478
|
+
|
|
8479
|
+
---
|
|
8480
|
+
|
|
8481
|
+
${extras.join("\n\n")}`;
|
|
8414
8482
|
}
|
|
8415
8483
|
function missingProviderMessage() {
|
|
8416
8484
|
const configHints = agentProvidersByPriority().join(", ");
|
|
@@ -8461,6 +8529,93 @@ function resolveSessionProviderAndModel(config, opts) {
|
|
|
8461
8529
|
return { provider, modelId };
|
|
8462
8530
|
}
|
|
8463
8531
|
|
|
8532
|
+
// src/agent/remote-mcp.ts
|
|
8533
|
+
import { Type as Type3 } from "@sinclair/typebox";
|
|
8534
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
8535
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
8536
|
+
var log18 = createLogger("RemoteMcp");
|
|
8537
|
+
var AERO_EXCLUDED_MCP_TOOLS2 = /* @__PURE__ */ new Set([]);
|
|
8538
|
+
var MAX_TOOL_RESULT_CHARS2 = 2e4;
|
|
8539
|
+
function truncate(text) {
|
|
8540
|
+
if (text.length <= MAX_TOOL_RESULT_CHARS2) return text;
|
|
8541
|
+
return text.slice(0, MAX_TOOL_RESULT_CHARS2) + "\n... (truncated, result too large)";
|
|
8542
|
+
}
|
|
8543
|
+
async function connectStreamableHttp(server) {
|
|
8544
|
+
const transport = new StreamableHTTPClientTransport(new URL(server.url), {
|
|
8545
|
+
requestInit: {
|
|
8546
|
+
headers: { Authorization: `Bearer ${server.token}` }
|
|
8547
|
+
}
|
|
8548
|
+
});
|
|
8549
|
+
const client = new Client(
|
|
8550
|
+
{ name: "canonry-aero", version: "1.0.0" },
|
|
8551
|
+
{ capabilities: {} }
|
|
8552
|
+
);
|
|
8553
|
+
await client.connect(transport);
|
|
8554
|
+
return client;
|
|
8555
|
+
}
|
|
8556
|
+
function isReadOnly(tool) {
|
|
8557
|
+
return tool.annotations?.readOnlyHint === true;
|
|
8558
|
+
}
|
|
8559
|
+
function adaptRemoteTool(client, tool) {
|
|
8560
|
+
const parameters = Type3.Unsafe(
|
|
8561
|
+
tool.inputSchema ?? { type: "object", properties: {} }
|
|
8562
|
+
);
|
|
8563
|
+
const execute = async (_toolCallId, params) => {
|
|
8564
|
+
const result = await client.callTool({ name: tool.name, arguments: params });
|
|
8565
|
+
return {
|
|
8566
|
+
content: [{ type: "text", text: truncate(JSON.stringify(result, null, 2)) }],
|
|
8567
|
+
details: result
|
|
8568
|
+
};
|
|
8569
|
+
};
|
|
8570
|
+
return {
|
|
8571
|
+
name: tool.name,
|
|
8572
|
+
label: tool.annotations?.title ?? tool.name,
|
|
8573
|
+
description: tool.description ?? "",
|
|
8574
|
+
parameters,
|
|
8575
|
+
execute
|
|
8576
|
+
};
|
|
8577
|
+
}
|
|
8578
|
+
async function loadExternalMcpTools(servers, opts = {}) {
|
|
8579
|
+
if (!servers || servers.length === 0) return [];
|
|
8580
|
+
const connect = opts.connect ?? connectStreamableHttp;
|
|
8581
|
+
const excluded = opts.excluded ?? AERO_EXCLUDED_MCP_TOOLS2;
|
|
8582
|
+
const tools = [];
|
|
8583
|
+
for (const server of servers) {
|
|
8584
|
+
const label = server.label ?? server.url;
|
|
8585
|
+
let client;
|
|
8586
|
+
try {
|
|
8587
|
+
client = await connect(server);
|
|
8588
|
+
} catch (err) {
|
|
8589
|
+
log18.error("external-mcp.connect-failed", {
|
|
8590
|
+
label,
|
|
8591
|
+
error: err instanceof Error ? err.message : String(err)
|
|
8592
|
+
});
|
|
8593
|
+
continue;
|
|
8594
|
+
}
|
|
8595
|
+
let listed;
|
|
8596
|
+
try {
|
|
8597
|
+
listed = await client.listTools();
|
|
8598
|
+
} catch (err) {
|
|
8599
|
+
log18.error("external-mcp.list-failed", {
|
|
8600
|
+
label,
|
|
8601
|
+
error: err instanceof Error ? err.message : String(err)
|
|
8602
|
+
});
|
|
8603
|
+
continue;
|
|
8604
|
+
}
|
|
8605
|
+
for (const tool of listed.tools) {
|
|
8606
|
+
if (excluded.has(tool.name)) continue;
|
|
8607
|
+
if (!isReadOnly(tool)) continue;
|
|
8608
|
+
tools.push(adaptRemoteTool(client, tool));
|
|
8609
|
+
}
|
|
8610
|
+
log18.info("external-mcp.loaded", {
|
|
8611
|
+
label,
|
|
8612
|
+
discovered: listed.tools.length,
|
|
8613
|
+
adopted: tools.length
|
|
8614
|
+
});
|
|
8615
|
+
}
|
|
8616
|
+
return tools;
|
|
8617
|
+
}
|
|
8618
|
+
|
|
8464
8619
|
// src/agent/memory-store.ts
|
|
8465
8620
|
import crypto18 from "crypto";
|
|
8466
8621
|
import { and as and13, desc as desc6, eq as eq17, like, sql as sql5 } from "drizzle-orm";
|
|
@@ -8684,7 +8839,7 @@ async function compactMessages(args) {
|
|
|
8684
8839
|
}
|
|
8685
8840
|
|
|
8686
8841
|
// src/agent/session-registry.ts
|
|
8687
|
-
var
|
|
8842
|
+
var log19 = createLogger("SessionRegistry");
|
|
8688
8843
|
var MAX_HYDRATE_NOTES = 20;
|
|
8689
8844
|
var MAX_HYDRATE_BYTES = 32 * 1024;
|
|
8690
8845
|
function escapeMemoryFragment(value) {
|
|
@@ -8703,10 +8858,53 @@ var SessionRegistry = class {
|
|
|
8703
8858
|
* awaits the same promise instead of kicking off a duplicate LLM call.
|
|
8704
8859
|
*/
|
|
8705
8860
|
compactions = /* @__PURE__ */ new Map();
|
|
8861
|
+
/**
|
|
8862
|
+
* Read-only tools loaded once from the injected remote MCP servers (OSS-A).
|
|
8863
|
+
* The server set is static config, so we connect + adapt a single time and
|
|
8864
|
+
* cache the promise; every session merges the same AgentTool list. Resolves
|
|
8865
|
+
* to `[]` when no servers are configured or all fail to connect (the load is
|
|
8866
|
+
* fail-soft and never throws).
|
|
8867
|
+
*/
|
|
8868
|
+
externalToolsPromise;
|
|
8706
8869
|
opts;
|
|
8707
8870
|
constructor(opts) {
|
|
8708
8871
|
this.opts = opts;
|
|
8709
8872
|
}
|
|
8873
|
+
/**
|
|
8874
|
+
* Lazily load + cache the injected remote MCP tools. The seam OSS-A exposes:
|
|
8875
|
+
* `loadExternalMcpTools` connects to each configured server over the frozen
|
|
8876
|
+
* bearer-gated Streamable HTTP transport, lists tools, and adapts the
|
|
8877
|
+
* read-only, non-excluded ones into AgentTools. Cached so we connect once per
|
|
8878
|
+
* registry lifetime regardless of how many projects or turns run.
|
|
8879
|
+
*/
|
|
8880
|
+
loadExternalTools() {
|
|
8881
|
+
if (!this.externalToolsPromise) {
|
|
8882
|
+
this.externalToolsPromise = loadExternalMcpTools(this.opts.config.externalMcpServers).catch(
|
|
8883
|
+
(err) => {
|
|
8884
|
+
log19.error("external-mcp.load-failed", {
|
|
8885
|
+
error: err instanceof Error ? err.message : String(err)
|
|
8886
|
+
});
|
|
8887
|
+
return [];
|
|
8888
|
+
}
|
|
8889
|
+
);
|
|
8890
|
+
}
|
|
8891
|
+
return this.externalToolsPromise;
|
|
8892
|
+
}
|
|
8893
|
+
/**
|
|
8894
|
+
* Append the cached external MCP tools to the live agent's tool list, idempotently.
|
|
8895
|
+
* Called after scope/model alignment in `acquireForTurn` (which rebuilds
|
|
8896
|
+
* `state.tools` from the local registry), so the remote read-only tools ride
|
|
8897
|
+
* alongside the local ones for the upcoming turn. No-op when none are configured.
|
|
8898
|
+
*/
|
|
8899
|
+
async mergeExternalTools(agent) {
|
|
8900
|
+
const external = await this.loadExternalTools();
|
|
8901
|
+
if (external.length === 0) return;
|
|
8902
|
+
const current = agent.state.tools;
|
|
8903
|
+
const present = new Set(current.map((t) => t.name));
|
|
8904
|
+
const additions = external.filter((t) => !present.has(t.name));
|
|
8905
|
+
if (additions.length === 0) return;
|
|
8906
|
+
agent.state.tools = [...current, ...additions];
|
|
8907
|
+
}
|
|
8710
8908
|
/** Read-only access to the config snapshot the registry was built with. */
|
|
8711
8909
|
getConfig() {
|
|
8712
8910
|
return this.opts.config;
|
|
@@ -8865,6 +9063,7 @@ ${lines.join("\n")}
|
|
|
8865
9063
|
if (preferences?.provider || preferences?.modelId) {
|
|
8866
9064
|
this.alignModel(projectName, agent, preferences);
|
|
8867
9065
|
}
|
|
9066
|
+
await this.mergeExternalTools(agent);
|
|
8868
9067
|
await this.maybeCompact(projectName, agent);
|
|
8869
9068
|
return agent;
|
|
8870
9069
|
}
|
|
@@ -8911,13 +9110,13 @@ ${lines.join("\n")}
|
|
|
8911
9110
|
agent.state.messages = result.messages;
|
|
8912
9111
|
agent.state.systemPrompt = this.buildHydratedSystemPrompt(projectId, row.systemPrompt);
|
|
8913
9112
|
this.save(projectName);
|
|
8914
|
-
|
|
9113
|
+
log19.info("compaction.completed", {
|
|
8915
9114
|
projectName,
|
|
8916
9115
|
removedCount: result.removedCount,
|
|
8917
9116
|
summaryBytes: Buffer.byteLength(result.summary, "utf8")
|
|
8918
9117
|
});
|
|
8919
9118
|
} catch (err) {
|
|
8920
|
-
|
|
9119
|
+
log19.error("compaction.failed", {
|
|
8921
9120
|
projectName,
|
|
8922
9121
|
error: err instanceof Error ? err.message : String(err)
|
|
8923
9122
|
});
|
|
@@ -9014,7 +9213,7 @@ ${lines.join("\n")}
|
|
|
9014
9213
|
await agent.prompt(msgs);
|
|
9015
9214
|
this.save(projectName);
|
|
9016
9215
|
} catch (err) {
|
|
9017
|
-
|
|
9216
|
+
log19.error("drain.failed", {
|
|
9018
9217
|
projectName,
|
|
9019
9218
|
error: err instanceof Error ? err.message : String(err)
|
|
9020
9219
|
});
|
|
@@ -9612,7 +9811,7 @@ function formatAuditFactorScore(factor) {
|
|
|
9612
9811
|
}
|
|
9613
9812
|
|
|
9614
9813
|
// src/snapshot-service.ts
|
|
9615
|
-
var
|
|
9814
|
+
var log20 = createLogger("Snapshot");
|
|
9616
9815
|
var ANALYSIS_PROVIDER_PRIORITY = ["openai", "claude", "gemini", "perplexity", "local"];
|
|
9617
9816
|
var SNAPSHOT_QUERY_COUNT = 6;
|
|
9618
9817
|
var ProviderExecutionGate2 = class {
|
|
@@ -9758,7 +9957,7 @@ var SnapshotService = class {
|
|
|
9758
9957
|
return mapAuditReport(report);
|
|
9759
9958
|
} catch (err) {
|
|
9760
9959
|
const message = err instanceof Error ? err.message : String(err);
|
|
9761
|
-
|
|
9960
|
+
log20.warn("audit.failed", { homepageUrl, error: message });
|
|
9762
9961
|
return {
|
|
9763
9962
|
url: homepageUrl,
|
|
9764
9963
|
finalUrl: homepageUrl,
|
|
@@ -9787,7 +9986,7 @@ var SnapshotService = class {
|
|
|
9787
9986
|
queries: parsedQueries
|
|
9788
9987
|
};
|
|
9789
9988
|
} catch (err) {
|
|
9790
|
-
|
|
9989
|
+
log20.warn("profile.generation-failed", {
|
|
9791
9990
|
domain: ctx.domain,
|
|
9792
9991
|
provider: ctx.analysisProvider.adapter.name,
|
|
9793
9992
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -9929,7 +10128,7 @@ var SnapshotService = class {
|
|
|
9929
10128
|
recommendedActions: uniqueStrings(parsed.recommendedActions ?? []).slice(0, 4)
|
|
9930
10129
|
};
|
|
9931
10130
|
} catch (err) {
|
|
9932
|
-
|
|
10131
|
+
log20.warn("response.analysis-failed", {
|
|
9933
10132
|
provider: ctx.analysisProvider.adapter.name,
|
|
9934
10133
|
error: err instanceof Error ? err.message : String(err)
|
|
9935
10134
|
});
|
|
@@ -10211,7 +10410,7 @@ function clipText(value, length) {
|
|
|
10211
10410
|
// src/server.ts
|
|
10212
10411
|
var _require3 = createRequire3(import.meta.url);
|
|
10213
10412
|
var { version: PKG_VERSION2 } = _require3("../package.json");
|
|
10214
|
-
var
|
|
10413
|
+
var log21 = createLogger("Server");
|
|
10215
10414
|
var DEFAULT_QUOTA = {
|
|
10216
10415
|
maxConcurrency: 2,
|
|
10217
10416
|
maxRequestsPerMinute: 10,
|
|
@@ -10344,7 +10543,7 @@ function applyLegacyCredentials(rows, config) {
|
|
|
10344
10543
|
}
|
|
10345
10544
|
if (migratedGoogle > 0) {
|
|
10346
10545
|
saveConfigPatch({ google: config.google });
|
|
10347
|
-
|
|
10546
|
+
log21.info("credentials.migrated", { type: "google", count: migratedGoogle });
|
|
10348
10547
|
}
|
|
10349
10548
|
let migratedGa4 = 0;
|
|
10350
10549
|
for (const row of rows.ga4) {
|
|
@@ -10362,7 +10561,7 @@ function applyLegacyCredentials(rows, config) {
|
|
|
10362
10561
|
}
|
|
10363
10562
|
if (migratedGa4 > 0) {
|
|
10364
10563
|
saveConfigPatch({ ga4: config.ga4 });
|
|
10365
|
-
|
|
10564
|
+
log21.info("credentials.migrated", { type: "ga4", count: migratedGa4 });
|
|
10366
10565
|
}
|
|
10367
10566
|
}
|
|
10368
10567
|
function isLoopbackBindHost(host) {
|
|
@@ -10401,11 +10600,11 @@ async function createServer(opts) {
|
|
|
10401
10600
|
applyLegacyCredentials(legacyRows, opts.config);
|
|
10402
10601
|
dropLegacyCredentialColumns(opts.db);
|
|
10403
10602
|
} catch (err) {
|
|
10404
|
-
|
|
10603
|
+
log21.warn("credentials.migration.failed", {
|
|
10405
10604
|
error: err instanceof Error ? err.message : String(err)
|
|
10406
10605
|
});
|
|
10407
10606
|
}
|
|
10408
|
-
|
|
10607
|
+
log21.info("providers.configured", { providers: Object.keys(providers).filter((k) => {
|
|
10409
10608
|
const p = providers[k];
|
|
10410
10609
|
return p?.apiKey || p?.baseUrl || p?.vertexProject;
|
|
10411
10610
|
}) });
|
|
@@ -118,8 +118,34 @@ Do not write config.yaml by hand; use "canonry init", "canonry settings", or "ca
|
|
|
118
118
|
} catch {
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
+
const parsedExternalMcp = parseExternalMcpEnv(process.env.CANONRY_EXTERNAL_MCP);
|
|
122
|
+
if (parsedExternalMcp) {
|
|
123
|
+
parsed.externalMcpServers = parsedExternalMcp;
|
|
124
|
+
}
|
|
121
125
|
return parsed;
|
|
122
126
|
}
|
|
127
|
+
function parseExternalMcpEnv(raw) {
|
|
128
|
+
const trimmed = raw?.trim();
|
|
129
|
+
if (!trimmed) return void 0;
|
|
130
|
+
let value;
|
|
131
|
+
try {
|
|
132
|
+
value = JSON.parse(trimmed);
|
|
133
|
+
} catch {
|
|
134
|
+
return void 0;
|
|
135
|
+
}
|
|
136
|
+
if (!Array.isArray(value)) return void 0;
|
|
137
|
+
const servers = [];
|
|
138
|
+
for (const entry of value) {
|
|
139
|
+
if (!entry || typeof entry !== "object") continue;
|
|
140
|
+
const candidate = entry;
|
|
141
|
+
const url = typeof candidate.url === "string" ? candidate.url.trim() : "";
|
|
142
|
+
const token = typeof candidate.token === "string" ? candidate.token : "";
|
|
143
|
+
if (!url || !token) continue;
|
|
144
|
+
const label = typeof candidate.label === "string" ? candidate.label : void 0;
|
|
145
|
+
servers.push({ url, token, ...label ? { label } : {} });
|
|
146
|
+
}
|
|
147
|
+
return servers.length > 0 ? servers : void 0;
|
|
148
|
+
}
|
|
123
149
|
function loadConfigRaw() {
|
|
124
150
|
const configPath = getConfigPath();
|
|
125
151
|
if (!fs.existsSync(configPath)) return null;
|
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-CEHD33NQ.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-VQN74WWA.js";
|
|
48
48
|
import {
|
|
49
49
|
apiKeys,
|
|
50
50
|
createClient,
|
package/dist/index.d.ts
CHANGED
|
@@ -156,6 +156,21 @@ interface VercelTrafficConnectionConfigEntry {
|
|
|
156
156
|
interface VercelTrafficConfigEntry {
|
|
157
157
|
connections?: VercelTrafficConnectionConfigEntry[];
|
|
158
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* One injected remote MCP server Aero loads read-only tools from (OSS-A).
|
|
161
|
+
* Generic shape: `{ url, token, label? }`. The transport is bearer-gated MCP
|
|
162
|
+
* Streamable HTTP (the contract is frozen in `agent/remote-mcp.ts`). The
|
|
163
|
+
* server is remote, never co-located in the OSS container; per-tenant
|
|
164
|
+
* isolation is the token's responsibility, not the container boundary.
|
|
165
|
+
*/
|
|
166
|
+
interface ExternalMcpServerConfig {
|
|
167
|
+
/** Streamable HTTP endpoint of the remote MCP server. */
|
|
168
|
+
url: string;
|
|
169
|
+
/** Bearer token sent as `Authorization: Bearer <token>`. */
|
|
170
|
+
token: string;
|
|
171
|
+
/** Optional human label used in logs. Defaults to `url`. */
|
|
172
|
+
label?: string;
|
|
173
|
+
}
|
|
159
174
|
interface AgentConfigEntry {
|
|
160
175
|
/**
|
|
161
176
|
* Agent mode. `'disabled'` turns the built-in Aero agent OFF entirely — the
|
|
@@ -212,6 +227,7 @@ interface CanonryConfig {
|
|
|
212
227
|
lastUpdateCheckAt?: string;
|
|
213
228
|
lastKnownLatestVersion?: string;
|
|
214
229
|
agent?: AgentConfigEntry;
|
|
230
|
+
externalMcpServers?: ExternalMcpServerConfig[];
|
|
215
231
|
places?: PlacesConfigEntry;
|
|
216
232
|
embed?: EmbedConfigEntry;
|
|
217
233
|
}
|
package/dist/index.js
CHANGED
package/dist/mcp.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainyc/canonry",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.99.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-routes": "0.0.0",
|
|
66
65
|
"@ainyc/canonry-api-client": "0.0.0",
|
|
67
|
-
"@ainyc/canonry-
|
|
66
|
+
"@ainyc/canonry-api-routes": "0.0.0",
|
|
68
67
|
"@ainyc/canonry-contracts": "0.0.0",
|
|
69
|
-
"@ainyc/canonry-
|
|
68
|
+
"@ainyc/canonry-config": "0.0.0",
|
|
70
69
|
"@ainyc/canonry-db": "0.0.0",
|
|
71
70
|
"@ainyc/canonry-integration-openai-ads": "0.0.0",
|
|
71
|
+
"@ainyc/canonry-integration-bing": "0.0.0",
|
|
72
72
|
"@ainyc/canonry-integration-cloud-run": "0.0.0",
|
|
73
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-
|
|
76
|
+
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
77
77
|
"@ainyc/canonry-intelligence": "0.0.0",
|
|
78
78
|
"@ainyc/canonry-integration-google-places": "0.0.0",
|
|
79
|
-
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
80
|
-
"@ainyc/canonry-integration-traffic": "0.0.0",
|
|
81
79
|
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
80
|
+
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
82
81
|
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
82
|
+
"@ainyc/canonry-integration-wordpress": "0.0.0",
|
|
83
83
|
"@ainyc/canonry-provider-local": "0.0.0",
|
|
84
|
-
"@ainyc/canonry-provider-
|
|
85
|
-
"@ainyc/canonry-provider-
|
|
84
|
+
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
85
|
+
"@ainyc/canonry-provider-perplexity": "0.0.0"
|
|
86
86
|
},
|
|
87
87
|
"scripts": {
|
|
88
88
|
"build": "tsx scripts/copy-agent-assets.ts && tsup && tsx build-web.ts",
|