Files
fusion/plugins/fusion-plugin-droid-runtime/src/__tests__/process-manager.test.ts
gsxdsm 5191e1f22d FN-6911: defer Droid CLI startup probes
Defer Droid CLI validation and discovery so startup no longer spawns or hangs on droid.

- Register the Droid provider without boot-time validation or model discovery side effects.
- Trigger CLI validation only when a Droid stream starts and expose explicit model discovery.
- Add regression coverage for non-interactive droid process spawning and startup probe behavior.
- Add a patch changeset for the published Fusion CLI package.

Files changed:
 .changeset/fn-6911-droid-cli-no-boot-spawn.md      |  5 ++
 .../commands/__tests__/droid-cli-extension.test.ts | 15 +++-
 packages/droid-cli/index.ts                        | 33 ++++----
 packages/droid-cli/src/__tests__/index.test.ts     | 90 +++++++++-------------
 .../src/__tests__/discover-models.test.ts          |  7 +-
 .../src/__tests__/probe.test.ts                    |  8 ++
 .../src/__tests__/process-manager.test.ts          | 74 ++++++++++++++++++
 .../src/__tests__/startup-probes.test.ts           |  5 +-
 8 files changed, 160 insertions(+), 77 deletions(-)

Fusion-Task-Id: FN-6911

Fusion-Task-Lineage: ef4bc3df-bfe8-416a-b701-64f752faea30
2026-06-21 23:44:26 -07:00

75 lines
2.0 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { EventEmitter } from "node:events";
const spawnMock = vi.hoisted(() => vi.fn());
vi.mock("node:child_process", () => ({
spawn: spawnMock,
}));
import { buildDroidSpawnArgs, spawnDroid } from "../process-manager.js";
function makeProc() {
const proc = new EventEmitter() as any;
proc.killed = false;
proc.exitCode = null;
proc.pid = 123;
proc.kill = vi.fn(() => {
proc.killed = true;
});
return proc;
}
describe("Droid agent spawn invariants", () => {
beforeEach(() => {
spawnMock.mockReset();
});
afterEach(() => {
vi.restoreAllMocks();
});
it("builds a non-interactive print-mode stream-json invocation", () => {
const args = buildDroidSpawnArgs("droid-pro", undefined, {
effort: "high",
mcpConfigPath: "/tmp/mcp.json",
newSessionId: "session-1",
});
expect(args[0]).toBe("-p");
expect(args).toEqual(expect.arrayContaining([
"--input-format",
"stream-json",
"--output-format",
"stream-json",
"--model",
"droid-pro",
"--session-id",
"session-1",
"--effort",
"high",
"--mcp-config",
"/tmp/mcp.json",
]));
expect(args).not.toContain("models");
expect(args).not.toContain("model");
});
it("spawns droid with piped stdio and never inherits a TTY", () => {
const proc = makeProc();
spawnMock.mockReturnValueOnce(proc);
expect(spawnDroid("droid-pro", undefined, { cwd: "/tmp/project" })).toBe(proc);
expect(spawnMock).toHaveBeenCalledTimes(1);
const [binary, args, options] = spawnMock.mock.calls[0] as [string, string[], { stdio: string[]; cwd: string }];
expect(binary).toBe("droid");
expect(args[0]).toBe("-p");
expect(args).toEqual(expect.arrayContaining(["--input-format", "stream-json"]));
expect(options.cwd).toBe("/tmp/project");
expect(options.stdio).toEqual(["pipe", "pipe", "pipe"]);
expect(options.stdio).not.toBe("inherit");
expect(options.stdio).not.toContain("inherit");
});
});