commit 9ef6ec2a05291a1b195b0bfbab9bafeb43e544f8
Author: askiiart <dev@askiiart.net>
Date:   Mon Mar 17 19:24:31 2025 -0500

    initial commit - laid out and stuff, cli's working

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..869df07
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/target
+Cargo.lock
\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..5461603
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "runner"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
+better-commands = "1.0.2"
+clap = { version = "4.5.32", features = ["derive"] }
+clap_complete = "4.5.46"
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/dev-notes.md b/dev-notes.md
new file mode 100644
index 0000000..63d23f4
--- /dev/null
+++ b/dev-notes.md
@@ -0,0 +1,11 @@
+- create config file from cli
+- daemon/control model
+- config stuff:
+  - optional:
+    - translation for exit codes to messages
+    - optional script to interpret exit code and output
+- sockets
+  - have socket use json api
+  - eventually add http api as well as just unix socket?
+  - sockets on remote machines are written via ssh (`echo > socket`)
+- no separate client and server program, just a matter of config/how it's used
diff --git a/src/cli.rs b/src/cli.rs
new file mode 100644
index 0000000..fda6942
--- /dev/null
+++ b/src/cli.rs
@@ -0,0 +1,90 @@
+// this is a separate feature for *optional* dependencies to ensure clap doesn't get compiled if you're just using the library
+use crate::{ctl, daemon};
+use clap::{CommandFactory, Parser, Subcommand};
+use clap_complete::aot::{Bash, Elvish, Fish, PowerShell, Zsh, generate};
+use std::{io::stdout, time::Instant};
+
+#[derive(Parser)]
+#[command(version, about, long_about = None)]
+pub(crate) struct Cli {
+    #[command(subcommand)]
+    pub command: Commands,
+}
+
+#[derive(Subcommand, Debug)]
+pub(crate) enum Commands {
+    ///Generate shell completions
+    GenCompletion {
+        #[command(subcommand)]
+        shell: ShellCommands,
+        #[arg(short, long, default_value = "runner")]
+        binary_name: String,
+    },
+    ///Starts runner as a daemon
+    Daemon,
+    ///Creates a job and sends it to the client(s)
+    CreateJob {
+        ///What command to run
+        #[arg(short, long, conflicts_with = "script")]
+        command: Option<String>,
+        ///What script to run
+        #[arg(short, long, conflicts_with = "command")]
+        script: Option<String>,
+        ///The position in the list of clients (0..x) of which client you want the job to run on - mutually exclusive with clients
+        #[arg(long, conflicts_with = "script")]
+        client_num: Option<u16>,
+        ///How many clients to run the job on - mutually exclusive with client_num
+        #[arg(long, conflicts_with = "client_num")]
+        clients: Option<String>,
+    },
+    ///Guides you through the config file creation process
+    BuildConfig {
+        #[arg(short, long)]
+        config_file: Option<String>,
+    },
+}
+
+pub(crate) fn run() {
+    let cli = Cli::parse();
+
+    match cli.command {
+        Commands::GenCompletion { shell, binary_name } => match shell {
+            ShellCommands::Bash => {
+                generate(Bash, &mut Cli::command(), binary_name, &mut stdout());
+            }
+            ShellCommands::Zsh => {
+                generate(Zsh, &mut Cli::command(), binary_name, &mut stdout());
+            }
+            ShellCommands::Fish => {
+                generate(Fish, &mut Cli::command(), binary_name, &mut stdout());
+            }
+            ShellCommands::Elvish => {
+                generate(Elvish, &mut Cli::command(), binary_name, &mut stdout());
+            }
+            ShellCommands::Powershell => {
+                generate(PowerShell, &mut Cli::command(), binary_name, &mut stdout());
+            }
+        },
+        Commands::Daemon => daemon::start_daemon(),
+        Commands::CreateJob {
+            command,
+            script,
+            client_num,
+            clients,
+        } => {
+            ctl::create_job(command, script, client_num, clients);
+        }
+        Commands::BuildConfig { config_file } => {
+            ctl::build_config(config_file);
+        }
+    }
+}
+
+#[derive(Subcommand, Debug)]
+pub enum ShellCommands {
+    Bash,
+    Zsh,
+    Fish,
+    Elvish,
+    Powershell,
+}
diff --git a/src/ctl.rs b/src/ctl.rs
new file mode 100644
index 0000000..a8403a3
--- /dev/null
+++ b/src/ctl.rs
@@ -0,0 +1,9 @@
+pub fn build_config(config_file: Option<String>) {}
+
+pub fn create_job(
+    command: Option<String>,
+    script: Option<String>,
+    client_num: Option<u16>,
+    clients: Option<String>,
+) {
+}
diff --git a/src/daemon.rs b/src/daemon.rs
new file mode 100644
index 0000000..9bb9b6c
--- /dev/null
+++ b/src/daemon.rs
@@ -0,0 +1,3 @@
+pub fn start_daemon() {}
+
+pub fn run_job() {}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..49181a8
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,11 @@
+use crate::cli::*;
+use clap::{CommandFactory, Parser};
+use clap_complete::aot::{Bash, Fish, Zsh, generate};
+
+mod cli;
+mod ctl;
+mod daemon;
+
+fn main() {
+    cli::run()
+}