Skip to content

Commit 9abaf6e

Browse files
feat(dev): support Linux dev environments in Nix flake and dev-start script (#1860)
The Nix flake switched to nixpkgs-unstable for broader Linux package availability, replaced the removed nodePackages.vercel with an npm auto-install fallback, and added stripe-cli and tmux as dev shell packages. The KiloClaw dev-start script now detects the OS and supports Linux terminal emulators (gnome-terminal, konsole, xfce4-terminal, mate-terminal, lxterminal, kitty, alacritty) for tabs mode, falls back to tmux when no supported terminal is found or when split mode is requested on Linux, and provides Linux-appropriate install instructions.
1 parent 8ebb0d6 commit 9abaf6e

File tree

3 files changed

+111
-16
lines changed

3 files changed

+111
-16
lines changed

flake.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
description = "Kilo Code Backend development environment";
33

44
inputs = {
5-
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
5+
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
66
};
77

88
outputs =
@@ -35,9 +35,10 @@
3535
_1password-cli
3636
postgresql_18
3737
wrangler
38-
nodePackages.vercel
3938
flyctl
4039
cloudflared
40+
stripe-cli
41+
tmux
4142
];
4243

4344
env = {
@@ -57,6 +58,16 @@
5758
${pkgs.lib.optionalString pkgs.stdenv.isLinux ''
5859
export SSL_CERT_FILE="${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
5960
''}
61+
62+
# vercel CLI was removed from nixpkgs; install it via npm into a
63+
# local prefix so it's available in the dev shell without polluting
64+
# the global node_modules.
65+
export VERCEL_PREFIX="$HOME/.cache/nix-vercel"
66+
if ! command -v vercel &>/dev/null && [ ! -x "$VERCEL_PREFIX/bin/vercel" ]; then
67+
echo "Installing vercel CLI into $VERCEL_PREFIX …"
68+
npm install --global --prefix "$VERCEL_PREFIX" vercel
69+
fi
70+
export PATH="$VERCEL_PREFIX/bin:$PATH"
6071
'';
6172
};
6273
in

kiloclaw/scripts/dev-start.sh

Lines changed: 94 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/bin/bash
1+
#!/usr/bin/env bash
22
# Start the local KiloClaw development environment.
33
#
44
# Opens terminal windows: Next.js, KiloClaw worker, cloudflared tunnel, and Stripe webhook.
@@ -18,9 +18,14 @@
1818
# temporary quick tunnel. Named tunnels have a
1919
# stable hostname that doesn't change between restarts.
2020
# --display <mode> How to display the dev processes:
21-
# tabs — separate terminal tabs (default)
22-
# split — single tab with split panes (requires iTerm2)
23-
# tmux — tmux session "kiloclaw" (2x2 pane grid)
21+
# tabs — separate terminal tabs/windows (default)
22+
# macOS: iTerm2 or Terminal.app
23+
# Linux: gnome-terminal, konsole, xfce4-terminal,
24+
# mate-terminal, lxterminal, kitty, alacritty
25+
# Falls back to tmux if no supported terminal found.
26+
# split — single tab with split panes (requires iTerm2, macOS only)
27+
# On Linux, automatically falls back to tmux.
28+
# tmux — tmux session "kiloclaw" (2x2 pane grid, cross-platform)
2429
# --with-replica Keep POSTGRES_REPLICA_EU_URL in .env.local.
2530
# By default it is commented out (unreachable locally).
2631
#
@@ -35,6 +40,10 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
3540
KILOCLAW_DIR="$(dirname "$SCRIPT_DIR")"
3641
MONOREPO_ROOT="$(cd "$KILOCLAW_DIR/.." && pwd)"
3742

43+
# ---------- OS detection ----------
44+
45+
OS_TYPE="$(uname -s)"
46+
3847
# ---------- Defaults (overridden by .dev-start.conf, then by CLI flags) ----------
3948

4049
HAS_CONTROLLER_CHANGES=false
@@ -75,7 +84,7 @@ while [[ $# -gt 0 ]]; do
7584
*)
7685
echo "Unknown option: $1"
7786
echo "Usage: $0 [--has-controller-changes] [--tunnel-name <name>] [--display <mode>] [--with-replica]"
78-
echo "Display modes: tabs (default), split, tmux"
87+
echo "Display modes: tabs (default), split (macOS/iTerm2), tmux"
7988
exit 1
8089
;;
8190
esac
@@ -91,6 +100,27 @@ case "$DISPLAY_MODE" in
91100
;;
92101
esac
93102

103+
# On Linux, 'split' requires iTerm2 (macOS-only) — fall back to tmux.
104+
# 'tabs' falls back to tmux if no supported Linux terminal emulator is found.
105+
if [ "$OS_TYPE" = "Linux" ]; then
106+
if [ "$DISPLAY_MODE" = "split" ]; then
107+
echo "==> 'split' display mode requires iTerm2 (macOS). Falling back to 'tmux'."
108+
DISPLAY_MODE="tmux"
109+
elif [ "$DISPLAY_MODE" = "tabs" ]; then
110+
LINUX_TERM=""
111+
for t in gnome-terminal konsole xfce4-terminal mate-terminal lxterminal kitty alacritty; do
112+
if command -v "$t" &>/dev/null; then
113+
LINUX_TERM="$t"
114+
break
115+
fi
116+
done
117+
if [ -z "$LINUX_TERM" ]; then
118+
echo "==> No supported terminal emulator found for 'tabs' mode on Linux. Falling back to 'tmux'."
119+
DISPLAY_MODE="tmux"
120+
fi
121+
fi
122+
fi
123+
94124
# ---------- Pre-flight checks ----------
95125

96126
# Verify required CLIs are available before doing any work
@@ -107,8 +137,13 @@ if [ "$missing_cli" = true ]; then
107137
echo " vercel: npm i -g vercel"
108138
echo " pnpm: corepack enable && corepack prepare pnpm@latest --activate"
109139
echo " docker: https://docs.docker.com/get-docker/"
110-
echo " cloudflared: brew install cloudflare/cloudflare/cloudflared"
111-
echo " stripe: brew install stripe/stripe-cli/stripe"
140+
if [ "$OS_TYPE" = "Darwin" ]; then
141+
echo " cloudflared: brew install cloudflare/cloudflare/cloudflared"
142+
echo " stripe: brew install stripe/stripe-cli/stripe"
143+
else
144+
echo " cloudflared: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/"
145+
echo " stripe: https://docs.stripe.com/stripe-cli#install"
146+
fi
112147
exit 1
113148
fi
114149

@@ -444,6 +479,42 @@ open_terminal_tab() {
444479
local title="$1"
445480
local cmd="$2"
446481

482+
if [ "$OS_TYPE" = "Linux" ]; then
483+
# On Linux, open a new terminal window with the given command.
484+
# LINUX_TERM is resolved during display-mode validation above.
485+
case "${LINUX_TERM:-}" in
486+
gnome-terminal)
487+
gnome-terminal --title="$title" -- bash -c "echo '--- $title ---'; $cmd; exec bash" &
488+
;;
489+
konsole)
490+
konsole --new-tab -p tabtitle="$title" -e bash -c "echo '--- $title ---'; $cmd; exec bash" &
491+
;;
492+
xfce4-terminal)
493+
xfce4-terminal --title="$title" -e "bash -c \"echo '--- $title ---'; $cmd; exec bash\"" &
494+
;;
495+
mate-terminal)
496+
mate-terminal --title="$title" -e "bash -c \"echo '--- $title ---'; $cmd; exec bash\"" &
497+
;;
498+
lxterminal)
499+
lxterminal --title="$title" -e "bash -c \"echo '--- $title ---'; $cmd; exec bash\"" &
500+
;;
501+
kitty)
502+
kitty --title "$title" bash -c "echo '--- $title ---'; $cmd; exec bash" &
503+
;;
504+
alacritty)
505+
alacritty --title "$title" -e bash -c "echo '--- $title ---'; $cmd; exec bash" &
506+
;;
507+
*)
508+
echo "ERROR: No supported terminal emulator for 'tabs' mode on Linux."
509+
echo "Supported: gnome-terminal, konsole, xfce4-terminal, mate-terminal, lxterminal, kitty, alacritty"
510+
echo "Use --display tmux instead."
511+
exit 1
512+
;;
513+
esac
514+
return
515+
fi
516+
517+
# macOS: use osascript for iTerm2 or Terminal.app
447518
# Escape backslashes and double quotes so $cmd is safe inside AppleScript strings
448519
local safe_cmd="${cmd//\\/\\\\}"
449520
safe_cmd="${safe_cmd//\"/\\\"}"
@@ -471,13 +542,18 @@ EOF
471542
fi
472543
}
473544

474-
# Open 3 commands in a single iTerm2 tab with vertical/horizontal splits:
545+
# Open 3 commands in a single iTerm2 tab with vertical/horizontal splits (macOS only):
475546
# ┌──────────────┬──────────────┐
476547
# │ tunnel │ Next.js │
477548
# │ ├──────────────┤
478549
# │ │ worker │
479550
# └──────────────┴──────────────┘
480551
open_split_screen() {
552+
if [ "$OS_TYPE" = "Linux" ]; then
553+
echo "ERROR: split mode requires iTerm2 (macOS only). Use --display tmux on Linux."
554+
exit 1
555+
fi
556+
481557
local title1="$1" cmd1="$2"
482558
local title2="$3" cmd2="$4"
483559
local title3="$5" cmd3="$6"
@@ -639,7 +715,11 @@ STRIPE_LOG="$(mktemp)"
639715
if [ "$DISPLAY_MODE" = "tmux" ]; then
640716
# For tmux, create the session now with stripe as the first window
641717
if ! command -v tmux &>/dev/null; then
642-
echo "ERROR: 'tmux' not found. Install it: brew install tmux"
718+
if [ "$OS_TYPE" = "Darwin" ]; then
719+
echo "ERROR: 'tmux' not found. Install it: brew install tmux"
720+
else
721+
echo "ERROR: 'tmux' not found. Install it via your package manager (e.g. apt install tmux)"
722+
fi
643723
exit 1
644724
fi
645725
tmux kill-session -t kiloclaw 2>/dev/null || true
@@ -759,7 +839,11 @@ EOF
759839
open_terminal_tab "KiloClaw worker" "$WORKER_CMD"
760840

761841
echo ""
762-
echo "Dev environment starting in 4 terminal tabs:"
842+
if [ "$OS_TYPE" = "Linux" ]; then
843+
echo "Dev environment starting in 4 terminal windows:"
844+
else
845+
echo "Dev environment starting in 4 terminal tabs:"
846+
fi
763847
echo " 1. Stripe webhook listener"
764848
echo " 2. cloudflared tunnel"
765849
echo " 3. Next.js (port 3000)"

0 commit comments

Comments
 (0)