refactor: remove terminal agent concept entirely
Remove the "agent can be a terminal" branching from the entire codebase. An agent is now always a session-backed chat agent. Standalone terminal infrastructure (terminal component, ANSI handling, terminal-stream-protocol) is preserved. Server: delete ManagedTerminalAgent, AgentKind, TerminalExitDetails, launchTerminalAgent, registerTerminalAgent, handleTerminalAgentExited, supportsTerminalMode capability, buildTerminalCreate/ResumeCommand from all providers, terminal agent persistence/projections. App: delete terminal-agent-panel.tsx, terminal-agent-reopen-store.ts, terminal/terminalExit fields on agent state, "Terminal Agents" launcher section, terminal-agent workspace setup flow, terminal badge in agent list. CLI: remove terminal column from ls, terminal-agent error from send. 60 files changed, -3592 lines
This commit is contained in:
@@ -9,7 +9,6 @@ import {
|
||||
createPersistedProjectRecord,
|
||||
createPersistedWorkspaceRecord,
|
||||
} from "./workspace-registry.js";
|
||||
import type { StoredAgentRecord } from "./agent/agent-storage.js";
|
||||
|
||||
function makeAgent(input: {
|
||||
id: string;
|
||||
@@ -39,7 +38,6 @@ function makeAgent(input: {
|
||||
supportsMcpServers: true,
|
||||
supportsReasoningStream: true,
|
||||
supportsToolInvocations: true,
|
||||
supportsTerminalMode: false,
|
||||
},
|
||||
currentModeId: null,
|
||||
availableModes: [],
|
||||
@@ -222,50 +220,6 @@ function seedWorkspace(options: {
|
||||
return record;
|
||||
}
|
||||
|
||||
function createStoredTerminalAgentRecord(input: {
|
||||
id: string;
|
||||
cwd: string;
|
||||
}): StoredAgentRecord {
|
||||
return {
|
||||
id: input.id,
|
||||
provider: "codex",
|
||||
cwd: input.cwd,
|
||||
createdAt: "2026-03-01T12:00:00.000Z",
|
||||
updatedAt: "2026-03-01T12:00:00.000Z",
|
||||
lastActivityAt: "2026-03-01T12:00:00.000Z",
|
||||
lastUserMessageAt: null,
|
||||
title: null,
|
||||
labels: {},
|
||||
lastStatus: "closed",
|
||||
lastModeId: null,
|
||||
config: {
|
||||
terminal: true,
|
||||
},
|
||||
runtimeInfo: {
|
||||
provider: "codex",
|
||||
sessionId: null,
|
||||
},
|
||||
persistence: {
|
||||
provider: "codex",
|
||||
sessionId: input.id,
|
||||
nativeHandle: input.id,
|
||||
},
|
||||
lastError: null,
|
||||
terminalExit: {
|
||||
command: "codex",
|
||||
message: "Terminal session ended",
|
||||
exitCode: 0,
|
||||
signal: null,
|
||||
outputLines: [],
|
||||
},
|
||||
requiresAttention: false,
|
||||
attentionReason: null,
|
||||
attentionTimestamp: null,
|
||||
internal: false,
|
||||
archivedAt: null,
|
||||
};
|
||||
}
|
||||
|
||||
function createTempGitRepo(options?: {
|
||||
remoteUrl?: string;
|
||||
branchName?: string;
|
||||
@@ -635,89 +589,6 @@ describe("workspace aggregation", () => {
|
||||
expect(sessionLogger.warn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("terminal agents reject timeline fetch without reloading as chat sessions", async () => {
|
||||
const emitted: Array<{ type: string; payload: any }> = [];
|
||||
const logger = {
|
||||
child: () => logger,
|
||||
trace: vi.fn(),
|
||||
debug: vi.fn(),
|
||||
info: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
error: vi.fn(),
|
||||
};
|
||||
const resumeAgentFromPersistence = vi.fn();
|
||||
const launchTerminalAgent = vi.fn();
|
||||
const hydrateTimelineFromProvider = vi.fn();
|
||||
|
||||
const session = new Session({
|
||||
clientId: "test-client",
|
||||
onMessage: (message) => emitted.push(message as any),
|
||||
logger: logger as any,
|
||||
downloadTokenStore: {} as any,
|
||||
pushTokenStore: {} as any,
|
||||
paseoHome: "/tmp/paseo-test",
|
||||
agentManager: {
|
||||
subscribe: () => () => {},
|
||||
listAgents: () => [],
|
||||
getAgent: () => null,
|
||||
resumeAgentFromPersistence,
|
||||
launchTerminalAgent,
|
||||
hydrateTimelineFromProvider,
|
||||
} as any,
|
||||
agentStorage: {
|
||||
list: async () => [],
|
||||
get: async (agentId: string) =>
|
||||
agentId === "terminal-1"
|
||||
? createStoredTerminalAgentRecord({ id: agentId, cwd: "/tmp/repo" })
|
||||
: null,
|
||||
} as any,
|
||||
projectRegistry: {
|
||||
initialize: async () => {},
|
||||
existsOnDisk: async () => true,
|
||||
list: async () => [],
|
||||
get: async () => null,
|
||||
upsert: async () => {},
|
||||
archive: async () => {},
|
||||
remove: async () => {},
|
||||
} as any,
|
||||
workspaceRegistry: {
|
||||
initialize: async () => {},
|
||||
existsOnDisk: async () => true,
|
||||
list: async () => [],
|
||||
get: async () => null,
|
||||
upsert: async () => {},
|
||||
archive: async () => {},
|
||||
remove: async () => {},
|
||||
} as any,
|
||||
createAgentMcpTransport: async () => {
|
||||
throw new Error("not used");
|
||||
},
|
||||
stt: null,
|
||||
tts: null,
|
||||
terminalManager: null,
|
||||
}) as any;
|
||||
|
||||
await session.handleMessage({
|
||||
type: "fetch_agent_timeline_request",
|
||||
requestId: "req-terminal-timeline",
|
||||
agentId: "terminal-1",
|
||||
});
|
||||
|
||||
expect(resumeAgentFromPersistence).not.toHaveBeenCalled();
|
||||
expect(launchTerminalAgent).not.toHaveBeenCalled();
|
||||
expect(hydrateTimelineFromProvider).not.toHaveBeenCalled();
|
||||
expect(emitted).toContainEqual(
|
||||
expect.objectContaining({
|
||||
type: "fetch_agent_timeline_response",
|
||||
payload: expect.objectContaining({
|
||||
requestId: "req-terminal-timeline",
|
||||
agentId: "terminal-1",
|
||||
error: "Agent terminal-1 is a terminal agent and has no timeline history",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test("uses persisted workspace names and stable status aggregation", async () => {
|
||||
const { session, projects, workspaces } = createSessionForWorkspaceTests();
|
||||
seedProject({
|
||||
|
||||
Reference in New Issue
Block a user