mirror of
https://github.com/humanlayer/humanlayer.git
synced 2025-08-20 19:01:22 +03:00
remove tui refs
This commit is contained in:
@@ -30,8 +30,7 @@ This is a monorepo containing two distinct but interconnected project groups:
|
||||
### Components
|
||||
- `hld/` - Go daemon that coordinates approvals and manages Claude Code sessions
|
||||
- `hlyr/` - TypeScript CLI with MCP (Model Context Protocol) server for Claude integration
|
||||
- `humanlayer-tui/` - Terminal UI (Go + Bubble Tea) for managing approvals
|
||||
- `humanlayer-wui/` - Desktop/Web UI (Tauri + React) for graphical approval management
|
||||
- `humanlayer-wui/` - CodeLayer - Desktop/Web UI (Tauri + React) for graphical approval management
|
||||
- `claudecode-go/` - Go SDK for programmatically launching Claude Code sessions
|
||||
|
||||
### Architecture Flow
|
||||
|
||||
5
Makefile
5
Makefile
@@ -29,9 +29,6 @@ check-hlyr:
|
||||
check-wui:
|
||||
@$(MAKE) -C humanlayer-wui check VERBOSE=$(VERBOSE)
|
||||
|
||||
check-tui:
|
||||
@$(MAKE) -C humanlayer-tui check VERBOSE=$(VERBOSE)
|
||||
|
||||
check-hld:
|
||||
@$(MAKE) -C hld check VERBOSE=$(VERBOSE)
|
||||
|
||||
@@ -46,7 +43,7 @@ check-header:
|
||||
# Summary removed - tracking doesn't work across sub-makes
|
||||
|
||||
.PHONY: check
|
||||
check: check-header check-py check-ts check-hlyr check-wui check-tui check-hld check-claudecode-go
|
||||
check: check-header check-py check-ts check-hlyr check-wui check-hld check-claudecode-go
|
||||
|
||||
typecheck: ## just the typechecks
|
||||
@. ./hack/run_silent.sh && run_silent "Static type checking: mypy" "uv run mypy"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# HumanLayer CLI (hlyr) Makefile
|
||||
|
||||
.PHONY: help install dev build build-go build-daemon build-tui lint format format-check test test-watch check check-quiet clean
|
||||
.PHONY: help install dev build build-go build-daemon lint format format-check test test-watch check check-quiet clean
|
||||
|
||||
help: ## Show this help message
|
||||
@echo "Available commands:"
|
||||
@@ -21,9 +21,6 @@ build-go: ## Build Go binaries (daemon and TUI)
|
||||
build-daemon: ## Build the daemon binary
|
||||
npm run build-daemon
|
||||
|
||||
build-tui: ## Build the TUI binary
|
||||
npm run build-tui
|
||||
|
||||
lint: ## Run ESLint
|
||||
npm run lint
|
||||
|
||||
|
||||
@@ -321,7 +321,6 @@ async function runInteractiveMode(query?: string) {
|
||||
log('info', `Approval ID: ${event.data.approval_id}`)
|
||||
log('info', `Tool: ${event.data.tool_name || 'N/A'}`)
|
||||
log('info', '\nYou can approve/deny this in:')
|
||||
log('info', ' - TUI: npx humanlayer tui')
|
||||
log('info', ' - WUI: Open the desktop app')
|
||||
log('info', ` - Session URL: #/sessions/${session.session_id}\n`)
|
||||
} else if (event.type === 'approval_resolved') {
|
||||
@@ -342,7 +341,6 @@ async function runInteractiveMode(query?: string) {
|
||||
log('info', `Session ID: ${session.session_id}`)
|
||||
log('info', `Run ID: ${session.run_id}`)
|
||||
log('info', '\n🛠️ Manage approvals:')
|
||||
log('info', ' TUI: npx humanlayer tui')
|
||||
log('info', ' WUI: Open the HumanLayer desktop app')
|
||||
log('info', '\n📊 Monitoring MCP logs...')
|
||||
log('info', 'Press Ctrl+C to stop monitoring\n')
|
||||
|
||||
@@ -13,9 +13,8 @@
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsup src/index.ts --format esm --target es2020 --clean && npm run build-go",
|
||||
"build-go": "npm run build-daemon && npm run build-tui",
|
||||
"build-go": "npm run build-daemon",
|
||||
"build-daemon": "cd ../hld && go build -o hld ./cmd/hld && mkdir -p ../hlyr/dist/bin && cp hld ../hlyr/dist/bin/",
|
||||
"build-tui": "cd ../humanlayer-tui && go build -o humanlayer-tui . && mkdir -p ../hlyr/dist/bin && cp humanlayer-tui ../hlyr/dist/bin/",
|
||||
"build:watch": "tsup src/index.ts --format esm --target es2020 --watch",
|
||||
"dev": "npm run build && ./dist/index.js",
|
||||
"lint": "eslint . --ext .ts",
|
||||
|
||||
@@ -183,8 +183,7 @@ export async function alertCommand(options: AlertOptions = {}): Promise<void> {
|
||||
console.error(chalk.red(`Error: ${error}`))
|
||||
|
||||
// Check if daemon is running
|
||||
console.error(chalk.gray('\nMake sure the HumanLayer daemon is running:'))
|
||||
console.error(chalk.gray(' npx humanlayer tui'))
|
||||
console.error(chalk.gray('\nMake sure the HumanLayer daemon is running'))
|
||||
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ export const launchCommand = async (query: string, options: LaunchOptions = {})
|
||||
console.log('\nSession launched successfully!')
|
||||
console.log('Session ID:', result.session_id)
|
||||
console.log('Run ID:', result.run_id)
|
||||
console.log('\nYou can now use "npx humanlayer tui" to manage approvals for this session.')
|
||||
console.log('\nYou can now use CodeLayer manage this session.')
|
||||
} finally {
|
||||
// Close the client connection
|
||||
client.close()
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
import { spawn } from 'child_process'
|
||||
import { join } from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { dirname } from 'path'
|
||||
import { existsSync } from 'fs'
|
||||
import { homedir } from 'os'
|
||||
import { connect } from 'net'
|
||||
import { resolveFullConfig } from '../config.js'
|
||||
|
||||
// Check if the daemon is running by trying to connect to its socket
|
||||
async function isDaemonRunning(socketPath: string): Promise<boolean> {
|
||||
return new Promise(resolve => {
|
||||
const client = connect(socketPath, () => {
|
||||
client.end()
|
||||
resolve(true)
|
||||
})
|
||||
|
||||
client.on('error', () => {
|
||||
resolve(false)
|
||||
})
|
||||
|
||||
// Set a timeout
|
||||
client.setTimeout(1000, () => {
|
||||
client.destroy()
|
||||
resolve(false)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Start the daemon in the background
|
||||
async function startDaemon(
|
||||
daemonPath: string,
|
||||
config: { api_key?: string; api_base_url?: string },
|
||||
): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log('Starting HumanLayer daemon...')
|
||||
|
||||
// Pass configuration via environment variables
|
||||
const env = { ...process.env }
|
||||
if (config.api_key) {
|
||||
env.HUMANLAYER_API_KEY = config.api_key
|
||||
}
|
||||
if (config.api_base_url) {
|
||||
env.HUMANLAYER_API_BASE_URL = config.api_base_url
|
||||
}
|
||||
|
||||
const daemon = spawn(daemonPath, [], {
|
||||
detached: true,
|
||||
stdio: 'ignore',
|
||||
env,
|
||||
})
|
||||
|
||||
daemon.on('error', err => {
|
||||
reject(new Error(`Failed to start daemon: ${err.message}`))
|
||||
})
|
||||
|
||||
daemon.on('spawn', () => {
|
||||
// Daemon started successfully
|
||||
daemon.unref() // Allow parent to exit independently
|
||||
|
||||
// Give the daemon a moment to initialize
|
||||
setTimeout(() => {
|
||||
console.log('Daemon started successfully')
|
||||
resolve()
|
||||
}, 2000)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const tuiCommand = async (options: Record<string, unknown> = {}) => {
|
||||
let child: ReturnType<typeof spawn> | null = null
|
||||
|
||||
try {
|
||||
// Get the directory of the current module
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = dirname(__filename)
|
||||
|
||||
// Get socket path from configuration
|
||||
const config = resolveFullConfig(options)
|
||||
let socketPath = config.daemon_socket
|
||||
|
||||
// Expand ~ to home directory if needed
|
||||
if (socketPath.startsWith('~')) {
|
||||
socketPath = join(homedir(), socketPath.slice(1))
|
||||
}
|
||||
|
||||
// Check if daemon is running
|
||||
const daemonRunning = await isDaemonRunning(socketPath)
|
||||
|
||||
if (!daemonRunning) {
|
||||
// Look for daemon binary
|
||||
const daemonPath = join(__dirname, './bin/hld')
|
||||
|
||||
if (!existsSync(daemonPath)) {
|
||||
console.error('Daemon binary not found at:', daemonPath)
|
||||
console.error('Please ensure the HumanLayer daemon is installed.')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
try {
|
||||
await startDaemon(daemonPath, config)
|
||||
} catch (err) {
|
||||
console.error('Failed to start daemon:', err)
|
||||
console.error('You can try starting it manually with: hld')
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Path to the Go binary in dist/bin
|
||||
const binaryPath = join(__dirname, './bin/humanlayer-tui')
|
||||
|
||||
// Prepare environment with daemon socket path if needed
|
||||
const env = { ...process.env }
|
||||
if (socketPath !== join(homedir(), '.humanlayer', 'daemon.sock')) {
|
||||
env.HUMANLAYER_DAEMON_SOCKET = socketPath
|
||||
}
|
||||
|
||||
// Spawn the Go binary
|
||||
child = spawn(binaryPath, [], { stdio: 'inherit', env })
|
||||
|
||||
// Handle child process exit
|
||||
child.on('exit', code => process.exit(code ?? 0))
|
||||
child.on('error', err => {
|
||||
console.error('Failed to start the TUI binary:', err)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
// Handle termination signals
|
||||
const handleSignal = (signal: NodeJS.Signals) => {
|
||||
if (child) {
|
||||
// Send the same signal to the child process
|
||||
child.kill(signal)
|
||||
}
|
||||
}
|
||||
|
||||
// Register signal handlers
|
||||
process.on('SIGINT', handleSignal) // Ctrl+C
|
||||
process.on('SIGTERM', handleSignal) // kill command
|
||||
process.on('SIGHUP', handleSignal) // terminal closed
|
||||
|
||||
// Cleanup on parent process exit
|
||||
process.on('exit', () => {
|
||||
if (child) {
|
||||
child.kill()
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error running tui:', error)
|
||||
if (child) {
|
||||
child.kill()
|
||||
}
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import { readFileSync } from 'fs'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { dirname, join } from 'path'
|
||||
import { loginCommand } from './commands/login.js'
|
||||
import { tuiCommand } from './commands/tui.js'
|
||||
import { contactHumanCommand } from './commands/contactHuman.js'
|
||||
import { configShowCommand } from './commands/configShow.js'
|
||||
import { pingCommand } from './commands/ping.js'
|
||||
@@ -105,13 +104,6 @@ program
|
||||
.option('--config-file <path>', 'Path to config file')
|
||||
.action(loginCommand)
|
||||
|
||||
program
|
||||
.command('tui')
|
||||
.description('Run the HumanLayer Terminal UI')
|
||||
.option('--daemon-socket <path>', 'Path to daemon socket')
|
||||
.option('--config-file <path>', 'Path to config file')
|
||||
.action(tuiCommand)
|
||||
|
||||
program
|
||||
.command('launch <query>')
|
||||
.description('Launch a new Claude Code session via the daemon')
|
||||
@@ -225,11 +217,6 @@ program.on('command:*', operands => {
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
// Set up default action when no command is provided
|
||||
program.action(() => {
|
||||
tuiCommand()
|
||||
})
|
||||
|
||||
// Override the default error handling
|
||||
program.configureOutput({
|
||||
writeErr: str => {
|
||||
|
||||
@@ -56,7 +56,7 @@ bun hack/test-local-approvals.ts -q "Hello, how are you?"
|
||||
While running in interactive mode:
|
||||
|
||||
- Approval requests will be highlighted in the console
|
||||
- Use TUI (`npx humanlayer tui`) or WUI to approve/deny
|
||||
- Use CodeLayer UI to approve/deny
|
||||
- Press Ctrl+C to stop monitoring
|
||||
|
||||
## What the Test Does
|
||||
|
||||
Reference in New Issue
Block a user