skillhub/cli/test/helpers/run-cli.ts
Danny 7cf9f22182
feat(cli): add OAuth device flow login (#857)
* feat(cli): add OAuth device flow login

Signed-off-by: Danny5487401 <64348131+Danny5487401@users.noreply.github.com>

* fix(cli): avoid browser launch in headless login

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>

* fix(cli): complete device flow runtime path

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>

---------

Signed-off-by: Danny5487401 <64348131+Danny5487401@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Co-authored-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-17 16:29:20 +08:00

56 lines
1.9 KiB
TypeScript

import { existsSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
/**
* Spawn the CLI with a clean environment so host-shell exports like
* SKILLHUB_REGISTRY or SKILLHUB_TOKEN don't leak into the test process and
* silently override stored credentials/config. Tests can still inject any
* SKILLHUB_* variable explicitly via the `env` argument.
*/
function sanitizeProcessEnv(): Record<string, string> {
const cleaned: Record<string, string> = {}
for (const [key, value] of Object.entries(process.env)) {
if (typeof value !== 'string') continue
if (key.startsWith('SKILLHUB_')) continue
cleaned[key] = value
}
return cleaned
}
export interface RunCliOptions {
/**
* Working directory for the child process. Defaults to the CLI package root
* so `bun src/index.ts` resolves. Pass a temp dir when the command scans
* cwd (e.g. `doctor`) so tests don't leak fixtures into the repo tree.
*/
cwd?: string
}
export async function runCli(
args: string[],
env: Record<string, string> = {},
options: RunCliOptions = {}
) {
// Use Bun.which() to find bun in PATH, but verify it exists
const whichBun = await Bun.which('bun')
const bunPath = (whichBun && existsSync(whichBun)) ? whichBun : process.execPath
const cliRoot = fileURLToPath(new URL('../../', import.meta.url))
const entry = `${cliRoot}src/index.ts`
const proc = Bun.spawn({
cmd: [bunPath, entry, ...args],
cwd: options.cwd ?? cliRoot,
// Integration tests must never launch real desktop applications. Tests
// that exercise browser-launch behavior inject a fake launcher directly.
env: { ...sanitizeProcessEnv(), CI: 'true', ...env },
stdout: 'pipe',
stderr: 'pipe'
})
const [stdout, stderr, exitCode] = await Promise.all([
new Response(proc.stdout).text(),
new Response(proc.stderr).text(),
proc.exited
])
return { stdout: stdout.trim(), stderr: stderr.trim(), exitCode }
}