@opencode-cloud/core 3.2.1 → 3.2.3

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 = "3.2.1"
3
+ version = "3.2.3"
4
4
  edition = "2024"
5
5
  rust-version = "1.88"
6
6
  license = "MIT"
package/README.md CHANGED
@@ -17,6 +17,15 @@ cargo install opencode-cloud
17
17
  opencode-cloud --version
18
18
  ```
19
19
 
20
+ ## Deploy to AWS
21
+
22
+ [![Deploy to AWS](https://s3.amazonaws.com/cloudformation-examples/cloudformation-launch-stack.png)](https://console.aws.amazon.com/cloudformation/home#/stacks/create/review?templateURL=https://raw.githubusercontent.com/pRizz/opencode-cloud/main/infra/aws/cloudformation/opencode-cloud-quick.yaml)
23
+
24
+ Quick deploy provisions a private EC2 instance behind a public ALB with HTTPS.
25
+ **A domain name is required** for ACM certificate validation.
26
+
27
+ Docs: `docs/deploy/aws.md` (includes teardown steps)
28
+
20
29
  ## Features
21
30
 
22
31
  - **Sandboxed execution** - opencode runs inside a Docker container, isolated from your host system
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencode-cloud/core",
3
- "version": "3.2.1",
3
+ "version": "3.2.3",
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
@@ -15,7 +15,7 @@ use anyhow::{Context, Result};
15
15
  use jsonc_parser::parse_to_serde_value;
16
16
 
17
17
  pub use paths::{get_config_dir, get_config_path, get_data_dir, get_hosts_path, get_pid_path};
18
- pub use schema::{CommitSha, Config, validate_bind_address};
18
+ pub use schema::{Config, validate_bind_address};
19
19
  pub use validation::{
20
20
  ValidationError, ValidationWarning, display_validation_error, display_validation_warning,
21
21
  validate_config,
@@ -88,10 +88,15 @@ pub fn load_config() -> Result<Config> {
88
88
  .with_context(|| format!("Failed to read config file: {}", config_path.display()))?;
89
89
 
90
90
  // Parse JSONC (JSON with comments)
91
- let parsed_value = parse_to_serde_value(&contents, &Default::default())
91
+ let mut parsed_value = parse_to_serde_value(&contents, &Default::default())
92
92
  .map_err(|e| anyhow::anyhow!("Invalid JSONC in config file: {e}"))?
93
93
  .ok_or_else(|| anyhow::anyhow!("Config file is empty"))?;
94
94
 
95
+ // Drop deprecated keys that were removed from the schema.
96
+ if let Some(obj) = parsed_value.as_object_mut() {
97
+ obj.remove("opencode_commit");
98
+ }
99
+
95
100
  // Deserialize into Config struct (deny_unknown_fields will reject unknown keys)
96
101
  let config: Config = serde_json::from_value(parsed_value).with_context(|| {
97
102
  format!(
@@ -4,51 +4,6 @@
4
4
 
5
5
  use serde::{Deserialize, Serialize};
6
6
  use std::net::{IpAddr, Ipv4Addr};
7
- use std::ops::Deref;
8
-
9
- /// Validated opencode commit SHA (7-40 hex characters)
10
- #[derive(Debug, Clone, Serialize, PartialEq, Eq)]
11
- #[serde(transparent)]
12
- pub struct CommitSha(String);
13
-
14
- impl CommitSha {
15
- pub fn parse(value: &str) -> Result<Self, String> {
16
- let trimmed = value.trim();
17
- if trimmed.is_empty() {
18
- return Err("Commit cannot be empty".to_string());
19
- }
20
- if !(7..=40).contains(&trimmed.len()) {
21
- return Err("Commit must be 7-40 hex characters".to_string());
22
- }
23
- if !trimmed.chars().all(|c| c.is_ascii_hexdigit()) {
24
- return Err("Commit must be a hexadecimal SHA".to_string());
25
- }
26
- Ok(Self(trimmed.to_string()))
27
- }
28
-
29
- pub fn as_str(&self) -> &str {
30
- &self.0
31
- }
32
- }
33
-
34
- impl Deref for CommitSha {
35
- type Target = str;
36
-
37
- fn deref(&self) -> &Self::Target {
38
- self.as_str()
39
- }
40
- }
41
-
42
- impl<'de> Deserialize<'de> for CommitSha {
43
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
44
- where
45
- D: serde::Deserializer<'de>,
46
- {
47
- let value = String::deserialize(deserializer)?;
48
- CommitSha::parse(&value).map_err(serde::de::Error::custom)
49
- }
50
- }
51
-
52
7
  /// Main configuration structure for opencode-cloud
53
8
  ///
54
9
  /// Serialized to/from `~/.config/opencode-cloud/config.json`
@@ -156,11 +111,6 @@ pub struct Config {
156
111
  #[serde(default = "default_image_source")]
157
112
  pub image_source: String,
158
113
 
159
- /// Override opencode commit used when building the Docker image (optional)
160
- /// Must be a 7-40 character hex commit SHA.
161
- #[serde(default)]
162
- pub opencode_commit: Option<CommitSha>,
163
-
164
114
  /// When to check for updates: 'always' (every start), 'once' (once per version), 'never'
165
115
  #[serde(default = "default_update_check")]
166
116
  pub update_check: String,
@@ -274,7 +224,6 @@ impl Default for Config {
274
224
  cockpit_port: default_cockpit_port(),
275
225
  cockpit_enabled: default_cockpit_enabled(),
276
226
  image_source: default_image_source(),
277
- opencode_commit: None,
278
227
  update_check: default_update_check(),
279
228
  mounts: Vec::new(),
280
229
  }
@@ -416,7 +365,6 @@ mod tests {
416
365
  cockpit_port: 9090,
417
366
  cockpit_enabled: true,
418
367
  image_source: default_image_source(),
419
- opencode_commit: None,
420
368
  update_check: default_update_check(),
421
369
  mounts: Vec::new(),
422
370
  };
@@ -34,9 +34,6 @@
34
34
  # -----------------------------------------------------------------------------
35
35
  FROM ubuntu:24.04 AS runtime
36
36
 
37
- # Pin opencode fork commit used during build
38
- ARG OPENCODE_COMMIT=dac099a4892689d11abedb0fcc1098b50e0958c8
39
-
40
37
  # OCI Labels for image metadata
41
38
  LABEL org.opencontainers.image.title="opencode-cloud"
42
39
  LABEL org.opencontainers.image.description="AI-assisted development environment with opencode"
@@ -520,7 +517,8 @@ RUN echo 'export PATH="/home/opencode/.local/bin:$PATH"' >> /home/opencode/.zshr
520
517
  # Clone the fork and build opencode from source (as non-root user)
521
518
  # Pin to specific commit for reproducibility
522
519
  # Build opencode from source (BuildKit cache mounts disabled for now)
523
- RUN rm -rf /tmp/opencode-repo \
520
+ RUN OPENCODE_COMMIT="8694cc2e60422ad82d5ca72b67716423b18dabc2" \
521
+ && rm -rf /tmp/opencode-repo \
524
522
  && git clone --depth 1 https://github.com/pRizz/opencode.git /tmp/opencode-repo \
525
523
  && cd /tmp/opencode-repo \
526
524
  && git fetch --depth 1 origin "${OPENCODE_COMMIT}" \
@@ -573,21 +571,31 @@ RUN ls -la /usr/local/bin/opencode-broker \
573
571
  # -----------------------------------------------------------------------------
574
572
  # Nginx Reverse Proxy for UI + API
575
573
  # -----------------------------------------------------------------------------
576
- # Serve the built UI from /var/www/opencode and proxy API/WebSocket
577
- # TODO: Explore a sustainable routing strategy (e.g., backend-driven base URL or
578
- # TODO: content-type aware proxying without hardcoded path lists).
574
+ # Serve the built UI from /var/www/opencode and proxy all 3000 traffic to backend.
579
575
  RUN rm -f /etc/nginx/sites-enabled/default /etc/nginx/conf.d/default.conf 2>/dev/null || true \
580
576
  && printf '%s\n' \
581
577
  'server {' \
582
578
  ' listen 3000;' \
583
579
  ' server_name _;' \
584
580
  '' \
585
- ' root /var/www/opencode;' \
586
- ' index index.html;' \
587
- '' \
588
- ' location = /health {' \
581
+ ' location / {' \
589
582
  ' proxy_pass http://127.0.0.1:3001;' \
583
+ ' proxy_http_version 1.1;' \
584
+ ' proxy_set_header Upgrade $http_upgrade;' \
585
+ ' proxy_set_header Connection "upgrade";' \
586
+ ' proxy_set_header Host $host;' \
587
+ ' proxy_set_header X-Real-IP $remote_addr;' \
588
+ ' proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;' \
589
+ ' proxy_set_header X-Forwarded-Proto $scheme;' \
590
590
  ' }' \
591
+ '}' \
592
+ '' \
593
+ 'server {' \
594
+ ' listen 3002;' \
595
+ ' server_name _;' \
596
+ '' \
597
+ ' root /var/www/opencode;' \
598
+ ' index index.html;' \
591
599
  '' \
592
600
  ' location /assets/ {' \
593
601
  ' try_files $uri =404;' \
@@ -597,17 +605,6 @@ RUN rm -f /etc/nginx/sites-enabled/default /etc/nginx/conf.d/default.conf 2>/dev
597
605
  ' try_files $uri =404;' \
598
606
  ' }' \
599
607
  '' \
600
- ' location ~ ^/(agent|auth|command|config|event|events|global|lsp|mcp|path|permission|project|provider|pty|question|rpc|session|sessions|status|v1|vcs|ws|api) {' \
601
- ' proxy_pass http://127.0.0.1:3001;' \
602
- ' proxy_http_version 1.1;' \
603
- ' proxy_set_header Upgrade $http_upgrade;' \
604
- ' proxy_set_header Connection "upgrade";' \
605
- ' proxy_set_header Host $host;' \
606
- ' proxy_set_header X-Real-IP $remote_addr;' \
607
- ' proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;' \
608
- ' proxy_set_header X-Forwarded-Proto $scheme;' \
609
- ' }' \
610
- '' \
611
608
  ' location / {' \
612
609
  ' try_files $uri $uri/ /index.html;' \
613
610
  ' }' \
@@ -746,20 +743,24 @@ RUN rm -f /etc/systemd/system/multi-user.target.wants/nginx.service \
746
743
  # -----------------------------------------------------------------------------
747
744
  # opencode Configuration
748
745
  # -----------------------------------------------------------------------------
749
- # Create opencode.json config file with PAM authentication enabled
746
+ # Create opencode.jsonc config file with PAM authentication enabled and UI URL
750
747
  RUN mkdir -p /home/opencode/.config/opencode \
751
748
  && printf '%s\n' \
752
749
  '{' \
750
+ ' // Container UI served via nginx on 3002' \
753
751
  ' "auth": {' \
754
752
  ' "enabled": true' \
753
+ ' },' \
754
+ ' "server": {' \
755
+ ' "uiUrl": "http://localhost:3002"' \
755
756
  ' }' \
756
757
  '}' \
757
- > /home/opencode/.config/opencode/opencode.json \
758
+ > /home/opencode/.config/opencode/opencode.jsonc \
758
759
  && chown -R opencode:opencode /home/opencode/.config/opencode \
759
- && chmod 644 /home/opencode/.config/opencode/opencode.json
760
+ && chmod 644 /home/opencode/.config/opencode/opencode.jsonc
760
761
 
761
762
  # Verify config file exists
762
- RUN ls -la /home/opencode/.config/opencode/opencode.json && cat /home/opencode/.config/opencode/opencode.json
763
+ RUN ls -la /home/opencode/.config/opencode/opencode.jsonc && cat /home/opencode/.config/opencode/opencode.jsonc
763
764
 
764
765
  USER opencode
765
766
 
@@ -811,8 +812,8 @@ RUN echo "${OPENCODE_CLOUD_VERSION}" > /etc/opencode-cloud-version
811
812
  # -----------------------------------------------------------------------------
812
813
  WORKDIR /home/opencode/workspace
813
814
 
814
- # Expose opencode web port (3000) and Cockpit port (9090)
815
- EXPOSE 3000 9090
815
+ # Expose opencode ports (3000/3001/3002) and Cockpit (9090)
816
+ EXPOSE 3000 3001 3002 9090
816
817
 
817
818
  # Hybrid init: entrypoint script chooses tini or systemd based on USE_SYSTEMD env
818
819
  ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
@@ -28,10 +28,10 @@ docker pull ghcr.io/prizz/opencode-cloud-sandbox:latest
28
28
  Run the container:
29
29
 
30
30
  ```
31
- docker run --rm -it -p 3000:3000 -p 9090:9090 ghcr.io/prizz/opencode-cloud-sandbox:latest
31
+ docker run --rm -it -p 3000:3000 -p 3001:3001 -p 3002:3002 -p 9090:9090 ghcr.io/prizz/opencode-cloud-sandbox:latest
32
32
  ```
33
33
 
34
- The opencode web UI is available at `http://localhost:3000`. Cockpit runs on `http://localhost:9090`.
34
+ The opencode web UI is available at `http://localhost:3000`. The backend is reachable at `http://localhost:3001`, and the static UI is served at `http://localhost:3002`. Cockpit runs on `http://localhost:9090`.
35
35
 
36
36
  ## Source
37
37
 
@@ -7,27 +7,9 @@
7
7
  //! clearly indicate this is the sandboxed container environment that the
8
8
  //! opencode-cloud CLI deploys, not the CLI tool itself.
9
9
 
10
- use std::collections::HashMap;
11
-
12
10
  /// The Dockerfile for building the opencode-cloud-sandbox container image
13
11
  pub const DOCKERFILE: &str = include_str!("Dockerfile");
14
12
 
15
- /// Build arg name for the opencode commit used in the Dockerfile.
16
- pub const OPENCODE_COMMIT_BUILD_ARG: &str = "OPENCODE_COMMIT";
17
-
18
- /// Default opencode commit pinned in the Dockerfile.
19
- pub const OPENCODE_COMMIT_DEFAULT: &str = "dac099a4892689d11abedb0fcc1098b50e0958c8";
20
-
21
- /// Build args for overriding the opencode commit in the Dockerfile.
22
- pub fn build_args_for_opencode_commit(
23
- maybe_commit: Option<&str>,
24
- ) -> Option<HashMap<String, String>> {
25
- let commit = maybe_commit?;
26
- let mut args = HashMap::new();
27
- args.insert(OPENCODE_COMMIT_BUILD_ARG.to_string(), commit.to_string());
28
- Some(args)
29
- }
30
-
31
13
  // =============================================================================
32
14
  // Docker Image Naming
33
15
  // =============================================================================
package/src/docker/mod.rs CHANGED
@@ -38,10 +38,7 @@ pub use health::{
38
38
  };
39
39
 
40
40
  // Dockerfile constants
41
- pub use dockerfile::{
42
- DOCKERFILE, IMAGE_NAME_DOCKERHUB, IMAGE_NAME_GHCR, IMAGE_TAG_DEFAULT,
43
- OPENCODE_COMMIT_BUILD_ARG, OPENCODE_COMMIT_DEFAULT, build_args_for_opencode_commit,
44
- };
41
+ pub use dockerfile::{DOCKERFILE, IMAGE_NAME_DOCKERHUB, IMAGE_NAME_GHCR, IMAGE_TAG_DEFAULT};
45
42
 
46
43
  // Image operations
47
44
  pub use image::{build_image, image_exists, pull_image};