Reduce daemon churn from terminals and archived agents

Decouple terminal list snapshots from workspace status invalidation, and filter archived stored agents before projection so seeded homes do less work.
This commit is contained in:
Mohamed Boudra
2026-06-15 20:07:33 +07:00
parent 754f6336c0
commit 1c9e78616f
16 changed files with 837 additions and 105 deletions
@@ -10,6 +10,7 @@ import { randomBytes, randomUUID } from "node:crypto";
import { resolve, sep } from "node:path";
import { assertAbsolutePath, isSameOrDescendantPath } from "../server/path-utils.js";
import type { TerminalActivity, TerminalActivityState } from "@getpaseo/protocol/terminal-activity";
import { deriveTerminalActivityStatusBucket } from "@getpaseo/protocol/terminal-activity";
export interface TerminalListItem {
id: string;
@@ -37,6 +38,16 @@ export interface TerminalActivityTransitionEvent {
export type TerminalActivityListener = (event: TerminalActivityTransitionEvent) => void;
export interface TerminalWorkspaceContributionChangedEvent {
terminalId: string;
cwd: string;
workspaceId?: string;
}
export type TerminalWorkspaceContributionChangedListener = (
event: TerminalWorkspaceContributionChangedEvent,
) => void;
export interface TerminalManager {
getTerminals(cwd: string, options?: { workspaceId?: string }): Promise<TerminalSession[]>;
createTerminal(options: {
@@ -74,6 +85,9 @@ export interface TerminalManager {
killAll(): void;
subscribeTerminalsChanged(listener: TerminalsChangedListener): () => void;
subscribeTerminalActivity(listener: TerminalActivityListener): () => void;
subscribeTerminalWorkspaceContributionChanged(
listener: TerminalWorkspaceContributionChangedListener,
): () => void;
}
export interface TerminalManagerOptions {
@@ -95,6 +109,8 @@ export function createTerminalManager(
const terminalActivityTokenById = new Map<string, string>();
const terminalsChangedListeners = new Set<TerminalsChangedListener>();
const terminalActivityListeners = new Set<TerminalActivityListener>();
const terminalWorkspaceContributionChangedListeners =
new Set<TerminalWorkspaceContributionChangedListener>();
const defaultEnvByRootCwd = new Map<string, Record<string, string>>();
function removeSessionById(id: string, options: { kill: boolean }): void {
@@ -137,6 +153,16 @@ export function createTerminalManager(
session.kill();
}
const previousActivity = session.getActivity();
const previousBucket = deriveTerminalActivityStatusBucket(previousActivity);
if (previousBucket !== null) {
emitTerminalWorkspaceContributionChanged({
terminalId: session.id,
cwd: session.cwd,
...(session.workspaceId ? { workspaceId: session.workspaceId } : {}),
});
}
emitTerminalsChanged({ cwd: session.cwd });
}
@@ -168,6 +194,15 @@ export function createTerminalManager(
const unsubscribeActivity = session.onActivityChange((transition) => {
emitTerminalActivityTransition({ session, transition });
emitTerminalsChanged({ cwd: session.cwd });
const previousBucket = deriveTerminalActivityStatusBucket(transition.previous);
const nextBucket = deriveTerminalActivityStatusBucket(transition.activity);
if (previousBucket !== nextBucket) {
emitTerminalWorkspaceContributionChanged({
terminalId: session.id,
cwd: session.cwd,
...(session.workspaceId ? { workspaceId: session.workspaceId } : {}),
});
}
});
terminalExitUnsubscribeById.set(session.id, unsubscribeExit);
terminalTitleUnsubscribeById.set(session.id, unsubscribeTitle);
@@ -231,6 +266,18 @@ export function createTerminalManager(
}
}
function emitTerminalWorkspaceContributionChanged(
event: TerminalWorkspaceContributionChangedEvent,
): void {
for (const listener of terminalWorkspaceContributionChangedListeners) {
try {
listener(event);
} catch {
// no-op
}
}
}
return {
async getTerminals(
cwd: string,
@@ -431,5 +478,14 @@ export function createTerminalManager(
terminalActivityListeners.delete(listener);
};
},
subscribeTerminalWorkspaceContributionChanged(
listener: TerminalWorkspaceContributionChangedListener,
): () => void {
terminalWorkspaceContributionChangedListeners.add(listener);
return () => {
terminalWorkspaceContributionChangedListeners.delete(listener);
};
},
};
}