Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ Built-ins:
| `gemini` | native (`gemini --acp`) | [Gemini CLI](https://github.com/google/gemini-cli) |
| `cursor` | native (`cursor-agent acp`) | [Cursor CLI](https://cursor.com/docs/cli/acp) |
| `copilot` | native (`copilot --acp --stdio`) | [GitHub Copilot CLI](https://docs.github.com/copilot/how-tos/copilot-chat/use-copilot-chat-in-the-command-line) |
| `droid` | native (`droid exec --output-format acp`) | [Factory Droid](https://www.factory.ai) |
| `kimi` | native (`kimi acp`) | [Kimi CLI](https://github.com/MoonshotAI/kimi-cli) |
| `opencode` | `npx -y opencode-ai acp` | [OpenCode](https://opencode.ai) |
| `kiro` | native (`kiro-cli acp`) | [Kiro CLI](https://kiro.dev) |
Expand Down
5 changes: 5 additions & 0 deletions agents/Droid.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Droid

- Built-in name: `droid`
- Default command: `droid exec --output-format acp`
- Upstream: https://www.factory.ai
2 changes: 2 additions & 0 deletions agents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Built-in agents:
- `gemini -> gemini --acp`
- `cursor -> cursor-agent acp`
- `copilot -> copilot --acp --stdio`
- `droid -> droid exec --output-format acp`
- `kimi -> kimi acp`
- `opencode -> npx -y opencode-ai acp`
- `kiro -> kiro-cli acp`
Expand All @@ -20,6 +21,7 @@ Harness-specific docs in this directory:
- [Gemini](Gemini.md): built-in `gemini -> gemini --acp`
- [Cursor](Cursor.md): built-in `cursor -> cursor-agent acp`
- [Copilot](Copilot.md): built-in `copilot -> copilot --acp --stdio`
- [Droid](Droid.md): built-in `droid -> droid exec --output-format acp`
- [Kimi](Kimi.md): built-in `kimi -> kimi acp`
- [OpenCode](OpenCode.md): built-in `opencode -> npx -y opencode-ai acp`
- [Kiro](Kiro.md): built-in `kiro -> kiro-cli acp`
Expand Down
8 changes: 5 additions & 3 deletions skills/acpx/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,17 @@ If prompt text is omitted and stdin is piped, `acpx` reads prompt text from stdi

Friendly agent names resolve to commands:

- `pi` -> `npx pi-acp`
- `openclaw` -> `openclaw acp`
- `codex` -> `npx @zed-industries/codex-acp`
- `claude` -> `npx -y @zed-industries/claude-agent-acp`
- `copilot` -> `copilot --acp --stdio`
- `gemini` -> `gemini --acp`
- `openclaw` -> `openclaw acp`
- `cursor` -> `cursor-agent acp`
- `copilot` -> `copilot --acp --stdio`
- `droid` -> `droid exec --output-format acp`
- `kimi` -> `kimi acp`
- `opencode` -> `npx -y opencode-ai acp`
- `kiro` -> `kiro-cli acp`
- `pi` -> `npx pi-acp`
- `kilocode` -> `npx -y @kilocode/cli acp`
- `qwen` -> `qwen --acp`

Expand Down
1 change: 1 addition & 0 deletions src/agent-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const AGENT_REGISTRY: Record<string, string> = {
gemini: "gemini --acp",
cursor: "cursor-agent acp",
copilot: "copilot --acp --stdio",
droid: "droid exec --output-format acp",
kimi: "kimi acp",
opencode: "npx -y opencode-ai acp",
kiro: "kiro-cli acp",
Expand Down
8 changes: 7 additions & 1 deletion test/agent-registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,20 @@ test("resolveAgentCommand returns raw value for unknown agents", () => {
test("listBuiltInAgents preserves the required built-in example order", () => {
const agents = listBuiltInAgents();
assert.deepEqual(agents, Object.keys(AGENT_REGISTRY));
assert.deepEqual(agents.slice(0, 7), [
assert.deepEqual(agents, [
"pi",
"openclaw",
"codex",
"claude",
"gemini",
"cursor",
"copilot",
"droid",
"kimi",
"opencode",
"kiro",
"kilocode",
"qwen",
]);
});

Expand Down
65 changes: 65 additions & 0 deletions test/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,33 @@ test("integration: built-in cursor agent resolves to cursor-agent acp", async ()
});
});

test("integration: built-in droid agent resolves to droid exec --output-format acp", async () => {
await withTempHome(async (homeDir) => {
const cwd = await fs.mkdtemp(path.join(os.tmpdir(), "acpx-integration-cwd-"));
const fakeBinDir = await fs.mkdtemp(path.join(os.tmpdir(), "acpx-fake-droid-"));

try {
await writeFakeDroidAgent(fakeBinDir);

const result = await runCli(
["--approve-all", "--cwd", cwd, "--format", "quiet", "droid", "exec", "echo hello"],
homeDir,
{
env: {
PATH: `${fakeBinDir}${path.delimiter}${process.env.PATH ?? ""}`,
},
},
);

assert.equal(result.code, 0, result.stderr);
assert.match(result.stdout, /hello/);
} finally {
await fs.rm(fakeBinDir, { recursive: true, force: true });
await fs.rm(cwd, { recursive: true, force: true });
}
});
});

test("integration: exec forwards model, allowed-tools, and max-turns in session/new _meta", async () => {
await withTempHome(async (homeDir) => {
const cwd = await fs.mkdtemp(path.join(os.tmpdir(), "acpx-integration-cwd-"));
Expand Down Expand Up @@ -1529,6 +1556,44 @@ async function writeFakeCursorAgent(binDir: string): Promise<void> {
);
}

async function writeFakeDroidAgent(binDir: string): Promise<void> {
if (process.platform === "win32") {
await fs.writeFile(
path.join(binDir, "droid.cmd"),
[
"@echo off",
"setlocal",
'if /I "%~1"=="exec" shift',
'if /I "%~1"=="--output-format" shift',
'if /I "%~1"=="acp" shift',
`"${process.execPath}" "${MOCK_AGENT_PATH}" %*`,
"",
].join("\r\n"),
{ encoding: "utf8" },
);
return;
}

await fs.writeFile(
path.join(binDir, "droid"),
[
"#!/bin/sh",
'if [ "$1" = "exec" ]; then',
" shift",
"fi",
'if [ "$1" = "--output-format" ]; then',
" shift",
"fi",
'if [ "$1" = "acp" ]; then',
" shift",
"fi",
`exec "${process.execPath}" "${MOCK_AGENT_PATH}" "$@"`,
"",
].join("\n"),
{ encoding: "utf8", mode: 0o755 },
);
}

async function withTempHome(run: (homeDir: string) => Promise<void>): Promise<void> {
const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "acpx-integration-home-"));
try {
Expand Down