@corenel/sidecar 0.8.1 → 0.8.3
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/cli.js +360 -61
- package/package.json +4 -4
package/dist/cli.js
CHANGED
|
@@ -14239,10 +14239,10 @@ var require_filters = __commonJS({
|
|
|
14239
14239
|
_exports.striptags = striptags;
|
|
14240
14240
|
function title(str10) {
|
|
14241
14241
|
str10 = normalize3(str10, "");
|
|
14242
|
-
var
|
|
14242
|
+
var words2 = str10.split(" ").map(function(word) {
|
|
14243
14243
|
return capitalize(word);
|
|
14244
14244
|
});
|
|
14245
|
-
return r2.copySafeness(str10,
|
|
14245
|
+
return r2.copySafeness(str10, words2.join(" "));
|
|
14246
14246
|
}
|
|
14247
14247
|
_exports.title = title;
|
|
14248
14248
|
function trim(str10) {
|
|
@@ -14297,7 +14297,7 @@ var require_filters = __commonJS({
|
|
|
14297
14297
|
length = Infinity;
|
|
14298
14298
|
}
|
|
14299
14299
|
var noFollowAttr = nofollow === true ? ' rel="nofollow"' : "";
|
|
14300
|
-
var
|
|
14300
|
+
var words2 = str10.split(/(\s+)/).filter(function(word) {
|
|
14301
14301
|
return word && word.length;
|
|
14302
14302
|
}).map(function(word) {
|
|
14303
14303
|
var matches = word.match(puncRe);
|
|
@@ -14317,13 +14317,13 @@ var require_filters = __commonJS({
|
|
|
14317
14317
|
}
|
|
14318
14318
|
return word;
|
|
14319
14319
|
});
|
|
14320
|
-
return
|
|
14320
|
+
return words2.join("");
|
|
14321
14321
|
}
|
|
14322
14322
|
_exports.urlize = urlize;
|
|
14323
14323
|
function wordcount(str10) {
|
|
14324
14324
|
str10 = normalize3(str10, "");
|
|
14325
|
-
var
|
|
14326
|
-
return
|
|
14325
|
+
var words2 = str10 ? str10.match(/\w+/g) : null;
|
|
14326
|
+
return words2 ? words2.length : null;
|
|
14327
14327
|
}
|
|
14328
14328
|
_exports.wordcount = wordcount;
|
|
14329
14329
|
function float(val, def) {
|
|
@@ -17408,10 +17408,10 @@ ${yamlContent}` : yamlContent;
|
|
|
17408
17408
|
if (!str10 || typeof str10 !== "string") {
|
|
17409
17409
|
return "";
|
|
17410
17410
|
}
|
|
17411
|
-
const
|
|
17411
|
+
const words2 = str10.split(/\s+/);
|
|
17412
17412
|
const lines = [];
|
|
17413
17413
|
let currentLine = "";
|
|
17414
|
-
for (const word of
|
|
17414
|
+
for (const word of words2) {
|
|
17415
17415
|
if (currentLine.length + word.length + 1 <= width) {
|
|
17416
17416
|
currentLine += (currentLine ? " " : "") + word;
|
|
17417
17417
|
} else {
|
|
@@ -18083,10 +18083,10 @@ ${content}` : parentData.content;
|
|
|
18083
18083
|
if (!str10 || typeof str10 !== "string") {
|
|
18084
18084
|
return "";
|
|
18085
18085
|
}
|
|
18086
|
-
const
|
|
18086
|
+
const words2 = str10.split(/\s+/);
|
|
18087
18087
|
const lines = [];
|
|
18088
18088
|
let currentLine = "";
|
|
18089
|
-
for (const word of
|
|
18089
|
+
for (const word of words2) {
|
|
18090
18090
|
if (currentLine.length + word.length + 1 <= width) {
|
|
18091
18091
|
currentLine += (currentLine ? " " : "") + word;
|
|
18092
18092
|
} else {
|
|
@@ -24888,7 +24888,7 @@ var require_abort_controller = __commonJS({
|
|
|
24888
24888
|
"use strict";
|
|
24889
24889
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24890
24890
|
var eventTargetShim = require_event_target_shim();
|
|
24891
|
-
var
|
|
24891
|
+
var AbortSignal2 = class extends eventTargetShim.EventTarget {
|
|
24892
24892
|
/**
|
|
24893
24893
|
* AbortSignal cannot be constructed directly.
|
|
24894
24894
|
*/
|
|
@@ -24907,9 +24907,9 @@ var require_abort_controller = __commonJS({
|
|
|
24907
24907
|
return aborted;
|
|
24908
24908
|
}
|
|
24909
24909
|
};
|
|
24910
|
-
eventTargetShim.defineEventAttribute(
|
|
24910
|
+
eventTargetShim.defineEventAttribute(AbortSignal2.prototype, "abort");
|
|
24911
24911
|
function createAbortSignal() {
|
|
24912
|
-
const signal = Object.create(
|
|
24912
|
+
const signal = Object.create(AbortSignal2.prototype);
|
|
24913
24913
|
eventTargetShim.EventTarget.call(signal);
|
|
24914
24914
|
abortedFlags.set(signal, false);
|
|
24915
24915
|
return signal;
|
|
@@ -24922,11 +24922,11 @@ var require_abort_controller = __commonJS({
|
|
|
24922
24922
|
signal.dispatchEvent({ type: "abort" });
|
|
24923
24923
|
}
|
|
24924
24924
|
var abortedFlags = /* @__PURE__ */ new WeakMap();
|
|
24925
|
-
Object.defineProperties(
|
|
24925
|
+
Object.defineProperties(AbortSignal2.prototype, {
|
|
24926
24926
|
aborted: { enumerable: true }
|
|
24927
24927
|
});
|
|
24928
24928
|
if (typeof Symbol === "function" && typeof Symbol.toStringTag === "symbol") {
|
|
24929
|
-
Object.defineProperty(
|
|
24929
|
+
Object.defineProperty(AbortSignal2.prototype, Symbol.toStringTag, {
|
|
24930
24930
|
configurable: true,
|
|
24931
24931
|
value: "AbortSignal"
|
|
24932
24932
|
});
|
|
@@ -24970,11 +24970,11 @@ var require_abort_controller = __commonJS({
|
|
|
24970
24970
|
});
|
|
24971
24971
|
}
|
|
24972
24972
|
exports.AbortController = AbortController2;
|
|
24973
|
-
exports.AbortSignal =
|
|
24973
|
+
exports.AbortSignal = AbortSignal2;
|
|
24974
24974
|
exports.default = AbortController2;
|
|
24975
24975
|
module.exports = AbortController2;
|
|
24976
24976
|
module.exports.AbortController = module.exports["default"] = AbortController2;
|
|
24977
|
-
module.exports.AbortSignal =
|
|
24977
|
+
module.exports.AbortSignal = AbortSignal2;
|
|
24978
24978
|
}
|
|
24979
24979
|
});
|
|
24980
24980
|
|
|
@@ -41720,6 +41720,9 @@ var BUILTIN_NAMESPACES = {
|
|
|
41720
41720
|
spawn_agents: "agent",
|
|
41721
41721
|
call_agent: "agent",
|
|
41722
41722
|
todo_write: "agent",
|
|
41723
|
+
// Finds deferred MCP tools (toolSearch.ts). Deliberately not `system`, which
|
|
41724
|
+
// the standard policy denies: search is a read and must always be reachable.
|
|
41725
|
+
tool_search: "agent",
|
|
41723
41726
|
// Named here as a backstop; the sidecar's own decls also carry `namespace`,
|
|
41724
41727
|
// and an explicit field always wins (resolveNamespace). Both say the same
|
|
41725
41728
|
// thing so a sidecar that predates this still lands in the right namespace.
|
|
@@ -41807,14 +41810,115 @@ ${ref.preview}${ref.bytes > ref.preview.length ? "\n\u2026(truncated)" : ""}` :
|
|
|
41807
41810
|
// ../harness/prompts/toolsMarker.ts
|
|
41808
41811
|
var TOOLS_MARKER = "\uE000PROMPD_TOOLS\uE000";
|
|
41809
41812
|
function formatToolLines(tools) {
|
|
41810
|
-
return tools.map((t2) =>
|
|
41813
|
+
return tools.map((t2) => `\`${t2.name}\``).join(", ");
|
|
41811
41814
|
}
|
|
41812
41815
|
function fillToolsMarker(system, tools) {
|
|
41813
41816
|
if (!system.includes(TOOLS_MARKER)) return system;
|
|
41814
41817
|
return system.replaceAll(TOOLS_MARKER, tools.length ? formatToolLines(tools) : "(no tools available this run)");
|
|
41815
41818
|
}
|
|
41816
41819
|
|
|
41820
|
+
// ../harness/tools/toolSearch.ts
|
|
41821
|
+
init_protocol();
|
|
41822
|
+
var TOOL_SEARCH_NAME = "tool_search";
|
|
41823
|
+
var LOADED_TOOLS_CAP = 24;
|
|
41824
|
+
var DEFAULT_LIMIT = 8;
|
|
41825
|
+
var MAX_LIMIT = 20;
|
|
41826
|
+
function serverOf(tool) {
|
|
41827
|
+
return parseMcpWireName(tool.name)?.server ?? "mcp";
|
|
41828
|
+
}
|
|
41829
|
+
function words(s2) {
|
|
41830
|
+
return s2.toLowerCase().split(/[^a-z0-9]+/).filter((w2) => w2.length > 1);
|
|
41831
|
+
}
|
|
41832
|
+
function rankTools(query, tools, opts = {}) {
|
|
41833
|
+
const limit2 = Math.min(MAX_LIMIT, Math.max(1, Math.floor(opts.limit ?? DEFAULT_LIMIT)));
|
|
41834
|
+
const pool = opts.server ? tools.filter((t2) => serverOf(t2) === opts.server) : tools;
|
|
41835
|
+
const q2 = words(query);
|
|
41836
|
+
const scored = pool.map((tool, i2) => {
|
|
41837
|
+
const parsed = parseMcpWireName(tool.name);
|
|
41838
|
+
const nameWords = words(parsed?.tool ?? tool.name);
|
|
41839
|
+
const serverWords = words(parsed?.server ?? "");
|
|
41840
|
+
const descWords = words(tool.description ?? "");
|
|
41841
|
+
let score = 0;
|
|
41842
|
+
for (const w2 of q2) {
|
|
41843
|
+
if (nameWords.includes(w2)) score += 3;
|
|
41844
|
+
else if (nameWords.some((n2) => n2.startsWith(w2) || w2.startsWith(n2))) score += 2;
|
|
41845
|
+
if (serverWords.includes(w2)) score += 2;
|
|
41846
|
+
if (descWords.includes(w2)) score += 1;
|
|
41847
|
+
else if (descWords.some((d2) => d2.startsWith(w2))) score += 0.5;
|
|
41848
|
+
}
|
|
41849
|
+
return { tool, score, i: i2 };
|
|
41850
|
+
});
|
|
41851
|
+
return scored.filter((s2) => s2.score > 0 || opts.server).sort((a2, b2) => b2.score - a2.score || a2.i - b2.i).slice(0, limit2).map((s2) => s2.tool);
|
|
41852
|
+
}
|
|
41853
|
+
function serverIndex(deferred) {
|
|
41854
|
+
const counts = /* @__PURE__ */ new Map();
|
|
41855
|
+
for (const t2 of deferred) counts.set(serverOf(t2), (counts.get(serverOf(t2)) ?? 0) + 1);
|
|
41856
|
+
const lines = [...counts].map(([s2, n2]) => `- ${s2} \xB7 ${n2} tool${n2 === 1 ? "" : "s"}`);
|
|
41857
|
+
return [
|
|
41858
|
+
`Connected services. Their tools are not loaded until you find them: call \`${TOOL_SEARCH_NAME}\` with what you want to do (and optionally the server) before concluding something is unavailable. Tools it returns can be called directly from then on.`,
|
|
41859
|
+
...lines
|
|
41860
|
+
].join("\n");
|
|
41861
|
+
}
|
|
41862
|
+
function createToolLoader(opts) {
|
|
41863
|
+
const cap = opts.cap ?? LOADED_TOOLS_CAP;
|
|
41864
|
+
const byName = new Map(opts.deferred.map((t2) => [t2.name, t2]));
|
|
41865
|
+
const incoming = opts.loaded ?? [];
|
|
41866
|
+
let order = incoming.filter((n2, i2) => byName.has(n2) && incoming.indexOf(n2) === i2).slice(-cap);
|
|
41867
|
+
if (order.length !== incoming.length) opts.onChange?.([...order]);
|
|
41868
|
+
const add = (names) => {
|
|
41869
|
+
const before = new Set(order);
|
|
41870
|
+
for (const n2 of names) {
|
|
41871
|
+
order = order.filter((x2) => x2 !== n2);
|
|
41872
|
+
order.push(n2);
|
|
41873
|
+
}
|
|
41874
|
+
if (order.length > cap) order = order.slice(order.length - cap);
|
|
41875
|
+
const changed = order.length !== before.size || order.some((n2) => !before.has(n2));
|
|
41876
|
+
if (changed) opts.onChange?.([...order]);
|
|
41877
|
+
};
|
|
41878
|
+
const searchTool = {
|
|
41879
|
+
name: TOOL_SEARCH_NAME,
|
|
41880
|
+
namespace: "agent",
|
|
41881
|
+
description: "Find tools on connected services (MCP servers) by what you want to do. Returns matching tools with their input schemas and makes them callable from your next step. Search before concluding a service cannot do something.",
|
|
41882
|
+
parameters: {
|
|
41883
|
+
type: "object",
|
|
41884
|
+
properties: {
|
|
41885
|
+
query: { type: "string", description: 'What you want to do, in plain words, e.g. "send an email" or "list calendar events".' },
|
|
41886
|
+
server: { type: "string", description: "Only search this server (a name from the connected services list)." },
|
|
41887
|
+
limit: { type: "number", description: `Most results to return (default ${DEFAULT_LIMIT}, max ${MAX_LIMIT}).` }
|
|
41888
|
+
},
|
|
41889
|
+
required: ["query"]
|
|
41890
|
+
},
|
|
41891
|
+
mutates: false,
|
|
41892
|
+
// The schemas ARE the answer; offloading them behind a pointer would hide
|
|
41893
|
+
// exactly what the model searched for.
|
|
41894
|
+
noOffload: true,
|
|
41895
|
+
async run(args) {
|
|
41896
|
+
const query = typeof args.query === "string" ? args.query.trim() : "";
|
|
41897
|
+
const server = typeof args.server === "string" && args.server ? args.server : void 0;
|
|
41898
|
+
if (!query && !server) return "Error: pass a query describing what you want to do.";
|
|
41899
|
+
const limit2 = typeof args.limit === "number" ? args.limit : void 0;
|
|
41900
|
+
const found = rankTools(query, opts.deferred, { server, limit: limit2 });
|
|
41901
|
+
add(found.map((t2) => t2.name));
|
|
41902
|
+
const servers = [...new Set(opts.deferred.map(serverOf))];
|
|
41903
|
+
return JSON.stringify({
|
|
41904
|
+
tools: found.map((t2) => ({ name: t2.name, server: serverOf(t2), description: t2.description, inputSchema: t2.parameters })),
|
|
41905
|
+
note: found.length ? "These tools are now loaded; call them directly." : `No tools matched. Connected servers: ${servers.join(", ") || "(none)"}. Try other words or name a server.`
|
|
41906
|
+
});
|
|
41907
|
+
}
|
|
41908
|
+
};
|
|
41909
|
+
return {
|
|
41910
|
+
searchTool,
|
|
41911
|
+
loaded: () => order.map((n2) => byName.get(n2)).filter((t2) => !!t2),
|
|
41912
|
+
loadedNames: () => [...order],
|
|
41913
|
+
touch: (name) => {
|
|
41914
|
+
if (!order.includes(name)) return;
|
|
41915
|
+
order = [...order.filter((n2) => n2 !== name), name];
|
|
41916
|
+
}
|
|
41917
|
+
};
|
|
41918
|
+
}
|
|
41919
|
+
|
|
41817
41920
|
// ../harness/core/loop.ts
|
|
41921
|
+
var MAX_PROVIDER_TOOLS = 128;
|
|
41818
41922
|
async function runAgent(args) {
|
|
41819
41923
|
const { client, system, tools, toolCtx } = args;
|
|
41820
41924
|
const policy = args.policy ?? STANDARD_POLICY;
|
|
@@ -41840,17 +41944,28 @@ async function runAgent(args) {
|
|
|
41840
41944
|
turnAc?.abort();
|
|
41841
41945
|
});
|
|
41842
41946
|
const messages = [...args.messages];
|
|
41843
|
-
const
|
|
41947
|
+
const deferred = args.deferredTools ?? [];
|
|
41948
|
+
const loader = deferred.length ? createToolLoader({ deferred, loaded: args.loadedTools, onChange: (names) => emit({ type: "tools-loaded", names }) }) : null;
|
|
41949
|
+
const eager = loader ? [...tools, loader.searchTool] : tools;
|
|
41950
|
+
const capped = (list) => list.length > MAX_PROVIDER_TOOLS ? list.slice(0, MAX_PROVIDER_TOOLS) : list;
|
|
41951
|
+
const activeTools = () => capped(loader ? [...eager, ...loader.loaded()] : eager);
|
|
41952
|
+
let sent = activeTools();
|
|
41953
|
+
const indexedSystem = loader ? system ? `${system}
|
|
41954
|
+
|
|
41955
|
+
${serverIndex(deferred)}` : serverIndex(deferred) : system;
|
|
41956
|
+
const filledSystem = indexedSystem ? fillToolsMarker(indexedSystem, sent) : indexedSystem;
|
|
41844
41957
|
if (filledSystem && !messages.some((m2) => m2.role === "system")) {
|
|
41845
41958
|
messages.unshift({ role: "system", content: filledSystem });
|
|
41846
41959
|
}
|
|
41847
|
-
const
|
|
41960
|
+
const defsFor = (list) => list.map((t2) => ({
|
|
41848
41961
|
type: "function",
|
|
41849
41962
|
function: { name: t2.name, description: t2.description, parameters: t2.parameters }
|
|
41850
41963
|
}));
|
|
41851
|
-
|
|
41964
|
+
let toolDefs = defsFor(sent);
|
|
41965
|
+
let toolByName = new Map(sent.map((t2) => [t2.name, t2]));
|
|
41852
41966
|
if (compressionStrategy === "deferred" && compression && compression.mode !== "off" && toolCtx.recall) {
|
|
41853
|
-
|
|
41967
|
+
const known = new Map([...eager, ...deferred].map((t2) => [t2.name, t2]));
|
|
41968
|
+
await compactIncomingOffloads(messages, known, compression, toolCtx.recall, emit);
|
|
41854
41969
|
}
|
|
41855
41970
|
const usage = { promptTokens: 0, completionTokens: 0 };
|
|
41856
41971
|
let text = "";
|
|
@@ -41879,6 +41994,11 @@ async function runAgent(args) {
|
|
|
41879
41994
|
break;
|
|
41880
41995
|
}
|
|
41881
41996
|
}
|
|
41997
|
+
if (loader) {
|
|
41998
|
+
sent = activeTools();
|
|
41999
|
+
toolDefs = defsFor(sent);
|
|
42000
|
+
toolByName = new Map(sent.map((t2) => [t2.name, t2]));
|
|
42001
|
+
}
|
|
41882
42002
|
let streamed;
|
|
41883
42003
|
let streamFail = null;
|
|
41884
42004
|
const model = args.getModel?.() ?? args.model;
|
|
@@ -42005,6 +42125,7 @@ async function runAgent(args) {
|
|
|
42005
42125
|
emit({ type: "tool-result", id: call.id, name: call.name, result: "unknown tool", isError: true });
|
|
42006
42126
|
continue;
|
|
42007
42127
|
}
|
|
42128
|
+
loader?.touch(tool.name);
|
|
42008
42129
|
const address = toolAddress(tool);
|
|
42009
42130
|
const gate = evaluateToolCall(policy, gstate, { name: call.name, exists: true, address });
|
|
42010
42131
|
if (!gate.ok) {
|
|
@@ -46193,7 +46314,7 @@ var FLAG_TO_KEY = {
|
|
|
46193
46314
|
"--default-model": "defaultModel",
|
|
46194
46315
|
"--name": "name"
|
|
46195
46316
|
};
|
|
46196
|
-
var DEFAULT_GUEST_IMAGE2 = "prompd/corenel-sandbox:0.8.
|
|
46317
|
+
var DEFAULT_GUEST_IMAGE2 = "prompd/corenel-sandbox:0.8.3";
|
|
46197
46318
|
function parseArgsWithProvenance(argv) {
|
|
46198
46319
|
const explicit = /* @__PURE__ */ new Set();
|
|
46199
46320
|
for (const a2 of argv) {
|
|
@@ -46884,7 +47005,7 @@ async function readMcpCredential(stateDir, server) {
|
|
|
46884
47005
|
function isUsableClient(v2) {
|
|
46885
47006
|
if (typeof v2 !== "object" || v2 === null) return false;
|
|
46886
47007
|
const r2 = v2;
|
|
46887
|
-
return typeof r2.clientId === "string" && r2.clientId.length > 0 && typeof r2.authServer === "string" && r2.authServer.length > 0 && (r2.clientSecret === void 0 || typeof r2.clientSecret === "string");
|
|
47008
|
+
return typeof r2.clientId === "string" && r2.clientId.length > 0 && typeof r2.authServer === "string" && r2.authServer.length > 0 && (r2.clientSecret === void 0 || typeof r2.clientSecret === "string") && (r2.redirectPort === void 0 || typeof r2.redirectPort === "number" && Number.isInteger(r2.redirectPort) && r2.redirectPort > 0 && r2.redirectPort < 65536);
|
|
46888
47009
|
}
|
|
46889
47010
|
async function readMcpClient(stateDir, server) {
|
|
46890
47011
|
const doc = await readAuthJson(stateDir);
|
|
@@ -46965,6 +47086,15 @@ function firstAuthServer(doc) {
|
|
|
46965
47086
|
const first = list[0];
|
|
46966
47087
|
return typeof first === "string" && first.length > 0 ? first : null;
|
|
46967
47088
|
}
|
|
47089
|
+
function scopesFrom(doc) {
|
|
47090
|
+
const list = doc.scopes_supported;
|
|
47091
|
+
if (!Array.isArray(list) || list.length === 0) return void 0;
|
|
47092
|
+
return list.every((s2) => typeof s2 === "string") ? list : void 0;
|
|
47093
|
+
}
|
|
47094
|
+
function resourceResult(doc, authServer, mcpUrl) {
|
|
47095
|
+
const scopes = scopesFrom(doc);
|
|
47096
|
+
return { authServer, resource: resourceFor(doc, mcpUrl), ...scopes ? { scopes } : {} };
|
|
47097
|
+
}
|
|
46968
47098
|
function resourceMetadataUrlFromHeader(headerValue) {
|
|
46969
47099
|
if (!headerValue) return null;
|
|
46970
47100
|
const match = /resource_metadata="([^"]+)"/.exec(headerValue);
|
|
@@ -46978,9 +47108,22 @@ async function discoverAuthServer(mcpUrl, fetchImpl = fetch) {
|
|
|
46978
47108
|
const wellKnownUrl = new URL(PROTECTED_RESOURCE_PATH, origin).toString();
|
|
46979
47109
|
const direct = await tryFetchJson(wellKnownUrl, fetchImpl);
|
|
46980
47110
|
if (direct) {
|
|
46981
|
-
const
|
|
46982
|
-
if (
|
|
47111
|
+
const authServer = firstAuthServer(direct);
|
|
47112
|
+
if (authServer) return resourceResult(direct, authServer, mcpUrl);
|
|
46983
47113
|
}
|
|
47114
|
+
const viaHint = await hintedResource(mcpUrl, fetchImpl);
|
|
47115
|
+
if (viaHint) {
|
|
47116
|
+
const authServer = firstAuthServer(viaHint);
|
|
47117
|
+
if (authServer) return resourceResult(viaHint, authServer, mcpUrl);
|
|
47118
|
+
}
|
|
47119
|
+
const own = await tryFetchJson(authServerMetadataUrl(origin), fetchImpl);
|
|
47120
|
+
if (own && typeof own.authorization_endpoint === "string" && own.authorization_endpoint.length > 0) {
|
|
47121
|
+
const issuer = typeof own.issuer === "string" && own.issuer.length > 0 ? own.issuer : origin;
|
|
47122
|
+
return resourceResult(own, issuer, mcpUrl);
|
|
47123
|
+
}
|
|
47124
|
+
return null;
|
|
47125
|
+
}
|
|
47126
|
+
async function hintedResource(mcpUrl, fetchImpl) {
|
|
46984
47127
|
let probe;
|
|
46985
47128
|
try {
|
|
46986
47129
|
probe = await fetchImpl(mcpUrl);
|
|
@@ -46990,10 +47133,7 @@ async function discoverAuthServer(mcpUrl, fetchImpl = fetch) {
|
|
|
46990
47133
|
if (probe.status !== 401) return null;
|
|
46991
47134
|
const hinted = resourceMetadataUrlFromHeader(probe.headers.get("www-authenticate"));
|
|
46992
47135
|
if (!hinted) return null;
|
|
46993
|
-
|
|
46994
|
-
if (!viaHint) return null;
|
|
46995
|
-
const authServer = firstAuthServer(viaHint);
|
|
46996
|
-
return authServer ? { authServer, resource: resourceFor(viaHint, mcpUrl) } : null;
|
|
47136
|
+
return tryFetchJson(hinted, fetchImpl);
|
|
46997
47137
|
}
|
|
46998
47138
|
function authServerMetadataUrl(authServer) {
|
|
46999
47139
|
const u2 = new URL(authServer);
|
|
@@ -47252,13 +47392,14 @@ async function loginToMcpServer(stateDir, server, deps = {}) {
|
|
|
47252
47392
|
message: `"${server.name}" does not advertise an OAuth authorization server. If it takes a static token instead, store that as a header.`
|
|
47253
47393
|
};
|
|
47254
47394
|
}
|
|
47255
|
-
const
|
|
47395
|
+
const asMeta = await discoverAuthMetadata(
|
|
47256
47396
|
discovered.authServer,
|
|
47257
47397
|
fetchImpl
|
|
47258
47398
|
);
|
|
47259
|
-
const
|
|
47260
|
-
const redirectUri = `http://localhost:${port}/callback`;
|
|
47399
|
+
const meta = discovered.scopes ? { ...asMeta, scopesSupported: discovered.scopes } : asMeta;
|
|
47261
47400
|
const cached = await readMcpClient(stateDir, server.name);
|
|
47401
|
+
const port = cached?.redirectPort ?? await getFreePort();
|
|
47402
|
+
const redirectUri = `http://localhost:${port}/callback`;
|
|
47262
47403
|
const registered2 = cached && cached.authServer === discovered.authServer ? { clientId: cached.clientId, ...cached.clientSecret ? { clientSecret: cached.clientSecret } : {} } : await registerClient(
|
|
47263
47404
|
meta,
|
|
47264
47405
|
redirectUri,
|
|
@@ -47276,7 +47417,7 @@ async function loginToMcpServer(stateDir, server, deps = {}) {
|
|
|
47276
47417
|
ok: false,
|
|
47277
47418
|
reason: "no-dcr",
|
|
47278
47419
|
authServer: discovered.authServer,
|
|
47279
|
-
message: `"${server.name}"'s authorization server (${discovered.authServer})
|
|
47420
|
+
message: `"${server.name}"'s authorization server (${discovered.authServer}) supports OAuth but not dynamic client registration, so no client can be created on demand. Store a static token as a header instead -- a server in this position normally issues one from its own settings.`
|
|
47280
47421
|
};
|
|
47281
47422
|
}
|
|
47282
47423
|
const pkce = makePkce();
|
|
@@ -47321,7 +47462,7 @@ async function loginToMcpServer(stateDir, server, deps = {}) {
|
|
|
47321
47462
|
}
|
|
47322
47463
|
|
|
47323
47464
|
// src/config/mcpCmd.ts
|
|
47324
|
-
var USAGE2 = "Use: corenel mcp add <name> <url> [--hosted] | remove <name> | list | set-header <name> <header> <value> | login <name> | refresh <name>";
|
|
47465
|
+
var USAGE2 = "Use: corenel mcp add <name> <url> [--hosted] | remove <name> | list | set-header <name> <header> <value> | set-client <name> <client-id> [<client-secret>] --auth-server <url> [--redirect-port <port>] | login <name> | refresh <name>";
|
|
47325
47466
|
function isHttpUrl(url) {
|
|
47326
47467
|
try {
|
|
47327
47468
|
const parsed = new URL(url);
|
|
@@ -47334,7 +47475,7 @@ async function runMcp(raw, io, deps = {}) {
|
|
|
47334
47475
|
const argv = stripStateDir(raw);
|
|
47335
47476
|
const sub = argv[0];
|
|
47336
47477
|
const { corrupt } = await readDaemonConfig(io.stateDir);
|
|
47337
|
-
const isWrite = sub === "add" || sub === "remove" || sub === "set-header" || sub === "login";
|
|
47478
|
+
const isWrite = sub === "add" || sub === "remove" || sub === "set-header" || sub === "set-client" || sub === "login";
|
|
47338
47479
|
if (corrupt && isWrite) {
|
|
47339
47480
|
io.err(`daemon.json in ${io.stateDir} is not valid JSON; fix or delete it before writing.`);
|
|
47340
47481
|
return 2;
|
|
@@ -47389,6 +47530,51 @@ async function runMcp(raw, io, deps = {}) {
|
|
|
47389
47530
|
if (corrupt) io.err(`daemon.json in ${io.stateDir} is not valid JSON; these are the defaults, not what the file says.`);
|
|
47390
47531
|
return 0;
|
|
47391
47532
|
}
|
|
47533
|
+
if (sub === "set-client") {
|
|
47534
|
+
const flagAt = argv.indexOf("--auth-server");
|
|
47535
|
+
const authServer = flagAt === -1 ? void 0 : argv[flagAt + 1];
|
|
47536
|
+
const portAt = argv.indexOf("--redirect-port");
|
|
47537
|
+
const portRaw = portAt === -1 ? void 0 : argv[portAt + 1];
|
|
47538
|
+
const consumed = /* @__PURE__ */ new Set([0, flagAt, flagAt + 1, portAt, portAt + 1]);
|
|
47539
|
+
const positional = argv.filter((a2, i2) => !consumed.has(i2));
|
|
47540
|
+
const name = positional[0];
|
|
47541
|
+
const clientId = positional[1];
|
|
47542
|
+
const clientSecret = positional[2];
|
|
47543
|
+
if (!name || !clientId) {
|
|
47544
|
+
io.err(`corenel mcp set-client needs a name and a client id. ${USAGE2}`);
|
|
47545
|
+
return 2;
|
|
47546
|
+
}
|
|
47547
|
+
if (!authServer || !isHttpUrl(authServer)) {
|
|
47548
|
+
io.err(`corenel mcp set-client needs --auth-server <url> -- the authorization server the client was registered with, copied from the service's own app settings. ${USAGE2}`);
|
|
47549
|
+
return 2;
|
|
47550
|
+
}
|
|
47551
|
+
let redirectPort;
|
|
47552
|
+
if (portRaw !== void 0) {
|
|
47553
|
+
const parsed = Number(portRaw);
|
|
47554
|
+
if (!Number.isInteger(parsed) || parsed <= 0 || parsed >= 65536) {
|
|
47555
|
+
io.err(`"${portRaw}" is not a usable port for --redirect-port. ${USAGE2}`);
|
|
47556
|
+
return 2;
|
|
47557
|
+
}
|
|
47558
|
+
redirectPort = parsed;
|
|
47559
|
+
}
|
|
47560
|
+
const servers = await readMcpServers(io.stateDir);
|
|
47561
|
+
if (!servers.some((s2) => s2.name === name)) {
|
|
47562
|
+
io.err(`"${name}" is not a configured MCP server. Add it first: corenel mcp add ${name} <url>`);
|
|
47563
|
+
return 2;
|
|
47564
|
+
}
|
|
47565
|
+
await writeMcpClient(io.stateDir, name, {
|
|
47566
|
+
clientId,
|
|
47567
|
+
...clientSecret ? { clientSecret } : {},
|
|
47568
|
+
authServer,
|
|
47569
|
+
...redirectPort ? { redirectPort } : {}
|
|
47570
|
+
});
|
|
47571
|
+
io.out(`Stored an OAuth client for "${name}" (client id ${clientId}${clientSecret ? ", with a secret" : ""}).`);
|
|
47572
|
+
if (redirectPort !== void 0) {
|
|
47573
|
+
io.out(`Register this redirect URL with the service: http://localhost:${redirectPort}/callback`);
|
|
47574
|
+
}
|
|
47575
|
+
io.out(`Run: corenel mcp login ${name}`);
|
|
47576
|
+
return 0;
|
|
47577
|
+
}
|
|
47392
47578
|
if (sub === "set-header") {
|
|
47393
47579
|
const name = argv[1];
|
|
47394
47580
|
const header = argv[2];
|
|
@@ -47442,7 +47628,7 @@ async function runMcp(raw, io, deps = {}) {
|
|
|
47442
47628
|
return 2;
|
|
47443
47629
|
}
|
|
47444
47630
|
if (outcome.reason === "no-dcr") {
|
|
47445
|
-
io.err(`"${name}"'s authorization server (${outcome.authServer})
|
|
47631
|
+
io.err(`"${name}"'s authorization server (${outcome.authServer}) supports OAuth but not dynamic client registration, so no client can be created on demand. Use: corenel mcp set-header ${name} <header> <value> with a token from the service's own settings.`);
|
|
47446
47632
|
return 2;
|
|
47447
47633
|
}
|
|
47448
47634
|
io.err(`Sign-in for "${name}" failed: ${outcome.message}`);
|
|
@@ -48849,7 +49035,8 @@ var McpHttpClient = class {
|
|
|
48849
49035
|
* loop -- a credential that fails twice is refused, not flaky. */
|
|
48850
49036
|
async send(method, params, isRetry = false) {
|
|
48851
49037
|
const headers = await this.buildHeaders();
|
|
48852
|
-
const
|
|
49038
|
+
const id = this.nextRequestId++;
|
|
49039
|
+
const res = await this.request(headers, id, method, params);
|
|
48853
49040
|
if (res.status === 401) {
|
|
48854
49041
|
if (!isRetry && await this.auth.onUnauthorized()) {
|
|
48855
49042
|
return this.send(method, params, true);
|
|
@@ -48860,26 +49047,77 @@ var McpHttpClient = class {
|
|
|
48860
49047
|
}
|
|
48861
49048
|
const sessionId = res.headers.get(SESSION_HEADER);
|
|
48862
49049
|
if (sessionId) this.sessionId = sessionId;
|
|
49050
|
+
if (!res.ok) {
|
|
49051
|
+
throw new Error(`MCP server "${this.server.name}" returned HTTP ${res.status}`);
|
|
49052
|
+
}
|
|
48863
49053
|
const contentType = res.headers.get("content-type") ?? "";
|
|
49054
|
+
let body2;
|
|
48864
49055
|
if (contentType.includes("text/event-stream")) {
|
|
48865
|
-
|
|
48866
|
-
|
|
48867
|
-
);
|
|
48868
|
-
}
|
|
48869
|
-
if (!contentType.includes("application/json")) {
|
|
49056
|
+
body2 = await this.readSseResponse(res, id);
|
|
49057
|
+
} else if (contentType.includes("application/json")) {
|
|
49058
|
+
body2 = await res.json();
|
|
49059
|
+
} else {
|
|
48870
49060
|
throw new Error(
|
|
48871
49061
|
`MCP server "${this.server.name}" answered with an unexpected content-type: "${contentType || "(none)"}"`
|
|
48872
49062
|
);
|
|
48873
49063
|
}
|
|
48874
|
-
if (!res.ok) {
|
|
48875
|
-
throw new Error(`MCP server "${this.server.name}" returned HTTP ${res.status}`);
|
|
48876
|
-
}
|
|
48877
|
-
const body2 = await res.json();
|
|
48878
49064
|
if (body2.error) {
|
|
48879
49065
|
throw new Error(`MCP server "${this.server.name}" returned error ${body2.error.code}: ${body2.error.message}`);
|
|
48880
49066
|
}
|
|
48881
49067
|
return body2.result;
|
|
48882
49068
|
}
|
|
49069
|
+
/** Read an SSE body until the JSON-RPC response for `id` arrives.
|
|
49070
|
+
*
|
|
49071
|
+
* Events are separated by a blank line; an event's `data:` lines are joined
|
|
49072
|
+
* with newlines, per the SSE spec, and parsed as one JSON-RPC message.
|
|
49073
|
+
* Notifications (no `id`) and responses to other ids are skipped. The reader
|
|
49074
|
+
* is cancelled once the answer is in, so a server that keeps the stream open
|
|
49075
|
+
* after replying cannot hold this call open with it. */
|
|
49076
|
+
async readSseResponse(res, id) {
|
|
49077
|
+
if (!res.body) {
|
|
49078
|
+
throw new Error(`MCP server "${this.server.name}" closed the stream without a response`);
|
|
49079
|
+
}
|
|
49080
|
+
const reader = res.body.getReader();
|
|
49081
|
+
const decoder = new TextDecoder();
|
|
49082
|
+
let buffer = "";
|
|
49083
|
+
try {
|
|
49084
|
+
for (; ; ) {
|
|
49085
|
+
const { done, value } = await reader.read();
|
|
49086
|
+
if (value) buffer += decoder.decode(value, { stream: true });
|
|
49087
|
+
buffer = buffer.replace(/\r\n/g, "\n");
|
|
49088
|
+
let boundary = buffer.indexOf("\n\n");
|
|
49089
|
+
while (boundary !== -1) {
|
|
49090
|
+
const event = buffer.slice(0, boundary);
|
|
49091
|
+
buffer = buffer.slice(boundary + 2);
|
|
49092
|
+
const match = this.matchSseEvent(event, id);
|
|
49093
|
+
if (match) return match;
|
|
49094
|
+
boundary = buffer.indexOf("\n\n");
|
|
49095
|
+
}
|
|
49096
|
+
if (done) {
|
|
49097
|
+
const tail3 = buffer.trim() ? this.matchSseEvent(buffer, id) : null;
|
|
49098
|
+
if (tail3) return tail3;
|
|
49099
|
+
throw new Error(`MCP server "${this.server.name}" closed the stream without a response`);
|
|
49100
|
+
}
|
|
49101
|
+
}
|
|
49102
|
+
} finally {
|
|
49103
|
+
reader.cancel().catch(() => {
|
|
49104
|
+
});
|
|
49105
|
+
}
|
|
49106
|
+
}
|
|
49107
|
+
/** The JSON-RPC response in one SSE event, if it answers `id`; else null. */
|
|
49108
|
+
matchSseEvent(event, id) {
|
|
49109
|
+
const data = event.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).replace(/^ /, "")).join("\n");
|
|
49110
|
+
if (!data) return null;
|
|
49111
|
+
let parsed;
|
|
49112
|
+
try {
|
|
49113
|
+
parsed = JSON.parse(data);
|
|
49114
|
+
} catch {
|
|
49115
|
+
return null;
|
|
49116
|
+
}
|
|
49117
|
+
if (!isRecord3(parsed) || parsed.id !== id) return null;
|
|
49118
|
+
if (!("result" in parsed) && !("error" in parsed)) return null;
|
|
49119
|
+
return parsed;
|
|
49120
|
+
}
|
|
48883
49121
|
/** The bare `fetch()` call, wrapped -- every OTHER throw in `send` already
|
|
48884
49122
|
* names the server; this is the one call whose own failures (DNS miss,
|
|
48885
49123
|
* connection refused, TLS failure) never reach `send`'s response-handling
|
|
@@ -48889,12 +49127,12 @@ var McpHttpClient = class {
|
|
|
48889
49127
|
* whose entire job is diagnosis. `err.cause` carries the real reason
|
|
48890
49128
|
* (ECONNREFUSED, ENOTFOUND, a TLS alert); undici puts it there rather than
|
|
48891
49129
|
* in `err.message`. */
|
|
48892
|
-
async request(headers, method, params) {
|
|
49130
|
+
async request(headers, id, method, params) {
|
|
48893
49131
|
try {
|
|
48894
49132
|
return await this.fetchImpl(this.server.url, {
|
|
48895
49133
|
method: "POST",
|
|
48896
49134
|
headers,
|
|
48897
|
-
body: JSON.stringify({ jsonrpc: "2.0", id
|
|
49135
|
+
body: JSON.stringify({ jsonrpc: "2.0", id, method, params })
|
|
48898
49136
|
});
|
|
48899
49137
|
} catch (err) {
|
|
48900
49138
|
const cause = err instanceof Error && err.cause instanceof Error ? err.cause.message : err instanceof Error ? err.message : String(err);
|
|
@@ -48955,6 +49193,25 @@ function authProviderFor(stateDir, server, fetchImpl = fetch, accountToken = asy
|
|
|
48955
49193
|
|
|
48956
49194
|
// src/mcp/registry.ts
|
|
48957
49195
|
init_store();
|
|
49196
|
+
|
|
49197
|
+
// src/mcp/timedFetch.ts
|
|
49198
|
+
var AUTH_REQUEST_TIMEOUT_MS = 15e3;
|
|
49199
|
+
function timedFetch(ms, inner = fetch) {
|
|
49200
|
+
return async (input, init2 = {}) => {
|
|
49201
|
+
const deadline = AbortSignal.timeout(ms);
|
|
49202
|
+
const signal = init2.signal ? AbortSignal.any([init2.signal, deadline]) : deadline;
|
|
49203
|
+
try {
|
|
49204
|
+
return await inner(input, { ...init2, signal });
|
|
49205
|
+
} catch (err) {
|
|
49206
|
+
if (deadline.aborted && !init2.signal?.aborted) {
|
|
49207
|
+
throw new Error(`no answer within ${ms / 1e3}s`, { cause: err });
|
|
49208
|
+
}
|
|
49209
|
+
throw err;
|
|
49210
|
+
}
|
|
49211
|
+
};
|
|
49212
|
+
}
|
|
49213
|
+
|
|
49214
|
+
// src/mcp/registry.ts
|
|
48958
49215
|
async function accountTokenFor(stateDir) {
|
|
48959
49216
|
try {
|
|
48960
49217
|
const cred = await resolveCredential(process.env, stateDir);
|
|
@@ -48964,8 +49221,12 @@ async function accountTokenFor(stateDir) {
|
|
|
48964
49221
|
}
|
|
48965
49222
|
}
|
|
48966
49223
|
function defaultClientFactory(stateDir, server) {
|
|
48967
|
-
return new McpHttpClient(
|
|
49224
|
+
return new McpHttpClient(
|
|
49225
|
+
server,
|
|
49226
|
+
authProviderFor(stateDir, server, timedFetch(AUTH_REQUEST_TIMEOUT_MS), () => accountTokenFor(stateDir))
|
|
49227
|
+
);
|
|
48968
49228
|
}
|
|
49229
|
+
var SERVER_CONNECT_TIMEOUT_MS = 3e4;
|
|
48969
49230
|
var McpRegistry = class {
|
|
48970
49231
|
constructor(stateDir, clientFactory = defaultClientFactory) {
|
|
48971
49232
|
this.stateDir = stateDir;
|
|
@@ -48989,27 +49250,60 @@ var McpRegistry = class {
|
|
|
48989
49250
|
* a server that fails to initialize, or fails listing tools, is recorded
|
|
48990
49251
|
* in `status()` with zero tools and the daemon keeps starting.
|
|
48991
49252
|
*/
|
|
48992
|
-
async connectAll() {
|
|
49253
|
+
async connectAll(opts = {}) {
|
|
48993
49254
|
this.connected.clear();
|
|
48994
49255
|
this.statuses.clear();
|
|
48995
49256
|
const servers = await readMcpServers(this.stateDir);
|
|
48996
49257
|
this.serverOrder = servers.map((s2) => s2.name);
|
|
48997
|
-
|
|
49258
|
+
const timeoutMs = opts.timeoutMs ?? SERVER_CONNECT_TIMEOUT_MS;
|
|
49259
|
+
await Promise.all(servers.map((server) => this.connectOne(server, timeoutMs, opts.onServer)));
|
|
48998
49260
|
}
|
|
48999
|
-
|
|
49000
|
-
|
|
49261
|
+
/* BOUNDED, AND SETTLED EXACTLY ONCE.
|
|
49262
|
+
*
|
|
49263
|
+
* Every server connects under one Promise.all, and daemon startup awaits it.
|
|
49264
|
+
* With no bound, one stalled server -- measured: an expired Microsoft 365
|
|
49265
|
+
* token refreshing against a cold service, still waiting at 60 seconds --
|
|
49266
|
+
* left the terminal silent after `mirrors sessions`, indistinguishable from a
|
|
49267
|
+
* crash.
|
|
49268
|
+
*
|
|
49269
|
+
* The deadline covers the whole connect (any credential refresh, initialize,
|
|
49270
|
+
* tools/list), not each request, because several individually bounded steps
|
|
49271
|
+
* in a row can still add up to a hang. The attempt that loses the race keeps
|
|
49272
|
+
* running; its late result is deliberately ignored, so a server reported as
|
|
49273
|
+
* timed out cannot quietly become connected afterwards -- status would then
|
|
49274
|
+
* tell doctor one thing and the registered tools another. */
|
|
49275
|
+
async connectOne(server, timeoutMs, onServer) {
|
|
49276
|
+
let timer;
|
|
49277
|
+
const deadline = new Promise((resolve13) => {
|
|
49278
|
+
timer = setTimeout(() => resolve13("timeout"), timeoutMs);
|
|
49279
|
+
});
|
|
49280
|
+
const attempt = (async () => {
|
|
49001
49281
|
const client = this.clientFactory(this.stateDir, server);
|
|
49002
49282
|
await client.initialize();
|
|
49003
49283
|
const tools = await client.listTools();
|
|
49004
|
-
|
|
49005
|
-
|
|
49284
|
+
return { client, tools };
|
|
49285
|
+
})();
|
|
49286
|
+
attempt.catch(() => {
|
|
49287
|
+
});
|
|
49288
|
+
try {
|
|
49289
|
+
const outcome = await Promise.race([attempt, deadline]);
|
|
49290
|
+
if (outcome === "timeout") {
|
|
49291
|
+
this.statuses.set(server.name, { connected: false, toolCount: 0, error: `timed out after ${timeoutMs / 1e3}s` });
|
|
49292
|
+
} else {
|
|
49293
|
+
this.connected.set(server.name, outcome);
|
|
49294
|
+
this.statuses.set(server.name, { connected: true, toolCount: outcome.tools.length });
|
|
49295
|
+
}
|
|
49006
49296
|
} catch (err) {
|
|
49007
49297
|
this.statuses.set(server.name, {
|
|
49008
49298
|
connected: false,
|
|
49009
49299
|
toolCount: 0,
|
|
49010
49300
|
error: err instanceof Error ? err.message : String(err)
|
|
49011
49301
|
});
|
|
49302
|
+
} finally {
|
|
49303
|
+
clearTimeout(timer);
|
|
49012
49304
|
}
|
|
49305
|
+
const settled = this.statuses.get(server.name);
|
|
49306
|
+
if (settled) onServer?.({ server: server.name, ...settled });
|
|
49013
49307
|
}
|
|
49014
49308
|
/** Every tool from every connected server, paired with the server it came
|
|
49015
49309
|
* from, in CONFIGURED order (`serverOrder`) -- not the order servers
|
|
@@ -49045,7 +49339,12 @@ var McpRegistry = class {
|
|
|
49045
49339
|
* that records a failure without a reason, because "no tools" alone tells
|
|
49046
49340
|
* the reader nothing about what to fix. */
|
|
49047
49341
|
status() {
|
|
49048
|
-
|
|
49342
|
+
const out = [];
|
|
49343
|
+
for (const server of this.serverOrder) {
|
|
49344
|
+
const s2 = this.statuses.get(server);
|
|
49345
|
+
if (s2) out.push({ server, ...s2 });
|
|
49346
|
+
}
|
|
49347
|
+
return out;
|
|
49049
49348
|
}
|
|
49050
49349
|
};
|
|
49051
49350
|
|
|
@@ -49690,11 +49989,11 @@ async function main() {
|
|
|
49690
49989
|
const procs = args.allowShell ? createNodeProcs({ roots: args.roots, log: slog }) : void 0;
|
|
49691
49990
|
const mcpPolicy = buildMcpPolicy(fileConfig);
|
|
49692
49991
|
const mcpRegistry = new McpRegistry(args.stateDir);
|
|
49693
|
-
|
|
49992
|
+
slog("mcp: connecting configured servers\u2026");
|
|
49993
|
+
await mcpRegistry.connectAll({
|
|
49994
|
+
onServer: (s2) => slog(s2.connected ? `mcp: "${s2.server}" connected -- ${s2.toolCount} tool(s)` : `mcp: "${s2.server}" not connected -- ${s2.error} (run: corenel mcp doctor)`)
|
|
49995
|
+
});
|
|
49694
49996
|
const unregisterMcpTools = registerMcpTools(mcpRegistry, mcpPolicy);
|
|
49695
|
-
for (const s2 of mcpRegistry.status()) {
|
|
49696
|
-
slog(s2.connected ? `mcp: "${s2.server}" connected -- ${s2.toolCount} tool(s)` : `mcp: "${s2.server}" not connected -- ${s2.error} (run: corenel mcp doctor)`);
|
|
49697
|
-
}
|
|
49698
49997
|
const mcpPort = buildMcpPort(mcpRegistry, mcpPolicy);
|
|
49699
49998
|
const mcpAdminPort = buildMcpAdmin(args.stateDir);
|
|
49700
49999
|
const sessions = runner ? await wireSessions({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@corenel/sidecar",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Elastic-2.0",
|
|
6
6
|
"description": "Prompd sidecar — a local capability server. Run it next to Prompd (prompd.app) so the browser app can reach your machine: local LLMs (Ollama/LM Studio/vLLM) without CORS, your filesystem, and (opt-in) shell.",
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
"esbuild": "^0.21.5",
|
|
37
37
|
"tsx": "^4.19.2",
|
|
38
38
|
"typescript": "^5.9.3",
|
|
39
|
-
"@corenel/protocol": "0.7.
|
|
40
|
-
"@corenel/
|
|
41
|
-
"@corenel/
|
|
39
|
+
"@corenel/protocol": "0.7.1",
|
|
40
|
+
"@corenel/harness": "0.7.1",
|
|
41
|
+
"@corenel/tools-node": "0.3.3",
|
|
42
42
|
"@corenel/crew": "0.0.0"
|
|
43
43
|
},
|
|
44
44
|
"repository": {
|