diff --git a/README.md b/README.md index f331dbc1..4b664675 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,16 @@ SwarmForge runs locally. Before starting a runnable branch, make sure the target - Babashka (`bb`) - At least one configured agent backend, such as `codex`, `claude`, `copilot`, or `grok` +### Windows + +Native Windows (no WSL) is supported via [MSYS2](https://www.msys2.org/), which provides `zsh`, `tmux`, and `git`: + +```sh +pacman -S zsh tmux git curl tar gawk +``` + +Install Babashka natively (e.g. via `winget install Babashka.Babashka` or `scoop install babashka`) and make sure the directories holding `bb`, your agent backend CLI, and `get-swarm-forge` are all on the MSYS2 shell's `PATH` (MSYS2's default `PATH` does not inherit the full Windows `PATH`; add the missing directories to `~/.zshrc`/`~/.bashrc`). Run everything — `get-swarm-forge` and `./swarm` — from an MSYS2 `zsh` shell, not from Git Bash or PowerShell. + ## Getting Started Install the `get-swarm-forge` helper somewhere on your `PATH`, such as `~/cmds` or `~/bin`: diff --git a/swarmforge/scripts/swarm_tool.bb b/swarmforge/scripts/swarm_tool.bb index 9e243c16..04d4f93a 100755 --- a/swarmforge/scripts/swarm_tool.bb +++ b/swarmforge/scripts/swarm_tool.bb @@ -156,7 +156,9 @@ (defn write-wrapper! [path body] (fs/create-dirs (fs/parent path)) (spit (str path) (str "#!/usr/bin/env bash\n" body)) - (fs/set-posix-file-permissions path "rwxr-xr-x") + (try + (fs/set-posix-file-permissions path "rwxr-xr-x") + (catch UnsupportedOperationException _ nil)) path) (defn write-bb-wrapper! [root tool bb-task src-dir] diff --git a/swarmforge/scripts/swarmforge.bb b/swarmforge/scripts/swarmforge.bb index 2bd83570..5b73104d 100755 --- a/swarmforge/scripts/swarmforge.bb +++ b/swarmforge/scripts/swarmforge.bb @@ -295,7 +295,9 @@ (str "#!/usr/bin/env zsh\n" "set -euo pipefail\n" "exec bb " (sq bb) " \"$@\"\n")) - (fs/set-posix-file-permissions hook "rwxr-xr-x"))) + (try + (fs/set-posix-file-permissions hook "rwxr-xr-x") + (catch UnsupportedOperationException _ nil)))) (defn prepare-workspace! [ctx] (doseq [dir [(:state-dir ctx) (:notify-dir ctx) (:prompts-dir ctx) @@ -565,13 +567,14 @@ (defn start-handoff-daemon! [ctx] (fs/delete-if-exists (fs/path (:daemon-dir ctx) "stop")) (let [command (into (vec (sleep-inhibitor-prefix)) - [(str (fs/path (:script-dir ctx) "handoffd.bb")) + ["bb" + (str (fs/path (:script-dir ctx) "handoffd.bb")) (str (:working-dir ctx))])] (process/process command {:out (str (:handoff-daemon-log ctx)) :err :out}) (println (str green "Started handoff daemon" - (when (> (count command) 2) " with OS sleep prevention") + (when (> (count command) 3) " with OS sleep prevention") "." reset)))) @@ -620,7 +623,7 @@ window-id))) (defn start-window-watchdog! [ctx] - (process/process [(str (fs/path (:script-dir ctx) "swarm-window-watchdog.sh")) + (process/process ["zsh" (str (fs/path (:script-dir ctx) "swarm-window-watchdog.sh")) (str (:window-state-file ctx)) (str (:window-ids-file ctx)) "1" @@ -701,7 +704,7 @@ (defn start-pack-web! [ctx] (let [script (str (fs/path (:script-dir ctx) "pack_web.sh")) log (fs/path (:state-dir ctx) "dashboard.log")] - (process/process [script "--serve" (str (:working-dir ctx))] + (process/process ["zsh" script "--serve" (str (:working-dir ctx))] {:out (str log) :err :out}) (when-not (wait-for-file (dashboard-url-file ctx) 5000) (fail! (str red "Error:" reset " Dashboard did not start.")))