boxd 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/boxd.gemspec +1 -0
- data/lib/boxd/dev_bootstrap.sh +73 -0
- data/lib/boxd/dev_command.rb +43 -10
- data/lib/boxd/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c522b2f321d84049fd8dd3d60cb82367edc2e4e587833020df8959ba6a13573b
|
|
4
|
+
data.tar.gz: 76708e00dcac901bcb25f3201e70d130a527d29176c1711145ebd5e4f9538063
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b47103a2b153dd685cbbe2bd80d001693c5db6a8636e0e513e8f53e0fd30b628a8624493f8cbdd21505813235601b7992b158a15554ac6fe70add2215329d1b5
|
|
7
|
+
data.tar.gz: f0da1fb7199421a2ddc9e940d827e264535dcc08690678dca4e07421a35a92c133c46d8f0a96471b232b2b2b476166ecfe2dc55ec80ecf065b0f06a0912816f3
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.1 — 2026-06-04
|
|
4
|
+
|
|
5
|
+
First-run UX fixes for `boxd-dev`:
|
|
6
|
+
|
|
7
|
+
- Top-level rescue prints a clear "Run `boxd login`" message instead of a
|
|
8
|
+
stack trace when the user isn't authenticated.
|
|
9
|
+
- Auto-creates the golden VM if it doesn't exist yet, so `boxd-dev owner/repo`
|
|
10
|
+
works on a fresh boxd account with no prior setup.
|
|
11
|
+
- Bundles the per-repo bootstrap script inside the gem (`lib/boxd/dev_bootstrap.sh`)
|
|
12
|
+
and uploads it to each fork at runtime — no dependency on a pre-baked golden.
|
|
13
|
+
- Better handling of missing/unauthenticated `gh` CLI: skip the preflight
|
|
14
|
+
check instead of failing, and tell the user how to get the better errors back.
|
|
15
|
+
|
|
3
16
|
## 0.1.0 — 2026-06-04
|
|
4
17
|
|
|
5
18
|
Initial release. CLI-backed v0.
|
data/boxd.gemspec
CHANGED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Per-fork bootstrap. Uploaded by the boxd-dev binary every time it runs,
|
|
3
|
+
# so the script always tracks the gem's version. Reads REPO_URL and
|
|
4
|
+
# REPO_NAME from the environment.
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
echo "[bootstrap] $(date +%T) starting"
|
|
8
|
+
cd ~
|
|
9
|
+
|
|
10
|
+
if [ -n "${REPO_URL:-}" ] && [ -n "${REPO_NAME:-}" ] && [ ! -d "$REPO_NAME" ]; then
|
|
11
|
+
echo "[bootstrap] cloning $REPO_URL"
|
|
12
|
+
git clone "$REPO_URL"
|
|
13
|
+
fi
|
|
14
|
+
[ -n "${REPO_NAME:-}" ] && cd "$REPO_NAME" || exit 0
|
|
15
|
+
|
|
16
|
+
# Prefer the project's own setup script if it ships one.
|
|
17
|
+
for s in script/bootstrap script/setup bin/setup; do
|
|
18
|
+
if [ -x "$s" ]; then
|
|
19
|
+
echo "[bootstrap] running $s"
|
|
20
|
+
"$s"
|
|
21
|
+
echo "[bootstrap] done."
|
|
22
|
+
exit 0
|
|
23
|
+
fi
|
|
24
|
+
done
|
|
25
|
+
|
|
26
|
+
# Ecosystem-default install per detected manifest.
|
|
27
|
+
if [ -f package.json ]; then
|
|
28
|
+
if [ -f pnpm-lock.yaml ]; then
|
|
29
|
+
command -v pnpm >/dev/null || sudo npm i -g pnpm
|
|
30
|
+
pnpm install
|
|
31
|
+
elif [ -f yarn.lock ]; then
|
|
32
|
+
command -v yarn >/dev/null || sudo npm i -g yarn
|
|
33
|
+
yarn install
|
|
34
|
+
else
|
|
35
|
+
npm install
|
|
36
|
+
fi
|
|
37
|
+
fi
|
|
38
|
+
if [ -f Cargo.toml ]; then
|
|
39
|
+
if ! command -v cargo >/dev/null; then
|
|
40
|
+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
|
|
41
|
+
| sh -s -- -y --default-toolchain stable --profile minimal
|
|
42
|
+
fi
|
|
43
|
+
. "$HOME/.cargo/env" 2>/dev/null || true
|
|
44
|
+
cargo fetch
|
|
45
|
+
fi
|
|
46
|
+
if [ -f mix.exs ]; then
|
|
47
|
+
if ! command -v mix >/dev/null; then
|
|
48
|
+
sudo apt-get update -qq && sudo apt-get install -y elixir
|
|
49
|
+
fi
|
|
50
|
+
mix local.hex --force && mix local.rebar --force
|
|
51
|
+
mix deps.get
|
|
52
|
+
fi
|
|
53
|
+
if [ -f Gemfile ]; then
|
|
54
|
+
if ! command -v bundle >/dev/null; then
|
|
55
|
+
sudo apt-get update -qq && sudo apt-get install -y ruby ruby-bundler
|
|
56
|
+
fi
|
|
57
|
+
bundle install
|
|
58
|
+
fi
|
|
59
|
+
if [ -f go.mod ] && command -v go >/dev/null; then
|
|
60
|
+
go mod download
|
|
61
|
+
fi
|
|
62
|
+
if [ -f pyproject.toml ] || [ -f requirements.txt ]; then
|
|
63
|
+
if ! command -v uv >/dev/null; then
|
|
64
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
65
|
+
fi
|
|
66
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
67
|
+
if [ -f pyproject.toml ]; then
|
|
68
|
+
uv sync || true
|
|
69
|
+
else
|
|
70
|
+
uv pip install -r requirements.txt || pip install -r requirements.txt
|
|
71
|
+
fi
|
|
72
|
+
fi
|
|
73
|
+
echo "[bootstrap] done."
|
data/lib/boxd/dev_command.rb
CHANGED
|
@@ -20,15 +20,36 @@ module Boxd
|
|
|
20
20
|
# <bare VM name> # connect to existing
|
|
21
21
|
class DevCommand
|
|
22
22
|
GOLDEN_DEFAULT = "dev-golden"
|
|
23
|
-
|
|
23
|
+
BOOTSTRAP_LOCAL = File.expand_path("dev_bootstrap.sh", __dir__)
|
|
24
|
+
BOOTSTRAP_REMOTE = "/tmp/dev-bootstrap"
|
|
24
25
|
|
|
25
26
|
def initialize(argv)
|
|
26
27
|
@argv = argv
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
def run
|
|
30
|
-
|
|
31
|
+
do_run
|
|
32
|
+
rescue Boxd::CLIMissingError => e
|
|
33
|
+
warn e.message
|
|
34
|
+
exit 1
|
|
35
|
+
rescue Boxd::AuthenticationError
|
|
36
|
+
warn <<~MSG
|
|
37
|
+
boxd-dev: you're not logged in to boxd yet.
|
|
38
|
+
|
|
39
|
+
Run: boxd login
|
|
40
|
+
|
|
41
|
+
(or set BOXD_TOKEN to a long-lived API key from `boxd keys create`)
|
|
42
|
+
MSG
|
|
43
|
+
exit 1
|
|
44
|
+
rescue Boxd::Error => e
|
|
45
|
+
warn "boxd-dev: #{e.message}"
|
|
46
|
+
exit 1
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
31
50
|
|
|
51
|
+
def do_run
|
|
52
|
+
arg = @argv.first || ENV["BOXD_DEV_VM"] || "dev-chad"
|
|
32
53
|
repo = parse_repo(arg)
|
|
33
54
|
vm = repo ? "dev-#{repo[:slug]}" : arg
|
|
34
55
|
golden = ENV.fetch("BOXD_GOLDEN", GOLDEN_DEFAULT)
|
|
@@ -41,8 +62,6 @@ module Boxd
|
|
|
41
62
|
exec_attach(box)
|
|
42
63
|
end
|
|
43
64
|
|
|
44
|
-
private
|
|
45
|
-
|
|
46
65
|
# ---- repo reference parsing ------------------------------------------
|
|
47
66
|
|
|
48
67
|
def parse_repo(arg)
|
|
@@ -76,7 +95,14 @@ module Boxd
|
|
|
76
95
|
return unless repo[:host] == "github.com"
|
|
77
96
|
|
|
78
97
|
unless system("command -v gh > /dev/null 2>&1")
|
|
79
|
-
warn "boxd-dev: gh CLI not
|
|
98
|
+
warn "boxd-dev: gh CLI not installed; skipping repo preflight check."
|
|
99
|
+
warn " install for better errors: brew install gh && gh auth login"
|
|
100
|
+
return
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
unless system("gh auth status > /dev/null 2>&1")
|
|
104
|
+
warn "boxd-dev: gh not authenticated; skipping repo preflight check."
|
|
105
|
+
warn " authenticate for better errors: gh auth login"
|
|
80
106
|
return
|
|
81
107
|
end
|
|
82
108
|
|
|
@@ -101,8 +127,9 @@ module Boxd
|
|
|
101
127
|
end
|
|
102
128
|
|
|
103
129
|
unless compute.boxes.find(golden)
|
|
104
|
-
warn "boxd-dev: golden VM '#{golden}'
|
|
105
|
-
|
|
130
|
+
warn "boxd-dev: golden VM '#{golden}' doesn't exist yet — creating it..."
|
|
131
|
+
compute.boxes.create(name: golden, auto_suspend_timeout: 0)
|
|
132
|
+
warn "boxd-dev: created #{golden} (vanilla VM; bake setup into it later if you want)."
|
|
106
133
|
end
|
|
107
134
|
|
|
108
135
|
warn "boxd-dev: forking #{golden} → #{vm} (#{repo[:display]})..."
|
|
@@ -112,9 +139,15 @@ module Boxd
|
|
|
112
139
|
# ---- tmux + bootstrap ------------------------------------------------
|
|
113
140
|
|
|
114
141
|
# Ensure the persistent tmux session "dev" exists on the box. If a
|
|
115
|
-
# repo arg was given and the clone isn't there yet,
|
|
116
|
-
# bootstrap script
|
|
142
|
+
# repo arg was given and the clone isn't there yet, upload the bundled
|
|
143
|
+
# bootstrap script and kick it off inside pane 0 — the attaching shell
|
|
144
|
+
# shows the build live and lands at a shell in the repo dir.
|
|
117
145
|
def prep_tmux(box, repo)
|
|
146
|
+
# Upload the gem's bootstrap script on every run so it always tracks the
|
|
147
|
+
# gem version (cheap idempotent write).
|
|
148
|
+
box.write_file(BOOTSTRAP_REMOTE, File.read(BOOTSTRAP_LOCAL))
|
|
149
|
+
box.exec(["chmod", "+x", BOOTSTRAP_REMOTE])
|
|
150
|
+
|
|
118
151
|
script = +<<~SH
|
|
119
152
|
set -e
|
|
120
153
|
if ! tmux has-session -t dev 2>/dev/null; then
|
|
@@ -124,7 +157,7 @@ module Boxd
|
|
|
124
157
|
if repo
|
|
125
158
|
script << <<~SH
|
|
126
159
|
if [ ! -d "$HOME/#{repo[:repo]}" ]; then
|
|
127
|
-
tmux send-keys -t dev "REPO_URL='#{repo[:clone_url]}' REPO_NAME='#{repo[:repo]}' #{
|
|
160
|
+
tmux send-keys -t dev "REPO_URL='#{repo[:clone_url]}' REPO_NAME='#{repo[:repo]}' #{BOOTSTRAP_REMOTE} && cd ~/#{repo[:repo]}" Enter
|
|
128
161
|
else
|
|
129
162
|
tmux send-keys -t dev "cd ~/#{repo[:repo]}" Enter
|
|
130
163
|
fi
|
data/lib/boxd/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: boxd
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- boxd contributors
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec
|
|
@@ -62,6 +62,7 @@ files:
|
|
|
62
62
|
- lib/boxd/box_service.rb
|
|
63
63
|
- lib/boxd/cli_backend.rb
|
|
64
64
|
- lib/boxd/compute.rb
|
|
65
|
+
- lib/boxd/dev_bootstrap.sh
|
|
65
66
|
- lib/boxd/dev_command.rb
|
|
66
67
|
- lib/boxd/errors.rb
|
|
67
68
|
- lib/boxd/version.rb
|