@akira-tl/forgerelay 0.8.3 → 0.8.5
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/CHANGELOG.md +25 -0
- package/README.md +2 -0
- package/capabilities/workspace-tasks/GUIDE.md +23 -2
- package/dist/capability-registry.js +15 -1
- package/dist/config.js +11 -0
- package/dist/remote-workspace-relay.js +160 -17
- package/dist/server.js +334 -51
- package/dist/workspace-task-reminders.js +42 -0
- package/dist/workspace-tasks.js +69 -0
- package/dist/workspaces.js +62 -30
- package/docs/chatgpt-coding-workflow.md +13 -3
- package/docs/configuration.md +46 -11
- package/package.json +5 -2
- package/scripts/debug/accept.mjs +178 -18
- package/scripts/debug/relay-accept.mjs +890 -0
- package/scripts/wiki/sync.mjs +246 -0
package/dist/server.js
CHANGED
|
@@ -53,6 +53,7 @@ import { ACTIVITY_PANEL_APP_LEGACY_URI, ACTIVITY_PANEL_APP_URI_TEMPLATE, MCP_APP
|
|
|
53
53
|
import { shutdownHttpServer } from "./server-shutdown.js";
|
|
54
54
|
import { formatPathForPrompt } from "./skills.js";
|
|
55
55
|
import { createWorkspaceStore } from "./workspace-store.js";
|
|
56
|
+
import { WorkspaceTaskReminderTracker } from "./workspace-task-reminders.js";
|
|
56
57
|
import { WorkspaceTaskStore } from "./workspace-tasks.js";
|
|
57
58
|
import { formatAgentsPath, WorkspaceRegistry } from "./workspaces.js";
|
|
58
59
|
import { formatAvailableSubagentProfile, summarizeSubagentProfile } from "./subagents/profiles.js";
|
|
@@ -259,6 +260,84 @@ const workspaceInventoryPageOutputSchema = z.object({
|
|
|
259
260
|
limit: z.number().int().positive(),
|
|
260
261
|
hasMore: z.boolean(),
|
|
261
262
|
});
|
|
263
|
+
const workspaceTaskInspectionSummaryOutputSchema = z.object({
|
|
264
|
+
level: z.literal("summary"),
|
|
265
|
+
version: z.literal(1),
|
|
266
|
+
revision: z.number().int().nonnegative(),
|
|
267
|
+
lists: z.array(z.object({
|
|
268
|
+
id: z.string(),
|
|
269
|
+
name: z.string(),
|
|
270
|
+
state: z.enum(["active", "archived"]),
|
|
271
|
+
revision: z.number().int().positive(),
|
|
272
|
+
taskCount: z.number().int().nonnegative(),
|
|
273
|
+
unfinishedTaskCount: z.number().int().nonnegative(),
|
|
274
|
+
})),
|
|
275
|
+
});
|
|
276
|
+
const workspaceInspectionMemberOutputSchema = z.object({
|
|
277
|
+
name: z.string(),
|
|
278
|
+
purpose: z.string(),
|
|
279
|
+
workspaceId: z.string(),
|
|
280
|
+
known: z.boolean(),
|
|
281
|
+
location: z.enum(["local", "relay"]).optional(),
|
|
282
|
+
state: z.enum(["active", "stale", "invalid", "closed"]).optional(),
|
|
283
|
+
status: z.string().optional(),
|
|
284
|
+
routeState: z.literal("known").optional(),
|
|
285
|
+
mode: z.enum(["checkout", "worktree"]).optional(),
|
|
286
|
+
rootValid: z.boolean().optional(),
|
|
287
|
+
});
|
|
288
|
+
const workspaceInspectionOutputSchema = z.union([
|
|
289
|
+
z.object({
|
|
290
|
+
workspaceId: z.string(),
|
|
291
|
+
kind: z.literal("workspace"),
|
|
292
|
+
location: z.literal("local"),
|
|
293
|
+
label: z.string(),
|
|
294
|
+
root: z.string(),
|
|
295
|
+
status: z.string(),
|
|
296
|
+
state: z.enum(["active", "stale", "invalid", "closed"]),
|
|
297
|
+
mode: z.enum(["checkout", "worktree"]),
|
|
298
|
+
sourceRoot: z.string().optional(),
|
|
299
|
+
branch: z.string().optional(),
|
|
300
|
+
targetBranch: z.string().optional(),
|
|
301
|
+
managed: z.boolean(),
|
|
302
|
+
createdAt: z.string(),
|
|
303
|
+
lastUsedAt: z.string(),
|
|
304
|
+
idleMs: z.number().nonnegative(),
|
|
305
|
+
rootValid: z.boolean(),
|
|
306
|
+
taskSummary: workspaceTaskInspectionSummaryOutputSchema.optional(),
|
|
307
|
+
}),
|
|
308
|
+
z.object({
|
|
309
|
+
workspaceId: z.string(),
|
|
310
|
+
kind: z.literal("workspace"),
|
|
311
|
+
location: z.literal("relay"),
|
|
312
|
+
root: z.string(),
|
|
313
|
+
routeState: z.literal("known"),
|
|
314
|
+
status: z.string().optional(),
|
|
315
|
+
state: z.enum(["active", "stale", "invalid", "closed"]).optional(),
|
|
316
|
+
mode: z.enum(["checkout", "worktree"]),
|
|
317
|
+
sourceRoot: z.string().optional(),
|
|
318
|
+
branch: z.string().optional(),
|
|
319
|
+
targetBranch: z.string().optional(),
|
|
320
|
+
managed: z.boolean().optional(),
|
|
321
|
+
createdAt: z.string().optional(),
|
|
322
|
+
lastUsedAt: z.string().optional(),
|
|
323
|
+
idleMs: z.number().nonnegative().optional(),
|
|
324
|
+
rootValid: z.boolean().optional(),
|
|
325
|
+
taskSummary: workspaceTaskInspectionSummaryOutputSchema.optional(),
|
|
326
|
+
relay: z.string(),
|
|
327
|
+
executionLocation: z.string(),
|
|
328
|
+
}),
|
|
329
|
+
z.object({
|
|
330
|
+
workspaceId: z.string(),
|
|
331
|
+
kind: z.literal("composite"),
|
|
332
|
+
name: z.string(),
|
|
333
|
+
status: z.enum(["active", "closed"]),
|
|
334
|
+
state: z.enum(["active", "closed"]),
|
|
335
|
+
createdAt: z.string(),
|
|
336
|
+
lastUsedAt: z.string(),
|
|
337
|
+
members: z.array(workspaceInspectionMemberOutputSchema),
|
|
338
|
+
taskSummary: workspaceTaskInspectionSummaryOutputSchema.optional(),
|
|
339
|
+
}),
|
|
340
|
+
]);
|
|
262
341
|
const reviewFileOutputSchema = z.object({
|
|
263
342
|
path: z.string(),
|
|
264
343
|
previousPath: z.string().optional(),
|
|
@@ -345,6 +424,17 @@ function logFailedToolResponse(config, fields, content, startedAt) {
|
|
|
345
424
|
function textBlock(text) {
|
|
346
425
|
return { type: "text", text };
|
|
347
426
|
}
|
|
427
|
+
function attachWorkspaceTaskReminder(result, reminder) {
|
|
428
|
+
if (!reminder || toolResultIsError(result) || typeof result !== "object" || result === null)
|
|
429
|
+
return result;
|
|
430
|
+
const content = result.content;
|
|
431
|
+
if (!Array.isArray(content))
|
|
432
|
+
return result;
|
|
433
|
+
return {
|
|
434
|
+
...result,
|
|
435
|
+
content: [...content, textBlock(reminder)],
|
|
436
|
+
};
|
|
437
|
+
}
|
|
348
438
|
function textSummary(content) {
|
|
349
439
|
const text = contentText(content);
|
|
350
440
|
return {
|
|
@@ -853,33 +943,43 @@ function requireCapabilityWorkspaceRoot(context) {
|
|
|
853
943
|
function runWorkspaceTasksCapability(store, workspaceId, input) {
|
|
854
944
|
switch (input.operation) {
|
|
855
945
|
case "get":
|
|
856
|
-
|
|
946
|
+
if (input.level === "headers")
|
|
947
|
+
return store.readHeaders(workspaceId, input.listId);
|
|
948
|
+
if (input.level === "detail")
|
|
949
|
+
return store.readTaskDetail(workspaceId, input.listId, input.taskId);
|
|
950
|
+
return store.readSummary(workspaceId);
|
|
857
951
|
case "list.create":
|
|
858
|
-
|
|
952
|
+
store.createList(workspaceId, { name: input.name, position: input.position });
|
|
953
|
+
return store.readSummary(workspaceId);
|
|
859
954
|
case "list.update":
|
|
860
|
-
|
|
955
|
+
store.updateList(workspaceId, input.listId, {
|
|
861
956
|
name: input.name,
|
|
862
957
|
state: input.state,
|
|
863
958
|
position: input.position,
|
|
864
959
|
});
|
|
960
|
+
return store.readSummary(workspaceId);
|
|
865
961
|
case "list.delete":
|
|
866
|
-
|
|
962
|
+
store.deleteList(workspaceId, input.listId);
|
|
963
|
+
return store.readSummary(workspaceId);
|
|
867
964
|
case "task.create":
|
|
868
|
-
|
|
965
|
+
store.createTask(workspaceId, input.listId, {
|
|
869
966
|
subject: input.subject,
|
|
870
967
|
content: input.content,
|
|
871
968
|
status: input.status,
|
|
872
969
|
position: input.position,
|
|
873
970
|
});
|
|
971
|
+
return store.readHeaders(workspaceId, input.listId);
|
|
874
972
|
case "task.update":
|
|
875
|
-
|
|
973
|
+
store.updateTask(workspaceId, input.listId, input.taskId, {
|
|
876
974
|
subject: input.subject,
|
|
877
975
|
content: input.content,
|
|
878
976
|
status: input.status,
|
|
879
977
|
position: input.position,
|
|
880
978
|
});
|
|
979
|
+
return store.readHeaders(workspaceId, input.listId);
|
|
881
980
|
case "task.delete":
|
|
882
|
-
|
|
981
|
+
store.deleteTask(workspaceId, input.listId, input.taskId);
|
|
982
|
+
return store.readHeaders(workspaceId, input.listId);
|
|
883
983
|
}
|
|
884
984
|
}
|
|
885
985
|
async function reviewWorkspaceChanges(reviewCheckpoints, workspace) {
|
|
@@ -1106,7 +1206,7 @@ function registerProcessTools(server, config, workspaces, processSessions, hooks
|
|
|
1106
1206
|
const target = routing.resolve(workspaceId, member);
|
|
1107
1207
|
const context = await routing.prepare(target, extra._meta, extra.signal, extra.sessionId);
|
|
1108
1208
|
if (routing.isRemote(target.executionWorkspaceId)) {
|
|
1109
|
-
return routing.
|
|
1209
|
+
return routing.presentSemantic(await routing.execCommandRemote(target.executionWorkspaceId, {
|
|
1110
1210
|
cmd,
|
|
1111
1211
|
...(tty !== undefined ? { tty } : {}),
|
|
1112
1212
|
...(columns !== undefined ? { columns } : {}),
|
|
@@ -1117,7 +1217,7 @@ function registerProcessTools(server, config, workspaces, processSessions, hooks
|
|
|
1117
1217
|
...(maxOutputTokens !== undefined ? { maxOutputTokens } : {}),
|
|
1118
1218
|
}, routing.hostScopeIdFor(extra._meta, extra.sessionId)), target);
|
|
1119
1219
|
}
|
|
1120
|
-
return routing.
|
|
1220
|
+
return routing.presentSemantic(await shellRun({
|
|
1121
1221
|
workspaceId: target.executionWorkspaceId,
|
|
1122
1222
|
command: cmd,
|
|
1123
1223
|
surface: "exec_command",
|
|
@@ -1242,9 +1342,13 @@ function registerProcessTools(server, config, workspaces, processSessions, hooks
|
|
|
1242
1342
|
}
|
|
1243
1343
|
export function createMcpServer(config, workspaces, reviewCheckpoints, processSessions, subagentProviders, incomingArtifactAdapters, codeIntelligence, activityLifecycle, bashOutputStore, activityQueries, options = {}) {
|
|
1244
1344
|
const connectionScopeId = `mcp-connection:${randomUUID()}`;
|
|
1245
|
-
const remoteWorkspaces =
|
|
1246
|
-
|
|
1345
|
+
const remoteWorkspaces = options.remoteWorkspaces
|
|
1346
|
+
?? new RemoteWorkspaceRelay(config.configDir, config.stateDir);
|
|
1347
|
+
const compositeWorkspaces = options.compositeWorkspaces
|
|
1348
|
+
?? new CompositeWorkspaceRegistry(config.stateDir);
|
|
1247
1349
|
const workspaceTasks = new WorkspaceTaskStore(config.stateDir);
|
|
1350
|
+
const taskReminders = options.taskReminders
|
|
1351
|
+
?? new WorkspaceTaskReminderTracker(config.taskReminderInterval, workspaceTasks);
|
|
1248
1352
|
const compositeTaskGuides = loadCapabilityGuides(config).filter((guide) => guide.name === "workspace-tasks");
|
|
1249
1353
|
const compositeActivity = new CompositeActivityCoordinator(compositeWorkspaces, activityQueries, remoteWorkspaces);
|
|
1250
1354
|
const resolveExecutionTarget = (workspaceId, memberName) => {
|
|
@@ -1278,6 +1382,25 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
1278
1382
|
: remapCompositeToolResult(result, target.executionWorkspaceId, target.compositeWorkspaceId, target.memberName);
|
|
1279
1383
|
return subagentMcp.decorateResult(target.executionWorkspaceId, presented);
|
|
1280
1384
|
};
|
|
1385
|
+
const taskReminderWorkspaceIdFor = (target) => {
|
|
1386
|
+
if (target.compositeWorkspaceId)
|
|
1387
|
+
return target.compositeWorkspaceId;
|
|
1388
|
+
if (remoteWorkspaces.has(target.executionWorkspaceId))
|
|
1389
|
+
return undefined;
|
|
1390
|
+
try {
|
|
1391
|
+
return workspaces.getWorkspace(target.executionWorkspaceId).id;
|
|
1392
|
+
}
|
|
1393
|
+
catch {
|
|
1394
|
+
return undefined;
|
|
1395
|
+
}
|
|
1396
|
+
};
|
|
1397
|
+
const presentSemanticWorkResult = (result, target) => {
|
|
1398
|
+
const presented = presentExecutionResult(result, target);
|
|
1399
|
+
if (toolResultIsError(presented))
|
|
1400
|
+
return presented;
|
|
1401
|
+
const reminderWorkspaceId = taskReminderWorkspaceIdFor(target);
|
|
1402
|
+
return attachWorkspaceTaskReminder(presented, reminderWorkspaceId ? taskReminders.recordWork(reminderWorkspaceId) : undefined);
|
|
1403
|
+
};
|
|
1281
1404
|
const hostScopeIdFor = (requestMeta, transportSessionId) => hostConversationScopeId(requestMeta, transportSessionId, connectionScopeId);
|
|
1282
1405
|
const prepareExecutionContext = async (target, requestMeta, signal, sessionId) => {
|
|
1283
1406
|
const conversationScopeId = hostScopeIdFor(requestMeta, sessionId);
|
|
@@ -1304,9 +1427,12 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
1304
1427
|
...subagentMcp.registryDependencies,
|
|
1305
1428
|
workspaceTasks: {
|
|
1306
1429
|
available: true,
|
|
1307
|
-
run: async (input, context) =>
|
|
1308
|
-
value
|
|
1309
|
-
|
|
1430
|
+
run: async (input, context) => {
|
|
1431
|
+
const value = runWorkspaceTasksCapability(workspaceTasks, context.workspaceId, input);
|
|
1432
|
+
if (input.operation !== "get")
|
|
1433
|
+
taskReminders.reset(context.workspaceId);
|
|
1434
|
+
return { value };
|
|
1435
|
+
},
|
|
1310
1436
|
},
|
|
1311
1437
|
batchExecute: {
|
|
1312
1438
|
available: batchExecuteAvailable,
|
|
@@ -2039,9 +2165,9 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
2039
2165
|
description: "Open or resume a ForgeRelay Workspace. Ordinary workspaces default to local execution; relay may name a registered remote ForgeRelay. Composite Workspaces use the same open lifecycle but have kind=\"composite\" and a name instead of a mounted root. Reuse the returned workspaceId for later calls. Bootstrap context is delivered automatically only when needed and can be suppressed or refreshed.",
|
|
2040
2166
|
inputSchema: {
|
|
2041
2167
|
action: z
|
|
2042
|
-
.enum(["open", "list", "member"])
|
|
2168
|
+
.enum(["open", "list", "inspect", "member"])
|
|
2043
2169
|
.optional()
|
|
2044
|
-
.describe("Defaults to open. Use list
|
|
2170
|
+
.describe("Defaults to open. Use list for lightweight inventory, inspect for bounded read-only metadata about one known Workspace without opening/resuming it, or member to change Composite membership."),
|
|
2045
2171
|
memberAction: z
|
|
2046
2172
|
.enum(["add", "update", "remove"])
|
|
2047
2173
|
.optional()
|
|
@@ -2081,7 +2207,7 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
2081
2207
|
workspaceId: z
|
|
2082
2208
|
.string()
|
|
2083
2209
|
.optional()
|
|
2084
|
-
.describe("For action=open, an existing Workspace ID to resume or reuse. Historical duplicate IDs from earlier ForgeRelay versions may resolve to the canonical Workspace ID. For action=list, filters inventory
|
|
2210
|
+
.describe("For action=open, an existing Workspace ID to resume or reuse. Historical duplicate IDs from earlier ForgeRelay versions may resolve to the canonical Workspace ID. For action=list, filters inventory. For action=inspect, identifies the single Workspace to inspect without opening or binding it."),
|
|
2085
2211
|
mode: z
|
|
2086
2212
|
.enum(["checkout", "worktree"])
|
|
2087
2213
|
.optional()
|
|
@@ -2133,7 +2259,7 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
2133
2259
|
.describe("For action=list, maximum records to return. Defaults to 50; maximum 100."),
|
|
2134
2260
|
},
|
|
2135
2261
|
outputSchema: {
|
|
2136
|
-
action: z.enum(["open", "list", "member"]),
|
|
2262
|
+
action: z.enum(["open", "list", "inspect", "member"]),
|
|
2137
2263
|
workspaceId: z.string().optional(),
|
|
2138
2264
|
memberAction: z.enum(["add", "update", "remove"]).optional(),
|
|
2139
2265
|
kind: z.enum(["workspace", "composite"]).optional(),
|
|
@@ -2208,6 +2334,7 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
2208
2334
|
})).optional(),
|
|
2209
2335
|
summary: workspaceInventorySummaryOutputSchema.optional(),
|
|
2210
2336
|
page: workspaceInventoryPageOutputSchema.optional(),
|
|
2337
|
+
inspection: workspaceInspectionOutputSchema.optional(),
|
|
2211
2338
|
instruction: z.string(),
|
|
2212
2339
|
},
|
|
2213
2340
|
_meta: {},
|
|
@@ -2221,6 +2348,136 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
2221
2348
|
const startedAt = performance.now();
|
|
2222
2349
|
const conversationScopeId = openAiConversationScopeId(_meta);
|
|
2223
2350
|
const protectedWorkspaceIds = processSessions.activeWorkspaceIds();
|
|
2351
|
+
const inspectTaskSummary = (targetWorkspaceId) => {
|
|
2352
|
+
try {
|
|
2353
|
+
const summary = workspaceTasks.inspectSummary(targetWorkspaceId);
|
|
2354
|
+
if (!summary)
|
|
2355
|
+
return undefined;
|
|
2356
|
+
const { fingerprint: _fingerprint, ...inspectionSummary } = summary;
|
|
2357
|
+
return inspectionSummary;
|
|
2358
|
+
}
|
|
2359
|
+
catch {
|
|
2360
|
+
return undefined;
|
|
2361
|
+
}
|
|
2362
|
+
};
|
|
2363
|
+
const inspectCompositeMember = async (entry) => {
|
|
2364
|
+
if (remoteWorkspaces.has(entry.workspaceId)) {
|
|
2365
|
+
try {
|
|
2366
|
+
const inspected = await remoteWorkspaces.inspectWorkspace(entry.workspaceId);
|
|
2367
|
+
return {
|
|
2368
|
+
name: entry.name,
|
|
2369
|
+
purpose: entry.purpose,
|
|
2370
|
+
workspaceId: entry.workspaceId,
|
|
2371
|
+
known: true,
|
|
2372
|
+
location: inspected.location,
|
|
2373
|
+
routeState: inspected.routeState,
|
|
2374
|
+
state: inspected.state,
|
|
2375
|
+
status: inspected.status,
|
|
2376
|
+
mode: inspected.mode,
|
|
2377
|
+
rootValid: inspected.rootValid,
|
|
2378
|
+
};
|
|
2379
|
+
}
|
|
2380
|
+
catch {
|
|
2381
|
+
return {
|
|
2382
|
+
name: entry.name,
|
|
2383
|
+
purpose: entry.purpose,
|
|
2384
|
+
workspaceId: entry.workspaceId,
|
|
2385
|
+
known: false,
|
|
2386
|
+
};
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
try {
|
|
2390
|
+
const inspected = await workspaces.inspectWorkspace(entry.workspaceId);
|
|
2391
|
+
return {
|
|
2392
|
+
name: entry.name,
|
|
2393
|
+
purpose: entry.purpose,
|
|
2394
|
+
workspaceId: entry.workspaceId,
|
|
2395
|
+
known: true,
|
|
2396
|
+
location: inspected.location,
|
|
2397
|
+
state: inspected.state,
|
|
2398
|
+
status: inspected.status,
|
|
2399
|
+
mode: inspected.mode,
|
|
2400
|
+
rootValid: inspected.rootValid,
|
|
2401
|
+
};
|
|
2402
|
+
}
|
|
2403
|
+
catch {
|
|
2404
|
+
return {
|
|
2405
|
+
name: entry.name,
|
|
2406
|
+
purpose: entry.purpose,
|
|
2407
|
+
workspaceId: entry.workspaceId,
|
|
2408
|
+
known: false,
|
|
2409
|
+
};
|
|
2410
|
+
}
|
|
2411
|
+
};
|
|
2412
|
+
if (action === "inspect") {
|
|
2413
|
+
if (!workspaceId) {
|
|
2414
|
+
throw new Error("open_workspace action=inspect requires workspaceId.");
|
|
2415
|
+
}
|
|
2416
|
+
if (memberAction !== undefined || member !== undefined || kind !== undefined || name !== undefined ||
|
|
2417
|
+
memberName !== undefined || path !== undefined || relay !== undefined || mode !== undefined ||
|
|
2418
|
+
baseRef !== undefined || newWorktree !== undefined || newWorkspace !== undefined || context !== undefined ||
|
|
2419
|
+
root !== undefined || status !== undefined || state !== undefined || staleOnly !== undefined ||
|
|
2420
|
+
offset !== undefined || limit !== undefined) {
|
|
2421
|
+
throw new Error("open_workspace action=inspect accepts only workspaceId. It never opens, resumes, binds, or mutates the inspected Workspace.");
|
|
2422
|
+
}
|
|
2423
|
+
let inspection;
|
|
2424
|
+
if (compositeWorkspaces.has(workspaceId)) {
|
|
2425
|
+
const composite = compositeWorkspaces.get(workspaceId);
|
|
2426
|
+
const members = await Promise.all(composite.members.map(inspectCompositeMember));
|
|
2427
|
+
const taskSummary = inspectTaskSummary(composite.id);
|
|
2428
|
+
inspection = {
|
|
2429
|
+
workspaceId: composite.id,
|
|
2430
|
+
kind: "composite",
|
|
2431
|
+
name: composite.name,
|
|
2432
|
+
status: composite.status,
|
|
2433
|
+
state: composite.status,
|
|
2434
|
+
createdAt: composite.createdAt,
|
|
2435
|
+
lastUsedAt: composite.lastUsedAt,
|
|
2436
|
+
members,
|
|
2437
|
+
...(taskSummary ? { taskSummary } : {}),
|
|
2438
|
+
};
|
|
2439
|
+
}
|
|
2440
|
+
else if (remoteWorkspaces.has(workspaceId)) {
|
|
2441
|
+
inspection = await remoteWorkspaces.inspectWorkspace(workspaceId);
|
|
2442
|
+
}
|
|
2443
|
+
else {
|
|
2444
|
+
const inspected = await workspaces.inspectWorkspace(workspaceId);
|
|
2445
|
+
const taskSummary = inspectTaskSummary(inspected.workspaceId);
|
|
2446
|
+
inspection = {
|
|
2447
|
+
...inspected,
|
|
2448
|
+
...(taskSummary ? { taskSummary } : {}),
|
|
2449
|
+
};
|
|
2450
|
+
}
|
|
2451
|
+
const instruction = "This is a bounded read-only Workspace inspection. It does not open/resume the target, deliver bootstrap context, bind this conversation, or grant file/process/Git/Capability authority. Explicitly open the Workspace before modifying or executing against it.";
|
|
2452
|
+
const result = [
|
|
2453
|
+
`Inspected Workspace ${inspection.workspaceId} (${inspection.kind}).`,
|
|
2454
|
+
inspection.kind === "composite"
|
|
2455
|
+
? `State: ${inspection.state}; members=${inspection.members.length}.`
|
|
2456
|
+
: inspection.location === "relay"
|
|
2457
|
+
? inspection.state
|
|
2458
|
+
? `State: ${inspection.state}; route=${inspection.routeState}; mode=${inspection.mode}; location=${inspection.location}. Lifecycle and Task facts come from the Execution ForgeRelay.`
|
|
2459
|
+
: `Route: ${inspection.routeState}; mode=${inspection.mode}; location=${inspection.location}.`
|
|
2460
|
+
: `State: ${inspection.state}; mode=${inspection.mode}; location=${inspection.location}.`,
|
|
2461
|
+
"Task summary is included only when durable Task state already exists on the owning Workspace; Task bodies are never returned.",
|
|
2462
|
+
instruction,
|
|
2463
|
+
].join("\n");
|
|
2464
|
+
logToolCall(config, {
|
|
2465
|
+
tool: "open_workspace",
|
|
2466
|
+
action: "inspect",
|
|
2467
|
+
success: true,
|
|
2468
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
2469
|
+
});
|
|
2470
|
+
return {
|
|
2471
|
+
content: [textBlock(result)],
|
|
2472
|
+
structuredContent: {
|
|
2473
|
+
action: "inspect",
|
|
2474
|
+
workspaceId: inspection.workspaceId,
|
|
2475
|
+
kind: inspection.kind,
|
|
2476
|
+
inspection,
|
|
2477
|
+
instruction,
|
|
2478
|
+
},
|
|
2479
|
+
};
|
|
2480
|
+
}
|
|
2224
2481
|
if (action === "member") {
|
|
2225
2482
|
if (!workspaceId || !compositeWorkspaces.has(workspaceId)) {
|
|
2226
2483
|
throw new Error("open_workspace action=member requires an existing Composite Workspace workspaceId.");
|
|
@@ -2525,10 +2782,16 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
2525
2782
|
if (name !== undefined || memberName !== undefined) {
|
|
2526
2783
|
throw new Error("open_workspace name/memberName are only valid for a Composite Workspace.");
|
|
2527
2784
|
}
|
|
2528
|
-
if (
|
|
2529
|
-
if (
|
|
2530
|
-
|
|
2785
|
+
if (workspaceId !== undefined && remoteWorkspaces.has(workspaceId)) {
|
|
2786
|
+
if (path !== undefined || relay !== undefined || mode !== undefined || baseRef !== undefined ||
|
|
2787
|
+
newWorktree !== undefined || newWorkspace !== undefined) {
|
|
2788
|
+
throw new Error("Resuming a relayed Workspace by workspaceId accepts context only.");
|
|
2531
2789
|
}
|
|
2790
|
+
const resumed = await remoteWorkspaces.resumeWorkspace(workspaceId, context ?? "auto", hostScopeIdFor(_meta, sessionId));
|
|
2791
|
+
rememberWorkspacePanelState(workspaceId, resumed);
|
|
2792
|
+
return resumed;
|
|
2793
|
+
}
|
|
2794
|
+
if (relay !== undefined) {
|
|
2532
2795
|
if (!path)
|
|
2533
2796
|
throw new Error("Relayed open_workspace requires path.");
|
|
2534
2797
|
const opened = await remoteWorkspaces.openWorkspace(relay, {
|
|
@@ -2673,7 +2936,7 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
2673
2936
|
const loadedAgentsFiles = includeBootstrapContext ? cardAgentsFiles : [];
|
|
2674
2937
|
const availableAgentsFileOutputs = includeBootstrapContext ? cardAvailableAgentsFiles : [];
|
|
2675
2938
|
const workspaceContextInstruction = "For later open_workspace calls, context=\"auto\" avoids repeating unchanged bootstrap context; use context=\"none\" when only the workspace handle/metadata is needed, or context=\"full\" to force a refresh.";
|
|
2676
|
-
const workspaceManagementInstruction = "
|
|
2939
|
+
const workspaceManagementInstruction = "Use open_workspace(action=\"list\") for lightweight Workspace inventory. Use action=\"inspect\" with one known workspaceId for bounded read-only metadata without opening/resuming it. Explicitly open a Workspace before executing or mutating against it, and ask the user before close_workspace cleanup.";
|
|
2677
2940
|
const cardInstruction = config.skillsEnabled
|
|
2678
2941
|
? `Use this workspaceId in all subsequent tool calls for this project. Follow loaded agentsFiles instructions. Read an availableAgentsFiles path before working under it. When a task matches an available skill, load it with read(path=\"skills://<name>\") before proceeding. When a task matches a capability guide, read its advertised path before proceeding. ${workspaceContextInstruction} ${workspaceManagementInstruction}`
|
|
2679
2942
|
: `Use this workspaceId in all subsequent tool calls for this project. Follow loaded agentsFiles instructions. Read an availableAgentsFiles path before working under it. When a task matches a capability guide, read its advertised path before proceeding. ${workspaceContextInstruction} ${workspaceManagementInstruction}`;
|
|
@@ -2955,12 +3218,15 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
2955
3218
|
const executionWorkspaceId = target.executionWorkspaceId;
|
|
2956
3219
|
const executionContext = await prepareExecutionContext(target, extra._meta, extra.signal, extra.sessionId);
|
|
2957
3220
|
if (remoteWorkspaces.has(executionWorkspaceId)) {
|
|
2958
|
-
|
|
3221
|
+
const response = await remoteWorkspaces.capability(executionWorkspaceId, {
|
|
2959
3222
|
name,
|
|
2960
3223
|
action,
|
|
2961
3224
|
...(capabilityArguments !== undefined ? { arguments: capabilityArguments } : {}),
|
|
2962
3225
|
...(file !== undefined ? { file } : {}),
|
|
2963
|
-
}, hostScopeIdFor(extra._meta, extra.sessionId))
|
|
3226
|
+
}, hostScopeIdFor(extra._meta, extra.sessionId));
|
|
3227
|
+
return action === "run" && name !== "workspace.tasks"
|
|
3228
|
+
? presentSemanticWorkResult(response, target)
|
|
3229
|
+
: presentExecutionResult(response, target);
|
|
2964
3230
|
}
|
|
2965
3231
|
if (action === "run" && name === "batch.execute") {
|
|
2966
3232
|
const workspace = workspaces.getWorkspace(executionWorkspaceId);
|
|
@@ -2984,7 +3250,7 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
2984
3250
|
success: true,
|
|
2985
3251
|
durationMs: Math.round(performance.now() - startedAt),
|
|
2986
3252
|
});
|
|
2987
|
-
return
|
|
3253
|
+
return presentSemanticWorkResult(result, target);
|
|
2988
3254
|
}
|
|
2989
3255
|
catch (error) {
|
|
2990
3256
|
if (extra.signal.aborted)
|
|
@@ -3011,7 +3277,10 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3011
3277
|
}
|
|
3012
3278
|
}
|
|
3013
3279
|
if (action === "run") {
|
|
3014
|
-
|
|
3280
|
+
const response = await coreOperations.capabilityRun({ workspaceId: executionWorkspaceId, name, arguments: capabilityArguments, file }, executionContext);
|
|
3281
|
+
return name === "workspace.tasks"
|
|
3282
|
+
? presentExecutionResult(response, target)
|
|
3283
|
+
: presentSemanticWorkResult(response, target);
|
|
3015
3284
|
}
|
|
3016
3285
|
const workspace = workspaces.getWorkspace(executionWorkspaceId);
|
|
3017
3286
|
return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(extra._meta, extra.sessionId), activityRequestFor({ workspaceId: executionWorkspaceId, name, action, arguments: capabilityArguments, file }, executionContext), {
|
|
@@ -3071,7 +3340,7 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3071
3340
|
});
|
|
3072
3341
|
registerAppTool(server, toolNames.closeWorkspace, {
|
|
3073
3342
|
title: "Close workspace",
|
|
3074
|
-
description: "Close or explicitly delete one Workspace after the user chooses cleanup. action=close (default) preserves checkout, managed-worktree, and
|
|
3343
|
+
description: "Close or explicitly delete one Workspace after the user chooses cleanup. action=close (default) preserves checkout, managed-worktree, Composite, and relayed identity for later reopen. action=delete permanently removes ForgeRelay-owned state. Managed-worktree-backed Workspaces still finalize safely when active and require commitMessage. Composite delete dissolves only Composite-owned state and never closes member Workspaces. Checkout project files are never deleted.",
|
|
3075
3344
|
inputSchema: {
|
|
3076
3345
|
workspaceId: z.string().describe("Workspace identifier to close or delete."),
|
|
3077
3346
|
action: z
|
|
@@ -3115,8 +3384,10 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3115
3384
|
const composite = action === "delete"
|
|
3116
3385
|
? compositeWorkspaces.dissolve(workspaceId)
|
|
3117
3386
|
: compositeWorkspaces.close(workspaceId);
|
|
3118
|
-
if (action === "delete")
|
|
3387
|
+
if (action === "delete") {
|
|
3119
3388
|
workspaceTasks.deleteWorkspace(workspaceId);
|
|
3389
|
+
taskReminders.forget(workspaceId);
|
|
3390
|
+
}
|
|
3120
3391
|
compositeActivity.forgetComposite(workspaceId);
|
|
3121
3392
|
workspacePanelStates.delete(workspaceId);
|
|
3122
3393
|
const result = [
|
|
@@ -3156,10 +3427,7 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3156
3427
|
};
|
|
3157
3428
|
}
|
|
3158
3429
|
if (remoteWorkspaces.has(workspaceId)) {
|
|
3159
|
-
|
|
3160
|
-
throw new Error("close_workspace action=delete is not available for relayed Workspaces until Workspace Relay lifecycle parity is implemented.");
|
|
3161
|
-
}
|
|
3162
|
-
const response = await remoteWorkspaces.closeWorkspace(workspaceId, commitMessage, hostScopeIdFor(extra._meta, extra.sessionId));
|
|
3430
|
+
const response = await remoteWorkspaces.closeWorkspace(workspaceId, { action, ...(commitMessage !== undefined ? { commitMessage } : {}) }, hostScopeIdFor(extra._meta, extra.sessionId));
|
|
3163
3431
|
workspacePanelStates.delete(workspaceId);
|
|
3164
3432
|
return response;
|
|
3165
3433
|
}
|
|
@@ -3184,6 +3452,7 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3184
3452
|
operation: async () => {
|
|
3185
3453
|
workspaces.deleteWorkspace(session.id);
|
|
3186
3454
|
workspaceTasks.deleteWorkspace(session.id);
|
|
3455
|
+
taskReminders.forget(session.id);
|
|
3187
3456
|
await reviewCheckpoints.releaseWorkspace(session.id);
|
|
3188
3457
|
const result = `Deleted ForgeRelay Workspace ${session.id}. Physical project files were not removed.`;
|
|
3189
3458
|
return {
|
|
@@ -3227,6 +3496,7 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3227
3496
|
operation: async () => {
|
|
3228
3497
|
workspaces.deleteWorkspace(session.id);
|
|
3229
3498
|
workspaceTasks.deleteWorkspace(session.id);
|
|
3499
|
+
taskReminders.forget(session.id);
|
|
3230
3500
|
await reviewCheckpoints.releaseWorkspace(session.id);
|
|
3231
3501
|
const result = `Deleted closed managed-worktree Workspace ${session.id}. Its already-removed worktree backing was not recreated.`;
|
|
3232
3502
|
return {
|
|
@@ -3290,6 +3560,7 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3290
3560
|
if (action === "delete") {
|
|
3291
3561
|
workspaces.deleteWorkspace(workspace.id);
|
|
3292
3562
|
workspaceTasks.deleteWorkspace(workspace.id);
|
|
3563
|
+
taskReminders.forget(workspace.id);
|
|
3293
3564
|
}
|
|
3294
3565
|
const result = [
|
|
3295
3566
|
action === "delete"
|
|
@@ -3454,10 +3725,10 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3454
3725
|
const executionWorkspaceId = target.executionWorkspaceId;
|
|
3455
3726
|
const executionContext = await prepareExecutionContext(target, extra._meta, extra.signal, extra.sessionId);
|
|
3456
3727
|
if (remoteWorkspaces.has(executionWorkspaceId)) {
|
|
3457
|
-
return
|
|
3728
|
+
return presentSemanticWorkResult(await remoteWorkspaces.read(executionWorkspaceId, { path, paths, offset, limit }, hostScopeIdFor(extra._meta, extra.sessionId)), target);
|
|
3458
3729
|
}
|
|
3459
3730
|
if (path !== undefined) {
|
|
3460
|
-
return
|
|
3731
|
+
return presentSemanticWorkResult(await coreOperations.read({ workspaceId: executionWorkspaceId, path, offset, limit }, executionContext), target);
|
|
3461
3732
|
}
|
|
3462
3733
|
const workspace = workspaces.getWorkspace(executionWorkspaceId);
|
|
3463
3734
|
let response;
|
|
@@ -3510,7 +3781,7 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3510
3781
|
: { type: "succeeded" }, activityRelationFor(executionContext));
|
|
3511
3782
|
if (!response)
|
|
3512
3783
|
throw new Error("Bulk Read completed without a response.");
|
|
3513
|
-
return
|
|
3784
|
+
return presentSemanticWorkResult(response, target);
|
|
3514
3785
|
});
|
|
3515
3786
|
if (config.toolMode !== "codex") {
|
|
3516
3787
|
registerAppTool(server, toolNames.write, {
|
|
@@ -3534,9 +3805,9 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3534
3805
|
const executionWorkspaceId = target.executionWorkspaceId;
|
|
3535
3806
|
const executionContext = await prepareExecutionContext(target, extra._meta, extra.signal, extra.sessionId);
|
|
3536
3807
|
if (remoteWorkspaces.has(executionWorkspaceId)) {
|
|
3537
|
-
return
|
|
3808
|
+
return presentSemanticWorkResult(await remoteWorkspaces.write(executionWorkspaceId, input, hostScopeIdFor(extra._meta, extra.sessionId)), target);
|
|
3538
3809
|
}
|
|
3539
|
-
return
|
|
3810
|
+
return presentSemanticWorkResult(await coreOperations.write({ workspaceId: executionWorkspaceId, ...input }, executionContext), target);
|
|
3540
3811
|
});
|
|
3541
3812
|
registerAppTool(server, toolNames.edit, {
|
|
3542
3813
|
title: "Edit file",
|
|
@@ -3587,12 +3858,12 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3587
3858
|
const executionWorkspaceId = target.executionWorkspaceId;
|
|
3588
3859
|
const executionContext = await prepareExecutionContext(target, extra._meta, extra.signal, extra.sessionId);
|
|
3589
3860
|
if (remoteWorkspaces.has(executionWorkspaceId)) {
|
|
3590
|
-
return
|
|
3861
|
+
return presentSemanticWorkResult(await remoteWorkspaces.edit(executionWorkspaceId, { path, paths, edits }, hostScopeIdFor(extra._meta, extra.sessionId)), target);
|
|
3591
3862
|
}
|
|
3592
3863
|
if (path !== undefined) {
|
|
3593
|
-
return
|
|
3864
|
+
return presentSemanticWorkResult(await coreOperations.edit({ workspaceId: executionWorkspaceId, path, edits }, executionContext), target);
|
|
3594
3865
|
}
|
|
3595
|
-
return
|
|
3866
|
+
return presentSemanticWorkResult(await nativeBulkMutations.edit({ workspaceId: executionWorkspaceId, paths: paths, edits }, executionContext), target);
|
|
3596
3867
|
});
|
|
3597
3868
|
}
|
|
3598
3869
|
registerAppTool(server, toolNames.rename, {
|
|
@@ -3616,9 +3887,9 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3616
3887
|
const executionWorkspaceId = target.executionWorkspaceId;
|
|
3617
3888
|
const executionContext = await prepareExecutionContext(target, extra._meta, extra.signal, extra.sessionId);
|
|
3618
3889
|
if (remoteWorkspaces.has(executionWorkspaceId)) {
|
|
3619
|
-
return
|
|
3890
|
+
return presentSemanticWorkResult(await remoteWorkspaces.rename(executionWorkspaceId, { path, newPath }, hostScopeIdFor(extra._meta, extra.sessionId)), target);
|
|
3620
3891
|
}
|
|
3621
|
-
return
|
|
3892
|
+
return presentSemanticWorkResult(await coreOperations.rename({ workspaceId: executionWorkspaceId, path, newPath }, executionContext), target);
|
|
3622
3893
|
});
|
|
3623
3894
|
registerAppTool(server, toolNames.delete, {
|
|
3624
3895
|
title: "Delete path",
|
|
@@ -3659,12 +3930,12 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3659
3930
|
const executionWorkspaceId = target.executionWorkspaceId;
|
|
3660
3931
|
const executionContext = await prepareExecutionContext(target, extra._meta, extra.signal, extra.sessionId);
|
|
3661
3932
|
if (remoteWorkspaces.has(executionWorkspaceId)) {
|
|
3662
|
-
return
|
|
3933
|
+
return presentSemanticWorkResult(await remoteWorkspaces.delete(executionWorkspaceId, { path, paths, recursive }, hostScopeIdFor(extra._meta, extra.sessionId)), target);
|
|
3663
3934
|
}
|
|
3664
3935
|
if (path !== undefined) {
|
|
3665
|
-
return
|
|
3936
|
+
return presentSemanticWorkResult(await coreOperations.delete({ workspaceId: executionWorkspaceId, path, recursive }, executionContext), target);
|
|
3666
3937
|
}
|
|
3667
|
-
return
|
|
3938
|
+
return presentSemanticWorkResult(await nativeBulkMutations.delete({ workspaceId: executionWorkspaceId, paths: paths, recursive }, executionContext), target);
|
|
3668
3939
|
});
|
|
3669
3940
|
if (config.toolMode === "codex") {
|
|
3670
3941
|
registerAppTool(server, "apply_patch", {
|
|
@@ -3695,7 +3966,7 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3695
3966
|
const executionWorkspaceId = target.executionWorkspaceId;
|
|
3696
3967
|
const executionContext = await prepareExecutionContext(target, extra._meta, extra.signal, extra.sessionId);
|
|
3697
3968
|
if (remoteWorkspaces.has(executionWorkspaceId)) {
|
|
3698
|
-
return
|
|
3969
|
+
return presentSemanticWorkResult(await remoteWorkspaces.applyPatch(executionWorkspaceId, { patch }, hostScopeIdFor(extra._meta, extra.sessionId)), target);
|
|
3699
3970
|
}
|
|
3700
3971
|
const workspace = workspaces.getWorkspace(executionWorkspaceId);
|
|
3701
3972
|
return runActivityToolWithHooks(activityLifecycle, hooks, workspace, hostScopeIdFor(extra._meta, extra.sessionId), activityRequestFor({ workspaceId: executionWorkspaceId, patch }, executionContext), {
|
|
@@ -3745,7 +4016,7 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3745
4016
|
},
|
|
3746
4017
|
};
|
|
3747
4018
|
},
|
|
3748
|
-
}, activityRelationFor(executionContext)).then((result) =>
|
|
4019
|
+
}, activityRelationFor(executionContext)).then((result) => presentSemanticWorkResult(result, target));
|
|
3749
4020
|
});
|
|
3750
4021
|
}
|
|
3751
4022
|
if (config.toolMode !== "codex") {
|
|
@@ -3835,7 +4106,7 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3835
4106
|
const executionWorkspaceId = target.executionWorkspaceId;
|
|
3836
4107
|
const executionContext = await prepareExecutionContext(target, extra._meta, extra.signal, extra.sessionId);
|
|
3837
4108
|
if (remoteWorkspaces.has(executionWorkspaceId)) {
|
|
3838
|
-
|
|
4109
|
+
const response = await remoteWorkspaces.bash(executionWorkspaceId, {
|
|
3839
4110
|
action,
|
|
3840
4111
|
...(command !== undefined ? { command } : {}),
|
|
3841
4112
|
...(processId !== undefined ? { processId } : {}),
|
|
@@ -3849,7 +4120,10 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3849
4120
|
...(yieldTimeMs !== undefined ? { yieldTimeMs } : {}),
|
|
3850
4121
|
...(timeoutMs !== undefined ? { timeoutMs } : {}),
|
|
3851
4122
|
...(maxOutputTokens !== undefined ? { maxOutputTokens } : {}),
|
|
3852
|
-
}, hostScopeIdFor(extra._meta, extra.sessionId))
|
|
4123
|
+
}, hostScopeIdFor(extra._meta, extra.sessionId));
|
|
4124
|
+
return action === "run"
|
|
4125
|
+
? presentSemanticWorkResult(response, target)
|
|
4126
|
+
: presentExecutionResult(response, target);
|
|
3853
4127
|
}
|
|
3854
4128
|
const workspace = workspaces.getWorkspace(executionWorkspaceId);
|
|
3855
4129
|
if (action === "run") {
|
|
@@ -3858,7 +4132,7 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3858
4132
|
if (processId !== undefined || outputId !== undefined || input !== undefined || interrupt !== undefined) {
|
|
3859
4133
|
throw new Error("bash action=run does not accept processId, outputId, input, or interrupt.");
|
|
3860
4134
|
}
|
|
3861
|
-
return
|
|
4135
|
+
return presentSemanticWorkResult(await coreOperations.shellRun({
|
|
3862
4136
|
workspaceId: executionWorkspaceId,
|
|
3863
4137
|
command,
|
|
3864
4138
|
surface: "bash",
|
|
@@ -3952,6 +4226,7 @@ export function createMcpServer(config, workspaces, reviewCheckpoints, processSe
|
|
|
3952
4226
|
resolve: resolveExecutionTarget,
|
|
3953
4227
|
prepare: prepareExecutionContext,
|
|
3954
4228
|
present: presentExecutionResult,
|
|
4229
|
+
presentSemantic: presentSemanticWorkResult,
|
|
3955
4230
|
isRemote: (workspaceId) => remoteWorkspaces.has(workspaceId),
|
|
3956
4231
|
execCommandRemote: (workspaceId, input, conversationScopeId) => remoteWorkspaces.execCommand(workspaceId, input, conversationScopeId),
|
|
3957
4232
|
writeStdinRemote: (workspaceId, input, conversationScopeId) => remoteWorkspaces.writeStdin(workspaceId, input, conversationScopeId),
|
|
@@ -3982,6 +4257,10 @@ export function createServer(config = loadConfig(), options = {}) {
|
|
|
3982
4257
|
});
|
|
3983
4258
|
const workspaceStore = createWorkspaceStore(config.stateDir);
|
|
3984
4259
|
const workspaces = new WorkspaceRegistry(config, workspaceStore);
|
|
4260
|
+
const sharedRemoteWorkspaces = new RemoteWorkspaceRelay(config.configDir, config.stateDir);
|
|
4261
|
+
const sharedCompositeWorkspaces = new CompositeWorkspaceRegistry(config.stateDir);
|
|
4262
|
+
const sharedWorkspaceTasks = new WorkspaceTaskStore(config.stateDir);
|
|
4263
|
+
const sharedTaskReminders = new WorkspaceTaskReminderTracker(config.taskReminderInterval, sharedWorkspaceTasks);
|
|
3985
4264
|
const activityAuditStore = new ActivityAuditStore(config.stateDir);
|
|
3986
4265
|
const bashOutputStore = new BashOutputStore(config.stateDir);
|
|
3987
4266
|
const hostTurnStore = new HostTurnStore(config.stateDir);
|
|
@@ -4176,7 +4455,11 @@ export function createServer(config = loadConfig(), options = {}) {
|
|
|
4176
4455
|
});
|
|
4177
4456
|
}
|
|
4178
4457
|
};
|
|
4179
|
-
const server = createMcpServer(config, workspaces, reviewCheckpoints, processSessions, subagentProviders, incomingArtifactAdapters, codeIntelligence, activityLifecycle, bashOutputStore, activityQueries
|
|
4458
|
+
const server = createMcpServer(config, workspaces, reviewCheckpoints, processSessions, subagentProviders, incomingArtifactAdapters, codeIntelligence, activityLifecycle, bashOutputStore, activityQueries, {
|
|
4459
|
+
taskReminders: sharedTaskReminders,
|
|
4460
|
+
remoteWorkspaces: sharedRemoteWorkspaces,
|
|
4461
|
+
compositeWorkspaces: sharedCompositeWorkspaces,
|
|
4462
|
+
});
|
|
4180
4463
|
await server.connect(transport);
|
|
4181
4464
|
}
|
|
4182
4465
|
else {
|