






















@@ -52,6 +52,27 @@ describe("Codex Computer Use setup", () => {
5252expect(request).not.toHaveBeenCalledWith("plugin/install", expect.anything());
5353});
545455+it("reports an installed but disabled Computer Use plugin separately", async () => {
56+const request = createComputerUseRequest({ installed: true, enabled: false });
57+58+await expect(
59+readCodexComputerUseStatus({
60+pluginConfig: { computerUse: { enabled: true, marketplaceName: "desktop-tools" } },
61+ request,
62+}),
63+).resolves.toEqual(
64+expect.objectContaining({
65+ready: false,
66+installed: true,
67+pluginEnabled: false,
68+mcpServerAvailable: false,
69+message:
70+"Computer Use is installed, but the computer-use plugin is disabled. Run /codex computer-use install or enable computerUse.autoInstall to re-enable it.",
71+}),
72+);
73+expect(request).not.toHaveBeenCalledWith("plugin/install", expect.anything());
74+});
75+5576it("does not register marketplace sources during status checks", async () => {
5677const request = createComputerUseRequest({ installed: true });
5778@@ -129,6 +150,28 @@ describe("Codex Computer Use setup", () => {
129150expect(request).toHaveBeenCalledWith("config/mcpServer/reload", undefined);
130151});
131152153+it("re-enables an installed but disabled Computer Use plugin during install", async () => {
154+const request = createComputerUseRequest({ installed: true, enabled: false });
155+156+await expect(
157+installCodexComputerUse({
158+pluginConfig: { computerUse: { marketplaceName: "desktop-tools" } },
159+ request,
160+}),
161+).resolves.toEqual(
162+expect.objectContaining({
163+ready: true,
164+installed: true,
165+pluginEnabled: true,
166+message: "Computer Use is ready.",
167+}),
168+);
169+expect(request).toHaveBeenCalledWith("plugin/install", {
170+marketplacePath: "/marketplaces/desktop-tools/.agents/plugins/marketplace.json",
171+pluginName: "computer-use",
172+});
173+});
174+132175it("fails closed when Computer Use is required but not installed", async () => {
133176const request = createComputerUseRequest({ installed: false });
134177@@ -240,6 +283,27 @@ describe("Codex Computer Use setup", () => {
240283expect(request).not.toHaveBeenCalledWith("plugin/read", expect.anything());
241284});
242285286+it("fails closed instead of installing from a remote-only Codex marketplace", async () => {
287+const request = createRemoteOnlyComputerUseRequest();
288+289+await expect(
290+installCodexComputerUse({
291+pluginConfig: { computerUse: { marketplaceName: "openai-curated" } },
292+ request,
293+}),
294+).rejects.toMatchObject({
295+status: expect.objectContaining({
296+ready: false,
297+installed: false,
298+pluginEnabled: false,
299+marketplaceName: "openai-curated",
300+message:
301+"Computer Use is available in remote Codex marketplace openai-curated, but Codex app-server does not support remote plugin install yet. Configure computerUse.marketplaceSource or computerUse.marketplacePath for a local marketplace, then run /codex computer-use install.",
302+}),
303+});
304+expect(request).not.toHaveBeenCalledWith("plugin/install", expect.anything());
305+});
306+243307it("waits for the default Codex marketplace during install", async () => {
244308vi.useFakeTimers();
245309const request = createComputerUseRequest({
@@ -291,9 +355,11 @@ describe("Codex Computer Use setup", () => {
291355292356function createComputerUseRequest(params: {
293357installed: boolean;
358+enabled?: boolean;
294359marketplaceAvailableAfterListCalls?: number;
295360}): CodexComputerUseRequest {
296361let installed = params.installed;
362+let enabled = params.enabled ?? installed;
297363let pluginListCalls = 0;
298364return vi.fn(async (method: string, requestParams?: unknown) => {
299365if (method === "experimentalFeature/enablement/set") {
@@ -317,7 +383,7 @@ function createComputerUseRequest(params: {
317383name: "desktop-tools",
318384path: "/marketplaces/desktop-tools/.agents/plugins/marketplace.json",
319385interface: null,
320-plugins: [pluginSummary(installed)],
386+plugins: [pluginSummary(installed, "desktop-tools", enabled)],
321387},
322388]
323389 : [],
@@ -335,7 +401,7 @@ function createComputerUseRequest(params: {
335401plugin: {
336402marketplaceName: "desktop-tools",
337403marketplacePath: "/marketplaces/desktop-tools/.agents/plugins/marketplace.json",
338-summary: pluginSummary(installed),
404+summary: pluginSummary(installed, "desktop-tools", enabled),
339405description: "Control desktop apps.",
340406skills: [],
341407apps: [],
@@ -345,36 +411,78 @@ function createComputerUseRequest(params: {
345411}
346412if (method === "plugin/install") {
347413installed = true;
414+enabled = true;
348415return { authPolicy: "ON_INSTALL", appsNeedingAuth: [] };
349416}
350417if (method === "config/mcpServer/reload") {
351418return undefined;
352419}
353420if (method === "mcpServerStatus/list") {
354421return {
355-data: installed
356- ? [
357-{
358-name: "computer-use",
359-tools: {
360-list_apps: {
361-name: "list_apps",
362-inputSchema: { type: "object" },
422+data:
423+installed && enabled
424+ ? [
425+{
426+name: "computer-use",
427+tools: {
428+list_apps: {
429+name: "list_apps",
430+inputSchema: { type: "object" },
431+},
363432},
433+resources: [],
434+resourceTemplates: [],
435+authStatus: "unsupported",
364436},
365-resources: [],
366-resourceTemplates: [],
367-authStatus: "unsupported",
368-},
369-]
370- : [],
437+]
438+ : [],
371439nextCursor: null,
372440};
373441}
374442throw new Error(`unexpected request ${method}`);
375443}) as CodexComputerUseRequest;
376444}
377445446+function createRemoteOnlyComputerUseRequest(): CodexComputerUseRequest {
447+return vi.fn(async (method: string, requestParams?: unknown) => {
448+if (method === "experimentalFeature/enablement/set") {
449+return { enablement: { plugins: true } };
450+}
451+if (method === "plugin/list") {
452+return {
453+marketplaces: [
454+{
455+name: "openai-curated",
456+path: null,
457+interface: null,
458+plugins: [pluginSummary(false, "openai-curated", false, "remote")],
459+},
460+],
461+marketplaceLoadErrors: [],
462+featuredPluginIds: [],
463+};
464+}
465+if (method === "plugin/read") {
466+expect(requestParams).toEqual({
467+remoteMarketplaceName: "openai-curated",
468+pluginName: "computer-use",
469+});
470+return {
471+plugin: {
472+marketplaceName: "openai-curated",
473+marketplacePath: null,
474+summary: pluginSummary(false, "openai-curated", false, "remote"),
475+description: "Control desktop apps.",
476+skills: [],
477+apps: [],
478+mcpServers: ["computer-use"],
479+},
480+};
481+}
482+throw new Error(`unexpected request ${method}`);
483+}) as CodexComputerUseRequest;
484+}
485+378486function createAmbiguousComputerUseRequest(): CodexComputerUseRequest {
379487return vi.fn(async (method: string) => {
380488if (method === "plugin/list") {
@@ -488,13 +596,21 @@ function marketplaceEntry(marketplaceName: string, installed: boolean) {
488596};
489597}
490598491-function pluginSummary(installed: boolean, marketplaceName = "desktop-tools") {
599+function pluginSummary(
600+installed: boolean,
601+marketplaceName = "desktop-tools",
602+enabled = installed,
603+source: "local" | "remote" = "local",
604+) {
492605return {
493606id: `computer-use@${marketplaceName}`,
494607name: "computer-use",
495-source: { type: "local", path: `/marketplaces/${marketplaceName}/plugins/computer-use` },
608+source:
609+source === "local"
610+ ? { type: "local", path: `/marketplaces/${marketplaceName}/plugins/computer-use` }
611+ : { type: "remote" },
496612 installed,
497-enabled: installed,
613+ enabled,
498614installPolicy: "AVAILABLE",
499615authPolicy: "ON_INSTALL",
500616interface: null,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。