Keep new workspaces recent in status groups
This commit is contained in:
@@ -6736,7 +6736,7 @@ export class Session {
|
||||
title: result.workspace.title,
|
||||
archivingAt: null,
|
||||
status: "done",
|
||||
statusEnteredAt: null,
|
||||
statusEnteredAt: result.workspace.createdAt,
|
||||
activityAt: null,
|
||||
diffStat: { additions: 0, deletions: 0 },
|
||||
scripts: [],
|
||||
|
||||
@@ -2894,6 +2894,8 @@ test("archiving the last workspace emits a remove carrying the now-empty project
|
||||
|
||||
test("create paseo worktree request returns a registered workspace descriptor", async () => {
|
||||
const emitted: SessionOutboundMessage[] = [];
|
||||
const createdAt = "2026-05-12T12:00:00.000Z";
|
||||
vi.setSystemTime(new Date(createdAt));
|
||||
const tempDir = realpathSync(mkdtempSync(path.join(tmpdir(), "session-worktree-test-")));
|
||||
const repoDir = path.join(tempDir, "repo");
|
||||
const paseoHome = path.join(tempDir, "paseo-home");
|
||||
@@ -2981,6 +2983,7 @@ test("create paseo worktree request returns a registered workspace descriptor",
|
||||
requestId: "req-worktree",
|
||||
});
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
rmSync(tempDir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
@@ -2993,6 +2996,7 @@ test("create paseo worktree request returns a registered workspace descriptor",
|
||||
workspaceKind: "worktree",
|
||||
name: "worktree-123",
|
||||
status: "done",
|
||||
statusEnteredAt: createdAt,
|
||||
});
|
||||
expect(response?.payload.workspace?.id).toMatch(/^wks_[0-9a-f]{16}$/);
|
||||
expect(response?.payload.workspace?.workspaceDirectory).toContain(path.join("worktree-123"));
|
||||
@@ -4365,7 +4369,7 @@ test("listWorkspaceDescriptorsSnapshot keeps git workspaces on the baseline desc
|
||||
name: "main",
|
||||
archivingAt: null,
|
||||
status: "done",
|
||||
statusEnteredAt: null,
|
||||
statusEnteredAt: workspace.createdAt,
|
||||
activityAt: null,
|
||||
diffStat: null,
|
||||
} as const;
|
||||
@@ -4424,14 +4428,14 @@ test("buildWorkspaceDescriptorMap computes statusEnteredAt from runtime agent fi
|
||||
return descriptor!;
|
||||
});
|
||||
|
||||
// 1. Empty workspace — no agents contribute. statusEnteredAt must be null
|
||||
// and the workspace status is "done".
|
||||
// 1. Empty workspace — no agents contribute. The workspace entered its
|
||||
// initial "done" bucket when it was created.
|
||||
{
|
||||
const { session, workspace } = setupSession();
|
||||
session.listAgentPayloads = async () => [];
|
||||
const descriptor = await buildDescriptor(session, workspace.workspaceId);
|
||||
expect(descriptor.status).toBe("done");
|
||||
expect(descriptor.statusEnteredAt).toBeNull();
|
||||
expect(descriptor.statusEnteredAt).toBe(workspace.createdAt);
|
||||
}
|
||||
|
||||
// Agents own the workspace by id; cwd is incidental.
|
||||
|
||||
@@ -32,8 +32,9 @@ const FETCH_WORKSPACES_SORT_KEYS = [
|
||||
* `statusEnteredAt`: when the winning bucket changes from a higher-priority
|
||||
* 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 has never had contributing agents.
|
||||
* underlying agent originally entered the lower-priority bucket. A fresh
|
||||
* workspace enters its initial `done` bucket at creation time, even before any
|
||||
* agent or terminal contributes activity.
|
||||
*/
|
||||
interface WorkspaceBucketHistoryEntry {
|
||||
bucket: WorkspaceStateBucket;
|
||||
@@ -205,6 +206,9 @@ export class WorkspaceDirectory {
|
||||
const includedWorkspaces = activeRecords.filter(
|
||||
(workspace) => !workspaceIds || workspaceIds.has(workspace.workspaceId),
|
||||
);
|
||||
const activeRecordsByWorkspaceId = new Map(
|
||||
activeRecords.map((workspace) => [workspace.workspaceId, workspace] as const),
|
||||
);
|
||||
const workspaceDescriptors = await Promise.all(
|
||||
includedWorkspaces.map((workspace) =>
|
||||
this.deps.buildWorkspaceDescriptor({
|
||||
@@ -253,6 +257,7 @@ export class WorkspaceDirectory {
|
||||
contributingAgents,
|
||||
terminalEntries,
|
||||
previous: this.bucketHistoryByWorkspaceId.get(workspaceId) ?? null,
|
||||
workspaceCreatedAt: activeRecordsByWorkspaceId.get(workspaceId)?.createdAt ?? null,
|
||||
nowIso,
|
||||
});
|
||||
descriptor.statusEnteredAt = result.statusEnteredAt;
|
||||
@@ -360,8 +365,8 @@ 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 that never had contributing agents or terminals get
|
||||
// `statusEnteredAt: null`.
|
||||
// - empty workspaces that never had contributing agents or terminals use
|
||||
// their workspace creation time as their initial `done` entry time.
|
||||
// - when archived agents leave a previously active workspace empty, keep
|
||||
// the previous done timestamp or stamp the transition to done now.
|
||||
private resolveStatusEnteredAt(params: {
|
||||
@@ -370,17 +375,32 @@ export class WorkspaceDirectory {
|
||||
contributingAgents: AgentSnapshotPayload[];
|
||||
terminalEntries: Array<{ bucket: WorkspaceStateBucket; changedAtIso: string }>;
|
||||
previous: WorkspaceBucketHistoryEntry | null;
|
||||
workspaceCreatedAt: string | null;
|
||||
nowIso: string;
|
||||
}): {
|
||||
statusEnteredAt: string | null;
|
||||
recordUpdate?: WorkspaceBucketHistoryEntry;
|
||||
recordDelete?: true;
|
||||
} {
|
||||
const { winningBucket, contributingAgents, terminalEntries, previous, nowIso } = params;
|
||||
const {
|
||||
winningBucket,
|
||||
contributingAgents,
|
||||
terminalEntries,
|
||||
previous,
|
||||
workspaceCreatedAt,
|
||||
nowIso,
|
||||
} = params;
|
||||
|
||||
if (contributingAgents.length === 0 && terminalEntries.length === 0) {
|
||||
if (!previous) {
|
||||
return { statusEnteredAt: null };
|
||||
if (!workspaceCreatedAt) {
|
||||
return { statusEnteredAt: null };
|
||||
}
|
||||
|
||||
return {
|
||||
statusEnteredAt: workspaceCreatedAt,
|
||||
recordUpdate: { bucket: "done", enteredAt: workspaceCreatedAt },
|
||||
};
|
||||
}
|
||||
|
||||
const enteredAt = previous.bucket === "done" ? previous.enteredAt : nowIso;
|
||||
|
||||
Reference in New Issue
Block a user