@corenel/sidecar 0.9.0 → 0.10.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.
- package/dist/cli.js +313 -40
- package/package.json +5 -5
package/dist/cli.js
CHANGED
|
@@ -25468,6 +25468,11 @@ var SidecarServer = class {
|
|
|
25468
25468
|
/** The friendly label from the same `hello`, kept beside `clientId` so the
|
|
25469
25469
|
* dirName resolver is handed the identity the manifest keys on. */
|
|
25470
25470
|
clientName;
|
|
25471
|
+
/** This connection's attended-client object, retained so an answer it sends
|
|
25472
|
+
* can be attributed to it. Typed `unknown` because its only consumer is the
|
|
25473
|
+
* registry's own identity lookup, which takes `unknown` for the
|
|
25474
|
+
* dependency-direction reason on `SidecarAttendanceRegistry.answer`. */
|
|
25475
|
+
attended;
|
|
25471
25476
|
/** Detach function for this connection's attendance attachment, set on a
|
|
25472
25477
|
* successful `hello` when `opts.attendance` is wired. Called once, on channel
|
|
25473
25478
|
* close, so a dead connection stops receiving/counting toward asks. */
|
|
@@ -25579,7 +25584,7 @@ var SidecarServer = class {
|
|
|
25579
25584
|
return;
|
|
25580
25585
|
case "permission-answer":
|
|
25581
25586
|
if (!this.authed) return;
|
|
25582
|
-
this.opts.attendance?.answer(m2.id, m2.decision);
|
|
25587
|
+
this.opts.attendance?.answer(m2.id, m2.decision, this.attended);
|
|
25583
25588
|
return;
|
|
25584
25589
|
case "roots-browse":
|
|
25585
25590
|
if (!this.authed) {
|
|
@@ -25829,10 +25834,11 @@ var SidecarServer = class {
|
|
|
25829
25834
|
}
|
|
25830
25835
|
this.authed = true;
|
|
25831
25836
|
this.hostStateDir = m2.stateDir ?? ".corenel";
|
|
25837
|
+
let accounts = [];
|
|
25832
25838
|
if (typeof m2.clientId === "string" && m2.clientId) {
|
|
25833
25839
|
const wireId = m2.clientId.slice(0, MAX_IDENTITY_FIELD_LEN);
|
|
25834
25840
|
const claimed = Array.isArray(m2.accounts) ? m2.accounts : [];
|
|
25835
|
-
|
|
25841
|
+
accounts = claimed.length > MAX_CLAIMED_ACCOUNTS ? [] : claimed.filter((a2) => typeof a2 === "string" && a2.length <= MAX_IDENTITY_FIELD_LEN);
|
|
25836
25842
|
let clientId = wireId;
|
|
25837
25843
|
if (this.opts.clientKey) {
|
|
25838
25844
|
try {
|
|
@@ -25861,11 +25867,16 @@ var SidecarServer = class {
|
|
|
25861
25867
|
}
|
|
25862
25868
|
}
|
|
25863
25869
|
if (this.opts.attendance) {
|
|
25864
|
-
|
|
25870
|
+
const attended = {
|
|
25865
25871
|
send: (ask) => this.ch.send({ t: "permission-ask", ...ask }),
|
|
25866
|
-
resolved: (id, decision, by) => this.ch.send({ t: "permission-resolved", id, decision, by }),
|
|
25872
|
+
resolved: (id, decision, by, byClientId) => this.ch.send({ t: "permission-resolved", id, decision, by, ...byClientId ? { byClientId } : {} }),
|
|
25867
25873
|
runActivity: (activity) => this.ch.send({ t: "run-activity", activity }),
|
|
25868
25874
|
registrations: (registrations) => this.ch.send({ t: "registrations", registrations })
|
|
25875
|
+
};
|
|
25876
|
+
this.attended = attended;
|
|
25877
|
+
this.attendedDetach = this.opts.attendance.attach(attended, {
|
|
25878
|
+
clientId: this.clientId ?? "",
|
|
25879
|
+
accounts
|
|
25869
25880
|
});
|
|
25870
25881
|
}
|
|
25871
25882
|
this.opts.log?.(`paired \u2014 ${this.tools.size} ${this.tools.size === 1 ? "tool" : "tools"} advertised (host dir: ${this.hostStateDir})`);
|
|
@@ -26543,8 +26554,20 @@ var SidecarServer = class {
|
|
|
26543
26554
|
this.ch.send({ t: "room-open-result", id: m2.id, ok: false, problems: ["this sidecar does not host rooms"] });
|
|
26544
26555
|
return;
|
|
26545
26556
|
}
|
|
26557
|
+
if (this.opts.teamMode && this.clientId === void 0) {
|
|
26558
|
+
this.ch.send({
|
|
26559
|
+
t: "room-open-result",
|
|
26560
|
+
id: m2.id,
|
|
26561
|
+
ok: false,
|
|
26562
|
+
problems: ["This connection has no verified identity (no clientId from hello), so it cannot open a room."]
|
|
26563
|
+
});
|
|
26564
|
+
return;
|
|
26565
|
+
}
|
|
26566
|
+
const clientId = this.clientId;
|
|
26567
|
+
const owner = clientId === void 0 ? void 0 : m2.req.participants.find((p2) => p2.kind === "human" && p2.role === "owner");
|
|
26568
|
+
const req = owner && clientId !== void 0 ? { ...m2.req, participants: m2.req.participants.map((p2) => p2 === owner ? { ...p2, id: clientId } : p2) } : m2.req;
|
|
26546
26569
|
try {
|
|
26547
|
-
const r2 = await this.opts.rooms.open(
|
|
26570
|
+
const r2 = await this.opts.rooms.open(req);
|
|
26548
26571
|
this.ch.send(r2.ok ? { t: "room-open-result", id: m2.id, ok: true, room: r2.room } : { t: "room-open-result", id: m2.id, ok: false, problems: r2.problems });
|
|
26549
26572
|
} catch (err) {
|
|
26550
26573
|
this.ch.send({ t: "room-open-result", id: m2.id, ok: false, problems: [errMessage(err)] });
|
|
@@ -26556,7 +26579,9 @@ var SidecarServer = class {
|
|
|
26556
26579
|
return;
|
|
26557
26580
|
}
|
|
26558
26581
|
try {
|
|
26559
|
-
|
|
26582
|
+
const rooms = await this.opts.rooms.list();
|
|
26583
|
+
const mine = !this.opts.teamMode ? rooms : this.clientId === void 0 ? [] : rooms.filter((r2) => r2.participants.some((p2) => p2.id === this.clientId));
|
|
26584
|
+
this.ch.send({ t: "room-list-result", id: m2.id, ok: true, rooms: mine });
|
|
26560
26585
|
} catch (err) {
|
|
26561
26586
|
this.ch.send({ t: "room-list-result", id: m2.id, ok: false, error: errMessage(err) });
|
|
26562
26587
|
}
|
|
@@ -26568,6 +26593,26 @@ var SidecarServer = class {
|
|
|
26568
26593
|
}
|
|
26569
26594
|
try {
|
|
26570
26595
|
const found = await this.opts.rooms.read(m2.roomId);
|
|
26596
|
+
if (found && this.opts.teamMode) {
|
|
26597
|
+
if (this.clientId === void 0) {
|
|
26598
|
+
this.ch.send({
|
|
26599
|
+
t: "room-read-result",
|
|
26600
|
+
id: m2.id,
|
|
26601
|
+
ok: false,
|
|
26602
|
+
error: "This connection has no verified identity, so membership in this room cannot be proven."
|
|
26603
|
+
});
|
|
26604
|
+
return;
|
|
26605
|
+
}
|
|
26606
|
+
if (!found.room.participants.some((p2) => p2.id === this.clientId)) {
|
|
26607
|
+
this.ch.send({
|
|
26608
|
+
t: "room-read-result",
|
|
26609
|
+
id: m2.id,
|
|
26610
|
+
ok: false,
|
|
26611
|
+
error: `"${this.clientId}" is not a member of room "${m2.roomId}".`
|
|
26612
|
+
});
|
|
26613
|
+
return;
|
|
26614
|
+
}
|
|
26615
|
+
}
|
|
26571
26616
|
this.ch.send(found ? { t: "room-read-result", id: m2.id, ok: true, room: found.room, messages: found.messages, turnCosts: found.turnCosts } : { t: "room-read-result", id: m2.id, ok: true, room: null, messages: [], turnCosts: [] });
|
|
26572
26617
|
} catch (err) {
|
|
26573
26618
|
this.ch.send({ t: "room-read-result", id: m2.id, ok: false, error: errMessage(err) });
|
|
@@ -26585,13 +26630,45 @@ var SidecarServer = class {
|
|
|
26585
26630
|
this.ch.send({ t: "room-resume-result", id: m2.id, ok: false, error: errMessage(err) });
|
|
26586
26631
|
}
|
|
26587
26632
|
}
|
|
26633
|
+
/* ONE identity rule for every room verb.
|
|
26634
|
+
*
|
|
26635
|
+
* `room-read` judges membership on `this.clientId` -- the identity this
|
|
26636
|
+
* connection PROVED at `hello`. The mutating verbs used to hand
|
|
26637
|
+
* `m.participantId` straight off the wire to `requireRole`/`mayAct`, so one
|
|
26638
|
+
* branch enforced while another trusted the caller: a viewer could send the
|
|
26639
|
+
* owner's participantId and close the room. Under team mode every verb now
|
|
26640
|
+
* judges the caller the same way `room-read` does, and a connection with no
|
|
26641
|
+
* proven identity is refused rather than attributed to whatever it claimed.
|
|
26642
|
+
*
|
|
26643
|
+
* KNOWN, DELIBERATE CONSEQUENCE (R9): the observed `clientId` and the
|
|
26644
|
+
* participant ids a room is opened with are currently DIFFERENT NAMESPACES
|
|
26645
|
+
* for everyone but the owner (whose id `onRoomOpen` overwrites with the
|
|
26646
|
+
* observed one). Until those namespaces are reconciled, these verbs will
|
|
26647
|
+
* REFUSE non-owner participants under `--mode team`. That refusal is the
|
|
26648
|
+
* intended outcome -- fail closed, consistently -- and must NOT be "fixed"
|
|
26649
|
+
* by falling back to the wire id, which is the hole this closes.
|
|
26650
|
+
*
|
|
26651
|
+
* With `--mode team` OFF this is the pre-existing behaviour, untouched: the
|
|
26652
|
+
* wire id is attribution only, exactly as the spec knowingly accepted. */
|
|
26653
|
+
actingId(claimed) {
|
|
26654
|
+
if (!this.opts.teamMode) return { ok: true, id: claimed };
|
|
26655
|
+
if (this.clientId === void 0) {
|
|
26656
|
+
return { ok: false, error: "This connection has no verified identity (no clientId from hello), so it cannot act on a room." };
|
|
26657
|
+
}
|
|
26658
|
+
return { ok: true, id: this.clientId };
|
|
26659
|
+
}
|
|
26588
26660
|
async onRoomAnswer(m2) {
|
|
26589
26661
|
if (!this.opts.rooms) {
|
|
26590
26662
|
this.ch.send({ t: "room-answer-result", id: m2.id, ok: false, error: "this sidecar does not host rooms" });
|
|
26591
26663
|
return;
|
|
26592
26664
|
}
|
|
26593
26665
|
try {
|
|
26594
|
-
const
|
|
26666
|
+
const actor = this.actingId(m2.participantId);
|
|
26667
|
+
if (!actor.ok) {
|
|
26668
|
+
this.ch.send({ t: "room-answer-result", id: m2.id, ok: false, error: actor.error });
|
|
26669
|
+
return;
|
|
26670
|
+
}
|
|
26671
|
+
const room = await this.opts.rooms.answer(m2.roomId, actor.id, m2.text, m2.addressed);
|
|
26595
26672
|
this.ch.send({ t: "room-answer-result", id: m2.id, ok: true, room });
|
|
26596
26673
|
} catch (err) {
|
|
26597
26674
|
this.ch.send({ t: "room-answer-result", id: m2.id, ok: false, error: errMessage(err) });
|
|
@@ -26603,7 +26680,12 @@ var SidecarServer = class {
|
|
|
26603
26680
|
return;
|
|
26604
26681
|
}
|
|
26605
26682
|
try {
|
|
26606
|
-
const
|
|
26683
|
+
const actor = this.actingId(m2.participantId);
|
|
26684
|
+
if (!actor.ok) {
|
|
26685
|
+
this.ch.send({ t: "room-interject-result", id: m2.id, ok: false, error: actor.error });
|
|
26686
|
+
return;
|
|
26687
|
+
}
|
|
26688
|
+
const room = await this.opts.rooms.interject(m2.roomId, actor.id, m2.text);
|
|
26607
26689
|
this.ch.send({ t: "room-interject-result", id: m2.id, ok: true, room });
|
|
26608
26690
|
} catch (err) {
|
|
26609
26691
|
this.ch.send({ t: "room-interject-result", id: m2.id, ok: false, error: errMessage(err) });
|
|
@@ -26615,7 +26697,12 @@ var SidecarServer = class {
|
|
|
26615
26697
|
return;
|
|
26616
26698
|
}
|
|
26617
26699
|
try {
|
|
26618
|
-
const
|
|
26700
|
+
const actor = this.actingId(m2.participantId);
|
|
26701
|
+
if (!actor.ok) {
|
|
26702
|
+
this.ch.send({ t: "room-close-result", id: m2.id, ok: false, error: actor.error });
|
|
26703
|
+
return;
|
|
26704
|
+
}
|
|
26705
|
+
const room = await this.opts.rooms.close(m2.roomId, actor.id, m2.reason);
|
|
26619
26706
|
this.ch.send({ t: "room-close-result", id: m2.id, ok: true, room });
|
|
26620
26707
|
} catch (err) {
|
|
26621
26708
|
this.ch.send({ t: "room-close-result", id: m2.id, ok: false, error: errMessage(err) });
|
|
@@ -26714,7 +26801,12 @@ var SidecarServer = class {
|
|
|
26714
26801
|
return;
|
|
26715
26802
|
}
|
|
26716
26803
|
try {
|
|
26717
|
-
const
|
|
26804
|
+
const actor = this.actingId(m2.participantId);
|
|
26805
|
+
if (!actor.ok) {
|
|
26806
|
+
this.ch.send({ t: "room-finding-edit-result", id: m2.id, ok: false, error: actor.error });
|
|
26807
|
+
return;
|
|
26808
|
+
}
|
|
26809
|
+
const findings = await this.opts.rooms.editFinding(m2.roomId, actor.id, m2.edit);
|
|
26718
26810
|
this.ch.send({ t: "room-finding-edit-result", id: m2.id, ok: true, findings });
|
|
26719
26811
|
} catch (err) {
|
|
26720
26812
|
this.ch.send({ t: "room-finding-edit-result", id: m2.id, ok: false, error: errMessage(err) });
|
|
@@ -27017,6 +27109,7 @@ function startSidecar(opts) {
|
|
|
27017
27109
|
procs: opts.procs,
|
|
27018
27110
|
sessions: opts.sessions,
|
|
27019
27111
|
rooms: opts.rooms,
|
|
27112
|
+
teamMode: opts.teamMode,
|
|
27020
27113
|
pauses: opts.pauses,
|
|
27021
27114
|
clientDirName: opts.clientDirName,
|
|
27022
27115
|
hosts: opts.hosts,
|
|
@@ -27201,6 +27294,7 @@ var FLAGS = [
|
|
|
27201
27294
|
{ flag: "--allow-origin", arg: "<url>", help: "Allow a browser origin to connect. Repeatable." },
|
|
27202
27295
|
{ flag: "--allow-shell", help: "Enable the shell tool. Off by default." },
|
|
27203
27296
|
{ flag: "--allow-lan", help: "Serve the local network, not just this machine: binds all interfaces and serves wss with a self-signed cert. --host / --tls-cert override each half." },
|
|
27297
|
+
{ flag: "--mode", arg: "team", help: "Route a permission ask to the connection whose run raised it, plus the other devices that owner is signed in on, rather than to everyone attached. The identity a client sends is CLAIMED and this daemon cannot verify it: attribution, not authorization. An ask is never diverted away from its owner, so a false claim can join a prompt but never steal one." },
|
|
27204
27298
|
{ flag: "--tls-cert", arg: "<file>", help: "TLS certificate for wss://." },
|
|
27205
27299
|
{ flag: "--tls-key", arg: "<file>", help: "TLS private key for wss://." },
|
|
27206
27300
|
{ flag: "--self-signed", help: "Generate a self-signed certificate instead of supplying one." },
|
|
@@ -28164,6 +28258,7 @@ var KNOWN_KEYS = [
|
|
|
28164
28258
|
"maxChainDepth",
|
|
28165
28259
|
"name",
|
|
28166
28260
|
"appUrl",
|
|
28261
|
+
"mode",
|
|
28167
28262
|
"defaultModel",
|
|
28168
28263
|
"mcpServers",
|
|
28169
28264
|
"mcpAllow"
|
|
@@ -31996,26 +32091,39 @@ function makeAgentMemoryProvider(getFiles, memoryRoot) {
|
|
|
31996
32091
|
};
|
|
31997
32092
|
}
|
|
31998
32093
|
|
|
32094
|
+
// ../crew/room/types.ts
|
|
32095
|
+
function roleOf(p2) {
|
|
32096
|
+
return p2.kind === "agent" ? null : p2.role ?? "contributor";
|
|
32097
|
+
}
|
|
32098
|
+
|
|
31999
32099
|
// ../crew/room/order.ts
|
|
32000
32100
|
var ID_RE = /^[A-Za-z0-9_-]+$/;
|
|
32001
32101
|
function isValidParticipantId(id) {
|
|
32002
32102
|
return ID_RE.test(id);
|
|
32003
32103
|
}
|
|
32104
|
+
function rotating(state) {
|
|
32105
|
+
return state.mode === "conversation" ? state.participants.filter((p2) => p2.kind === "agent") : state.participants;
|
|
32106
|
+
}
|
|
32004
32107
|
function currentSpeaker(state) {
|
|
32005
32108
|
if (state.closed) return null;
|
|
32006
|
-
|
|
32007
|
-
|
|
32109
|
+
const roster = rotating(state);
|
|
32110
|
+
if (state.jump) {
|
|
32111
|
+
const jumped = roster.find((p2) => p2.id === state.jump);
|
|
32112
|
+
if (jumped) return jumped;
|
|
32113
|
+
}
|
|
32114
|
+
return roster[state.floor] ?? null;
|
|
32008
32115
|
}
|
|
32009
32116
|
function advance(state, addressed) {
|
|
32010
32117
|
if (state.closed) return state;
|
|
32118
|
+
const roster = rotating(state);
|
|
32011
32119
|
const speaker = currentSpeaker(state);
|
|
32012
32120
|
const spokeViaJump = state.jump != null;
|
|
32013
32121
|
const turns = state.turns + 1;
|
|
32014
32122
|
const mayAddress = !spokeViaJump;
|
|
32015
|
-
const target = mayAddress && addressed && addressed !== speaker?.id &&
|
|
32016
|
-
let floor = spokeViaJump ? state.floor : (state.floor + 1) %
|
|
32017
|
-
if (target != null &&
|
|
32018
|
-
floor = (floor + 1) %
|
|
32123
|
+
const target = mayAddress && addressed && addressed !== speaker?.id && roster.some((p2) => p2.id === addressed) ? addressed : null;
|
|
32124
|
+
let floor = spokeViaJump ? state.floor : (state.floor + 1) % roster.length;
|
|
32125
|
+
if (target != null && roster[floor]?.id === target) {
|
|
32126
|
+
floor = (floor + 1) % roster.length;
|
|
32019
32127
|
}
|
|
32020
32128
|
const closed = turns >= state.maxTurns ? { by: "room", reason: `Turn cap reached (${state.maxTurns}).`, at: (/* @__PURE__ */ new Date()).toISOString() } : null;
|
|
32021
32129
|
return { ...state, floor, jump: target, jumpBy: target ? speaker?.id ?? null : null, turns, closed };
|
|
@@ -32063,6 +32171,9 @@ function foldRoom(text) {
|
|
|
32063
32171
|
maxUsd: typeof line.maxUsd === "number" ? line.maxUsd : null,
|
|
32064
32172
|
spentUsd: 0,
|
|
32065
32173
|
closed: null,
|
|
32174
|
+
// Absent means a room written before conversation mode existed, and
|
|
32175
|
+
// every one of those is a rotation room.
|
|
32176
|
+
mode: line.mode ?? "rotation",
|
|
32066
32177
|
// Absent, rather than 0, on a line whose `at` is missing or not a
|
|
32067
32178
|
// number: "the log does not say" is not a date at the epoch.
|
|
32068
32179
|
...typeof line.at === "number" ? { openedAt: line.at } : {}
|
|
@@ -32142,6 +32253,7 @@ function foldSession(text) {
|
|
|
32142
32253
|
const turns = [];
|
|
32143
32254
|
let title = "";
|
|
32144
32255
|
let titleLocked;
|
|
32256
|
+
let movedTo;
|
|
32145
32257
|
let updatedAt = 0;
|
|
32146
32258
|
for (const raw of text.split("\n")) {
|
|
32147
32259
|
const s2 = raw.trim();
|
|
@@ -32163,6 +32275,9 @@ function foldSession(text) {
|
|
|
32163
32275
|
} else if (line.k === "turn" && Number.isInteger(line.i) && line.i >= 0 && typeof line.at === "number") {
|
|
32164
32276
|
turns[line.i] = line.m;
|
|
32165
32277
|
updatedAt = Math.max(updatedAt, line.at);
|
|
32278
|
+
} else if (line.k === "moved" && typeof line.roomId === "string" && typeof line.at === "number") {
|
|
32279
|
+
movedTo = { movedToRoom: line.roomId, at: line.at };
|
|
32280
|
+
updatedAt = Math.max(updatedAt, line.at);
|
|
32166
32281
|
}
|
|
32167
32282
|
}
|
|
32168
32283
|
if (!meta) return null;
|
|
@@ -32173,7 +32288,12 @@ function foldSession(text) {
|
|
|
32173
32288
|
updatedAt: updatedAt || meta.createdAt,
|
|
32174
32289
|
messages: turns.filter((t2) => t2 !== void 0),
|
|
32175
32290
|
...meta.surface ? { surface: meta.surface } : {},
|
|
32176
|
-
|
|
32291
|
+
// Only a STRING owner survives the fold: the line came from disk (or a
|
|
32292
|
+
// sidecar), so its declared type guarantees nothing, and a non-string here
|
|
32293
|
+
// would reach a comparison that decides how a row is drawn.
|
|
32294
|
+
...typeof meta.owner === "string" && meta.owner ? { owner: meta.owner } : {},
|
|
32295
|
+
...titleLocked !== void 0 ? { titleLocked } : {},
|
|
32296
|
+
...movedTo !== void 0 ? { movedTo } : {}
|
|
32177
32297
|
};
|
|
32178
32298
|
}
|
|
32179
32299
|
|
|
@@ -32583,9 +32703,37 @@ function validateRoomRequest(req) {
|
|
|
32583
32703
|
"A browser cannot host a room: the messages and outcome a turn produces never leave the browser tab's worker, so the room would rotate blindly with every hand-over and close silently lost. Choose the daemon runtime instead."
|
|
32584
32704
|
);
|
|
32585
32705
|
}
|
|
32706
|
+
if (req.mode === "conversation") {
|
|
32707
|
+
if (!req.participants.some((p2) => p2.kind === "agent")) {
|
|
32708
|
+
problems.push(
|
|
32709
|
+
"A conversation room needs at least one agent: humans never hold the floor in this mode, so a room without one has nobody who can ever take a turn."
|
|
32710
|
+
);
|
|
32711
|
+
}
|
|
32712
|
+
if (req.presence === "wait") {
|
|
32713
|
+
problems.push(
|
|
32714
|
+
'presence "wait" means waiting for a person to take their turn, and in a conversation room nobody does. Use "carry-on".'
|
|
32715
|
+
);
|
|
32716
|
+
}
|
|
32717
|
+
}
|
|
32586
32718
|
if (!Number.isInteger(req.maxTurns) || req.maxTurns < 1) {
|
|
32587
32719
|
problems.push("The turn cap must be a positive whole number.");
|
|
32588
32720
|
}
|
|
32721
|
+
const ROLES = ["owner", "contributor", "viewer"];
|
|
32722
|
+
const owners = req.participants.filter((p2) => p2.kind === "human" && p2.role === "owner");
|
|
32723
|
+
if (owners.length > 1) {
|
|
32724
|
+
problems.push(
|
|
32725
|
+
`A room has one owner; this request names ${owners.length}: ${owners.map((p2) => p2.name).join(", ")}.`
|
|
32726
|
+
);
|
|
32727
|
+
}
|
|
32728
|
+
for (const p2 of req.participants) {
|
|
32729
|
+
const role = p2.role;
|
|
32730
|
+
if (role === void 0) continue;
|
|
32731
|
+
if (p2.kind === "agent") {
|
|
32732
|
+
problems.push(`"${p2.name}" is an agent and cannot hold a role: agents are the work, not participants who are granted access.`);
|
|
32733
|
+
} else if (!ROLES.includes(role)) {
|
|
32734
|
+
problems.push(`"${role}" is not a role. Known roles: ${ROLES.join(", ")}.`);
|
|
32735
|
+
}
|
|
32736
|
+
}
|
|
32589
32737
|
return problems;
|
|
32590
32738
|
}
|
|
32591
32739
|
async function planOpen(req, reach, at2) {
|
|
@@ -32617,7 +32765,8 @@ async function planOpen(req, reach, at2) {
|
|
|
32617
32765
|
brief: (req.brief ?? "").trim(),
|
|
32618
32766
|
...req.maxUsd !== void 0 ? { maxUsd: req.maxUsd } : {},
|
|
32619
32767
|
runtime: req.runtime,
|
|
32620
|
-
presence: req.presence
|
|
32768
|
+
presence: req.presence,
|
|
32769
|
+
...req.mode !== void 0 ? { mode: req.mode } : {}
|
|
32621
32770
|
}
|
|
32622
32771
|
};
|
|
32623
32772
|
}
|
|
@@ -43136,9 +43285,10 @@ function now() {
|
|
|
43136
43285
|
return lastTs;
|
|
43137
43286
|
}
|
|
43138
43287
|
var JsonlSessionStore = class _JsonlSessionStore {
|
|
43139
|
-
constructor(getFiles, root = sessionsRoot) {
|
|
43288
|
+
constructor(getFiles, root = sessionsRoot, owner = () => void 0) {
|
|
43140
43289
|
this.getFiles = getFiles;
|
|
43141
43290
|
this.root = root;
|
|
43291
|
+
this.owner = owner;
|
|
43142
43292
|
}
|
|
43143
43293
|
cursors = /* @__PURE__ */ new Map();
|
|
43144
43294
|
async files() {
|
|
@@ -43173,11 +43323,13 @@ var JsonlSessionStore = class _JsonlSessionStore {
|
|
|
43173
43323
|
async create(title, surface) {
|
|
43174
43324
|
const createdAt = now();
|
|
43175
43325
|
const id = uid("ses");
|
|
43176
|
-
const
|
|
43326
|
+
const owner = this.owner();
|
|
43327
|
+
const own = owner ? { owner } : {};
|
|
43328
|
+
const meta = { k: "meta", id, title, createdAt, ...surface ? { surface } : {}, ...own };
|
|
43177
43329
|
const text = encodeLine(meta);
|
|
43178
43330
|
await (await this.files()).write(this.path(id), text);
|
|
43179
43331
|
this.cursors.set(id, { text, turnJson: [], title });
|
|
43180
|
-
return { id, title, createdAt, updatedAt: createdAt, messages: [], ...surface ? { surface } : {} };
|
|
43332
|
+
return { id, title, createdAt, updatedAt: createdAt, messages: [], ...surface ? { surface } : {}, ...own };
|
|
43181
43333
|
}
|
|
43182
43334
|
async get(id) {
|
|
43183
43335
|
const text = await (await this.files()).read(this.path(id)).catch(() => null);
|
|
@@ -43320,7 +43472,8 @@ var JsonlSessionStore = class _JsonlSessionStore {
|
|
|
43320
43472
|
id: session.id,
|
|
43321
43473
|
title: session.title,
|
|
43322
43474
|
createdAt: session.createdAt,
|
|
43323
|
-
...session.surface ? { surface: session.surface } : {}
|
|
43475
|
+
...session.surface ? { surface: session.surface } : {},
|
|
43476
|
+
...session.owner ? { owner: session.owner } : {}
|
|
43324
43477
|
});
|
|
43325
43478
|
return { text: meta, turnJson: [], title: session.title, titleLocked: void 0 };
|
|
43326
43479
|
}
|
|
@@ -43838,7 +43991,7 @@ function makeUnattendedPrompt(deps) {
|
|
|
43838
43991
|
for (; ; ) {
|
|
43839
43992
|
if (remaining <= 0) return { by: "timeout" };
|
|
43840
43993
|
const tickMs = Math.min(remaining, PARK_POLL_MS);
|
|
43841
|
-
if (deps.registry.isAttended()) {
|
|
43994
|
+
if (deps.registry.isAttended(deps.owner)) {
|
|
43842
43995
|
const ctrl2 = new AbortController();
|
|
43843
43996
|
const answered = deps.registry.broadcastAsk(ask, ctrl2.signal);
|
|
43844
43997
|
const ticked = sleep2(tickMs, ctrl2.signal).then(() => "tick");
|
|
@@ -43876,7 +44029,11 @@ function makeUnattendedPrompt(deps) {
|
|
|
43876
44029
|
agent: deps.agent,
|
|
43877
44030
|
tool: req.tool,
|
|
43878
44031
|
input: req.input,
|
|
43879
|
-
deadline: now2() + bound
|
|
44032
|
+
deadline: now2() + bound,
|
|
44033
|
+
// Spread-when-present rather than `owner: deps.owner`, so an ownerless
|
|
44034
|
+
// ask has no `owner` KEY at all -- the registry's `!ask.owner` test
|
|
44035
|
+
// stays unambiguous and a serialised ask does not carry a null.
|
|
44036
|
+
...deps.owner ? { owner: deps.owner } : {}
|
|
43880
44037
|
};
|
|
43881
44038
|
if (deps.unattended === "park") {
|
|
43882
44039
|
deps.onParkChange?.(true);
|
|
@@ -43896,7 +44053,7 @@ function makeUnattendedPrompt(deps) {
|
|
|
43896
44053
|
}
|
|
43897
44054
|
}
|
|
43898
44055
|
const fallthrough = deps.unattended === "allow" ? "allow" : "deny";
|
|
43899
|
-
if (deps.registry.isAttended()) {
|
|
44056
|
+
if (deps.registry.isAttended(deps.owner)) {
|
|
43900
44057
|
deps.onParkChange?.(true);
|
|
43901
44058
|
deps.onAskWait?.(ask);
|
|
43902
44059
|
try {
|
|
@@ -44298,6 +44455,21 @@ var NodeRunnerService = class {
|
|
|
44298
44455
|
registry: registry2,
|
|
44299
44456
|
runId: sessionId,
|
|
44300
44457
|
agent,
|
|
44458
|
+
/* WHOSE RUN THIS IS, for `--mode team`'s ask routing.
|
|
44459
|
+
*
|
|
44460
|
+
* Only the `{ clientId }` variant names a connection. `{ owner }` is
|
|
44461
|
+
* a dirName the daemon's own trigger dispatcher resolved from
|
|
44462
|
+
* filesystem enumeration -- there is no socket behind it, so an ask
|
|
44463
|
+
* it raises has nobody to route to and correctly falls back to
|
|
44464
|
+
* fan-out. Same for a `{ clientId }` of `undefined` (an older peer).
|
|
44465
|
+
*
|
|
44466
|
+
* Deliberately the RAW clientId rather than `owner` (the resolved
|
|
44467
|
+
* dirName computed above): this value is only ever compared against
|
|
44468
|
+
* the identity a connection ATTACHED with, which is the same
|
|
44469
|
+
* authenticated clientId the harness filed it under. It is never
|
|
44470
|
+
* used as a path, so the manifest resolution that `owner` needs
|
|
44471
|
+
* would not make it safer -- it would just make it fail to match. */
|
|
44472
|
+
..."owner" in identity || identity.clientId === void 0 ? {} : { owner: identity.clientId },
|
|
44301
44473
|
unattended: def.policy.unattended ?? "deny",
|
|
44302
44474
|
...def.policy.parkTimeoutMs != null ? { parkTimeoutMs: def.policy.parkTimeoutMs } : {},
|
|
44303
44475
|
remainingMs,
|
|
@@ -45079,6 +45251,20 @@ function evaluateRunComplete(completion, agents, maxChainDepth, log) {
|
|
|
45079
45251
|
}
|
|
45080
45252
|
|
|
45081
45253
|
// src/runner/roomService.ts
|
|
45254
|
+
function hasRecordedOwner(state) {
|
|
45255
|
+
return state.participants.some((p2) => p2.kind === "human" && p2.role === "owner");
|
|
45256
|
+
}
|
|
45257
|
+
function mayAct(state, participantId, verb) {
|
|
45258
|
+
const member = state.participants.find((p2) => p2.id === participantId);
|
|
45259
|
+
if (!member) return `"${participantId}" is not a member of this room.`;
|
|
45260
|
+
const role = roleOf(member);
|
|
45261
|
+
if (role === null) return `"${participantId}" is an agent, not a participant who acts on the room.`;
|
|
45262
|
+
if (verb === "close") {
|
|
45263
|
+
if (!hasRecordedOwner(state)) return null;
|
|
45264
|
+
return role === "owner" ? null : `Only the owner can ${verb} this room; you are a ${role}.`;
|
|
45265
|
+
}
|
|
45266
|
+
return role === "viewer" ? `You are a viewer in this room and cannot ${verb}.` : null;
|
|
45267
|
+
}
|
|
45082
45268
|
function isDepsFactory(d2) {
|
|
45083
45269
|
return typeof d2 === "function";
|
|
45084
45270
|
}
|
|
@@ -45200,6 +45386,11 @@ function makeRoomService(opts) {
|
|
|
45200
45386
|
}
|
|
45201
45387
|
async function open(req) {
|
|
45202
45388
|
return enqueue(req.roomId, async () => {
|
|
45389
|
+
if (req.fromSession && req.fromSession.messages.length !== req.fromSession.turns) {
|
|
45390
|
+
const message = `Room "${req.roomId}" was not opened: the promoted thread arrived with ${req.fromSession.messages.length} message(s) but ${req.fromSession.turns} were expected. Refusing to open a room missing part of the conversation.`;
|
|
45391
|
+
log(`room "${req.roomId}" could not be opened: ${message}`);
|
|
45392
|
+
return { ok: false, problems: [message] };
|
|
45393
|
+
}
|
|
45203
45394
|
let deps;
|
|
45204
45395
|
try {
|
|
45205
45396
|
deps = await resolveDeps(req.participants, req.maxUsd ?? null);
|
|
@@ -45210,6 +45401,15 @@ function makeRoomService(opts) {
|
|
|
45210
45401
|
}
|
|
45211
45402
|
const opened = await openRoom(req, opts.reachability, deps);
|
|
45212
45403
|
if (!opened.ok) return opened;
|
|
45404
|
+
if (req.fromSession) {
|
|
45405
|
+
try {
|
|
45406
|
+
await deps.store.appendTurns(req.roomId, 0, req.fromSession.messages, deps.now());
|
|
45407
|
+
} catch (err) {
|
|
45408
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
45409
|
+
log(`room "${req.roomId}" opened but its promoted transcript failed to append: ${message}`);
|
|
45410
|
+
return { ok: false, problems: [`Room "${req.roomId}" opened, but the promoted conversation could not be saved into it: ${message}`] };
|
|
45411
|
+
}
|
|
45412
|
+
}
|
|
45213
45413
|
depsByRoom.set(req.roomId, deps);
|
|
45214
45414
|
const room = summaryOf(opened.state, null, null, 0);
|
|
45215
45415
|
record(room);
|
|
@@ -45265,10 +45465,22 @@ function makeRoomService(opts) {
|
|
|
45265
45465
|
}
|
|
45266
45466
|
return fresh;
|
|
45267
45467
|
}
|
|
45468
|
+
async function requireRole(deps, roomId, participantId, verb) {
|
|
45469
|
+
const state = await deps.store.read(roomId);
|
|
45470
|
+
if (!state || state.closed) return;
|
|
45471
|
+
const refusal = mayAct(state, participantId, verb);
|
|
45472
|
+
if (refusal) throw new Error(refusal);
|
|
45473
|
+
}
|
|
45268
45474
|
async function interject(roomId, participantId, text) {
|
|
45269
45475
|
return enqueue(roomId, async () => {
|
|
45270
45476
|
const deps = await baseDeps();
|
|
45477
|
+
await requireRole(deps, roomId, participantId, "interject");
|
|
45271
45478
|
await interjectHuman(roomId, participantId, text, deps);
|
|
45479
|
+
const state = await deps.store.read(roomId);
|
|
45480
|
+
if (state && !state.closed && state.mode === "conversation") {
|
|
45481
|
+
const driveDeps = await depsFor(roomId);
|
|
45482
|
+
if (driveDeps) return driveRoom(roomId, driveDeps);
|
|
45483
|
+
}
|
|
45272
45484
|
const summary = await summaryNow(roomId);
|
|
45273
45485
|
record(summary);
|
|
45274
45486
|
return summary;
|
|
@@ -45277,6 +45489,7 @@ function makeRoomService(opts) {
|
|
|
45277
45489
|
async function closeRoom(roomId, participantId, reason) {
|
|
45278
45490
|
return enqueue(roomId, async () => {
|
|
45279
45491
|
const deps = await baseDeps();
|
|
45492
|
+
await requireRole(deps, roomId, participantId, "close");
|
|
45280
45493
|
await closeRoomByHuman(roomId, participantId, reason, deps);
|
|
45281
45494
|
const summary = await summaryNow(roomId);
|
|
45282
45495
|
record(summary);
|
|
@@ -45290,6 +45503,7 @@ function makeRoomService(opts) {
|
|
|
45290
45503
|
async function editFinding(roomId, participantId, edit) {
|
|
45291
45504
|
return enqueue(roomId, async () => {
|
|
45292
45505
|
const deps = await baseDeps();
|
|
45506
|
+
await requireRole(deps, roomId, participantId, "finding-edit");
|
|
45293
45507
|
const doc = await editFindingByHuman(roomId, participantId, edit, deps);
|
|
45294
45508
|
record(await summaryNow(roomId));
|
|
45295
45509
|
return doc;
|
|
@@ -45299,6 +45513,7 @@ function makeRoomService(opts) {
|
|
|
45299
45513
|
return enqueue(roomId, async () => {
|
|
45300
45514
|
const deps = await depsFor(roomId);
|
|
45301
45515
|
if (!deps) throw new Error(`No room "${roomId}".`);
|
|
45516
|
+
await requireRole(deps, roomId, participantId, "answer");
|
|
45302
45517
|
await answerHumanTurn(roomId, participantId, text, deps, addressed);
|
|
45303
45518
|
return driveRoom(roomId, deps);
|
|
45304
45519
|
});
|
|
@@ -45865,27 +46080,49 @@ function startDaemonCore(opts) {
|
|
|
45865
46080
|
function makeAttendanceRegistry(opts) {
|
|
45866
46081
|
const log = opts?.log ?? (() => {
|
|
45867
46082
|
});
|
|
46083
|
+
const teamMode = opts?.teamMode === true;
|
|
46084
|
+
const EMPTY = /* @__PURE__ */ new Set();
|
|
45868
46085
|
const clients = /* @__PURE__ */ new Set();
|
|
46086
|
+
const identities = /* @__PURE__ */ new Map();
|
|
45869
46087
|
let lastRegistrations = null;
|
|
45870
46088
|
const outstanding = /* @__PURE__ */ new Map();
|
|
45871
46089
|
let idCounter = 0;
|
|
45872
|
-
const
|
|
46090
|
+
const recipients = (ask) => {
|
|
46091
|
+
if (!teamMode || !ask.owner) return clients;
|
|
46092
|
+
const owners = [];
|
|
46093
|
+
const ownerAccounts = /* @__PURE__ */ new Set();
|
|
46094
|
+
for (const [client, id] of identities) {
|
|
46095
|
+
if (id.clientId !== ask.owner) continue;
|
|
46096
|
+
owners.push(client);
|
|
46097
|
+
for (const a2 of id.accounts) ownerAccounts.add(a2);
|
|
46098
|
+
}
|
|
46099
|
+
if (owners.length === 0) return EMPTY;
|
|
46100
|
+
const out = new Set(owners);
|
|
46101
|
+
if (ownerAccounts.size > 0) {
|
|
46102
|
+
for (const [client, id] of identities) {
|
|
46103
|
+
if (id.accounts.some((a2) => ownerAccounts.has(a2))) out.add(client);
|
|
46104
|
+
}
|
|
46105
|
+
}
|
|
46106
|
+
return out;
|
|
46107
|
+
};
|
|
46108
|
+
const notifyResolved = (id, decision, by, byClientId) => {
|
|
45873
46109
|
for (const c2 of clients) {
|
|
45874
|
-
c2.resolved(id, decision, by);
|
|
46110
|
+
c2.resolved(id, decision, by, byClientId);
|
|
45875
46111
|
}
|
|
45876
46112
|
};
|
|
45877
|
-
const resolveEntry = (id, decision, by) => {
|
|
46113
|
+
const resolveEntry = (id, decision, by, byClientId) => {
|
|
45878
46114
|
const entry = outstanding.get(id);
|
|
45879
46115
|
if (!entry) return;
|
|
45880
46116
|
outstanding.delete(id);
|
|
45881
46117
|
entry.resolve(decision);
|
|
45882
|
-
notifyResolved(id, decision, by);
|
|
46118
|
+
notifyResolved(id, decision, by, byClientId);
|
|
45883
46119
|
};
|
|
45884
46120
|
return {
|
|
45885
|
-
attach(client) {
|
|
46121
|
+
attach(client, identity) {
|
|
45886
46122
|
clients.add(client);
|
|
46123
|
+
if (identity) identities.set(client, identity);
|
|
45887
46124
|
for (const { ask } of outstanding.values()) {
|
|
45888
|
-
client.send(ask);
|
|
46125
|
+
if (recipients(ask).has(client)) client.send(ask);
|
|
45889
46126
|
}
|
|
45890
46127
|
if (lastRegistrations) {
|
|
45891
46128
|
try {
|
|
@@ -45898,6 +46135,7 @@ function makeAttendanceRegistry(opts) {
|
|
|
45898
46135
|
if (detached) return;
|
|
45899
46136
|
detached = true;
|
|
45900
46137
|
clients.delete(client);
|
|
46138
|
+
identities.delete(client);
|
|
45901
46139
|
if (clients.size === 0 && outstanding.size > 0) {
|
|
45902
46140
|
log(`attendance: last client detached with ${outstanding.size} ask(s) outstanding; resolving null`);
|
|
45903
46141
|
for (const [id, entry] of Array.from(outstanding.entries())) {
|
|
@@ -45907,14 +46145,22 @@ function makeAttendanceRegistry(opts) {
|
|
|
45907
46145
|
}
|
|
45908
46146
|
};
|
|
45909
46147
|
},
|
|
45910
|
-
|
|
45911
|
-
return
|
|
46148
|
+
attachedIdentities() {
|
|
46149
|
+
return Array.from(identities.values());
|
|
46150
|
+
},
|
|
46151
|
+
isAttended(owner) {
|
|
46152
|
+
if (!teamMode || !owner) return clients.size > 0;
|
|
46153
|
+
for (const id of identities.values()) {
|
|
46154
|
+
if (id.clientId === owner) return true;
|
|
46155
|
+
}
|
|
46156
|
+
return false;
|
|
45912
46157
|
},
|
|
45913
46158
|
outstanding() {
|
|
45914
46159
|
return Array.from(outstanding.values()).map((e2) => e2.ask);
|
|
45915
46160
|
},
|
|
45916
46161
|
broadcastAsk(ask, signal) {
|
|
45917
|
-
|
|
46162
|
+
const to = recipients(ask);
|
|
46163
|
+
if (to.size === 0) {
|
|
45918
46164
|
return Promise.resolve(null);
|
|
45919
46165
|
}
|
|
45920
46166
|
return new Promise((resolve14) => {
|
|
@@ -45932,7 +46178,7 @@ function makeAttendanceRegistry(opts) {
|
|
|
45932
46178
|
resolve14(decision);
|
|
45933
46179
|
}
|
|
45934
46180
|
});
|
|
45935
|
-
for (const c2 of
|
|
46181
|
+
for (const c2 of to) {
|
|
45936
46182
|
c2.send(ask);
|
|
45937
46183
|
}
|
|
45938
46184
|
if (signal) {
|
|
@@ -45962,8 +46208,9 @@ function makeAttendanceRegistry(opts) {
|
|
|
45962
46208
|
}
|
|
45963
46209
|
}
|
|
45964
46210
|
},
|
|
45965
|
-
answer(id, decision) {
|
|
45966
|
-
|
|
46211
|
+
answer(id, decision, by) {
|
|
46212
|
+
const named = by ? identities.get(by)?.clientId : void 0;
|
|
46213
|
+
resolveEntry(id, decision, "client", named);
|
|
45967
46214
|
},
|
|
45968
46215
|
settle(id, decision, by) {
|
|
45969
46216
|
resolveEntry(id, decision, by);
|
|
@@ -47361,6 +47608,7 @@ var FLAG_TO_KEY = {
|
|
|
47361
47608
|
"--clone-under": "cloneUnder",
|
|
47362
47609
|
"--allow-origin": "allowOrigins",
|
|
47363
47610
|
"--allow-lan": "allowLan",
|
|
47611
|
+
"--mode": "teamMode",
|
|
47364
47612
|
"--allow-shell": "allowShell",
|
|
47365
47613
|
"--keep-transcripts": "keepTranscripts",
|
|
47366
47614
|
"--isolation": "isolation",
|
|
@@ -47379,7 +47627,7 @@ var FLAG_TO_KEY = {
|
|
|
47379
47627
|
"--default-model": "defaultModel",
|
|
47380
47628
|
"--name": "name"
|
|
47381
47629
|
};
|
|
47382
|
-
var DEFAULT_GUEST_IMAGE2 = "prompd/corenel-sandbox:0.
|
|
47630
|
+
var DEFAULT_GUEST_IMAGE2 = "prompd/corenel-sandbox:0.10.0";
|
|
47383
47631
|
function parseArgsWithProvenance(argv) {
|
|
47384
47632
|
const explicit = /* @__PURE__ */ new Set();
|
|
47385
47633
|
for (const a2 of argv) {
|
|
@@ -47396,6 +47644,7 @@ function parseArgs(argv) {
|
|
|
47396
47644
|
allowOrigins: [],
|
|
47397
47645
|
allowShell: false,
|
|
47398
47646
|
allowLan: false,
|
|
47647
|
+
teamMode: false,
|
|
47399
47648
|
keepTranscripts: false,
|
|
47400
47649
|
isolation: "none",
|
|
47401
47650
|
msbBin: process.env.MSB_BIN ?? "msb",
|
|
@@ -47450,7 +47699,11 @@ function parseArgs(argv) {
|
|
|
47450
47699
|
throw new Error(`--snapshot-budget: ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
47451
47700
|
}
|
|
47452
47701
|
} else if (a2 === "--allow-lan") out.allowLan = true;
|
|
47453
|
-
else if (a2 === "--
|
|
47702
|
+
else if (a2 === "--mode") {
|
|
47703
|
+
const mode = argv[++i2];
|
|
47704
|
+
if (mode !== "team") throw new Error(`unknown --mode "${mode}". Known modes: team`);
|
|
47705
|
+
out.teamMode = true;
|
|
47706
|
+
} else if (a2 === "--tls-cert") out.tlsCert = resolve10(argv[++i2]);
|
|
47454
47707
|
else if (a2 === "--tls-key") out.tlsKey = resolve10(argv[++i2]);
|
|
47455
47708
|
else if (a2 === "--self-signed") out.selfSigned = true;
|
|
47456
47709
|
else if (a2 === "--tunnel") out.tunnel = argv[++i2];
|
|
@@ -47572,6 +47825,17 @@ function layerConfig(args, explicit, file) {
|
|
|
47572
47825
|
from[key] = "file";
|
|
47573
47826
|
if (key === "endpoint") out.endpointExplicit = true;
|
|
47574
47827
|
}
|
|
47828
|
+
if (explicit.has("teamMode")) {
|
|
47829
|
+
from.teamMode = "flag";
|
|
47830
|
+
} else if (file.mode === void 0) {
|
|
47831
|
+
from.teamMode = "default";
|
|
47832
|
+
} else if (file.mode === "team") {
|
|
47833
|
+
out.teamMode = true;
|
|
47834
|
+
from.teamMode = "file";
|
|
47835
|
+
} else {
|
|
47836
|
+
warnings.push(`daemon.json: "mode" must be "team", got ${JSON.stringify(file.mode)} -- ignoring it, using the default`);
|
|
47837
|
+
from.teamMode = "default";
|
|
47838
|
+
}
|
|
47575
47839
|
if (out.allowLan) {
|
|
47576
47840
|
if (from.host === "default") out.host = "0.0.0.0";
|
|
47577
47841
|
if (from.selfSigned === "default" && !out.tlsCert && !out.tlsKey) out.selfSigned = true;
|
|
@@ -47753,6 +48017,11 @@ var KEY_TYPES = {
|
|
|
47753
48017
|
allowShell: "boolean",
|
|
47754
48018
|
keepTranscripts: "boolean",
|
|
47755
48019
|
isolation: "string",
|
|
48020
|
+
// A string, not a boolean, so the file spells it the way the flag does
|
|
48021
|
+
// (`--mode team`) and a second mode needs no second key. layer.ts refuses
|
|
48022
|
+
// any value but 'team', with a warning -- typed loosely here, validated
|
|
48023
|
+
// strictly there, the same split `isolation` has.
|
|
48024
|
+
mode: "string",
|
|
47756
48025
|
msbBin: "string",
|
|
47757
48026
|
guestImage: "string",
|
|
47758
48027
|
maxChainDepth: "number",
|
|
@@ -51244,7 +51513,7 @@ async function main() {
|
|
|
51244
51513
|
// schedule looks broken for a quarter of an hour.
|
|
51245
51514
|
onWrite: () => core?.wake()
|
|
51246
51515
|
});
|
|
51247
|
-
const attendance = makeAttendanceRegistry({ log: slog });
|
|
51516
|
+
const attendance = makeAttendanceRegistry({ log: slog, teamMode: args.teamMode });
|
|
51248
51517
|
const runs = makeRunHub({ log: slog });
|
|
51249
51518
|
let core;
|
|
51250
51519
|
let crewSessions;
|
|
@@ -51560,6 +51829,10 @@ async function main() {
|
|
|
51560
51829
|
// (roomCtx above) -- absent otherwise, so `welcome.features` omits
|
|
51561
51830
|
// 'rooms' exactly like every other optional daemon capability here.
|
|
51562
51831
|
rooms: core?.rooms,
|
|
51832
|
+
// Same operator flag `attendance.ts` already reads for ask routing --
|
|
51833
|
+
// `room-list` applies the identical private-by-default narrowing to
|
|
51834
|
+
// rooms once this is on (see `onRoomList`'s R7 comment).
|
|
51835
|
+
teamMode: args.teamMode,
|
|
51563
51836
|
// The pause control plane. Absent without --daemon, so 'agent-pause' is not
|
|
51564
51837
|
// advertised and a client correctly reports that this daemon holds none.
|
|
51565
51838
|
...pauses ? {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@corenel/sidecar",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
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,11 +36,11 @@
|
|
|
36
36
|
"esbuild": "^0.21.5",
|
|
37
37
|
"tsx": "^4.19.2",
|
|
38
38
|
"typescript": "^5.9.3",
|
|
39
|
-
"@corenel/config": "0.
|
|
40
|
-
"@corenel/protocol": "0.8.0",
|
|
41
|
-
"@corenel/tools-node": "0.5.0",
|
|
39
|
+
"@corenel/config": "0.3.0",
|
|
42
40
|
"@corenel/mcp": "0.2.0",
|
|
43
|
-
"@corenel/
|
|
41
|
+
"@corenel/protocol": "0.9.0",
|
|
42
|
+
"@corenel/harness": "0.10.0",
|
|
43
|
+
"@corenel/tools-node": "0.5.0",
|
|
44
44
|
"@corenel/crew": "0.0.0"
|
|
45
45
|
},
|
|
46
46
|
"repository": {
|