@agentvault/muse-bridge 0.1.30 → 0.1.31
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/bridge.d.ts +8 -0
- package/dist/index.js +113 -52
- package/dist/muse-driver.d.ts +6 -2
- package/dist/muse-session.d.ts +5 -1
- package/dist/muse-spawn.d.ts +7 -0
- package/package.json +1 -1
package/dist/bridge.d.ts
CHANGED
|
@@ -15,6 +15,12 @@ export interface RoomMessage {
|
|
|
15
15
|
* `plaintext`. The @ gate reads this; absent on emitters < 0.23.42. */
|
|
16
16
|
caption?: string;
|
|
17
17
|
senderIsAgent?: boolean;
|
|
18
|
+
/** #1459 — SecureChannel: a human in THIS agent's own account. Absent on
|
|
19
|
+
* emitters < 0.23.55, which reads as "not the owner" (fail closed). */
|
|
20
|
+
senderIsOwner?: boolean;
|
|
21
|
+
/** #1459 — SecureChannel: this turn carries a file from someone other than
|
|
22
|
+
* the owner. Only an explicit `false` lets an owner turn be powered. */
|
|
23
|
+
foreignContent?: boolean;
|
|
18
24
|
/** ISO send time from the emit (`data.created_at`). Used to stamp a message
|
|
19
25
|
* held as room context; receipt time stands in when absent. */
|
|
20
26
|
timestamp?: string;
|
|
@@ -108,6 +114,8 @@ export declare function attachLifecycle(channel: LifecycleChannel, opts?: {
|
|
|
108
114
|
restart: boolean;
|
|
109
115
|
}) => void;
|
|
110
116
|
}): void;
|
|
117
|
+
/** #1459 — appended to an owner turn that lost full access to someone else's file. */
|
|
118
|
+
export declare const FILE_LOCK_NOTE: string;
|
|
111
119
|
export declare function roomTurnPrefix(roomId: string, senderName: string, roomName?: string): string;
|
|
112
120
|
/**
|
|
113
121
|
* What a held (unaddressed) room message contributes as context: the CAPTION
|
package/dist/index.js
CHANGED
|
@@ -11798,11 +11798,11 @@ async function joinWithFirstMatchingKp(welcomeBytes, candidates) {
|
|
|
11798
11798
|
return null;
|
|
11799
11799
|
}
|
|
11800
11800
|
function ownIdentity() {
|
|
11801
|
-
const v2 = true ? "0.23.
|
|
11801
|
+
const v2 = true ? "0.23.55" : FALLBACK;
|
|
11802
11802
|
return `${PACKAGE}@${v2}`;
|
|
11803
11803
|
}
|
|
11804
11804
|
function buildSha() {
|
|
11805
|
-
const raw = true ? "
|
|
11805
|
+
const raw = true ? "45e77bd" : "";
|
|
11806
11806
|
const cleaned = (raw ?? "").trim();
|
|
11807
11807
|
return !cleaned || cleaned === "unknown" ? null : cleaned;
|
|
11808
11808
|
}
|
|
@@ -13215,6 +13215,14 @@ function _isSelfHubAddress(ownHubAddress, target) {
|
|
|
13215
13215
|
const tgt = (target ?? "").trim().toLowerCase();
|
|
13216
13216
|
return own2.length > 0 && own2 === tgt;
|
|
13217
13217
|
}
|
|
13218
|
+
function keepKnownMemberTenants(previous, next) {
|
|
13219
|
+
const known = /* @__PURE__ */ new Map();
|
|
13220
|
+
for (const m2 of previous) if (m2.tenantId) known.set(m2.deviceId, m2.tenantId);
|
|
13221
|
+
return next.map((m2) => {
|
|
13222
|
+
const tenantId = m2.tenantId ? void 0 : known.get(m2.deviceId);
|
|
13223
|
+
return tenantId ? { ...m2, tenantId } : m2;
|
|
13224
|
+
});
|
|
13225
|
+
}
|
|
13218
13226
|
function historyErrorReason(error2) {
|
|
13219
13227
|
let name = "Error";
|
|
13220
13228
|
let status;
|
|
@@ -71809,15 +71817,19 @@ var init_dist = __esm({
|
|
|
71809
71817
|
*/
|
|
71810
71818
|
_recentRoomAttachments = /* @__PURE__ */ new Map();
|
|
71811
71819
|
static RECENT_ROOM_ATTACHMENT_MS = 10 * 60 * 1e3;
|
|
71812
|
-
/** #1181: prefix a room turn that carries no attachment with the one saved in this room recently.
|
|
71820
|
+
/** #1181: prefix a room turn that carries no attachment with the one saved in this room recently.
|
|
71821
|
+
* `from` is who sent that file (#1459), so the turn can be marked as carrying their content. */
|
|
71813
71822
|
_withRecentRoomAttachmentNote(roomId, text) {
|
|
71814
71823
|
const recent = this._recentRoomAttachments.get(roomId);
|
|
71815
|
-
if (!recent) return text;
|
|
71824
|
+
if (!recent) return { text };
|
|
71816
71825
|
const ageMs = Date.now() - recent.at;
|
|
71817
|
-
if (ageMs > _SecureChannel.RECENT_ROOM_ATTACHMENT_MS) return text;
|
|
71818
|
-
return
|
|
71826
|
+
if (ageMs > _SecureChannel.RECENT_ROOM_ATTACHMENT_MS) return { text };
|
|
71827
|
+
return {
|
|
71828
|
+
text: `[Most recent file in this room: ${recent.filePath} (${recent.name}, received ${Math.round(ageMs / 1e3)}s ago). If this message refers to "the file" or "this file", it means that one \u2014 use your Read tool on it.]
|
|
71819
71829
|
|
|
71820
|
-
${text}
|
|
71830
|
+
${text}`,
|
|
71831
|
+
from: recent.senderDeviceId ?? null
|
|
71832
|
+
};
|
|
71821
71833
|
}
|
|
71822
71834
|
/**
|
|
71823
71835
|
* #1161: room attachments whose caption addressed nobody, NOT yet fetched.
|
|
@@ -71831,22 +71843,22 @@ ${text}`;
|
|
|
71831
71843
|
_deferredRoomAttachments = /* @__PURE__ */ new Map();
|
|
71832
71844
|
static DEFERRED_ROOM_ATTACHMENT_MAX = 5;
|
|
71833
71845
|
static DEFERRED_ROOM_ATTACHMENT_MS = 60 * 60 * 1e3;
|
|
71834
|
-
_deferRoomAttachment(roomId, info) {
|
|
71846
|
+
_deferRoomAttachment(roomId, info, senderDeviceId) {
|
|
71835
71847
|
const list = this._deferredRoomAttachments.get(roomId) ?? [];
|
|
71836
|
-
list.push({ info, at: Date.now() });
|
|
71848
|
+
list.push({ info, at: Date.now(), senderDeviceId });
|
|
71837
71849
|
while (list.length > _SecureChannel.DEFERRED_ROOM_ATTACHMENT_MAX) list.shift();
|
|
71838
71850
|
this._deferredRoomAttachments.set(roomId, list);
|
|
71839
71851
|
console.log(
|
|
71840
71852
|
`[SecureChannel] room ${roomId.slice(0, 8)}: attachment ${String(info?.filename ?? "file")} deferred \u2014 caption addresses nobody, fetch on the next @-addressed turn (#1161)`
|
|
71841
71853
|
);
|
|
71842
71854
|
}
|
|
71843
|
-
/** Drain the room's deferred attachments that are still fresh (oldest first). */
|
|
71855
|
+
/** Drain the room's deferred attachments that are still fresh (oldest first), with who sent each. */
|
|
71844
71856
|
_takeDeferredRoomAttachments(roomId) {
|
|
71845
71857
|
const list = this._deferredRoomAttachments.get(roomId);
|
|
71846
71858
|
if (!list?.length) return [];
|
|
71847
71859
|
this._deferredRoomAttachments.delete(roomId);
|
|
71848
71860
|
const cutoff = Date.now() - _SecureChannel.DEFERRED_ROOM_ATTACHMENT_MS;
|
|
71849
|
-
return list.filter((d2) => d2.at >= cutoff).map((d2) => d2.info);
|
|
71861
|
+
return list.filter((d2) => d2.at >= cutoff).map((d2) => ({ info: d2.info, senderDeviceId: d2.senderDeviceId }));
|
|
71850
71862
|
}
|
|
71851
71863
|
/** In-flight roster-refresh promises (per room) — dedup concurrent refreshes. */
|
|
71852
71864
|
_roomRosterRefreshInFlight = /* @__PURE__ */ new Map();
|
|
@@ -73938,7 +73950,7 @@ ${text}`;
|
|
|
73938
73950
|
*/
|
|
73939
73951
|
sendActivitySpan(spanData) {
|
|
73940
73952
|
if (!this._ws || this._ws.readyState !== WebSocket.OPEN) return;
|
|
73941
|
-
const pluginVersion = true ? "0.23.
|
|
73953
|
+
const pluginVersion = true ? "0.23.55" : "0.0.0-dev";
|
|
73942
73954
|
const agentName = this.config.agentName ?? "Agent";
|
|
73943
73955
|
const resource = {
|
|
73944
73956
|
"service.name": "agentvault-agent",
|
|
@@ -74089,11 +74101,15 @@ ${text}`;
|
|
|
74089
74101
|
}
|
|
74090
74102
|
const existingMlsGroupId = this._persisted.rooms[roomData.roomId]?.mlsGroupId;
|
|
74091
74103
|
const existingMlsTs = this._persisted.rooms[roomData.roomId]?.lastMlsMessageTs;
|
|
74104
|
+
const members2 = keepKnownMemberTenants(
|
|
74105
|
+
this._persisted.rooms[roomData.roomId]?.members ?? [],
|
|
74106
|
+
roomData.members
|
|
74107
|
+
);
|
|
74092
74108
|
this._persisted.rooms[roomData.roomId] = {
|
|
74093
74109
|
roomId: roomData.roomId,
|
|
74094
74110
|
name: roomData.name,
|
|
74095
74111
|
conversationIds,
|
|
74096
|
-
members:
|
|
74112
|
+
members: members2,
|
|
74097
74113
|
...existingMlsGroupId && { mlsGroupId: existingMlsGroupId },
|
|
74098
74114
|
...existingMlsTs && { lastMlsMessageTs: existingMlsTs }
|
|
74099
74115
|
};
|
|
@@ -74598,7 +74614,8 @@ ${text}`;
|
|
|
74598
74614
|
entityType: m2.entity_type,
|
|
74599
74615
|
displayName: m2.display_name,
|
|
74600
74616
|
identityPublicKey: m2.identity_public_key,
|
|
74601
|
-
ephemeralPublicKey: m2.ephemeral_public_key
|
|
74617
|
+
ephemeralPublicKey: m2.ephemeral_public_key,
|
|
74618
|
+
...typeof m2.tenant_id === "string" ? { tenantId: m2.tenant_id } : {}
|
|
74602
74619
|
}));
|
|
74603
74620
|
if (members2.length > 0) {
|
|
74604
74621
|
const roomState = this._persisted.rooms[roomId];
|
|
@@ -76143,7 +76160,7 @@ ${text}`;
|
|
|
76143
76160
|
agentVersion: this.config.agentVersion ?? "0.0.0",
|
|
76144
76161
|
// __AV_VERSION__ is injected by esbuild from package.json at build time.
|
|
76145
76162
|
// Falls back to "0.0.0-dev" in non-bundled contexts (tests).
|
|
76146
|
-
pluginVersion: true ? "0.23.
|
|
76163
|
+
pluginVersion: true ? "0.23.55" : "0.0.0-dev"
|
|
76147
76164
|
});
|
|
76148
76165
|
this._telemetryReporter.startAutoFlush(3e4);
|
|
76149
76166
|
}
|
|
@@ -76299,7 +76316,8 @@ ${text}`;
|
|
|
76299
76316
|
entityType: m2.entity_type,
|
|
76300
76317
|
displayName: m2.display_name,
|
|
76301
76318
|
identityPublicKey: m2.identity_public_key,
|
|
76302
|
-
ephemeralPublicKey: m2.ephemeral_public_key
|
|
76319
|
+
ephemeralPublicKey: m2.ephemeral_public_key,
|
|
76320
|
+
...typeof m2.tenant_id === "string" ? { tenantId: m2.tenant_id } : {}
|
|
76303
76321
|
})),
|
|
76304
76322
|
conversations: (d2.conversations || []).map((c2) => ({
|
|
76305
76323
|
id: c2.id,
|
|
@@ -76474,7 +76492,7 @@ ${text}`;
|
|
|
76474
76492
|
agentVersion: this.config.agentVersion ?? "0.0.0",
|
|
76475
76493
|
// __AV_VERSION__ is injected by esbuild from package.json at build time.
|
|
76476
76494
|
// Falls back to "0.0.0-dev" in non-bundled contexts (tests).
|
|
76477
|
-
pluginVersion: true ? "0.23.
|
|
76495
|
+
pluginVersion: true ? "0.23.55" : "0.0.0-dev"
|
|
76478
76496
|
});
|
|
76479
76497
|
this._telemetryReporter.startAutoFlush(3e4);
|
|
76480
76498
|
}
|
|
@@ -77331,13 +77349,13 @@ ${messageText}`;
|
|
|
77331
77349
|
* Returns the text unchanged when there is no attachment or the fetch fails —
|
|
77332
77350
|
* but a failure is LOGGED and announced in the text, never silent.
|
|
77333
77351
|
*/
|
|
77334
|
-
async _augmentWithAttachment(attachmentInfo, baseText, roomId) {
|
|
77352
|
+
async _augmentWithAttachment(attachmentInfo, baseText, roomId, senderDeviceId) {
|
|
77335
77353
|
if (!attachmentInfo) return baseText;
|
|
77336
77354
|
try {
|
|
77337
77355
|
const { filePath, decrypted } = await this._downloadAndDecryptAttachment(attachmentInfo);
|
|
77338
77356
|
const mime = String(attachmentInfo.mime ?? "application/octet-stream");
|
|
77339
77357
|
const name = String(attachmentInfo.filename ?? "attachment");
|
|
77340
|
-
if (roomId) this._recentRoomAttachments.set(roomId, { filePath, name, at: Date.now() });
|
|
77358
|
+
if (roomId) this._recentRoomAttachments.set(roomId, { filePath, name, at: Date.now(), senderDeviceId });
|
|
77341
77359
|
const textMimes = ["text/", "application/json", "application/xml", "application/csv"];
|
|
77342
77360
|
if (textMimes.some((m2) => mime.startsWith(m2))) {
|
|
77343
77361
|
const content = new TextDecoder().decode(decrypted);
|
|
@@ -77993,22 +78011,34 @@ ${baseText}`;
|
|
|
77993
78011
|
}
|
|
77994
78012
|
const caption = messageText;
|
|
77995
78013
|
const addressed = parseMentions(messageText).length > 0;
|
|
78014
|
+
const foldedFrom = [];
|
|
77996
78015
|
if (roomAttachment && !addressed) {
|
|
77997
|
-
this._deferRoomAttachment(resolvedRoomId, roomAttachment);
|
|
78016
|
+
this._deferRoomAttachment(resolvedRoomId, roomAttachment, senderDeviceId);
|
|
77998
78017
|
} else {
|
|
77999
78018
|
const deferred = addressed ? this._takeDeferredRoomAttachments(resolvedRoomId) : [];
|
|
78000
|
-
for (const
|
|
78001
|
-
messageText = await this._augmentWithAttachment(info, messageText, resolvedRoomId);
|
|
78019
|
+
for (const d2 of deferred) {
|
|
78020
|
+
messageText = await this._augmentWithAttachment(d2.info, messageText, resolvedRoomId, d2.senderDeviceId);
|
|
78021
|
+
foldedFrom.push(d2.senderDeviceId ?? null);
|
|
78002
78022
|
}
|
|
78003
78023
|
if (roomAttachment) {
|
|
78004
|
-
messageText = await this._augmentWithAttachment(roomAttachment, messageText, resolvedRoomId);
|
|
78024
|
+
messageText = await this._augmentWithAttachment(roomAttachment, messageText, resolvedRoomId, senderDeviceId);
|
|
78025
|
+
foldedFrom.push(senderDeviceId ?? null);
|
|
78005
78026
|
} else if (deferred.length === 0) {
|
|
78006
|
-
|
|
78027
|
+
const noted = this._withRecentRoomAttachmentNote(resolvedRoomId, messageText);
|
|
78028
|
+
messageText = noted.text;
|
|
78029
|
+
if (noted.from !== void 0) foldedFrom.push(noted.from);
|
|
78007
78030
|
}
|
|
78008
78031
|
}
|
|
78009
78032
|
const roomMembers = this._persisted?.rooms?.[resolvedRoomId]?.members ?? [];
|
|
78010
78033
|
const senderMember = roomMembers.find((m2) => m2.deviceId === senderDeviceId);
|
|
78011
78034
|
const senderIsAgent = senderMember?.entityType === "agent" ? true : senderMember?.entityType === "owner" || senderMember?.entityType === "human" ? false : void 0;
|
|
78035
|
+
const ownTenantId = this._deviceJwt ? this._decodeTenantIdForRecovery(this._deviceJwt) : null;
|
|
78036
|
+
const isOwnerMember = (deviceId) => {
|
|
78037
|
+
const member = deviceId ? roomMembers.find((m2) => m2.deviceId === deviceId) : void 0;
|
|
78038
|
+
return (member?.entityType === "owner" || member?.entityType === "human") && ownTenantId !== null && typeof member?.tenantId === "string" && member.tenantId.toLowerCase() === ownTenantId;
|
|
78039
|
+
};
|
|
78040
|
+
const senderIsOwner = senderIsAgent === false && isOwnerMember(senderDeviceId);
|
|
78041
|
+
const foreignContent = foldedFrom.some((from) => !isOwnerMember(from));
|
|
78012
78042
|
const metadata = {
|
|
78013
78043
|
messageId: data.message_id ?? "",
|
|
78014
78044
|
conversationId: "",
|
|
@@ -78017,6 +78047,8 @@ ${baseText}`;
|
|
|
78017
78047
|
roomId: resolvedRoomId,
|
|
78018
78048
|
senderDeviceId,
|
|
78019
78049
|
senderIsAgent,
|
|
78050
|
+
senderIsOwner,
|
|
78051
|
+
foreignContent,
|
|
78020
78052
|
senderName: senderMember?.displayName || "unknown",
|
|
78021
78053
|
roomName: this._persisted?.rooms?.[resolvedRoomId]?.name,
|
|
78022
78054
|
caption
|
|
@@ -78042,7 +78074,10 @@ ${baseText}`;
|
|
|
78042
78074
|
timestamp: data.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
78043
78075
|
// Bridges require an explicit human classification for room tools.
|
|
78044
78076
|
// Reply policy separately uses this field for agent-loop prevention.
|
|
78045
|
-
senderIsAgent
|
|
78077
|
+
senderIsAgent,
|
|
78078
|
+
// #1459 — owner-only power keys on these, never on senderIsAgent.
|
|
78079
|
+
senderIsOwner,
|
|
78080
|
+
foreignContent
|
|
78046
78081
|
});
|
|
78047
78082
|
const contextualMessage = senderIsAgent ? messageText : `[${senderLabel}]: ${messageText}`;
|
|
78048
78083
|
Promise.resolve(this.config.onMessage?.(contextualMessage, metadata)).catch((err) => {
|
|
@@ -102874,7 +102909,7 @@ data:
|
|
|
102874
102909
|
await init_policy_enforcer();
|
|
102875
102910
|
init_room_protocol();
|
|
102876
102911
|
init_tool_telemetry();
|
|
102877
|
-
VERSION = true ? "0.23.
|
|
102912
|
+
VERSION = true ? "0.23.55" : "0.0.0-dev";
|
|
102878
102913
|
}
|
|
102879
102914
|
});
|
|
102880
102915
|
await init_index();
|
|
@@ -103595,7 +103630,8 @@ var MuseSession = class {
|
|
|
103595
103630
|
text,
|
|
103596
103631
|
reply,
|
|
103597
103632
|
autoReplyOnText: opts?.replyExpected ?? opts?.autoReplyOnText,
|
|
103598
|
-
sayAllowed: opts?.replyExpected ?? true
|
|
103633
|
+
sayAllowed: opts?.replyExpected ?? true,
|
|
103634
|
+
ownerTurn: opts?.ownerTurn === true
|
|
103599
103635
|
});
|
|
103600
103636
|
if (!this.running) this.drain = this.run();
|
|
103601
103637
|
}
|
|
@@ -103646,7 +103682,7 @@ var MuseSession = class {
|
|
|
103646
103682
|
const prompt = this.opts.identity ? `${this.opts.identity}
|
|
103647
103683
|
|
|
103648
103684
|
${item.text}` : item.text;
|
|
103649
|
-
const result = await this.driver.runTurn(prompt);
|
|
103685
|
+
const result = await this.driver.runTurn(prompt, { ownerTurn: item.ownerTurn });
|
|
103650
103686
|
await this.maybeFallback(item, result);
|
|
103651
103687
|
} catch {
|
|
103652
103688
|
this.log("turn failed reason=driver");
|
|
@@ -103743,7 +103779,7 @@ function museSpawnArgs(opts) {
|
|
|
103743
103779
|
);
|
|
103744
103780
|
}
|
|
103745
103781
|
const provider = opts.provider ?? "meta";
|
|
103746
|
-
const ownerOn = opts.workAllowed === true && opts.gatesRemoved === true;
|
|
103782
|
+
const ownerOn = opts.workAllowed === true && opts.gatesRemoved === true && opts.ownerTurn === true;
|
|
103747
103783
|
const powerFlags = ownerOn ? ["--yolo"] : ["--disable-shell", "--disable-write"];
|
|
103748
103784
|
const args = [
|
|
103749
103785
|
"exec",
|
|
@@ -104019,6 +104055,7 @@ async function createMuseProviderAdapter(opts) {
|
|
|
104019
104055
|
|
|
104020
104056
|
// src/muse-driver.ts
|
|
104021
104057
|
var SESSION_FILE = "muse-session-id";
|
|
104058
|
+
var OWNER_SESSION_FILE = "muse-owner-session-id";
|
|
104022
104059
|
var DEFAULT_TURN_TIMEOUT_MS = 3e5;
|
|
104023
104060
|
var SIGKILL_GRACE_MS = 2e3;
|
|
104024
104061
|
var MuseDriver = class {
|
|
@@ -104031,37 +104068,33 @@ var MuseDriver = class {
|
|
|
104031
104068
|
spawnFn;
|
|
104032
104069
|
turnTimeoutMs;
|
|
104033
104070
|
persistedId = null;
|
|
104071
|
+
ownerId = null;
|
|
104034
104072
|
current = null;
|
|
104035
104073
|
child = null;
|
|
104036
104074
|
probed = false;
|
|
104037
104075
|
adapter = null;
|
|
104038
|
-
/** Load or create `<dataDir>/muse-session-id
|
|
104076
|
+
/** Load or create `<dataDir>/muse-session-id` and the owner lane's id. Does not spawn muse. */
|
|
104039
104077
|
async start() {
|
|
104040
104078
|
mkdirSync3(this.opts.dataDir, { recursive: true });
|
|
104041
|
-
|
|
104042
|
-
|
|
104043
|
-
const existing = readFileSync5(file, "utf8").trim();
|
|
104044
|
-
if (existing) {
|
|
104045
|
-
this.persistedId = existing;
|
|
104046
|
-
return existing;
|
|
104047
|
-
}
|
|
104048
|
-
}
|
|
104049
|
-
this.persistedId = randomUUID5();
|
|
104050
|
-
writeFileSync2(file, this.persistedId + "\n", { encoding: "utf8" });
|
|
104079
|
+
this.persistedId = loadOrMintId(join11(this.opts.dataDir, SESSION_FILE));
|
|
104080
|
+
this.ownerId = loadOrMintId(join11(this.opts.dataDir, OWNER_SESSION_FILE));
|
|
104051
104081
|
return this.persistedId;
|
|
104052
104082
|
}
|
|
104053
104083
|
sessionId() {
|
|
104054
104084
|
return this.persistedId;
|
|
104055
104085
|
}
|
|
104056
|
-
|
|
104057
|
-
|
|
104086
|
+
ownerSessionId() {
|
|
104087
|
+
return this.ownerId;
|
|
104088
|
+
}
|
|
104089
|
+
runTurn(prompt, opts = {}) {
|
|
104090
|
+
if (!this.persistedId || !this.ownerId) {
|
|
104058
104091
|
throw new Error("MuseDriver.runTurn before start()");
|
|
104059
104092
|
}
|
|
104060
104093
|
if (this.current || this.child) {
|
|
104061
104094
|
throw new Error("MuseDriver.runTurn called while a turn is in flight");
|
|
104062
104095
|
}
|
|
104063
104096
|
this.current = { spoke: false, cancelled: false };
|
|
104064
|
-
return this.executeTurn(prompt).finally(() => {
|
|
104097
|
+
return this.executeTurn(prompt, opts.ownerTurn === true).finally(() => {
|
|
104065
104098
|
this.current = null;
|
|
104066
104099
|
});
|
|
104067
104100
|
}
|
|
@@ -104084,8 +104117,8 @@ var MuseDriver = class {
|
|
|
104084
104117
|
const dead = await waitForExit(child, SIGKILL_GRACE_MS);
|
|
104085
104118
|
if (!dead) child.kill("SIGKILL");
|
|
104086
104119
|
}
|
|
104087
|
-
async executeTurn(prompt) {
|
|
104088
|
-
const sessionId = this.persistedId;
|
|
104120
|
+
async executeTurn(prompt, ownerTurn) {
|
|
104121
|
+
const sessionId = ownerTurn ? this.ownerId : this.persistedId;
|
|
104089
104122
|
if (!sessionId) {
|
|
104090
104123
|
throw new Error("MuseDriver.runTurn before start()");
|
|
104091
104124
|
}
|
|
@@ -104099,7 +104132,8 @@ var MuseDriver = class {
|
|
|
104099
104132
|
prompt,
|
|
104100
104133
|
apiKey: this.opts.apiKey,
|
|
104101
104134
|
workAllowed: readFlag(this.opts.workAllowed),
|
|
104102
|
-
gatesRemoved: readFlag(this.opts.gatesRemoved)
|
|
104135
|
+
gatesRemoved: readFlag(this.opts.gatesRemoved),
|
|
104136
|
+
ownerTurn
|
|
104103
104137
|
});
|
|
104104
104138
|
await this.probeUsable(spawn2);
|
|
104105
104139
|
if (this.current?.cancelled) throw new Error("muse turn stopped");
|
|
@@ -104252,6 +104286,15 @@ function defaultSpawn(command, args, options) {
|
|
|
104252
104286
|
stdio: ["ignore", "pipe", "pipe"]
|
|
104253
104287
|
});
|
|
104254
104288
|
}
|
|
104289
|
+
function loadOrMintId(file) {
|
|
104290
|
+
if (existsSync4(file)) {
|
|
104291
|
+
const existing = readFileSync5(file, "utf8").trim();
|
|
104292
|
+
if (existing) return existing;
|
|
104293
|
+
}
|
|
104294
|
+
const id = randomUUID5();
|
|
104295
|
+
writeFileSync2(file, id + "\n", { encoding: "utf8" });
|
|
104296
|
+
return id;
|
|
104297
|
+
}
|
|
104255
104298
|
function readFlag(value) {
|
|
104256
104299
|
return typeof value === "function" ? value() : value;
|
|
104257
104300
|
}
|
|
@@ -104805,6 +104848,7 @@ function attachLifecycle2(channel, opts = {}) {
|
|
|
104805
104848
|
if (/reconnect loop detected/i.test(msg)) terminal("reconnect_loop", true);
|
|
104806
104849
|
});
|
|
104807
104850
|
}
|
|
104851
|
+
var FILE_LOCK_NOTE = "[AgentVault: this turn has no commands and no file changes, because it includes a file another room member shared. If you were asked to run or change something, say so, and that it will work in a message that doesn't refer to that file, or in a 1:1 chat.]";
|
|
104808
104852
|
function roomTurnPrefix(roomId, senderName, roomName) {
|
|
104809
104853
|
return `[room ${roomLabel(roomId, roomName)} | ${sanitizeLabel(senderName)}]`;
|
|
104810
104854
|
}
|
|
@@ -104905,19 +104949,33 @@ function wireBridge(channel, session, target, opts = {}) {
|
|
|
104905
104949
|
log(`inbound from ${e.senderName} in ${e.roomId.slice(0, 8)}`);
|
|
104906
104950
|
target.setRoom(e.roomId);
|
|
104907
104951
|
const held = roomContext.peek(e.roomId);
|
|
104908
|
-
const contextBlock = formatRoomContext(held.entries, roomLabel(e.roomId, roomNames.get(e.roomId)), held.dropped);
|
|
104909
104952
|
const turnText = `${roomTurnPrefix(e.roomId, e.senderName, roomNames.get(e.roomId))}: ${e.plaintext}`;
|
|
104953
|
+
const ownerPowered = e.senderIsAgent === false && e.senderIsOwner === true && e.foreignContent === false && workAllowed() && gatesRemoved();
|
|
104954
|
+
const contextBlock = ownerPowered ? "" : formatRoomContext(held.entries, roomLabel(e.roomId, roomNames.get(e.roomId)), held.dropped);
|
|
104955
|
+
const fileLocked = e.senderIsOwner === true && e.foreignContent === true && workAllowed() && gatesRemoved();
|
|
104956
|
+
if (fileLocked) log(`room ${e.roomId.slice(0, 8)}: owner turn WITHOUT full access \u2014 it carries a file another member shared (#1459)`);
|
|
104957
|
+
const body = fileLocked ? `${turnText}
|
|
104958
|
+
|
|
104959
|
+
${FILE_LOCK_NOTE}` : turnText;
|
|
104910
104960
|
session.push(
|
|
104911
104961
|
contextBlock ? `${contextBlock}
|
|
104912
104962
|
|
|
104913
|
-
${
|
|
104963
|
+
${body}` : body,
|
|
104914
104964
|
target.snapshotReply(channel, log),
|
|
104915
104965
|
{
|
|
104916
104966
|
autoReplyOnText: false,
|
|
104917
|
-
replyExpected: owes
|
|
104967
|
+
replyExpected: owes,
|
|
104968
|
+
ownerTurn: ownerPowered
|
|
104918
104969
|
}
|
|
104919
104970
|
);
|
|
104920
|
-
if (
|
|
104971
|
+
if (ownerPowered) {
|
|
104972
|
+
log(`room ${e.roomId.slice(0, 8)}: owner turn with full access`);
|
|
104973
|
+
if (held.entries.length > 0) {
|
|
104974
|
+
log(
|
|
104975
|
+
`room ${e.roomId.slice(0, 8)}: ${held.entries.length} held message(s) kept for the next turn without full access (a full-access turn never carries room context)`
|
|
104976
|
+
);
|
|
104977
|
+
}
|
|
104978
|
+
} else if (held.entries.length > 0) {
|
|
104921
104979
|
roomContext.clear(e.roomId);
|
|
104922
104980
|
log(`room ${e.roomId.slice(0, 8)}: delivered ${held.entries.length} held message(s) as context with this turn`);
|
|
104923
104981
|
}
|
|
@@ -104931,7 +104989,10 @@ ${turnText}` : turnText,
|
|
|
104931
104989
|
log("inbound 1:1 DM from owner");
|
|
104932
104990
|
}
|
|
104933
104991
|
target.setDm(metadata?.conversationId, metadata?.conversationGroupId);
|
|
104934
|
-
session.push(text, target.snapshotReply(channel, log), {
|
|
104992
|
+
session.push(text, target.snapshotReply(channel, log), {
|
|
104993
|
+
autoReplyOnText: ownerAttested,
|
|
104994
|
+
ownerTurn: ownerAttested
|
|
104995
|
+
});
|
|
104935
104996
|
});
|
|
104936
104997
|
}
|
|
104937
104998
|
|
|
@@ -104989,7 +105050,7 @@ function mkdir700(path2) {
|
|
|
104989
105050
|
chmodSync5(path2, 448);
|
|
104990
105051
|
}
|
|
104991
105052
|
function packageVersion() {
|
|
104992
|
-
return true ? "0.1.
|
|
105053
|
+
return true ? "0.1.31" : void 0;
|
|
104993
105054
|
}
|
|
104994
105055
|
function helpText(version2) {
|
|
104995
105056
|
return [
|
package/dist/muse-driver.d.ts
CHANGED
|
@@ -40,15 +40,19 @@ export declare class MuseDriver {
|
|
|
40
40
|
private readonly spawnFn;
|
|
41
41
|
private readonly turnTimeoutMs;
|
|
42
42
|
private persistedId;
|
|
43
|
+
private ownerId;
|
|
43
44
|
private current;
|
|
44
45
|
private child;
|
|
45
46
|
private probed;
|
|
46
47
|
private adapter;
|
|
47
48
|
constructor(opts: MuseDriverOpts);
|
|
48
|
-
/** Load or create `<dataDir>/muse-session-id
|
|
49
|
+
/** Load or create `<dataDir>/muse-session-id` and the owner lane's id. Does not spawn muse. */
|
|
49
50
|
start(): Promise<string>;
|
|
50
51
|
sessionId(): string | null;
|
|
51
|
-
|
|
52
|
+
ownerSessionId(): string | null;
|
|
53
|
+
runTurn(prompt: string, opts?: {
|
|
54
|
+
ownerTurn?: boolean;
|
|
55
|
+
}): Promise<{
|
|
52
56
|
text: string;
|
|
53
57
|
spoke: boolean;
|
|
54
58
|
}>;
|
package/dist/muse-session.d.ts
CHANGED
|
@@ -2,10 +2,13 @@ export interface RoomSession {
|
|
|
2
2
|
push(text: string, reply?: (text: string) => Promise<void>, opts?: {
|
|
3
3
|
autoReplyOnText?: boolean;
|
|
4
4
|
replyExpected?: boolean;
|
|
5
|
+
ownerTurn?: boolean;
|
|
5
6
|
}): void;
|
|
6
7
|
}
|
|
7
8
|
export interface DriverLike {
|
|
8
|
-
runTurn(prompt: string
|
|
9
|
+
runTurn(prompt: string, opts?: {
|
|
10
|
+
ownerTurn?: boolean;
|
|
11
|
+
}): Promise<{
|
|
9
12
|
text: string;
|
|
10
13
|
spoke: boolean;
|
|
11
14
|
}>;
|
|
@@ -33,6 +36,7 @@ export declare class MuseSession implements RoomSession {
|
|
|
33
36
|
push(text: string, reply?: (text: string) => Promise<void>, opts?: {
|
|
34
37
|
autoReplyOnText?: boolean;
|
|
35
38
|
replyExpected?: boolean;
|
|
39
|
+
ownerTurn?: boolean;
|
|
36
40
|
}): void;
|
|
37
41
|
sayHandler(): (text: string) => void;
|
|
38
42
|
idle(): Promise<void>;
|
package/dist/muse-spawn.d.ts
CHANGED
|
@@ -14,6 +14,13 @@ export interface MuseSpawnOpts {
|
|
|
14
14
|
apiKey?: string;
|
|
15
15
|
workAllowed: boolean;
|
|
16
16
|
gatesRemoved: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* #1459 — this turn came from the owner: an owner-attested 1:1 DM, or a room
|
|
19
|
+
* message whose sender SecureChannel placed in this agent's own account.
|
|
20
|
+
* Owner power needs all three; the owner's switches alone used to grant it
|
|
21
|
+
* to whoever @-mentioned the agent.
|
|
22
|
+
*/
|
|
23
|
+
ownerTurn: boolean;
|
|
17
24
|
}
|
|
18
25
|
export interface MuseSpawnEnv {
|
|
19
26
|
HOME: string;
|
package/package.json
CHANGED