feat: add multi-session desktop workspace
This commit is contained in:
+43
-15
@@ -134,6 +134,10 @@ test("drains a forget still resolving its canonical path during shutdown", async
|
||||
await stop();
|
||||
};
|
||||
|
||||
const selectedFeature = registry
|
||||
.listAgents()
|
||||
.find((agent) => agent.worktreePath === worktrees.feature);
|
||||
await registry.closeSessionRuntime(selectedFeature.runtimeId);
|
||||
const forgetting = registry.forgetDirectory(featureAlias);
|
||||
const stopping = registry.stop();
|
||||
await Promise.all([forgetting, stopping]);
|
||||
@@ -170,6 +174,11 @@ test("forgets a directory without deleting its resumable session history", async
|
||||
`${JSON.stringify({ sessionPath, worktreePath: worktrees.feature })}\n`,
|
||||
);
|
||||
|
||||
await assert.rejects(
|
||||
registry.forgetDirectory(worktrees.feature),
|
||||
/runtimes are open/,
|
||||
);
|
||||
await registry.closeSessionRuntime(feature.runtimeId);
|
||||
await registry.forgetDirectory(worktrees.feature);
|
||||
|
||||
assert.equal(fixture.calls[1].adapter.stopped, true);
|
||||
@@ -227,10 +236,14 @@ test("coordinates forgetting with directory creation and active commands", async
|
||||
|
||||
const selecting = registry.selectWorktree(worktrees.feature);
|
||||
await featureStarted;
|
||||
const forgettingDuringCreation = registry.forgetDirectory(worktrees.feature);
|
||||
releaseFeatureCreation();
|
||||
await selecting;
|
||||
await forgettingDuringCreation;
|
||||
const selectedDuringCreation = await selecting;
|
||||
await assert.rejects(
|
||||
registry.forgetDirectory(worktrees.feature),
|
||||
/runtimes are open/,
|
||||
);
|
||||
await registry.closeSessionRuntime(selectedDuringCreation.runtimeId);
|
||||
await registry.forgetDirectory(worktrees.feature);
|
||||
assert.equal(fixture.calls[1].adapter.stopped, true);
|
||||
assert.equal(
|
||||
(await registry.listDirectories()).some(
|
||||
@@ -252,15 +265,18 @@ test("coordinates forgetting with directory creation and active commands", async
|
||||
await stopGate;
|
||||
await stop();
|
||||
};
|
||||
const firstForget = registry.forgetDirectory(worktrees.feature);
|
||||
const secondForget = registry.forgetDirectory(worktrees.feature);
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
await assert.rejects(
|
||||
registry.selectWorktree(worktrees.feature),
|
||||
/being forgotten/,
|
||||
registry.forgetDirectory(worktrees.feature),
|
||||
/runtimes are open/,
|
||||
);
|
||||
const closing = registry.closeSessionRuntime(
|
||||
registry.listAgents().find((agent) => agent.worktreePath === worktrees.feature)
|
||||
.runtimeId,
|
||||
);
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
releaseStop();
|
||||
await Promise.all([firstForget, secondForget]);
|
||||
await closing;
|
||||
await registry.forgetDirectory(worktrees.feature);
|
||||
assert.equal(stopCalls, 1);
|
||||
assert.equal(registry.listAgents().length, 1);
|
||||
|
||||
@@ -276,15 +292,15 @@ test("coordinates forgetting with directory creation and active commands", async
|
||||
const prompt = registry.route(feature.id, "prompt", {
|
||||
message: "Keep working",
|
||||
});
|
||||
const forgettingDuringPrompt = registry.forgetDirectory(worktrees.feature);
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
await assert.rejects(
|
||||
registry.forgetDirectory(worktrees.feature),
|
||||
/runtimes are open/,
|
||||
);
|
||||
assert.equal(adapter.stopped, false);
|
||||
releasePrompt({ type: "response", success: true });
|
||||
await prompt;
|
||||
await assert.rejects(forgettingDuringPrompt, /while Pi is working/);
|
||||
assert.equal(adapter.stopped, false);
|
||||
|
||||
options.onEvent({ type: "agent_state", data: { state: "idle" } });
|
||||
await registry.closeSessionRuntime(feature.runtimeId);
|
||||
await registry.forgetDirectory(worktrees.feature);
|
||||
assert.equal(adapter.stopped, true);
|
||||
|
||||
@@ -307,14 +323,19 @@ test("coordinates forgetting with directory creation and active commands", async
|
||||
});
|
||||
rejectPrompt(new Error("send failed"));
|
||||
await failedPromptAssertion;
|
||||
assert.equal(
|
||||
registry.listAgents().find((entry) => entry.id === failedFeature.id).state,
|
||||
"streaming",
|
||||
);
|
||||
await assert.rejects(
|
||||
registry.forgetDirectory(worktrees.feature),
|
||||
/while Pi is working/,
|
||||
/runtimes are open/,
|
||||
);
|
||||
failedFixture.options.onEvent({
|
||||
type: "agent_state",
|
||||
data: { state: "idle" },
|
||||
});
|
||||
await registry.closeSessionRuntime(failedFeature.runtimeId);
|
||||
await registry.forgetDirectory(worktrees.feature);
|
||||
await registry.stop();
|
||||
});
|
||||
@@ -389,6 +410,7 @@ test("catalogues managed directories and exposes only their sessions", async ()
|
||||
}),
|
||||
/ENOENT|belong/,
|
||||
);
|
||||
await registry.closeSessionRuntime(feature.runtimeId);
|
||||
await registry.stop();
|
||||
|
||||
const restored = createAgentRegistry({
|
||||
@@ -444,11 +466,17 @@ test("routes commands by explicit agent ID and replays only events after the cur
|
||||
command: "get_commands",
|
||||
success: true,
|
||||
});
|
||||
await registry.route(agent.id, "set_session_name", { name: "Release UI" });
|
||||
await registry.route(agent.id, "compact", {
|
||||
customInstructions: "Preserve implementation details",
|
||||
});
|
||||
assert.deepEqual(adapter.sent, [
|
||||
{ type: "get_state" },
|
||||
{ type: "prompt", message: "Stay in this worktree" },
|
||||
{ type: "get_session_stats" },
|
||||
{ type: "get_commands" },
|
||||
{ type: "set_session_name", name: "Release UI" },
|
||||
{ type: "compact", customInstructions: "Preserve implementation details" },
|
||||
]);
|
||||
|
||||
options.onEvent({
|
||||
|
||||
Reference in New Issue
Block a user