diff --git a/CLAUDE.md b/CLAUDE.md index 43aa48f..e7558db 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,7 +5,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Repository Overview This is a Docker base image for Coder workspaces, built on top of `codercom/enterprise-base:ubuntu`. It provides a comprehensive development environment with: -- Zsh shell with Zimfw framework and Oh My Posh prompt +- Zsh shell with Zimfw framework and Powerlevel10k prompt (Catppuccin lean/mocha theme) - Runtimes managed by mise (Node.js, Bun, Deno, Java) with pinned global defaults - Java (Temurin 21) via mise - Claude Code CLI @@ -52,7 +52,7 @@ The repository uses a two-phase Docker build with clear separation between root **Build Phases:** - **Phase 1 (Root)**: System packages, CLI tools (gh, gcloud), fonts, Docker, root-level tools -- **Phase 2 (Coder User)**: Development SDKs, Oh My Posh, Homebrew, Graphite CLI +- **Phase 2 (Coder User)**: Development SDKs, Zimfw modules + Powerlevel10k prompt, Homebrew, Graphite CLI **For detailed build phases, script organization, and configuration files, see [images/CLAUDE.md](images/CLAUDE.md)** @@ -71,7 +71,9 @@ GitHub Actions workflow at `.github/workflows/docker-publish.yml`: - mise is activated in `.zshrc` (`eval "$(mise activate zsh)"`); non-interactive shells resolve tools through `~/.local/share/mise/shims` - Flutter is NOT pre-baked (mise can install on demand: `mise use flutter@latest`) - Homebrew is installed for coder user at `/home/linuxbrew/.linuxbrew/` -- Oh My Posh is installed via official script (not Homebrew) to `~/.local/bin` +- Powerlevel10k and the Catppuccin theme are Zimfw modules declared in `images/base/.zimrc`; `install-prompt.sh` overwrites the Zimfw installer's default `.zimrc` with it and installs the modules +- `~/.p10k.zsh` is an override-only file layered on top of the Catppuccin theme selected via `zstyle ':catppuccin:p10k'` +- `.zshrc` reloads the Orca per-workspace `HISTFILE` (only when `ORCA_WORKSPACE_ID` is set) so past commands show up in history search and autosuggestions - Docker daemon must be started separately in Coder workspaces - All user scripts run as coder user, root scripts run as root - Scripts are copied to `/tmp/` and deleted after execution to minimize image size \ No newline at end of file diff --git a/README.md b/README.md index ae79d88..2150397 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A comprehensive Docker base image for [Coder](https://coder.com/) workspaces, bu ### Shell Environment - **Zsh** with [Zimfw](https://github.com/zimfw/zimfw) framework -- **Oh My Posh** for customizable prompt themes +- **Powerlevel10k** prompt with the Catppuccin (lean/mocha) theme - Vim mode, syntax highlighting, autosuggestions, and history search - Custom Nerd Fonts (MesloLGS NF, JetBrainsMono, D2Coding) @@ -102,7 +102,7 @@ All installation scripts are located in the `scripts/` directory: | `install-root-sdk.sh` | Qodana CLI, AWS CLI | root | | `install-docker.sh` | Docker Engine | root | | `install-sdk.sh` | fnm, SDKMAN, Bun, Deno, Claude Code, FVM | coder | -| `install-ohmyposh.sh` | Oh My Posh prompt | coder | +| `install-prompt.sh` | Zimfw modules (`.zimrc`), Powerlevel10k prompt, Orca history | coder | | `install-brew.sh` | Homebrew package manager | coder | | `install-graphite.sh` | Graphite CLI | coder | @@ -126,7 +126,7 @@ All installation scripts are located in the `scripts/` directory: ### Modifying Shell Configuration - **Zimfw modules**: Edit `.zimrc` -- **Oh My Posh theme**: Modify initialization in `scripts/install-ohmyposh.sh` +- **Prompt theme**: Change `zstyle ':catppuccin:p10k'` in `scripts/install-prompt.sh`, or add overrides to `.p10k.zsh` - **Environment variables**: Update `.zshenv` ## CI/CD @@ -146,7 +146,7 @@ Images are automatically built and published to GitHub Container Registry via Gi - **fnm vs nvm**: This image uses fnm instead of nvm. An alias `nvm="fnm"` is provided for compatibility - **Homebrew location**: Installed at `/home/linuxbrew/.linuxbrew/` -- **Oh My Posh**: Installed via official script to `~/.local/bin` +- **Powerlevel10k**: Installed as a Zimfw module; requires a Nerd Font in the client terminal - **Docker daemon**: Must be started separately in Coder workspaces - **Timezone**: Configured to `Asia/Seoul` diff --git a/images/CLAUDE.md b/images/CLAUDE.md index 3d852da..b53ca75 100644 --- a/images/CLAUDE.md +++ b/images/CLAUDE.md @@ -18,7 +18,7 @@ images/ ├── install-docker.sh # Docker Engine 설치 (Root) ├── install-orca.sh # Orca headless server (Root) ├── install-sdk.sh # 사용자 개발 도구 (mise 글로벌 런타임, Claude Code) - ├── install-ohmyposh.sh # Oh My Posh 프롬프트 + ├── install-prompt.sh # Zimfw 모듈 + Powerlevel10k 프롬프트 ├── install-brew.sh # Homebrew 패키지 매니저 └── install-graphite.sh # Graphite CLI (스택 PR) ``` @@ -34,7 +34,7 @@ images/ **쉘 및 프롬프트:** - Zsh (기본 쉘) - Zimfw (Zsh 플러그인 관리자) -- Oh My Posh (프롬프트 테마) +- Powerlevel10k (프롬프트, Catppuccin lean/mocha 테마) **개발 도구:** - mise (런타임 버전 매니저, apt로 시스템 설치) @@ -96,9 +96,10 @@ images/ - Claude Code CLI - `.zshrc`에 mise 활성화(`mise activate zsh`) 추가 -2. **프롬프트 설정** (`install-ohmyposh.sh`) - - Oh My Posh 공식 설치 스크립트 사용 - - `~/.local/bin`에 설치 (Homebrew 불필요) +2. **프롬프트 설정** (`install-prompt.sh`) + - 저장소의 `.zimrc`로 덮어쓴 뒤 Zimfw 모듈 설치 (Powerlevel10k, Catppuccin 테마 포함) + - `.zshrc` 맨 앞에 p10k instant prompt와 Catppuccin 테마 선택 추가 + - `.zshrc` 끝에 `~/.p10k.zsh` 로드와 Orca HISTFILE 재로딩 추가 3. **패키지 매니저** (`install-brew.sh`) - Homebrew 설치 (`/home/linuxbrew/.linuxbrew/`) @@ -125,7 +126,6 @@ Zimfw 초기화 및 zshrc 설정을 관리하는 메인 스크립트: - `update_zshrc_block()`: 기존 블록 업데이트 또는 새로 추가 - `add_header_block()`: Coder 설정 헤더 블록 추가 - Zimfw 모듈 설치 -- Oh My Posh 초기화 설정 **마커 시스템:** ```bash @@ -141,6 +141,7 @@ Zimfw 초기화 및 zshrc 설정을 관리하는 메인 스크립트: Zsh 환경 변수 파일: - `skip_global_compinit=1` 설정으로 글로벌 compinit 스킵 - 쉘 시작 속도 최적화 +- `~/.local/share/mise/shims`를 PATH 앞에 추가해 비대화형 셸에서도 mise 도구 사용 #### .zimrc @@ -214,12 +215,15 @@ Orca headless server 설치 ([가이드](https://github.com/amondnet/orca/blob/m > mise가 관리하는 node/npm 등을 사용하며, npm 전역 설치 후 `mise reshim`으로 > 새 실행파일(turbo, vercel, gt 등) shim을 생성한다. -#### install-ohmyposh.sh (Coder User) +#### install-prompt.sh (Coder User) -Oh My Posh 설치: -- 공식 설치 스크립트 사용 (Homebrew 불필요) -- 설치 위치: `~/.local/bin` -- bash로 실행 (공식 스크립트 요구사항) +Zimfw 모듈 구성과 Powerlevel10k 프롬프트 설정: +- `install-sdk.sh`가 Zimfw를 설치한 **뒤에** 실행해야 함. Zimfw 설치 스크립트는 기존 + `.zimrc` 앞에 기본 템플릿을 덧붙이므로, 설치 후 저장소의 `.zimrc`로 덮어쓰고 모듈을 설치한다 +- 테마는 `zstyle ':catppuccin:p10k'`(lean/mocha)로 선택하고, `~/.p10k.zsh`는 추가 override 전용 +- Orca가 워크스페이스별로 바꾸는 `HISTFILE`을 `fc -R`로 다시 읽어 과거 history를 복원 + (`ORCA_WORKSPACE_ID`가 있을 때만 동작) +- 클라이언트 터미널에 Nerd Font가 필요 #### install-brew.sh (Coder User) @@ -253,7 +257,7 @@ Graphite CLI 설치: **Coder User Phase:** 1. SDK (`install-sdk.sh`) - mise 글로벌 런타임(node/bun/deno/java), npm 전역 패키지, Claude Code -2. Oh My Posh (`install-ohmyposh.sh`) +2. 프롬프트 (`install-prompt.sh`) - Zimfw 설치 이후 3. Graphite (`install-graphite.sh`) - mise node(npm) 필요 4. Homebrew diff --git a/images/base/.p10k.zsh b/images/base/.p10k.zsh new file mode 100644 index 0000000..18cf92d --- /dev/null +++ b/images/base/.p10k.zsh @@ -0,0 +1,7 @@ +# zstyle(:catppuccin:p10k)로 선택된 테마(lean/mocha)는 +# catppuccin-powerlevel10k-themes 플러그인이 zsh 초기화 시 자동 적용한다. +# 이 파일은 그 위에 얹을 추가 커스터마이징 override 전용이다. 예: +# +# typeset -g POWERLEVEL9K_PROMPT_CHAR_OK_{VIINS,VICMD,VIVIS,VIOWR}_FOREGROUND=$P10K_COLOR_PEACH +# +# 수정 후에는 `source ~/.p10k.zsh` 로 다시 적용한다. diff --git a/images/base/.zimrc b/images/base/.zimrc index d19e576..9e11e82 100644 --- a/images/base/.zimrc +++ b/images/base/.zimrc @@ -30,6 +30,12 @@ zmodule utility # A heavily reduced, ASCII-only version of the Spaceship and Starship prompts. # zmodule asciiship +# Powerlevel10k. zsh 함수로 동작하고 git 상태는 gitstatusd 데몬에 비동기로 물어 +# 프롬프트를 블록하지 않는다. +zmodule romkatv/powerlevel10k +# Catppuccin 테마 (zstyle로 theme/flavour 선택, .zshrc에서 선언) +zmodule tolkonepiu/catppuccin-powerlevel10k-themes + # # Completion # diff --git a/images/base/.zshenv b/images/base/.zshenv index 33cf15f..08ac146 100644 --- a/images/base/.zshenv +++ b/images/base/.zshenv @@ -1 +1,6 @@ skip_global_compinit=1 + +# 비대화형 셸에서 mise 사용 (shims 방식 — mise 공식 권장) +# .zshenv는 중첩된 zsh마다 다시 읽히므로 PATH 중복을 제거한다. +typeset -gU path PATH +[ -d "$HOME/.local/share/mise/shims" ] && export PATH="$HOME/.local/share/mise/shims:$PATH" diff --git a/images/base/Dockerfile b/images/base/Dockerfile index 5ec6b84..258fee1 100644 --- a/images/base/Dockerfile +++ b/images/base/Dockerfile @@ -124,11 +124,12 @@ RUN chmod +x /tmp/install-sdk.sh && \ /usr/bin/zsh /tmp/install-sdk.sh && \ rm /tmp/install-sdk.sh -# Oh My Posh 설치 -COPY --chown=coder:coder scripts/install-ohmyposh.sh /tmp/install-ohmyposh.sh -RUN chmod +x /tmp/install-ohmyposh.sh && \ - /bin/bash /tmp/install-ohmyposh.sh && \ - rm /tmp/install-ohmyposh.sh +# Zimfw 모듈 및 Powerlevel10k 프롬프트 설정 +COPY --chown=coder:coder .zimrc .p10k.zsh /tmp/ +COPY --chown=coder:coder scripts/install-prompt.sh /tmp/install-prompt.sh +RUN chmod +x /tmp/install-prompt.sh && \ + /usr/bin/zsh /tmp/install-prompt.sh && \ + rm /tmp/install-prompt.sh /tmp/.zimrc /tmp/.p10k.zsh # Graphite CLI 설치 (npm 사용) COPY --chown=coder:coder scripts/install-graphite.sh /tmp/install-graphite.sh diff --git a/images/base/install.sh b/images/base/install.sh index b54c06e..db6c7bd 100644 --- a/images/base/install.sh +++ b/images/base/install.sh @@ -97,6 +97,3 @@ cp .zimrc ~/ zimfw install add_header_block -add_to_zshrc "on-my-posh" ' -eval "$(oh-my-posh init zsh)" -' \ No newline at end of file diff --git a/images/base/scripts/install-ohmyposh.sh b/images/base/scripts/install-ohmyposh.sh deleted file mode 100644 index a63e878..0000000 --- a/images/base/scripts/install-ohmyposh.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -echo "🎨 Installing Oh My Posh..." - -# Oh My Posh 설치 (공식 설치 스크립트 사용) -curl -s https://ohmyposh.dev/install.sh | bash -s - -# PATH 업데이트 -export PATH="$HOME/.local/bin:$PATH" - -# Oh My Posh 설치 확인 -if command -v oh-my-posh &> /dev/null; then - echo "✅ Oh My Posh installation completed!" - oh-my-posh --version -else - echo "❌ Oh My Posh installation failed!" - exit 1 -fi - -# Oh My Posh 초기화를 .zshrc에 추가 -echo '' >> ~/.zshrc -echo '# Oh My Posh initialization' >> ~/.zshrc -echo 'eval "$(oh-my-posh init zsh)"' >> ~/.zshrc - -echo "✅ Oh My Posh configuration added to .zshrc" \ No newline at end of file diff --git a/images/base/scripts/install-prompt.sh b/images/base/scripts/install-prompt.sh new file mode 100755 index 0000000..ec741a0 --- /dev/null +++ b/images/base/scripts/install-prompt.sh @@ -0,0 +1,69 @@ +#!/bin/zsh +set -e + +# Zimfw 모듈 구성과 Powerlevel10k(Catppuccin) 프롬프트 설정 +# install-sdk.sh가 Zimfw를 설치하고 기본 ~/.zshrc를 만든 뒤에 실행한다. + +ZIM_HOME=${HOME}/.zim + +echo "🎨 Configuring Zimfw modules and Powerlevel10k prompt..." + +# Zimfw 설치 스크립트는 기존 .zimrc 앞에 기본 템플릿을 덧붙이므로, +# 설치가 끝난 뒤에 저장소의 .zimrc로 덮어쓰고 모듈을 설치한다. +cp /tmp/.zimrc ~/.zimrc +cp /tmp/.p10k.zsh ~/.p10k.zsh +source ${ZIM_HOME}/zimfw.zsh install -q + +# Powerlevel10k instant prompt와 테마 선택은 .zshrc 맨 앞에 둔다. +# instant prompt 블록보다 위에서는 표준 입출력에 접근하는 코드를 두지 않는다. +# ~/.zshrc(Zimfw 초기화 포함)는 install-sdk.sh가 만든다. 없으면 테마가 로드되지 않는 +# .zshrc가 만들어지므로 빌드를 멈춘다. +[[ -f ~/.zshrc ]] || { echo "❌ ~/.zshrc not found; install-sdk.sh (Zimfw) must run first" >&2; exit 1; } +{ + cat <<'EOF' +# Powerlevel10k instant prompt. 초기화가 끝나기 전에 캐시된 프롬프트를 먼저 그린다. +# 이 블록보다 위에서는 표준 입출력에 접근하는 코드를 두지 않는다. +if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then + source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" +fi + +# Catppuccin p10k 테마 선택. tolkonepiu/catppuccin-powerlevel10k-themes 플러그인이 +# 모듈 로드 시 이 값을 읽어 자동으로 apply_catppuccin을 호출한다. +zstyle ':catppuccin:p10k' 'theme' 'lean' +zstyle ':catppuccin:p10k' 'flavour' 'mocha' + +EOF + cat ~/.zshrc +} > ~/.zshrc.tmp +mv ~/.zshrc.tmp ~/.zshrc + +cat >> ~/.zshrc <<'EOF' + +# ~/.p10k.zsh는 Catppuccin 테마 위에 얹는 추가 커스터마이징 override용 +[[ -r ~/.p10k.zsh ]] && source ~/.p10k.zsh + +# +# Orca: 워크스페이스별 HISTFILE 로딩 +# +# Orca는 워크스페이스마다 별도 history 파일을 두고, 사용자 .zshrc가 끝난 뒤 +# 첫 프롬프트에서 HISTFILE을 그 파일로 바꾼다. zsh는 HISTFILE을 바꿔도 새 파일의 +# 기존 내용을 다시 읽지 않으므로, 이전 세션에 남긴 명령이 위/아래 화살표·substring +# search(메모리 history를 검색)에 안 잡힌다. Orca가 HISTFILE을 바꾼 직후 그 파일을 +# 한 번 fc -R로 읽어들여 과거 history를 복원한다. +if [[ -n $ORCA_WORKSPACE_ID ]]; then + # .zshrc를 다시 source해도 이미 로드한 파일을 다시 읽지 않도록 기존 값을 유지한다. + typeset -g _orca_loaded_histfile="${_orca_loaded_histfile-}" + autoload -Uz add-zsh-hook + _orca_load_histfile() { + [[ "$HISTFILE" == "$_orca_loaded_histfile" ]] && return + # 아직 파일이 없으면 다음 프롬프트에서 다시 시도한다. 이 세션이 쓴 명령을 + # 다시 읽게 되어도 Zimfw environment 모듈의 HIST_IGNORE_ALL_DUPS가 중복을 없앤다. + [[ -r "$HISTFILE" ]] || return 0 + _orca_loaded_histfile=$HISTFILE + fc -R "$HISTFILE" 2>/dev/null + } + add-zsh-hook precmd _orca_load_histfile +fi +EOF + +echo "✅ Powerlevel10k prompt configuration completed!"