letagents 0.12.11 → 0.12.13
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/mcp/git-remote.js +7 -7
- package/dist/mcp/local-state/agent-sessions.js +78 -5
- package/dist/mcp/local-state/local-chat.js +189 -48
- package/dist/mcp/local-state/storage.js +16 -9
- package/dist/mcp/server/daemon-tool-executor.js +92 -0
- package/dist/mcp/server/register-tools.js +25 -12
- package/dist/mcp/server/runtime/agent-sessions.js +58 -9
- package/dist/mcp/server/runtime/api.js +40 -4
- package/dist/mcp/server/runtime/daemon-tool-context.js +11 -0
- package/dist/mcp/server/runtime/execution-profile.js +19 -0
- package/dist/mcp/server/runtime/identity/directory.js +2 -2
- package/dist/mcp/server/runtime/messages.js +55 -0
- 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 +59 -3
- package/dist/mcp/server/runtime/rooms.js +67 -32
- package/dist/mcp/server/runtime/supervised-room-authority.js +8 -0
- package/dist/mcp/server/runtime/supervisor-bridge.js +702 -24
- package/dist/mcp/server/runtime/tool-surface-policy.js +26 -0
- package/dist/mcp/server/runtime/worker-bearer.js +44 -6
- package/dist/mcp/server/runtime-contract.js +27 -0
- package/dist/mcp/server/runtime.js +15 -4
- package/dist/mcp/server/supervised-tool-facade.js +134 -0
- package/dist/mcp/server/tools/agent-sessions.js +74 -7
- package/dist/mcp/server/tools/messages/index.js +3 -2
- package/dist/mcp/server/tools/messages/read-tool.js +54 -97
- package/dist/mcp/server/tools/messages/reasoning-tool.js +2 -0
- package/dist/mcp/server/tools/messages/send-tool.js +5 -0
- package/dist/mcp/server/tools/messages/status-tool.js +2 -0
- package/dist/mcp/server/tools/messages/wait-tool.js +344 -71
- package/dist/mcp/server/tools/onboarding/status-tool.js +9 -8
- package/dist/mcp/server/tools/rooms/inspection-tools.js +40 -22
- package/dist/mcp/server/tools/rooms/repo-initialization-tool.js +2 -1
- package/dist/mcp/server/tools/supervised-room-turn.js +42 -0
- package/dist/mcp/server/tools/tasks/board-tools.js +34 -2
- package/dist/mcp/server.js +14 -7
- package/dist/mcp/sse-client.js +163 -20
- package/dist/shared/activation-routing.js +187 -20
- package/dist/shared/agent-presence.js +6 -0
- package/dist/shared/desktop-release-manifest.js +63 -0
- package/dist/shared/desktop-release.js +60 -0
- package/dist/shared/scoped-ids.js +6 -0
- package/package.json +11 -3
- package/shared/message-contracts.d.mts +32 -0
- package/shared/message-contracts.mjs +109 -0
- package/shared/routing-aliases.d.mts +18 -0
- package/shared/routing-aliases.mjs +66 -0
- package/shared/sqlite-thread-routing.d.mts +72 -0
- package/shared/sqlite-thread-routing.mjs +1038 -0
|
@@ -9,7 +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 { requireValidWorkerBearerRuntime } from "./worker-bearer.js";
|
|
12
|
+
import { isSupervisedBoundedTurn, requireValidWorkerBearerRuntime } from "./worker-bearer.js";
|
|
13
13
|
export function normalizeJoinSessionMode(value) {
|
|
14
14
|
return String(value || "").trim().toLowerCase() === "live" ? "live" : "current";
|
|
15
15
|
}
|
|
@@ -20,7 +20,7 @@ function isNotFoundApiError(error) {
|
|
|
20
20
|
return error instanceof ApiError && error.status === 404;
|
|
21
21
|
}
|
|
22
22
|
function parseGeneratedGitRefRoomIdentifier(identifier) {
|
|
23
|
-
const match = /^
|
|
23
|
+
const match = /^github\.com\/([^/\s]+\/[^/\s]+)\/focus\/git:(branch|tag):[A-Za-z0-9_-]+$/.exec(identifier.trim());
|
|
24
24
|
if (!match) {
|
|
25
25
|
return null;
|
|
26
26
|
}
|
|
@@ -30,6 +30,9 @@ function parseGeneratedGitRefRoomIdentifier(identifier) {
|
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
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
|
+
}
|
|
33
36
|
const roomId = joinedVia === "join_code" ? normalizeInviteCode(identifier) : identifier.trim();
|
|
34
37
|
if (joinedVia !== "join_code" && await isLocalRoomStorageEnabled(roomId)) {
|
|
35
38
|
if (options.allowCreate === false && !getStoredRoomSession(roomId)) {
|
|
@@ -64,6 +67,7 @@ export async function joinRoomIdentifier(identifier, joinedVia, options = {}) {
|
|
|
64
67
|
const agentIdentity = await ensureAgentIdentity();
|
|
65
68
|
const room = rememberRoom(toRoomState({
|
|
66
69
|
room_id: joinedRoomId,
|
|
70
|
+
navigation_locator: joinedRoomId === roomId ? null : roomId,
|
|
67
71
|
project_id: typeof response.project_id === "string" ? response.project_id : null,
|
|
68
72
|
code: typeof response.code === "string"
|
|
69
73
|
? response.code
|
|
@@ -187,6 +191,9 @@ export async function joinRoomIdentifierWithoutImplicitGitRefCreate(identifier,
|
|
|
187
191
|
}));
|
|
188
192
|
}
|
|
189
193
|
export async function createInviteRoom() {
|
|
194
|
+
if (isSupervisedBoundedTurn()) {
|
|
195
|
+
throw new Error("Room joins and creation are disabled during a daemon-supervised bounded turn.");
|
|
196
|
+
}
|
|
190
197
|
const project = await apiCall("/projects", { method: "POST" });
|
|
191
198
|
const roomId = typeof project.code === "string"
|
|
192
199
|
? project.code
|
|
@@ -254,7 +261,27 @@ export async function joinNamedRoom(name, sessionMode) {
|
|
|
254
261
|
session_mode: sessionMode,
|
|
255
262
|
});
|
|
256
263
|
}
|
|
257
|
-
function
|
|
264
|
+
async function bindWorkerRoomLocator(roomLocator, source) {
|
|
265
|
+
const response = await apiCall(`/rooms/resolve/${encodeURIComponent(roomLocator)}`);
|
|
266
|
+
if (response.room_exists !== true) {
|
|
267
|
+
throw new ApiError(404, JSON.stringify({ error: "Room not found", code: "ROOM_NOT_FOUND" }));
|
|
268
|
+
}
|
|
269
|
+
const roomId = typeof response.canonical_room_id === "string"
|
|
270
|
+
? response.canonical_room_id
|
|
271
|
+
: roomLocator;
|
|
272
|
+
return {
|
|
273
|
+
room: rememberRoom(toRoomState({
|
|
274
|
+
room_id: roomId,
|
|
275
|
+
navigation_locator: roomId === roomLocator ? null : roomLocator,
|
|
276
|
+
project_id: roomId,
|
|
277
|
+
display_name: roomId,
|
|
278
|
+
git_room: response.git_room ?? null,
|
|
279
|
+
joined_via: source === ".letagents.json" ? "config" : "git-remote",
|
|
280
|
+
})),
|
|
281
|
+
source,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
async function bindWorkerRoomFromContext() {
|
|
258
285
|
const configRoom = getRoomFromConfig();
|
|
259
286
|
if (configRoom) {
|
|
260
287
|
const gitContext = buildActiveGitRoomContext({
|
|
@@ -262,26 +289,26 @@ function bindWorkerRoomFromContext() {
|
|
|
262
289
|
currentBranch: getGitCurrentBranch(),
|
|
263
290
|
defaultBranch: getGitDefaultBranch(),
|
|
264
291
|
});
|
|
265
|
-
const roomId = gitContext.
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
292
|
+
const roomId = gitContext.activeRoomLocator ?? configRoom;
|
|
293
|
+
try {
|
|
294
|
+
return await bindWorkerRoomLocator(roomId, ".letagents.json");
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
if (roomId === configRoom || !isNotFoundApiError(error))
|
|
298
|
+
throw error;
|
|
299
|
+
return bindWorkerRoomLocator(configRoom, ".letagents.json");
|
|
300
|
+
}
|
|
274
301
|
}
|
|
275
302
|
const gitContext = getGitRoomContext();
|
|
276
|
-
if (gitContext.
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
303
|
+
if (gitContext.activeRoomLocator) {
|
|
304
|
+
try {
|
|
305
|
+
return await bindWorkerRoomLocator(gitContext.activeRoomLocator, "git remote");
|
|
306
|
+
}
|
|
307
|
+
catch (error) {
|
|
308
|
+
if (!gitContext.repoRoom || !isNotFoundApiError(error))
|
|
309
|
+
throw error;
|
|
310
|
+
return bindWorkerRoomLocator(gitContext.repoRoom, "git remote");
|
|
311
|
+
}
|
|
285
312
|
}
|
|
286
313
|
const savedCurrentRoom = getStoredCurrentRoom();
|
|
287
314
|
if (!savedCurrentRoom) {
|
|
@@ -301,10 +328,18 @@ function bindWorkerRoomFromContext() {
|
|
|
301
328
|
}
|
|
302
329
|
export async function autoJoinFromContext() {
|
|
303
330
|
try {
|
|
304
|
-
|
|
305
|
-
|
|
331
|
+
const workerRuntime = requireValidWorkerBearerRuntime();
|
|
332
|
+
if (workerRuntime.mode === "supervised") {
|
|
333
|
+
// The exact room may change after a durable daemon-owned room move.
|
|
334
|
+
// Bind it per tool effect from the supervisor response, never from
|
|
335
|
+
// ambient repository, persisted state, or launch-time environment.
|
|
336
|
+
console.error("ℹ️ Daemon-supervised bounded turn leaves room selection to its exact supervisor context.");
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (workerRuntime.mode === "worker") {
|
|
340
|
+
const bound = await bindWorkerRoomFromContext();
|
|
306
341
|
if (bound) {
|
|
307
|
-
console.error(`🏠 Bound worker bearer to room '${bound.room.room_id}' (from ${bound.source}
|
|
342
|
+
console.error(`🏠 Bound worker bearer to existing room '${bound.room.room_id}' (from ${bound.source}).`);
|
|
308
343
|
}
|
|
309
344
|
else {
|
|
310
345
|
console.error("ℹ️ Worker bearer has no .letagents.json, git remote, or saved room to bind locally.");
|
|
@@ -318,17 +353,17 @@ export async function autoJoinFromContext() {
|
|
|
318
353
|
currentBranch: getGitCurrentBranch(),
|
|
319
354
|
defaultBranch: getGitDefaultBranch(),
|
|
320
355
|
});
|
|
321
|
-
if (gitContext.
|
|
322
|
-
const joinedBranchRoom = await joinExistingRoomIdentifier(gitContext.
|
|
356
|
+
if (gitContext.activeRefRoomLocator && gitContext.currentBranch) {
|
|
357
|
+
const joinedBranchRoom = await joinExistingRoomIdentifier(gitContext.activeRefRoomLocator, "config");
|
|
323
358
|
if (joinedBranchRoom) {
|
|
324
359
|
await ensureAgentIdentity();
|
|
325
|
-
console.error(`🏠 Auto-joined existing branch room '${gitContext.
|
|
360
|
+
console.error(`🏠 Auto-joined existing branch room '${gitContext.activeRefRoomLocator}' (from .letagents.json + branch '${gitContext.currentBranch}')`);
|
|
326
361
|
return;
|
|
327
362
|
}
|
|
328
363
|
}
|
|
329
364
|
await joinRoomIdentifier(configRoom, "config");
|
|
330
365
|
await ensureAgentIdentity();
|
|
331
|
-
const branchNote = gitContext.
|
|
366
|
+
const branchNote = gitContext.activeRefRoomLocator && gitContext.currentBranch
|
|
332
367
|
? `; branch '${gitContext.currentBranch}' has no existing Git Room`
|
|
333
368
|
: "";
|
|
334
369
|
console.error(`🏠 Auto-joined room '${configRoom}' (from .letagents.json${branchNote})`);
|
|
@@ -336,17 +371,17 @@ export async function autoJoinFromContext() {
|
|
|
336
371
|
}
|
|
337
372
|
const gitContext = getGitRoomContext();
|
|
338
373
|
if (gitContext.repoRoom) {
|
|
339
|
-
if (gitContext.
|
|
340
|
-
const joinedBranchRoom = await joinExistingRoomIdentifier(gitContext.
|
|
374
|
+
if (gitContext.activeRefRoomLocator && gitContext.currentBranch) {
|
|
375
|
+
const joinedBranchRoom = await joinExistingRoomIdentifier(gitContext.activeRefRoomLocator, "git-remote");
|
|
341
376
|
if (joinedBranchRoom) {
|
|
342
377
|
await ensureAgentIdentity();
|
|
343
|
-
console.error(`🏠 Auto-joined existing branch room '${gitContext.
|
|
378
|
+
console.error(`🏠 Auto-joined existing branch room '${gitContext.activeRefRoomLocator}' (inferred from git remote and branch '${gitContext.currentBranch}' — consider adding a .letagents.json)`);
|
|
344
379
|
return;
|
|
345
380
|
}
|
|
346
381
|
}
|
|
347
382
|
await joinRoomIdentifier(gitContext.repoRoom, "git-remote");
|
|
348
383
|
await ensureAgentIdentity();
|
|
349
|
-
const branchNote = gitContext.
|
|
384
|
+
const branchNote = gitContext.activeRefRoomLocator && gitContext.currentBranch
|
|
350
385
|
? `; branch '${gitContext.currentBranch}' has no existing Git Room`
|
|
351
386
|
: "";
|
|
352
387
|
console.error(`🏠 Auto-joined room '${gitContext.repoRoom}' (inferred from git remote${branchNote} — consider adding a .letagents.json)`);
|
|
@@ -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
|
+
}
|