@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "opencode-cloud-core"
3
- version = "1.0.10"
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.6"
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
  [![CI](https://github.com/pRizz/opencode-cloud/actions/workflows/ci.yml/badge.svg)](https://github.com/pRizz/opencode-cloud/actions/workflows/ci.yml)
4
4
  [![crates.io](https://img.shields.io/crates/v/opencode-cloud.svg)](https://crates.io/crates/opencode-cloud)
5
- [![npm](https://img.shields.io/npm/v/opencode-cloud.svg)](https://www.npmjs.com/package/opencode-cloud)
5
+ [![GHCR](https://img.shields.io/badge/ghcr.io-sandbox-blue?logo=github)](https://github.com/pRizz/opencode-cloud/pkgs/container/opencode-cloud-sandbox)
6
+ [![Docker Hub](https://img.shields.io/docker/v/prizz/opencode-cloud-sandbox?label=docker&sort=semver)](https://hub.docker.com/r/prizz/opencode-cloud-sandbox)
6
7
  [![docs.rs](https://docs.rs/opencode-cloud/badge.svg)](https://docs.rs/opencode-cloud)
7
8
  [![MSRV](https://img.shields.io/badge/MSRV-1.85-blue.svg)](https://blog.rust-lang.org/2025/02/20/Rust-1.85.0.html)
8
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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
- - Cross-platform CLI (`opencode-cloud` / `occ`)
22
- - Docker container management
23
- - Service lifecycle commands (start, stop, status, logs)
24
- - Platform service integration (systemd/launchd)
25
- - XDG-compliant configuration
26
- - Singleton enforcement (one instance per host)
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
- ## Requirements
30
+ ## How it works
29
31
 
30
- ### For npm installation
32
+ opencode-cloud runs opencode inside a Docker container, providing:
31
33
 
32
- - **Node.js 20+**
33
- - **Rust 1.82+** (for compiling native bindings)
34
- - Install via [rustup](https://rustup.rs): `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`
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
- ### For cargo installation
39
+ The CLI manages the container lifecycle, so you don't need to interact with Docker directly.
37
40
 
38
- - **Rust 1.82+**
41
+ ## Docker Images
39
42
 
40
- ## Installation
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
- ### Via npm (compiles from source)
52
+ Pull commands:
43
53
 
54
+ Docker Hub:
44
55
  ```bash
45
- npx opencode-cloud --version
56
+ docker pull prizz/opencode-cloud-sandbox:latest
46
57
  ```
47
58
 
48
- Or install globally:
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
- npm install -g opencode-cloud
52
- occ --version
66
+ occ start # Pulls or builds the image as needed
53
67
  ```
54
68
 
55
- ### Via cargo
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
- opencode-cloud --version
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 image on first run)
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 with NAPI-RS bindings
176
- - `packages/cli-rust` - Rust CLI binary
177
- - `packages/cli-node` - Node.js CLI wrapper (calls into core via NAPI)
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. This is because when users install the npm package, they only get `packages/core/` without the workspace root `Cargo.toml`, so workspace inheritance would fail.
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencode-cloud/core",
3
- "version": "1.0.10",
3
+ "version": "3.1.1",
4
4
  "description": "Core NAPI bindings for opencode-cloud (internal package)",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -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
  }
@@ -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
- RUN sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended
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
- RUN curl -sS https://starship.rs/install.sh | sh -s -- --yes --bin-dir /home/opencode/.local/bin
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
- RUN echo 'eval "$(starship init zsh)"' >> /home/opencode/.zshrc \
197
- && echo 'export PATH="/home/opencode/.local/bin:$PATH"' >> /home/opencode/.zshrc
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
- RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
269
- && go install github.com/jesseduffield/lazygit@v0.58.1
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
- RUN git clone --branch v0.67.0 --depth 1 https://github.com/junegunn/fzf.git /home/opencode/.fzf \
276
- && /home/opencode/.fzf/install --all --no-bash --no-fish
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
- 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
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
- USER root
284
- RUN apt-get update && apt-get install -y --no-install-recommends direnv=2.32.* \
285
- && rm -rf /var/lib/apt/lists/*
286
- USER opencode
287
- RUN echo 'eval "$(direnv hook zsh)"' >> /home/opencode/.zshrc
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
- RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
291
- && pipx install httpie
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
- USER root
295
- RUN apt-get update && apt-get install -y --no-install-recommends shellcheck=0.9.* \
296
- && rm -rf /var/lib/apt/lists/*
297
- USER opencode
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
- RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
300
- && go install mvdan.cc/sh/v3/cmd/shfmt@v3.12.0
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 Tools
358
+ # CI/CD + tooling (disabled)
355
359
  # -----------------------------------------------------------------------------
356
- # act v0.2.84 (2026-01-01) - run GitHub Actions locally
357
- RUN curl -sL https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash -s -- -b /home/opencode/.local/bin v0.2.84
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
- # Code Quality Tools
376
- # -----------------------------------------------------------------------------
377
- # JavaScript/TypeScript tools
378
- RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
379
- && pnpm add -g \
380
- prettier \
381
- eslint \
382
- @biomejs/biome
383
-
384
- # Python tools
385
- RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
386
- && pipx install black \
387
- && pipx install ruff
388
-
389
- # Test runners (commonly needed)
390
- RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
391
- && pnpm add -g jest vitest
392
-
393
- # Python pytest via pipx
394
- RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
395
- && pipx install pytest
396
-
397
- # -----------------------------------------------------------------------------
398
- # Protocol Buffers / gRPC (2026-01-22)
399
- # -----------------------------------------------------------------------------
400
- USER root
401
- RUN apt-get update && apt-get install -y --no-install-recommends protobuf-compiler=3.21.* \
402
- && rm -rf /var/lib/apt/lists/*
403
- USER opencode
404
-
405
- # grpcurl v1.9.3 (2025-03-11) - gRPC debugging tool
406
- RUN eval "$(/home/opencode/.local/bin/mise activate bash)" \
407
- && go install github.com/fullstorydev/grpcurl/cmd/grpcurl@v1.9.3
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
- RUN curl -fsSL https://opencode.ai/install | bash \
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
- RUN git clone https://github.com/rokicool/gsd-opencode.git /home/opencode/.config/opencode/plugins/gsd-opencode
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
- USER opencode
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