fix(codex): add array coercion and typed arguments for CLI-backed routes

- Coerce mcp/plugins/marketplaces GET responses to arrays (CLI may emit
  object), degrading to empty list rather than crash on unexpected shape
- Add typed interfaces: CodexMcpAddArgs, CodexPluginActionArgs,
  CodexMarketplaceActionArgs with validated action literals
- Mirrors ccConfig's type safety across the namespace
This commit is contained in:
2026-09-08 20:27:52 +07:00
parent 2ae9b06652
commit 8021e569f2
+43 -9
View File
@@ -1700,25 +1700,37 @@ export const api = {
requestCodexBackupsHelper(params), requestCodexBackupsHelper(params),
/** /**
* GET /api/codex-config/mcp - configured MCP servers from the codex CLI. * GET /api/codex-config/mcp - configured MCP servers from the codex CLI.
* Coerces the CLI's JSON output (which may be an object) to an array.
* @returns `{ mcp }` — {@link CodexMcpServer} items. * @returns `{ mcp }` — {@link CodexMcpServer} items.
*/ */
mcp: () => request<{ mcp: CodexMcpServer[] }>("/codex-config/mcp"), mcp: async () => {
const res = await request<{ mcp: unknown }>("/codex-config/mcp");
return { mcp: Array.isArray(res.mcp) ? res.mcp : [] };
},
/** /**
* GET /api/codex-config/plugins - installed plugins from the codex CLI. * GET /api/codex-config/plugins - installed plugins from the codex CLI.
* Coerces the CLI's JSON output (which may be an object) to an array.
* @returns `{ plugins }` — {@link CodexPlugin} items. * @returns `{ plugins }` — {@link CodexPlugin} items.
*/ */
plugins: () => request<{ plugins: CodexPlugin[] }>("/codex-config/plugins"), plugins: async () => {
const res = await request<{ plugins: unknown }>("/codex-config/plugins");
return { plugins: Array.isArray(res.plugins) ? res.plugins : [] };
},
/** /**
* GET /api/codex-config/marketplaces - registered marketplaces from the codex CLI. * GET /api/codex-config/marketplaces - registered marketplaces from the codex CLI.
* Coerces the CLI's JSON output (which may be an object) to an array.
* @returns `{ marketplaces }` — {@link CodexMarketplace} items. * @returns `{ marketplaces }` — {@link CodexMarketplace} items.
*/ */
marketplaces: () => request<{ marketplaces: CodexMarketplace[] }>("/codex-config/marketplaces"), marketplaces: async () => {
const res = await request<{ marketplaces: unknown }>("/codex-config/marketplaces");
return { marketplaces: Array.isArray(res.marketplaces) ? res.marketplaces : [] };
},
/** /**
* POST /api/codex-config/mcp/add - add an MCP server via the `codex` CLI. * POST /api/codex-config/mcp/add - add an MCP server via the `codex` CLI.
* @param args Arguments for `codex mcp add`. * @param args {@link CodexMcpAddArgs} for `codex mcp add`.
* @returns `{ ok, stdout, stderr }` — success and CLI output. * @returns `{ ok, stdout, stderr }` — success and CLI output.
*/ */
mcpAdd: (args: unknown) => mcpAdd: (args: CodexMcpAddArgs) =>
request<{ ok: true; stdout: string; stderr: string }>("/codex-config/mcp/add", { request<{ ok: true; stdout: string; stderr: string }>("/codex-config/mcp/add", {
method: "POST", method: "POST",
body: JSON.stringify(args), body: JSON.stringify(args),
@@ -1735,10 +1747,10 @@ export const api = {
}), }),
/** /**
* POST /api/codex-config/plugins/action - add or remove a plugin via the `codex` CLI. * POST /api/codex-config/plugins/action - add or remove a plugin via the `codex` CLI.
* @param args Arguments with `spec` and `action` fields. * @param args {@link CodexPluginActionArgs} with `spec` and `action` fields.
* @returns `{ ok, stdout, stderr }` — success and CLI output. * @returns `{ ok, stdout, stderr }` — success and CLI output.
*/ */
pluginAction: (args: unknown) => pluginAction: (args: CodexPluginActionArgs) =>
request<{ ok: true; stdout: string; stderr: string }>("/codex-config/plugins/action", { request<{ ok: true; stdout: string; stderr: string }>("/codex-config/plugins/action", {
method: "POST", method: "POST",
body: JSON.stringify(args), body: JSON.stringify(args),
@@ -1755,10 +1767,10 @@ export const api = {
}), }),
/** /**
* POST /api/codex-config/marketplaces/action - update or remove a marketplace via the `codex` CLI. * POST /api/codex-config/marketplaces/action - update or remove a marketplace via the `codex` CLI.
* @param args Arguments with `name` and `action` fields. * @param args {@link CodexMarketplaceActionArgs} with `name` and `action` fields.
* @returns `{ ok, stdout, stderr }` — success and CLI output. * @returns `{ ok, stdout, stderr }` — success and CLI output.
*/ */
marketplaceAction: (args: unknown) => marketplaceAction: (args: CodexMarketplaceActionArgs) =>
request<{ ok: true; stdout: string; stderr: string }>("/codex-config/marketplaces/action", { request<{ ok: true; stdout: string; stderr: string }>("/codex-config/marketplaces/action", {
method: "POST", method: "POST",
body: JSON.stringify(args), body: JSON.stringify(args),
@@ -2994,6 +3006,28 @@ export interface CodexMarketplace {
[key: string]: unknown; [key: string]: unknown;
} }
/** Arguments for POST /api/codex-config/mcp/add. */
export interface CodexMcpAddArgs {
name: string;
url?: string;
bearerTokenEnvVar?: string;
command?: string;
args?: string[];
env?: Record<string, string>;
}
/** Arguments for POST /api/codex-config/plugins/action. */
export interface CodexPluginActionArgs {
spec: string;
action: "add" | "remove";
}
/** Arguments for POST /api/codex-config/marketplaces/action. */
export interface CodexMarketplaceActionArgs {
name: string;
action: "remove";
}
// ───────────────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────────────
// Run types — request/response shapes for the Run page's `claude` process // Run types — request/response shapes for the Run page's `claude` process
// spawning/management. `RunMode`/`RunStatus`/`PermissionMode`/`EffortLevel` // spawning/management. `RunMode`/`RunStatus`/`PermissionMode`/`EffortLevel`