Files
hapi/cli/src/commands/auth.ts
T
weishu aa0c3f2f0d refactor(cli): split command routing and modularize RPC handlers
Restructure CLI entry point and RPC handler registration to improve maintainability:

- Introduce command registry pattern with CommandDefinition interface for consistent command structure
- Extract individual command modules (claude, codex, daemon, doctor, gemini, auth, connect, etc.)
- Move RPC handlers into separate feature modules (bash, files, git, directories, ripgrep, difftastic, slashCommands)
- Create shared RPC types and response helpers (rpcTypes.ts, rpcResponses.ts)
- Move SpawnSessionOptions and SpawnSessionResult to rpcTypes for proper type organization
- Simplify index.ts to minimal entrypoint using command registry
- Update imports in apiMachine.ts and daemon/run.ts to use rpcTypes module

This enables:
- Better code organization by feature/command
- Easier testing of individual commands
- Safer RPC handler registration without side effects
- Clearer separation of concerns between routing and business logic
2026-01-03 17:29:05 +08:00

118 lines
4.2 KiB
TypeScript

import chalk from 'chalk'
import os from 'node:os'
import * as readline from 'node:readline/promises'
import { stdin as input, stdout as output } from 'node:process'
import { configuration } from '@/configuration'
import { readSettings, clearMachineId, updateSettings } from '@/persistence'
import type { CommandDefinition } from './types'
export async function handleAuthCommand(args: string[]): Promise<void> {
const subcommand = args[0]
if (!subcommand || subcommand === 'help' || subcommand === '--help' || subcommand === '-h') {
showHelp()
return
}
if (subcommand === 'status') {
const settings = await readSettings()
const envToken = process.env.CLI_API_TOKEN
const settingsToken = settings.cliApiToken
const hasToken = Boolean(envToken || settingsToken)
const tokenSource = envToken ? 'environment' : (settingsToken ? 'settings file' : 'none')
console.log(chalk.bold('\nDirect Connect Status\n'))
console.log(chalk.gray(` HAPI_SERVER_URL: ${configuration.serverUrl}`))
console.log(chalk.gray(` CLI_API_TOKEN: ${hasToken ? 'set' : 'missing'}`))
console.log(chalk.gray(` Token Source: ${tokenSource}`))
console.log(chalk.gray(` Machine ID: ${settings.machineId ?? 'not set'}`))
console.log(chalk.gray(` Host: ${os.hostname()}`))
if (!hasToken) {
console.log('')
console.log(chalk.yellow(' Token not configured. To get your token:'))
console.log(chalk.gray(' 1. Check the server startup logs (first run shows generated token)'))
console.log(chalk.gray(' 2. Read ~/.hapi/settings.json on the server'))
console.log(chalk.gray(' 3. Ask your server administrator (if token is set via env var)'))
console.log('')
console.log(chalk.gray(' Then run: hapi auth login'))
}
return
}
if (subcommand === 'login') {
if (!process.stdin.isTTY) {
console.error(chalk.red('Cannot prompt for token in non-TTY environment.'))
console.error(chalk.gray('Set CLI_API_TOKEN environment variable instead.'))
process.exit(1)
}
const rl = readline.createInterface({ input, output })
try {
const token = await rl.question(chalk.cyan('Enter CLI_API_TOKEN: '))
if (!token.trim()) {
console.error(chalk.red('Token cannot be empty'))
process.exit(1)
}
await updateSettings(current => ({
...current,
cliApiToken: token.trim()
}))
configuration._setCliApiToken(token.trim())
console.log(chalk.green(`\nToken saved to ${configuration.settingsFile}`))
} finally {
rl.close()
}
return
}
if (subcommand === 'logout') {
await updateSettings(current => ({
...current,
cliApiToken: undefined
}))
await clearMachineId()
console.log(chalk.green('Cleared local credentials (token and machineId).'))
console.log(chalk.gray('Note: If CLI_API_TOKEN is set via environment variable, it will still be used.'))
return
}
console.error(chalk.red(`Unknown auth subcommand: ${subcommand}`))
showHelp()
process.exit(1)
}
function showHelp(): void {
console.log(`
${chalk.bold('hapi auth')} - Authentication management
${chalk.bold('Usage:')}
hapi auth status Show current configuration
hapi auth login Enter and save CLI_API_TOKEN
hapi auth logout Clear saved credentials
${chalk.bold('Token priority (highest to lowest):')}
1. CLI_API_TOKEN environment variable
2. ~/.hapi/settings.json
3. Interactive prompt (on first run)
`)
}
export const authCommand: CommandDefinition = {
name: 'auth',
requiresRuntimeAssets: true,
run: async ({ commandArgs }) => {
try {
await handleAuthCommand(commandArgs)
} catch (error) {
console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error')
if (process.env.DEBUG) {
console.error(error)
}
process.exit(1)
}
}
}