@corenel/sidecar 0.8.1 → 0.8.2
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 +80 -15
- package/package.json +4 -4
package/dist/cli.js
CHANGED
|
@@ -46193,7 +46193,7 @@ var FLAG_TO_KEY = {
|
|
|
46193
46193
|
"--default-model": "defaultModel",
|
|
46194
46194
|
"--name": "name"
|
|
46195
46195
|
};
|
|
46196
|
-
var DEFAULT_GUEST_IMAGE2 = "prompd/corenel-sandbox:0.8.
|
|
46196
|
+
var DEFAULT_GUEST_IMAGE2 = "prompd/corenel-sandbox:0.8.2";
|
|
46197
46197
|
function parseArgsWithProvenance(argv) {
|
|
46198
46198
|
const explicit = /* @__PURE__ */ new Set();
|
|
46199
46199
|
for (const a2 of argv) {
|
|
@@ -46884,7 +46884,7 @@ async function readMcpCredential(stateDir, server) {
|
|
|
46884
46884
|
function isUsableClient(v2) {
|
|
46885
46885
|
if (typeof v2 !== "object" || v2 === null) return false;
|
|
46886
46886
|
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");
|
|
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") && (r2.redirectPort === void 0 || typeof r2.redirectPort === "number" && Number.isInteger(r2.redirectPort) && r2.redirectPort > 0 && r2.redirectPort < 65536);
|
|
46888
46888
|
}
|
|
46889
46889
|
async function readMcpClient(stateDir, server) {
|
|
46890
46890
|
const doc = await readAuthJson(stateDir);
|
|
@@ -46965,6 +46965,15 @@ function firstAuthServer(doc) {
|
|
|
46965
46965
|
const first = list[0];
|
|
46966
46966
|
return typeof first === "string" && first.length > 0 ? first : null;
|
|
46967
46967
|
}
|
|
46968
|
+
function scopesFrom(doc) {
|
|
46969
|
+
const list = doc.scopes_supported;
|
|
46970
|
+
if (!Array.isArray(list) || list.length === 0) return void 0;
|
|
46971
|
+
return list.every((s2) => typeof s2 === "string") ? list : void 0;
|
|
46972
|
+
}
|
|
46973
|
+
function resourceResult(doc, authServer, mcpUrl) {
|
|
46974
|
+
const scopes = scopesFrom(doc);
|
|
46975
|
+
return { authServer, resource: resourceFor(doc, mcpUrl), ...scopes ? { scopes } : {} };
|
|
46976
|
+
}
|
|
46968
46977
|
function resourceMetadataUrlFromHeader(headerValue) {
|
|
46969
46978
|
if (!headerValue) return null;
|
|
46970
46979
|
const match = /resource_metadata="([^"]+)"/.exec(headerValue);
|
|
@@ -46978,9 +46987,22 @@ async function discoverAuthServer(mcpUrl, fetchImpl = fetch) {
|
|
|
46978
46987
|
const wellKnownUrl = new URL(PROTECTED_RESOURCE_PATH, origin).toString();
|
|
46979
46988
|
const direct = await tryFetchJson(wellKnownUrl, fetchImpl);
|
|
46980
46989
|
if (direct) {
|
|
46981
|
-
const
|
|
46982
|
-
if (
|
|
46990
|
+
const authServer = firstAuthServer(direct);
|
|
46991
|
+
if (authServer) return resourceResult(direct, authServer, mcpUrl);
|
|
46992
|
+
}
|
|
46993
|
+
const viaHint = await hintedResource(mcpUrl, fetchImpl);
|
|
46994
|
+
if (viaHint) {
|
|
46995
|
+
const authServer = firstAuthServer(viaHint);
|
|
46996
|
+
if (authServer) return resourceResult(viaHint, authServer, mcpUrl);
|
|
46983
46997
|
}
|
|
46998
|
+
const own = await tryFetchJson(authServerMetadataUrl(origin), fetchImpl);
|
|
46999
|
+
if (own && typeof own.authorization_endpoint === "string" && own.authorization_endpoint.length > 0) {
|
|
47000
|
+
const issuer = typeof own.issuer === "string" && own.issuer.length > 0 ? own.issuer : origin;
|
|
47001
|
+
return resourceResult(own, issuer, mcpUrl);
|
|
47002
|
+
}
|
|
47003
|
+
return null;
|
|
47004
|
+
}
|
|
47005
|
+
async function hintedResource(mcpUrl, fetchImpl) {
|
|
46984
47006
|
let probe;
|
|
46985
47007
|
try {
|
|
46986
47008
|
probe = await fetchImpl(mcpUrl);
|
|
@@ -46990,10 +47012,7 @@ async function discoverAuthServer(mcpUrl, fetchImpl = fetch) {
|
|
|
46990
47012
|
if (probe.status !== 401) return null;
|
|
46991
47013
|
const hinted = resourceMetadataUrlFromHeader(probe.headers.get("www-authenticate"));
|
|
46992
47014
|
if (!hinted) return null;
|
|
46993
|
-
|
|
46994
|
-
if (!viaHint) return null;
|
|
46995
|
-
const authServer = firstAuthServer(viaHint);
|
|
46996
|
-
return authServer ? { authServer, resource: resourceFor(viaHint, mcpUrl) } : null;
|
|
47015
|
+
return tryFetchJson(hinted, fetchImpl);
|
|
46997
47016
|
}
|
|
46998
47017
|
function authServerMetadataUrl(authServer) {
|
|
46999
47018
|
const u2 = new URL(authServer);
|
|
@@ -47252,13 +47271,14 @@ async function loginToMcpServer(stateDir, server, deps = {}) {
|
|
|
47252
47271
|
message: `"${server.name}" does not advertise an OAuth authorization server. If it takes a static token instead, store that as a header.`
|
|
47253
47272
|
};
|
|
47254
47273
|
}
|
|
47255
|
-
const
|
|
47274
|
+
const asMeta = await discoverAuthMetadata(
|
|
47256
47275
|
discovered.authServer,
|
|
47257
47276
|
fetchImpl
|
|
47258
47277
|
);
|
|
47259
|
-
const
|
|
47260
|
-
const redirectUri = `http://localhost:${port}/callback`;
|
|
47278
|
+
const meta = discovered.scopes ? { ...asMeta, scopesSupported: discovered.scopes } : asMeta;
|
|
47261
47279
|
const cached = await readMcpClient(stateDir, server.name);
|
|
47280
|
+
const port = cached?.redirectPort ?? await getFreePort();
|
|
47281
|
+
const redirectUri = `http://localhost:${port}/callback`;
|
|
47262
47282
|
const registered2 = cached && cached.authServer === discovered.authServer ? { clientId: cached.clientId, ...cached.clientSecret ? { clientSecret: cached.clientSecret } : {} } : await registerClient(
|
|
47263
47283
|
meta,
|
|
47264
47284
|
redirectUri,
|
|
@@ -47276,7 +47296,7 @@ async function loginToMcpServer(stateDir, server, deps = {}) {
|
|
|
47276
47296
|
ok: false,
|
|
47277
47297
|
reason: "no-dcr",
|
|
47278
47298
|
authServer: discovered.authServer,
|
|
47279
|
-
message: `"${server.name}"'s authorization server (${discovered.authServer})
|
|
47299
|
+
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
47300
|
};
|
|
47281
47301
|
}
|
|
47282
47302
|
const pkce = makePkce();
|
|
@@ -47321,7 +47341,7 @@ async function loginToMcpServer(stateDir, server, deps = {}) {
|
|
|
47321
47341
|
}
|
|
47322
47342
|
|
|
47323
47343
|
// 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>";
|
|
47344
|
+
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
47345
|
function isHttpUrl(url) {
|
|
47326
47346
|
try {
|
|
47327
47347
|
const parsed = new URL(url);
|
|
@@ -47334,7 +47354,7 @@ async function runMcp(raw, io, deps = {}) {
|
|
|
47334
47354
|
const argv = stripStateDir(raw);
|
|
47335
47355
|
const sub = argv[0];
|
|
47336
47356
|
const { corrupt } = await readDaemonConfig(io.stateDir);
|
|
47337
|
-
const isWrite = sub === "add" || sub === "remove" || sub === "set-header" || sub === "login";
|
|
47357
|
+
const isWrite = sub === "add" || sub === "remove" || sub === "set-header" || sub === "set-client" || sub === "login";
|
|
47338
47358
|
if (corrupt && isWrite) {
|
|
47339
47359
|
io.err(`daemon.json in ${io.stateDir} is not valid JSON; fix or delete it before writing.`);
|
|
47340
47360
|
return 2;
|
|
@@ -47389,6 +47409,51 @@ async function runMcp(raw, io, deps = {}) {
|
|
|
47389
47409
|
if (corrupt) io.err(`daemon.json in ${io.stateDir} is not valid JSON; these are the defaults, not what the file says.`);
|
|
47390
47410
|
return 0;
|
|
47391
47411
|
}
|
|
47412
|
+
if (sub === "set-client") {
|
|
47413
|
+
const flagAt = argv.indexOf("--auth-server");
|
|
47414
|
+
const authServer = flagAt === -1 ? void 0 : argv[flagAt + 1];
|
|
47415
|
+
const portAt = argv.indexOf("--redirect-port");
|
|
47416
|
+
const portRaw = portAt === -1 ? void 0 : argv[portAt + 1];
|
|
47417
|
+
const consumed = /* @__PURE__ */ new Set([0, flagAt, flagAt + 1, portAt, portAt + 1]);
|
|
47418
|
+
const positional = argv.filter((a2, i2) => !consumed.has(i2));
|
|
47419
|
+
const name = positional[0];
|
|
47420
|
+
const clientId = positional[1];
|
|
47421
|
+
const clientSecret = positional[2];
|
|
47422
|
+
if (!name || !clientId) {
|
|
47423
|
+
io.err(`corenel mcp set-client needs a name and a client id. ${USAGE2}`);
|
|
47424
|
+
return 2;
|
|
47425
|
+
}
|
|
47426
|
+
if (!authServer || !isHttpUrl(authServer)) {
|
|
47427
|
+
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}`);
|
|
47428
|
+
return 2;
|
|
47429
|
+
}
|
|
47430
|
+
let redirectPort;
|
|
47431
|
+
if (portRaw !== void 0) {
|
|
47432
|
+
const parsed = Number(portRaw);
|
|
47433
|
+
if (!Number.isInteger(parsed) || parsed <= 0 || parsed >= 65536) {
|
|
47434
|
+
io.err(`"${portRaw}" is not a usable port for --redirect-port. ${USAGE2}`);
|
|
47435
|
+
return 2;
|
|
47436
|
+
}
|
|
47437
|
+
redirectPort = parsed;
|
|
47438
|
+
}
|
|
47439
|
+
const servers = await readMcpServers(io.stateDir);
|
|
47440
|
+
if (!servers.some((s2) => s2.name === name)) {
|
|
47441
|
+
io.err(`"${name}" is not a configured MCP server. Add it first: corenel mcp add ${name} <url>`);
|
|
47442
|
+
return 2;
|
|
47443
|
+
}
|
|
47444
|
+
await writeMcpClient(io.stateDir, name, {
|
|
47445
|
+
clientId,
|
|
47446
|
+
...clientSecret ? { clientSecret } : {},
|
|
47447
|
+
authServer,
|
|
47448
|
+
...redirectPort ? { redirectPort } : {}
|
|
47449
|
+
});
|
|
47450
|
+
io.out(`Stored an OAuth client for "${name}" (client id ${clientId}${clientSecret ? ", with a secret" : ""}).`);
|
|
47451
|
+
if (redirectPort !== void 0) {
|
|
47452
|
+
io.out(`Register this redirect URL with the service: http://localhost:${redirectPort}/callback`);
|
|
47453
|
+
}
|
|
47454
|
+
io.out(`Run: corenel mcp login ${name}`);
|
|
47455
|
+
return 0;
|
|
47456
|
+
}
|
|
47392
47457
|
if (sub === "set-header") {
|
|
47393
47458
|
const name = argv[1];
|
|
47394
47459
|
const header = argv[2];
|
|
@@ -47442,7 +47507,7 @@ async function runMcp(raw, io, deps = {}) {
|
|
|
47442
47507
|
return 2;
|
|
47443
47508
|
}
|
|
47444
47509
|
if (outcome.reason === "no-dcr") {
|
|
47445
|
-
io.err(`"${name}"'s authorization server (${outcome.authServer})
|
|
47510
|
+
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
47511
|
return 2;
|
|
47447
47512
|
}
|
|
47448
47513
|
io.err(`Sign-in for "${name}" failed: ${outcome.message}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@corenel/sidecar",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
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,10 +36,10 @@
|
|
|
36
36
|
"esbuild": "^0.21.5",
|
|
37
37
|
"tsx": "^4.19.2",
|
|
38
38
|
"typescript": "^5.9.3",
|
|
39
|
-
"@corenel/protocol": "0.7.0",
|
|
40
|
-
"@corenel/tools-node": "0.3.2",
|
|
41
39
|
"@corenel/harness": "0.7.0",
|
|
42
|
-
"@corenel/
|
|
40
|
+
"@corenel/protocol": "0.7.0",
|
|
41
|
+
"@corenel/crew": "0.0.0",
|
|
42
|
+
"@corenel/tools-node": "0.3.2"
|
|
43
43
|
},
|
|
44
44
|
"repository": {
|
|
45
45
|
"type": "git",
|