From 768b58c6dbb7092b71ad04acd9d015bc4fcc27e3 Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Tue, 27 Oct 2026 11:08:53 +0800 Subject: [PATCH] fix(setup): honor Droid home override --- src/application/SupportedClients.ts | 5 +- .../setup/droidSelectedHomeCli.test.ts | 57 +++++++++++++++++++ .../droidClientConfiguration.test.ts | 18 ++++++ tests/fixtures/clientEnvironment.ts | 1 + 4 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 tests/acceptance/setup/droidSelectedHomeCli.test.ts diff --git a/src/application/SupportedClients.ts b/src/application/SupportedClients.ts index 0cba3dae3a..7b0cb756ad 100644 --- a/src/application/SupportedClients.ts +++ b/src/application/SupportedClients.ts @@ -196,8 +196,9 @@ const kimiDirectory = ({ home, env }: ClientPathContext): string => const qoderDirectory = ({ home, env }: ClientPathContext): string => env.QODER_CONFIG_DIR || join(home, ".qoder"); -const factoryDirectory = ({ home }: ClientPathContext): string => - join(home, ".factory"); +/** Droid's override selects the home containing .factory, including personal skills. */ +const factoryDirectory = ({ home, env }: ClientPathContext): string => + join(env.FACTORY_HOME_OVERRIDE || home, ".factory"); /** Match Qwen Code's home override, including tilde and cwd-relative paths. */ const qwenCodeDirectory = ({ home, env }: ClientPathContext): string => { diff --git a/tests/acceptance/setup/droidSelectedHomeCli.test.ts b/tests/acceptance/setup/droidSelectedHomeCli.test.ts new file mode 100644 index 0000000000..0cf43456d5 --- /dev/null +++ b/tests/acceptance/setup/droidSelectedHomeCli.test.ts @@ -0,0 +1,57 @@ +import { access, mkdir, readFile, writeFile } from "node:fs/promises"; +import { join } from "node:path"; +import { expect } from "vitest"; + +import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; +import { cliTest } from "../../support/cli/cliFixture.js"; + +cliTest( + "registers Droid in its selected home and preserves peers and backups", + async ({ cli }) => { + const home = await createTestTempDirectory("rea-droid-home-"); + const selected = join(home, "selected"); + const config = join(selected, ".factory", "mcp.json"); + const original = JSON.stringify({ + mcpServers: { peer: { command: "peer" } }, + }); + await mkdir(join(selected, ".factory"), { recursive: true }); + await writeFile(config, original); + const run = () => + cli.run({ + arguments: [ + "setup", + "--client", + "droid", + "--skill=false", + "--yes", + "--json", + ], + cwd: home, + environment: { + HOME: home, + USERPROFILE: home, + FACTORY_HOME_OVERRIDE: selected, + HOPPER_LAUNCHER_PATH: join(home, "missing-hopper"), + GHIDRA_INSTALL_DIR: join(home, "missing-ghidra"), + JAVA_HOME: join(home, "missing-java"), + }, + }); + const first = await run(); + expect(first.exitCode, first.stdout).toBe(0); + const configured = await readFile(config, "utf8"); + expect(JSON.parse(configured)).toMatchObject({ + mcpServers: { + peer: { command: "peer" }, + rea: { args: expect.arrayContaining(["mcp"]) }, + }, + }); + expect(await readFile(`${config}.rea.backup`, "utf8")).toBe(original); + await expect( + access(join(home, ".factory", "mcp.json")), + ).rejects.toMatchObject({ code: "ENOENT" }); + const second = await run(); + expect(second.exitCode, second.stdout).toBe(0); + expect(await readFile(config, "utf8")).toBe(configured); + expect(await readFile(`${config}.rea.backup`, "utf8")).toBe(original); + }, +); diff --git a/tests/boundary/filesystem/droidClientConfiguration.test.ts b/tests/boundary/filesystem/droidClientConfiguration.test.ts index 6f9b264233..992113d8d0 100644 --- a/tests/boundary/filesystem/droidClientConfiguration.test.ts +++ b/tests/boundary/filesystem/droidClientConfiguration.test.ts @@ -51,6 +51,24 @@ describe("Factory Droid configuration paths", () => { join("/home/a", ".factory", "skills", "reverse-engineer-anything"), ]); }); + + it("uses Droid's selected home for configuration, discovery, and personal skills", () => { + const environment = { FACTORY_HOME_OVERRIDE: "/selected/home" }; + expect(droidPath("/home/a", "darwin", environment)).toMatchObject({ + configPath: join("/selected/home", ".factory", "mcp.json"), + markerPath: join("/selected/home", ".factory"), + }); + expect( + skillDestinations("/home/a", ["droid"], environment).map( + ({ path }) => path, + ), + ).toEqual([ + join("/selected/home", ".factory", "skills", "reverse-engineer-anything"), + ]); + expect( + droidPath("/home/a", "darwin", { FACTORY_HOME_OVERRIDE: "" }), + ).toEqual(droidPath("/home/a", "darwin")); + }); }); describe("Factory Droid JSON registration", () => { diff --git a/tests/fixtures/clientEnvironment.ts b/tests/fixtures/clientEnvironment.ts index 5a2a99f2ec..9b73fc5949 100644 --- a/tests/fixtures/clientEnvironment.ts +++ b/tests/fixtures/clientEnvironment.ts @@ -18,6 +18,7 @@ export const CLIENT_LOCATION_ENVIRONMENT = [ "DSH_HOME", "DSH_AGENTS_HOME", "COPILOT_HOME", + "FACTORY_HOME_OVERRIDE", "GROK_HOME", "GEMINI_CLI_HOME", "GEMINI_CLI_TRUST_WORKSPACE",