oceancode 0.1.2 → 0.1.4

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 oceancode
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2025 opencode
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/NOTICE ADDED
@@ -0,0 +1,9 @@
1
+ OceanCode
2
+ Copyright (c) 2026 OceanCode contributors
3
+
4
+ This product includes software derived from OpenCode, Copyright (c) 2025 opencode,
5
+ licensed under the MIT License. The original MIT license text is included in the
6
+ LICENSE file in this repository.
7
+
8
+ OceanCode is an independent project and is not affiliated with or endorsed by
9
+ the OpenCode project or its maintainers.
package/README.md CHANGED
@@ -1,42 +1,118 @@
1
- # OceanCode 🌊
2
-
3
- Next-generation CLI coding assistant powered by the OpenCode server backend.
4
-
5
- ## Install
6
-
7
- Requires **Node.js 18+**.
8
-
9
- ```bash
10
- npm install -g oceancode
11
- ```
12
-
13
- This installs two commands — `oceancode` and its short alias `ocean` — plus the
14
- `opencode` backend binary (via the `opencode-ai` dependency), which the CLI
15
- manages automatically on first run. No other setup needed.
16
-
17
- ## Usage
18
-
19
- ```bash
20
- oceancode # launch interactive chat
21
- ocean # same thing, shorter
22
- oceancode run "explain this repo and fix the failing build"
23
- oceancode run "add tests for the parser" -m gpt-4o --agent build
24
- ```
25
-
26
- Slash commands inside interactive mode: `/init` `/goal` `/new` `/undo` `/redo`
27
- `/models` `/connect` `/mcp` `/diff` `/agent` `/compact` `/clear` `/info` `/help` `/exit`
28
-
29
- ## How it works
30
-
31
- On startup the CLI spawns a local `opencode serve` backend (isolated on port
32
- 4196 with its own config under `~/.config/oceancode`) and talks to it over HTTP/SSE.
33
-
34
- ## Uninstall
35
-
36
- ```bash
37
- npm uninstall -g oceancode
38
- ```
39
-
40
- ## License
41
-
42
- MIT
1
+ <p align="center">
2
+ <a href="https://github.com/ianimatethings12-stack/oceancode">
3
+ <picture>
4
+ <source srcset="packages/web/src/assets/oceancode-logo-dark.svg" media="(prefers-color-scheme: dark)">
5
+ <source srcset="packages/web/src/assets/oceancode-logo-light.svg" media="(prefers-color-scheme: light)">
6
+ <img src="packages/web/src/assets/oceancode-logo-light.svg" alt="OceanCode logo">
7
+ </picture>
8
+ </a>
9
+ </p>
10
+ <p align="center">The open source AI coding agent.</p>
11
+ <p align="center">
12
+ <a href="https://github.com/ianimatethings12-stack/oceancode/discussions"><img alt="Discord" src="https://img.shields.io/discord/1391832426048651334?style=flat-square&label=discord" /></a>
13
+ <a href="https://www.npmjs.com/package/oceancode"><img alt="npm" src="https://img.shields.io/npm/v/oceancode?style=flat-square" /></a>
14
+ <a href="https://github.com/ianimatethings12-stack/oceancode/actions/workflows/publish.yml"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/ianimatethings12-stack/oceancode/publish.yml?style=flat-square&branch=dev" /></a>
15
+ </p>
16
+
17
+ <p align="center">
18
+ <a href="README.md">English</a> |
19
+ <a href="README.zh.md">简体中文</a> |
20
+ <a href="README.zht.md">繁體中文</a> |
21
+ <a href="README.ko.md">한국어</a> |
22
+ <a href="README.de.md">Deutsch</a> |
23
+ <a href="README.es.md">Español</a> |
24
+ <a href="README.fr.md">Français</a> |
25
+ <a href="README.it.md">Italiano</a> |
26
+ <a href="README.da.md">Dansk</a> |
27
+ <a href="README.ja.md">日本語</a> |
28
+ <a href="README.pl.md">Polski</a> |
29
+ <a href="README.ru.md">Русский</a> |
30
+ <a href="README.bs.md">Bosanski</a> |
31
+ <a href="README.ar.md">العربية</a> |
32
+ <a href="README.no.md">Norsk</a> |
33
+ <a href="README.br.md">Português (Brasil)</a> |
34
+ <a href="README.th.md">ไทย</a> |
35
+ <a href="README.tr.md">Türkçe</a> |
36
+ <a href="README.uk.md">Українська</a> |
37
+ <a href="README.bn.md">বাংলা</a> |
38
+ <a href="README.gr.md">Ελληνικά</a> |
39
+ <a href="README.vi.md">Tiếng Việt</a>
40
+ </p>
41
+
42
+ [![OceanCode Terminal UI](packages/web/src/assets/lander/screenshot.png)](https://github.com/ianimatethings12-stack/oceancode)
43
+
44
+ ---
45
+
46
+ ### Installation
47
+
48
+ ```bash
49
+ # Install script
50
+ curl -fsSL https://raw.githubusercontent.com/ianimatethings12-stack/oceancode/dev/install | bash
51
+
52
+ # Package managers
53
+ npm install -g oceancode@latest
54
+ bun add -g oceancode@latest
55
+ pnpm add -g oceancode@latest
56
+ yarn global add oceancode@latest
57
+ ```
58
+
59
+ > [!TIP]
60
+ > Remove versions older than 0.1.x before installing.
61
+
62
+ ### Desktop App (BETA)
63
+
64
+ OceanCode is also available as a desktop application. Download the unsigned v0.1 build from the [releases page](https://github.com/ianimatethings12-stack/oceancode/releases).
65
+
66
+ | Platform | Download |
67
+ | --------------------- | ----------------------------------------- |
68
+ | macOS (Apple Silicon) | `oceancode-desktop-mac-arm64.dmg` |
69
+ | Windows | `oceancode-desktop-windows-x64.exe` |
70
+ | Linux | `oceancode-desktop-linux-x64.AppImage` |
71
+
72
+ v0.1 desktop builds are unsigned and macOS Intel builds are not yet available. macOS may require right-click → Open, and Windows may show a SmartScreen warning.
73
+
74
+ #### Installation Directory
75
+
76
+ The install script respects the following priority order for the installation path:
77
+
78
+ 1. `$OCEANCODE_INSTALL_DIR` - Custom installation directory
79
+ 2. `$XDG_BIN_DIR` - XDG Base Directory Specification compliant path
80
+ 3. `$HOME/bin` - Standard user binary directory (if it exists or can be created)
81
+ 4. `$HOME/.oceancode/bin` - Default fallback
82
+
83
+ ```bash
84
+ # Examples
85
+ OCEANCODE_INSTALL_DIR=/usr/local/bin curl -fsSL https://raw.githubusercontent.com/ianimatethings12-stack/oceancode/dev/install | bash
86
+ XDG_BIN_DIR=$HOME/.local/bin curl -fsSL https://raw.githubusercontent.com/ianimatethings12-stack/oceancode/dev/install | bash
87
+ ```
88
+
89
+ ### Agents
90
+
91
+ OceanCode includes two built-in agents you can switch between with the `Tab` key.
92
+
93
+ - **build** - Default, full-access agent for development work
94
+ - **plan** - Read-only agent for analysis and code exploration
95
+ - Denies file edits by default
96
+ - Asks permission before running bash commands
97
+ - Ideal for exploring unfamiliar codebases or planning changes
98
+
99
+ Also included is a **general** subagent for complex searches and multistep tasks.
100
+ This is used internally and can be invoked using `@general` in messages.
101
+
102
+ Learn more about [agents](https://github.com/ianimatethings12-stack/oceancode/tree/dev/packages/web/src/content/docs/agents).
103
+
104
+ ### Documentation
105
+
106
+ For more info on how to configure OceanCode, [**head over to our docs**](https://github.com/ianimatethings12-stack/oceancode/tree/dev/packages/web/src/content/docs).
107
+
108
+ ### Contributing
109
+
110
+ If you're interested in contributing to OceanCode, please read our [contributing docs](./CONTRIBUTING.md) before submitting a pull request.
111
+
112
+ ### Building on OceanCode
113
+
114
+ If you maintain a third-party project with "oceancode" in its name, for example "oceancode-dashboard" or "oceancode-mobile", please add a note to your README to clarify that it is not built by the OceanCode team and is not affiliated with us in any way.
115
+
116
+ ---
117
+
118
+ **Join our community** [Discord](https://github.com/ianimatethings12-stack/oceancode/discussions) | [X.com](https://github.com/ianimatethings12-stack/oceancode)
package/bin/oceancode ADDED
@@ -0,0 +1,254 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { createRequire } from "node:module"
4
+ import { fileURLToPath } from "node:url"
5
+
6
+ const require = createRequire(import.meta.url)
7
+ const __filename = fileURLToPath(import.meta.url)
8
+
9
+ const childProcess = require("child_process")
10
+ const fs = require("fs")
11
+ const path = require("path")
12
+ const os = require("os")
13
+
14
+ const forwardedSignals = ["SIGINT", "SIGTERM", "SIGHUP"]
15
+
16
+ function run(target) {
17
+ const child = childProcess.spawn(target, process.argv.slice(2), {
18
+ stdio: "inherit",
19
+ })
20
+
21
+ child.on("error", (error) => {
22
+ console.error(error.message)
23
+ process.exit(1)
24
+ })
25
+
26
+ const forwarders = {}
27
+ for (const signal of forwardedSignals) {
28
+ forwarders[signal] = () => {
29
+ try {
30
+ child.kill(signal)
31
+ } catch {
32
+ // The child may have already exited.
33
+ }
34
+ }
35
+ process.on(signal, forwarders[signal])
36
+ }
37
+
38
+ child.on("exit", (code, signal) => {
39
+ for (const forwardedSignal of forwardedSignals) {
40
+ process.removeListener(forwardedSignal, forwarders[forwardedSignal])
41
+ }
42
+
43
+ if (signal) {
44
+ process.kill(process.pid, signal)
45
+ return
46
+ }
47
+
48
+ process.exit(typeof code === "number" ? code : 0)
49
+ })
50
+ }
51
+
52
+ const envPath = process.env.OCEANCODE_BIN_PATH || process.env.OCEAN_BIN_PATH || process.env.OPENCODE_BIN_PATH
53
+
54
+ const scriptPath = fs.realpathSync(__filename)
55
+ const scriptDir = path.dirname(scriptPath)
56
+
57
+ const cached = path.join(scriptDir, ".oceancode")
58
+ const legacyCached = [path.join(scriptDir, ".ocean"), path.join(scriptDir, ".opencode")]
59
+
60
+ const platformMap = {
61
+ darwin: "darwin",
62
+ linux: "linux",
63
+ win32: "windows",
64
+ }
65
+ const archMap = {
66
+ x64: "x64",
67
+ arm64: "arm64",
68
+ arm: "arm",
69
+ }
70
+
71
+ let platform = platformMap[os.platform()]
72
+ if (!platform) {
73
+ platform = os.platform()
74
+ }
75
+ let arch = archMap[os.arch()]
76
+ if (!arch) {
77
+ arch = os.arch()
78
+ }
79
+ const base = "oceancode-" + platform + "-" + arch
80
+ const binary = platform === "windows" ? "oceancode.exe" : "oceancode"
81
+
82
+ function supportsAvx2() {
83
+ if (arch !== "x64") return false
84
+
85
+ if (platform === "linux") {
86
+ try {
87
+ return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
88
+ } catch {
89
+ return false
90
+ }
91
+ }
92
+
93
+ if (platform === "darwin") {
94
+ try {
95
+ const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
96
+ encoding: "utf8",
97
+ timeout: 1500,
98
+ })
99
+ if (result.status !== 0) return false
100
+ return (result.stdout || "").trim() === "1"
101
+ } catch {
102
+ return false
103
+ }
104
+ }
105
+
106
+ if (platform === "windows") {
107
+ const cmd =
108
+ '(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
109
+
110
+ for (const exe of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
111
+ try {
112
+ const result = childProcess.spawnSync(exe, ["-NoProfile", "-NonInteractive", "-Command", cmd], {
113
+ encoding: "utf8",
114
+ timeout: 3000,
115
+ windowsHide: true,
116
+ })
117
+ if (result.status !== 0) continue
118
+ const out = (result.stdout || "").trim().toLowerCase()
119
+ if (out === "true" || out === "1") return true
120
+ if (out === "false" || out === "0") return false
121
+ } catch {
122
+ continue
123
+ }
124
+ }
125
+
126
+ return false
127
+ }
128
+
129
+ return false
130
+ }
131
+
132
+ const names = (() => {
133
+ const avx2 = supportsAvx2()
134
+ const baseline = arch === "x64" && !avx2
135
+
136
+ if (platform === "linux") {
137
+ const musl = (() => {
138
+ try {
139
+ if (fs.existsSync("/etc/alpine-release")) return true
140
+ } catch {
141
+ // ignore
142
+ }
143
+
144
+ try {
145
+ const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
146
+ const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
147
+ if (text.includes("musl")) return true
148
+ } catch {
149
+ // ignore
150
+ }
151
+
152
+ return false
153
+ })()
154
+
155
+ if (musl) {
156
+ if (arch === "x64") {
157
+ if (baseline) return [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
158
+ return [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
159
+ }
160
+ return [`${base}-musl`, base]
161
+ }
162
+
163
+ if (arch === "x64") {
164
+ if (baseline) return [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
165
+ return [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
166
+ }
167
+ return [base, `${base}-musl`]
168
+ }
169
+
170
+ if (arch === "x64") {
171
+ if (baseline) return [`${base}-baseline`, base]
172
+ return [base, `${base}-baseline`]
173
+ }
174
+ return [base]
175
+ })()
176
+
177
+ function findBinary(startDir) {
178
+ let current = startDir
179
+ for (;;) {
180
+ const modules = path.join(current, "node_modules")
181
+ if (fs.existsSync(modules)) {
182
+ for (const name of names) {
183
+ for (const candidateName of [name, name.replace(/^oceancode-/, "ocean-"), name.replace(/^oceancode-/, "opencode-")]) {
184
+ for (const candidateBinary of [binary, platform === "windows" ? "ocean.exe" : "ocean", platform === "windows" ? "opencode.exe" : "opencode"]) {
185
+ const candidate = path.join(modules, candidateName, "bin", candidateBinary)
186
+ if (fs.existsSync(candidate)) return candidate
187
+ }
188
+ }
189
+ }
190
+ }
191
+ const parent = path.dirname(current)
192
+ if (parent === current) {
193
+ return
194
+ }
195
+ current = parent
196
+ }
197
+ }
198
+
199
+ function findBun() {
200
+ const candidates = [
201
+ process.env.BUN_INSTALL ? path.join(process.env.BUN_INSTALL, "bin", process.platform === "windows" ? "bun.exe" : "bun") : null,
202
+ process.env.APPDATA ? path.join(process.env.APPDATA, "npm", "node_modules", "bun", "bin", "bun.exe") : null,
203
+ path.join(os.homedir(), ".bun", "bin", process.platform === "windows" ? "bun.exe" : "bun"),
204
+ ].filter(Boolean)
205
+
206
+ for (const c of candidates) {
207
+ if (fs.existsSync(c)) return c
208
+ }
209
+
210
+ try {
211
+ const out = childProcess.spawnSync(process.platform === "windows" ? "where.exe" : "which", ["bun"], {
212
+ encoding: "utf8",
213
+ timeout: 1000,
214
+ })
215
+ const lines = (out.stdout || "").trim().split(/\r?\n/).map((l) => l.trim()).filter(Boolean)
216
+ const exe = lines.find((l) => l.endsWith(".exe")) || lines[0]
217
+ if (exe) return exe
218
+ } catch {
219
+ // ignore
220
+ }
221
+
222
+ return process.platform === "windows" ? "bun.cmd" : "bun"
223
+ }
224
+
225
+ const devEntry = path.resolve(scriptDir, "../src/index.ts")
226
+ const resolved =
227
+ envPath ||
228
+ (fs.existsSync(cached) ? cached : (legacyCached.find((candidate) => fs.existsSync(candidate)) ?? findBinary(scriptDir)))
229
+
230
+ if (resolved) {
231
+ run(resolved)
232
+ } else if (fs.existsSync(devEntry)) {
233
+ const bunCmd = findBun()
234
+ const child = childProcess.spawn(bunCmd, ["run", devEntry, ...process.argv.slice(2)], {
235
+ stdio: "inherit",
236
+ shell: bunCmd.endsWith(".cmd") || bunCmd.endsWith(".bat"),
237
+ })
238
+
239
+ child.on("error", (error) => {
240
+ console.error(error.message)
241
+ process.exit(1)
242
+ })
243
+
244
+ child.on("exit", (code) => {
245
+ process.exit(typeof code === "number" ? code : 0)
246
+ })
247
+ } else {
248
+ console.error(
249
+ "It seems that your package manager failed to install the right version of the OceanCode CLI for your platform. You can try manually installing " +
250
+ names.map((n) => `\"${n}\"`).join(" or ") +
251
+ " package",
252
+ )
253
+ process.exit(1)
254
+ }
package/package.json CHANGED
@@ -1,51 +1,38 @@
1
1
  {
2
2
  "name": "oceancode",
3
- "version": "0.1.2",
4
- "description": "Next-generation CLI coding assistant powered by OpenCode server",
5
- "main": "dist/index.js",
3
+ "version": "0.1.4",
4
+ "description": "OceanCode - an AI coding agent for the terminal, desktop, and IDE",
5
+ "license": "MIT",
6
+ "homepage": "https://github.com/ianimatethings12-stack/oceancode",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/ianimatethings12-stack/oceancode"
10
+ },
6
11
  "bin": {
7
- "oceancode": "dist/index.js",
8
- "ocean": "dist/index.js"
12
+ "oceancode": "./bin/oceancode",
13
+ "ocean": "./bin/oceancode"
9
14
  },
10
- "type": "module",
11
- "files": [
12
- "dist",
13
- "scripts/postinstall.mjs",
14
- "README.md",
15
- "LICENSE"
15
+ "os": [
16
+ "darwin",
17
+ "linux",
18
+ "win32"
16
19
  ],
17
- "engines": {
18
- "node": ">=18"
19
- },
20
- "scripts": {
21
- "build": "tsup",
22
- "dev": "tsx src/index.ts",
23
- "start": "node dist/index.js",
24
- "prepare": "npm run build",
25
- "postinstall": "node ./scripts/postinstall.mjs",
26
- "prepublishOnly": "npm run build"
27
- },
28
- "keywords": [
29
- "ai",
30
- "cli",
31
- "coding-assistant",
32
- "opencode",
33
- "oceancode"
20
+ "cpu": [
21
+ "arm64",
22
+ "x64"
34
23
  ],
35
- "author": "",
36
- "license": "MIT",
37
- "dependencies": {
38
- "@inquirer/prompts": "^7.3.2",
39
- "chalk": "^5.4.1",
40
- "commander": "^13.1.0",
41
- "dotenv": "^16.4.7",
42
- "opencode-ai": "^1.18.29",
43
- "ora": "^8.2.0"
44
- },
45
- "devDependencies": {
46
- "@types/node": "^22.13.5",
47
- "tsup": "^8.4.0",
48
- "tsx": "^4.19.3",
49
- "typescript": "^5.7.3"
24
+ "optionalDependencies": {
25
+ "oceancode-windows-x64-baseline": "0.1.4",
26
+ "oceancode-windows-x64": "0.1.4",
27
+ "oceancode-windows-arm64": "0.1.4",
28
+ "oceancode-linux-x64-musl": "0.1.4",
29
+ "oceancode-linux-x64-baseline-musl": "0.1.4",
30
+ "oceancode-linux-x64-baseline": "0.1.4",
31
+ "oceancode-linux-x64": "0.1.4",
32
+ "oceancode-linux-arm64-musl": "0.1.4",
33
+ "oceancode-linux-arm64": "0.1.4",
34
+ "oceancode-darwin-x64-baseline": "0.1.4",
35
+ "oceancode-darwin-x64": "0.1.4",
36
+ "oceancode-darwin-arm64": "0.1.4"
50
37
  }
51
- }
38
+ }