letagents 0.12.10 → 0.12.12
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/README.md +2 -0
- package/dist/api/board-intent-payloads.js +25 -0
- package/dist/mcp/codex-session/runtime-bridge.js +42 -25
- package/dist/mcp/local-state/agent-sessions.js +15 -0
- package/dist/mcp/local-state/local-chat.js +1 -1
- package/dist/mcp/rental-tools/context.js +30 -0
- package/dist/mcp/server/register-tools.js +23 -12
- package/dist/mcp/server/runtime/agent-sessions.js +81 -2
- package/dist/mcp/server/runtime/api.js +63 -13
- package/dist/mcp/server/runtime/execution-profile.js +19 -0
- package/dist/mcp/server/runtime/identity/directory.js +9 -2
- package/dist/mcp/server/runtime/identity.js +2 -1
- package/dist/mcp/server/runtime/presence.js +4 -2
- package/dist/mcp/server/runtime/room-api.js +24 -7
- package/dist/mcp/server/runtime/room-state.js +46 -0
- package/dist/mcp/server/runtime/rooms.js +70 -0
- package/dist/mcp/server/runtime/supervised-room-authority.js +8 -0
- package/dist/mcp/server/runtime/supervisor-bridge.js +731 -0
- package/dist/mcp/server/runtime/tool-surface-policy.js +26 -0
- package/dist/mcp/server/runtime/worker-bearer.js +101 -0
- package/dist/mcp/server/runtime-contract.js +27 -0
- package/dist/mcp/server/runtime.js +14 -3
- package/dist/mcp/server/supervised-tool-facade.js +105 -0
- package/dist/mcp/server/tools/agent-sessions.js +113 -5
- package/dist/mcp/server/tools/messages/index.js +3 -2
- package/dist/mcp/server/tools/messages/message-lookup.js +75 -0
- package/dist/mcp/server/tools/messages/read-tool.js +1 -1
- package/dist/mcp/server/tools/messages/send-tool.js +5 -45
- package/dist/mcp/server/tools/messages/wait-tool.js +212 -91
- package/dist/mcp/server/tools/onboarding/device-auth-tools.js +10 -0
- package/dist/mcp/server/tools/onboarding/name-tool.js +5 -1
- package/dist/mcp/server/tools/onboarding/status-tool.js +18 -0
- package/dist/mcp/server/tools/rental/context-tools.js +9 -1
- package/dist/mcp/server/tools/rooms/inspection-tools.js +47 -18
- package/dist/mcp/server/tools/supervised-room-turn.js +42 -0
- package/dist/mcp/server/tools/tasks/board-intent-tools.js +7 -2
- package/dist/mcp/server/tools/tasks/index.js +2 -0
- package/dist/mcp/server/tools/tasks/verdict-tools.js +51 -0
- package/dist/mcp/server.js +16 -7
- package/dist/mcp/sse-client.js +3 -3
- package/dist/shared/activation-routing.js +57 -4
- package/dist/shared/agent-presence.js +1 -0
- package/dist/shared/agent-session-bearer.js +28 -0
- package/dist/shared/board-manager-failover.js +16 -0
- package/dist/shared/room-agent-prompts.js +2 -2
- package/package.json +24 -15
|
@@ -3,6 +3,8 @@ import { getStoredAgentIdentity, saveRoomSession, touchRoomSession, } from "../.
|
|
|
3
3
|
import { getCanonicalRoomWebPath, } from "../../room-id.js";
|
|
4
4
|
import { API_URL, getLetagentsToken } from "./api.js";
|
|
5
5
|
import { AGENT_INSTANCE_UUID, currentAgentIdentity, currentAgentIdentityKey, } from "./identity.js";
|
|
6
|
+
import { isSupervisedBoundedTurn } from "./worker-bearer.js";
|
|
7
|
+
import { getCurrentSupervisedRoomAuthority, runWithSupervisedRoomAuthority, } from "./supervised-room-authority.js";
|
|
6
8
|
let mcpServer = null;
|
|
7
9
|
let sseClient = null;
|
|
8
10
|
export let currentRoom = null;
|
|
@@ -85,6 +87,8 @@ export function toPublicRoomResponse(response, fallbackRoomId) {
|
|
|
85
87
|
}
|
|
86
88
|
export function rememberRoom(state, lastMessageId) {
|
|
87
89
|
currentRoom = state;
|
|
90
|
+
if (isSupervisedBoundedTurn())
|
|
91
|
+
return state;
|
|
88
92
|
saveRoomSession({
|
|
89
93
|
room_id: state.room_id,
|
|
90
94
|
project_id: state.project_id ?? null,
|
|
@@ -109,14 +113,56 @@ export function rememberRoom(state, lastMessageId) {
|
|
|
109
113
|
return state;
|
|
110
114
|
}
|
|
111
115
|
export function touchCurrentRoom(lastMessageId) {
|
|
116
|
+
if (isSupervisedBoundedTurn())
|
|
117
|
+
return;
|
|
112
118
|
if (!currentRoom) {
|
|
113
119
|
return;
|
|
114
120
|
}
|
|
115
121
|
touchRoomSession(currentRoom.room_id, lastMessageId);
|
|
116
122
|
}
|
|
117
123
|
export function getTargetRoomId(roomId) {
|
|
124
|
+
if (isSupervisedBoundedTurn()) {
|
|
125
|
+
const exactRoomAuthority = getCurrentSupervisedRoomAuthority();
|
|
126
|
+
if (!exactRoomAuthority) {
|
|
127
|
+
throw new Error("The daemon-supervised tool has not received its exact room authority.");
|
|
128
|
+
}
|
|
129
|
+
if (roomId && roomId !== exactRoomAuthority) {
|
|
130
|
+
throw new Error(`The daemon-supervised tool is authorized for ${exactRoomAuthority}, not ${roomId}.`);
|
|
131
|
+
}
|
|
132
|
+
return exactRoomAuthority;
|
|
133
|
+
}
|
|
118
134
|
return roomId || currentRoom?.room_id || null;
|
|
119
135
|
}
|
|
136
|
+
/** The last room authority returned by this process's exact daemon effect. */
|
|
137
|
+
export { getCurrentSupervisedRoomAuthority } from "./supervised-room-authority.js";
|
|
138
|
+
/** Public room metadata without inventing join provenance or locality. */
|
|
139
|
+
export function toPublicCurrentRoomState() {
|
|
140
|
+
const exactRoomAuthority = getCurrentSupervisedRoomAuthority();
|
|
141
|
+
if (!exactRoomAuthority)
|
|
142
|
+
return toPublicRoomState(currentRoom);
|
|
143
|
+
return {
|
|
144
|
+
...toPublicRoomState(toRoomState({ room_id: exactRoomAuthority, joined_via: "join_room" })),
|
|
145
|
+
joined_via: null,
|
|
146
|
+
is_local: null,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Bind only the in-memory default used by one supervised MCP process. The
|
|
151
|
+
* daemon response is the authority; this performs no join, storage, SSE, or
|
|
152
|
+
* repository inspection and can safely rebind after a durable room move.
|
|
153
|
+
*/
|
|
154
|
+
export function runWithCurrentSupervisedRoom(roomId, callback) {
|
|
155
|
+
if (!isSupervisedBoundedTurn()) {
|
|
156
|
+
throw new Error("Only a daemon-supervised bounded turn can bind supervisor room authority.");
|
|
157
|
+
}
|
|
158
|
+
const normalized = roomId.trim();
|
|
159
|
+
if (!normalized || normalized.length > 1_024 || /[\u0000-\u001f\u007f]/.test(normalized)) {
|
|
160
|
+
throw new Error("The daemon-supervised room authority is malformed.");
|
|
161
|
+
}
|
|
162
|
+
return runWithSupervisedRoomAuthority(normalized, callback);
|
|
163
|
+
}
|
|
120
164
|
export function getFallbackProjectId() {
|
|
165
|
+
if (isSupervisedBoundedTurn())
|
|
166
|
+
return null;
|
|
121
167
|
return currentRoom?.project_id ?? null;
|
|
122
168
|
}
|
|
@@ -9,6 +9,7 @@ import { ensureAgentIdentity, toPublicAgentIdentity, withAgentIdentity, } from "
|
|
|
9
9
|
import { withJoinRoomAgentPrompt } from "./messages.js";
|
|
10
10
|
import { syncRoomPresence } from "./presence.js";
|
|
11
11
|
import { rememberRoom, toPublicRoomResponse, toRoomState, } from "./room-state.js";
|
|
12
|
+
import { isSupervisedBoundedTurn, requireValidWorkerBearerRuntime } from "./worker-bearer.js";
|
|
12
13
|
export function normalizeJoinSessionMode(value) {
|
|
13
14
|
return String(value || "").trim().toLowerCase() === "live" ? "live" : "current";
|
|
14
15
|
}
|
|
@@ -29,6 +30,9 @@ function parseGeneratedGitRefRoomIdentifier(identifier) {
|
|
|
29
30
|
};
|
|
30
31
|
}
|
|
31
32
|
export async function joinRoomIdentifier(identifier, joinedVia, options = {}) {
|
|
33
|
+
if (isSupervisedBoundedTurn()) {
|
|
34
|
+
throw new Error("Room joins and creation are disabled during a daemon-supervised bounded turn.");
|
|
35
|
+
}
|
|
32
36
|
const roomId = joinedVia === "join_code" ? normalizeInviteCode(identifier) : identifier.trim();
|
|
33
37
|
if (joinedVia !== "join_code" && await isLocalRoomStorageEnabled(roomId)) {
|
|
34
38
|
if (options.allowCreate === false && !getStoredRoomSession(roomId)) {
|
|
@@ -186,6 +190,9 @@ export async function joinRoomIdentifierWithoutImplicitGitRefCreate(identifier,
|
|
|
186
190
|
}));
|
|
187
191
|
}
|
|
188
192
|
export async function createInviteRoom() {
|
|
193
|
+
if (isSupervisedBoundedTurn()) {
|
|
194
|
+
throw new Error("Room joins and creation are disabled during a daemon-supervised bounded turn.");
|
|
195
|
+
}
|
|
189
196
|
const project = await apiCall("/projects", { method: "POST" });
|
|
190
197
|
const roomId = typeof project.code === "string"
|
|
191
198
|
? project.code
|
|
@@ -253,8 +260,71 @@ export async function joinNamedRoom(name, sessionMode) {
|
|
|
253
260
|
session_mode: sessionMode,
|
|
254
261
|
});
|
|
255
262
|
}
|
|
263
|
+
function bindWorkerRoomFromContext() {
|
|
264
|
+
const configRoom = getRoomFromConfig();
|
|
265
|
+
if (configRoom) {
|
|
266
|
+
const gitContext = buildActiveGitRoomContext({
|
|
267
|
+
repoRoom: configRoom,
|
|
268
|
+
currentBranch: getGitCurrentBranch(),
|
|
269
|
+
defaultBranch: getGitDefaultBranch(),
|
|
270
|
+
});
|
|
271
|
+
const roomId = gitContext.activeRoom ?? configRoom;
|
|
272
|
+
return {
|
|
273
|
+
room: rememberRoom(toRoomState({
|
|
274
|
+
room_id: roomId,
|
|
275
|
+
display_name: roomId,
|
|
276
|
+
joined_via: "config",
|
|
277
|
+
})),
|
|
278
|
+
source: ".letagents.json",
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
const gitContext = getGitRoomContext();
|
|
282
|
+
if (gitContext.activeRoom) {
|
|
283
|
+
return {
|
|
284
|
+
room: rememberRoom(toRoomState({
|
|
285
|
+
room_id: gitContext.activeRoom,
|
|
286
|
+
display_name: gitContext.activeRoom,
|
|
287
|
+
joined_via: "git-remote",
|
|
288
|
+
})),
|
|
289
|
+
source: "git remote",
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
const savedCurrentRoom = getStoredCurrentRoom();
|
|
293
|
+
if (!savedCurrentRoom) {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
return {
|
|
297
|
+
room: rememberRoom(toRoomState({
|
|
298
|
+
room_id: savedCurrentRoom.room_id,
|
|
299
|
+
project_id: savedCurrentRoom.project_id,
|
|
300
|
+
code: savedCurrentRoom.code,
|
|
301
|
+
display_name: savedCurrentRoom.display_name,
|
|
302
|
+
git_room: savedCurrentRoom.git_room,
|
|
303
|
+
joined_via: savedCurrentRoom.joined_via,
|
|
304
|
+
})),
|
|
305
|
+
source: "saved local room state",
|
|
306
|
+
};
|
|
307
|
+
}
|
|
256
308
|
export async function autoJoinFromContext() {
|
|
257
309
|
try {
|
|
310
|
+
const workerRuntime = requireValidWorkerBearerRuntime();
|
|
311
|
+
if (workerRuntime.mode === "supervised") {
|
|
312
|
+
// The exact room may change after a durable daemon-owned room move.
|
|
313
|
+
// Bind it per tool effect from the supervisor response, never from
|
|
314
|
+
// ambient repository, persisted state, or launch-time environment.
|
|
315
|
+
console.error("ℹ️ Daemon-supervised bounded turn leaves room selection to its exact supervisor context.");
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (workerRuntime.mode === "worker") {
|
|
319
|
+
const bound = bindWorkerRoomFromContext();
|
|
320
|
+
if (bound) {
|
|
321
|
+
console.error(`🏠 Bound worker bearer to room '${bound.room.room_id}' (from ${bound.source}; no join/create request).`);
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
console.error("ℹ️ Worker bearer has no .letagents.json, git remote, or saved room to bind locally.");
|
|
325
|
+
}
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
258
328
|
const configRoom = getRoomFromConfig();
|
|
259
329
|
if (configRoom) {
|
|
260
330
|
const gitContext = buildActiveGitRoomContext({
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
const exactRoomAuthority = new AsyncLocalStorage();
|
|
3
|
+
export function getCurrentSupervisedRoomAuthority() {
|
|
4
|
+
return exactRoomAuthority.getStore() ?? null;
|
|
5
|
+
}
|
|
6
|
+
export function runWithSupervisedRoomAuthority(roomId, callback) {
|
|
7
|
+
return exactRoomAuthority.run(roomId, callback);
|
|
8
|
+
}
|