@corenel/sidecar 0.4.1 → 0.4.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 +96 -24
- package/package.json +4 -4
package/dist/cli.js
CHANGED
|
@@ -23292,6 +23292,15 @@ async function resolveCredential(env = process.env, stateDir, now2 = Date.now) {
|
|
|
23292
23292
|
}
|
|
23293
23293
|
|
|
23294
23294
|
// src/controlPlane.ts
|
|
23295
|
+
function describeBackend(url, mirrors, cred) {
|
|
23296
|
+
if (!mirrors) return { url, mirrors: false };
|
|
23297
|
+
return {
|
|
23298
|
+
url,
|
|
23299
|
+
mirrors: true,
|
|
23300
|
+
signedIn: !!cred.token,
|
|
23301
|
+
...cred.expired ? { expired: true } : {}
|
|
23302
|
+
};
|
|
23303
|
+
}
|
|
23295
23304
|
function makeControlPlane(deps) {
|
|
23296
23305
|
if (!deps || !deps.baseUrl) return null;
|
|
23297
23306
|
const log = deps.log ?? (() => void 0);
|
|
@@ -28408,10 +28417,65 @@ async function listOwnerRoots(stateDir) {
|
|
|
28408
28417
|
return roots;
|
|
28409
28418
|
}
|
|
28410
28419
|
|
|
28420
|
+
// src/crewDeployment.ts
|
|
28421
|
+
import { readFile } from "node:fs/promises";
|
|
28422
|
+
import { join as join9 } from "node:path";
|
|
28423
|
+
|
|
28424
|
+
// ../crew/deployment.ts
|
|
28425
|
+
var DEPLOYMENT_FILE = "deployment.json";
|
|
28426
|
+
function emptyDeployment() {
|
|
28427
|
+
return { agents: /* @__PURE__ */ Object.create(null) };
|
|
28428
|
+
}
|
|
28429
|
+
function deploymentKey(name, wsId) {
|
|
28430
|
+
return wsId ? `workspaces/${wsId}/crew/${name}` : `crew/${name}`;
|
|
28431
|
+
}
|
|
28432
|
+
function parseDeployment(text) {
|
|
28433
|
+
const out = emptyDeployment();
|
|
28434
|
+
let raw;
|
|
28435
|
+
try {
|
|
28436
|
+
raw = JSON.parse(text);
|
|
28437
|
+
} catch {
|
|
28438
|
+
return out;
|
|
28439
|
+
}
|
|
28440
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return out;
|
|
28441
|
+
const agents = raw.agents;
|
|
28442
|
+
if (!agents || typeof agents !== "object" || Array.isArray(agents)) return out;
|
|
28443
|
+
for (const [key, value] of Object.entries(agents)) {
|
|
28444
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
|
28445
|
+
const root = value.root;
|
|
28446
|
+
if (typeof root === "string" && root) out.agents[key] = { root };
|
|
28447
|
+
}
|
|
28448
|
+
return out;
|
|
28449
|
+
}
|
|
28450
|
+
function deploymentRootFor(d2, key) {
|
|
28451
|
+
if (!Object.prototype.hasOwnProperty.call(d2.agents, key)) return void 0;
|
|
28452
|
+
return d2.agents[key].root;
|
|
28453
|
+
}
|
|
28454
|
+
|
|
28455
|
+
// src/crewDeployment.ts
|
|
28456
|
+
function splitOwner(owner) {
|
|
28457
|
+
if (owner === "") return void 0;
|
|
28458
|
+
const parts = owner.split("/");
|
|
28459
|
+
if (parts.length === 1) return { dirName: parts[0] };
|
|
28460
|
+
if (parts.length === 3 && parts[1] === "ws") return { dirName: parts[0], wsId: parts[2] };
|
|
28461
|
+
return void 0;
|
|
28462
|
+
}
|
|
28463
|
+
async function deployedRoot(stateDir, owner, agent) {
|
|
28464
|
+
const parts = splitOwner(owner);
|
|
28465
|
+
if (!parts) return void 0;
|
|
28466
|
+
let text;
|
|
28467
|
+
try {
|
|
28468
|
+
text = await readFile(join9(hostsDirFor(stateDir, parts.dirName), DEPLOYMENT_FILE), "utf8");
|
|
28469
|
+
} catch {
|
|
28470
|
+
return void 0;
|
|
28471
|
+
}
|
|
28472
|
+
return deploymentRootFor(parseDeployment(text), deploymentKey(agent, parts.wsId));
|
|
28473
|
+
}
|
|
28474
|
+
|
|
28411
28475
|
// src/cert.ts
|
|
28412
28476
|
import { promises as fs8 } from "node:fs";
|
|
28413
28477
|
import { networkInterfaces } from "node:os";
|
|
28414
|
-
import { join as
|
|
28478
|
+
import { join as join10 } from "node:path";
|
|
28415
28479
|
import selfsigned from "selfsigned";
|
|
28416
28480
|
function lanIPv4s() {
|
|
28417
28481
|
const out = [];
|
|
@@ -28422,9 +28486,9 @@ function lanIPv4s() {
|
|
|
28422
28486
|
}
|
|
28423
28487
|
return [...new Set(out)];
|
|
28424
28488
|
}
|
|
28425
|
-
var certPath = () =>
|
|
28426
|
-
var keyPath = () =>
|
|
28427
|
-
var sansPath = () =>
|
|
28489
|
+
var certPath = () => join10(sidecarSubdir(), "sidecar.crt");
|
|
28490
|
+
var keyPath = () => join10(sidecarSubdir(), "sidecar.key");
|
|
28491
|
+
var sansPath = () => join10(sidecarSubdir(), "sidecar.sans.json");
|
|
28428
28492
|
function isIp(s2) {
|
|
28429
28493
|
return /^\d{1,3}(?:\.\d{1,3}){3}$/.test(s2) || s2.includes(":");
|
|
28430
28494
|
}
|
|
@@ -38505,7 +38569,7 @@ var NodeRunnerService = class {
|
|
|
38505
38569
|
fromWorkdir ? `crew agent not found: ${agent} (looked in ${fromWorkdir} and the owner's own crew)` : `crew agent not found: ${agent}`
|
|
38506
38570
|
);
|
|
38507
38571
|
}
|
|
38508
|
-
const workDir = this.opts.workRootFor?.(def) ?? this.opts.roots[0];
|
|
38572
|
+
const workDir = await this.opts.workRootFor?.(def, owner) ?? this.opts.roots[0];
|
|
38509
38573
|
if (!workDir) throw new Error("daemon has no --root workspace to run an agent in");
|
|
38510
38574
|
const workFiles = new NodeFileService(workDir);
|
|
38511
38575
|
const deps = this.opts.deps ?? {
|
|
@@ -38617,7 +38681,7 @@ var NodeRunnerService = class {
|
|
|
38617
38681
|
// src/runner/core.ts
|
|
38618
38682
|
import { watch } from "node:fs";
|
|
38619
38683
|
import { readdir as readdir2, stat } from "node:fs/promises";
|
|
38620
|
-
import { join as
|
|
38684
|
+
import { join as join11, relative as relative5, sep as sep3 } from "node:path";
|
|
38621
38685
|
|
|
38622
38686
|
// src/runner/triggerConfig.ts
|
|
38623
38687
|
function inputFor(trigger, fallback) {
|
|
@@ -39127,9 +39191,9 @@ function startDaemonCore(opts) {
|
|
|
39127
39191
|
for (const entry of entries) {
|
|
39128
39192
|
if (entry.isDirectory()) {
|
|
39129
39193
|
if (isExcludedSegment(entry.name, dotDir)) continue;
|
|
39130
|
-
await walkForChanges(root,
|
|
39194
|
+
await walkForChanges(root, join11(dir, entry.name), since);
|
|
39131
39195
|
} else {
|
|
39132
|
-
const abs =
|
|
39196
|
+
const abs = join11(dir, entry.name);
|
|
39133
39197
|
let mtimeMs;
|
|
39134
39198
|
try {
|
|
39135
39199
|
mtimeMs = (await stat(abs)).mtimeMs;
|
|
@@ -39410,9 +39474,9 @@ function makeRunHub(opts = {}) {
|
|
|
39410
39474
|
import { promises as fs10 } from "node:fs";
|
|
39411
39475
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
39412
39476
|
import { hostname } from "node:os";
|
|
39413
|
-
import { join as
|
|
39477
|
+
import { join as join12 } from "node:path";
|
|
39414
39478
|
function idPath(dir = sidecarSubdir()) {
|
|
39415
|
-
return
|
|
39479
|
+
return join12(dir, "daemon.id");
|
|
39416
39480
|
}
|
|
39417
39481
|
async function loadOrCreateSidecarId(dir = sidecarSubdir()) {
|
|
39418
39482
|
const path = idPath(dir);
|
|
@@ -39441,7 +39505,7 @@ function sidecarName(opts) {
|
|
|
39441
39505
|
// src/hosts.ts
|
|
39442
39506
|
import { promises as fs11 } from "node:fs";
|
|
39443
39507
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
39444
|
-
import { join as
|
|
39508
|
+
import { join as join13, dirname as dirname4 } from "node:path";
|
|
39445
39509
|
var MAX_DIR = 32;
|
|
39446
39510
|
var MAX_FIELD_LEN = 200;
|
|
39447
39511
|
var MAX_HOSTS = 200;
|
|
@@ -39474,8 +39538,8 @@ function sanitizeDirName(raw) {
|
|
|
39474
39538
|
const safe = collapsed || "host";
|
|
39475
39539
|
return RESERVED_WINDOWS_NAMES.has(safe) ? `${safe}-host` : safe;
|
|
39476
39540
|
}
|
|
39477
|
-
function hostsPath(
|
|
39478
|
-
return
|
|
39541
|
+
function hostsPath(stateDir) {
|
|
39542
|
+
return join13(stateDir, "sidecar", "hosts.json");
|
|
39479
39543
|
}
|
|
39480
39544
|
function emptyManifest() {
|
|
39481
39545
|
return /* @__PURE__ */ Object.create(null);
|
|
@@ -39514,10 +39578,11 @@ async function read(dir, fallbackLastSeen) {
|
|
|
39514
39578
|
}
|
|
39515
39579
|
return manifest;
|
|
39516
39580
|
}
|
|
39517
|
-
async function write(
|
|
39581
|
+
async function write(stateDir, manifest) {
|
|
39582
|
+
const dir = dirname4(hostsPath(stateDir));
|
|
39518
39583
|
await fs11.mkdir(dir, { recursive: true });
|
|
39519
|
-
const target = hostsPath(
|
|
39520
|
-
const tmp =
|
|
39584
|
+
const target = hostsPath(stateDir);
|
|
39585
|
+
const tmp = join13(dir, `.hosts.json.tmp-${randomBytes3(8).toString("hex")}`);
|
|
39521
39586
|
try {
|
|
39522
39587
|
await fs11.writeFile(tmp, JSON.stringify(manifest, null, 2));
|
|
39523
39588
|
await fs11.rename(tmp, target);
|
|
@@ -39670,7 +39735,7 @@ function makeHostSync(opts) {
|
|
|
39670
39735
|
}
|
|
39671
39736
|
|
|
39672
39737
|
// src/hostsCli.ts
|
|
39673
|
-
import { resolve as resolve5
|
|
39738
|
+
import { resolve as resolve5 } from "node:path";
|
|
39674
39739
|
import { promises as fs12 } from "node:fs";
|
|
39675
39740
|
async function listHosts(manifest) {
|
|
39676
39741
|
const m2 = await manifest.list();
|
|
@@ -39705,10 +39770,10 @@ async function forgetHost(stateDir, manifest, dirName2) {
|
|
|
39705
39770
|
return { ok: true };
|
|
39706
39771
|
}
|
|
39707
39772
|
async function checkHostsDrift(stateDir, manifest, log) {
|
|
39708
|
-
const
|
|
39773
|
+
const root = hostsRoot(stateDir);
|
|
39709
39774
|
let entries;
|
|
39710
39775
|
try {
|
|
39711
|
-
entries = (await fs12.readdir(
|
|
39776
|
+
entries = (await fs12.readdir(root, { withFileTypes: true })).filter((d2) => d2.isDirectory()).map((d2) => d2.name);
|
|
39712
39777
|
} catch {
|
|
39713
39778
|
return [];
|
|
39714
39779
|
}
|
|
@@ -41992,7 +42057,7 @@ async function main() {
|
|
|
41992
42057
|
}
|
|
41993
42058
|
const sidecarId = await loadOrCreateSidecarId(sidecarSubdir(args.stateDir));
|
|
41994
42059
|
const friendlyName = sidecarName({ name: args.name });
|
|
41995
|
-
const hosts = makeHostsManifest(
|
|
42060
|
+
const hosts = makeHostsManifest(args.stateDir);
|
|
41996
42061
|
if (args.tlsCert && !args.tlsKey || !args.tlsCert && args.tlsKey) {
|
|
41997
42062
|
throw new Error("TLS needs both --tls-cert and --tls-key");
|
|
41998
42063
|
}
|
|
@@ -42020,7 +42085,7 @@ async function main() {
|
|
|
42020
42085
|
};
|
|
42021
42086
|
await assertPortFree(probeAddress(args.host), args.port);
|
|
42022
42087
|
await assertStateDirFree(sidecarSubdir(args.stateDir));
|
|
42023
|
-
await checkHostsDrift(
|
|
42088
|
+
await checkHostsDrift(args.stateDir, hosts, slog);
|
|
42024
42089
|
const hostSync = makeHostSync({ stateDir: args.stateDir, manifest: hosts, log: slog });
|
|
42025
42090
|
const attendance = makeAttendanceRegistry({ log: slog });
|
|
42026
42091
|
const runs = makeRunHub({ log: slog });
|
|
@@ -42045,8 +42110,8 @@ async function main() {
|
|
|
42045
42110
|
* run. Removing a --root should not silently convert an agent into a
|
|
42046
42111
|
* dead one; it runs where it always did, and the browser is what reports
|
|
42047
42112
|
* the mismatch. */
|
|
42048
|
-
workRootFor: (def) => {
|
|
42049
|
-
const want = def.settings.workRoots?.[sidecarId];
|
|
42113
|
+
workRootFor: async (def, owner) => {
|
|
42114
|
+
const want = await deployedRoot(args.stateDir, owner, def.name) ?? def.settings.workRoots?.[sidecarId];
|
|
42050
42115
|
if (want && args.roots.includes(want)) return want;
|
|
42051
42116
|
if (want) slog(`crew: "${def.name}" asks for root "${want}", which is not approved \u2014 using ${args.roots[0]}`);
|
|
42052
42117
|
return args.roots[0];
|
|
@@ -42168,16 +42233,21 @@ async function main() {
|
|
|
42168
42233
|
...args.stateDir ? { stateDir: args.stateDir } : {},
|
|
42169
42234
|
log: slog
|
|
42170
42235
|
});
|
|
42236
|
+
let backendInfo;
|
|
42171
42237
|
if (controlPlane) {
|
|
42172
42238
|
const caps = await controlPlane.backend.probe();
|
|
42173
42239
|
if (caps.includes("sessions")) {
|
|
42174
42240
|
slog(`backend: ${args.endpoint} mirrors sessions (as "${friendlyName || sidecarId}")`);
|
|
42175
42241
|
const cred = await resolveCredential(process.env, args.stateDir);
|
|
42242
|
+
backendInfo = describeBackend(args.endpoint, true, cred);
|
|
42176
42243
|
if (!cred.token) {
|
|
42177
42244
|
slog("backend: NOT SIGNED IN \u2014 pushes will be refused until `corenel login` (or CORENEL_TOKEN)");
|
|
42245
|
+
} else if (cred.expired) {
|
|
42246
|
+
slog("backend: SIGN-IN EXPIRED \u2014 pushes will be refused until `corenel login`");
|
|
42178
42247
|
}
|
|
42179
42248
|
} else {
|
|
42180
42249
|
slog(`backend: ${args.endpoint} holds no sessions \u2014 working local-only`);
|
|
42250
|
+
backendInfo = describeBackend(args.endpoint, false, { token: null });
|
|
42181
42251
|
controlPlane.dispose();
|
|
42182
42252
|
controlPlane = null;
|
|
42183
42253
|
}
|
|
@@ -42245,7 +42315,9 @@ async function main() {
|
|
|
42245
42315
|
billing: acpAuth.billing,
|
|
42246
42316
|
notes: [...acpAuth.notes]
|
|
42247
42317
|
}
|
|
42248
|
-
} : {}
|
|
42318
|
+
} : {},
|
|
42319
|
+
// Absent when this daemon has no backend at all — see backendInfo above.
|
|
42320
|
+
...backendInfo ? { backend: backendInfo } : {}
|
|
42249
42321
|
},
|
|
42250
42322
|
// The mutable root set. Present only so a client may add a working directory
|
|
42251
42323
|
// mid-session; with no --allow-add-under its areas are empty and every add is
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@corenel/sidecar",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.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/
|
|
39
|
+
"@corenel/protocol": "0.4.2",
|
|
40
40
|
"@corenel/tools-node": "0.2.2",
|
|
41
|
-
"@corenel/
|
|
42
|
-
"@corenel/
|
|
41
|
+
"@corenel/crew": "0.0.0",
|
|
42
|
+
"@corenel/harness": "0.4.1"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"prebuild": "pnpm --filter @corenel/protocol build && pnpm --filter @corenel/harness build",
|