Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@opencode-cloud/core

Package Overview
Dependencies
Maintainers
1
Versions
90
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@opencode-cloud/core - npm Package Compare versions

Comparing version
4.2.1
to
4.2.2
+1
-1
Cargo.toml
[package]
name = "opencode-cloud-core"
version = "4.2.1"
version = "4.2.2"
edition = "2024"

@@ -5,0 +5,0 @@ rust-version = "1.88"

{
"name": "@opencode-cloud/core",
"version": "4.2.1",
"version": "4.2.2",
"description": "Core NAPI bindings for opencode-cloud (internal package)",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -12,3 +12,3 @@ # opencode-cloud

> [!WARNING]
> This project is a work in progress and evolving rapidly. Use with caution.
> This tool is still a work in progress and is rapidly evolving. Expect frequent updates and breaking changes. Follow updates at https://github.com/pRizz/opencode-cloud. Stability will be announced at some point. Use with caution.

@@ -15,0 +15,0 @@ 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.

@@ -17,2 +17,3 @@ //! Configuration management for opencode-cloud

use crate::docker::mount::ParsedMount;
pub use paths::{get_config_dir, get_config_path, get_data_dir, get_hosts_path, get_pid_path};

@@ -103,3 +104,3 @@ pub use schema::{Config, default_mounts, validate_bind_address};

// Deserialize into Config struct (deny_unknown_fields will reject unknown keys)
let config: Config = serde_json::from_value(parsed_value).with_context(|| {
let mut config: Config = serde_json::from_value(parsed_value).with_context(|| {
format!(

@@ -111,2 +112,25 @@ "Invalid configuration in {}. Check for unknown fields or invalid values.",

let mut removed_shadowing_mounts = false;
config.mounts.retain(|mount_str| {
let parsed = match ParsedMount::parse(mount_str) {
Ok(parsed) => parsed,
Err(_) => return true,
};
if parsed.container_path == "/opt/opencode"
|| parsed.container_path.starts_with("/opt/opencode/")
{
removed_shadowing_mounts = true;
tracing::warn!(
"Skipping bind mount that overrides opencode binaries: {}",
mount_str
);
return false;
}
true
});
if removed_shadowing_mounts {
tracing::info!("Removed bind mounts that shadow /opt/opencode");
}
ensure_default_mount_dirs(&config)?;

@@ -113,0 +137,0 @@ Ok(config)

@@ -5,4 +5,6 @@ //! Configuration schema for opencode-cloud

use super::paths::{get_config_dir, get_data_dir};
use crate::docker::volume::{MOUNT_CONFIG, MOUNT_PROJECTS, MOUNT_SESSION};
use crate::docker::volume::{
MOUNT_CACHE, MOUNT_CONFIG, MOUNT_PROJECTS, MOUNT_SESSION, MOUNT_STATE,
};
use directories::BaseDirs;
use serde::{Deserialize, Serialize};

@@ -180,14 +182,17 @@ use std::net::{IpAddr, Ipv4Addr};

pub fn default_mounts() -> Vec<String> {
let maybe_data_dir = get_data_dir();
let maybe_config_dir = get_config_dir();
let (Some(data_dir), Some(config_dir)) = (maybe_data_dir, maybe_config_dir) else {
let Some(base_dirs) = BaseDirs::new() else {
return Vec::new();
};
let home_dir = base_dirs.home_dir();
let session_dir = data_dir.join("data");
let data_dir = home_dir.join(".local").join("share").join("opencode");
let state_dir = home_dir.join(".local").join("state").join("opencode");
let cache_dir = home_dir.join(".cache").join("opencode");
let config_dir = home_dir.join(".config").join("opencode");
let workspace_dir = data_dir.join("workspace");
let config_dir = config_dir.join("container");
vec![
format!("{}:{MOUNT_SESSION}", session_dir.display()),
format!("{}:{MOUNT_SESSION}", data_dir.display()),
format!("{}:{MOUNT_STATE}", state_dir.display()),
format!("{}:{MOUNT_CACHE}", cache_dir.display()),
format!("{}:{MOUNT_PROJECTS}", workspace_dir.display()),

@@ -194,0 +199,0 @@ format!("{}:{MOUNT_CONFIG}", config_dir.display()),

@@ -9,3 +9,4 @@ //! Docker container lifecycle management

use super::volume::{
MOUNT_CONFIG, MOUNT_PROJECTS, MOUNT_SESSION, VOLUME_CONFIG, VOLUME_PROJECTS, VOLUME_SESSION,
MOUNT_CACHE, MOUNT_CONFIG, MOUNT_PROJECTS, MOUNT_SESSION, MOUNT_STATE, VOLUME_CACHE,
VOLUME_CONFIG, VOLUME_PROJECTS, VOLUME_SESSION, VOLUME_STATE,
};

@@ -20,3 +21,3 @@ use super::{DockerClient, DockerError};

};
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use tracing::debug;

@@ -30,2 +31,7 @@

fn has_env_key(env: &[String], key: &str) -> bool {
let prefix = format!("{key}=");
env.iter().any(|entry| entry.starts_with(&prefix))
}
/// Create the opencode container with volume mounts

@@ -91,26 +97,32 @@ ///

// Create volume mounts
let mut mounts = vec![
Mount {
target: Some(MOUNT_SESSION.to_string()),
source: Some(VOLUME_SESSION.to_string()),
let mut bind_targets = HashSet::new();
if let Some(ref user_mounts) = bind_mounts {
for parsed in user_mounts {
bind_targets.insert(parsed.container_path.clone());
}
}
// Create volume mounts (skip if overridden by bind mounts)
let mut mounts = Vec::new();
let mut add_volume_mount = |target: &str, source: &str| {
if bind_targets.contains(target) {
tracing::trace!(
"Skipping volume mount for {} (overridden by bind mount)",
target
);
return;
}
mounts.push(Mount {
target: Some(target.to_string()),
source: Some(source.to_string()),
typ: Some(MountTypeEnum::VOLUME),
read_only: Some(false),
..Default::default()
},
Mount {
target: Some(MOUNT_PROJECTS.to_string()),
source: Some(VOLUME_PROJECTS.to_string()),
typ: Some(MountTypeEnum::VOLUME),
read_only: Some(false),
..Default::default()
},
Mount {
target: Some(MOUNT_CONFIG.to_string()),
source: Some(VOLUME_CONFIG.to_string()),
typ: Some(MountTypeEnum::VOLUME),
read_only: Some(false),
..Default::default()
},
];
});
};
add_volume_mount(MOUNT_SESSION, VOLUME_SESSION);
add_volume_mount(MOUNT_STATE, VOLUME_STATE);
add_volume_mount(MOUNT_CACHE, VOLUME_CACHE);
add_volume_mount(MOUNT_PROJECTS, VOLUME_PROJECTS);
add_volume_mount(MOUNT_CONFIG, VOLUME_CONFIG);

@@ -196,10 +208,20 @@ // Add user-defined bind mounts from config/CLI

// Build environment variables
let mut env = env_vars.unwrap_or_default();
if !has_env_key(&env, "XDG_DATA_HOME") {
env.push("XDG_DATA_HOME=/home/opencode/.local/share".to_string());
}
if !has_env_key(&env, "XDG_STATE_HOME") {
env.push("XDG_STATE_HOME=/home/opencode/.local/state".to_string());
}
if !has_env_key(&env, "XDG_CONFIG_HOME") {
env.push("XDG_CONFIG_HOME=/home/opencode/.config".to_string());
}
if !has_env_key(&env, "XDG_CACHE_HOME") {
env.push("XDG_CACHE_HOME=/home/opencode/.cache".to_string());
}
// Add USE_SYSTEMD=1 when Cockpit is enabled to tell entrypoint to use systemd
let final_env = if cockpit_enabled_val {
let mut env = env_vars.unwrap_or_default();
if cockpit_enabled_val && !has_env_key(&env, "USE_SYSTEMD") {
env.push("USE_SYSTEMD=1".to_string());
Some(env)
} else {
env_vars
};
}
let final_env = if env.is_empty() { None } else { Some(env) };

@@ -206,0 +228,0 @@ // Create container config

@@ -167,2 +167,3 @@ # =============================================================================

/home/opencode/.local/share \
/home/opencode/.local/state \
/home/opencode/.cache \

@@ -533,12 +534,11 @@ /home/opencode/workspace

&& cd /tmp/opencode-repo \
&& mkdir -p /home/opencode/.local/share/opencode/bin \
&& mkdir -p /home/opencode/.local/share/opencode/ui \
&& cp /tmp/opencode-repo/packages/opencode/dist/opencode-*/bin/opencode /home/opencode/.local/share/opencode/bin/opencode \
&& cp -R /tmp/opencode-repo/packages/opencode/dist/opencode-*/ui/. /home/opencode/.local/share/opencode/ui/ \
&& chown -R opencode:opencode /home/opencode/.local/share/opencode \
&& chmod +x /home/opencode/.local/share/opencode/bin/opencode \
&& /home/opencode/.local/share/opencode/bin/opencode --version
&& sudo mkdir -p /opt/opencode/bin /opt/opencode/ui \
&& sudo cp /tmp/opencode-repo/packages/opencode/dist/opencode-*/bin/opencode /opt/opencode/bin/opencode \
&& sudo cp -R /tmp/opencode-repo/packages/opencode/dist/opencode-*/ui/. /opt/opencode/ui/ \
&& sudo chown -R opencode:opencode /opt/opencode \
&& sudo chmod +x /opt/opencode/bin/opencode \
&& /opt/opencode/bin/opencode --version
# Add opencode to PATH
ENV PATH="/home/opencode/.local/share/opencode/bin:${PATH}"
ENV PATH="/opt/opencode/bin:${PATH}"

@@ -656,6 +656,6 @@ # -----------------------------------------------------------------------------

'WorkingDirectory=/home/opencode/workspace' \
'ExecStart=/home/opencode/.local/share/opencode/bin/opencode web --port 3000 --hostname 0.0.0.0' \
'ExecStart=/opt/opencode/bin/opencode web --port 3000 --hostname 0.0.0.0' \
'Restart=always' \
'RestartSec=5' \
'Environment=PATH=/home/opencode/.local/share/opencode/bin:/home/opencode/.local/bin:/home/opencode/.cargo/bin:/home/opencode/.local/share/mise/shims:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' \
'Environment=PATH=/opt/opencode/bin:/home/opencode/.local/bin:/home/opencode/.cargo/bin:/home/opencode/.local/share/mise/shims:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' \
'' \

@@ -706,3 +706,3 @@ '[Install]' \

' # Use runuser to switch to opencode user without password prompt' \
' exec runuser -u opencode -- sh -lc "cd /home/opencode/workspace && /home/opencode/.local/share/opencode/bin/opencode web --port 3000 --hostname 0.0.0.0"' \
' exec runuser -u opencode -- sh -lc "cd /home/opencode/workspace && /opt/opencode/bin/opencode web --port 3000 --hostname 0.0.0.0"' \
'fi' \

@@ -709,0 +709,0 @@ > /usr/local/bin/entrypoint.sh && chmod +x /usr/local/bin/entrypoint.sh

@@ -63,4 +63,5 @@ //! Docker operations module

pub use volume::{
MOUNT_CONFIG, MOUNT_PROJECTS, MOUNT_SESSION, VOLUME_CONFIG, VOLUME_NAMES, VOLUME_PROJECTS,
VOLUME_SESSION, ensure_volumes_exist, remove_all_volumes, remove_volume, volume_exists,
MOUNT_CACHE, MOUNT_CONFIG, MOUNT_PROJECTS, MOUNT_SESSION, MOUNT_STATE, VOLUME_CACHE,
VOLUME_CONFIG, VOLUME_NAMES, VOLUME_PROJECTS, VOLUME_SESSION, VOLUME_STATE,
ensure_volumes_exist, remove_all_volumes, remove_volume, volume_exists,
};

@@ -67,0 +68,0 @@

@@ -14,2 +14,8 @@ //! Docker volume management

/// Volume name for opencode state
pub const VOLUME_STATE: &str = "opencode-state";
/// Volume name for opencode cache
pub const VOLUME_CACHE: &str = "opencode-cache";
/// Volume name for project files

@@ -22,7 +28,19 @@ pub const VOLUME_PROJECTS: &str = "opencode-workspace";

/// All volume names as array for iteration
pub const VOLUME_NAMES: [&str; 3] = [VOLUME_SESSION, VOLUME_PROJECTS, VOLUME_CONFIG];
pub const VOLUME_NAMES: [&str; 5] = [
VOLUME_SESSION,
VOLUME_STATE,
VOLUME_CACHE,
VOLUME_PROJECTS,
VOLUME_CONFIG,
];
/// Mount point for opencode data inside container
pub const MOUNT_SESSION: &str = "/home/opencode/.local/share";
pub const MOUNT_SESSION: &str = "/home/opencode/.local/share/opencode";
/// Mount point for opencode state inside container
pub const MOUNT_STATE: &str = "/home/opencode/.local/state/opencode";
/// Mount point for opencode cache inside container
pub const MOUNT_CACHE: &str = "/home/opencode/.cache/opencode";
/// Mount point for project files inside container

@@ -32,3 +50,3 @@ pub const MOUNT_PROJECTS: &str = "/home/opencode/workspace";

/// Mount point for configuration inside container
pub const MOUNT_CONFIG: &str = "/home/opencode/.config";
pub const MOUNT_CONFIG: &str = "/home/opencode/.config/opencode";

@@ -129,2 +147,4 @@ /// Ensure all required volumes exist

assert_eq!(VOLUME_SESSION, "opencode-data");
assert_eq!(VOLUME_STATE, "opencode-state");
assert_eq!(VOLUME_CACHE, "opencode-cache");
assert_eq!(VOLUME_PROJECTS, "opencode-workspace");

@@ -136,4 +156,6 @@ assert_eq!(VOLUME_CONFIG, "opencode-config");

fn volume_names_array_has_all_volumes() {
assert_eq!(VOLUME_NAMES.len(), 3);
assert_eq!(VOLUME_NAMES.len(), 5);
assert!(VOLUME_NAMES.contains(&VOLUME_SESSION));
assert!(VOLUME_NAMES.contains(&VOLUME_STATE));
assert!(VOLUME_NAMES.contains(&VOLUME_CACHE));
assert!(VOLUME_NAMES.contains(&VOLUME_PROJECTS));

@@ -145,6 +167,8 @@ assert!(VOLUME_NAMES.contains(&VOLUME_CONFIG));

fn mount_points_are_correct() {
assert_eq!(MOUNT_SESSION, "/home/opencode/.local/share");
assert_eq!(MOUNT_SESSION, "/home/opencode/.local/share/opencode");
assert_eq!(MOUNT_STATE, "/home/opencode/.local/state/opencode");
assert_eq!(MOUNT_CACHE, "/home/opencode/.cache/opencode");
assert_eq!(MOUNT_PROJECTS, "/home/opencode/workspace");
assert_eq!(MOUNT_CONFIG, "/home/opencode/.config");
assert_eq!(MOUNT_CONFIG, "/home/opencode/.config/opencode");
}
}