Add secure tmux integration into the sandbox, as well as allowing for connections over the webserver running on openced which will be at localhost:4096
Add secure tmux integration into the sandbox, as well as allowing for connections over the webserver running on openced which will be at localhost:4096
I'll help you add secure tmux integration with web-based access. Let me first explore the current codebase to understand the sandbox structure.
total 752128
drwxr-xr-x 4 jm jm 4096 Jan 21 03:51 .
drwx------ 5 jm jm 100 Jan 21 08:10 ..
-rwxrwxr-x 1 jm jm 1882 Apr 20 2025 24-bit-color.sh
-rwxr-xr-x 1 jm jm 218 Jun 29 2018 34bytes-eclipse
-rwxr-xr-x 1 jm jm 88 Mar 31 2018 34db-dev
-rwxr-xr-x 1 jm jm 98 Jun 20 2018 34gitd
-rwxr-xr-x 1 jm jm 94 Dec 5 2017 34login
-rwxr-xr-x 1 jm jm 72 Apr 14 2018 34start
-rwxr-xr-x 1 jm jm 77 Mar 2 2018 34update
-rw-r--r-- 1 jm jm 67 Mar 21 2023 ac3convert
-rw-rw-r-- 1 jm jm 1689 Jun 2 2025 atspi-stub.py
-rwxr-xr-x 1 jm jm 217 Feb 1 2023 automat-visualize
-rwxr-xr-x 1 jm jm 114 Jan 15 2018 aws-login
-rw-rw-r-- 1 jm jm 107 Feb 21 2025 backup
lrwxrwxrwx 1 jm jm 32 Nov 13 16:36 bazel -> /home/jm/dl/bazelisk-linux-amd64
-rwxr-xr-x 1 jm jm 69 Sep 12 2018 binaryninja
-rwxr-xr-x 1 jm jm 78 Jan 18 2022 bscribe
lrwxrwxrwx 1 jm jm 21 Aug 30 05:08 bunx -> /home/jm/.bun/bin/bun
-rwxrwxr-x 1 jm jm 1688 May 29 2025 bwfirefox
-rwxr-xr-x 1 jm jm 223 Feb 1 2023 cftp
-rwxr-xr-x 1 jm jm 45919064 Oct 6 23:31 comby
-rwxr-xr-x 1 jm jm 224 Feb 1 2023 conch
lrwxrwxrwx 1 jm jm 35 Aug 15 20:12 config -> /home/jm/.dotfiles/local_bin/config
-rwxr-xr-x 1 jm jm 47519229 Nov 17 12:54 d2
lrwxrwxrwx 1 jm jm 60 Nov 2 09:01 deepagents -> /home/jm/.local/share/uv/tools/deepagents-cli/bin/deepagents
lrwxrwxrwx 1 jm jm 64 Nov 2 09:01 deepagents-cli -> /home/jm/.local/share/uv/tools/deepagents-cli/bin/deepagents-cli
-rwxrwxr-x 1 jm jm 212 Oct 6 20:10 docker
-r-xr-xr-x 1 jm jm 23467696 Oct 14 02:26 dune
-rw-rw-r-- 1 jm jm 346 Aug 16 11:04 env
-rw-rw-r-- 1 jm jm 183 Aug 16 11:04 env.fish
-rwxr-xr-x 1 jm jm 222 Nov 27 2022 epylint
-rwxr-xr-x 1 jm jm 216 Apr 24 2020 f2py
-rwxr-xr-x 1 jm jm 216 Apr 24 2020 f2py3
-rwxr-xr-x 1 jm jm 216 Apr 24 2020 f2py3.8
lrwxrwxrwx 1 jm jm 34 Aug 15 20:13 f.../home/jm/.local/bin/atspi-stub.py
/home/jm/.local/bin/jp.py
/home/jm/.local/bin/pywallet.pyNo files found/home/jm/.local/bin/token-check.tstmux binding /tmp/tmux-1000
<file>
00001| #!/usr/bin/env fish
00002|
00003| set -l APP $argv[1]
00004| if test -z "$APP"
00005| echo "usage: sbox <cmd> [args...]"
00006| exit 1
00007| end
00008| set -e argv[1]
00009|
00010| set -l APP_ID (basename "$APP")
00011| set -l ROOTS (test -n "$ROOTS"; and echo $ROOTS; or echo "/usr:/etc")
00012| set -l RW (test -n "$RW"; and echo $RW; or echo "$HOME/.sandboxes/$APP_ID:/tmp")
00013| set -l APP_HOME "$HOME/.sandboxes/$APP_ID"
00014| mkdir -p "$APP_HOME"
00015|
00016| # 1) Filtered D-Bus
00017| set -l SOCK "$XDG_RUNTIME_DIR/dbus-proxy-$APP_ID.sock"
00018| pkill -f "xdg-dbus-proxy .* $SOCK" 2>/dev/null || true
00019| xdg-dbus-proxy "$DBUS_SESSION_BUS_ADDRESS" "$SOCK" --filter \
00020| --see="org.freedesktop.DBus" --talk="org.freedesktop.DBus" \
00021| --talk="org.freedesktop.portal.*" --broadcast="org.freedesktop.portal.*=@/org/freedesktop/portal/*" &
00022| set -l DBUS_PROXY_PID $last_pid
00023| trap 'kill $DBUS_PROXY_PID 2>/dev/null || true' EXIT
00024| set -gx DBUS_SESSION_BUS_ADDRESS "unix:path=$SOCK"
00025|
00026| # 2) Landlock (via landrun if present)
00027| # if command -v landrun >/dev/null
00028| if false
00029|
00030| set -l LR
00031|
00032| # Process ROOTS
00033| set -l _r (string split : "$ROOTS")
00034| for p in $_r
00035| set LR $LR --ro "$p"
00036| end
00037|
00038| # Process RW
00039| set -l _w (string split : "$RW")
00040| for p in $_w
00041| set LR $LR --rw "$p"
00042| end
00043|
00044| set LR $LR --unrestricted-network
00045|
00046| exec landrun $LR -- bwrap --unshare-user --unshare-ipc --unshare-pid --unshare-uts --unshare-cgroup \
00047| --ro-bind /usr /usr --ro-bind /etc /etc --proc /proc --dev /dev \
00048| --dev-bind /dev/dri /dev/dri --bind "$APP_HOME" "$APP_HOME" \
00049| --bind "$XDG_RUNTIME_DIR" "$XDG_RUNTIME_DIR" \
00050| --setenv HOME "$APP_HOME" --setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
00051| --setenv D...ls: cannot access '/tmp/tmux-1000/': No such file or directory
<file>
00001| #!/usr/bin/env fish
00002|
00003| set -g PROJECT_DIR (pwd)
00004| set -g OPENCODE_DIR /home/jm/data/code/opencode
00005| cd $OPENCODE_DIR
00006| echo "Changing into $OPENCODE_DIR"
00007| echo "argv: $argv"
00008| echo "ARGS: $ARGS"
00009|
00010| set -g OPENCODE_CMDS (bun run dev --get-yargs-completions)
00011|
00012| if [ (count $argv) -eq 0 ] || test -z "$argv[1]"
00013| # IF no args, set cwd
00014| set -a ARGS $argv
00015| else if contains $argv[1] $OPENCODE_CMDS
00016| # IF first arg is a known opencode command, set cwd
00017| # We are using a model
00018| set -a ARGS $argv
00019| else
00020| # ELSE first arg is project dir
00021| set -g PROJECT_DIR $argv[1]
00022| set -g ARGS $argv
00023| end
00024|
00025| echo "PROJECT_DIR: $PROJECT_DIR"
00026| echo "bun run dev $ARGS"
00027|
00028| # We can set custom configs if we want to here
00029| set -g OPENCODE_CONFIG_DIR $HOME/.config/opencode
00030|
00031| set -gx OPENCODE_DISABLE_PRUNE false
00032| set -gx OPENCODE_AUTO_SHARE false
00033| set -gx OPENCODE_EXPERIMENTAL_LSP_TOOL true
00034| set -gx OPENCODE_LIBC glibc
00035|
00036| echo "Launching project in $PROJECT_DIR from $OPENCODE_DIR"
00037| echo "with args: $ARGS"
00038| echo
00039|
00040| bwrap \
00041| --ro-bind /usr /usr \
00042| --ro-bind /lib /lib \
00043| --ro-bind /lib64 /lib64 \
00044| --ro-bind /bin /bin \
00045| --ro-bind /etc/resolv.conf /etc/resolv.conf \
00046| --ro-bind /etc/hosts /etc/hosts \
00047| --ro-bind /etc/ssl /etc/ssl \
00048| --ro-bind /etc/passwd /etc/passwd \
00049| --ro-bind /etc/group /etc/group \
00050| --ro-bind-try $HOME.gitconfig $HOME/.gitconfig \
00051| --bind-try $HOME/.bun $HOME/.bun \
00052| --bind-try $OPENCODE_CONFIG_DIR $OPENCODE_CONFIG_DIR \
00053| --bind-try $OPENCODE_DIR $OPENCODE_DIR \
00054| --bind $HOME/.cache/opencode $HOME/.cache/opencode \
00055| --bind $HOME/.local/share/opencode $HOME/.local/share/op...193
LISTEN 0 512 127.0.0.1:4096 0.0.0.0:*
/usr/bin/bash: line 1: which: command not found
opncd
total 1392
drwxrwxr-x 1 jm jm 922 Jan 21 07:55 .
drwx------ 3 jm jm 60 Jan 21 08:10 ..
-rw------- 1 jm jm 14197 Jan 19 13:33 AGENT_ASSIGNMENT_CARD.md
-rw-rw-r-- 1 jm jm 1125 Jan 16 23:23 AGENTS.md
-rw------- 1 jm jm 22842 Jan 19 13:33 ARCHITECTURE_DIAGRAMS.md
drwxrwxr-x 1 jm jm 34 Jan 18 22:25 .ast
-rw-rw-r-- 1 jm jm 430 Jan 19 04:17 biome.json
-rw-rw-r-- 1 jm jm 0 Jan 19 18:17 build.ts
-rw-rw-r-- 1 jm jm 23 Jan 16 23:23 bunfig.toml
-rw-r--r-- 1 jm jm 602134 Jan 21 02:54 bun.lock
-rw-r--r-- 1 jm jm 637684 Jan 19 01:47 bun.lock.backup
-rw-rw-r-- 1 jm jm 5036 Jan 16 23:23 CONTRIBUTING.md
drwxr-xr-x 1 jm jm 0 Jan 21 07:02 dev
-rw-rw-r-- 1 jm jm 569 Dec 30 15:13 flake.lock
-rw-rw-r-- 1 jm jm 2754 Jan 16 23:23 flake.nix
drwxrwxr-x 1 jm jm 266 Jan 21 07:56 .git
drwxrwxr-x 1 jm jm 104 Jan 16 23:23 .github
drwxrwxr-x 1 jm jm 176 Jan 16 23:23 github
-rw-rw-r-- 1 jm jm 200 Jan 19 13:32 .gitignore
drwxrwxr-x 1 jm jm 18 Jan 16 23:23 .husky
drwxrwxr-x 1 jm jm 92 Jan 16 23:23 infra
-rwxrwxr-x 1 jm jm 11657 Jan 16 23:23 install
drwxrwxr-x 1 jm jm 52 Jan 21 07:55 .jj
-rw-rw-r-- 1 jm jm 1065 Jan 16 23:23 LICENSE
drwxrwxr-x 1 jm jm 110 Jan 16 23:23 nix
drwxr-xr-x 1 jm jm 240 Jan 19 01:28 node_modules
drwxrwxr-x 1 jm jm 356 Jan 20 22:47 .opencode
-rw------- 1 jm jm 24533 Jan 19 13:33 OPENCODE_COMPLETE_DESIGN.md
drwxrwxr-x 1 jm jm 0 Jan 19 11:43 os
-rw-rw-r-- 1 jm jm 2822 Jan 21 02:54 package.json
drwxrwxr-x 1 jm jm 226 Jan 17 00:56 packages
drwxrwxr-x 1 jm jm 46 Jan 16 23:23 patches
-rw-rw-r-- 1 jm jm 12 Jan 16 23:23 .prettierignore
-rw------- 1 jm jm 227 Jan 21 04:59 private.key
drwxr-xr-x 1 jm jm 0 Jan 21 07:02 proc
drwxrwxr-x 1 jm jm 24 Jan 19 13:38 .prose
-rw-rw-r-- 1 jm jm 5277 Jan 16 23:23 README.md
-rw-rw-r-- 1 jm jm 5405 Jan 16 23:23 README.zh-TW.md
drwxrwxr-x 1 jm jm 446 Jan 18 20:01 .scratch
drwxrwxr-x 1 jm jm 172 Jan 16 23:23 script
drwxrwxr-x 1 jm jm 12 O...I"m instde a sandbox now
<file>
00001| {
00002| "$schema": "https://json.schemastore.org/package.json",
00003| "name": "opencode",
00004| "description": "AI-powered development tool",
00005| "private": true,
00006| "type": "module",
00007| "packageManager": "bun@1.3.5",
00008| "scripts": {
00009| "dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts",
00010| "typecheck": "bun turbo typecheck",
00011| "prepare": "husky",
00012| "random": "echo 'Random script'",
00013| "hello": "echo 'Hello World!'"
00014| },
00015| "workspaces": {
00016| "packages": [
00017| "packages/*",
00018| "packages/console/*",
00019| "packages/sdk/js",
00020| "packages/slack"
00021| ],
00022| "catalog": {
00023| "@types/bun": "1.3.4",
00024| "@octokit/rest": "22.0.0",
00025| "@hono/zod-validator": "0.4.2",
00026| "ulid": "3.0.1",
00027| "@kobalte/core": "0.13.11",
00028| "@types/luxon": "3.7.1",
00029| "@types/node": "22.13.9",
00030| "@tsconfig/node22": "22.0.2",
00031| "@tsconfig/bun": "1.0.9",
00032| "@cloudflare/workers-types": "4.20251008.0",
00033| "@openauthjs/openauth": "0.0.0-20250322224806",
00034| "@pierre/diffs": "1.0.2",
00035| "@solid-primitives/storage": "4.3.3",
00036| "@tailwindcss/vite": "4.1.11",
00037| "diff": "8.0.2",
00038| "ai": "5.0.97",
00039| "hono": "4.10.7",
00040| "hono-openapi": "1.1.2",
00041| "fuzzysort": "3.1.0",
00042| "luxon": "3.6.1",
00043| "marked": "17.0.1",
00044| "marked-shiki": "1.2.1",
00045| "typescript": "5.8.2",
00046| "@typescript/native-preview": "7.0.0-dev.20251207.1",
00047| "zod": "4.1.8",
00048| "remeda": "2.26.0",
00049| "shiki": "3.20.0",
00050| "solid-list": "0.3.0",
00051| "tailwindcss": "4.1.11",
00052| "virtua": "0.42.3",
00053| "vite": "7.1.4",
00054| "@solidjs/meta": "0.29.4",
0...No files foundNo files found<file>
00001| import yargs from "yargs"
00002| import { hideBin } from "yargs/helpers"
00003| import { RunCommand } from "./cli/cmd/run"
00004| import { GenerateCommand } from "./cli/cmd/generate"
00005| import { Log } from "./util/log"
00006| import { AuthCommand } from "./cli/cmd/auth"
00007| import { AgentCommand } from "./cli/cmd/agent"
00008| import { UpgradeCommand } from "./cli/cmd/upgrade"
00009| import { UninstallCommand } from "./cli/cmd/uninstall"
00010| import { ModelsCommand } from "./cli/cmd/models"
00011| import { UI } from "./cli/ui"
00012| import { Installation } from "./installation"
00013| import { NamedError } from "../util/error"
00014| import { FormatError } from "./cli/error"
00015| import { ServeCommand } from "./cli/cmd/serve"
00016| import { DebugCommand } from "./cli/cmd/debug"
00017| import { StatsCommand } from "./cli/cmd/stats"
00018| import { McpCommand } from "./cli/cmd/mcp"
00019| import { GithubCommand } from "./cli/cmd/github"
00020| import { ExportCommand } from "./cli/cmd/export"
00021| import { ImportCommand } from "./cli/cmd/import"
00022| import { AttachCommand } from "./cli/cmd/tui/attach"
00023| import { TuiThreadCommand } from "./cli/cmd/tui/thread"
00024| import { TuiSpawnCommand } from "./cli/cmd/tui/spawn"
00025| import { AcpCommand } from "./cli/cmd/acp"
00026| import { EOL } from "os"
00027| import { WebCommand } from "./cli/cmd/web"
00028| import { PrCommand } from "./cli/cmd/pr"
00029| import { SessionCommand } from "./cli/cmd/session"
00030|
00031| process.on("unhandledRejection", (e) => {
00032| Log.Default.error("rejection", {
00033| e: e instanceof Error ? e.message : e,
00034| })
00035| })
00036|
00037| process.on("uncaughtException", (e) => {
00038| Log.Default.error("exception", {
00039| e: e instanceof Error ? e.message : e,
00040| })
00041| })
00042|
00043| const cli = yargs(hideBin(process.argv))
00044| .parserConfiguration({ "populate--": true })
00045| .scriptName("opencode")
00046|...the opncd fish script in here is where I wrap the bun executable witrh bwrap
No files foundtotal 0
drwxrwxr-x 1 jm jm 226 Jan 17 00:56 .
drwxrwxr-x 1 jm jm 922 Jan 21 07:55 ..
drwxrwxr-x 1 jm jm 298 Jan 18 21:28 app
drwxrwxr-x 1 jm jm 54 Dec 30 15:13 console
drwxrwxr-x 1 jm jm 242 Jan 18 21:28 desktop
drwxrwxr-x 1 jm jm 244 Jan 16 23:23 docs
drwxrwxr-x 1 jm jm 284 Jan 18 21:28 enterprise
drwxrwxr-x 1 jm jm 6 Dec 30 15:13 extensions
drwxrwxr-x 1 jm jm 310 Jan 18 21:28 function
drwxrwxr-x 1 jm jm 180 Jan 16 23:23 identity
drwxrwxr-x 1 jm jm 344 Jan 18 21:28 opencode
drwxrwxr-x 1 jm jm 156 Jan 18 21:28 plugin
drwxrwxr-x 1 jm jm 104 Jan 18 21:28 script
drwxrwxr-x 1 jm jm 88 Jan 16 23:23 sdk
drwxrwxr-x 1 jm jm 368 Jan 21 06:42 sessions
drwxrwxr-x 1 jm jm 178 Jan 18 21:28 slack
drwxrwxr-x 1 jm jm 176 Jan 18 21:28 ui
drwxrwxr-x 1 jm jm 116 Jan 18 21:28 util
drwxrwxr-x 1 jm jm 434 Jan 21 06:42 web
drwxrwxr-x 1 jm jm 234 Jan 18 21:28 worker-test
No files foundNo files found/home/jm/data/code/opencode/packages/web/src/pages/[...slug].md.ts
/home/jm/data/code/opencode/packages/web/src/types/lang-map.d.ts
/home/jm/data/code/opencode/packages/web/src/api.ts
/home/jm/data/code/opencode/packages/web/src/worker.ts
/home/jm/data/code/opencode/packages/web/worker-configuration.d.ts
/home/jm/data/code/opencode/packages/web/node_modules/@cloudflare/kv-asset-handler/dist/index.d.ts
/home/jm/data/code/opencode/packages/web/node_modules/@cloudflare/kv-asset-handler/src/types.ts
/home/jm/data/code/opencode/packages/web/node_modules/@cloudflare/kv-asset-handler/src/index.ts
/home/jm/data/code/opencode/packages/web/node_modules/@cloudflare/unenv-preset/dist/index.d.ts
/home/jm/data/code/opencode/packages/web/node_modules/@cloudflare/unenv-preset/dist/runtime/node/process.d.ts
/home/jm/data/code/opencode/packages/web/node_modules/@cloudflare/unenv-preset/dist/runtime/node/console.d.ts
/home/jm/data/code/opencode/packages/web/node_modules/@cloudflare/unenv-preset/dist/runtime/polyfill/performance.d.ts
/home/jm/data/code/opencode/packages/web/node_modules/hono/dist/types/middleware/jwt/index.d.ts
/home/jm/data/code/opencode/packages/web/node_modules/hono/dist/types/middleware/jwt/jwt.d.ts
/home/jm/data/code/opencode/packages/web/node_modules/hono/dist/types/middleware/cache/index.d.ts
/home/jm/data/code/opencode/packages/web/node_modules/hono/dist/types/middleware/bearer-auth/index.d.ts
/home/jm/data/code/opencode/packages/web/node_modules/hono/dist/types/middleware/trailing-slash/index.d.ts
/home/jm/data/code/opencode/packages/web/node_modules/hono/dist/types/middleware/jwk/jwk.d.ts
/home/jm/data/code/opencode/packages/web/node_modules/hono/dist/types/middleware/jwk/index.d.ts
/home/jm/data/code/opencode/packages/web/node_modules/hono/dist/types/middleware/serve-static/path.d.ts
/home/jm/data/code/opencode/packages/opencode/script/build.ts
/home/jm/data/code/opencode/packages/opencode/script/publish-registries.ts
/home/jm/data/code/opencode/packages/opencode/script/publish.ts
/home/jm/data/code/opencode/packages/opencode/script/schema.ts
/home/jm/data/code/opencode/packages/opencode/src/agent/agent.ts
/home/jm/data/code/opencode/packages/opencode/src/auth/index.ts
/home/jm/data/code/opencode/packages/opencode/src/bun/index.ts
/home/jm/data/code/opencode/packages/opencode/src/bus/bus-event.ts
/home/jm/data/code/opencode/packages/opencode/src/bus/global.ts
/home/jm/data/code/opencode/packages/opencode/src/bus/index.ts
/home/jm/data/code/opencode/packages/opencode/src/cli/cmd/debug/config.ts
/home/jm/data/code/opencode/packages/opencode/src/cli/cmd/debug/file.ts
/home/jm/data/code/opencode/packages/opencode/src/cli/cmd/debug/index.ts
/home/jm/data/code/opencode/packages/opencode/src/cli/cmd/debug/lsp.ts
/home/jm/data/code/opencode/packages/opencode/src/cli/cmd/debug/ripgrep.ts
/home/jm/data/code/opencode/packages/opencode/src/cli/cmd/debug/scrap.ts
/home/jm/data/code/opencode/packages/opencode/src/cli/cmd/debug/skill.ts
/home/jm/data/code/opencode/packages/opencode/src/cli/cmd/debug/snapshot.ts
/home/jm/data/code/opencode/packages/opencode/src/cli/cmd/tui/component/tips.ts
/home/jm/data/code/opencode/packages/opencode/src/cli/cmd/tui/context/directory.ts
<file>
00001| // Client-side API helper for making requests to the worker API
00002|
00003| export async function getSessions() {
00004| const response = await fetch('/api/sessions')
00005| if (!response.ok) {
00006| throw new Error(`Failed to fetch sessions: ${response.statusText}`)
00007| }
00008| return response.json()
00009| }
00010|
00011| export async function getShare(id: string) {
00012| const response = await fetch(`/api/share/${id}`)
00013| if (!response.ok) {
00014| throw new Error(`Failed to fetch share: ${response.statusText}`)
00015| }
00016| return response.json()
00017| }
00018|
00019| export async function createShare(sessionID: string) {
00020| const response = await fetch('/api/share', {
00021| method: 'POST',
00022| headers: { 'Content-Type': 'application/json' },
00023| body: JSON.stringify({ sessionID }),
00024| })
00025| if (!response.ok) {
00026| throw new Error(`Failed to create share: ${response.statusText}`)
00027| }
00028| return response.json()
00029| }
00030|
00031| export async function syncShare(id: string, secret: string, data: any[]) {
00032| const response = await fetch(`/api/share/${id}/sync`, {
00033| method: 'POST',
00034| headers: { 'Content-Type': 'application/json' },
00035| body: JSON.stringify({ secret, data }),
00036| })
00037| if (!response.ok) {
00038| throw new Error(`Failed to sync share: ${response.statusText}`)
00039| }
00040| return response.json()
00041| }
00042|
(End of file - total 42 lines)
</file>/home/jm/data/code/opencode/packages/web/src/components/icons/custom.tsx
/home/jm/data/code/opencode/packages/web/src/components/icons/index.tsx
/home/jm/data/code/opencode/packages/web/src/components/share/common.tsx
/home/jm/data/code/opencode/packages/web/src/components/share/content-bash.tsx
/home/jm/data/code/opencode/packages/web/src/components/share/content-code.tsx
/home/jm/data/code/opencode/packages/web/src/components/share/content-diff.tsx
/home/jm/data/code/opencode/packages/web/src/components/share/content-error.tsx
/home/jm/data/code/opencode/packages/web/src/components/share/content-markdown.tsx
/home/jm/data/code/opencode/packages/web/src/components/share/content-text.tsx
/home/jm/data/code/opencode/packages/web/src/components/share/copy-button.tsx
/home/jm/data/code/opencode/packages/web/src/components/share/part.tsx
/home/jm/data/code/opencode/packages/web/src/components/SessionsList.tsx
/home/jm/data/code/opencode/packages/web/src/components/Share.tsx
/home/jm/data/code/opencode/packages/web/src/pages/[...slug].md.ts
/home/jm/data/code/opencode/packages/web/src/types/lang-map.d.ts
/home/jm/data/code/opencode/packages/web/src/App.tsx
/home/jm/data/code/opencode/packages/web/src/api.ts
/home/jm/data/code/opencode/packages/web/src/client.tsx
/home/jm/data/code/opencode/packages/web/src/worker.ts
<file>
00001| /// <reference types="@cloudflare/workers-types" />
00002|
00003| import { Hono } from "hono"
00004| import { cors } from "hono/cors"
00005|
00006| export type Env = {
00007| SESSIONS_API: Fetcher
00008| SESSIONS_REF: DurableObjectNamespace
00009| }
00010|
00011| export class SessionRef implements DurableObject {
00012| state: DurableObjectState
00013| env: Env
00014| private sessions: Map<string, WebSocket> = new Map()
00015|
00016| constructor(state: DurableObjectState, env: Env) {
00017| this.state = state
00018| this.env = env
00019| this.restoreConnections()
00020| }
00021|
00022| private restoreConnections() {
00023| const websockets = this.state.getWebSockets()
00024| for (const ws of websockets) {
00025| const attachment = ws.deserializeAttachment()
00026| if (attachment?.clientId) {
00027| this.sessions.set(attachment.clientId, ws)
00028| }
00029| }
00030| }
00031|
00032| async fetch(request: Request): Promise<Response> {
00033| const url = new URL(request.url)
00034| const shareId = url.pathname.split('/')[2]
00035|
00036| if (request.headers.get("Upgrade") === "websocket") {
00037| const pair = new WebSocketPair()
00038| const [client, server] = Object.values(pair)
00039|
00040| const clientId = crypto.randomUUID()
00041| this.sessions.set(clientId, server)
00042|
00043| // Persist metadata
00044| server.serializeAttachment({
00045| clientId,
00046| shareId,
00047| connectedAt: Date.now()
00048| })
00049|
00050| this.state.acceptWebSocket(server, ['session', shareId])
00051|
00052| return new Response(null, {
00053| status: 101,
00054| webSocket: client
00055| })
00056| }
00057|
00058| return new Response("Not Found", { status: 404 })
00059| }
00060|
00061| async webSocketMessage(ws: WebSocket, message: string) {
00062| const attachme...No files found-rw-rw-r-- 1 jm jm 2253 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/acp.ts
-rw-rw-r-- 1 jm jm 7749 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/agent.ts
-rw-rw-r-- 1 jm jm 12464 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/auth.ts
-rw-rw-r-- 1 jm jm 183 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/cmd.ts
-rw-rw-r-- 1 jm jm 422 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/debug/config.ts
-rw-rw-r-- 1 jm jm 2305 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/debug/file.ts
-rw-rw-r-- 1 jm jm 1185 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/debug/index.ts
-rw-rw-r-- 1 jm jm 1628 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/debug/lsp.ts
-rw-rw-r-- 1 jm jm 2216 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/debug/ripgrep.ts
-rw-rw-r-- 1 jm jm 418 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/debug/scrap.ts
-rw-rw-r-- 1 jm jm 410 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/debug/skill.ts
-rw-rw-r-- 1 jm jm 1145 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/debug/snapshot.ts
-rw-rw-r-- 1 jm jm 2469 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/export.ts
-rw-rw-r-- 1 jm jm 1179 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/generate.ts
-rw-rw-r-- 1 jm jm 51701 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/github.ts
-rw-rw-r-- 1 jm jm 2952 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/import.ts
-rw-rw-r-- 1 jm jm 21922 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/mcp.ts
-rw-rw-r-- 1 jm jm 2437 Jan 16 23:23 /home/jm/data/code/opencode/packages/opencode/src/cli/cmd/models.ts
-rw-rw-r-- 1 jm jm 4453 Jan 16 23:23 /home/jm/data/code/op...<file>
00001| import { Server } from "../../server/server"
00002| import { cmd } from "./cmd"
00003| import { withNetworkOptions, resolveNetworkOptions } from "../network"
00004|
00005| export const ServeCommand = cmd({
00006| command: "serve",
00007| builder: (yargs) => withNetworkOptions(yargs),
00008| describe: "starts a headless opencode server",
00009| handler: async (args) => {
00010| const opts = await resolveNetworkOptions(args)
00011| const server = Server.listen(opts)
00012| console.log(`opencode server listening on http://${server.hostname}:${server.port}`)
00013| await new Promise(() => {})
00014| await server.stop()
00015| },
00016| })
00017|
(End of file - total 17 lines)
</file>/home/jm/data/code/opencode/packages/opencode/src/cli/cmd/tui/attach.ts: describe: "http://localhost:4096",
/home/jm/data/code/opencode/packages/opencode/src/cli/cmd/run.ts: describe: "attach to a running opencode server (e.g., http://localhost:4096)",
/home/jm/data/code/opencode/packages/opencode/src/plugin/index.ts: baseUrl: "http://localhost:4096",
/home/jm/data/code/opencode/packages/opencode/src/server/server.ts: const server = opts.port === 0 ? (tryServe(4096) ?? tryServe(0)) : tryServe(opts.port)
/home/jm/data/code/opencode/packages/opencode/src/tool/read.ts: const bufferSize = Math.min(4096, fileSize)
<file>
00001| import { BusEvent } from "@/bus/bus-event"
00002| import { Bus } from "@/bus"
00003| import { GlobalBus } from "@/bus/global"
00004| import { Log } from "../util/log"
00005| import { describeRoute, generateSpecs, validator, resolver, openAPIRouteHandler } from "hono-openapi"
00006| import { Hono } from "hono"
00007| import { cors } from "hono/cors"
00008| import { stream, streamSSE } from "hono/streaming"
00009| import { proxy } from "hono/proxy"
00010| import { Session } from "../session"
00011| import z from "zod"
00012| import { Provider } from "../provider/provider"
00013| import { filter, mapValues, sortBy, pipe } from "remeda"
00014| import { NamedError } from "@opencode-ai/util/error"
00015| import { ModelsDev } from "../provider/models"
00016| import { Ripgrep } from "../file/ripgrep"
00017| import { Config } from "../config/config"
00018| import { File } from "../file"
00019| import { LSP } from "../lsp"
00020| import { Format } from "../format"
00021| import { MessageV2 } from "../session/message-v2"
00022| import { TuiRoute } from "./tui"
00023| import { Permission } from "../permission"
00024| import { Instance } from "../project/instance"
00025| import { Vcs } from "../project/vcs"
00026| import { Agent } from "../agent/agent"
00027| import { Auth } from "../auth"
00028| import { Command } from "../command"
00029| import { ProviderAuth } from "../provider/auth"
00030| import { Global } from "../global"
00031| import { ProjectRoute } from "./project"
00032| import { ToolRegistry } from "../tool/registry"
00033| import { zodToJsonSchema } from "zod-to-json-schema"
00034| import { SessionPrompt } from "../session/prompt"
00035| import { SessionCompaction } from "../session/compaction"
00036| import { SessionRevert } from "../session/revert"
00037| import { lazy } from "../util/lazy"
00038| import { Todo } from "../session/todo"
00039| import { InstanceBootstrap } from "../project/bootstrap"
00040| import { MCP } from "../mcp"
00041| import { ...45:import { SessionSummary } from "@/session/summary"
46:import { SessionStatus } from "@/session/status"
47:import { upgradeWebSocket, websocket } from "hono/bun"
48:import type { BunWebSocketData } from "hono/bun"
49:import { errors } from "./error"
50:import { Pty } from "@/pty"
51:import { Installation } from "@/installation"
52:import { MDNS } from "./mdns"
57:export namespace Server {
60: export const Event = {
66: export const App = lazy(() =>
2091: const supportsOAuth = await MCP.supportsOAuth(name)
2092: if (!supportsOAuth) {
2093: return c.json({ error: `MCP server ${name} does not support OAuth` }, 400)
2151: const supportsOAuth = await MCP.supportsOAuth(name)
2152: if (!supportsOAuth) {
2153: return c.json({ error: `MCP server ${name} does not support OAuth` }, 400)
2638: export async function openapi() {
2652: export function listen(opts: { port: number; hostname: string; mdns?: boolean }) {
2654: hostname: opts.hostname,
2659: const tryServe = (port: number) => {
2661: return Bun.serve({ ...args, port })
2666: const server = opts.port === 0 ? (tryServe(4096) ?? tryServe(0)) : tryServe(opts.port)
2667: if (!server) throw new Error(`Failed to start server on port ${opts.port}`)
2671: server.port &&
2672: opts.hostname !== "127.0.0.1" &&
2673: opts.hostname !== "localhost" &&
2674: opts.hostname !== "::1"
2676: MDNS.publish(server.port!)
2678: log.warn("mDNS enabled but hostname is loopback; skipping mDNS publish")
log.info("event connected")
return streamSSE(c, async (stream) => {
stream.writeSSE({
data: JSON.stringify({
type: "server.connected",
properties: {},
}),
})
const unsub = Bus.subscribeAll(async (event) => {
await stream.writeSSE({
data: JSON.stringify(event),
})
if (event.type === Bus.InstanceDisposed.type) {
stream.close()
}
})
// Send heartbeat every 30s to prevent WKWebView timeout (60s default)
const heartbeat = setInterval(() => {
stream.writeSSE({
data: JSON.stringify({
type: "server.heartbeat",
properties: {},
}),
})
}, 30000)
await new Promise<void>((resolve) => {
stream.onAbort(() => {
clearInterval(heartbeat)
unsub()
resolve()
log.info("event disconnected")
})
})
})
},
)
.all("/*", async (c) => {
return proxy(`https://app.opencode.ai${c.req.path}`, {
...c.req,
headers: {
host: "app.opencode.ai",
},
})
}),
)
export async function openapi() {
const result = await generateSpecs(App(), {
documentation: {
info: {
title: "opencode",
version: "1.0.0",
description: "opencode api",
},
openapi: "3.1.1",
},
})
return result
}
export function listen(opts: { port: number; hostname: string; mdns?: boolean }) {
const args = {
hostname: opts.hostname,
idleTimeout: 0,
fetch: App().fetch,
websocket: websocket,
} as const
const tryServe = (port: number) => {
try {
return Bun.serve({ ...arg.../home/jm/data/code/opencode/packages/opencode/src/pty
/home/jm/data/code/opencode/packages/opencode/src/pty/index.ts
<file>
00001| import { BusEvent } from "@/bus/bus-event"
00002| import { Bus } from "@/bus"
00003| import { type IPty } from "bun-pty"
00004| import z from "zod"
00005| import { Identifier } from "../id/id"
00006| import { Log } from "../util/log"
00007| import type { WSContext } from "hono/ws"
00008| import { Instance } from "../project/instance"
00009| import { lazy } from "@opencode-ai/util/lazy"
00010| import {} from "process"
00011| import { Installation } from "@/installation"
00012| import { Shell } from "@/shell/shell"
00013|
00014| export namespace Pty {
00015| const log = Log.create({ service: "pty" })
00016|
00017| const pty = lazy(async () => {
00018| if (!Installation.isLocal()) {
00019| const path = require(
00020| `bun-pty/rust-pty/target/release/${
00021| process.platform === "win32"
00022| ? "rust_pty.dll"
00023| : process.platform === "linux" && process.arch === "x64"
00024| ? "librust_pty.so"
00025| : process.platform === "darwin" && process.arch === "x64"
00026| ? "librust_pty.dylib"
00027| : process.platform === "darwin" && process.arch === "arm64"
00028| ? "librust_pty_arm64.dylib"
00029| : process.platform === "linux" && process.arch === "arm64"
00030| ? "librust_pty_arm64.so"
00031| : ""
00032| }`,
00033| )
00034| process.env.BUN_PTY_LIB = path
00035| }
00036| const { spawn } = await import("bun-pty")
00037| return spawn
00038| })
00039|
00040| export const Info = z
00041| .object({
00042| id: Identifier.schema("pty"),
00043| title: z.string(),
00044| command: z.string(),
00045| args: z.array(z.string()),
00046| cwd: z.string(),
00047| status: z.enum(["running", "exited"]),
00048| pid: z.number(),
00049| })
00050| .meta({ ref: "Pty" })
00051|
00052| export typ...total 8
drwxrwxr-x 1 jm jm 16 Jan 16 23:23 .
drwxrwxr-x 1 jm jm 368 Jan 16 23:23 ..
-rw-rw-r-- 1 jm jm 6373 Jan 16 23:23 index.ts
/home/jm/data/code/opencode/packages/opencode/src/shell/shell.ts
<file>
00001| import { Flag } from "@/flag/flag"
00002| import { lazy } from "@/util/lazy"
00003| import path from "path"
00004| import { spawn, type ChildProcess } from "child_process"
00005|
00006| const SIGKILL_TIMEOUT_MS = 200
00007|
00008| export namespace Shell {
00009| export async function killTree(proc: ChildProcess, opts?: { exited?: () => boolean }): Promise<void> {
00010| const pid = proc.pid
00011| if (!pid || opts?.exited?.()) return
00012|
00013| if (process.platform === "win32") {
00014| await new Promise<void>((resolve) => {
00015| const killer = spawn("taskkill", ["/pid", String(pid), "/f", "/t"], { stdio: "ignore" })
00016| killer.once("exit", () => resolve())
00017| killer.once("error", () => resolve())
00018| })
00019| return
00020| }
00021|
00022| try {
00023| process.kill(-pid, "SIGTERM")
00024| await Bun.sleep(SIGKILL_TIMEOUT_MS)
00025| if (!opts?.exited?.()) {
00026| process.kill(-pid, "SIGKILL")
00027| }
00028| } catch (_e) {
00029| proc.kill("SIGTERM")
00030| await Bun.sleep(SIGKILL_TIMEOUT_MS)
00031| if (!opts?.exited?.()) {
00032| proc.kill("SIGKILL")
00033| }
00034| }
00035| }
00036| const BLACKLIST = new Set(["fish", "nu"])
00037|
00038| function fallback() {
00039| if (process.platform === "win32") {
00040| if (Flag.OPENCODE_GIT_BASH_PATH) return Flag.OPENCODE_GIT_BASH_PATH
00041| const git = Bun.which("git")
00042| if (git) {
00043| // git.exe is typically at: C:\Program Files\Git\cmd\git.exe
00044| // bash.exe is at: C:\Program Files\Git\bin\bash.exe
00045| const bash = path.join(git, "..", "..", "bin", "bash.exe")
00046| if (Bun.file(bash).size) return bash
00047| }
00048| return process.env.COMSPEC || "cmd.exe"
00049| }
00050| if (process.platform === "darwin") return "/bin/zsh"
00051| const bash = Bun.which("...<file>
00405| .get(
00406| "/config",
00407| describeRoute({
00408| summary: "Get configuration",
00409| description: "Retrieve the current OpenCode configuration settings and preferences.",
00410| operationId: "config.get",
00411| responses: {
00412| 200: {
00413| description: "Get config info",
00414| content: {
00415| "application/json": {
00416| schema: resolver(Config.Info),
00417| },
00418| },
00419| },
00420| },
00421| }),
00422| async (c) => {
00423| return c.json(await Config.get())
00424| },
00425| )
00426|
00427| .patch(
00428| "/config",
00429| describeRoute({
00430| summary: "Update configuration",
00431| description: "Update OpenCode configuration settings and preferences.",
00432| operationId: "config.update",
00433| responses: {
00434| 200: {
00435| description: "Successfully updated config",
00436| content: {
00437| "application/json": {
00438| schema: resolver(Config.Info),
00439| },
00440| },
00441| },
00442| ...errors(400),
00443| },
00444| }),
00445| validator("json", Config.Info),
00446| async (c) => {
00447| const config = c.req.valid("json")
00448| await Config.update(config)
00449| return c.json(config)
00450| },
00451| )
00452| .get(
00453| "/experimental/tool/ids",
00454| describeRoute({
(File has more lines. Use 'offset' parameter to read beyond line 454)
</file>NO I am doing this in order to allow nvim to interact with the cli tool, we dont need to do much more than that I think
Got it, much simpler! Let me remove the complex tmux management and just keep the essential part - the bwrap binding for the socket.
▎ error creating /tmp/tmux-1000/default (No such file or directory)
▎
▎ },[Process exited 0]
this is the error I get in neovim at the moment
<file>
00001| #!/usr/bin/env fish
00002|
00003| set -g PROJECT_DIR (pwd)
00004| set -g OPENCODE_DIR /home/jm/data/code/opencode
00005|
00006| # Ensure tmux socket directory exists before launching sandbox
00007| if not test -d /tmp/tmux-1000
00008| mkdir -p /tmp/tmux-1000
00009| chmod 700 /tmp/tmux-1000
00010| end
00011|
00012| cd $OPENCODE_DIR
00013| echo "Changing into $OPENCODE_DIR"
00014| echo "argv: $argv"
00015| echo "ARGS: $ARGS"
00016|
00017| set -g OPENCODE_CMDS (bun run dev --get-yargs-completions)
00018|
00019| if [ (count $argv) -eq 0 ] || test -z "$argv[1]"
00020| # IF no args, set cwd
00021| set -a ARGS $argv
00022| else if contains $argv[1] $OPENCODE_CMDS
00023| # IF first arg is a known opencode command, set cwd
00024| # We are using a model
00025| set -a ARGS $argv
00026| else
00027| # ELSE first arg is project dir
00028| set -g PROJECT_DIR $argv[1]
00029| set -g ARGS $argv
00030| end
00031|
00032| echo "PROJECT_DIR: $PROJECT_DIR"
00033| echo "bun run dev $ARGS"
00034|
00035| # We can set custom configs if we want to here
00036| set -g OPENCODE_CONFIG_DIR $HOME/.config/opencode
00037|
00038| set -gx OPENCODE_DISABLE_PRUNE false
00039| set -gx OPENCODE_AUTO_SHARE false
00040| set -gx OPENCODE_EXPERIMENTAL_LSP_TOOL true
00041| set -gx OPENCODE_LIBC glibc
00042|
00043| echo "Launching project in $PROJECT_DIR from $OPENCODE_DIR"
00044| echo "with args: $ARGS"
00045| echo
00046|
00047| bwrap \
00048| --ro-bind /usr /usr \
00049| --ro-bind /lib /lib \
00050| --ro-bind /lib64 /lib64 \
00051| --ro-bind /bin /bin \
00052| --ro-bind /etc/resolv.conf /etc/resolv.conf \
00053| --ro-bind /etc/hosts /etc/hosts \
00054| --ro-bind /etc/ssl /etc/ssl \
00055| --ro-bind /etc/passwd /etc/passwd \
00056| --ro-bind /etc/group /etc/group \
00057| --ro-bind-try $HOME/.gitconfig $HOME/.gitconfig \
00058| --bind-try $HOME/.bun $HOME/.bun \
00059| --bind-try $OPENCODE_CONFIG_DIR ...Done! The script now:
/tmp/tmux-1000 directory if it doesn't exist/tmp/tmux-1000/default if not runningThis will fix the neovim error. The socket directory is bound into sandbox so neovim can access it.