Connect daemons to Hub through browser approval (#2208)
* feat(cli): connect daemons to Hub through browser approval Let interactive setup complete through a short-lived browser authorization while preserving --token for automation and existing integrations. * ci: build server before CLI tests * fix(cli): keep Hub approval polling within expiry Bound both response headers and body consumption to the original authorization lifetime so stalled responses remain retryable without extending approval. Run the CLI test helper through Node and the resolved tsx entry for cross-platform behavior. * fix(cli): bound Hub registration startup Fail a stalled authorization start within a fixed timeout without retrying the non-idempotent request. Declare the response validator as a direct CLI runtime dependency. * fix(cli): restrict Hub activation URLs * fix(cli): harden Hub approval transport
This commit is contained in:
@@ -16,6 +16,7 @@ import { mkdtemp, rm, mkdir } from "fs/promises";
|
||||
import { existsSync } from "fs";
|
||||
import { tmpdir } from "os";
|
||||
import { join } from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { ChildProcess, spawn } from "child_process";
|
||||
import { getAvailablePort } from "./network.ts";
|
||||
|
||||
@@ -43,6 +44,7 @@ const TEST_DAEMON_ENV_DEFAULTS: Record<string, string> = {
|
||||
PASEO_VOICE_MODE_ENABLED: process.env.PASEO_VOICE_MODE_ENABLED ?? "0",
|
||||
};
|
||||
const TEST_DAEMON_HOST = "127.0.0.1";
|
||||
const TSX_ENTRY = fileURLToPath(import.meta.resolve("tsx/cli"));
|
||||
|
||||
const DEFAULT_OUTPUT_CAPTURE_LIMIT = 256 * 1024;
|
||||
const TEST_OUTPUT_CAPTURE_LIMIT = Number.parseInt(
|
||||
@@ -233,19 +235,23 @@ export async function startTestDaemon(options?: {
|
||||
const cliSrcPath = join(cliDir, "src", "index.ts");
|
||||
|
||||
// Start daemon process using tsx to run TypeScript directly
|
||||
const daemonProcess = spawn("npx", ["tsx", cliSrcPath, "daemon", "start", "--foreground"], {
|
||||
env: {
|
||||
...process.env,
|
||||
...TEST_DAEMON_ENV_DEFAULTS,
|
||||
PASEO_HOME: paseoHome,
|
||||
PASEO_LISTEN: `${TEST_DAEMON_HOST}:${port}`,
|
||||
// Force no TTY to prevent QR code output
|
||||
CI: "true",
|
||||
...options?.env,
|
||||
const daemonProcess = spawn(
|
||||
process.execPath,
|
||||
[TSX_ENTRY, cliSrcPath, "daemon", "start", "--foreground"],
|
||||
{
|
||||
env: {
|
||||
...process.env,
|
||||
...TEST_DAEMON_ENV_DEFAULTS,
|
||||
PASEO_HOME: paseoHome,
|
||||
PASEO_LISTEN: `${TEST_DAEMON_HOST}:${port}`,
|
||||
// Force no TTY to prevent QR code output
|
||||
CI: "true",
|
||||
...options?.env,
|
||||
},
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
detached: process.platform !== "win32",
|
||||
},
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
detached: process.platform !== "win32",
|
||||
});
|
||||
);
|
||||
|
||||
const stdout = createOutputCapture();
|
||||
const stderr = createOutputCapture();
|
||||
@@ -345,7 +351,7 @@ export async function runPaseoCli(
|
||||
const cliSrcPath = join(cliDir, "src", "index.ts");
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const proc = spawn("npx", ["tsx", cliSrcPath, ...args], {
|
||||
const proc = spawn(process.execPath, [TSX_ENTRY, cliSrcPath, ...args], {
|
||||
env: {
|
||||
...process.env,
|
||||
...TEST_DAEMON_ENV_DEFAULTS,
|
||||
|
||||
Reference in New Issue
Block a user