feat: add multi-session desktop workspace
This commit is contained in:
+74
-7
@@ -8,6 +8,14 @@ const requestOperations = new Map([
|
||||
["list_directories", { agent: false, payload: "none" }],
|
||||
["select_agent", { agent: false, payload: "worktree" }],
|
||||
["forget_directory", { agent: false, payload: "worktree" }],
|
||||
["get_workspace", { agent: false, payload: "none" }],
|
||||
["get_workspace_summary", { agent: false, payload: "none" }],
|
||||
["create_session_runtime", { agent: false, payload: "worktree" }],
|
||||
["open_session_runtime", { agent: false, payload: "worktreeSession" }],
|
||||
["close_session_runtime", { agent: false, payload: "runtime" }],
|
||||
["list_directory_sessions", { agent: false, payload: "worktree" }],
|
||||
["get_session_runtime_snapshot", { agent: false, payload: "runtime" }],
|
||||
["subscribe_workspace", { agent: false, payload: "cursor" }],
|
||||
["get_state", { agent: true, payload: "none" }],
|
||||
["get_session_stats", { agent: true, payload: "none" }],
|
||||
["list_sessions", { agent: true, payload: "none" }],
|
||||
@@ -25,6 +33,8 @@ const requestOperations = new Map([
|
||||
["restart", { agent: true, payload: "none" }],
|
||||
["get_available_models", { agent: true, payload: "none" }],
|
||||
["get_commands", { agent: true, payload: "none" }],
|
||||
["set_session_name", { agent: true, payload: "sessionName" }],
|
||||
["compact", { agent: true, payload: "compact" }],
|
||||
["set_model", { agent: true, payload: "model" }],
|
||||
["set_thinking_level", { agent: true, payload: "thinking" }],
|
||||
]);
|
||||
@@ -100,10 +110,10 @@ function assertString(value, field, { maxLength = 4096, pattern } = {}) {
|
||||
function assertOptionalCursor(value) {
|
||||
if (value === undefined) return undefined;
|
||||
if (Number.isSafeInteger(value) && value >= 0) return value;
|
||||
return assertString(value, "payload.cursor", {
|
||||
maxLength: 256,
|
||||
pattern: idPattern,
|
||||
});
|
||||
throw new ProtocolError(
|
||||
"invalid_message",
|
||||
"payload.cursor must be a non-negative integer",
|
||||
);
|
||||
}
|
||||
|
||||
function validatePayload(kind, value) {
|
||||
@@ -115,6 +125,7 @@ function validatePayload(kind, value) {
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
if (kind === "compact" && value === undefined) return undefined;
|
||||
|
||||
const payload = assertRecord(value, "payload");
|
||||
switch (kind) {
|
||||
@@ -137,9 +148,7 @@ function validatePayload(kind, value) {
|
||||
const sessionPath = assertString(
|
||||
payload.sessionPath,
|
||||
"payload.sessionPath",
|
||||
{
|
||||
maxLength: 4096,
|
||||
},
|
||||
{ maxLength: 4096 },
|
||||
);
|
||||
if (!path.isAbsolute(sessionPath))
|
||||
throw new ProtocolError(
|
||||
@@ -148,6 +157,38 @@ function validatePayload(kind, value) {
|
||||
);
|
||||
return { sessionPath };
|
||||
}
|
||||
case "worktreeSession": {
|
||||
assertAllowedKeys(
|
||||
payload,
|
||||
new Set(["worktreePath", "sessionPath"]),
|
||||
"payload",
|
||||
);
|
||||
const worktreePath = assertString(
|
||||
payload.worktreePath,
|
||||
"payload.worktreePath",
|
||||
{ maxLength: 4096 },
|
||||
);
|
||||
const sessionPath = assertString(
|
||||
payload.sessionPath,
|
||||
"payload.sessionPath",
|
||||
{ maxLength: 4096 },
|
||||
);
|
||||
if (!path.isAbsolute(worktreePath) || !path.isAbsolute(sessionPath))
|
||||
throw new ProtocolError(
|
||||
"invalid_message",
|
||||
"payload worktree and session paths must be absolute",
|
||||
);
|
||||
return { worktreePath, sessionPath };
|
||||
}
|
||||
case "runtime": {
|
||||
assertAllowedKeys(payload, new Set(["runtimeId"]), "payload");
|
||||
return {
|
||||
runtimeId: assertString(payload.runtimeId, "payload.runtimeId", {
|
||||
maxLength: 128,
|
||||
pattern: idPattern,
|
||||
}),
|
||||
};
|
||||
}
|
||||
case "cursor": {
|
||||
assertAllowedKeys(payload, new Set(["cursor"]), "payload");
|
||||
return {
|
||||
@@ -185,6 +226,32 @@ function validatePayload(kind, value) {
|
||||
response,
|
||||
};
|
||||
}
|
||||
case "sessionName": {
|
||||
assertAllowedKeys(payload, new Set(["name"]), "payload");
|
||||
const name = assertString(payload.name, "payload.name", {
|
||||
maxLength: 4096,
|
||||
}).trim();
|
||||
if (!name)
|
||||
throw new ProtocolError(
|
||||
"invalid_message",
|
||||
"payload.name must not be blank",
|
||||
);
|
||||
return { name };
|
||||
}
|
||||
case "compact": {
|
||||
assertAllowedKeys(payload, new Set(["customInstructions"]), "payload");
|
||||
const customInstructions = assertString(
|
||||
payload.customInstructions,
|
||||
"payload.customInstructions",
|
||||
{ maxLength: 32 * 1024 },
|
||||
).trim();
|
||||
if (!customInstructions)
|
||||
throw new ProtocolError(
|
||||
"invalid_message",
|
||||
"payload.customInstructions must not be blank",
|
||||
);
|
||||
return { customInstructions };
|
||||
}
|
||||
case "model": {
|
||||
assertAllowedKeys(payload, new Set(["provider", "modelId"]), "payload");
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user