@opencode-cloud/core 1.0.8 → 3.0.15

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,8 +1,8 @@
1
1
  [package]
2
2
  name = "opencode-cloud-core"
3
- version = "1.0.8"
3
+ version = "3.0.15"
4
4
  edition = "2024"
5
- rust-version = "1.85"
5
+ rust-version = "1.88"
6
6
  license = "MIT"
7
7
  repository = "https://github.com/pRizz/opencode-cloud"
8
8
  homepage = "https://github.com/pRizz/opencode-cloud"
@@ -32,6 +32,7 @@ thiserror = "2"
32
32
  anyhow = "1"
33
33
  tracing = "0.1"
34
34
  console = "0.16"
35
+ chrono = { version = "0.4", default-features = false, features = ["std", "clock"] }
35
36
 
36
37
  # NAPI dependencies (optional - only for Node bindings)
37
38
  napi = { version = "2", features = ["tokio_rt", "napi9"], optional = true }
@@ -46,10 +47,16 @@ tokio-retry = "0.3"
46
47
  indicatif = { version = "0.17", features = ["tokio", "futures"] }
47
48
  http-body-util = "0.1"
48
49
  bytes = "1.9"
50
+ reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json"] }
49
51
 
50
52
  # Platform service management (macOS)
51
53
  plist = "1.8"
52
54
 
55
+ # Host management
56
+ whoami = "1.5"
57
+ ssh2-config-rs = "0.7.1"
58
+ dirs = "6"
59
+
53
60
  [build-dependencies]
54
61
  napi-build = "2"
55
62
 
package/README.md CHANGED
@@ -2,54 +2,82 @@
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.
12
+
13
+ ## Quick install (cargo)
14
+
15
+ ```bash
16
+ cargo install opencode-cloud
17
+ opencode-cloud --version
18
+ ```
11
19
 
12
20
  ## Features
13
21
 
14
- - Cross-platform CLI (`opencode-cloud` / `occ`)
15
- - Docker container management
16
- - Service lifecycle commands (start, stop, status, logs)
17
- - Platform service integration (systemd/launchd)
18
- - XDG-compliant configuration
19
- - 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
20
29
 
21
- ## Requirements
30
+ ## How it works
22
31
 
23
- ### For npm installation
32
+ opencode-cloud runs opencode inside a Docker container, providing:
24
33
 
25
- - **Node.js 20+**
26
- - **Rust 1.82+** (for compiling native bindings)
27
- - 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
28
38
 
29
- ### For cargo installation
39
+ The CLI manages the container lifecycle, so you don't need to interact with Docker directly.
30
40
 
31
- - **Rust 1.82+**
41
+ ## Docker Images
32
42
 
33
- ## 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:
34
46
 
35
- ### Via npm (compiles from source)
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) |
36
51
 
52
+ Pull commands:
53
+
54
+ Docker Hub:
37
55
  ```bash
38
- npx opencode-cloud --version
56
+ docker pull prizz/opencode-cloud-sandbox:latest
39
57
  ```
40
58
 
41
- Or install globally:
59
+ GitHub Container Registry:
60
+ ```bash
61
+ docker pull ghcr.io/prizz/opencode-cloud-sandbox:latest
62
+ ```
42
63
 
64
+ **For most users:** Just use the CLI - it handles image pulling/building automatically:
43
65
  ```bash
44
- npm install -g opencode-cloud
45
- occ --version
66
+ occ start # Pulls or builds the image as needed
46
67
  ```
47
68
 
48
- ### 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)
49
77
 
50
78
  ```bash
51
79
  cargo install opencode-cloud
52
- opencode-cloud --version
80
+ occ --version
53
81
  ```
54
82
 
55
83
  ### From source
@@ -67,7 +95,7 @@ cargo run -p opencode-cloud -- --version
67
95
  # Show version
68
96
  occ --version
69
97
 
70
- # Start the service (builds image on first run)
98
+ # Start the service (builds Docker container on first run, ~10-15 min)
71
99
  occ start
72
100
 
73
101
  # Start on a custom port
@@ -165,15 +193,13 @@ just lint
165
193
  ## Architecture
166
194
 
167
195
  This is a monorepo with:
168
- - `packages/core` - Rust core library with NAPI-RS bindings
169
- - `packages/cli-rust` - Rust CLI binary
170
- - `packages/cli-node` - Node.js CLI wrapper (calls into core via NAPI)
171
-
172
- 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)
173
199
 
174
200
  ### Cargo.toml Sync Requirement
175
201
 
176
- 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.
177
203
 
178
204
  When updating package metadata (version, edition, rust-version, etc.), keep both files in sync:
179
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.8",
3
+ "version": "3.0.15",
4
4
  "description": "Core NAPI bindings for opencode-cloud (internal package)",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
package/src/config/mod.rs CHANGED
@@ -5,6 +5,7 @@
5
5
 
6
6
  pub mod paths;
7
7
  pub mod schema;
8
+ pub mod validation;
8
9
 
9
10
  use std::fs::{self, File};
10
11
  use std::io::{Read, Write};
@@ -13,8 +14,12 @@ use std::path::PathBuf;
13
14
  use anyhow::{Context, Result};
14
15
  use jsonc_parser::parse_to_serde_value;
15
16
 
16
- pub use paths::{get_config_dir, get_config_path, get_data_dir, get_pid_path};
17
- pub use schema::Config;
17
+ pub use paths::{get_config_dir, get_config_path, get_data_dir, get_hosts_path, get_pid_path};
18
+ pub use schema::{Config, validate_bind_address};
19
+ pub use validation::{
20
+ ValidationError, ValidationWarning, display_validation_error, display_validation_warning,
21
+ validate_config,
22
+ };
18
23
 
19
24
  /// Ensure the config directory exists
20
25
  ///
@@ -84,7 +89,7 @@ pub fn load_config() -> Result<Config> {
84
89
 
85
90
  // Parse JSONC (JSON with comments)
86
91
  let parsed_value = parse_to_serde_value(&contents, &Default::default())
87
- .map_err(|e| anyhow::anyhow!("Invalid JSONC in config file: {}", e))?
92
+ .map_err(|e| anyhow::anyhow!("Invalid JSONC in config file: {e}"))?
88
93
  .ok_or_else(|| anyhow::anyhow!("Config file is empty"))?;
89
94
 
90
95
  // Deserialize into Config struct (deny_unknown_fields will reject unknown keys)
@@ -72,6 +72,13 @@ pub fn get_pid_path() -> Option<PathBuf> {
72
72
  get_data_dir().map(|d| d.join("opencode-cloud.pid"))
73
73
  }
74
74
 
75
+ /// Get the full path to the hosts configuration file
76
+ ///
77
+ /// Returns: `{config_dir}/hosts.json`
78
+ pub fn get_hosts_path() -> Option<PathBuf> {
79
+ get_config_dir().map(|d| d.join("hosts.json"))
80
+ }
81
+
75
82
  #[cfg(test)]
76
83
  mod tests {
77
84
  use super::*;
@@ -105,4 +112,11 @@ mod tests {
105
112
  assert!(path.is_some());
106
113
  assert!(path.unwrap().ends_with("opencode-cloud.pid"));
107
114
  }
115
+
116
+ #[test]
117
+ fn test_hosts_path_ends_with_hosts_json() {
118
+ let path = get_hosts_path();
119
+ assert!(path.is_some());
120
+ assert!(path.unwrap().ends_with("hosts.json"));
121
+ }
108
122
  }