Merge branch 'development' into development_tmux
* development: ... ... ... ... # Conflicts: # examples/osal/sshagent.vsh # examples/osal/sshagent/sshagent_example.v # examples/osal/tmux.vsh # lib/osal/sshagent/agent.v # lib/osal/sshagent/builder_integration.v # lib/osal/tmux/tmux_pane.v # lib/osal/tmux/tmux_scan.v # lib/osal/tmux/tmux_session.v # lib/osal/tmux/tmux_window.v
This commit is contained in:
@@ -1,86 +0,0 @@
|
||||
module core
|
||||
|
||||
import freeflowuniverse.herolib.core.pathlib
|
||||
import os
|
||||
|
||||
@[params]
|
||||
pub struct SSHConfig {
|
||||
pub:
|
||||
directory string = os.join_path(os.home_dir(), '.ssh')
|
||||
}
|
||||
|
||||
// Returns a specific SSH key with the given name from the default SSH directory (~/.ssh)
|
||||
pub fn get_ssh_key(key_name string, config SSHConfig) ?SSHKey {
|
||||
mut ssh_dir := pathlib.get_dir(path: config.directory) or { return none }
|
||||
|
||||
list := ssh_dir.list(files_only: true) or { return none }
|
||||
for file in list.paths {
|
||||
if file.name() == key_name {
|
||||
return SSHKey{
|
||||
name: file.name()
|
||||
directory: ssh_dir.path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return none
|
||||
}
|
||||
|
||||
// Lists SSH keys in the default SSH directory (~/.ssh) and returns an array of SSHKey structs
|
||||
fn list_ssh_keys(config SSHConfig) ![]SSHKey {
|
||||
mut ssh_dir := pathlib.get_dir(path: config.directory) or {
|
||||
return error('Error getting ssh directory: ${err}')
|
||||
}
|
||||
|
||||
mut keys := []SSHKey{}
|
||||
list := ssh_dir.list(files_only: true) or {
|
||||
return error('Failed to list files in SSH directory')
|
||||
}
|
||||
|
||||
for file in list.paths {
|
||||
if file.extension() == 'pub' || file.name().starts_with('id_') {
|
||||
keys << SSHKey{
|
||||
name: file.name()
|
||||
directory: ssh_dir.path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
// Creates a new SSH key pair to the specified directory
|
||||
pub fn new_ssh_key(key_name string, config SSHConfig) !SSHKey {
|
||||
ssh_dir := pathlib.get_dir(
|
||||
path: config.directory
|
||||
create: true
|
||||
) or { return error('Error getting SSH directory: ${err}') }
|
||||
|
||||
// Paths for the private and public keys
|
||||
priv_key_path := os.join_path(ssh_dir.path, key_name)
|
||||
pub_key_path := '${priv_key_path}.pub'
|
||||
|
||||
// Check if the key already exists
|
||||
if os.exists(priv_key_path) || os.exists(pub_key_path) {
|
||||
return error("Key pair already exists with the name '${key_name}'")
|
||||
}
|
||||
|
||||
panic('implement shhkeygen logic')
|
||||
// Generate a random private key (for demonstration purposes)
|
||||
// Replace this with actual key generation logic (e.g., calling `ssh-keygen` or similar)
|
||||
// private_key_content := '-----BEGIN PRIVATE KEY-----\n${rand.string(64)}\n-----END PRIVATE KEY-----'
|
||||
// public_key_content := 'ssh-rsa ${rand.string(64)} user@host'
|
||||
|
||||
// Save the keys to their respective files
|
||||
// os.write_file(priv_key_path, private_key_content) or {
|
||||
// return error("Failed to write private key: ${err}")
|
||||
// }
|
||||
// os.write_file(pub_key_path, public_key_content) or {
|
||||
// return error("Failed to write public key: ${err}")
|
||||
// }
|
||||
|
||||
return SSHKey{
|
||||
name: key_name
|
||||
directory: ssh_dir.path
|
||||
}
|
||||
}
|
||||
@@ -39,3 +39,85 @@ pub fn (key SSHKey) private_key() !string {
|
||||
content := path.read()!
|
||||
return content
|
||||
}
|
||||
|
||||
@[params]
|
||||
pub struct SSHConfig {
|
||||
pub:
|
||||
directory string = os.join_path(os.home_dir(), '.ssh')
|
||||
}
|
||||
|
||||
// Returns a specific SSH key with the given name from the default SSH directory (~/.ssh)
|
||||
pub fn get_ssh_key(key_name string, config SSHConfig) ?SSHKey {
|
||||
mut ssh_dir := pathlib.get_dir(path: config.directory) or { return none }
|
||||
|
||||
list := ssh_dir.list(files_only: true) or { return none }
|
||||
for file in list.paths {
|
||||
if file.name() == key_name {
|
||||
return SSHKey{
|
||||
name: file.name()
|
||||
directory: ssh_dir.path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return none
|
||||
}
|
||||
|
||||
// Lists SSH keys in the default SSH directory (~/.ssh) and returns an array of SSHKey structs
|
||||
fn list_ssh_keys(config SSHConfig) ![]SSHKey {
|
||||
mut ssh_dir := pathlib.get_dir(path: config.directory) or {
|
||||
return error('Error getting ssh directory: ${err}')
|
||||
}
|
||||
|
||||
mut keys := []SSHKey{}
|
||||
list := ssh_dir.list(files_only: true) or {
|
||||
return error('Failed to list files in SSH directory')
|
||||
}
|
||||
|
||||
for file in list.paths {
|
||||
if file.extension() == 'pub' || file.name().starts_with('id_') {
|
||||
keys << SSHKey{
|
||||
name: file.name()
|
||||
directory: ssh_dir.path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
// Creates a new SSH key pair to the specified directory
|
||||
pub fn new_ssh_key(key_name string, config SSHConfig) !SSHKey {
|
||||
ssh_dir := pathlib.get_dir(
|
||||
path: config.directory
|
||||
create: true
|
||||
) or { return error('Error getting SSH directory: ${err}') }
|
||||
|
||||
// Paths for the private and public keys
|
||||
priv_key_path := os.join_path(ssh_dir.path, key_name)
|
||||
pub_key_path := '${priv_key_path}.pub'
|
||||
|
||||
// Check if the key already exists
|
||||
if os.exists(priv_key_path) || os.exists(pub_key_path) {
|
||||
return error("Key pair already exists with the name '${key_name}'")
|
||||
}
|
||||
|
||||
panic('implement shhkeygen logic')
|
||||
// Generate a random private key (for demonstration purposes)
|
||||
// Replace this with actual key generation logic (e.g., calling `ssh-keygen` or similar)
|
||||
// private_key_content := '-----BEGIN PRIVATE KEY-----\n${rand.string(64)}\n-----END PRIVATE KEY-----'
|
||||
// public_key_content := 'ssh-rsa ${rand.string(64)} user@host'
|
||||
|
||||
// Save the keys to their respective files
|
||||
// os.write_file(priv_key_path, private_key_content) or {
|
||||
// return error("Failed to write private key: ${err}")
|
||||
// }
|
||||
// os.write_file(pub_key_path, public_key_content) or {
|
||||
// return error("Failed to write public key: ${err}")
|
||||
// }
|
||||
|
||||
return SSHKey{
|
||||
name: key_name
|
||||
directory: ssh_dir.path
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,6 @@ pub:
|
||||
pub fn new(args LinuxNewArgs) !LinuxFactory {
|
||||
mut t := LinuxFactory{
|
||||
username: args.username
|
||||
}
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
@@ -11,34 +11,34 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
|
||||
// Process user_create actions
|
||||
play_user_create(mut plbook, mut lf)!
|
||||
|
||||
|
||||
// Process user_delete actions
|
||||
play_user_delete(mut plbook, mut lf)!
|
||||
|
||||
|
||||
// Process sshkey_create actions
|
||||
play_sshkey_create(mut plbook, mut lf)!
|
||||
|
||||
|
||||
// Process sshkey_delete actions
|
||||
play_sshkey_delete(mut plbook, mut lf)!
|
||||
}
|
||||
|
||||
fn play_user_create(mut plbook PlayBook, mut lf LinuxFactory) ! {
|
||||
mut actions := plbook.find(filter: 'usermgmt.user_create')!
|
||||
|
||||
|
||||
for mut action in actions {
|
||||
mut p := action.params
|
||||
|
||||
|
||||
mut args := UserCreateArgs{
|
||||
name: p.get('name')!
|
||||
giteakey: p.get_default('giteakey', '')!
|
||||
giteaurl: p.get_default('giteaurl', '')!
|
||||
passwd: p.get_default('passwd', '')!
|
||||
name: p.get('name')!
|
||||
giteakey: p.get_default('giteakey', '')!
|
||||
giteaurl: p.get_default('giteaurl', '')!
|
||||
passwd: p.get_default('passwd', '')!
|
||||
description: p.get_default('description', '')!
|
||||
email: p.get_default('email', '')!
|
||||
tel: p.get_default('tel', '')!
|
||||
sshkey: p.get_default('sshkey', '')! // SSH public key
|
||||
email: p.get_default('email', '')!
|
||||
tel: p.get_default('tel', '')!
|
||||
sshkey: p.get_default('sshkey', '')! // SSH public key
|
||||
}
|
||||
|
||||
|
||||
lf.user_create(args)!
|
||||
action.done = true
|
||||
}
|
||||
@@ -46,14 +46,14 @@ fn play_user_create(mut plbook PlayBook, mut lf LinuxFactory) ! {
|
||||
|
||||
fn play_user_delete(mut plbook PlayBook, mut lf LinuxFactory) ! {
|
||||
mut actions := plbook.find(filter: 'usermgmt.user_delete')!
|
||||
|
||||
|
||||
for mut action in actions {
|
||||
mut p := action.params
|
||||
|
||||
|
||||
mut args := UserDeleteArgs{
|
||||
name: p.get('name')!
|
||||
}
|
||||
|
||||
|
||||
lf.user_delete(args)!
|
||||
action.done = true
|
||||
}
|
||||
@@ -61,17 +61,17 @@ fn play_user_delete(mut plbook PlayBook, mut lf LinuxFactory) ! {
|
||||
|
||||
fn play_sshkey_create(mut plbook PlayBook, mut lf LinuxFactory) ! {
|
||||
mut actions := plbook.find(filter: 'usermgmt.sshkey_create')!
|
||||
|
||||
|
||||
for mut action in actions {
|
||||
mut p := action.params
|
||||
|
||||
|
||||
mut args := SSHKeyCreateArgs{
|
||||
username: p.get('username')!
|
||||
username: p.get('username')!
|
||||
sshkey_name: p.get('sshkey_name')!
|
||||
sshkey_pub: p.get_default('sshkey_pub', '')!
|
||||
sshkey_pub: p.get_default('sshkey_pub', '')!
|
||||
sshkey_priv: p.get_default('sshkey_priv', '')!
|
||||
}
|
||||
|
||||
|
||||
lf.sshkey_create(args)!
|
||||
action.done = true
|
||||
}
|
||||
@@ -79,16 +79,16 @@ fn play_sshkey_create(mut plbook PlayBook, mut lf LinuxFactory) ! {
|
||||
|
||||
fn play_sshkey_delete(mut plbook PlayBook, mut lf LinuxFactory) ! {
|
||||
mut actions := plbook.find(filter: 'usermgmt.sshkey_delete')!
|
||||
|
||||
|
||||
for mut action in actions {
|
||||
mut p := action.params
|
||||
|
||||
|
||||
mut args := SSHKeyDeleteArgs{
|
||||
username: p.get('username')!
|
||||
username: p.get('username')!
|
||||
sshkey_name: p.get('sshkey_name')!
|
||||
}
|
||||
|
||||
|
||||
lf.sshkey_delete(args)!
|
||||
action.done = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
lib/osal/linux/templates/profile_sshagent.sh
Normal file
12
lib/osal/linux/templates/profile_sshagent.sh
Normal file
@@ -0,0 +1,12 @@
|
||||
# Auto-start ssh-agent if not running
|
||||
SSH_AGENT_PID_FILE="$HOME/.ssh/agent.pid"
|
||||
SSH_AUTH_SOCK_FILE="$HOME/.ssh/agent.sock"
|
||||
|
||||
chown "$NEWUSER":"$NEWUSER" "$PROFILE_SCRIPT"
|
||||
chmod 644 "$PROFILE_SCRIPT"
|
||||
|
||||
# --- source it on login ---
|
||||
#TODO should be done in vcode
|
||||
if ! grep -q ".profile_sshagent" "$USERHOME/.bashrc"; then
|
||||
echo "[ -f ~/.profile_sshagent ] && source ~/.profile_sshagent" >> "$USERHOME/.bashrc"
|
||||
fi
|
||||
@@ -57,19 +57,4 @@ chown root:ourworld /code
|
||||
chmod 2775 /code # rwx for user+group, SGID bit so new files inherit group
|
||||
echo "✅ /code prepared (group=ourworld, rwx for group, SGID bit set)"
|
||||
|
||||
# --- create login helper script for ssh-agent ---
|
||||
PROFILE_SCRIPT="$USERHOME/.profile_sshagent"
|
||||
cat > "$PROFILE_SCRIPT" <<'EOF'
|
||||
# Auto-start ssh-agent if not running
|
||||
SSH_AGENT_PID_FILE="$HOME/.ssh/agent.pid"
|
||||
SSH_AUTH_SOCK_FILE="$HOME/.ssh/agent.sock"
|
||||
|
||||
chown "$NEWUSER":"$NEWUSER" "$PROFILE_SCRIPT"
|
||||
chmod 644 "$PROFILE_SCRIPT"
|
||||
|
||||
# --- source it on login ---
|
||||
if ! grep -q ".profile_sshagent" "$USERHOME/.bashrc"; then
|
||||
echo "[ -f ~/.profile_sshagent ] && source ~/.profile_sshagent" >> "$USERHOME/.bashrc"
|
||||
fi
|
||||
|
||||
echo "🎉 Setup complete for user $NEWUSER"
|
||||
@@ -119,7 +119,9 @@ pub fn (mut lf LinuxFactory) sshkey_create(args SSHKeyCreateArgs) ! {
|
||||
} else {
|
||||
// Generate new SSH key (modern ed25519)
|
||||
key_path := '${ssh_dir}/${args.sshkey_name}'
|
||||
osal.exec(cmd: 'ssh-keygen -t ed25519 -f ${key_path} -N "" -C "${args.username}@$(hostname)"')!
|
||||
osal.exec(
|
||||
cmd: 'ssh-keygen -t ed25519 -f ${key_path} -N "" -C "${args.username}@$(hostname)"'
|
||||
)!
|
||||
console.print_green('✅ New SSH key generated for ${args.username}')
|
||||
}
|
||||
|
||||
@@ -175,12 +177,12 @@ fn (mut lf LinuxFactory) save_user_config(args UserCreateArgs) ! {
|
||||
}
|
||||
|
||||
new_config := UserConfig{
|
||||
name: args.name
|
||||
giteakey: args.giteakey
|
||||
giteaurl: args.giteaurl
|
||||
email: args.email
|
||||
name: args.name
|
||||
giteakey: args.giteakey
|
||||
giteaurl: args.giteaurl
|
||||
email: args.email
|
||||
description: args.description
|
||||
tel: args.tel
|
||||
tel: args.tel
|
||||
}
|
||||
|
||||
if found_idx >= 0 {
|
||||
@@ -201,7 +203,7 @@ fn (mut lf LinuxFactory) remove_user_config(username string) ! {
|
||||
config_path := '${config_dir}/myconfig.json'
|
||||
|
||||
if !os.exists(config_path) {
|
||||
return // Nothing to remove
|
||||
return
|
||||
}
|
||||
|
||||
content := osal.file_read(config_path)!
|
||||
@@ -243,7 +245,9 @@ fn (mut lf LinuxFactory) create_user_system(args UserCreateArgs) ! {
|
||||
|
||||
// Ensure ourworld group exists
|
||||
group_check := osal.exec(cmd: 'getent group ourworld', raise_error: false) or {
|
||||
osal.Job{ exit_code: 1 }
|
||||
osal.Job{
|
||||
exit_code: 1
|
||||
}
|
||||
}
|
||||
if group_check.exit_code != 0 {
|
||||
console.print_item('➕ Creating group ourworld')
|
||||
@@ -284,58 +288,9 @@ fn (mut lf LinuxFactory) create_ssh_agent_profile(username string) ! {
|
||||
user_home := '/home/${username}'
|
||||
profile_script := '${user_home}/.profile_sshagent'
|
||||
|
||||
script_content := '# Auto-start ssh-agent if not running
|
||||
SSH_AGENT_PID_FILE="$HOME/.ssh/agent.pid"
|
||||
SSH_AUTH_SOCK_FILE="$HOME/.ssh/agent.sock"
|
||||
// script_content := ''
|
||||
|
||||
# Function to start ssh-agent
|
||||
start_ssh_agent() {
|
||||
mkdir -p "$HOME/.ssh"
|
||||
chmod 700 "$HOME/.ssh"
|
||||
|
||||
# Start ssh-agent and save connection info
|
||||
ssh-agent -s > "$SSH_AGENT_PID_FILE"
|
||||
source "$SSH_AGENT_PID_FILE"
|
||||
|
||||
# Save socket path for future sessions
|
||||
echo "$SSH_AUTH_SOCK" > "$SSH_AUTH_SOCK_FILE"
|
||||
|
||||
# Load all private keys found in ~/.ssh
|
||||
if [ -d "$HOME/.ssh" ]; then
|
||||
for KEY in "$HOME"/.ssh/*; do
|
||||
if [ -f "$KEY" ] && [ ! "${KEY##*.}" = "pub" ] && grep -q "PRIVATE KEY" "$KEY" 2>/dev/null; then
|
||||
'ssh-' + 'add "$KEY" >/dev/null 2>&1 && echo "🔑 Loaded key: $(basename $KEY)"'
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if ssh-agent is running
|
||||
if [ -f "$SSH_AGENT_PID_FILE" ]; then
|
||||
source "$SSH_AGENT_PID_FILE" >/dev/null 2>&1
|
||||
# Test if agent is responsive
|
||||
if ! ('ssh-' + 'add -l >/dev/null 2>&1'); then
|
||||
start_ssh_agent
|
||||
else
|
||||
# Agent is running, restore socket path
|
||||
if [ -f "$SSH_AUTH_SOCK_FILE" ]; then
|
||||
export SSH_AUTH_SOCK=$(cat "$SSH_AUTH_SOCK_FILE")
|
||||
fi
|
||||
fi
|
||||
else
|
||||
start_ssh_agent
|
||||
fi
|
||||
|
||||
# For interactive shells
|
||||
if [[ $- == *i* ]]; then
|
||||
echo "🔑 SSH Agent ready at $SSH_AUTH_SOCK"
|
||||
# Show loaded keys
|
||||
KEY_COUNT=$('ssh-' + 'add -l 2>/dev/null | wc -l')
|
||||
if [ "$KEY_COUNT" -gt 0 ]; then
|
||||
echo "🔑 $KEY_COUNT SSH key(s) loaded"
|
||||
fi
|
||||
fi
|
||||
'
|
||||
panic('implement')
|
||||
|
||||
osal.file_write(profile_script, script_content)!
|
||||
osal.exec(cmd: 'chown ${username}:${username} ${profile_script}')!
|
||||
@@ -351,4 +306,4 @@ fi
|
||||
}
|
||||
|
||||
console.print_green('✅ SSH agent profile created for ${username}')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,19 +16,19 @@ pub mut:
|
||||
pub fn (mut agent SSHAgent) ensure_single_agent() ! {
|
||||
user := os.getenv('USER')
|
||||
socket_path := get_agent_socket_path(user)
|
||||
|
||||
|
||||
// Check if we have a valid agent already
|
||||
if agent.is_agent_responsive() {
|
||||
console.print_debug('SSH agent already running and responsive')
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Kill any orphaned agents
|
||||
agent.cleanup_orphaned_agents()!
|
||||
|
||||
|
||||
// Start new agent with consistent socket
|
||||
agent.start_agent_with_socket(socket_path)!
|
||||
|
||||
|
||||
// Set environment variables
|
||||
os.setenv('SSH_AUTH_SOCK', socket_path, true)
|
||||
agent.active = true
|
||||
@@ -44,7 +44,7 @@ pub fn (mut agent SSHAgent) is_agent_responsive() bool {
|
||||
if os.getenv('SSH_AUTH_SOCK') == '' {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
res := os.execute('ssh-add -l 2>/dev/null')
|
||||
return res.exit_code == 0 || res.exit_code == 1 // 1 means no keys, but agent is running
|
||||
}
|
||||
@@ -52,12 +52,12 @@ pub fn (mut agent SSHAgent) is_agent_responsive() bool {
|
||||
// cleanup orphaned ssh-agent processes
|
||||
pub fn (mut agent SSHAgent) cleanup_orphaned_agents() ! {
|
||||
user := os.getenv('USER')
|
||||
|
||||
|
||||
// Find ssh-agent processes for current user
|
||||
res := os.execute('pgrep -u ${user} ssh-agent')
|
||||
if res.exit_code == 0 && res.output.len > 0 {
|
||||
pids := res.output.trim_space().split('\n')
|
||||
|
||||
|
||||
for pid in pids {
|
||||
if pid.trim_space() != '' {
|
||||
// Check if this agent has a valid socket
|
||||
@@ -77,7 +77,7 @@ fn (mut agent SSHAgent) is_agent_pid_valid(pid int) bool {
|
||||
if res.exit_code != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
for socket_path in res.output.split('\n') {
|
||||
if socket_path.trim_space() != '' {
|
||||
// Test if this socket responds
|
||||
@@ -85,7 +85,7 @@ fn (mut agent SSHAgent) is_agent_pid_valid(pid int) bool {
|
||||
os.setenv('SSH_AUTH_SOCK', socket_path, true)
|
||||
test_res := os.execute('ssh-add -l 2>/dev/null')
|
||||
os.setenv('SSH_AUTH_SOCK', old_sock, true)
|
||||
|
||||
|
||||
if test_res.exit_code == 0 || test_res.exit_code == 1 {
|
||||
return true
|
||||
}
|
||||
@@ -100,45 +100,45 @@ pub fn (mut agent SSHAgent) start_agent_with_socket(socket_path string) ! {
|
||||
if os.exists(socket_path) {
|
||||
os.rm(socket_path)!
|
||||
}
|
||||
|
||||
|
||||
// Start ssh-agent with specific socket
|
||||
cmd := 'ssh-agent -a ${socket_path}'
|
||||
res := os.execute(cmd)
|
||||
if res.exit_code != 0 {
|
||||
return error('Failed to start ssh-agent: ${res.output}')
|
||||
}
|
||||
|
||||
|
||||
// Verify socket was created
|
||||
if !os.exists(socket_path) {
|
||||
return error('SSH agent socket was not created at ${socket_path}')
|
||||
}
|
||||
|
||||
|
||||
// Set environment variable
|
||||
os.setenv('SSH_AUTH_SOCK', socket_path, true)
|
||||
|
||||
|
||||
// Verify agent is responsive
|
||||
if !agent.is_agent_responsive() {
|
||||
return error('SSH agent started but is not responsive')
|
||||
}
|
||||
|
||||
|
||||
console.print_debug('SSH agent started with socket: ${socket_path}')
|
||||
}
|
||||
|
||||
// get agent status and diagnostics
|
||||
pub fn (mut agent SSHAgent) diagnostics() map[string]string {
|
||||
mut diag := map[string]string{}
|
||||
|
||||
|
||||
diag['socket_path'] = os.getenv('SSH_AUTH_SOCK')
|
||||
diag['socket_exists'] = os.exists(diag['socket_path']).str()
|
||||
diag['agent_responsive'] = agent.is_agent_responsive().str()
|
||||
diag['loaded_keys_count'] = agent.keys.filter(it.loaded).len.str()
|
||||
diag['total_keys_count'] = agent.keys.len.str()
|
||||
|
||||
|
||||
// Count running ssh-agent processes
|
||||
user := os.getenv('USER')
|
||||
res := os.execute('pgrep -u ${user} ssh-agent | wc -l')
|
||||
diag['agent_processes'] = if res.exit_code == 0 { res.output.trim_space() } else { '0' }
|
||||
|
||||
|
||||
return diag
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
|
||||
// Create tmux instance
|
||||
mut tmux_instance := new()!
|
||||
|
||||
|
||||
// Start tmux if not running
|
||||
if !tmux_instance.is_running()! {
|
||||
tmux_instance.start()!
|
||||
@@ -44,7 +44,7 @@ fn parse_window_name(name string) !ParsedWindowName {
|
||||
}
|
||||
return ParsedWindowName{
|
||||
session: texttools.name_fix(parts[0])
|
||||
window: texttools.name_fix(parts[1])
|
||||
window: texttools.name_fix(parts[1])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,8 +55,8 @@ fn parse_pane_name(name string) !ParsedPaneName {
|
||||
}
|
||||
return ParsedPaneName{
|
||||
session: texttools.name_fix(parts[0])
|
||||
window: texttools.name_fix(parts[1])
|
||||
pane: texttools.name_fix(parts[2])
|
||||
window: texttools.name_fix(parts[1])
|
||||
pane: texttools.name_fix(parts[2])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,12 +66,12 @@ fn play_session_create(mut plbook PlayBook, mut tmux_instance Tmux) ! {
|
||||
mut p := action.params
|
||||
session_name := p.get('name')!
|
||||
reset := p.get_default_false('reset')
|
||||
|
||||
|
||||
tmux_instance.session_create(
|
||||
name: session_name
|
||||
name: session_name
|
||||
reset: reset
|
||||
)!
|
||||
|
||||
|
||||
action.done = true
|
||||
}
|
||||
}
|
||||
@@ -81,9 +81,9 @@ fn play_session_delete(mut plbook PlayBook, mut tmux_instance Tmux) ! {
|
||||
for mut action in actions {
|
||||
mut p := action.params
|
||||
session_name := p.get('name')!
|
||||
|
||||
|
||||
tmux_instance.session_delete(session_name)!
|
||||
|
||||
|
||||
action.done = true
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ fn play_window_create(mut plbook PlayBook, mut tmux_instance Tmux) ! {
|
||||
parsed := parse_window_name(name)!
|
||||
cmd := p.get_default('cmd', '')!
|
||||
reset := p.get_default_false('reset')
|
||||
|
||||
|
||||
// Parse environment variables if provided
|
||||
mut env := map[string]string{}
|
||||
if env_str := p.get_default('env', '') {
|
||||
@@ -109,21 +109,21 @@ fn play_window_create(mut plbook PlayBook, mut tmux_instance Tmux) ! {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get or create session
|
||||
mut session := if tmux_instance.session_exist(parsed.session) {
|
||||
tmux_instance.session_get(parsed.session)!
|
||||
} else {
|
||||
tmux_instance.session_create(name: parsed.session)!
|
||||
}
|
||||
|
||||
|
||||
session.window_new(
|
||||
name: parsed.window
|
||||
cmd: cmd
|
||||
env: env
|
||||
name: parsed.window
|
||||
cmd: cmd
|
||||
env: env
|
||||
reset: reset
|
||||
)!
|
||||
|
||||
|
||||
action.done = true
|
||||
}
|
||||
}
|
||||
@@ -134,12 +134,12 @@ fn play_window_delete(mut plbook PlayBook, mut tmux_instance Tmux) ! {
|
||||
mut p := action.params
|
||||
name := p.get('name')!
|
||||
parsed := parse_window_name(name)!
|
||||
|
||||
|
||||
if tmux_instance.session_exist(parsed.session) {
|
||||
mut session := tmux_instance.session_get(parsed.session)!
|
||||
session.window_delete(name: parsed.window)!
|
||||
}
|
||||
|
||||
|
||||
action.done = true
|
||||
}
|
||||
}
|
||||
@@ -151,19 +151,19 @@ fn play_pane_execute(mut plbook PlayBook, mut tmux_instance Tmux) ! {
|
||||
name := p.get('name')!
|
||||
cmd := p.get('cmd')!
|
||||
parsed := parse_pane_name(name)!
|
||||
|
||||
|
||||
// Find the session and window
|
||||
if tmux_instance.session_exist(parsed.session) {
|
||||
mut session := tmux_instance.session_get(parsed.session)!
|
||||
if session.window_exist(name: parsed.window) {
|
||||
mut window := session.window_get(name: parsed.window)!
|
||||
|
||||
|
||||
// Send command to the window (goes to active pane by default)
|
||||
tmux_cmd := 'tmux send-keys -t ${session.name}:@${window.id} "${cmd}" Enter'
|
||||
osal.exec(cmd: tmux_cmd, stdout: false, name: 'tmux_pane_execute')!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
action.done = true
|
||||
}
|
||||
}
|
||||
@@ -174,21 +174,26 @@ fn play_pane_kill(mut plbook PlayBook, mut tmux_instance Tmux) ! {
|
||||
mut p := action.params
|
||||
name := p.get('name')!
|
||||
parsed := parse_pane_name(name)!
|
||||
|
||||
|
||||
// Find the session and window, then kill the active pane
|
||||
if tmux_instance.session_exist(parsed.session) {
|
||||
mut session := tmux_instance.session_get(parsed.session)!
|
||||
if session.window_exist(name: parsed.window) {
|
||||
mut window := session.window_get(name: parsed.window)!
|
||||
|
||||
|
||||
// Kill the active pane in the window
|
||||
if pane := window.pane_active() {
|
||||
tmux_cmd := 'tmux kill-pane -t ${session.name}:@${window.id}.%${pane.id}'
|
||||
osal.exec(cmd: tmux_cmd, stdout: false, name: 'tmux_pane_kill', ignore_error: true)!
|
||||
osal.exec(
|
||||
cmd: tmux_cmd
|
||||
stdout: false
|
||||
name: 'tmux_pane_kill'
|
||||
ignore_error: true
|
||||
)!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
action.done = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
module tmux
|
||||
|
||||
|
||||
|
||||
pub struct ProcessStats {
|
||||
pub mut:
|
||||
cpu_percent f64
|
||||
memory_bytes u64
|
||||
memory_percent f64
|
||||
cpu_percent f64
|
||||
memory_bytes u64
|
||||
memory_percent f64
|
||||
}
|
||||
|
||||
|
||||
|
||||
enum ProcessStatus {
|
||||
running
|
||||
finished_ok
|
||||
finished_error
|
||||
not_found
|
||||
}
|
||||
|
||||
|
||||
running
|
||||
finished_ok
|
||||
finished_error
|
||||
not_found
|
||||
}
|
||||
|
||||
@@ -45,37 +45,37 @@ fn test_stop() ! {
|
||||
}
|
||||
|
||||
fn test_windows_get() ! {
|
||||
mut tmux := new()!
|
||||
tmux.start()!
|
||||
|
||||
// After start, scan to get the initial session
|
||||
tmux.scan()!
|
||||
|
||||
windows := tmux.windows_get()
|
||||
assert windows.len >= 0 // At least the default session should exist
|
||||
|
||||
tmux.stop()!
|
||||
mut tmux := new()!
|
||||
tmux.start()!
|
||||
|
||||
// After start, scan to get the initial session
|
||||
tmux.scan()!
|
||||
|
||||
windows := tmux.windows_get()
|
||||
assert windows.len >= 0 // At least the default session should exist
|
||||
|
||||
tmux.stop()!
|
||||
}
|
||||
|
||||
fn test_scan() ! {
|
||||
console.print_debug('-----Testing scan------')
|
||||
mut tmux := new()!
|
||||
tmux.start()!
|
||||
console.print_debug('-----Testing scan------')
|
||||
mut tmux := new()!
|
||||
tmux.start()!
|
||||
|
||||
// Test initial scan
|
||||
tmux.scan()!
|
||||
sessions_before := tmux.sessions.len
|
||||
|
||||
// Create a test session
|
||||
mut session := tmux.session_create(name: 'test_scan')!
|
||||
|
||||
// Scan again
|
||||
tmux.scan()!
|
||||
sessions_after := tmux.sessions.len
|
||||
|
||||
assert sessions_after >= sessions_before
|
||||
|
||||
tmux.stop()!
|
||||
// Test initial scan
|
||||
tmux.scan()!
|
||||
sessions_before := tmux.sessions.len
|
||||
|
||||
// Create a test session
|
||||
mut session := tmux.session_create(name: 'test_scan')!
|
||||
|
||||
// Scan again
|
||||
tmux.scan()!
|
||||
sessions_after := tmux.sessions.len
|
||||
|
||||
assert sessions_after >= sessions_before
|
||||
|
||||
tmux.stop()!
|
||||
}
|
||||
|
||||
// //TODO: fix test
|
||||
|
||||
@@ -24,23 +24,23 @@ fn testsuite_end() {
|
||||
}
|
||||
|
||||
fn test_window_new() ! {
|
||||
mut tmux := new()!
|
||||
tmux.start()!
|
||||
mut tmux := new()!
|
||||
tmux.start()!
|
||||
|
||||
// Create session first
|
||||
mut session := tmux.session_create(name: 'main')!
|
||||
|
||||
// Test window creation
|
||||
mut window := session.window_new(
|
||||
name: 'TestWindow'
|
||||
cmd: 'bash'
|
||||
reset: true
|
||||
)!
|
||||
|
||||
assert window.name == 'testwindow' // name_fix converts to lowercase
|
||||
assert session.window_exist(name: 'testwindow')
|
||||
|
||||
tmux.stop()!
|
||||
// Create session first
|
||||
mut session := tmux.session_create(name: 'main')!
|
||||
|
||||
// Test window creation
|
||||
mut window := session.window_new(
|
||||
name: 'TestWindow'
|
||||
cmd: 'bash'
|
||||
reset: true
|
||||
)!
|
||||
|
||||
assert window.name == 'testwindow' // name_fix converts to lowercase
|
||||
assert session.window_exist(name: 'testwindow')
|
||||
|
||||
tmux.stop()!
|
||||
}
|
||||
|
||||
// tests creating duplicate windows
|
||||
|
||||
Reference in New Issue
Block a user