@corenel/cli 0.7.0 → 0.8.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 (2) hide show
  1. package/dist/main.js +269 -59
  2. package/package.json +7 -7
package/dist/main.js CHANGED
@@ -390,6 +390,19 @@ var init_fileService = __esm({
390
390
  await this.assertReal(a);
391
391
  await writeFileAtomic(a, bytes, { shownPath: path });
392
392
  }
393
+ /** O_APPEND, NOT atomic-rename: the point is that another process appending
394
+ * to the same file at the same moment lands too, and a rename would replace
395
+ * whatever it wrote. Same confinement as write. */
396
+ async append(path, content) {
397
+ const a = await this.writeTarget(path);
398
+ await fs2.mkdir(dirname2(a), { recursive: true });
399
+ await this.assertReal(a);
400
+ try {
401
+ await fs2.appendFile(a, content, "utf8");
402
+ } catch (e) {
403
+ throw diskFullError(path, e) ?? e;
404
+ }
405
+ }
393
406
  async create(path, content = "") {
394
407
  const a = await this.writeTarget(path);
395
408
  await fs2.mkdir(dirname2(a), { recursive: true });
@@ -7878,7 +7891,7 @@ var require_public_api = __commonJS({
7878
7891
  }
7879
7892
  return doc;
7880
7893
  }
7881
- function parse2(src, reviver, options) {
7894
+ function parse3(src, reviver, options) {
7882
7895
  let _reviver = void 0;
7883
7896
  if (typeof reviver === "function") {
7884
7897
  _reviver = reviver;
@@ -7919,7 +7932,7 @@ var require_public_api = __commonJS({
7919
7932
  return value.toString(options);
7920
7933
  return new Document.Document(value, _replacer, options).toString(options);
7921
7934
  }
7922
- exports.parse = parse2;
7935
+ exports.parse = parse3;
7923
7936
  exports.parseAllDocuments = parseAllDocuments;
7924
7937
  exports.parseDocument = parseDocument;
7925
7938
  exports.stringify = stringify2;
@@ -8445,7 +8458,7 @@ var require_parse = __commonJS({
8445
8458
  "../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/parse.js"(exports, module) {
8446
8459
  "use strict";
8447
8460
  var SemVer = require_semver();
8448
- var parse2 = (version2, options, throwErrors = false) => {
8461
+ var parse3 = (version2, options, throwErrors = false) => {
8449
8462
  if (version2 instanceof SemVer) {
8450
8463
  return version2;
8451
8464
  }
@@ -8458,7 +8471,7 @@ var require_parse = __commonJS({
8458
8471
  throw er;
8459
8472
  }
8460
8473
  };
8461
- module.exports = parse2;
8474
+ module.exports = parse3;
8462
8475
  }
8463
8476
  });
8464
8477
 
@@ -8466,9 +8479,9 @@ var require_parse = __commonJS({
8466
8479
  var require_valid = __commonJS({
8467
8480
  "../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/valid.js"(exports, module) {
8468
8481
  "use strict";
8469
- var parse2 = require_parse();
8482
+ var parse3 = require_parse();
8470
8483
  var valid = (version2, options) => {
8471
- const v = parse2(version2, options);
8484
+ const v = parse3(version2, options);
8472
8485
  return v ? v.version : null;
8473
8486
  };
8474
8487
  module.exports = valid;
@@ -8479,9 +8492,9 @@ var require_valid = __commonJS({
8479
8492
  var require_clean = __commonJS({
8480
8493
  "../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/clean.js"(exports, module) {
8481
8494
  "use strict";
8482
- var parse2 = require_parse();
8495
+ var parse3 = require_parse();
8483
8496
  var clean = (version2, options) => {
8484
- const s = parse2(version2.trim().replace(/^[=v]+/, ""), options);
8497
+ const s = parse3(version2.trim().replace(/^[=v]+/, ""), options);
8485
8498
  return s ? s.version : null;
8486
8499
  };
8487
8500
  module.exports = clean;
@@ -8516,10 +8529,10 @@ var require_inc = __commonJS({
8516
8529
  var require_diff = __commonJS({
8517
8530
  "../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/diff.js"(exports, module) {
8518
8531
  "use strict";
8519
- var parse2 = require_parse();
8532
+ var parse3 = require_parse();
8520
8533
  var diff = (version1, version2) => {
8521
- const v1 = parse2(version1, null, true);
8522
- const v2 = parse2(version2, null, true);
8534
+ const v1 = parse3(version1, null, true);
8535
+ const v2 = parse3(version2, null, true);
8523
8536
  const comparison = v1.compare(v2);
8524
8537
  if (comparison === 0) {
8525
8538
  return null;
@@ -8590,9 +8603,9 @@ var require_patch = __commonJS({
8590
8603
  var require_prerelease = __commonJS({
8591
8604
  "../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/prerelease.js"(exports, module) {
8592
8605
  "use strict";
8593
- var parse2 = require_parse();
8606
+ var parse3 = require_parse();
8594
8607
  var prerelease = (version2, options) => {
8595
- const parsed = parse2(version2, options);
8608
+ const parsed = parse3(version2, options);
8596
8609
  return parsed && parsed.prerelease.length ? parsed.prerelease : null;
8597
8610
  };
8598
8611
  module.exports = prerelease;
@@ -8778,7 +8791,7 @@ var require_coerce = __commonJS({
8778
8791
  "../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/coerce.js"(exports, module) {
8779
8792
  "use strict";
8780
8793
  var SemVer = require_semver();
8781
- var parse2 = require_parse();
8794
+ var parse3 = require_parse();
8782
8795
  var { safeRe: re, t } = require_re();
8783
8796
  var coerce = (version2, options) => {
8784
8797
  if (version2 instanceof SemVer) {
@@ -8813,7 +8826,7 @@ var require_coerce = __commonJS({
8813
8826
  const patch = match[4] || "0";
8814
8827
  const prerelease = options.includePrerelease && match[5] ? `-${match[5]}` : "";
8815
8828
  const build = options.includePrerelease && match[6] ? `+${match[6]}` : "";
8816
- return parse2(`${major}.${minor}.${patch}${prerelease}${build}`, options);
8829
+ return parse3(`${major}.${minor}.${patch}${prerelease}${build}`, options);
8817
8830
  };
8818
8831
  module.exports = coerce;
8819
8832
  }
@@ -8823,7 +8836,7 @@ var require_coerce = __commonJS({
8823
8836
  var require_truncate = __commonJS({
8824
8837
  "../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/truncate.js"(exports, module) {
8825
8838
  "use strict";
8826
- var parse2 = require_parse();
8839
+ var parse3 = require_parse();
8827
8840
  var constants2 = require_constants();
8828
8841
  var SemVer = require_semver();
8829
8842
  var truncate2 = (version2, truncation, options) => {
@@ -8835,7 +8848,7 @@ var require_truncate = __commonJS({
8835
8848
  };
8836
8849
  var cloneInputVersion = (version2, options) => {
8837
8850
  const versionStringToParse = version2 instanceof SemVer ? version2.version : version2;
8838
- return parse2(versionStringToParse, options);
8851
+ return parse3(versionStringToParse, options);
8839
8852
  };
8840
8853
  var doTruncation = (version2, truncation) => {
8841
8854
  if (isPrerelease(truncation)) {
@@ -9877,7 +9890,7 @@ var require_semver2 = __commonJS({
9877
9890
  var constants2 = require_constants();
9878
9891
  var SemVer = require_semver();
9879
9892
  var identifiers = require_identifiers();
9880
- var parse2 = require_parse();
9893
+ var parse3 = require_parse();
9881
9894
  var valid = require_valid();
9882
9895
  var clean = require_clean();
9883
9896
  var inc = require_inc();
@@ -9916,7 +9929,7 @@ var require_semver2 = __commonJS({
9916
9929
  var simplifyRange = require_simplify();
9917
9930
  var subset = require_subset();
9918
9931
  module.exports = {
9919
- parse: parse2,
9932
+ parse: parse3,
9920
9933
  valid,
9921
9934
  clean,
9922
9935
  inc,
@@ -12303,7 +12316,7 @@ var require_parser2 = __commonJS({
12303
12316
  }
12304
12317
  return buf;
12305
12318
  };
12306
- _proto.parse = function parse2() {
12319
+ _proto.parse = function parse3() {
12307
12320
  return new nodes.NodeList(0, 0, this.parseNodes());
12308
12321
  };
12309
12322
  _proto.parseAsRoot = function parseAsRoot() {
@@ -12312,7 +12325,7 @@ var require_parser2 = __commonJS({
12312
12325
  return Parser2;
12313
12326
  }(Obj);
12314
12327
  module.exports = {
12315
- parse: function parse2(src, extensions, opts) {
12328
+ parse: function parse3(src, extensions, opts) {
12316
12329
  var p = new Parser(lexer.lex(src, opts));
12317
12330
  if (extensions !== void 0) {
12318
12331
  p.extensions = extensions;
@@ -13894,7 +13907,7 @@ var require_filters = __commonJS({
13894
13907
  return r.copySafeness(str, res);
13895
13908
  }
13896
13909
  _exports.indent = indent;
13897
- function join13(arr, del, attr) {
13910
+ function join14(arr, del, attr) {
13898
13911
  del = del || "";
13899
13912
  if (attr) {
13900
13913
  arr = lib.map(arr, function(v) {
@@ -13903,7 +13916,7 @@ var require_filters = __commonJS({
13903
13916
  }
13904
13917
  return arr.join(del);
13905
13918
  }
13906
- _exports.join = join13;
13919
+ _exports.join = join14;
13907
13920
  function last(arr) {
13908
13921
  return arr[arr.length - 1];
13909
13922
  }
@@ -21103,7 +21116,7 @@ var require_extension = __commonJS({
21103
21116
  if (dest[name] === void 0) dest[name] = [elem];
21104
21117
  else dest[name].push(elem);
21105
21118
  }
21106
- function parse2(header) {
21119
+ function parse3(header) {
21107
21120
  const offers = /* @__PURE__ */ Object.create(null);
21108
21121
  let params = /* @__PURE__ */ Object.create(null);
21109
21122
  let mustUnescape = false;
@@ -21243,7 +21256,7 @@ var require_extension = __commonJS({
21243
21256
  }).join(", ");
21244
21257
  }).join(", ");
21245
21258
  }
21246
- module.exports = { format, parse: parse2 };
21259
+ module.exports = { format, parse: parse3 };
21247
21260
  }
21248
21261
  });
21249
21262
 
@@ -21277,7 +21290,7 @@ var require_websocket = __commonJS({
21277
21290
  var {
21278
21291
  EventTarget: { addEventListener, removeEventListener }
21279
21292
  } = require_event_target();
21280
- var { format, parse: parse2 } = require_extension();
21293
+ var { format, parse: parse3 } = require_extension();
21281
21294
  var { toBuffer } = require_buffer_util();
21282
21295
  var kAborted = Symbol("kAborted");
21283
21296
  var protocolVersions = [8, 13];
@@ -21954,7 +21967,7 @@ var require_websocket = __commonJS({
21954
21967
  }
21955
21968
  let extensions;
21956
21969
  try {
21957
- extensions = parse2(secWebSocketExtensions);
21970
+ extensions = parse3(secWebSocketExtensions);
21958
21971
  } catch (err) {
21959
21972
  const message = "Invalid Sec-WebSocket-Extensions header";
21960
21973
  abortHandshake(websocket, socket, message);
@@ -22246,7 +22259,7 @@ var require_subprotocol = __commonJS({
22246
22259
  "../../node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/subprotocol.js"(exports, module) {
22247
22260
  "use strict";
22248
22261
  var { tokenChars } = require_validation();
22249
- function parse2(header) {
22262
+ function parse3(header) {
22250
22263
  const protocols = /* @__PURE__ */ new Set();
22251
22264
  let start = -1;
22252
22265
  let end = -1;
@@ -22282,7 +22295,7 @@ var require_subprotocol = __commonJS({
22282
22295
  protocols.add(protocol);
22283
22296
  return protocols;
22284
22297
  }
22285
- module.exports = { parse: parse2 };
22298
+ module.exports = { parse: parse3 };
22286
22299
  }
22287
22300
  });
22288
22301
 
@@ -24865,7 +24878,7 @@ async function deviceLogin(opts) {
24865
24878
  );
24866
24879
  }
24867
24880
  };
24868
- const dc = await post("/oauth/device/code", { client_id: "corenel-cli", scope: "agent" });
24881
+ const dc = await post("/oauth/device/code", { client_id: "corenel-cli", scope: "agent pair" });
24869
24882
  if (!dc.device_code) throw new Error("device authorization failed");
24870
24883
  (opts.open ?? defaultOpen)(dc.verification_uri, dc.user_code);
24871
24884
  let interval = opts.pollMs ?? Math.max(MIN_POLL_MS, (dc.interval ?? 5) * 1e3);
@@ -24913,8 +24926,8 @@ var InvalidApiBaseError = class extends Error {
24913
24926
  this.name = "InvalidApiBaseError";
24914
24927
  }
24915
24928
  };
24916
- function isLoopback(hostname) {
24917
- const h = hostname.replace(/^\[|\]$/g, "").toLowerCase();
24929
+ function isLoopback(hostname2) {
24930
+ const h = hostname2.replace(/^\[|\]$/g, "").toLowerCase();
24918
24931
  return h === "localhost" || h === "127.0.0.1" || h === "::1" || h.endsWith(".localhost");
24919
24932
  }
24920
24933
  var warnedCleartext = false;
@@ -25417,6 +25430,7 @@ var KNOWN_KEYS = [
25417
25430
  "addUnder",
25418
25431
  "cloneUnder",
25419
25432
  "allowLan",
25433
+ "behindTlsProxy",
25420
25434
  "allowOrigins",
25421
25435
  "tlsCert",
25422
25436
  "tlsKey",
@@ -25438,7 +25452,7 @@ var KNOWN_KEYS = [
25438
25452
  "mcpServers",
25439
25453
  "mcpAllow",
25440
25454
  "identityIssuer",
25441
- "identity",
25455
+ "org",
25442
25456
  "push",
25443
25457
  "audit",
25444
25458
  "sendTelemetry",
@@ -26323,7 +26337,7 @@ import { procTools } from "@corenel/harness/tools/procs";
26323
26337
 
26324
26338
  // src/sidecarConnect.ts
26325
26339
  import { stateDirName as stateDirName5 } from "@corenel/protocol";
26326
- import { SidecarHost } from "@corenel/harness/sidecar/host";
26340
+ import { SidecarHost, isSidecarKeyMismatch, isSidecarAccountRefusal } from "@corenel/harness/sidecar/host";
26327
26341
 
26328
26342
  // ../../node_modules/.pnpm/ws@8.21.0/node_modules/ws/wrapper.mjs
26329
26343
  var import_stream = __toESM(require_stream(), 1);
@@ -26486,12 +26500,209 @@ function hostBackedProcs(host, seed = []) {
26486
26500
  };
26487
26501
  }
26488
26502
 
26503
+ // src/sidecarDevice.ts
26504
+ init_tools_node();
26505
+ import { join as join10 } from "node:path";
26506
+ import { asEcPublicJwk, generatePrivateJwk, signerFromPrivateJwk } from "@corenel/harness/sidecar/deviceKeys";
26507
+ function cliDevicesPath(base) {
26508
+ return join10(corenelDir(base), "cli", "sidecar-devices.json");
26509
+ }
26510
+ var B64 = /^[A-Za-z0-9_-]{1,64}$/;
26511
+ var B43 = /^[A-Za-z0-9_-]{43}$/;
26512
+ function isCliDevice(v) {
26513
+ if (typeof v !== "object" || v === null) return false;
26514
+ const r = v;
26515
+ const k = r.privateJwk;
26516
+ return typeof r.id === "string" && B64.test(r.id) && typeof r.sidecarJkt === "string" && B43.test(r.sidecarJkt) && typeof k === "object" && k !== null && !!asEcPublicJwk({ kty: k.kty, crv: k.crv, x: k.x, y: k.y }) && typeof k.d === "string" && B43.test(k.d);
26517
+ }
26518
+ function parse2(text) {
26519
+ let raw;
26520
+ try {
26521
+ raw = JSON.parse(text);
26522
+ } catch {
26523
+ return null;
26524
+ }
26525
+ const r = raw;
26526
+ if (typeof r !== "object" || r === null || r.version !== 1) return null;
26527
+ if (typeof r.devices !== "object" || r.devices === null || Array.isArray(r.devices)) return null;
26528
+ const devices = /* @__PURE__ */ Object.create(null);
26529
+ for (const [url, d] of Object.entries(r.devices)) {
26530
+ if (!isCliDevice(d)) return null;
26531
+ const k = d.privateJwk;
26532
+ devices[url] = { id: d.id, sidecarJkt: d.sidecarJkt, privateJwk: { kty: k.kty, crv: k.crv, x: k.x, y: k.y, d: k.d } };
26533
+ }
26534
+ return { version: 1, devices };
26535
+ }
26536
+ function cliDeviceStore(path = cliDevicesPath()) {
26537
+ const file = fileTextStore(path);
26538
+ const dir = join10(path, "..");
26539
+ const load = async () => {
26540
+ const text = await file.read();
26541
+ return text === null ? { version: 1, devices: /* @__PURE__ */ Object.create(null) } : parse2(text);
26542
+ };
26543
+ const change = async (edit) => {
26544
+ const f = await load();
26545
+ if (!f) throw new Error(`${path} is not a file this CLI understands. Remove it to pair again.`);
26546
+ edit(f);
26547
+ await ensurePrivateDir(dir);
26548
+ await file.write(`${JSON.stringify(f, null, 2)}
26549
+ `);
26550
+ };
26551
+ return {
26552
+ async get(url) {
26553
+ try {
26554
+ const f = await load();
26555
+ return f && Object.prototype.hasOwnProperty.call(f.devices, url) ? f.devices[url] : void 0;
26556
+ } catch {
26557
+ return void 0;
26558
+ }
26559
+ },
26560
+ set: (url, device) => change((f) => {
26561
+ f.devices[url] = device;
26562
+ }),
26563
+ forget: (url) => change((f) => {
26564
+ delete f.devices[url];
26565
+ })
26566
+ };
26567
+ }
26568
+ async function sidecarCredential(url, env, store) {
26569
+ const kept = await store.get(url);
26570
+ const enroll = env.CORENEL_SIDECAR_CODE || void 0;
26571
+ if (!kept && !enroll) return null;
26572
+ const privateJwk = kept?.privateJwk ?? await generatePrivateJwk();
26573
+ return {
26574
+ ...enroll ? { enroll } : {},
26575
+ ...kept ? { device: { id: kept.id, sidecarJkt: kept.sidecarJkt } } : {},
26576
+ deviceKey: await signerFromPrivateJwk(privateJwk),
26577
+ privateJwk
26578
+ };
26579
+ }
26580
+
26581
+ // src/sidecarIdentity.ts
26582
+ function cliIdentity(o) {
26583
+ const fetchImpl = o.fetchImpl ?? fetch;
26584
+ const timeoutMs = o.timeoutMs ?? 8e3;
26585
+ let last = null;
26586
+ return {
26587
+ problem: () => last,
26588
+ answer: async ({ nonce, sidecarId, jkt, orgId }) => {
26589
+ last = null;
26590
+ let token;
26591
+ try {
26592
+ token = await o.token();
26593
+ } catch {
26594
+ token = null;
26595
+ }
26596
+ if (!token) {
26597
+ last = "this CLI is not signed in, and the sidecar only admits a verified account. Run `corenel login` (or set CORENEL_TOKEN), then try again.";
26598
+ return null;
26599
+ }
26600
+ try {
26601
+ const base = (await o.base()).replace(/\/+$/, "");
26602
+ const res = await fetchImpl(`${base}/v1/pairing-assertions`, {
26603
+ method: "POST",
26604
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
26605
+ body: JSON.stringify({ aud: sidecarId, nonce, jkt, ...orgId ? { org_id: orgId } : {} }),
26606
+ signal: AbortSignal.timeout(timeoutMs)
26607
+ });
26608
+ if (res.status === 403) {
26609
+ let code3;
26610
+ try {
26611
+ code3 = (await res.json())?.code;
26612
+ } catch {
26613
+ code3 = void 0;
26614
+ }
26615
+ if (code3 === "CLI_SCOPE") {
26616
+ last = "this CLI sign-in is not allowed to connect to sidecars. Run `corenel login` again and allow sidecar access when you approve it.";
26617
+ return null;
26618
+ }
26619
+ if (orgId) {
26620
+ last = `your account is not a member of the organization this sidecar admits (${orgId}).`;
26621
+ return null;
26622
+ }
26623
+ }
26624
+ if (res.status === 401) {
26625
+ last = "the API refused this CLI sign-in. Run `corenel login` again, then try again.";
26626
+ return null;
26627
+ }
26628
+ if (!res.ok) {
26629
+ last = `could not get a pairing assertion from ${base} (HTTP ${res.status}).`;
26630
+ return null;
26631
+ }
26632
+ const body = await res.json();
26633
+ const assertion = body?.assertion;
26634
+ if (typeof assertion !== "string" || !assertion) {
26635
+ last = `${base} answered without a pairing assertion.`;
26636
+ return null;
26637
+ }
26638
+ return assertion;
26639
+ } catch (e) {
26640
+ last = `could not reach the API for a pairing assertion (${e instanceof Error ? e.message : String(e)}).`;
26641
+ return null;
26642
+ }
26643
+ }
26644
+ };
26645
+ }
26646
+
26489
26647
  // src/sidecarConnect.ts
26648
+ init_tools_node();
26649
+ import { hostname } from "node:os";
26490
26650
  var CONNECT_TIMEOUT_MS = 3e3;
26491
- async function connectSidecarProcs(env = process.env) {
26651
+ var HANDSHAKE_TIMEOUT_MS = 15e3;
26652
+ function cliDeviceName(host = hostname) {
26653
+ let h = "";
26654
+ try {
26655
+ h = host().trim();
26656
+ } catch {
26657
+ h = "";
26658
+ }
26659
+ return h ? `CLI on ${h}` : "CLI";
26660
+ }
26661
+ function defaultCliIdentity(env) {
26662
+ return cliIdentity({ base: () => apiBase(void 0, { env }), token: () => nodeAuthToken().getToken() });
26663
+ }
26664
+ async function reportHandshakeFailure(e, url, usedDevice, store, identity2, fallback) {
26665
+ const msg = e instanceof Error ? e.message : String(e);
26666
+ if (isSidecarKeyMismatch(e)) {
26667
+ process.stderr.write(`corenel: sidecar connection at ${url} failed to complete: ${msg} -- ${fallback}
26668
+ `);
26669
+ process.stderr.write(mismatchNote(url));
26670
+ return;
26671
+ }
26672
+ if (isSidecarAccountRefusal(e)) {
26673
+ const problem = identity2.problem() ?? "the sidecar verified this account and did not admit it (not its owner, or not a member of its organization, or a device another member paired).";
26674
+ process.stderr.write(`corenel: the sidecar at ${url} did not accept this CLI: ${problem} -- ${fallback}
26675
+ `);
26676
+ return;
26677
+ }
26678
+ process.stderr.write(`corenel: sidecar connection at ${url} failed to complete: ${msg} -- ${fallback}
26679
+ `);
26680
+ if (usedDevice && /denied/.test(msg)) await store.forget(url).catch(() => void 0);
26681
+ }
26682
+ async function credentialOptions(url, env, store) {
26683
+ const cred = await sidecarCredential(url, env, store);
26684
+ if (!cred) return null;
26685
+ const { privateJwk, ...host } = cred;
26686
+ return {
26687
+ ...host,
26688
+ usedDevice: !!cred.device,
26689
+ onDeviceIssued: (device) => {
26690
+ store.set(url, { ...device, privateJwk }).catch((e) => {
26691
+ process.stderr.write(`corenel: paired, but could not keep the device key: ${e instanceof Error ? e.message : String(e)}
26692
+ `);
26693
+ });
26694
+ }
26695
+ };
26696
+ }
26697
+ function mismatchNote(url) {
26698
+ return `corenel: the sidecar at ${url} is not the sidecar this CLI paired with (its key does not match the pinned fingerprint). Check the address. If that sidecar was reinstalled, pair again with a fresh code (CORENEL_SIDECAR_CODE from \`corenel-sidecar pair\`).
26699
+ `;
26700
+ }
26701
+ async function connectSidecarProcs(env = process.env, store = cliDeviceStore(), identity2 = defaultCliIdentity(env)) {
26492
26702
  const url = env.CORENEL_SIDECAR_URL;
26493
- const token = env.CORENEL_SIDECAR_TOKEN;
26494
- if (!url || !token) return null;
26703
+ if (!url) return null;
26704
+ const cred = await credentialOptions(url, env, store);
26705
+ if (!cred) return null;
26495
26706
  const ac = new AbortController();
26496
26707
  const timer = setTimeout(() => ac.abort(), CONNECT_TIMEOUT_MS);
26497
26708
  let channel;
@@ -26506,24 +26717,23 @@ async function connectSidecarProcs(env = process.env) {
26506
26717
  } finally {
26507
26718
  clearTimeout(timer);
26508
26719
  }
26720
+ const { usedDevice, ...credential } = cred;
26509
26721
  const host = new SidecarHost({
26510
26722
  channel,
26511
- token,
26723
+ ...credential,
26512
26724
  stateDir: stateDirName5(),
26513
26725
  clientId: `corenel-cli-${process.pid}`,
26514
- clientName: "corenel-cli",
26726
+ clientName: cliDeviceName(),
26727
+ onIdentityChallenge: identity2.answer,
26515
26728
  providers: {},
26516
26729
  registerTool: () => {
26517
26730
  }
26518
26731
  });
26519
26732
  try {
26520
- await host.connect(CONNECT_TIMEOUT_MS);
26733
+ await host.connect(HANDSHAKE_TIMEOUT_MS);
26521
26734
  } catch (e) {
26522
- process.stderr.write(
26523
- `corenel: sidecar connection at ${url} failed to complete: ${e instanceof Error ? e.message : String(e)} -- continuing without proc_start/proc_stop/proc_list.
26524
- `
26525
- );
26526
26735
  host.disconnect("handshake failed");
26736
+ await reportHandshakeFailure(e, url, usedDevice, store, identity2, "continuing without proc_start/proc_stop/proc_list.");
26527
26737
  return null;
26528
26738
  }
26529
26739
  if (!host.supportsProcs()) {
@@ -26533,10 +26743,11 @@ async function connectSidecarProcs(env = process.env) {
26533
26743
  const seed = await host.procList().catch(() => []);
26534
26744
  return { procs: hostBackedProcs(host, seed), disconnect: () => host.disconnect() };
26535
26745
  }
26536
- async function connectMcpAdmin(env = process.env) {
26746
+ async function connectMcpAdmin(env = process.env, store = cliDeviceStore(), identity2 = defaultCliIdentity(env)) {
26537
26747
  const url = env.CORENEL_SIDECAR_URL;
26538
- const token = env.CORENEL_SIDECAR_TOKEN;
26539
- if (!url || !token) return null;
26748
+ if (!url) return null;
26749
+ const cred = await credentialOptions(url, env, store);
26750
+ if (!cred) return null;
26540
26751
  const ac = new AbortController();
26541
26752
  const timer = setTimeout(() => ac.abort(), CONNECT_TIMEOUT_MS);
26542
26753
  let channel;
@@ -26551,24 +26762,23 @@ async function connectMcpAdmin(env = process.env) {
26551
26762
  } finally {
26552
26763
  clearTimeout(timer);
26553
26764
  }
26765
+ const { usedDevice, ...credential } = cred;
26554
26766
  const host = new SidecarHost({
26555
26767
  channel,
26556
- token,
26768
+ ...credential,
26557
26769
  stateDir: stateDirName5(),
26558
26770
  clientId: `corenel-cli-${process.pid}`,
26559
- clientName: "corenel-cli",
26771
+ clientName: cliDeviceName(),
26772
+ onIdentityChallenge: identity2.answer,
26560
26773
  providers: {},
26561
26774
  registerTool: () => {
26562
26775
  }
26563
26776
  });
26564
26777
  try {
26565
- await host.connect(CONNECT_TIMEOUT_MS);
26778
+ await host.connect(HANDSHAKE_TIMEOUT_MS);
26566
26779
  } catch (e) {
26567
- process.stderr.write(
26568
- `corenel: sidecar connection at ${url} failed to complete: ${e instanceof Error ? e.message : String(e)} -- writing MCP config locally instead.
26569
- `
26570
- );
26571
26780
  host.disconnect("handshake failed");
26781
+ await reportHandshakeFailure(e, url, usedDevice, store, identity2, "writing MCP config locally instead.");
26572
26782
  return null;
26573
26783
  }
26574
26784
  if (!host.supportsMcpAdmin()) {
@@ -26823,7 +27033,7 @@ async function resolveStrategyPrompt(files, id) {
26823
27033
  // src/policyResolve.ts
26824
27034
  import { readFile as readFile2 } from "node:fs/promises";
26825
27035
  import { homedir as homedir3 } from "node:os";
26826
- import { join as join10 } from "node:path";
27036
+ import { join as join11 } from "node:path";
26827
27037
  import { stateDirName as stateDirName6 } from "@corenel/protocol";
26828
27038
  import { BUILTIN_POLICIES, STANDARD_POLICY as STANDARD_POLICY3, policyFromYaml } from "@corenel/harness/guardrail";
26829
27039
  var PolicyResolutionError = class extends Error {
@@ -26883,10 +27093,10 @@ async function resolvePolicy(opts) {
26883
27093
  );
26884
27094
  return { policy, source: { kind: "file", path: flag2 } };
26885
27095
  }
26886
- const projectPath = join10(cwd, stateDirName6(), "policy.yaml");
27096
+ const projectPath = join11(cwd, stateDirName6(), "policy.yaml");
26887
27097
  const project = await loadDiscoveredPolicyFile(projectPath);
26888
27098
  if (project) return { policy: project, source: { kind: "project", path: projectPath } };
26889
- const userPath = join10(homedir3(), stateDirName6(), "policy.yaml");
27099
+ const userPath = join11(homedir3(), stateDirName6(), "policy.yaml");
26890
27100
  const user = await loadDiscoveredPolicyFile(userPath);
26891
27101
  if (user) return { policy: user, source: { kind: "user", path: userPath } };
26892
27102
  return { policy: STANDARD_POLICY3, source: { kind: "default" } };
@@ -27747,9 +27957,9 @@ function gatedAgentTools(registry, policy) {
27747
27957
  // ../mcp/src/cache.ts
27748
27958
  import { createHash as createHash2 } from "node:crypto";
27749
27959
  import { readFile as readFile4, writeFile as writeFile3, mkdir as mkdir3, rename as rename2 } from "node:fs/promises";
27750
- import { dirname as dirname8, join as join11 } from "node:path";
27960
+ import { dirname as dirname8, join as join12 } from "node:path";
27751
27961
  function toolCachePath(stateDir) {
27752
- return join11(stateDir, "mcp-tools.json");
27962
+ return join12(stateDir, "mcp-tools.json");
27753
27963
  }
27754
27964
  function credentialFingerprint(cred) {
27755
27965
  if (!cred) return "none";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@corenel/cli",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "type": "module",
5
5
  "description": "Corenel CLI — runs the harness in node, in-proc, no transport. The headless proof the kernel is host-agnostic. (corenel run/ask/chat/login + start --sidecar to follow.)",
6
6
  "bin": {
@@ -9,11 +9,11 @@
9
9
  "dependencies": {
10
10
  "openai": "^4.77.0",
11
11
  "ws": "^8.18.0",
12
- "@corenel/config": "0.4.0",
13
- "@corenel/harness": "0.11.0",
14
- "@corenel/mcp": "0.3.0",
15
- "@corenel/protocol": "0.10.0",
16
- "@corenel/term": "0.5.0"
12
+ "@corenel/config": "0.6.0",
13
+ "@corenel/mcp": "0.4.0",
14
+ "@corenel/protocol": "0.12.0",
15
+ "@corenel/harness": "0.13.0",
16
+ "@corenel/term": "0.7.0"
17
17
  },
18
18
  "devDependencies": {
19
19
  "esbuild": "^0.21.5",
@@ -22,7 +22,7 @@
22
22
  "tsx": "^4.19.2",
23
23
  "typescript": "^5.9.3",
24
24
  "@corenel/crew": "0.0.0",
25
- "@corenel/tools-node": "0.5.1"
25
+ "@corenel/tools-node": "0.7.0"
26
26
  },
27
27
  "publishConfig": {
28
28
  "access": "public"