@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.
Files changed (2) hide show
  1. package/dist/cli.js +80 -15
  2. 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.1";
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 authServer2 = firstAuthServer(direct);
46982
- if (authServer2) return { authServer: authServer2, resource: resourceFor(direct, mcpUrl) };
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
- const viaHint = await tryFetchJson(hinted, fetchImpl);
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 meta = await discoverAuthMetadata(
47274
+ const asMeta = await discoverAuthMetadata(
47256
47275
  discovered.authServer,
47257
47276
  fetchImpl
47258
47277
  );
47259
- const port = await getFreePort();
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}) does not support dynamic client registration, and there is no configured client id to fall back to. Store a static token as a header instead, if the server offers one.`
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}) does not support dynamic client registration, and corenel mcp login has no configured client id to fall back to. Use: corenel mcp set-header ${name} <header> <value> instead, if the server also offers a static token.`);
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.1",
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/crew": "0.0.0"
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",