Code Rooms
#!/usr/bin/env bash
set -euo pipefail
SELF_NAME="${0##*/}"
CURRENT_DIR="$(pwd -P)"
log() {
printf '[omx-bridge] %s\n' "$*" >&2
}
print_stdout_lines() {
local line
for line in "$@"; do
printf '%s\n' "$line"
done
print_stderr_lines() {
printf '%s\n' "$line" >&2
die() {
log "ERROR: $*"
exit 1
resolve_path_from() {
local base_dir="$1"
local target_path="$2"
case "$target_path" in
/*) printf '%s\n' "$target_path" ;;
*) printf '%s\n' "$base_dir/$target_path" ;;
esac
require_program() {
local program="$1"
if [[ "$program" == */* ]]; then
[[ -x "$program" ]] || die "Required executable not found: $program"
return 0
fi
command -v "$program" >/dev/null 2>&1 || die "Required executable not found in PATH: $program"
is_commit_like_ref() {
[[ "$1" =~ ^[0-9a-fA-F]{7,40}$ ]]
current_git_head() {
"$GIT_BIN" -C "$OMX_SOURCE_DIR" rev-parse HEAD 2>/dev/null || true
sync_omx_git_checkout() {
require_program "$GIT_BIN"
if [[ ! -d "$OMX_SOURCE_DIR/.git" ]]; then
rm -rf "$OMX_SOURCE_DIR"
log "Cloning upstream OMX from $OMX_REPO_URL"
"$GIT_BIN" clone --depth 1 "$OMX_REPO_URL" "$OMX_SOURCE_DIR"
log "Checking out upstream OMX ref $OMX_REPO_REF"
"$GIT_BIN" -C "$OMX_SOURCE_DIR" fetch --depth 1 origin "$OMX_REPO_REF"
"$GIT_BIN" -C "$OMX_SOURCE_DIR" checkout --detach FETCH_HEAD
normalize_lower_trimmed() {
printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]'
is_truthy() {
case "$(normalize_lower_trimmed "${1:-}")" in
1|true|yes|y|on)
;;
*)
return 1
detect_current_project_root() {
local detected_root=""
if command -v git >/dev/null 2>&1; then
detected_root="$(git -C "$CURRENT_DIR" rev-parse --show-toplevel 2>/dev/null || true)"
if [[ -n "$detected_root" ]]; then
printf '%s\n' "$detected_root"
else
printf '%s\n' "$CURRENT_DIR"
default_project_root_suggestion() {
local parent_dir
local project_name
parent_dir="$(dirname "$CURRENT_PROJECT_ROOT")"
project_name="$(basename "$CURRENT_PROJECT_ROOT")"
printf '%s\n' "$parent_dir/${project_name}-omx-workspace"
print_in_place_warning() {
local selected_root="$1"
print_stderr_lines \
"[omx-bridge] WARNING: OMX work root matches the current project root:" \
"[omx-bridge] $selected_root" \
"[omx-bridge] In-place mode may create or update:" \
"[omx-bridge] $selected_root/AGENTS.md" \
"[omx-bridge] $selected_root/.codex" \
"[omx-bridge] $selected_root/.omx" \
"[omx-bridge] $selected_root/.omx-codex-app-bridge" \
"[omx-bridge] Use a separate work root outside the current project unless you explicitly want OMX to manage this repo in place."
confirm_in_place_interactive() {
local response=""
print_in_place_warning "$selected_root"
printf '[omx-bridge] Continue in-place? [y/N]: ' >&2
IFS= read -r response || true
if is_truthy "$response"; then
die "In-place OMX root was not confirmed. Choose a separate --project-root outside the current project, or rerun with --in-place if intentional."
prompt_project_root() {
local suggested_root="$1"
"[omx-bridge] Choose where OMX should work." \
"[omx-bridge] Recommended default is a separate workspace outside the current project:" \
"[omx-bridge] $suggested_root" \
"[omx-bridge] If you point OMX at the current project root, it may create or update AGENTS.md, .codex, .omx, and .omx-codex-app-bridge there."
printf '[omx-bridge] OMX work root [%s]: ' "$suggested_root" >&2
printf '%s\n' "${response:-$suggested_root}"
resolve_requested_project_root() {
local selected_root=""
local raw_input=""
local from_prompt=0
if [[ -n "$CLI_PROJECT_ROOT" ]]; then
selected_root="$(resolve_path_from "$CURRENT_DIR" "$CLI_PROJECT_ROOT")"
elif is_truthy "$ALLOW_IN_PLACE"; then
selected_root="$CURRENT_PROJECT_ROOT"
elif [[ -t 0 && -t 1 ]]; then
raw_input="$(prompt_project_root "$DEFAULT_PROJECT_ROOT")"
selected_root="$(resolve_path_from "$CURRENT_DIR" "$raw_input")"
from_prompt=1
die "OMX_PROJECT_ROOT is required in non-interactive mode. Recommended isolated root: $DEFAULT_PROJECT_ROOT . If you intentionally want the current project root, rerun with --in-place or OMX_ALLOW_IN_PLACE=1."
if [[ "$selected_root" == "$CURRENT_PROJECT_ROOT" ]]; then
if is_truthy "$ALLOW_IN_PLACE"; then
elif [[ "$from_prompt" -eq 1 ]]; then
confirm_in_place_interactive "$selected_root"
ALLOW_IN_PLACE=1
die "Selected OMX work root matches the current project root: $selected_root . This may create or update AGENTS.md, .codex, .omx, and .omx-codex-app-bridge there. Re-run with --in-place or OMX_ALLOW_IN_PLACE=1 if intentional, or choose a separate --project-root outside the current project."
printf '%s\n' "$selected_root"
validate_openai_api_key() {
local raw_value="${OPENAI_API_KEY:-}"
local normalized
[[ -n "$raw_value" ]] || die "OPENAI_API_KEY is required for codex-login-api-key"
normalized="$(normalize_lower_trimmed "$raw_value")"
case "$normalized" in
""|none|null|undefined)
die "OPENAI_API_KEY must be a real API key. If your main Codex login uses a ChatGPT account session, use '$SELF_NAME codex-login-device' for the isolated project login."
timestamp() {
date '+%Y%m%d-%H%M%S'
record_invocation() {
local label="$1"
shift
mkdir -p "$RUNS_DIR"
local record_path="$RUNS_DIR/$(timestamp)-${label}.log"
{
printf 'label=%s\n' "$label"
printf 'current_project_root=%s\n' "$CURRENT_PROJECT_ROOT"
printf 'project_root=%s\n' "$PROJECT_ROOT"
printf 'omx_source_dir=%s\n' "$OMX_SOURCE_DIR"
printf 'codex_home=%s\n' "$PROJECT_CODEX_HOME"
printf 'in_place_mode=%s\n' "$IN_PLACE_MODE"
printf 'cwd=%s\n' "$(pwd)"
printf 'argv='
printf '%q ' "$@"
printf '\n'
} >"$record_path"
ensure_project_dirs() {
mkdir -p "$PROJECT_ROOT" "$PROJECT_CODEX_HOME" "$RUNTIME_ROOT" "$RUNS_DIR"
resolve_omx_entrypoint() {
local candidate
if [[ -n "${OMX_ENTRYPOINT:-}" ]]; then
candidate="$(resolve_path_from "$PROJECT_ROOT" "$OMX_ENTRYPOINT")"
[[ -f "$candidate" ]] || die "OMX_ENTRYPOINT does not exist: $candidate"
printf '%s\n' "$candidate"
for candidate in \
"$OMX_SOURCE_DIR/dist/cli/omx.js" \
"$OMX_SOURCE_DIR/bin/omx.js"
do
if [[ -f "$candidate" ]]; then
die "Could not find a local OMX entrypoint. Run '$SELF_NAME bootstrap' first."
local_codex_login_status() {
ensure_project_dirs
CODEX_HOME="$PROJECT_CODEX_HOME" "$CODEX_BIN" login status
ensure_local_codex_auth() {
if CODEX_HOME="$PROJECT_CODEX_HOME" "$CODEX_BIN" login status >/dev/null 2>&1; then
"[omx-bridge] No project-local Codex login found in:" \
"[omx-bridge] $PROJECT_CODEX_HOME" \
"[omx-bridge] To continue, use one of:" \
"[omx-bridge] $SELF_NAME codex-login-device" \
"[omx-bridge] OPENAI_API_KEY=... $SELF_NAME codex-login-api-key"
subcommand_requires_auth() {
case "${1:-}" in
""|exec|question|team|swarm)
bootstrap_omx() {
local update_existing=0
if [[ "${1:-}" == "--update" ]]; then
update_existing=1
[[ $# -eq 0 ]] || die "bootstrap accepts at most one flag: --update"
require_program "$NODE_BIN"
require_program "$NPM_BIN"
mkdir -p "$(dirname "$OMX_SOURCE_DIR")"
if [[ "$update_existing" -eq 1 ]]; then
record_invocation "bootstrap" "$SELF_NAME" bootstrap --update
record_invocation "bootstrap" "$SELF_NAME" bootstrap
if [[ -d "$OMX_SOURCE_DIR/.git" ]]; then
local current_head=""
current_head="$(current_git_head)"
log "Updating existing OMX checkout in $OMX_SOURCE_DIR"
sync_omx_git_checkout
elif is_commit_like_ref "$OMX_REPO_REF" && [[ "$current_head" == "$OMX_REPO_REF" ]]; then
log "Reusing existing OMX checkout at pinned ref $OMX_REPO_REF"
log "Aligning existing OMX checkout to upstream ref $OMX_REPO_REF"
elif [[ -f "$OMX_SOURCE_DIR/package.json" ]]; then
log "Reusing existing local OMX source directory: $OMX_SOURCE_DIR"
[[ -f "$OMX_SOURCE_DIR/package.json" ]] || die "OMX source directory is missing package.json: $OMX_SOURCE_DIR"
if [[ -f "$OMX_SOURCE_DIR/package-lock.json" ]]; then
log "Installing upstream OMX dependencies with npm ci --ignore-scripts"
(
cd "$OMX_SOURCE_DIR"
"$NPM_BIN" ci --ignore-scripts
)
log "Installing upstream OMX dependencies with npm install --ignore-scripts"
"$NPM_BIN" install --ignore-scripts
log "Building upstream OMX"
"$NPM_BIN" run build
log "Bootstrap complete"
run_local_omx() {
local entrypoint="$1"
record_invocation "omx" "$NODE_BIN" "$entrypoint" "$@"
cd "$PROJECT_ROOT"
CODEX_HOME="$PROJECT_CODEX_HOME" "$NODE_BIN" "$entrypoint" "$@"
print_status() {
local entrypoint=""
if entrypoint="$(resolve_omx_entrypoint 2>/dev/null)"; then
:
entrypoint="(not built yet)"
print_stdout_lines \
"current_project_root=$CURRENT_PROJECT_ROOT" \
"project_root=$PROJECT_ROOT" \
"in_place_mode=$IN_PLACE_MODE" \
"project_codex_home=$PROJECT_CODEX_HOME" \
"project_omx_dir=$PROJECT_OMX_DIR" \
"bridge_runtime_root=$RUNTIME_ROOT" \
"runs_dir=$RUNS_DIR" \
"omx_source_dir=$OMX_SOURCE_DIR" \
"omx_entrypoint=$entrypoint" \
"omx_repo_url=$OMX_REPO_URL" \
"omx_repo_ref=$OMX_REPO_REF"
if local_codex_login_status; then
log "Project-local Codex login is not configured yet"
print_help() {
"$SELF_NAME - Isolated bridge between Codex App sessions and upstream oh-my-codex" \
"" \
"Usage:" \
" $SELF_NAME [--project-root PATH] [--in-place] bootstrap [--update]" \
" $SELF_NAME [--project-root PATH] [--in-place] setup [omx-setup-args...]" \
" $SELF_NAME [--project-root PATH] [--in-place] doctor [omx-doctor-args...]" \
" $SELF_NAME [--project-root PATH] [--in-place] launch [omx-launch-args...]" \
" $SELF_NAME [--project-root PATH] [--in-place] launch-dangerous [omx-launch-args...]" \
" $SELF_NAME [--project-root PATH] [--in-place] exec [omx-exec-args...]" \
" $SELF_NAME [--project-root PATH] [--in-place] question [omx-question-args...]" \
" $SELF_NAME [--project-root PATH] [--in-place] omx [upstream-omx-args...]" \
" $SELF_NAME [--project-root PATH] [--in-place] status" \
" $SELF_NAME [--project-root PATH] [--in-place] codex-login-status" \
" $SELF_NAME [--project-root PATH] [--in-place] codex-login-device" \
" $SELF_NAME [--project-root PATH] [--in-place] codex-login-api-key" \
"Environment:" \
" OMX_PROJECT_ROOT OMX work root (required non-interactively unless --in-place is set)" \
" OMX_ALLOW_IN_PLACE Allow the current project root to be used as the OMX work root" \
" OMX_SOURCE_DIR Local OMX checkout (default: ./.omx-codex-app-bridge/vendor/oh-my-codex)" \
" OMX_REPO_URL Upstream OMX repo URL" \
" OMX_REPO_REF Upstream OMX commit, tag, or branch" \
" OMX_ENTRYPOINT Explicit OMX entrypoint override" \
" CODEX_BIN Codex CLI binary override" \
" NODE_BIN Node.js binary override" \
" NPM_BIN npm binary override" \
" GIT_BIN git binary override" \
" OPENAI_API_KEY Used only by codex-login-api-key" \
"Default safe behavior:" \
" - In TTY sessions, the wrapper asks where OMX should work and suggests a separate root:" \
" $DEFAULT_PROJECT_ROOT" \
" - In non-interactive mode, pass --project-root PATH (recommended) or --in-place explicitly."
warn_dangerous_launch() {
"[omx-bridge] WARNING: launch-dangerous uses upstream OMX with --madmax --high." \
"[omx-bridge] This may bypass Codex approvals and sandboxing inside the launched OMX session." \
"[omx-bridge] Keep using launch unless you explicitly want the dangerous upstream path."
CURRENT_PROJECT_ROOT="$(detect_current_project_root)"
DEFAULT_PROJECT_ROOT="$(default_project_root_suggestion)"
CLI_PROJECT_ROOT="${OMX_PROJECT_ROOT:-}"
ALLOW_IN_PLACE="${OMX_ALLOW_IN_PLACE:-0}"
OMX_REPO_URL="${OMX_REPO_URL:-https://github.com/Yeachan-Heo/oh-my-codex.git}"
OMX_REPO_REF="${OMX_REPO_REF:-d56148c2020454acb37082d251f9a6ee9dba9f82}"
CODEX_BIN="${CODEX_BIN:-codex}"
NODE_BIN="${NODE_BIN:-node}"
NPM_BIN="${NPM_BIN:-npm}"
GIT_BIN="${GIT_BIN:-git}"
while [[ $# -gt 0 ]]; do
case "$1" in
--project-root)
[[ $# -ge 2 ]] || die "--project-root requires a path"
CLI_PROJECT_ROOT="$2"
shift 2
--project-root=*)
CLI_PROJECT_ROOT="${1#*=}"
--in-place)
--)
break
COMMAND="${1:-help}"
if [[ $# -gt 0 ]]; then
if [[ "$COMMAND" != "help" && "$COMMAND" != "-h" && "$COMMAND" != "--help" ]]; then
PROJECT_ROOT="$(resolve_requested_project_root)"
RUNTIME_ROOT="$(resolve_path_from "$PROJECT_ROOT" "${OMX_BRIDGE_RUNTIME_DIR:-$PROJECT_ROOT/.omx-codex-app-bridge}")"
RUNS_DIR="$RUNTIME_ROOT/runs"
OMX_SOURCE_DIR="$(resolve_path_from "$PROJECT_ROOT" "${OMX_SOURCE_DIR:-$RUNTIME_ROOT/vendor/oh-my-codex}")"
PROJECT_CODEX_HOME="$PROJECT_ROOT/.codex"
PROJECT_OMX_DIR="$PROJECT_ROOT/.omx"
if [[ "$PROJECT_ROOT" == "$CURRENT_PROJECT_ROOT" ]]; then
IN_PLACE_MODE="true"
IN_PLACE_MODE="false"
PROJECT_ROOT=""
RUNTIME_ROOT=""
RUNS_DIR=""
OMX_SOURCE_DIR=""
PROJECT_CODEX_HOME=""
PROJECT_OMX_DIR=""
case "$COMMAND" in
help|-h|--help)
print_help
bootstrap)
bootstrap_omx "$@"
setup)
entrypoint="$(resolve_omx_entrypoint)"
run_local_omx "$entrypoint" setup --scope project "$@"
doctor)
run_local_omx "$entrypoint" doctor "$@"
launch)
ensure_local_codex_auth
if [[ $# -eq 0 ]]; then
run_local_omx "$entrypoint" --high
run_local_omx "$entrypoint" "$@"
launch-dangerous)
warn_dangerous_launch
run_local_omx "$entrypoint" --madmax --high
exec)
run_local_omx "$entrypoint" exec "$@"
question)
run_local_omx "$entrypoint" question "$@"
omx)
if subcommand_requires_auth "${1:-}"; then
status)
print_status
codex-login-status)
record_invocation "codex-login-status" "$CODEX_BIN" login status
local_codex_login_status
codex-login-device)
require_program "$CODEX_BIN"
record_invocation "codex-login-device" "$CODEX_BIN" login --device-auth
CODEX_HOME="$PROJECT_CODEX_HOME" "$CODEX_BIN" login --device-auth
codex-login-api-key)
validate_openai_api_key
record_invocation "codex-login-api-key" "$CODEX_BIN" login --with-api-key
printf '%s' "$OPENAI_API_KEY" | CODEX_HOME="$PROJECT_CODEX_HOME" "$CODEX_BIN" login --with-api-key
die "Unknown command: $COMMAND. Run '$SELF_NAME --help' for usage."