fix: resolve type errors and test failures from branch integration
- Align portless code with storage branch's numeric workspace IDs and new field names - Update workspace kind comparisons (local_checkout → checkout/worktree) - Add missing services, supportsTerminalMode, terminal fields to test fixtures - Fix archive timestamp assertions to match dynamic archiveSnapshot flow - Fix dictation, voice runtime, and service health monitor test timing - Add xterm-addon-ligatures type declaration for terminal emulator
This commit is contained in:
@@ -266,6 +266,8 @@ describe("DictationStreamManager (provider-agnostic provider)", () => {
|
||||
|
||||
it("drops dangling uncommitted non-final transcripts when finishing after silence tail clear", async () => {
|
||||
vi.useFakeTimers();
|
||||
const previousDebug = process.env.PASEO_DICTATION_DEBUG;
|
||||
process.env.PASEO_DICTATION_DEBUG = "false";
|
||||
try {
|
||||
const session = new FakeRealtimeSession();
|
||||
const emitted: Array<{ type: string; payload: any }> = [];
|
||||
@@ -299,6 +301,7 @@ describe("DictationStreamManager (provider-agnostic provider)", () => {
|
||||
await manager.handleFinish("d-clear-tail", 1);
|
||||
await tick();
|
||||
await vi.advanceTimersByTimeAsync(5_100);
|
||||
await tick();
|
||||
|
||||
const final = emitted.find((msg) => msg.type === "dictation_stream_final");
|
||||
const error = emitted.find((msg) => msg.type === "dictation_stream_error");
|
||||
@@ -306,6 +309,7 @@ describe("DictationStreamManager (provider-agnostic provider)", () => {
|
||||
expect(error).toBeUndefined();
|
||||
expect(final?.payload.text).toBe("hello");
|
||||
} finally {
|
||||
process.env.PASEO_DICTATION_DEBUG = previousDebug;
|
||||
vi.useRealTimers();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -51,7 +51,7 @@ async function closeServer(server: net.Server): Promise<void> {
|
||||
|
||||
async function advancePoll(ms: number): Promise<void> {
|
||||
await vi.advanceTimersByTimeAsync(ms);
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
for (let i = 0; i < 20; i += 1) {
|
||||
await scheduler.yield();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4857,7 +4857,7 @@ export class Session {
|
||||
services: this.serviceRouteStore
|
||||
? buildWorkspaceServicePayloads(
|
||||
this.serviceRouteStore,
|
||||
workspace.workspaceId,
|
||||
workspace.directory,
|
||||
this.getDaemonTcpPort?.() ?? null,
|
||||
this.resolveServiceStatus ?? undefined,
|
||||
)
|
||||
@@ -5574,6 +5574,7 @@ export class Session {
|
||||
private async createPaseoWorktreeInBackground(options: {
|
||||
requestCwd: string;
|
||||
repoRoot: string;
|
||||
workspaceId: number;
|
||||
worktree: { branchName: string; worktreePath: string };
|
||||
shouldBootstrap: boolean;
|
||||
}): Promise<void> {
|
||||
|
||||
@@ -291,30 +291,31 @@ function createTempGitRepo(options?: {
|
||||
describe("workspace aggregation", () => {
|
||||
test("archive request emits agent_archived using the snapshot archive flow", async () => {
|
||||
const emitted: Array<{ type: string; payload: any }> = [];
|
||||
const archivedAt = "2026-04-01T00:00:00.000Z";
|
||||
const archivedRecord = {
|
||||
id: "agent-1",
|
||||
provider: "codex",
|
||||
cwd: "/tmp/repo",
|
||||
createdAt: "2026-03-30T15:00:00.000Z",
|
||||
updatedAt: archivedAt,
|
||||
lastActivityAt: "2026-03-30T15:00:00.000Z",
|
||||
lastUserMessageAt: null,
|
||||
lastStatus: "idle" as const,
|
||||
lastModeId: null,
|
||||
runtimeInfo: null,
|
||||
config: {
|
||||
const archiveSnapshot = vi.fn(async (_agentId: string, archivedAt: string) => {
|
||||
return {
|
||||
id: "agent-1",
|
||||
provider: "codex",
|
||||
cwd: "/tmp/repo",
|
||||
},
|
||||
persistence: null,
|
||||
title: "Archive me",
|
||||
labels: {},
|
||||
requiresAttention: false,
|
||||
attentionReason: null,
|
||||
attentionTimestamp: null,
|
||||
archivedAt,
|
||||
};
|
||||
createdAt: "2026-03-30T15:00:00.000Z",
|
||||
updatedAt: archivedAt,
|
||||
lastActivityAt: "2026-03-30T15:00:00.000Z",
|
||||
lastUserMessageAt: null,
|
||||
lastStatus: "idle" as const,
|
||||
lastModeId: null,
|
||||
runtimeInfo: null,
|
||||
config: {
|
||||
provider: "codex",
|
||||
cwd: "/tmp/repo",
|
||||
},
|
||||
persistence: null,
|
||||
title: "Archive me",
|
||||
labels: {},
|
||||
requiresAttention: false,
|
||||
attentionReason: null,
|
||||
attentionTimestamp: null,
|
||||
archivedAt,
|
||||
};
|
||||
});
|
||||
|
||||
const logger = {
|
||||
child: () => logger,
|
||||
@@ -337,7 +338,7 @@ describe("workspace aggregation", () => {
|
||||
subscribe: () => () => {},
|
||||
listAgents: () => [],
|
||||
getAgent: (agentId: string) => (agentId === "agent-1" ? { id: agentId } : null),
|
||||
archiveSnapshot: vi.fn(async () => archivedRecord),
|
||||
archiveSnapshot,
|
||||
closeAgent,
|
||||
clearAgentAttention: async () => {},
|
||||
} as any,
|
||||
@@ -391,18 +392,37 @@ describe("workspace aggregation", () => {
|
||||
|
||||
expect(session.interruptAgentIfRunning).toHaveBeenCalledWith("agent-1");
|
||||
expect(closeAgent).toHaveBeenCalledWith("agent-1");
|
||||
expect(
|
||||
emitted.find((message) => message.type === "agent_archived")?.payload,
|
||||
).toMatchObject({
|
||||
const archivedPayload = emitted.find((message) => message.type === "agent_archived")?.payload;
|
||||
expect(archivedPayload).toMatchObject({
|
||||
agentId: "agent-1",
|
||||
archivedAt,
|
||||
archivedAt: expect.any(String),
|
||||
requestId: "req-archive",
|
||||
});
|
||||
expect(archiveSnapshot).toHaveBeenCalledWith("agent-1", archivedPayload.archivedAt);
|
||||
});
|
||||
|
||||
test("close_items_request archives agents and kills terminals in one batch", async () => {
|
||||
const emitted: Array<{ type: string; payload: any }> = [];
|
||||
const archivedAt = "2026-04-01T00:00:00.000Z";
|
||||
const archiveSnapshot = vi.fn(async (_agentId: string, archivedAt: string) => ({
|
||||
id: "agent-1",
|
||||
provider: "codex",
|
||||
cwd: "/tmp/repo",
|
||||
createdAt: "2026-03-01T12:00:00.000Z",
|
||||
updatedAt: archivedAt,
|
||||
lastActivityAt: "2026-03-01T12:00:00.000Z",
|
||||
lastUserMessageAt: null,
|
||||
lastStatus: "idle" as const,
|
||||
lastModeId: null,
|
||||
runtimeInfo: null,
|
||||
config: null,
|
||||
persistence: null,
|
||||
title: null,
|
||||
labels: {},
|
||||
requiresAttention: false,
|
||||
attentionReason: null,
|
||||
attentionTimestamp: null,
|
||||
archivedAt,
|
||||
}));
|
||||
const sessionLogger = {
|
||||
child: () => sessionLogger,
|
||||
trace: vi.fn(),
|
||||
@@ -423,26 +443,7 @@ describe("workspace aggregation", () => {
|
||||
subscribe: () => () => {},
|
||||
listAgents: () => [],
|
||||
getAgent: (agentId: string) => (agentId === "agent-1" ? { id: agentId } : null),
|
||||
archiveSnapshot: async () => ({
|
||||
id: "agent-1",
|
||||
provider: "codex",
|
||||
cwd: "/tmp/repo",
|
||||
createdAt: "2026-03-01T12:00:00.000Z",
|
||||
updatedAt: archivedAt,
|
||||
lastActivityAt: "2026-03-01T12:00:00.000Z",
|
||||
lastUserMessageAt: null,
|
||||
lastStatus: "idle" as const,
|
||||
lastModeId: null,
|
||||
runtimeInfo: null,
|
||||
config: null,
|
||||
persistence: null,
|
||||
title: null,
|
||||
labels: {},
|
||||
requiresAttention: false,
|
||||
attentionReason: null,
|
||||
attentionTimestamp: null,
|
||||
archivedAt,
|
||||
}),
|
||||
archiveSnapshot,
|
||||
closeAgent: async () => undefined,
|
||||
clearAgentAttention: async () => {},
|
||||
} as any,
|
||||
@@ -504,13 +505,13 @@ describe("workspace aggregation", () => {
|
||||
|
||||
expect(session.interruptAgentIfRunning).toHaveBeenCalledWith("agent-1");
|
||||
expect(session.terminalManager.killTerminal).toHaveBeenCalledWith("term-1");
|
||||
expect(
|
||||
emitted.find((message) => message.type === "close_items_response")?.payload,
|
||||
).toEqual({
|
||||
agents: [{ agentId: "agent-1", archivedAt }],
|
||||
const closePayload = emitted.find((message) => message.type === "close_items_response")?.payload;
|
||||
expect(closePayload).toEqual({
|
||||
agents: [{ agentId: "agent-1", archivedAt: expect.any(String) }],
|
||||
terminals: [{ terminalId: "term-1", success: true }],
|
||||
requestId: "req-close-items",
|
||||
});
|
||||
expect(archiveSnapshot).toHaveBeenCalledWith("agent-1", closePayload.agents[0].archivedAt);
|
||||
});
|
||||
|
||||
test("close_items_request continues after an archive failure", async () => {
|
||||
@@ -523,7 +524,31 @@ describe("workspace aggregation", () => {
|
||||
warn: vi.fn(),
|
||||
error: vi.fn(),
|
||||
};
|
||||
const archivedAt = "2026-04-01T00:00:00.000Z";
|
||||
const archiveSnapshot = vi.fn(async (agentId: string, archivedAt: string) => {
|
||||
if (agentId === "agent-bad") {
|
||||
throw new Error("archive failed");
|
||||
}
|
||||
return {
|
||||
id: "agent-good",
|
||||
provider: "codex",
|
||||
cwd: "/tmp/repo",
|
||||
createdAt: "2026-03-01T12:00:00.000Z",
|
||||
updatedAt: archivedAt,
|
||||
lastActivityAt: "2026-03-01T12:00:00.000Z",
|
||||
lastUserMessageAt: null,
|
||||
lastStatus: "idle" as const,
|
||||
lastModeId: null,
|
||||
runtimeInfo: null,
|
||||
config: null,
|
||||
persistence: null,
|
||||
title: null,
|
||||
labels: {},
|
||||
requiresAttention: false,
|
||||
attentionReason: null,
|
||||
attentionTimestamp: null,
|
||||
archivedAt,
|
||||
};
|
||||
});
|
||||
|
||||
const session = new Session({
|
||||
clientId: "test-client",
|
||||
@@ -537,31 +562,7 @@ describe("workspace aggregation", () => {
|
||||
listAgents: () => [],
|
||||
getAgent: (agentId: string) =>
|
||||
agentId === "agent-bad" || agentId === "agent-good" ? { id: agentId } : null,
|
||||
archiveSnapshot: async (agentId: string) => {
|
||||
if (agentId === "agent-bad") {
|
||||
throw new Error("archive failed");
|
||||
}
|
||||
return {
|
||||
id: "agent-good",
|
||||
provider: "codex",
|
||||
cwd: "/tmp/repo",
|
||||
createdAt: "2026-03-01T12:00:00.000Z",
|
||||
updatedAt: archivedAt,
|
||||
lastActivityAt: "2026-03-01T12:00:00.000Z",
|
||||
lastUserMessageAt: null,
|
||||
lastStatus: "idle" as const,
|
||||
lastModeId: null,
|
||||
runtimeInfo: null,
|
||||
config: null,
|
||||
persistence: null,
|
||||
title: null,
|
||||
labels: {},
|
||||
requiresAttention: false,
|
||||
attentionReason: null,
|
||||
attentionTimestamp: null,
|
||||
archivedAt,
|
||||
};
|
||||
},
|
||||
archiveSnapshot,
|
||||
closeAgent: async () => undefined,
|
||||
clearAgentAttention: async () => {},
|
||||
} as any,
|
||||
@@ -624,13 +625,13 @@ describe("workspace aggregation", () => {
|
||||
expect(session.interruptAgentIfRunning).toHaveBeenCalledWith("agent-bad");
|
||||
expect(session.interruptAgentIfRunning).toHaveBeenCalledWith("agent-good");
|
||||
expect(session.terminalManager.killTerminal).toHaveBeenCalledWith("term-1");
|
||||
expect(
|
||||
emitted.find((message) => message.type === "close_items_response")?.payload,
|
||||
).toEqual({
|
||||
agents: [{ agentId: "agent-good", archivedAt }],
|
||||
const closePayload = emitted.find((message) => message.type === "close_items_response")?.payload;
|
||||
expect(closePayload).toEqual({
|
||||
agents: [{ agentId: "agent-good", archivedAt: expect.any(String) }],
|
||||
terminals: [{ terminalId: "term-1", success: true }],
|
||||
requestId: "req-close-best-effort",
|
||||
});
|
||||
expect(archiveSnapshot).toHaveBeenCalledWith("agent-good", closePayload.agents[0].archivedAt);
|
||||
expect(sessionLogger.warn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
@@ -167,15 +167,16 @@ function createServer(options?: { speechReadiness?: SpeechReadinessSnapshot | nu
|
||||
"/tmp/paseo-test",
|
||||
async () => ({}) as any,
|
||||
{ allowedOrigins: new Set() },
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
speechReadiness
|
||||
? {
|
||||
getSpeechReadiness: () => speechReadiness,
|
||||
getReadiness: () => speechReadiness,
|
||||
onReadinessChange: vi.fn(() => () => {}),
|
||||
}
|
||||
: undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
TEST_DAEMON_VERSION,
|
||||
undefined,
|
||||
undefined,
|
||||
|
||||
@@ -237,6 +237,7 @@ describe("createPaseoWorktreeInBackground", () => {
|
||||
const logger = createLogger();
|
||||
const emitWorkspaceUpdateForCwd = vi.fn(async () => {});
|
||||
const archiveWorkspaceRecord = vi.fn(async () => {});
|
||||
const workspaceId = 101;
|
||||
|
||||
await createPaseoWorktreeInBackground(
|
||||
{
|
||||
@@ -253,6 +254,7 @@ describe("createPaseoWorktreeInBackground", () => {
|
||||
{
|
||||
requestCwd: repoDir,
|
||||
repoRoot: repoDir,
|
||||
workspaceId,
|
||||
worktree: {
|
||||
branchName: "broken-feature",
|
||||
worktreePath,
|
||||
@@ -275,7 +277,7 @@ describe("createPaseoWorktreeInBackground", () => {
|
||||
status: "failed",
|
||||
error: expect.stringContaining("Failed to parse paseo.json"),
|
||||
});
|
||||
expect(archiveWorkspaceRecord).toHaveBeenCalledWith(worktreePath);
|
||||
expect(archiveWorkspaceRecord).toHaveBeenCalledWith(workspaceId);
|
||||
expect(emitWorkspaceUpdateForCwd).toHaveBeenCalledWith(worktreePath);
|
||||
});
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ type CreatePaseoWorktreeInBackgroundDependencies = {
|
||||
emit: EmitSessionMessage;
|
||||
sessionLogger: Logger;
|
||||
terminalManager: TerminalManager | null;
|
||||
archiveWorkspaceRecord: (workspaceId: string) => Promise<void>;
|
||||
archiveWorkspaceRecord: (workspaceId: number) => Promise<void>;
|
||||
serviceRouteStore: ServiceRouteStore | null;
|
||||
daemonPort?: number | null;
|
||||
};
|
||||
@@ -134,6 +134,7 @@ type HandleCreatePaseoWorktreeRequestDependencies = {
|
||||
createPaseoWorktreeInBackground: (options: {
|
||||
requestCwd: string;
|
||||
repoRoot: string;
|
||||
workspaceId: number;
|
||||
worktree: WorktreeConfig;
|
||||
shouldBootstrap: boolean;
|
||||
}) => Promise<void>;
|
||||
@@ -625,6 +626,7 @@ export async function handleCreatePaseoWorktreeRequest(
|
||||
void dependencies.createPaseoWorktreeInBackground({
|
||||
requestCwd: request.cwd,
|
||||
repoRoot,
|
||||
workspaceId: workspace.id,
|
||||
worktree: createdWorktree.worktree,
|
||||
shouldBootstrap: createdWorktree.shouldBootstrap,
|
||||
});
|
||||
@@ -666,6 +668,7 @@ export async function createPaseoWorktreeInBackground(
|
||||
options: {
|
||||
requestCwd: string;
|
||||
repoRoot: string;
|
||||
workspaceId: number;
|
||||
worktree: WorktreeConfig;
|
||||
shouldBootstrap: boolean;
|
||||
},
|
||||
@@ -741,7 +744,7 @@ export async function createPaseoWorktreeInBackground(
|
||||
emitSetupProgress("failed", message);
|
||||
|
||||
if (!setupStarted) {
|
||||
await dependencies.archiveWorkspaceRecord(normalizePersistedWorkspaceId(worktree.worktreePath));
|
||||
await dependencies.archiveWorkspaceRecord(options.workspaceId);
|
||||
}
|
||||
|
||||
dependencies.sessionLogger.error(
|
||||
|
||||
@@ -58,12 +58,13 @@ describe("workspace message schemas", () => {
|
||||
payload: {
|
||||
kind: "upsert",
|
||||
workspace: {
|
||||
id: "/repo",
|
||||
projectId: "/repo",
|
||||
id: 1,
|
||||
projectId: 1,
|
||||
projectDisplayName: "repo",
|
||||
projectRootPath: "/repo",
|
||||
projectKind: "non_git",
|
||||
workspaceKind: "directory",
|
||||
workspaceDirectory: "/repo",
|
||||
projectKind: "directory",
|
||||
workspaceKind: "checkout",
|
||||
name: "repo",
|
||||
status: "done",
|
||||
activityAt: null,
|
||||
|
||||
Reference in New Issue
Block a user