# Bun shell migration plan

Practical phased replacement of Bun `$` calls.

## Goal

Replace runtime Bun shell template-tag usage in `packages/opencode/src` with a unified `Process` API in `util/process.ts`.

Keep behavior stable while improving safety, testability, and observability.

Current baseline from audit:

- 143 runtime command invocations across 17 files
- 84 are git commands
- Largest hotspots:
  - `src/cli/cmd/github.ts` (33)
  - `src/worktree/index.ts` (22)
  - `src/lsp/server.ts` (21)
  - `src/installation/index.ts` (20)
  - `src/snapshot/index.ts` (18)

## Decisions

- Extend `src/util/process.ts` (do not create a separate exec module).
- Proceed with phased migration for both git and non-git paths.
- Keep plugin `$` compatibility in 1.x and remove in 2.0.

## Non-goals

- Do not remove plugin `$` compatibility in this effort.
- Do not redesign command semantics beyond what is needed to preserve behavior.

## Constraints

- Keep migration phased, not big-bang.
- Minimize behavioral drift.
- Keep these explicit shell-only exceptions:
  - `src/session/prompt.ts` raw command execution
  - worktree start scripts in `src/worktree/index.ts`

## Process API proposal (`src/util/process.ts`)

Add higher-level wrappers on top of current spawn support.

Core methods:

- `Process.run(cmd, opts)`
- `Process.text(cmd, opts)`
- `Process.lines(cmd, opts)`
- `Process.status(cmd, opts)`
- `Process.shell(command, opts)` for intentional shell execution

Git helpers:

- `Process.git(args, opts)`
- `Process.gitText(args, opts)`

Shared options:

- `cwd`, `env`, `stdin`, `stdout`, `stderr`, `abort`, `timeout`, `kill`
- `allowFailure` / non-throw mode
- optional redaction + trace metadata

Standard result shape:

- `code`, `stdout`, `stderr`, `duration_ms`, `cmd`
- helpers like `text()` and `arrayBuffer()` where useful

## Phased rollout

### Phase 0: Foundation

- Implement Process wrappers in `src/util/process.ts`.
- Refactor `src/util/git.ts` to use Process only.
- Add tests for exit handling, timeout, abort, and output capture.

### Phase 1: High-impact hotspots

Migrate these first:

- `src/cli/cmd/github.ts`
- `src/worktree/index.ts`
- `src/lsp/server.ts`
- `src/installation/index.ts`
- `src/snapshot/index.ts`

Within each file, migrate git paths first where applicable.

### Phase 2: Remaining git-heavy files

Migrate git-centric call sites to `Process.git*` helpers:

- `../core/src/filesystem.ts`
- `src/project/vcs.ts`
- `../core/src/filesystem/watcher.ts`
- `src/storage/storage.ts`
- `src/cli/cmd/pr.ts`

### Phase 3: Remaining non-git files

Migrate residual non-git usages:

- `src/cli/cmd/tui/util/clipboard.ts`
- `src/util/archive.ts`
- `../core/src/filesystem/ripgrep.ts`
- `src/tool/bash.ts`
- `src/cli/cmd/uninstall.ts`

### Phase 4: Stabilize

- Remove dead wrappers and one-off patterns.
- Keep plugin `$` compatibility isolated and documented as temporary.
- Create linked 2.0 task for plugin `$` removal.

## Validation strategy

- Unit tests for new `Process` methods and options.
- Integration tests on hotspot modules.
- Smoke tests for install, snapshot, worktree, and GitHub flows.
- Regression checks for output parsing behavior.

## Risk mitigation

- File-by-file PRs with small diffs.
- Preserve behavior first, simplify second.
- Keep shell-only exceptions explicit and documented.
- Add consistent error shaping and logging at Process layer.

## Definition of done

- Runtime Bun `$` usage in `packages/opencode/src` is removed except:
  - approved shell-only exceptions
  - temporary plugin compatibility path (1.x)
- Git paths use `Process.git*` consistently.
- CI and targeted smoke tests pass.
- 2.0 issue exists for plugin `$` removal.
