opencode-cloud 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/README.md CHANGED
@@ -1,185 +1,57 @@
1
- # opencode-cloud
1
+ # opencode-cloud Node.js CLI
2
2
 
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
- [![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)
6
- [![docs.rs](https://docs.rs/opencode-cloud/badge.svg)](https://docs.rs/opencode-cloud)
7
- [![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
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
-
10
- A production-ready toolkit for deploying [opencode](https://github.com/anomalyco/opencode) as a persistent cloud service.
11
-
12
- ## Features
13
-
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)
20
-
21
- ## Requirements
22
-
23
- ### For npm installation
24
-
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`
28
-
29
- ### For cargo installation
30
-
31
- - **Rust 1.82+**
3
+ Cross-platform CLI for opencode-cloud with prebuilt binaries for major platforms.
32
4
 
33
5
  ## Installation
34
6
 
35
- ### Via npm (compiles from source)
36
-
37
- ```bash
38
- npx opencode-cloud --version
39
- ```
40
-
41
- Or install globally:
42
-
43
7
  ```bash
44
8
  npm install -g opencode-cloud
45
- occ --version
46
- ```
47
-
48
- ### Via cargo
49
-
50
- ```bash
51
- cargo install opencode-cloud
52
- opencode-cloud --version
53
- ```
54
-
55
- ### From source
56
-
57
- ```bash
58
- git clone https://github.com/pRizz/opencode-cloud.git
59
- cd opencode-cloud
60
- just build
61
- cargo run -p opencode-cloud -- --version
9
+ # or
10
+ npx opencode-cloud --version
62
11
  ```
63
12
 
64
- ## Usage
65
-
66
- ```bash
67
- # Show version
68
- occ --version
69
-
70
- # Start the service (builds image on first run)
71
- occ start
72
-
73
- # Start on a custom port
74
- occ start --port 8080
75
-
76
- # Start and open browser
77
- occ start --open
13
+ No Rust toolchain required — npm automatically downloads the correct binary for your platform.
78
14
 
79
- # Check service status
80
- occ status
81
-
82
- # View logs
83
- occ logs
84
-
85
- # Follow logs in real-time
86
- occ logs -f
87
-
88
- # Stop the service
89
- occ stop
15
+ ## Supported Platforms
90
16
 
91
- # Restart the service
92
- occ restart
17
+ | Platform | Architecture | Package |
18
+ |----------|--------------|---------|
19
+ | macOS | Apple Silicon (arm64) | @opencode-cloud/cli-node-darwin-arm64 |
20
+ | macOS | Intel (x64) | @opencode-cloud/cli-node-darwin-x64 |
21
+ | Linux | x64 (glibc) | @opencode-cloud/cli-node-linux-x64 |
22
+ | Linux | ARM64 (glibc) | @opencode-cloud/cli-node-linux-arm64 |
23
+ | Linux | x64 (musl/Alpine) | @opencode-cloud/cli-node-linux-x64-musl |
24
+ | Linux | ARM64 (musl/Alpine) | @opencode-cloud/cli-node-linux-arm64-musl |
93
25
 
94
- # Install as a system service (starts on login/boot)
95
- occ install
26
+ Windows support planned for a future release.
96
27
 
97
- # Uninstall the system service
98
- occ uninstall
28
+ ## How it works
99
29
 
100
- # View configuration
101
- occ config show
102
- ```
30
+ 1. When you install `opencode-cloud`, npm downloads a platform-specific package based on your OS and architecture
31
+ 2. The main package finds the binary from the platform package
32
+ 3. All CLI invocations spawn the Rust binary with transparent passthrough (stdio: inherit)
33
+ 4. Exit codes, colors, and TTY detection are preserved
103
34
 
104
- ### Rebuilding the Docker Image
35
+ ## Development
105
36
 
106
- When developing locally or after updating opencode-cloud, you may need to rebuild the Docker image to pick up changes in the embedded Dockerfile:
37
+ When developing locally, place the Rust binary in the Node package `bin/` directory:
107
38
 
108
39
  ```bash
109
- # Rebuild using Docker cache (fast - only rebuilds changed layers)
110
- occ start --cached-rebuild
111
-
112
- # Rebuild from scratch without cache (slow - for troubleshooting)
113
- occ start --full-rebuild
40
+ cargo build --release
41
+ cp target/release/occ packages/cli-node/bin/
114
42
  ```
115
43
 
116
- **`--cached-rebuild`** (recommended for most cases):
117
- - Uses Docker layer cache for fast rebuilds
118
- - Only rebuilds layers that changed (e.g., if only the CMD changed, it's nearly instant)
119
- - Stops and removes any existing container before rebuilding
44
+ Then run via `just run` or `node packages/cli-node/dist/index.js <args>`. The wrapper resolves the binary from `bin/` when platform packages are not used.
120
45
 
121
- **`--full-rebuild`** (for troubleshooting):
122
- - Ignores Docker cache and rebuilds everything from scratch
123
- - Takes 10-15 minutes but guarantees a completely fresh image
124
- - Use when cached rebuild doesn't fix issues
125
-
126
- **When to rebuild:**
127
- - After pulling updates to opencode-cloud → use `--cached-rebuild`
128
- - When modifying the Dockerfile during development → use `--cached-rebuild`
129
- - When the container fails to start due to image issues → try `--cached-rebuild` first, then `--full-rebuild`
130
- - When you want a completely fresh environment → use `--full-rebuild`
131
-
132
- ## Configuration
133
-
134
- Configuration is stored at:
135
- - Linux/macOS: `~/.config/opencode-cloud/config.json`
136
-
137
- Data (PID files, etc.) is stored at:
138
- - Linux/macOS: `~/.local/share/opencode-cloud/`
139
-
140
- ## Development
46
+ ## Usage
141
47
 
142
48
  ```bash
143
- # Install dependencies
144
- pnpm install
145
-
146
- # Configure git hooks (once after cloning)
147
- git config core.hooksPath .githooks
148
-
149
- # Build everything
150
- just build
151
-
152
- # Compile and run occ (arguments automatically get passed to the binary)
153
- just run --version
154
-
155
- # Run tests
156
- just test
157
-
158
- # Format and lint
159
- just fmt
160
- just lint
49
+ occ start
50
+ occ status
51
+ occ stop
161
52
  ```
162
53
 
163
- > **Note:** The git hooks automatically sync `README.md` to npm package directories on commit.
164
-
165
- ## Architecture
166
-
167
- 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).
173
-
174
- ### Cargo.toml Sync Requirement
175
-
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.
177
-
178
- When updating package metadata (version, edition, rust-version, etc.), keep both files in sync:
179
- - `Cargo.toml` (workspace root)
180
- - `packages/core/Cargo.toml`
181
-
182
- Use `scripts/set-all-versions.sh <version>` to update versions across all files automatically.
54
+ All commands are identical between the npm and cargo installations.
183
55
 
184
56
  ## License
185
57
 
package/bin/.gitkeep ADDED
File without changes
@@ -0,0 +1,8 @@
1
+ /**
2
+ * CLI Parity Tests
3
+ *
4
+ * Verifies the Node CLI wrapper can successfully invoke all commands from the Rust CLI.
5
+ * Commands are discovered dynamically from `occ --help` to avoid hardcoded lists.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=cli-parity.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-parity.test.d.ts","sourceRoot":"","sources":["../src/cli-parity.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * CLI Parity Tests
3
+ *
4
+ * Verifies the Node CLI wrapper can successfully invoke all commands from the Rust CLI.
5
+ * Commands are discovered dynamically from `occ --help` to avoid hardcoded lists.
6
+ */
7
+ import { execSync } from 'child_process';
8
+ import { describe, it, expect, beforeAll } from 'vitest';
9
+ import { join, resolve } from 'path';
10
+ import { existsSync } from 'fs';
11
+ // Path to the Rust binary (built from workspace)
12
+ const RUST_BINARY_PATH = resolve(__dirname, '../../../target/debug/opencode-cloud');
13
+ // Path where Node CLI expects to find the binary
14
+ const NODE_BIN_DIR = resolve(__dirname, '../bin');
15
+ const NODE_BIN_PATH = join(NODE_BIN_DIR, 'occ');
16
+ // Path to the Node CLI wrapper (built TypeScript)
17
+ const NODE_CLI_PATH = resolve(__dirname, '../dist/index.js');
18
+ /**
19
+ * Parse commands from `occ --help` output
20
+ */
21
+ function discoverCommands() {
22
+ const helpOutput = execSync(`${RUST_BINARY_PATH} --help`, {
23
+ encoding: 'utf-8',
24
+ });
25
+ const lines = helpOutput.split('\n');
26
+ const commandsSection = lines.findIndex((line) => line.trim() === 'Commands:');
27
+ if (commandsSection === -1) {
28
+ throw new Error('Failed to find Commands: section in help output');
29
+ }
30
+ const commands = [];
31
+ // Parse lines after "Commands:" until we hit "Options:"
32
+ for (let i = commandsSection + 1; i < lines.length; i++) {
33
+ const line = lines[i];
34
+ // Stop at Options: section
35
+ if (line.trim() === 'Options:') {
36
+ break;
37
+ }
38
+ // Extract command name (first word after leading whitespace)
39
+ const match = line.match(/^\s+([a-z-]+)\s+/);
40
+ if (match) {
41
+ commands.push(match[1]);
42
+ }
43
+ }
44
+ return commands;
45
+ }
46
+ describe('CLI Parity', () => {
47
+ let commands;
48
+ beforeAll(() => {
49
+ // Ensure Rust binary exists
50
+ if (!existsSync(RUST_BINARY_PATH)) {
51
+ throw new Error(`Rust binary not found at ${RUST_BINARY_PATH}. Run: cargo build -p opencode-cloud`);
52
+ }
53
+ // Ensure Node CLI wrapper is built
54
+ if (!existsSync(NODE_CLI_PATH)) {
55
+ throw new Error(`Node CLI not built at ${NODE_CLI_PATH}. Run: pnpm -C packages/cli-node build`);
56
+ }
57
+ // Copy Rust binary to Node bin directory for passthrough
58
+ execSync(`mkdir -p ${NODE_BIN_DIR}`);
59
+ execSync(`cp ${RUST_BINARY_PATH} ${NODE_BIN_PATH}`);
60
+ // Discover commands dynamically
61
+ commands = discoverCommands();
62
+ });
63
+ it('should discover at least 10 commands', () => {
64
+ expect(commands.length).toBeGreaterThanOrEqual(10);
65
+ });
66
+ it.each([
67
+ 'start',
68
+ 'stop',
69
+ 'restart',
70
+ 'status',
71
+ 'logs',
72
+ 'install',
73
+ 'uninstall',
74
+ 'config',
75
+ 'setup',
76
+ 'user',
77
+ 'mount',
78
+ 'update',
79
+ 'cockpit',
80
+ 'host',
81
+ ])('should discover %s command', (command) => {
82
+ expect(commands).toContain(command);
83
+ });
84
+ describe('Command Passthrough', () => {
85
+ it('should pass --version through Node CLI', () => {
86
+ const output = execSync(`node ${NODE_CLI_PATH} --version`, {
87
+ encoding: 'utf-8',
88
+ }).trim();
89
+ expect(output).toMatch(/^opencode-cloud \d+\.\d+\.\d+$/);
90
+ });
91
+ it('should pass --help through Node CLI', () => {
92
+ const output = execSync(`node ${NODE_CLI_PATH} --help`, {
93
+ encoding: 'utf-8',
94
+ });
95
+ expect(output).toContain('Usage:');
96
+ expect(output).toContain('Commands:');
97
+ expect(output).toContain('Options:');
98
+ });
99
+ it.each([
100
+ 'start --help',
101
+ 'stop --help',
102
+ 'restart --help',
103
+ 'status --help',
104
+ 'logs --help',
105
+ 'install --help',
106
+ 'uninstall --help',
107
+ 'config --help',
108
+ 'setup --help',
109
+ 'user --help',
110
+ 'mount --help',
111
+ 'update --help',
112
+ 'cockpit --help',
113
+ 'host --help',
114
+ ])('should pass "%s" through Node CLI', (commandWithArgs) => {
115
+ const output = execSync(`node ${NODE_CLI_PATH} ${commandWithArgs}`, {
116
+ encoding: 'utf-8',
117
+ });
118
+ // All help outputs should contain "Usage:" and describe the command
119
+ expect(output).toContain('Usage:');
120
+ });
121
+ });
122
+ });
123
+ //# sourceMappingURL=cli-parity.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-parity.test.js","sourceRoot":"","sources":["../src/cli-parity.test.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -2,8 +2,8 @@
2
2
  /**
3
3
  * opencode-cloud Node.js CLI
4
4
  *
5
- * This is a thin wrapper that calls into the Rust core library via NAPI bindings.
6
- * The heavy lifting is done in Rust - this just provides npm/npx distribution.
5
+ * Resolves the platform-specific binary from optionalDependencies,
6
+ * with fallback to local bin/ for development.
7
7
  */
8
8
  export {};
9
9
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -2,47 +2,105 @@
2
2
  /**
3
3
  * opencode-cloud Node.js CLI
4
4
  *
5
- * This is a thin wrapper that calls into the Rust core library via NAPI bindings.
6
- * The heavy lifting is done in Rust - this just provides npm/npx distribution.
5
+ * Resolves the platform-specific binary from optionalDependencies,
6
+ * with fallback to local bin/ for development.
7
7
  */
8
- import { getVersionJs } from "@opencode-cloud/core";
9
- const args = process.argv.slice(2);
10
- function printHelp() {
11
- console.log(`
12
- opencode-cloud - Manage your opencode cloud service
13
-
14
- USAGE:
15
- opencode-cloud [OPTIONS] [COMMAND]
16
-
17
- OPTIONS:
18
- -V, --version Print version information
19
- -h, --help Print help information
20
-
21
- COMMANDS:
22
- (none yet - real commands coming in future phases)
23
-
24
- For more information, see: https://github.com/pRizz/opencode-cloud
25
- `);
8
+ import { spawn, execSync } from 'child_process';
9
+ import { existsSync } from 'fs';
10
+ import { fileURLToPath } from 'url';
11
+ import { dirname, join } from 'path';
12
+ import { createRequire } from 'module';
13
+ const require = createRequire(import.meta.url);
14
+ const scriptDir = dirname(fileURLToPath(import.meta.url));
15
+ /**
16
+ * Detect if running on musl libc (Alpine Linux)
17
+ */
18
+ function isMusl() {
19
+ if (existsSync('/etc/alpine-release')) {
20
+ return true;
21
+ }
22
+ try {
23
+ const out = execSync('ldd --version 2>&1', { encoding: 'utf-8' });
24
+ return out.includes('musl');
25
+ }
26
+ catch {
27
+ return false;
28
+ }
26
29
  }
27
- function printVersion() {
28
- const version = getVersionJs();
29
- console.log(version);
30
+ /**
31
+ * Get the platform package name for the current environment
32
+ */
33
+ function getPlatformPackage() {
34
+ const { platform, arch } = process;
35
+ if (platform === 'darwin') {
36
+ return arch === 'arm64'
37
+ ? '@opencode-cloud/cli-node-darwin-arm64'
38
+ : '@opencode-cloud/cli-node-darwin-x64';
39
+ }
40
+ if (platform === 'linux') {
41
+ const musl = isMusl();
42
+ if (arch === 'x64') {
43
+ return musl
44
+ ? '@opencode-cloud/cli-node-linux-x64-musl'
45
+ : '@opencode-cloud/cli-node-linux-x64';
46
+ }
47
+ if (arch === 'arm64') {
48
+ return musl
49
+ ? '@opencode-cloud/cli-node-linux-arm64-musl'
50
+ : '@opencode-cloud/cli-node-linux-arm64';
51
+ }
52
+ }
53
+ return null;
30
54
  }
31
- function main() {
32
- // Handle --version / -V
33
- if (args.includes("--version") || args.includes("-V")) {
34
- printVersion();
35
- process.exit(0);
36
- }
37
- // Handle --help / -h
38
- if (args.includes("--help") || args.includes("-h") || args.length === 0) {
39
- printHelp();
40
- process.exit(0);
41
- }
42
- // Unknown command
43
- console.error(`Unknown command: ${args.join(" ")}`);
44
- console.error('Run "opencode-cloud --help" for usage information.');
55
+ /**
56
+ * Resolve path to the occ binary
57
+ */
58
+ function resolveBinaryPath() {
59
+ const platformPkg = getPlatformPackage();
60
+ if (platformPkg) {
61
+ try {
62
+ const pkg = require(platformPkg);
63
+ if (pkg.binaryPath && existsSync(pkg.binaryPath)) {
64
+ return pkg.binaryPath;
65
+ }
66
+ }
67
+ catch {
68
+ // Package not installed, try fallback
69
+ }
70
+ }
71
+ const localBinary = join(scriptDir, '..', 'bin', 'occ');
72
+ if (existsSync(localBinary)) {
73
+ return localBinary;
74
+ }
75
+ return null;
76
+ }
77
+ const binaryPath = resolveBinaryPath();
78
+ if (!binaryPath) {
79
+ const platformPkg = getPlatformPackage();
80
+ console.error('Error: Could not find opencode-cloud binary\n');
81
+ console.error(`Platform: ${process.platform} (${process.arch})`);
82
+ if (platformPkg) {
83
+ console.error(`Expected package: ${platformPkg}\n`);
84
+ console.error('This may indicate a failed npm install. Try:');
85
+ console.error(' npm install opencode-cloud\n');
86
+ }
87
+ else {
88
+ console.error('\nYour platform is not supported with prebuilt binaries.');
89
+ console.error('Install the Rust CLI directly:');
90
+ console.error(' cargo install opencode-cloud\n');
91
+ }
45
92
  process.exit(1);
46
93
  }
47
- main();
94
+ const child = spawn(binaryPath, process.argv.slice(2), {
95
+ stdio: 'inherit',
96
+ });
97
+ child.on('close', (code) => {
98
+ process.exit(code ?? 1);
99
+ });
100
+ child.on('error', (err) => {
101
+ console.error(`Error: Failed to spawn binary at ${binaryPath}`);
102
+ console.error(`Error: ${err.message}\n`);
103
+ console.error('Try reinstalling: npm install opencode-cloud');
104
+ process.exit(1);
105
+ });
48
106
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEpD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;CAcb,CAAC,CAAC;AACH,CAAC;AAED,SAAS,YAAY;IACnB,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACvB,CAAC;AAED,SAAS,IAAI;IACX,wBAAwB;IACxB,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,YAAY,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,qBAAqB;IACrB,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxE,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,kBAAkB;IAClB,OAAO,CAAC,KAAK,CAAC,oBAAoB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACpD,OAAO,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "opencode-cloud",
3
- "version": "1.0.8",
4
- "description": "CLI for managing opencode as a persistent cloud service",
3
+ "version": "3.0.15",
4
+ "description": "Cross-platform CLI for opencode-cloud (includes prebuilt binaries)",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": "pRizz",
@@ -26,6 +26,10 @@
26
26
  "opencode-cloud": "./dist/index.js",
27
27
  "occ": "./dist/index.js"
28
28
  },
29
+ "files": [
30
+ "dist",
31
+ "bin"
32
+ ],
29
33
  "engines": {
30
34
  "node": ">=20.0.0"
31
35
  },
@@ -37,15 +41,23 @@
37
41
  "x64",
38
42
  "arm64"
39
43
  ],
40
- "dependencies": {
41
- "@opencode-cloud/core": "1.0.8"
44
+ "optionalDependencies": {
45
+ "@opencode-cloud/cli-node-darwin-arm64": "3.0.0",
46
+ "@opencode-cloud/cli-node-linux-arm64": "3.0.0",
47
+ "@opencode-cloud/cli-node-darwin-x64": "3.0.0",
48
+ "@opencode-cloud/cli-node-linux-x64": "3.0.0",
49
+ "@opencode-cloud/cli-node-linux-arm64-musl": "3.0.0",
50
+ "@opencode-cloud/cli-node-linux-x64-musl": "3.0.0"
42
51
  },
43
52
  "devDependencies": {
44
53
  "typescript": "^5.7.3",
45
- "@types/node": "^22.10.7"
54
+ "@types/node": "^22.10.7",
55
+ "vitest": "^3.0.0"
46
56
  },
47
57
  "scripts": {
48
58
  "build": "tsc || (echo \"Error: TypeScript compiler (tsc) not found. Install dev dependencies or run npm i -D typescript before building.\" && exit 1)",
49
- "start": "node dist/index.js"
59
+ "start": "node dist/index.js",
60
+ "test": "vitest run",
61
+ "test:watch": "vitest"
50
62
  }
51
63
  }
package/src/index.ts DELETED
@@ -1,55 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * opencode-cloud Node.js CLI
4
- *
5
- * This is a thin wrapper that calls into the Rust core library via NAPI bindings.
6
- * The heavy lifting is done in Rust - this just provides npm/npx distribution.
7
- */
8
-
9
- import { getVersionJs } from "@opencode-cloud/core";
10
-
11
- const args = process.argv.slice(2);
12
-
13
- function printHelp(): void {
14
- console.log(`
15
- opencode-cloud - Manage your opencode cloud service
16
-
17
- USAGE:
18
- opencode-cloud [OPTIONS] [COMMAND]
19
-
20
- OPTIONS:
21
- -V, --version Print version information
22
- -h, --help Print help information
23
-
24
- COMMANDS:
25
- (none yet - real commands coming in future phases)
26
-
27
- For more information, see: https://github.com/pRizz/opencode-cloud
28
- `);
29
- }
30
-
31
- function printVersion(): void {
32
- const version = getVersionJs();
33
- console.log(version);
34
- }
35
-
36
- function main(): void {
37
- // Handle --version / -V
38
- if (args.includes("--version") || args.includes("-V")) {
39
- printVersion();
40
- process.exit(0);
41
- }
42
-
43
- // Handle --help / -h
44
- if (args.includes("--help") || args.includes("-h") || args.length === 0) {
45
- printHelp();
46
- process.exit(0);
47
- }
48
-
49
- // Unknown command
50
- console.error(`Unknown command: ${args.join(" ")}`);
51
- console.error('Run "opencode-cloud --help" for usage information.');
52
- process.exit(1);
53
- }
54
-
55
- main();
package/tsconfig.json DELETED
@@ -1,18 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ESNext",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "outDir": "./dist",
7
- "rootDir": "./src",
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true,
11
- "forceConsistentCasingInFileNames": true,
12
- "declaration": true,
13
- "declarationMap": true,
14
- "sourceMap": true
15
- },
16
- "include": ["src/**/*"],
17
- "exclude": ["node_modules", "dist"]
18
- }