acpx/test/queue-owner-process.test.ts
DMQ 3b94ac9c39
feat(cli): add terminal capability opt-out
Add --no-terminal so ACPX can initialize new agent clients with clientCapabilities.terminal=false.

Reworked on current main because the original branch targeted stale paths. Includes CLI/docs/changelog updates plus regression coverage for direct exec and queue-owner propagation.

Local verification:
- fnm exec --using=24.15.0 corepack pnpm@10.33.2 run check

CI: https://github.com/openclaw/acpx/actions/runs/24926378907

Co-authored-by: DMQ <6860287+DMQ@users.noreply.github.com>
2026-04-25 09:08:35 +01:00

127 lines
3.6 KiB
TypeScript

import assert from "node:assert/strict";
import { realpathSync } from "node:fs";
import { mkdtemp, rm, symlink, writeFile } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { describe, it } from "node:test";
import {
buildQueueOwnerArgOverride,
queueOwnerRuntimeOptionsFromSend,
resolveQueueOwnerSpawnArgs,
sanitizeQueueOwnerExecArgv,
} from "../src/cli/session/queue-owner-process.js";
async function withTempDir(run: (dir: string) => Promise<void>): Promise<void> {
const dir = await mkdtemp(path.join(os.tmpdir(), "acpx-queue-owner-path-"));
try {
await run(dir);
} finally {
await rm(dir, { recursive: true, force: true });
}
}
describe("resolveQueueOwnerSpawnArgs", () => {
it("prefers ACPX_QUEUE_OWNER_ARGS when provided", () => {
const previous = process.env.ACPX_QUEUE_OWNER_ARGS;
process.env.ACPX_QUEUE_OWNER_ARGS = JSON.stringify([
"--import",
"tsx",
"src/cli.ts",
"__queue-owner",
]);
try {
const args = resolveQueueOwnerSpawnArgs(["node", "ignored.js"]);
assert.deepEqual(args, ["--import", "tsx", "src/cli.ts", "__queue-owner"]);
} finally {
if (previous === undefined) {
delete process.env.ACPX_QUEUE_OWNER_ARGS;
} else {
process.env.ACPX_QUEUE_OWNER_ARGS = previous;
}
}
});
it("returns <real cli path> and __queue-owner", async () => {
await withTempDir(async (dir) => {
const cliFile = path.join(dir, "cli.js");
const cliLink = path.join(dir, "acpx-link.js");
await writeFile(cliFile, "// stub\n", "utf8");
await symlink(cliFile, cliLink);
const args = resolveQueueOwnerSpawnArgs(["node", cliLink]);
assert.deepEqual(args, [realpathSync(cliLink), "__queue-owner"]);
});
});
it("throws when argv lacks an entry path", () => {
assert.throws(() => resolveQueueOwnerSpawnArgs(["node"]), {
message: "acpx self-spawn failed: missing CLI entry path",
});
});
});
describe("sanitizeQueueOwnerExecArgv", () => {
it("drops test runner coverage flags but keeps loader args", () => {
assert.deepEqual(
sanitizeQueueOwnerExecArgv([
"--experimental-test-coverage",
"--test",
"--test-name-pattern",
"flow",
"--import",
"tsx",
"--loader",
"custom-loader",
]),
["--import", "tsx", "--loader", "custom-loader"],
);
});
it("drops debugger flags from queue-owner exec args", () => {
assert.deepEqual(
sanitizeQueueOwnerExecArgv([
"--inspect-brk=9229",
"--inspect-port",
"9230",
"--debug-port=9231",
"--import",
"tsx",
]),
["--import", "tsx"],
);
});
});
describe("buildQueueOwnerArgOverride", () => {
it("returns null when no loader args remain after sanitization", () => {
assert.equal(
buildQueueOwnerArgOverride("/tmp/cli.js", [
"--experimental-test-coverage",
"--test",
"--test-name-pattern",
"flow",
]),
null,
);
});
it("returns a serialized override when loader args are required", () => {
assert.equal(
buildQueueOwnerArgOverride("/tmp/cli.js", ["--import", "tsx"]),
JSON.stringify(["--import", "tsx", "/tmp/cli.js", "__queue-owner"]),
);
});
});
describe("queueOwnerRuntimeOptionsFromSend", () => {
it("preserves terminal capability preference", () => {
const options = queueOwnerRuntimeOptionsFromSend({
sessionId: "session-1",
permissionMode: "approve-reads",
terminal: false,
});
assert.equal(options.terminal, false);
});
});