@opencode-cloud/core 1.0.10 → 3.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.
- package/Cargo.toml +3 -3
- package/README.md +49 -30
- package/package.json +1 -1
- package/src/config/schema.rs +91 -0
- package/src/docker/Dockerfile +105 -84
- package/src/docker/README.dockerhub.md +39 -0
- package/src/docker/container.rs +114 -3
- package/src/docker/dockerfile.rs +15 -12
- package/src/docker/mod.rs +25 -4
- package/src/docker/mount.rs +330 -0
- package/src/docker/state.rs +120 -0
- package/src/host/ssh_config.rs +1 -1
package/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "opencode-cloud-core"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "3.1.1"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
rust-version = "1.88"
|
|
6
6
|
license = "MIT"
|
|
@@ -47,14 +47,14 @@ tokio-retry = "0.3"
|
|
|
47
47
|
indicatif = { version = "0.17", features = ["tokio", "futures"] }
|
|
48
48
|
http-body-util = "0.1"
|
|
49
49
|
bytes = "1.9"
|
|
50
|
-
reqwest = { version = "0.12", features = ["json"] }
|
|
50
|
+
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json"] }
|
|
51
51
|
|
|
52
52
|
# Platform service management (macOS)
|
|
53
53
|
plist = "1.8"
|
|
54
54
|
|
|
55
55
|
# Host management
|
|
56
56
|
whoami = "1.5"
|
|
57
|
-
ssh2-config = "0.
|
|
57
|
+
ssh2-config-rs = "0.7.2"
|
|
58
58
|
dirs = "6"
|
|
59
59
|
|
|
60
60
|
[build-dependencies]
|
package/README.md
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/pRizz/opencode-cloud/actions/workflows/ci.yml)
|
|
4
4
|
[](https://crates.io/crates/opencode-cloud)
|
|
5
|
-
[](https://github.com/pRizz/opencode-cloud/pkgs/container/opencode-cloud-sandbox)
|
|
6
|
+
[](https://hub.docker.com/r/prizz/opencode-cloud-sandbox)
|
|
6
7
|
[](https://docs.rs/opencode-cloud)
|
|
7
8
|
[](https://blog.rust-lang.org/2025/02/20/Rust-1.85.0.html)
|
|
8
9
|
[](https://opensource.org/licenses/MIT)
|
|
9
10
|
|
|
10
|
-
A production-ready toolkit for deploying [opencode](https://github.com/anomalyco/opencode) as a persistent cloud service.
|
|
11
|
+
A production-ready toolkit for deploying and managing [opencode](https://github.com/anomalyco/opencode) as a persistent cloud service, **sandboxed inside a Docker container** for isolation and security.
|
|
11
12
|
|
|
12
13
|
## Quick install (cargo)
|
|
13
14
|
|
|
@@ -18,45 +19,65 @@ opencode-cloud --version
|
|
|
18
19
|
|
|
19
20
|
## Features
|
|
20
21
|
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
22
|
+
- **Sandboxed execution** - opencode runs inside a Docker container, isolated from your host system
|
|
23
|
+
- **Persistent environment** - Your projects, settings, and shell history persist across restarts
|
|
24
|
+
- **Cross-platform CLI** (`opencode-cloud` / `occ`) - Works on Linux and macOS
|
|
25
|
+
- **Service lifecycle commands** - start, stop, restart, status, logs
|
|
26
|
+
- **Platform service integration** - systemd (Linux) / launchd (macOS) for auto-start on boot
|
|
27
|
+
- **Remote host management** - Manage opencode containers on remote servers via SSH
|
|
28
|
+
- **Web-based admin** - Cockpit integration for container administration
|
|
27
29
|
|
|
28
|
-
##
|
|
30
|
+
## How it works
|
|
29
31
|
|
|
30
|
-
|
|
32
|
+
opencode-cloud runs opencode inside a Docker container, providing:
|
|
31
33
|
|
|
32
|
-
- **
|
|
33
|
-
- **
|
|
34
|
-
|
|
34
|
+
- **Isolation** - opencode and its AI-generated code run in a sandbox, separate from your host system
|
|
35
|
+
- **Reproducibility** - The container includes a full development environment (languages, tools, runtimes)
|
|
36
|
+
- **Persistence** - Docker volumes preserve your work across container restarts and updates
|
|
37
|
+
- **Security** - Network exposure is opt-in; by default, the service only binds to localhost
|
|
35
38
|
|
|
36
|
-
|
|
39
|
+
The CLI manages the container lifecycle, so you don't need to interact with Docker directly.
|
|
37
40
|
|
|
38
|
-
|
|
41
|
+
## Docker Images
|
|
39
42
|
|
|
40
|
-
|
|
43
|
+
The sandbox container image is named **`opencode-cloud-sandbox`** (not `opencode-cloud`) to clearly distinguish it from the CLI tool. The CLI (`opencode-cloud` / `occ`) deploys and manages this sandbox container.
|
|
44
|
+
|
|
45
|
+
The image is published to both registries:
|
|
46
|
+
|
|
47
|
+
| Registry | Image |
|
|
48
|
+
|----------|-------|
|
|
49
|
+
| GitHub Container Registry | [`ghcr.io/prizz/opencode-cloud-sandbox`](https://github.com/pRizz/opencode-cloud/pkgs/container/opencode-cloud-sandbox) |
|
|
50
|
+
| Docker Hub | [`prizz/opencode-cloud-sandbox`](https://hub.docker.com/r/prizz/opencode-cloud-sandbox) |
|
|
41
51
|
|
|
42
|
-
|
|
52
|
+
Pull commands:
|
|
43
53
|
|
|
54
|
+
Docker Hub:
|
|
44
55
|
```bash
|
|
45
|
-
|
|
56
|
+
docker pull prizz/opencode-cloud-sandbox:latest
|
|
46
57
|
```
|
|
47
58
|
|
|
48
|
-
|
|
59
|
+
GitHub Container Registry:
|
|
60
|
+
```bash
|
|
61
|
+
docker pull ghcr.io/prizz/opencode-cloud-sandbox:latest
|
|
62
|
+
```
|
|
49
63
|
|
|
64
|
+
**For most users:** Just use the CLI - it handles image pulling/building automatically:
|
|
50
65
|
```bash
|
|
51
|
-
|
|
52
|
-
occ --version
|
|
66
|
+
occ start # Pulls or builds the image as needed
|
|
53
67
|
```
|
|
54
68
|
|
|
55
|
-
|
|
69
|
+
## Requirements
|
|
70
|
+
|
|
71
|
+
- **Rust 1.85+** - Install via [rustup](https://rustup.rs): `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`
|
|
72
|
+
- **Docker** - For running the opencode container
|
|
73
|
+
|
|
74
|
+
## Installation
|
|
75
|
+
|
|
76
|
+
### Via cargo (recommended)
|
|
56
77
|
|
|
57
78
|
```bash
|
|
58
79
|
cargo install opencode-cloud
|
|
59
|
-
|
|
80
|
+
occ --version
|
|
60
81
|
```
|
|
61
82
|
|
|
62
83
|
### From source
|
|
@@ -74,7 +95,7 @@ cargo run -p opencode-cloud -- --version
|
|
|
74
95
|
# Show version
|
|
75
96
|
occ --version
|
|
76
97
|
|
|
77
|
-
# Start the service (builds
|
|
98
|
+
# Start the service (builds Docker container on first run, ~10-15 min)
|
|
78
99
|
occ start
|
|
79
100
|
|
|
80
101
|
# Start on a custom port
|
|
@@ -172,15 +193,13 @@ just lint
|
|
|
172
193
|
## Architecture
|
|
173
194
|
|
|
174
195
|
This is a monorepo with:
|
|
175
|
-
- `packages/core` - Rust core library
|
|
176
|
-
- `packages/cli-rust` - Rust CLI binary
|
|
177
|
-
- `packages/cli-node` - Node.js CLI
|
|
178
|
-
|
|
179
|
-
The npm package compiles the Rust core on install (no prebuilt binaries).
|
|
196
|
+
- `packages/core` - Rust core library
|
|
197
|
+
- `packages/cli-rust` - Rust CLI binary (recommended)
|
|
198
|
+
- `packages/cli-node` - Node.js CLI (deprecated, directs users to cargo install)
|
|
180
199
|
|
|
181
200
|
### Cargo.toml Sync Requirement
|
|
182
201
|
|
|
183
|
-
The `packages/core/Cargo.toml` file must use **explicit values** rather than `workspace = true` references.
|
|
202
|
+
The `packages/core/Cargo.toml` file must use **explicit values** rather than `workspace = true` references.
|
|
184
203
|
|
|
185
204
|
When updating package metadata (version, edition, rust-version, etc.), keep both files in sync:
|
|
186
205
|
- `Cargo.toml` (workspace root)
|
package/package.json
CHANGED
package/src/config/schema.rs
CHANGED
|
@@ -100,6 +100,19 @@ pub struct Config {
|
|
|
100
100
|
/// - No Cockpit web UI
|
|
101
101
|
#[serde(default = "default_cockpit_enabled")]
|
|
102
102
|
pub cockpit_enabled: bool,
|
|
103
|
+
|
|
104
|
+
/// Source of Docker image: 'prebuilt' (pull from registry) or 'build' (compile locally)
|
|
105
|
+
#[serde(default = "default_image_source")]
|
|
106
|
+
pub image_source: String,
|
|
107
|
+
|
|
108
|
+
/// When to check for updates: 'always' (every start), 'once' (once per version), 'never'
|
|
109
|
+
#[serde(default = "default_update_check")]
|
|
110
|
+
pub update_check: String,
|
|
111
|
+
|
|
112
|
+
/// Bind mounts to apply when starting the container
|
|
113
|
+
/// Format: ["/host/path:/container/path", "/host:/mnt:ro"]
|
|
114
|
+
#[serde(default)]
|
|
115
|
+
pub mounts: Vec<String>,
|
|
103
116
|
}
|
|
104
117
|
|
|
105
118
|
fn default_opencode_web_port() -> u16 {
|
|
@@ -146,6 +159,14 @@ fn default_cockpit_enabled() -> bool {
|
|
|
146
159
|
false
|
|
147
160
|
}
|
|
148
161
|
|
|
162
|
+
fn default_image_source() -> String {
|
|
163
|
+
"prebuilt".to_string()
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
fn default_update_check() -> String {
|
|
167
|
+
"always".to_string()
|
|
168
|
+
}
|
|
169
|
+
|
|
149
170
|
/// Validate and parse a bind address string
|
|
150
171
|
///
|
|
151
172
|
/// Accepts:
|
|
@@ -196,6 +217,9 @@ impl Default for Config {
|
|
|
196
217
|
users: Vec::new(),
|
|
197
218
|
cockpit_port: default_cockpit_port(),
|
|
198
219
|
cockpit_enabled: default_cockpit_enabled(),
|
|
220
|
+
image_source: default_image_source(),
|
|
221
|
+
update_check: default_update_check(),
|
|
222
|
+
mounts: Vec::new(),
|
|
199
223
|
}
|
|
200
224
|
}
|
|
201
225
|
}
|
|
@@ -276,6 +300,7 @@ mod tests {
|
|
|
276
300
|
assert_eq!(config.rate_limit_attempts, 5);
|
|
277
301
|
assert_eq!(config.rate_limit_window_seconds, 60);
|
|
278
302
|
assert!(config.users.is_empty());
|
|
303
|
+
assert!(config.mounts.is_empty());
|
|
279
304
|
}
|
|
280
305
|
|
|
281
306
|
#[test]
|
|
@@ -330,6 +355,9 @@ mod tests {
|
|
|
330
355
|
users: vec!["admin".to_string()],
|
|
331
356
|
cockpit_port: 9090,
|
|
332
357
|
cockpit_enabled: true,
|
|
358
|
+
image_source: default_image_source(),
|
|
359
|
+
update_check: default_update_check(),
|
|
360
|
+
mounts: Vec::new(),
|
|
333
361
|
};
|
|
334
362
|
let json = serde_json::to_string(&config).unwrap();
|
|
335
363
|
let parsed: Config = serde_json::from_str(&json).unwrap();
|
|
@@ -619,4 +647,67 @@ mod tests {
|
|
|
619
647
|
// cockpit_enabled defaults to false (requires Linux host)
|
|
620
648
|
assert!(!config.cockpit_enabled);
|
|
621
649
|
}
|
|
650
|
+
|
|
651
|
+
// Tests for image_source and update_check fields
|
|
652
|
+
|
|
653
|
+
#[test]
|
|
654
|
+
fn test_default_config_image_fields() {
|
|
655
|
+
let config = Config::default();
|
|
656
|
+
assert_eq!(config.image_source, "prebuilt");
|
|
657
|
+
assert_eq!(config.update_check, "always");
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
#[test]
|
|
661
|
+
fn test_serialize_deserialize_with_image_fields() {
|
|
662
|
+
let config = Config {
|
|
663
|
+
image_source: "build".to_string(),
|
|
664
|
+
update_check: "never".to_string(),
|
|
665
|
+
..Config::default()
|
|
666
|
+
};
|
|
667
|
+
let json = serde_json::to_string(&config).unwrap();
|
|
668
|
+
let parsed: Config = serde_json::from_str(&json).unwrap();
|
|
669
|
+
assert_eq!(parsed.image_source, "build");
|
|
670
|
+
assert_eq!(parsed.update_check, "never");
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
#[test]
|
|
674
|
+
fn test_image_fields_default_on_missing() {
|
|
675
|
+
// Old configs without image fields should get defaults
|
|
676
|
+
let json = r#"{"version": 1}"#;
|
|
677
|
+
let config: Config = serde_json::from_str(json).unwrap();
|
|
678
|
+
assert_eq!(config.image_source, "prebuilt");
|
|
679
|
+
assert_eq!(config.update_check, "always");
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// Tests for mounts field
|
|
683
|
+
|
|
684
|
+
#[test]
|
|
685
|
+
fn test_default_config_mounts_field() {
|
|
686
|
+
let config = Config::default();
|
|
687
|
+
assert!(config.mounts.is_empty());
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
#[test]
|
|
691
|
+
fn test_serialize_deserialize_with_mounts() {
|
|
692
|
+
let config = Config {
|
|
693
|
+
mounts: vec![
|
|
694
|
+
"/home/user/data:/workspace/data".to_string(),
|
|
695
|
+
"/home/user/config:/etc/app:ro".to_string(),
|
|
696
|
+
],
|
|
697
|
+
..Config::default()
|
|
698
|
+
};
|
|
699
|
+
let json = serde_json::to_string(&config).unwrap();
|
|
700
|
+
let parsed: Config = serde_json::from_str(&json).unwrap();
|
|
701
|
+
assert_eq!(parsed.mounts.len(), 2);
|
|
702
|
+
assert_eq!(parsed.mounts[0], "/home/user/data:/workspace/data");
|
|
703
|
+
assert_eq!(parsed.mounts[1], "/home/user/config:/etc/app:ro");
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
#[test]
|
|
707
|
+
fn test_mounts_field_default_on_missing() {
|
|
708
|
+
// Old configs without mounts field should get empty vec
|
|
709
|
+
let json = r#"{"version": 1}"#;
|
|
710
|
+
let config: Config = serde_json::from_str(json).unwrap();
|
|
711
|
+
assert!(config.mounts.is_empty());
|
|
712
|
+
}
|
|
622
713
|
}
|
package/src/docker/Dockerfile
CHANGED
|
@@ -53,10 +53,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
|
53
53
|
# -----------------------------------------------------------------------------
|
|
54
54
|
FROM ubuntu:24.04 AS runtime
|
|
55
55
|
|
|
56
|
-
# Version passed at build time (must be after FROM to be available in this stage)
|
|
57
|
-
# Default "dev" for local builds; CI sets actual version via --build-arg
|
|
58
|
-
ARG OPENCODE_CLOUD_VERSION=dev
|
|
59
|
-
|
|
60
56
|
# OCI Labels for image metadata
|
|
61
57
|
LABEL org.opencontainers.image.title="opencode-cloud"
|
|
62
58
|
LABEL org.opencontainers.image.description="AI-assisted development environment with opencode"
|
|
@@ -65,8 +61,6 @@ LABEL org.opencontainers.image.source="https://github.com/pRizz/opencode-cloud"
|
|
|
65
61
|
LABEL org.opencontainers.image.vendor="pRizz"
|
|
66
62
|
LABEL org.opencontainers.image.licenses="MIT"
|
|
67
63
|
LABEL org.opencontainers.image.base.name="ubuntu:24.04"
|
|
68
|
-
# Version label for CLI compatibility checks (set via --build-arg OPENCODE_CLOUD_VERSION)
|
|
69
|
-
LABEL org.opencode-cloud.version="${OPENCODE_CLOUD_VERSION}"
|
|
70
64
|
|
|
71
65
|
# Environment configuration
|
|
72
66
|
ENV DEBIAN_FRONTEND=noninteractive
|
|
@@ -187,14 +181,17 @@ ENV PATH="/home/opencode/.local/bin:${PATH}"
|
|
|
187
181
|
# Shell Setup: Zsh + Oh My Zsh + Starship
|
|
188
182
|
# -----------------------------------------------------------------------------
|
|
189
183
|
# Oh My Zsh - self-managing installer, trusted to handle versions
|
|
190
|
-
|
|
184
|
+
# Disabled temporarily to reduce Docker build time.
|
|
185
|
+
# RUN sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended
|
|
191
186
|
|
|
192
187
|
# Starship prompt - self-managing installer, trusted to handle versions
|
|
193
|
-
|
|
188
|
+
# Disabled temporarily to reduce Docker build time.
|
|
189
|
+
# RUN curl -sS https://starship.rs/install.sh | sh -s -- --yes --bin-dir /home/opencode/.local/bin
|
|
194
190
|
|
|
195
191
|
# Configure zsh with starship
|
|
196
|
-
|
|
197
|
-
|
|
192
|
+
# Disabled temporarily to reduce Docker build time.
|
|
193
|
+
# RUN echo 'eval "$(starship init zsh)"' >> /home/opencode/.zshrc \
|
|
194
|
+
# && echo 'export PATH="/home/opencode/.local/bin:$PATH"' >> /home/opencode/.zshrc
|
|
198
195
|
|
|
199
196
|
# -----------------------------------------------------------------------------
|
|
200
197
|
# mise: Universal Version Manager
|
|
@@ -265,39 +262,46 @@ RUN . /home/opencode/.cargo/env \
|
|
|
265
262
|
&& cargo install --locked ripgrep@15.1.0 eza@0.23.4
|
|
266
263
|
|
|
267
264
|
# lazygit v0.58.1 (2026-01-12) - terminal UI for git
|
|
268
|
-
|
|
269
|
-
|
|
265
|
+
# Disabled temporarily to reduce Docker build time.
|
|
266
|
+
# RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
|
|
267
|
+
# && go install github.com/jesseduffield/lazygit@v0.58.1
|
|
270
268
|
|
|
271
269
|
# -----------------------------------------------------------------------------
|
|
272
270
|
# Additional Development Tools
|
|
273
271
|
# -----------------------------------------------------------------------------
|
|
274
272
|
# fzf v0.67.0 (2025-11-16) - fuzzy finder
|
|
275
|
-
|
|
276
|
-
|
|
273
|
+
# Disabled temporarily to reduce Docker build time.
|
|
274
|
+
# RUN git clone --branch v0.67.0 --depth 1 https://github.com/junegunn/fzf.git /home/opencode/.fzf \
|
|
275
|
+
# && /home/opencode/.fzf/install --all --no-bash --no-fish
|
|
277
276
|
|
|
278
277
|
# yq v4.50.1 (2025-12-14) - YAML processor
|
|
279
|
-
|
|
280
|
-
|
|
278
|
+
# Disabled temporarily to reduce Docker build time.
|
|
279
|
+
# RUN curl -sL https://github.com/mikefarah/yq/releases/download/v4.50.1/yq_linux_$(dpkg --print-architecture) -o /home/opencode/.local/bin/yq \
|
|
280
|
+
# && chmod +x /home/opencode/.local/bin/yq
|
|
281
281
|
|
|
282
282
|
# Install direnv (2026-01-22)
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
283
|
+
# Disabled temporarily to reduce Docker build time.
|
|
284
|
+
# USER root
|
|
285
|
+
# RUN apt-get update && apt-get install -y --no-install-recommends direnv=2.32.* \
|
|
286
|
+
# && rm -rf /var/lib/apt/lists/*
|
|
287
|
+
# USER opencode
|
|
288
|
+
# RUN echo 'eval "$(direnv hook zsh)"' >> /home/opencode/.zshrc
|
|
288
289
|
|
|
289
290
|
# Install HTTPie
|
|
290
|
-
|
|
291
|
-
|
|
291
|
+
# Disabled temporarily to reduce Docker build time.
|
|
292
|
+
# RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
|
|
293
|
+
# && pipx install httpie
|
|
292
294
|
|
|
293
295
|
# Install shellcheck (2026-01-22)
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
296
|
+
# Disabled temporarily to reduce Docker build time.
|
|
297
|
+
# USER root
|
|
298
|
+
# RUN apt-get update && apt-get install -y --no-install-recommends shellcheck=0.9.* \
|
|
299
|
+
# && rm -rf /var/lib/apt/lists/*
|
|
300
|
+
# USER opencode
|
|
298
301
|
# shfmt v3.12.0 (2025-07-06) - shell formatter
|
|
299
|
-
|
|
300
|
-
|
|
302
|
+
# Disabled temporarily to reduce Docker build time.
|
|
303
|
+
# RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
|
|
304
|
+
# && go install mvdan.cc/sh/v3/cmd/shfmt@v3.12.0
|
|
301
305
|
|
|
302
306
|
# Install btop system monitor (2026-01-22)
|
|
303
307
|
USER root
|
|
@@ -351,67 +355,77 @@ RUN mkdir -p /etc/cockpit && \
|
|
|
351
355
|
USER opencode
|
|
352
356
|
|
|
353
357
|
# -----------------------------------------------------------------------------
|
|
354
|
-
# CI/CD
|
|
358
|
+
# CI/CD + tooling (disabled)
|
|
355
359
|
# -----------------------------------------------------------------------------
|
|
356
|
-
#
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
# -----------------------------------------------------------------------------
|
|
360
|
-
# Rust Tooling - pinned versions (2026-01-22)
|
|
361
|
-
# -----------------------------------------------------------------------------
|
|
362
|
-
# cargo-nextest 0.9.122 - fast test runner
|
|
363
|
-
# cargo-audit 0.22.0 - security audit
|
|
364
|
-
# cargo-deny 0.19.0 - dependency linter
|
|
365
|
-
RUN . /home/opencode/.cargo/env \
|
|
366
|
-
&& cargo install --locked cargo-nextest@0.9.122 cargo-audit@0.22.0 cargo-deny@0.19.0
|
|
367
|
-
|
|
368
|
-
# Install mold fast linker (2026-01-22)
|
|
369
|
-
USER root
|
|
370
|
-
RUN apt-get update && apt-get install -y --no-install-recommends mold=2.30.* \
|
|
371
|
-
&& rm -rf /var/lib/apt/lists/*
|
|
372
|
-
USER opencode
|
|
373
|
-
|
|
360
|
+
# NOTE: Commented out because this section adds significant time in GitHub Actions
|
|
361
|
+
# builds. We will reconsider re-adding these tools later, potentially in a more
|
|
362
|
+
# templated/configured Docker image optimized for build tooling.
|
|
374
363
|
# -----------------------------------------------------------------------------
|
|
375
|
-
#
|
|
376
|
-
# -----------------------------------------------------------------------------
|
|
377
|
-
#
|
|
378
|
-
RUN
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
#
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
#
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
#
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
# -----------------------------------------------------------------------------
|
|
398
|
-
#
|
|
399
|
-
#
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
#
|
|
406
|
-
RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
|
|
407
|
-
|
|
364
|
+
# # CI/CD Tools
|
|
365
|
+
# # -----------------------------------------------------------------------------
|
|
366
|
+
# # act v0.2.84 (2026-01-01) - run GitHub Actions locally
|
|
367
|
+
# RUN curl -sL https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash -s -- -b /home/opencode/.local/bin v0.2.84
|
|
368
|
+
#
|
|
369
|
+
# # -----------------------------------------------------------------------------
|
|
370
|
+
# # Rust Tooling - pinned versions (2026-01-22)
|
|
371
|
+
# # -----------------------------------------------------------------------------
|
|
372
|
+
# # cargo-nextest 0.9.122 - fast test runner
|
|
373
|
+
# # cargo-audit 0.22.0 - security audit
|
|
374
|
+
# # cargo-deny 0.19.0 - dependency linter
|
|
375
|
+
# RUN . /home/opencode/.cargo/env \
|
|
376
|
+
# && cargo install --locked cargo-nextest@0.9.122 cargo-audit@0.22.0 cargo-deny@0.19.0
|
|
377
|
+
#
|
|
378
|
+
# # Install mold fast linker (2026-01-22)
|
|
379
|
+
# USER root
|
|
380
|
+
# RUN apt-get update && apt-get install -y --no-install-recommends mold=2.30.* \
|
|
381
|
+
# && rm -rf /var/lib/apt/lists/*
|
|
382
|
+
# USER opencode
|
|
383
|
+
#
|
|
384
|
+
# # -----------------------------------------------------------------------------
|
|
385
|
+
# # Code Quality Tools
|
|
386
|
+
# # -----------------------------------------------------------------------------
|
|
387
|
+
# # JavaScript/TypeScript tools
|
|
388
|
+
# RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
|
|
389
|
+
# && pnpm add -g \
|
|
390
|
+
# prettier \
|
|
391
|
+
# eslint \
|
|
392
|
+
# @biomejs/biome
|
|
393
|
+
#
|
|
394
|
+
# # Python tools
|
|
395
|
+
# RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
|
|
396
|
+
# && pipx install black \
|
|
397
|
+
# && pipx install ruff
|
|
398
|
+
#
|
|
399
|
+
# # Test runners (commonly needed)
|
|
400
|
+
# RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
|
|
401
|
+
# && pnpm add -g jest vitest
|
|
402
|
+
#
|
|
403
|
+
# # Python pytest via pipx
|
|
404
|
+
# RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
|
|
405
|
+
# && pipx install pytest
|
|
406
|
+
#
|
|
407
|
+
# # -----------------------------------------------------------------------------
|
|
408
|
+
# # Protocol Buffers / gRPC (2026-01-22)
|
|
409
|
+
# # -----------------------------------------------------------------------------
|
|
410
|
+
# USER root
|
|
411
|
+
# RUN apt-get update && apt-get install -y --no-install-recommends protobuf-compiler=3.21.* \
|
|
412
|
+
# && rm -rf /var/lib/apt/lists/*
|
|
413
|
+
# USER opencode
|
|
414
|
+
#
|
|
415
|
+
# # grpcurl v1.9.3 (2025-03-11) - gRPC debugging tool
|
|
416
|
+
# RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
|
|
417
|
+
# && go install github.com/fullstorydev/grpcurl/cmd/grpcurl@v1.9.3
|
|
408
418
|
|
|
409
419
|
# -----------------------------------------------------------------------------
|
|
410
420
|
# opencode Installation
|
|
411
421
|
# -----------------------------------------------------------------------------
|
|
412
422
|
# opencode - self-managing installer, trusted to handle versions
|
|
413
423
|
# The script installs to ~/.opencode/bin/
|
|
414
|
-
|
|
424
|
+
# Retry logic added because opencode.ai API can be flaky during parallel builds
|
|
425
|
+
RUN for i in 1 2 3 4 5; do \
|
|
426
|
+
curl -fsSL https://opencode.ai/install | bash && break || \
|
|
427
|
+
echo "Attempt $i failed, retrying in 10s..." && sleep 10; \
|
|
428
|
+
done \
|
|
415
429
|
&& ls -la /home/opencode/.opencode/bin/opencode \
|
|
416
430
|
&& /home/opencode/.opencode/bin/opencode --version
|
|
417
431
|
|
|
@@ -422,7 +436,9 @@ ENV PATH="/home/opencode/.opencode/bin:${PATH}"
|
|
|
422
436
|
# GSD Plugin Installation
|
|
423
437
|
# -----------------------------------------------------------------------------
|
|
424
438
|
# Install the GSD (Get Shit Done) plugin for opencode
|
|
425
|
-
|
|
439
|
+
# Note: If this fails in container builds due to "~" path resolution, retry with
|
|
440
|
+
# OPENCODE_CONFIG_DIR=/home/opencode/.config/opencode set explicitly.
|
|
441
|
+
RUN npx --yes get-shit-done-cc --opencode --global
|
|
426
442
|
|
|
427
443
|
# -----------------------------------------------------------------------------
|
|
428
444
|
# opencode systemd Service (2026-01-22)
|
|
@@ -552,10 +568,15 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
|
|
552
568
|
# Version File
|
|
553
569
|
# -----------------------------------------------------------------------------
|
|
554
570
|
# Store version in file for runtime access (debugging, scripts)
|
|
571
|
+
# Keep this near the end: changing the version invalidates the cache
|
|
572
|
+
# and significantly slows down docker builds if placed earlier.
|
|
555
573
|
USER root
|
|
556
574
|
ARG OPENCODE_CLOUD_VERSION=dev
|
|
575
|
+
LABEL org.opencode-cloud.version="${OPENCODE_CLOUD_VERSION}"
|
|
557
576
|
RUN echo "${OPENCODE_CLOUD_VERSION}" > /etc/opencode-cloud-version
|
|
558
|
-
|
|
577
|
+
# Note: Stay as root - entrypoint.sh needs root to run either:
|
|
578
|
+
# - /sbin/init (systemd mode)
|
|
579
|
+
# - runuser (tini mode, which then drops privileges to opencode user)
|
|
559
580
|
|
|
560
581
|
# -----------------------------------------------------------------------------
|
|
561
582
|
# Final Configuration
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# opencode-cloud-sandbox
|
|
2
|
+
|
|
3
|
+
Opinionated container image for AI-assisted coding with opencode.
|
|
4
|
+
|
|
5
|
+
## What is included
|
|
6
|
+
|
|
7
|
+
- Ubuntu 24.04 (noble)
|
|
8
|
+
- Non-root user with passwordless sudo
|
|
9
|
+
- mise-managed runtimes (Node.js LTS, Python 3.12, Go 1.24)
|
|
10
|
+
- Rust toolchain via rustup
|
|
11
|
+
- Core CLI utilities (ripgrep, eza, jq, git, etc.)
|
|
12
|
+
- Cockpit web console for administration
|
|
13
|
+
- opencode preinstalled with the GSD plugin
|
|
14
|
+
|
|
15
|
+
## Tags
|
|
16
|
+
|
|
17
|
+
- `latest`: Most recent published release
|
|
18
|
+
- `X.Y.Z`: Versioned releases (recommended for pinning)
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
Pull the image:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
docker pull ghcr.io/prizz/opencode-cloud-sandbox:latest
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Run the container:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
docker run --rm -it -p 3000:3000 -p 9090:9090 ghcr.io/prizz/opencode-cloud-sandbox:latest
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The opencode web UI is available at `http://localhost:3000`. Cockpit runs on `http://localhost:9090`.
|
|
35
|
+
|
|
36
|
+
## Source
|
|
37
|
+
|
|
38
|
+
- Repository: https://github.com/pRizz/opencode-cloud
|
|
39
|
+
- Dockerfile: packages/core/src/docker/Dockerfile
|