mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Keep archived workspaces recent in Done
This commit is contained in:
@@ -4356,6 +4356,62 @@ test("buildWorkspaceDescriptorMap computes statusEnteredAt from runtime agent fi
|
||||
}
|
||||
});
|
||||
|
||||
test("buildWorkspaceDescriptorMap keeps a done workspace recent after its agents are archived", async () => {
|
||||
const session = createSessionForWorkspaceTests();
|
||||
const project = createPersistedProjectRecord({
|
||||
projectId: "proj-archive-status-entered",
|
||||
rootPath: REPO_CWD,
|
||||
kind: "git",
|
||||
displayName: "repo",
|
||||
createdAt: "2026-03-01T12:00:00.000Z",
|
||||
updatedAt: "2026-03-01T12:00:00.000Z",
|
||||
});
|
||||
const workspace = createPersistedWorkspaceRecord({
|
||||
workspaceId: "ws-archive-status-entered",
|
||||
projectId: project.projectId,
|
||||
cwd: "/tmp/repo/archive-status-entered",
|
||||
kind: "worktree",
|
||||
displayName: "feature",
|
||||
createdAt: "2026-03-01T12:00:00.000Z",
|
||||
updatedAt: "2026-03-01T12:00:00.000Z",
|
||||
});
|
||||
const doneEnteredAt = "2026-05-12T09:30:00.000Z";
|
||||
const archivedAt = "2026-05-12T09:45:00.000Z";
|
||||
|
||||
session.projectRegistry.list = async () => [project];
|
||||
session.workspaceRegistry.list = async () => [workspace];
|
||||
session.listAgentPayloads = async () => [
|
||||
makeAgent({
|
||||
id: "agent-done",
|
||||
cwd: workspace.cwd,
|
||||
status: "idle",
|
||||
updatedAt: doneEnteredAt,
|
||||
}),
|
||||
];
|
||||
|
||||
const first = await session.buildWorkspaceDescriptorMap({ includeGitData: false });
|
||||
expect(first.get(workspace.workspaceId)?.status).toBe("done");
|
||||
expect(first.get(workspace.workspaceId)?.statusEnteredAt).toBe(doneEnteredAt);
|
||||
|
||||
session.listAgentPayloads = async () => [
|
||||
{
|
||||
...makeAgent({
|
||||
id: "agent-done",
|
||||
cwd: workspace.cwd,
|
||||
status: "idle",
|
||||
updatedAt: doneEnteredAt,
|
||||
}),
|
||||
archivedAt,
|
||||
},
|
||||
];
|
||||
|
||||
const second = await session.buildWorkspaceDescriptorMap({ includeGitData: false });
|
||||
expect(second.get(workspace.workspaceId)).toMatchObject({
|
||||
status: "done",
|
||||
statusEnteredAt: doneEnteredAt,
|
||||
});
|
||||
});
|
||||
|
||||
test("buildWorkspaceDescriptorMap stamps workspace archiving state", async () => {
|
||||
const session = createSessionForWorkspaceTests();
|
||||
const archivingAt = "2026-04-30T20:45:00.000Z";
|
||||
|
||||
@@ -30,7 +30,7 @@ const FETCH_WORKSPACES_SORT_KEYS = [
|
||||
* mask to a lower-priority bucket, the new entry time is the unmask time
|
||||
* (i.e., the moment the higher-priority bucket cleared), not when the
|
||||
* underlying agent originally entered the lower-priority bucket. Cleared when
|
||||
* the workspace becomes `done` with no contributing agents.
|
||||
* the workspace has never had contributing agents.
|
||||
*/
|
||||
interface WorkspaceBucketHistoryEntry {
|
||||
bucket: WorkspaceStateBucket;
|
||||
@@ -279,7 +279,10 @@ export class WorkspaceDirectory {
|
||||
// - priority unmasking: when the winning bucket transitions (e.g. a
|
||||
// higher-priority bucket cleared), the new entry time is "now";
|
||||
// - same-bucket emits reuse the previous entered-at;
|
||||
// - empty workspaces (no contributing agents) get `statusEnteredAt: null`.
|
||||
// - empty workspaces that never had contributing agents get
|
||||
// `statusEnteredAt: null`.
|
||||
// - when archived agents leave a previously active workspace empty, keep
|
||||
// the previous done timestamp or stamp the transition to done now.
|
||||
private resolveStatusEnteredAt(params: {
|
||||
workspaceId: string;
|
||||
winningBucket: WorkspaceStateBucket;
|
||||
@@ -294,16 +297,15 @@ export class WorkspaceDirectory {
|
||||
const { winningBucket, contributingAgents, previous, nowIso } = params;
|
||||
|
||||
if (contributingAgents.length === 0) {
|
||||
if (previous && previous.bucket !== "done") {
|
||||
return { statusEnteredAt: null, recordDelete: true };
|
||||
if (!previous) {
|
||||
return { statusEnteredAt: null };
|
||||
}
|
||||
if (previous) {
|
||||
return {
|
||||
statusEnteredAt: null,
|
||||
recordUpdate: { bucket: "done", enteredAt: previous.enteredAt },
|
||||
};
|
||||
}
|
||||
return { statusEnteredAt: null };
|
||||
|
||||
const enteredAt = previous.bucket === "done" ? previous.enteredAt : nowIso;
|
||||
return {
|
||||
statusEnteredAt: enteredAt,
|
||||
recordUpdate: { bucket: "done", enteredAt },
|
||||
};
|
||||
}
|
||||
|
||||
if (!previous) {
|
||||
|
||||
Reference in New Issue
Block a user