mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Improve Codex connection failure status
This commit is contained in:
parent
e32bff8a9b
commit
cd2d06dfeb
5 changed files with 55 additions and 1 deletions
|
|
@ -362,6 +362,7 @@ export function createChatViewControllerAssembly(host: ChatViewControllerAssembl
|
|||
resetThreadTurnPresence: host.effects.thread.resetTurnPresence,
|
||||
setStatus: host.effects.status.set,
|
||||
addSystemMessage: host.effects.status.addSystemMessage,
|
||||
configuredCommand: () => host.plugin.settings.codexPath,
|
||||
refreshLiveState: host.effects.liveState.refresh,
|
||||
render: host.effects.render.now,
|
||||
scheduleRender: host.effects.render.schedule,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export interface ChatConnectionControllerHost {
|
|||
resetThreadTurnPresence: (hadTurns: boolean) => void;
|
||||
setStatus: (status: string) => void;
|
||||
addSystemMessage: (text: string) => void;
|
||||
configuredCommand: () => string;
|
||||
refreshLiveState: () => void;
|
||||
render: () => void;
|
||||
scheduleRender: () => void;
|
||||
|
|
@ -125,7 +126,7 @@ export class ChatConnectionController {
|
|||
if (this.host.connectionWork.isStale(connection)) return;
|
||||
if (error instanceof StaleConnectionError) return;
|
||||
this.host.setStatus("Connection failed.");
|
||||
this.host.addSystemMessage(error instanceof Error ? error.message : String(error));
|
||||
this.host.addSystemMessage(connectionErrorMessage(error, this.host.configuredCommand()));
|
||||
this.host.notifyConnectionFailed();
|
||||
}
|
||||
if (!this.host.connectionWork.isStale(connection)) {
|
||||
|
|
@ -137,3 +138,15 @@ export class ChatConnectionController {
|
|||
this.host.stateStore.dispatch(action);
|
||||
}
|
||||
}
|
||||
|
||||
function connectionErrorMessage(error: unknown, configuredCommand: string): string {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
if (!isMissingCommandError(error)) return message;
|
||||
return `Could not start Codex app-server because the configured command was not found: ${configuredCommand}. Check the Codex command path in settings. (${message})`;
|
||||
}
|
||||
|
||||
function isMissingCommandError(error: unknown): boolean {
|
||||
if (!(error instanceof Error)) return false;
|
||||
const candidate = error as { code?: unknown; syscall?: unknown };
|
||||
return candidate.code === "ENOENT" && candidate.syscall === "spawn";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ export interface StatusDotStateInput {
|
|||
connected: boolean;
|
||||
turnBusy: boolean;
|
||||
diagnostics: AppServerDiagnostics;
|
||||
connectionFailed?: boolean;
|
||||
turnStartBlocked?: boolean;
|
||||
}
|
||||
|
||||
|
|
@ -156,6 +157,7 @@ export function toolbarViewModel(input: ToolbarViewModelInput): ToolbarViewModel
|
|||
connected: input.connected,
|
||||
turnBusy: input.turnBusy,
|
||||
diagnostics: state.appServerDiagnostics,
|
||||
connectionFailed: state.status === "Connection failed.",
|
||||
});
|
||||
const model = currentModel(snapshot, config);
|
||||
const effort = currentReasoningEffort(snapshot, config);
|
||||
|
|
@ -197,6 +199,7 @@ export function toolbarViewModel(input: ToolbarViewModelInput): ToolbarViewModel
|
|||
|
||||
export function statusDotState(input: StatusDotStateInput): ToolbarStatusState {
|
||||
if (input.turnBusy) return "running";
|
||||
if (input.connectionFailed) return "blocked";
|
||||
if (!input.connected) return "offline";
|
||||
if (input.turnStartBlocked) return "blocked";
|
||||
return hasDiagnosticIssue(input.diagnostics) ? "degraded" : "ready";
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ function createController({ connected = false, client = {} as AppServerClient }
|
|||
resetThreadTurnPresence: vi.fn(),
|
||||
setStatus: vi.fn(),
|
||||
addSystemMessage: vi.fn(),
|
||||
configuredCommand: () => "codex",
|
||||
refreshLiveState: vi.fn(),
|
||||
render: vi.fn(),
|
||||
scheduleRender: vi.fn(),
|
||||
|
|
@ -117,4 +118,18 @@ describe("ChatConnectionController", () => {
|
|||
runtimePicker: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("explains missing configured command failures", async () => {
|
||||
const { controller, connect, host } = createController();
|
||||
const error = Object.assign(new Error("spawn codex ENOENT"), { code: "ENOENT", syscall: "spawn" });
|
||||
connect.mockRejectedValueOnce(error);
|
||||
|
||||
await controller.ensureConnected();
|
||||
|
||||
expect(host.setStatus).toHaveBeenCalledWith("Connection failed.");
|
||||
expect(host.addSystemMessage).toHaveBeenCalledWith(
|
||||
"Could not start Codex app-server because the configured command was not found: codex. Check the Codex command path in settings. (spawn codex ENOENT)",
|
||||
);
|
||||
expect(host.notifyConnectionFailed).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ describe("chat view model", () => {
|
|||
|
||||
expect(statusDotState({ connected: true, turnBusy: true, diagnostics })).toBe("running");
|
||||
expect(statusDotState({ connected: false, turnBusy: false, diagnostics })).toBe("offline");
|
||||
expect(statusDotState({ connected: false, turnBusy: false, diagnostics, connectionFailed: true })).toBe("blocked");
|
||||
expect(statusDotState({ connected: true, turnBusy: false, diagnostics })).toBe("ready");
|
||||
expect(statusDotState({ connected: true, turnBusy: false, diagnostics, turnStartBlocked: true })).toBe("blocked");
|
||||
});
|
||||
|
|
@ -138,6 +139,27 @@ describe("chat view model", () => {
|
|||
expect(runningModel.statusState).toBe("running");
|
||||
});
|
||||
|
||||
it("marks connection failure status as blocked in the toolbar model", () => {
|
||||
const state = createChatState();
|
||||
state.status = "Connection failed.";
|
||||
|
||||
const model = toolbarViewModel({
|
||||
state,
|
||||
snapshot: runtimeSnapshotForChatState({ state }),
|
||||
connected: false,
|
||||
turnBusy: false,
|
||||
vaultPath: "/vault",
|
||||
configuredCommand: "codex",
|
||||
archiveConfirmThreadId: null,
|
||||
archiveExportEnabled: true,
|
||||
modelChoices: [],
|
||||
effortChoices: [],
|
||||
renameState: () => null,
|
||||
});
|
||||
|
||||
expect(model.statusState).toBe("blocked");
|
||||
});
|
||||
|
||||
it("builds slash-command status lines from chat state", () => {
|
||||
const state = createChatState();
|
||||
state.activeThreadId = "thread-1";
|
||||
|
|
|
|||
Loading…
Reference in a new issue