Skip to content

Commit ba0abbf

Browse files
authored
feat: add Factory Droid aliases (#156)
1 parent 01b6f1b commit ba0abbf

File tree

9 files changed

+58
-4
lines changed

9 files changed

+58
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Repo: https://github.com/openclaw/acpx
77
### Changes
88

99
- Conformance/ACP: add a data-driven ACP core v1 conformance suite with CI smoke coverage, nightly coverage, and a hardened runner that reports startup failures cleanly and scopes filesystem checks to the session cwd. (#130) Thanks @lynnzc.
10+
- Agents/droid: add `factory-droid` and `factorydroid` aliases for the built-in Factory Droid adapter and sync the built-in docs. Thanks @vincentkoc.
1011

1112
### Breaking
1213

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@ Built-ins:
296296
| `opencode` | `npx -y opencode-ai acp` | [OpenCode](https://opencode.ai) |
297297
| `qwen` | native (`qwen --acp`) | [Qwen Code](https://github.com/QwenLM/qwen-code) |
298298

299+
`factory-droid` and `factorydroid` also resolve to the built-in `droid` adapter.
300+
299301
Additional built-in agent docs live in [agents/README.md](agents/README.md).
300302

301303
Use `--agent` as an escape hatch for custom ACP servers:

agents/Droid.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Droid
22

33
- Built-in name: `droid`
4+
- Aliases: `factory-droid`, `factorydroid`
45
- Default command: `droid exec --output-format acp`
56
- Upstream: https://www.factory.ai

agents/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Built-in agents:
99
- `gemini -> gemini --acp`
1010
- `cursor -> cursor-agent acp`
1111
- `copilot -> copilot --acp --stdio`
12-
- `droid -> droid exec --output-format acp`
12+
- `droid -> droid exec --output-format acp` (`factory-droid` and `factorydroid` also resolve to `droid`)
1313
- `iflow -> iflow --experimental-acp`
1414
- `kilocode -> npx -y @kilocode/cli acp`
1515
- `kimi -> kimi acp`
@@ -21,7 +21,7 @@ Harness-specific docs in this directory:
2121

2222
- [Codex](Codex.md): built-in `codex -> npx @zed-industries/codex-acp`
2323
- [Copilot](Copilot.md): built-in `copilot -> copilot --acp --stdio`
24-
- [Droid](Droid.md): built-in `droid -> droid exec --output-format acp`
24+
- [Droid](Droid.md): built-in `droid -> droid exec --output-format acp` with `factory-droid` and `factorydroid` aliases
2525
- [Cursor](Cursor.md): built-in `cursor -> cursor-agent acp`
2626
- [Gemini](Gemini.md): built-in `gemini -> gemini --acp`
2727
- [iFlow](Iflow.md): built-in `iflow -> iflow --experimental-acp`

docs/2026-02-17-agent-registry.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ When you run `acpx <agent> ...`:
2828

2929
This means custom names work without any registry file edits.
3030

31+
`factory-droid` and `factorydroid` are built-in aliases for `droid`, so they
32+
resolve to the same `droid exec --output-format acp` command.
33+
3134
## `--agent` escape hatch
3235

3336
`--agent <command>` forces a raw adapter command and bypasses positional agent resolution.

skills/acpx/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ Friendly agent names resolve to commands:
7878
- `gemini` -> `gemini --acp`
7979
- `cursor` -> `cursor-agent acp`
8080
- `copilot` -> `copilot --acp --stdio`
81-
- `droid` -> `droid exec --output-format acp`
81+
- `droid` -> `droid exec --output-format acp` (`factory-droid` and `factorydroid` also resolve to `droid`)
8282
- `kimi` -> `kimi acp`
8383
- `opencode` -> `npx -y opencode-ai acp`
8484
- `kiro` -> `kiro-cli acp`

src/agent-registry.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ export const AGENT_REGISTRY: Record<string, string> = {
2121
qwen: "qwen --acp",
2222
};
2323

24+
const AGENT_ALIASES: Record<string, string> = {
25+
"factory-droid": "droid",
26+
factorydroid: "droid",
27+
};
28+
2429
export const DEFAULT_AGENT_NAME = "codex";
2530

2631
export function normalizeAgentName(value: string): string {
@@ -46,7 +51,7 @@ export function mergeAgentRegistry(overrides?: Record<string, string>): Record<s
4651
export function resolveAgentCommand(agentName: string, overrides?: Record<string, string>): string {
4752
const normalized = normalizeAgentName(agentName);
4853
const registry = mergeAgentRegistry(overrides);
49-
return registry[normalized] ?? agentName;
54+
return registry[normalized] ?? registry[AGENT_ALIASES[normalized] ?? normalized] ?? agentName;
5055
}
5156

5257
export function listBuiltInAgents(overrides?: Record<string, string>): string[] {

test/agent-registry.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,21 @@ test("resolveAgentCommand returns raw value for unknown agents", () => {
1717
assert.equal(resolveAgentCommand("custom-acp-server"), "custom-acp-server");
1818
});
1919

20+
test("resolveAgentCommand maps factory droid aliases to the droid command", () => {
21+
assert.equal(resolveAgentCommand("factory-droid"), AGENT_REGISTRY.droid);
22+
assert.equal(resolveAgentCommand("factorydroid"), AGENT_REGISTRY.droid);
23+
});
24+
25+
test("resolveAgentCommand prefers explicit alias overrides over built-in alias mapping", () => {
26+
assert.equal(
27+
resolveAgentCommand("factory-droid", {
28+
"factory-droid": "custom-factory-droid --acp",
29+
droid: "custom-droid --acp",
30+
}),
31+
"custom-factory-droid --acp",
32+
);
33+
});
34+
2035
test("listBuiltInAgents preserves the required example prefix and alphabetical tail", () => {
2136
const agents = listBuiltInAgents();
2237
assert.deepEqual(agents, Object.keys(AGENT_REGISTRY));

test/integration.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,33 @@ test("integration: built-in droid agent resolves to droid exec --output-format a
9999
});
100100
});
101101

102+
test("integration: factory-droid alias resolves to droid exec --output-format acp", async () => {
103+
await withTempHome(async (homeDir) => {
104+
const cwd = await fs.mkdtemp(path.join(os.tmpdir(), "acpx-integration-cwd-"));
105+
const fakeBinDir = await fs.mkdtemp(path.join(os.tmpdir(), "acpx-fake-droid-"));
106+
107+
try {
108+
await writeFakeDroidAgent(fakeBinDir);
109+
110+
const result = await runCli(
111+
["--approve-all", "--cwd", cwd, "--format", "quiet", "factory-droid", "exec", "echo hello"],
112+
homeDir,
113+
{
114+
env: {
115+
PATH: `${fakeBinDir}${path.delimiter}${process.env.PATH ?? ""}`,
116+
},
117+
},
118+
);
119+
120+
assert.equal(result.code, 0, result.stderr);
121+
assert.match(result.stdout, /hello/);
122+
} finally {
123+
await fs.rm(fakeBinDir, { recursive: true, force: true });
124+
await fs.rm(cwd, { recursive: true, force: true });
125+
}
126+
});
127+
});
128+
102129
test("integration: built-in iflow agent resolves to iflow --experimental-acp", async () => {
103130
await withTempHome(async (homeDir) => {
104131
const cwd = await fs.mkdtemp(path.join(os.tmpdir(), "acpx-integration-cwd-"));

0 commit comments

Comments
 (0)