@opencode-cloud/core 13.0.0 → 13.0.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 = "13.0.0"
3
+ version = "13.0.1"
4
4
  edition = "2024"
5
5
  rust-version = "1.89"
6
6
  license = "MIT"
@@ -23,11 +23,11 @@ napi = ["dep:napi", "dep:napi-derive"]
23
23
 
24
24
  [dependencies]
25
25
  clap = { version = "4.5", features = ["derive"] }
26
- tokio = { version = "1.43", features = ["rt-multi-thread", "macros"] }
26
+ tokio = { version = "1.49", features = ["rt-multi-thread", "macros"] }
27
27
  serde = { version = "1.0", features = ["derive"] }
28
28
  serde_json = "1.0"
29
29
  jsonc-parser = { version = "0.29", features = ["serde"] }
30
- directories = "5"
30
+ directories = "6"
31
31
  thiserror = "2"
32
32
  anyhow = "1"
33
33
  tracing = "0.1"
@@ -35,18 +35,18 @@ console = "0.16"
35
35
  chrono = { version = "0.4", default-features = false, features = ["std", "clock"] }
36
36
 
37
37
  # NAPI dependencies (optional - only for Node bindings)
38
- napi = { version = "2", features = ["tokio_rt", "napi9"], optional = true }
39
- napi-derive = { version = "2", optional = true }
38
+ napi = { version = "3", features = ["tokio_rt", "napi9"], optional = true }
39
+ napi-derive = { version = "3", optional = true }
40
40
 
41
41
  # Docker integration
42
42
  bollard = { version = "0.20.1", features = ["chrono", "buildkit"] }
43
43
  futures-util = "0.3"
44
44
  tar = "0.4"
45
- flate2 = "1.0"
45
+ flate2 = "1.1"
46
46
  tokio-retry = "0.3"
47
- indicatif = { version = "0.17", features = ["tokio", "futures"] }
47
+ indicatif = { version = "0.18", features = ["tokio", "futures"] }
48
48
  http-body-util = "0.1"
49
- bytes = "1.9"
49
+ bytes = "1.11"
50
50
  reqwest = { version = "0.13", default-features = false, features = ["rustls", "webpki-roots", "json"] }
51
51
 
52
52
  # Platform service management (macOS)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencode-cloud/core",
3
- "version": "13.0.0",
3
+ "version": "13.0.1",
4
4
  "description": "Core NAPI bindings for opencode-cloud (internal package)",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -85,9 +85,12 @@ pub trait ServiceManager: Send + Sync {
85
85
 
86
86
  /// Get the appropriate service manager for the current platform
87
87
  ///
88
+ /// # Arguments
89
+ /// * `boot_mode` - "user" for user-level service (default), "system" for system-level
90
+ ///
88
91
  /// Returns an error if the platform is not supported or if the
89
92
  /// service manager implementation is not yet available.
90
- pub fn get_service_manager() -> Result<Box<dyn ServiceManager>> {
93
+ pub fn get_service_manager(boot_mode: &str) -> Result<Box<dyn ServiceManager>> {
91
94
  #[cfg(target_os = "linux")]
92
95
  {
93
96
  if !systemd::systemd_available() {
@@ -96,11 +99,11 @@ pub fn get_service_manager() -> Result<Box<dyn ServiceManager>> {
96
99
  Service registration requires systemd as the init system."
97
100
  ));
98
101
  }
99
- Ok(Box::new(systemd::SystemdManager::new("user")))
102
+ Ok(Box::new(systemd::SystemdManager::new(boot_mode)))
100
103
  }
101
104
  #[cfg(target_os = "macos")]
102
105
  {
103
- Ok(Box::new(launchd::LaunchdManager::new("user")))
106
+ Ok(Box::new(launchd::LaunchdManager::new(boot_mode)))
104
107
  }
105
108
  #[cfg(not(any(target_os = "linux", target_os = "macos")))]
106
109
  {
@@ -164,7 +167,7 @@ mod tests {
164
167
 
165
168
  #[test]
166
169
  fn test_get_service_manager_behavior() {
167
- let result = get_service_manager();
170
+ let result = get_service_manager("user");
168
171
 
169
172
  // On Linux with systemd: returns Ok(SystemdManager)
170
173
  // On Linux without systemd: returns Err (systemd not available)
@@ -188,4 +191,16 @@ mod tests {
188
191
  assert!(result.is_err());
189
192
  }
190
193
  }
194
+
195
+ #[test]
196
+ fn test_get_service_manager_respects_boot_mode() {
197
+ // Test that boot_mode parameter is passed through
198
+ let user_result = get_service_manager("user");
199
+ let system_result = get_service_manager("system");
200
+
201
+ // Both should either succeed or fail based on platform support,
202
+ // but they should not panic
203
+ let _ = user_result;
204
+ let _ = system_result;
205
+ }
191
206
  }
@@ -130,11 +130,37 @@ pub fn systemd_available() -> bool {
130
130
  Path::new("/run/systemd/system").exists()
131
131
  }
132
132
 
133
+ /// Check if systemd user session is available for the current user
134
+ ///
135
+ /// Returns true if XDG_RUNTIME_DIR is set and the user's systemd directory exists.
136
+ /// This is needed for `systemctl --user` commands to work.
137
+ pub fn systemd_user_session_available() -> bool {
138
+ if let Ok(runtime_dir) = std::env::var("XDG_RUNTIME_DIR") {
139
+ // Check if the user's systemd directory exists
140
+ Path::new(&runtime_dir).join("systemd").exists()
141
+ } else {
142
+ false
143
+ }
144
+ }
145
+
133
146
  impl ServiceManager for SystemdManager {
134
147
  fn install(&self, config: &ServiceConfig) -> Result<InstallResult> {
135
- // Check permissions for system-level installation
136
- if !self.user_mode {
137
- // Check if we can write to /etc/systemd/system/
148
+ // Check permissions and session availability based on mode
149
+ if self.user_mode {
150
+ // User-level installation requires an active systemd user session
151
+ if !systemd_user_session_available() {
152
+ return Err(anyhow!(
153
+ "User-level systemd session not available.\n\
154
+ This typically happens during cloud-init or when running as a \
155
+ different user without an active login session.\n\n\
156
+ Solutions:\n\
157
+ 1. Use system-level installation: occ config set boot_mode system\n\
158
+ 2. Run the command from an interactive login session\n\
159
+ 3. Ensure XDG_RUNTIME_DIR is set and the user has an active systemd session"
160
+ ));
161
+ }
162
+ } else {
163
+ // System-level installation requires root privileges
138
164
  let test_path = self.service_dir().join(".opencode-cloud-test");
139
165
  if fs::write(&test_path, "").is_err() {
140
166
  return Err(anyhow!(