aibox-cli 0.2.0 → 0.4.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.
- package/README.md +27 -16
- package/bin/aibox +58 -8
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -19,11 +19,8 @@ On macOS, if Docker isn't installed, aibox will offer to install [Colima](https:
|
|
|
19
19
|
## Usage
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
# first time (once)
|
|
23
|
-
aibox build
|
|
24
|
-
|
|
25
22
|
# in any project directory
|
|
26
|
-
aibox up # start container
|
|
23
|
+
aibox up # start container (auto-builds image on first run)
|
|
27
24
|
aibox claude --yolo # no prompts, full sudo, no firewall
|
|
28
25
|
aibox claude --safe # keep prompts, restricted sudo, firewall on
|
|
29
26
|
aibox claude # asks you each time
|
|
@@ -71,6 +68,17 @@ aibox down --all # stop all containers for this project
|
|
|
71
68
|
aibox nuke # remove ALL aibox containers
|
|
72
69
|
```
|
|
73
70
|
|
|
71
|
+
### From a Git Repo
|
|
72
|
+
|
|
73
|
+
Start directly from a repo URL — aibox clones it and runs:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
aibox --repo https://github.com/user/project.git claude --yolo
|
|
77
|
+
aibox --repo git@github.com:user/project.git --branch dev claude
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Repos are cloned to `~/.config/aibox/repos/` with `--recursive` (submodules included). On subsequent runs, the existing clone is reused.
|
|
81
|
+
|
|
74
82
|
### Custom Image
|
|
75
83
|
|
|
76
84
|
```bash
|
|
@@ -88,7 +96,7 @@ aibox generates a `compose.dev.yaml` and configures your IDE on `aibox init` (or
|
|
|
88
96
|
2. Run `aibox init` in your project
|
|
89
97
|
3. Set the plugin's startup command to:
|
|
90
98
|
```
|
|
91
|
-
|
|
99
|
+
npx aibox claude --yolo
|
|
92
100
|
```
|
|
93
101
|
|
|
94
102
|
The Node.js interpreter is also configured to use the container, so running/debugging from the IDE uses the same sandboxed environment.
|
|
@@ -147,17 +155,20 @@ SHARED_MODULES=false
|
|
|
147
155
|
|
|
148
156
|
## All Flags
|
|
149
157
|
|
|
150
|
-
|
|
|
151
|
-
|
|
152
|
-
| `--name NAME` | Named instance (multiple containers per project) |
|
|
153
|
-
| `--
|
|
154
|
-
| `--
|
|
155
|
-
|
|
|
156
|
-
| `--
|
|
157
|
-
| `--
|
|
158
|
-
| `--
|
|
159
|
-
| `--
|
|
160
|
-
|
|
|
158
|
+
| Short | Long | Description |
|
|
159
|
+
|-------|------|-------------|
|
|
160
|
+
| `-n` | `--name NAME` | Named instance (multiple containers per project) |
|
|
161
|
+
| `-d` | `--dir PATH` | Run in a different project directory |
|
|
162
|
+
| `-r` | `--repo URL` | Clone a git repo and run in it |
|
|
163
|
+
| `-b` | `--branch NAME` | Branch to checkout (with `--repo`) |
|
|
164
|
+
| `-i` | `--image NAME` | Override base Docker image |
|
|
165
|
+
| `-c` | `--copy` | Copy repo into Docker volume (full isolation) |
|
|
166
|
+
| `-w` | `--worktree` | Use git worktree (lightweight isolation) |
|
|
167
|
+
| `-y` | `--yolo` | Skip prompts, full sudo, no firewall |
|
|
168
|
+
| `-s` | `--safe` | Keep prompts, restricted sudo, firewall on |
|
|
169
|
+
| | `--shared-modules` | Share node_modules between host and container |
|
|
170
|
+
| | `--all` | With `down`: stop all project containers |
|
|
171
|
+
| | `--clean` | With `down`: also remove copy volumes / worktrees |
|
|
161
172
|
|
|
162
173
|
## License
|
|
163
174
|
|
package/bin/aibox
CHANGED
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
# -n, --name NAME Run a named instance (e.g. -n refactor)
|
|
24
24
|
# Allows multiple containers per project
|
|
25
25
|
# -d, --dir PATH Run in a different project directory
|
|
26
|
+
# -r, --repo URL Clone a git repo and run in it
|
|
27
|
+
# -b, --branch NAME Branch to checkout (with --repo)
|
|
26
28
|
# -i, --image NAME Override base Docker image (default: aibox:latest)
|
|
27
29
|
# -c, --copy Copy project into container (full isolation, no host sync)
|
|
28
30
|
# -w, --worktree Use git worktree (lightweight isolation, stays on host)
|
|
@@ -55,7 +57,7 @@ set -euo pipefail
|
|
|
55
57
|
|
|
56
58
|
# ── Script identity ──────────────────────────────────────────────
|
|
57
59
|
SCRIPT_NAME="$(basename "$0")"
|
|
58
|
-
AIBOX_VERSION="
|
|
60
|
+
AIBOX_VERSION="6"
|
|
59
61
|
CONFIG_DIR="${HOME}/.config/aibox"
|
|
60
62
|
DEFAULT_IMAGE="aibox:latest"
|
|
61
63
|
CONTAINER_PREFIX="aibox"
|
|
@@ -185,6 +187,8 @@ IMAGE="$DEFAULT_IMAGE"
|
|
|
185
187
|
SHARED_MODULES=false
|
|
186
188
|
INSTANCE_NAME=""
|
|
187
189
|
PROJECT_DIR_FLAG=""
|
|
190
|
+
REPO_URL=""
|
|
191
|
+
REPO_BRANCH=""
|
|
188
192
|
DOWN_ALL=false
|
|
189
193
|
DOWN_CLEAN=false
|
|
190
194
|
SKIP_PERMISSIONS=false
|
|
@@ -207,6 +211,14 @@ parse_flags() {
|
|
|
207
211
|
PROJECT_DIR_FLAG="${2:?'--dir requires a value'}"
|
|
208
212
|
shift 2
|
|
209
213
|
;;
|
|
214
|
+
-r|--repo)
|
|
215
|
+
REPO_URL="${2:?'--repo requires a value'}"
|
|
216
|
+
shift 2
|
|
217
|
+
;;
|
|
218
|
+
-b|--branch)
|
|
219
|
+
REPO_BRANCH="${2:?'--branch requires a value'}"
|
|
220
|
+
shift 2
|
|
221
|
+
;;
|
|
210
222
|
--shared-modules)
|
|
211
223
|
SHARED_MODULES=true
|
|
212
224
|
shift
|
|
@@ -259,6 +271,31 @@ elif [[ "$SAFE_MODE" == "true" ]]; then
|
|
|
259
271
|
export AIBOX_MODE="safe"
|
|
260
272
|
fi
|
|
261
273
|
|
|
274
|
+
# ── Repo clone ───────────────────────────────────────────────────
|
|
275
|
+
if [[ -n "$REPO_URL" ]]; then
|
|
276
|
+
# Derive a directory name from the repo URL (hash prevents collisions)
|
|
277
|
+
_repo_name=$(basename "$REPO_URL" .git)
|
|
278
|
+
_repo_hash=$(printf '%s' "$REPO_URL" | shasum | cut -c1-6)
|
|
279
|
+
_repo_dir="${CONFIG_DIR}/repos/${_repo_name}-${_repo_hash}"
|
|
280
|
+
|
|
281
|
+
if [[ -d "$_repo_dir/.git" ]]; then
|
|
282
|
+
echo "Repo already cloned (${_repo_dir}). Reusing."
|
|
283
|
+
# Fetch latest and checkout branch if specified
|
|
284
|
+
if [[ -n "$REPO_BRANCH" ]]; then
|
|
285
|
+
git -C "$_repo_dir" fetch --all --quiet 2>/dev/null || true
|
|
286
|
+
git -C "$_repo_dir" checkout "$REPO_BRANCH" 2>/dev/null || true
|
|
287
|
+
fi
|
|
288
|
+
else
|
|
289
|
+
echo "Cloning ${REPO_URL}..."
|
|
290
|
+
mkdir -p "${CONFIG_DIR}/repos"
|
|
291
|
+
_clone_args=(--recursive)
|
|
292
|
+
[[ -n "$REPO_BRANCH" ]] && _clone_args+=(--branch "$REPO_BRANCH")
|
|
293
|
+
git clone "${_clone_args[@]}" "$REPO_URL" "$_repo_dir"
|
|
294
|
+
fi
|
|
295
|
+
|
|
296
|
+
PROJECT_DIR_FLAG="$_repo_dir"
|
|
297
|
+
fi
|
|
298
|
+
|
|
262
299
|
# ── Per-project config file (.aibox) ─────────────────────────────
|
|
263
300
|
if [[ -n "$PROJECT_DIR_FLAG" ]]; then
|
|
264
301
|
PROJECT_DIR="$(cd "$PROJECT_DIR_FLAG" 2>/dev/null && pwd)" || {
|
|
@@ -347,7 +384,7 @@ if ! [[ "$INSTANCE_NAME" =~ ^[a-z0-9_-]+$ ]]; then
|
|
|
347
384
|
exit 1
|
|
348
385
|
fi
|
|
349
386
|
CONTAINER_NAME="${BASE_CONTAINER_NAME}-${INSTANCE_NAME}"
|
|
350
|
-
WORKSPACE_DIR="/${PROJECT_NAME}"
|
|
387
|
+
WORKSPACE_DIR="/workspace/${PROJECT_NAME}"
|
|
351
388
|
|
|
352
389
|
# ── Isolation mode setup ─────────────────────────────────────────
|
|
353
390
|
COPY_VOLUME=""
|
|
@@ -436,6 +473,16 @@ set -e
|
|
|
436
473
|
# Fix auth volume ownership (Docker creates volumes as root)
|
|
437
474
|
chown -R aibox:aibox /home/aibox/.claude 2>/dev/null || true
|
|
438
475
|
|
|
476
|
+
# ── IDE path symlink ─────────────────────────────────────────
|
|
477
|
+
# Create symlink so container paths match host paths for IDE integration.
|
|
478
|
+
# Claude Code reports cwd-based paths to the IDE plugin; if they don't
|
|
479
|
+
# match host paths, diffs break (empty left side, wrong file path).
|
|
480
|
+
if [[ -n "${AIBOX_HOST_DIR:-}" && -n "${AIBOX_WORKSPACE_DIR:-}" \
|
|
481
|
+
&& "$AIBOX_HOST_DIR" != "$AIBOX_WORKSPACE_DIR" ]]; then
|
|
482
|
+
mkdir -p "$(dirname "$AIBOX_HOST_DIR")"
|
|
483
|
+
ln -sfn "$AIBOX_WORKSPACE_DIR" "$AIBOX_HOST_DIR"
|
|
484
|
+
fi
|
|
485
|
+
|
|
439
486
|
# ── Mode-dependent setup ──────────────────────────────────────
|
|
440
487
|
MODE="${AIBOX_MODE:-safe}"
|
|
441
488
|
|
|
@@ -535,7 +582,7 @@ _prepare_copy_volume() {
|
|
|
535
582
|
|
|
536
583
|
# Check if volume already has content (--entrypoint bypasses su-exec drop)
|
|
537
584
|
local has_content
|
|
538
|
-
has_content=$(docker run --rm --entrypoint sh -v "${COPY_VOLUME}
|
|
585
|
+
has_content=$(docker run --rm --entrypoint sh -v "${COPY_VOLUME}:${WORKSPACE_DIR}" "$IMAGE" -c "ls -A ${WORKSPACE_DIR} 2>/dev/null | head -1" 2>/dev/null || true)
|
|
539
586
|
|
|
540
587
|
if [[ -n "$has_content" ]]; then
|
|
541
588
|
echo "Copy volume already populated (${COPY_VOLUME}). Reusing."
|
|
@@ -555,14 +602,15 @@ _prepare_copy_volume() {
|
|
|
555
602
|
fi
|
|
556
603
|
|
|
557
604
|
if ! cat "$bundle_file" | docker run --rm -i --entrypoint sh \
|
|
558
|
-
-v "${COPY_VOLUME}
|
|
605
|
+
-v "${COPY_VOLUME}:${WORKSPACE_DIR}" \
|
|
559
606
|
"$IMAGE" -c "
|
|
560
607
|
cat > /tmp/repo.bundle
|
|
561
|
-
|
|
608
|
+
mkdir -p ${WORKSPACE_DIR}
|
|
609
|
+
cd ${WORKSPACE_DIR}
|
|
562
610
|
git clone /tmp/repo.bundle .
|
|
563
611
|
rm /tmp/repo.bundle
|
|
564
612
|
git checkout -b '${branch_name}' 2>/dev/null || git checkout '${branch_name}'
|
|
565
|
-
chown -R aibox:aibox
|
|
613
|
+
chown -R aibox:aibox ${WORKSPACE_DIR}
|
|
566
614
|
"; then
|
|
567
615
|
rm -f "$bundle_file"
|
|
568
616
|
docker volume rm "$COPY_VOLUME" 2>/dev/null || true
|
|
@@ -648,6 +696,8 @@ _environment_yaml() {
|
|
|
648
696
|
echo "${indent}- CLAUDE_CONFIG_DIR=/home/aibox/.claude"
|
|
649
697
|
echo "${indent}- AIBOX_MODE=\${AIBOX_MODE:-safe}"
|
|
650
698
|
echo "${indent}- AIBOX_EXTRA_DOMAINS=\${AIBOX_EXTRA_DOMAINS:-}"
|
|
699
|
+
echo "${indent}- AIBOX_HOST_DIR=${PROJECT_DIR}"
|
|
700
|
+
echo "${indent}- AIBOX_WORKSPACE_DIR=${WORKSPACE_DIR}"
|
|
651
701
|
}
|
|
652
702
|
|
|
653
703
|
# Build -e flags for docker exec from current terminal environment
|
|
@@ -709,7 +759,7 @@ services:
|
|
|
709
759
|
$(_labels_yaml " ")
|
|
710
760
|
volumes:
|
|
711
761
|
$(_volumes_yaml " " "$PROJECT_DIR")
|
|
712
|
-
working_dir: ${
|
|
762
|
+
working_dir: ${PROJECT_DIR}
|
|
713
763
|
environment:
|
|
714
764
|
$(_environment_yaml " ")
|
|
715
765
|
stdin_open: true
|
|
@@ -737,7 +787,7 @@ services:
|
|
|
737
787
|
$(_labels_yaml " ")
|
|
738
788
|
volumes:
|
|
739
789
|
$(_volumes_yaml " " ".")
|
|
740
|
-
working_dir: ${
|
|
790
|
+
working_dir: ${PROJECT_DIR}
|
|
741
791
|
environment:
|
|
742
792
|
$(_environment_yaml " ")
|
|
743
793
|
stdin_open: true
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aibox-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Run AI coding agents in isolated Docker containers",
|
|
5
5
|
"author": "repalash <palash@shaders.app>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,5 +35,8 @@
|
|
|
35
35
|
],
|
|
36
36
|
"engines": {
|
|
37
37
|
"node": ">=18"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"release": "git tag v$npm_package_version && git push origin v$npm_package_version"
|
|
38
41
|
}
|
|
39
42
|
}
|