Utoljára aktív 1 week ago

Cross-platform Zsh setup scripts and managed dotfiles with Oh My Zsh framework, Starship prompt, aliases, functions, and path configuration.

Revízió 12179e0de4c9b1ab5e8e64959145cd05bd65ca94

README.md Eredeti

Bash Script Installer for Zsh

The "Bash Script Installer" simplifies the setup of Zsh.

Zsh

Ubuntu

bash -c "$(curl -fsSL https://tinyurl.com/y6fhb594)"

WSL

bash -c "$(curl -fsSL https://tinyurl.com/ycyct6wp)"

MacOS

bash -c "$(curl -fsSL https://tinyurl.com/yptybtpa)"

Configuration

bash -c "$(curl -fsSL https://tinyurl.com/y8vf753j)"

Shell framework and prompt

The installers use Oh My Zsh for framework features and plugins, with the OMZ theme disabled:

ZSH_THEME=""
source "$ZSH/oh-my-zsh.sh"
eval "$(starship init zsh)"

Starship owns the prompt and loads after Oh My Zsh. The managed Starship config is installed at ~/.config/starship.toml. A Nerd Font is required for the Powerline symbols.

Plan-build workflow

The local plan_build function is a thin cached launcher for the canonical public plan-build gist. When curl is available, each invocation stages plan_build.zsh, SKILL.md, and ARCHITECT.md, requires all three to be non-empty, and syntax-checks the executable. It then moves the complete bundle into a unique immutable release directory and atomically switches one current symlink. Refresh activation is serialized with a kernel-backed Zsh file lock so concurrent callers cannot mix releases and crashes cannot leave a stale lock. If refresh fails, the launcher preserves and uses the last complete, validated release and repairs its skill links. Zsh is always required; curl is required only when no valid cached release exists.

plan_build
plan_build --prompt
plan_build --writing-plan
plan_build --prompt --brainstorm
plan_build --yolo --writing-plan
plan_build --architect
plan_build --architect --new
plan_build --architect --yolo

The canonical executable defines the current command behavior and options. Each invocation binds the executable and both skills to its selected immutable release. The launcher also points the installed Claude Code skill paths through the active current release:

  • SKILL.md~/.claude/skills/plan-build/SKILL.md
  • ARCHITECT.md~/.claude/skills/plan-build-architect/SKILL.md

The launcher defaults to https://opengist.resetrix.work/weehong/plan-build/raw/HEAD and ${XDG_CACHE_HOME:-$HOME/.cache}/plan-build. Override these with PLAN_BUILD_BASE_URL and PLAN_BUILD_CACHE_DIR. Installed skill paths remain fixed at ~/.claude/skills; cached invocations receive immutable release paths through environment variables. The downloaded script is remote executable code: syntax validation catches malformed Zsh but is not a security sandbox, so only point PLAN_BUILD_BASE_URL at a source you trust. Remote code is executed in a child Zsh process and is never sourced into the caller shell.

Invoking plan_build once installs or repairs both skill links. To install standalone files without the cached launcher, follow the installation instructions in the canonical gist instead.

alias Eredeti
1# =============================================================================
2# OS-SPECIFIC ALIASES
3# =============================================================================
4if [[ "$OSTYPE" == "linux-gnu"* ]] && command -v apt-get >/dev/null 2>&1; then
5 # Linux Only System update & cleanup
6 alias uu='sudo apt-get update && \
7 sudo apt-get upgrade -y && \
8 sudo apt-get full-upgrade -y && \
9 sudo apt-get autoremove -y && \
10 sudo apt-get autoclean -y && \
11 sudo apt-get clean'
12elif [[ "$OSTYPE" == "darwin"* ]]; then
13 # macOS Only
14 alias flushdns='sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder'
15fi
16
17# =============================================================================
18# UNIVERSAL GIT ALIASES (Fixed: Removed broken "$@" from aliases)
19# =============================================================================
20alias gph='git push'
21alias gco='git checkout'
22alias gbh='git branch'
23alias gmt='git commit'
24alias gpl='git pull'
25alias grb='git rebase'
26alias grt='git reset'
27alias gst='git status'
28alias grmrf='git checkout -- . && git clean -fd'
config.sh Eredeti
1#!/bin/bash
2set -euo pipefail
3
4# Configuration
5GIST_RAW_BASE="https://opengist.resetrix.work/weehong/f0d940c3c1214bf5b7996195199fdc09/raw/HEAD"
6CONFIG_FILES=(
7 ".alias"
8 ".func"
9 ".pathrc"
10 ".sourcerc"
11 ".vimrc"
12 ".zshrc"
13 ".config/starship.toml"
14)
15
16echo "Starting configuration download..."
17download_failed=0
18
19for f in "${CONFIG_FILES[@]}"; do
20 # Remove the leading dot for the URL path
21 remote_name="${f#.}"
22 [[ "$f" == ".config/starship.toml" ]] && remote_name="starship.toml"
23 url="$GIST_RAW_BASE/$remote_name"
24 target="$HOME/$f"
25 tmp="${target}.tmp.$$"
26
27 echo "Downloading $f..."
28 mkdir -p "$(dirname "$target")"
29
30 # Use -f to fail silently on server errors, -s for silent, -L to follow redirects
31 if curl -fsSL "$url" -o "$tmp" && mv "$tmp" "$target"; then
32 echo "Successfully updated $target"
33 else
34 rm -f "$tmp"
35 echo "Error: Failed to download $f from $url" >&2
36 download_failed=1
37 fi
38done
39
40if [ "$download_failed" -ne 0 ]; then
41 echo "Configuration download completed with errors." >&2
42 exit 1
43fi
44
45echo "Done! All configuration files have been replaced."
46
func Eredeti
1# =============================================================================
2# CUSTOM FUNCTIONS
3# =============================================================================
4
5# -----------------------------------------------------------------------------
6# Function: funcs (List available .func functions)
7# -----------------------------------------------------------------------------
8funcs() {
9 local func_file="${1:-$HOME/.func}"
10
11 if [ ! -f "$func_file" ]; then
12 printf "Error: Function file '%s' not found.\n" "$func_file" >&2
13 return 1
14 fi
15
16 printf "Available functions in %s:\n" "$func_file"
17 awk '
18 /^# Function: / {
19 line = $0
20 sub(/^# Function: /, "", line)
21
22 name = line
23 sub(/ .*/, "", name)
24
25 desc = ""
26 if (line ~ / \(.+\)$/) {
27 desc = line
28 sub(/^[^ ]+ \(/, "", desc)
29 sub(/\)$/, "", desc)
30 }
31
32 if (desc != "") {
33 printf " %-22s %s\n", name, desc
34 } else {
35 printf " %s\n", name
36 }
37 }
38 ' "$func_file"
39}
40
41# -----------------------------------------------------------------------------
42# Function: clip (Cross-platform clipboard)
43# -----------------------------------------------------------------------------
44clip() {
45 local cmd
46 local args=()
47
48 if command -v pbcopy >/dev/null 2>&1; then
49 cmd="pbcopy" # macOS
50 elif grep -qi "microsoft" /proc/version 2>/dev/null && command -v clip.exe >/dev/null 2>&1; then
51 cmd="clip.exe" # WSL
52 elif [ "$XDG_SESSION_TYPE" = "wayland" ] && command -v wl-copy >/dev/null 2>&1; then
53 cmd="wl-copy" # Linux Wayland
54 elif command -v xclip >/dev/null 2>&1; then
55 cmd="xclip" # Linux X11 (Fallback 1)
56 args=("-selection" "clipboard")
57 elif command -v xsel >/dev/null 2>&1; then
58 cmd="xsel" # Linux X11 (Fallback 2)
59 args=("--clipboard" "--input")
60 else
61 printf "Error: No supported clipboard utility found.\n" >&2
62 return 1
63 fi
64
65 if [ $# -gt 0 ]; then
66 if [ -f "$1" ]; then
67 "$cmd" "${args[@]}" < "$1"
68 echo "Copied contents of '$1' to clipboard."
69 else
70 printf "Error: File '%s' not found.\n" "$1" >&2
71 return 1
72 fi
73 else
74 "$cmd" "${args[@]}"
75 fi
76}
77
78# -----------------------------------------------------------------------------
79# Function: open_file (Cross-platform file/directory opener)
80# -----------------------------------------------------------------------------
81open_file() {
82 local target="${1:-.}"
83
84 if [[ "$OSTYPE" == "darwin"* ]]; then
85 command open "$target"
86 elif grep -qi "microsoft" /proc/version 2>/dev/null; then
87 if command -v wslpath >/dev/null 2>&1 && command -v explorer.exe >/dev/null 2>&1; then
88 explorer.exe "$(wslpath -w "$target")"
89 else
90 printf "Error: 'wslpath' or 'explorer.exe' not found.\n" >&2
91 return 1
92 fi
93 elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
94 if command -v xdg-open >/dev/null 2>&1; then
95 xdg-open "$target"
96 else
97 printf "Error: 'xdg-open' not found.\n" >&2
98 return 1
99 fi
100 fi
101}
102alias open='open_file'
103
104# -----------------------------------------------------------------------------
105# Function: clear_history (Supports shell, Claude, Codex, and OpenCode)
106# -----------------------------------------------------------------------------
107clear_history() {
108 case "${1:-}" in
109 claude)
110 if [ -d "$HOME/.claude/projects" ]; then
111 # Use 'yes' to skip prompts and -f to ignore non-existent files
112 yes | rm -rf "$HOME/.claude/projects"/*
113 echo "Claude project history/cache cleared."
114 fi
115 ;;
116
117 codex)
118 local codex_home="${CODEX_HOME:-$HOME/.codex}"
119 local codex_session_file
120 local codex_session_id
121
122 mkdir -p "$codex_home"
123 : > "$codex_home/history.jsonl"
124
125 if command -v codex >/dev/null 2>&1; then
126 find "$codex_home/sessions" "$codex_home/archived_sessions" -type f -name '*.jsonl' -print 2>/dev/null | while IFS= read -r codex_session_file; do
127 codex_session_id="$(sed -n 's/.*"session_id":"\([^"]*\)".*/\1/p; q' "$codex_session_file")"
128 if [ -n "$codex_session_id" ]; then
129 codex delete --force "$codex_session_id" >/dev/null 2>&1 || true
130 fi
131 done
132 fi
133
134 rm -rf "$codex_home/sessions" "$codex_home/archived_sessions" "$codex_home/shell_snapshots"
135 mkdir -p "$codex_home/sessions" "$codex_home/archived_sessions" "$codex_home/shell_snapshots"
136
137 echo "Codex history cleared."
138 ;;
139
140 opencode)
141 local opencode_state_home="${XDG_STATE_HOME:-$HOME/.local/state}/opencode"
142 local opencode_data_home="${XDG_DATA_HOME:-$HOME/.local/share}/opencode"
143
144 mkdir -p "$opencode_state_home" "$opencode_data_home"
145 : > "$opencode_state_home/prompt-history.jsonl"
146 rm -f \
147 "$opencode_data_home/opencode.db" \
148 "$opencode_data_home/opencode.db-shm" \
149 "$opencode_data_home/opencode.db-wal"
150 rm -rf "$opencode_data_home/repos" "$opencode_data_home/log"
151 mkdir -p "$opencode_data_home/repos" "$opencode_data_home/log"
152
153 echo "OpenCode history cleared."
154 ;;
155
156 *)
157 # 1. Truncate the file
158 : > "$HISTFILE"
159
160 # 2. Clear RAM by briefly setting history size to 0
161 local old_histsize=$HISTSIZE
162 HISTSIZE=0
163 HISTSIZE=$old_histsize
164
165 echo "Shell history cleared."
166 ;;
167 esac
168}
169
170# -----------------------------------------------------------------------------
171# Function: require_cli (Check external CLI availability)
172# -----------------------------------------------------------------------------
173require_cli() {
174 local binary="$1"
175 local label="$2"
176 local resolved
177
178 if command -v whence >/dev/null 2>&1; then
179 if whence -p "$binary" >/dev/null 2>&1; then
180 return 0
181 fi
182 else
183 resolved="$(command -v "$binary" 2>/dev/null)" || resolved=""
184 if [ -n "$resolved" ] && [ -x "$resolved" ]; then
185 return 0
186 fi
187 fi
188
189 printf "Error: %s ('%s') is not installed or not in your PATH.\n" "$label" "$binary" >&2
190 return 1
191}
192
193# -----------------------------------------------------------------------------
194# Function: claude (Includes --yolo and clear shortcuts)
195# -----------------------------------------------------------------------------
196claude() {
197 # Shortcut for clearing cache
198 if [[ "$1" == "clear" ]]; then
199 clear_history claude
200 return 0
201 fi
202
203 # Check if binary exists
204 require_cli claude "Claude Code CLI" || return 1
205
206 # Handle --yolo mode
207 if [[ "$1" == "--yolo" ]]; then
208 shift
209 command claude --dangerously-skip-permissions "$@"
210 return $?
211 fi
212
213 command claude "$@"
214}
215
216# -----------------------------------------------------------------------------
217# Internal: _prompt_confirm_indexing (Confirm project indexing via the terminal)
218# -----------------------------------------------------------------------------
219_prompt_confirm_indexing() {
220 local project_root="$1"
221 local reply
222
223 if ! (: </dev/tty) 2>/dev/null; then
224 printf "Notice: No interactive terminal available; enhancing without project indexing.\n" >&2
225 return 1
226 fi
227
228 printf "Allow Auggie to index and use project context from '%s'? (y/N) " "$project_root" >/dev/tty
229 if ! IFS= read -r reply </dev/tty; then
230 printf "\nNotice: Unable to read confirmation; enhancing without project indexing.\n" >&2
231 return 1
232 fi
233
234 case "$reply" in
235 y|Y|yes|YES|Yes)
236 return 0
237 ;;
238 *)
239 return 1
240 ;;
241 esac
242}
243
244# -----------------------------------------------------------------------------
245# Internal: _enhance_prompt (Run Auggie and write only the enhanced prompt)
246# -----------------------------------------------------------------------------
247_enhance_prompt() {
248 local prompt="$1"
249 local output_file="$2"
250 local run_dir
251 local prompt_file
252 local workspace
253 local cache_dir
254 local auth_file
255 local log_file
256 local parsed_file
257 local project_root
258 local use_project_context
259 local script_pid
260 local waited
261 local timeout_seconds
262 local monitor_status
263
264 if [ -z "$prompt" ]; then
265 printf "Error: Prompt was empty.\n" >&2
266 return 1
267 fi
268
269 if [ ! -s "$HOME/.augment/session.json" ]; then
270 printf "Error: Auggie session file not found. Run 'auggie login' first.\n" >&2
271 return 1
272 fi
273
274 run_dir="$(mktemp -d "${TMPDIR:-/tmp}/auggie-enhance.XXXXXX")" || return 1
275 prompt_file="$run_dir/prompt.txt"
276 workspace="$run_dir/workspace"
277 cache_dir="$run_dir/cache"
278 auth_file="$HOME/.augment/session.json"
279 log_file="$run_dir/auggie.log"
280 parsed_file="$run_dir/enhanced.txt"
281 mkdir -p "$workspace" "$cache_dir"
282 printf "%s\n" "$prompt" > "$prompt_file"
283
284 project_root="$(git rev-parse --show-toplevel 2>/dev/null)" || project_root="$PWD"
285 use_project_context=0
286 timeout_seconds=90
287
288 if _prompt_confirm_indexing "$project_root"; then
289 use_project_context=1
290 timeout_seconds=300
291 workspace="$project_root"
292 cache_dir="$HOME/.augment"
293 printf "Indexing approved; enhancing with project context from '%s'.\n" "$project_root" >&2
294 else
295 printf "Enhancing without project indexing.\n" >&2
296 fi
297
298 (
299 if [ "$use_project_context" -eq 1 ]; then
300 AUGGIE_PROMPT_FILE="$prompt_file" \
301 AUGGIE_WORKSPACE="$workspace" \
302 AUGGIE_CACHE_DIR="$cache_dir" \
303 AUGGIE_AUTH_FILE="$auth_file" \
304 script -q -f -O "$log_file" -c 'auggie --print --enhance-prompt --workspace-root "$AUGGIE_WORKSPACE" --augment-cache-dir "$AUGGIE_CACHE_DIR" --augment-session-json "$AUGGIE_AUTH_FILE" --allow-indexing --wait-for-indexing --dont-save-session --instruction-file "$AUGGIE_PROMPT_FILE"' </dev/null >/dev/null 2>&1 &
305 else
306 AUGGIE_PROMPT_FILE="$prompt_file" \
307 AUGGIE_WORKSPACE="$workspace" \
308 AUGGIE_CACHE_DIR="$cache_dir" \
309 AUGGIE_AUTH_FILE="$auth_file" \
310 script -q -f -O "$log_file" -c 'auggie --print --enhance-prompt --no-discover-workspaces --workspace-root "$AUGGIE_WORKSPACE" --augment-cache-dir "$AUGGIE_CACHE_DIR" --augment-session-json "$AUGGIE_AUTH_FILE" --dont-save-session --instruction-file "$AUGGIE_PROMPT_FILE"' </dev/null >/dev/null 2>&1 &
311 fi
312
313 script_pid=$!
314 waited=0
315
316 while kill -0 "$script_pid" >/dev/null 2>&1; do
317 if grep -aq "🤖" "$log_file" 2>/dev/null || grep -aq "Tool call:" "$log_file" 2>/dev/null; then
318 kill "$script_pid" >/dev/null 2>&1 || true
319 wait "$script_pid" >/dev/null 2>&1 || true
320 exit 0
321 fi
322
323 if [ "$waited" -ge "$timeout_seconds" ]; then
324 kill "$script_pid" >/dev/null 2>&1 || true
325 wait "$script_pid" >/dev/null 2>&1 || true
326 exit 124
327 fi
328
329 sleep 1
330 waited=$((waited + 1))
331 done
332
333 wait "$script_pid" >/dev/null 2>&1 || true
334 exit 0
335 )
336 monitor_status=$?
337
338 if [ "$monitor_status" -eq 124 ]; then
339 printf "Error: Timed out waiting for Auggie to enhance the prompt.\n" >&2
340 rm -rf "$run_dir"
341 return 124
342 fi
343
344 perl -ne '
345 # Auggie redraws streamed terminal lines with carriage returns. Keep only
346 # the final rendered segment so stale text cannot corrupt the prompt.
347 s/\r$//;
348 s/.*\r//;
349 1 while s/[^\x08]\x08//g;
350 s/\x08//g;
351 s/\e\][^\a]*(?:\a|\e\\)//g;
352 s/\e\[[0-?]*[ -\/]*[@-~]//g;
353 next if /Script started on/ || /Script done on/;
354 if (/^(?:✨\s*)?Enhanced prompt:\s*(.*)$/) {
355 $capturing = 1;
356 $output .= "$1\n" if length $1;
357 next;
358 }
359 next unless $capturing;
360 exit if /^🤖/ || /Tool call:/ || /Session terminated/;
361 $output .= $_;
362 END {
363 $output =~ s/^\s*\n//;
364 $output =~ s/\s+\z//;
365 print "$output\n" if length $output;
366 }
367 ' "$log_file" > "$parsed_file"
368
369 if [ ! -s "$parsed_file" ]; then
370 printf "Error: Auggie did not return an enhanced prompt.\n" >&2
371 rm -rf "$run_dir"
372 return 1
373 fi
374
375 if ! command cp "$parsed_file" "$output_file"; then
376 printf "Error: Unable to save the enhanced prompt.\n" >&2
377 rm -rf "$run_dir"
378 return 1
379 fi
380 rm -rf "$run_dir"
381}
382
383# -----------------------------------------------------------------------------
384# Function: prompt (Enhance a prompt with Auggie and optional project context)
385# -----------------------------------------------------------------------------
386prompt() {
387 local prompt
388 local line
389 local output_file
390
391 require_cli auggie "Auggie CLI" || return 1
392 require_cli script "script utility" || return 1
393
394 if [ $# -gt 0 ]; then
395 prompt="$*"
396 elif [ ! -t 0 ]; then
397 prompt="$(cat)"
398 else
399 echo "Reading prompt... Type 'EOF' on a new line and press Enter when finished."
400 prompt=""
401
402 while IFS= read -r line; do
403 [ "$line" = "EOF" ] && break
404 if [ -z "$prompt" ]; then
405 prompt="$line"
406 else
407 prompt="${prompt}"$'\n'"${line}"
408 fi
409 done
410 fi
411
412 if [ -z "$prompt" ]; then
413 printf "Error: Prompt was empty.\n" >&2
414 return 1
415 fi
416
417 output_file="$(mktemp "${TMPDIR:-/tmp}/auggie-enhanced-prompt.XXXXXX")" || return 1
418 if ! _enhance_prompt "$prompt" "$output_file"; then
419 rm -f "$output_file"
420 return 1
421 fi
422
423 printf "Enhanced prompt:\n"
424 command cat "$output_file"
425 rm -f "$output_file"
426
427 command auggie account status
428}
429
430# -----------------------------------------------------------------------------
431# Function: plan_build (Cached canonical plan-build launcher)
432# -----------------------------------------------------------------------------
433plan_build() {
434 emulate -L zsh
435 setopt localtraps
436 local base_url="${PLAN_BUILD_BASE_URL:-https://opengist.resetrix.work/weehong/plan-build/raw/HEAD}"
437 local cache_dir="${PLAN_BUILD_CACHE_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/plan-build}"
438 local curl_command="${PLAN_BUILD_CURL_COMMAND:-curl}"
439 local skill_file="$HOME/.claude/skills/plan-build/SKILL.md"
440 local architect_file="$HOME/.claude/skills/plan-build-architect/SKILL.md"
441 local stage_dir="" release_dir="" current_tmp=""
442 local skill_tmp="" architect_tmp="" skill_backup="" architect_backup=""
443 local activation_lock="$cache_dir/.activate.lock"
444 local activation_lock_fd=""
445 local selected_release="" active_pid="" refresh_rc=1 call_rc=0 interrupted_rc=0
446
447 if ! zmodload zsh/system 2>/dev/null; then
448 printf "Error: Unable to load the Zsh system module required by plan-build.\n" >&2
449 return 1
450 fi
451
452 require_cli zsh "Zsh" || return 1
453
454 if ! command mkdir -p "$cache_dir" "${skill_file:h}" "${architect_file:h}"; then
455 printf "Error: Unable to create plan-build cache or skill directories.\n" >&2
456 return 1
457 fi
458
459 _plan_build_cleanup() {
460 if [[ -n "${active_pid:-}" ]] && command kill -0 "$active_pid" 2>/dev/null; then
461 command kill "$active_pid" 2>/dev/null || true
462 wait "$active_pid" 2>/dev/null || true
463 fi
464 active_pid=""
465 [[ -n "$stage_dir" && -d "$stage_dir" ]] && command rm -rf -- "$stage_dir"
466 command rm -f -- "$current_tmp" "$skill_tmp" "$architect_tmp"
467 command rm -f -- "$skill_backup" "$architect_backup"
468 if [[ -n "${activation_lock_fd:-}" ]]; then
469 zsystem flock -u "$activation_lock_fd" 2>/dev/null || true
470 activation_lock_fd=""
471 fi
472 }
473 _plan_build_cancel() {
474 interrupted_rc="$1"
475 [[ -n "${active_pid:-}" ]] && command kill "$active_pid" 2>/dev/null || true
476 }
477 trap '_plan_build_cleanup' EXIT
478 trap '_plan_build_cancel 129' HUP
479 trap '_plan_build_cancel 130' INT
480 trap '_plan_build_cancel 143' TERM
481
482 _plan_build_validate_release() {
483 local candidate="$1"
484 [[ -d "$candidate" &&
485 -s "$candidate/plan_build.zsh" &&
486 -s "$candidate/SKILL.md" &&
487 -s "$candidate/ARCHITECT.md" ]] &&
488 command zsh -n "$candidate/plan_build.zsh"
489 }
490
491 _plan_build_replace_path() {
492 local replacement="$1" destination="$2"
493 if command mv -fT "$replacement" "$destination" 2>/dev/null; then
494 return 0
495 fi
496 command mv -fh "$replacement" "$destination"
497 }
498
499 _plan_build_select_current() {
500 local resolved
501 [[ -L "$cache_dir/current" ]] || return 1
502 resolved="$cache_dir/current"
503 resolved="${resolved:A}"
504 _plan_build_validate_release "$resolved" || return 1
505 selected_release="$resolved"
506 }
507
508 _plan_build_acquire_activation_lock() {
509 (( interrupted_rc )) && return 1
510 command touch "$activation_lock" || return 1
511 zsystem flock -t 10 -f activation_lock_fd "$activation_lock"
512 }
513
514 _plan_build_release_activation_lock() {
515 [[ -n "$activation_lock_fd" ]] || return 0
516 zsystem flock -u "$activation_lock_fd" || return 1
517 activation_lock_fd=""
518 }
519
520 _plan_build_download() {
521 local remote="$1" destination="$2" download_rc
522 command "$curl_command" -fsSL "$remote" -o "$destination" &
523 active_pid=$!
524 wait "$active_pid"
525 download_rc=$?
526 active_pid=""
527 (( interrupted_rc )) && return "$interrupted_rc"
528 return "$download_rc"
529 }
530
531 _plan_build_backup_path() {
532 local source="$1" backup="$2"
533 [[ -e "$source" || -L "$source" ]] || return 0
534 command rm -f -- "$backup" && command cp -RP "$source" "$backup"
535 }
536
537 _plan_build_restore_path() {
538 local destination="$1" backup="$2" had_old="$3"
539 if (( had_old )); then
540 _plan_build_replace_path "$backup" "$destination" || return 1
541 else
542 command rm -f -- "$destination"
543 fi
544 }
545
546 _plan_build_install_skill_links() {
547 local activation_ok=1
548 local skill_had_old=0 architect_had_old=0
549
550 skill_tmp="$(command mktemp "${skill_file}.link.XXXXXX")" &&
551 command rm -f "$skill_tmp" &&
552 command ln -s "$cache_dir/current/SKILL.md" "$skill_tmp" || skill_tmp=""
553 architect_tmp="$(command mktemp "${architect_file}.link.XXXXXX")" &&
554 command rm -f "$architect_tmp" &&
555 command ln -s "$cache_dir/current/ARCHITECT.md" "$architect_tmp" || architect_tmp=""
556 [[ -n "$skill_tmp" && -L "$skill_tmp" &&
557 -n "$architect_tmp" && -L "$architect_tmp" ]] || return 1
558
559 skill_backup="${skill_file}.backup.$$.$RANDOM"
560 architect_backup="${architect_file}.backup.$$.$RANDOM"
561 [[ -e "$skill_file" || -L "$skill_file" ]] && skill_had_old=1
562 [[ -e "$architect_file" || -L "$architect_file" ]] && architect_had_old=1
563 _plan_build_backup_path "$skill_file" "$skill_backup" || activation_ok=0
564 (( activation_ok )) && _plan_build_backup_path "$architect_file" "$architect_backup" || activation_ok=0
565 (( activation_ok && ! interrupted_rc )) &&
566 _plan_build_replace_path "$skill_tmp" "$skill_file" || activation_ok=0
567 (( activation_ok )) && skill_tmp=""
568 (( activation_ok && ! interrupted_rc )) &&
569 _plan_build_replace_path "$architect_tmp" "$architect_file" || activation_ok=0
570 (( activation_ok )) && architect_tmp=""
571
572 if (( activation_ok )); then
573 command rm -f -- "$skill_backup" "$architect_backup"
574 skill_backup="" architect_backup=""
575 return 0
576 fi
577
578 if ! _plan_build_restore_path "$skill_file" "$skill_backup" "$skill_had_old"; then
579 printf "Error: Unable to restore plan-build skill; backup preserved at %s.\n" "$skill_backup" >&2
580 skill_backup=""
581 fi
582 if ! _plan_build_restore_path "$architect_file" "$architect_backup" "$architect_had_old"; then
583 printf "Error: Unable to restore architect skill; backup preserved at %s.\n" "$architect_backup" >&2
584 architect_backup=""
585 fi
586 return 1
587 }
588
589 if (( $+commands[$curl_command] )) || [[ "$curl_command" == */* && -x "$curl_command" ]]; then
590 stage_dir="$(command mktemp -d "$cache_dir/.stage.XXXXXX")" || stage_dir=""
591 if [[ -n "$stage_dir" ]]; then
592 _plan_build_download "$base_url/plan_build.zsh" "$stage_dir/plan_build.zsh" &&
593 _plan_build_download "$base_url/SKILL.md" "$stage_dir/SKILL.md" &&
594 _plan_build_download "$base_url/ARCHITECT.md" "$stage_dir/ARCHITECT.md"
595 refresh_rc=$?
596 if (( interrupted_rc )); then
597 _plan_build_cleanup
598 trap - EXIT HUP INT TERM
599 return "$interrupted_rc"
600 fi
601 else
602 refresh_rc=1
603 fi
604 if (( refresh_rc == 0 )) &&
605 _plan_build_validate_release "$stage_dir"; then
606 release_dir="$(command mktemp -d "$cache_dir/release.XXXXXX")" || release_dir=""
607 if [[ -n "$release_dir" ]] &&
608 command rmdir "$release_dir" &&
609 command mv "$stage_dir" "$release_dir" &&
610 _plan_build_acquire_activation_lock; then
611 stage_dir=""
612 release_dir="${release_dir:A}"
613 current_tmp="$(command mktemp "$cache_dir/.current.XXXXXX")" &&
614 command rm -f "$current_tmp" &&
615 command ln -s "$release_dir" "$current_tmp" || current_tmp=""
616
617 if [[ -n "$current_tmp" && -L "$current_tmp" ]] &&
618 _plan_build_install_skill_links &&
619 _plan_build_replace_path "$current_tmp" "$cache_dir/current"; then
620 current_tmp=""
621 selected_release="$release_dir"
622 fi
623 _plan_build_release_activation_lock || true
624 fi
625 fi
626 fi
627
628 if (( interrupted_rc )); then
629 _plan_build_cleanup
630 trap - EXIT HUP INT TERM
631 return "$interrupted_rc"
632 fi
633
634 if [[ -z "$selected_release" ]]; then
635 if ! _plan_build_select_current; then
636 if (( ! $+commands[$curl_command] )) && [[ ! ( "$curl_command" == */* && -x "$curl_command" ) ]]; then
637 printf "Error: curl is required because no valid cached plan-build bundle is available.\n" >&2
638 else
639 printf "Error: Unable to refresh plan-build and no valid cached bundle is available.\n" >&2
640 fi
641 return 1
642 fi
643 if (( ! $+commands[$curl_command] )) && [[ ! ( "$curl_command" == */* && -x "$curl_command" ) ]]; then
644 printf "Warning: curl is unavailable; using the validated cached plan-build bundle.\n" >&2
645 else
646 printf "Warning: Unable to refresh plan-build; using the validated cached bundle.\n" >&2
647 fi
648 fi
649
650 if [[ "$(command readlink "$skill_file" 2>/dev/null)" != "$cache_dir/current/SKILL.md" ||
651 "$(command readlink "$architect_file" 2>/dev/null)" != "$cache_dir/current/ARCHITECT.md" ]]; then
652 if ! _plan_build_acquire_activation_lock || ! _plan_build_install_skill_links; then
653 _plan_build_release_activation_lock 2>/dev/null || true
654 if (( interrupted_rc )); then
655 _plan_build_cleanup
656 trap - EXIT HUP INT TERM
657 return "$interrupted_rc"
658 fi
659 printf "Error: Unable to install the plan-build skill links.\n" >&2
660 return 1
661 fi
662 _plan_build_release_activation_lock || true
663 fi
664
665 if (( interrupted_rc )); then
666 _plan_build_cleanup
667 trap - EXIT HUP INT TERM
668 return "$interrupted_rc"
669 fi
670
671 PLAN_BUILD_SKILL_PATH="$selected_release/SKILL.md" \
672 PLAN_BUILD_ARCHITECT_SKILL_PATH="$selected_release/ARCHITECT.md" \
673 command zsh "$selected_release/plan_build.zsh" "$@" &
674 active_pid=$!
675 wait "$active_pid"
676 call_rc=$?
677 active_pid=""
678 (( interrupted_rc )) && call_rc="$interrupted_rc"
679 _plan_build_cleanup
680 trap - EXIT HUP INT TERM
681 return "$call_rc"
682}
683
684# -----------------------------------------------------------------------------
685# Function: aicommit (Automated Conventional Commit Engine Wrapper)
686# -----------------------------------------------------------------------------
687aicommit() {
688 local diff engine prompt
689
690 # 1. Get diff safely: exclude lock files/minified files and cap at ~100k characters to prevent CLI crashes
691 diff=$(git diff --cached -- . ":(exclude)*.lock" ":(exclude)*-lock.json" ":(exclude)*.min.js" | head -c 100000)
692
693 if [ -z "$diff" ]; then
694 printf "❌ Error: Nothing staged to commit.\n" >&2
695 return 1
696 fi
697
698 if [ ! -f "$HOME/.config/ai-commit-prompt.txt" ]; then
699 printf "❌ Error: Configuration file not found at ~/.config/ai-commit-prompt.txt\n" >&2
700 printf "Please create it and paste your system prompt inside.\n" >&2
701 return 1
702 fi
703
704 engine=${1:-claude}
705 prompt=$(cat "$HOME/.config/ai-commit-prompt.txt")
706
707 case "$engine" in
708 claude)
709 echo "🤖 Claude is analyzing staged changes..."
710 cat "$HOME/.config/ai-commit-prompt.txt" <(echo -e "\n\nHere is the git diff:\n$diff") \
711 | command claude --allowedTools 'Bash(git commit *)' --permission-mode dontAsk -p \
712 "Read the provided instructions and diff, then generate and execute the commit."
713 ;;
714
715 codex)
716 echo "🤖 Codex is analyzing staged changes..."
717 cat "$HOME/.config/ai-commit-prompt.txt" <(echo -e "\n\nHere is the git diff:\n$diff") \
718 | command codex --ask-for-approval never exec --sandbox workspace-write --ephemeral \
719 "Read the provided instructions and diff, then generate and execute the commit."
720 ;;
721
722 copilot)
723 echo "🤖 Copilot is analyzing staged changes..."
724 copilot -p "$prompt
725
726Here is the git diff:
727$diff" -s --no-ask-user --allow-tool='shell(git:*)'
728 ;;
729
730 opencode)
731 echo "🤖 OpenCode is analyzing staged changes..."
732 cat "$HOME/.config/ai-commit-prompt.txt" <(echo -e "\n\nHere is the git diff:\n$diff") | opencode run
733 ;;
734
735 *)
736 printf "❌ Error: Invalid engine '%s'\n" "$engine" >&2
737 printf "Usage: aicommit [claude | codex | copilot | opencode]\n" >&2
738 return 1
739 ;;
740 esac
741}
742
743# -----------------------------------------------------------------------------
744# Function: create (Efficiently create file + parent dirs)
745# -----------------------------------------------------------------------------
746create() {
747 if ! command -v install >/dev/null 2>&1; then
748 printf "Error: 'install' coreutil is not available.\n" >&2
749 return 1
750 fi
751
752 if [ $# -eq 0 ]; then
753 printf "Usage: create <file> [file ...]\n" >&2
754 return 2
755 fi
756
757 for p in "$@"; do
758 # Expand tilde manually if shell doesn't
759 [[ "$p" == "~/"* ]] && p="${HOME}/${p#\~/}"
760
761 if [ -z "$p" ] || [ "$p" = "/" ]; then
762 printf "create: refusing to operate on '%s'\n" "$p" >&2
763 continue
764 fi
765
766 if [ -e "$p" ]; then
767 printf "create: '%s' already exists. Skipping.\n" "$p" >&2
768 continue
769 fi
770
771 if install -D /dev/null "$p"; then
772 echo "Created '$p'"
773 fi
774 done
775}
776
777# -----------------------------------------------------------------------------
778# Function: kill_port (Kill or check the process using a port)
779# -----------------------------------------------------------------------------
780kill_port() {
781 local action="kill"
782 local signal="TERM"
783 local port
784 local pids
785 local pid
786
787 case "${1:-}" in
788 -c|--check)
789 action="check"
790 shift
791 ;;
792 -k|--kill)
793 action="kill"
794 shift
795 ;;
796 -f|--force)
797 action="kill"
798 signal="KILL"
799 shift
800 ;;
801 -h|--help|"")
802 printf "Usage: kill_port [--check|-c|--kill|-k|--force|-f] <port_number>\n" >&2
803 return 1
804 ;;
805 esac
806
807 port="${1:-}"
808 if [[ ! "$port" =~ ^[0-9]+$ ]] || [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then
809 printf "Error: port must be a number between 1 and 65535.\n" >&2
810 printf "Usage: kill_port [--check|-c|--kill|-k|--force|-f] <port_number>\n" >&2
811 return 1
812 fi
813
814 if [[ "$OSTYPE" == "darwin"* ]]; then
815 pids="$(
816 {
817 lsof -nP -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null
818 lsof -nP -tiUDP:"$port" 2>/dev/null
819 } | sort -u
820 )"
821
822 if [ -z "$pids" ]; then
823 printf "Port %s is FREE\n" "$port"
824 return 0
825 fi
826
827 printf "Port %s is in use:\n" "$port"
828 lsof -nP -iTCP:"$port" -sTCP:LISTEN -iUDP:"$port" 2>/dev/null
829 else
830 local port_hex
831 local inodes
832
833 port_hex="$(printf "%04X" "$port")"
834 inodes="$(
835 awk -v port="$port_hex" '
836 NR > 1 {
837 split($2, local_addr, ":")
838 if (toupper(local_addr[length(local_addr)]) == port && ($4 == "0A" || FILENAME ~ /udp/)) {
839 print $10
840 }
841 }
842 ' /proc/net/tcp /proc/net/tcp6 /proc/net/udp /proc/net/udp6 2>/dev/null | sort -u
843 )"
844
845 if [ -z "$inodes" ]; then
846 printf "Port %s is FREE\n" "$port"
847 return 0
848 fi
849
850 pids=""
851 pids="$(
852 find /proc/[0-9]*/fd -maxdepth 1 -type l -printf "%p %l\n" 2>/dev/null |
853 awk -v inodes="$inodes" '
854 BEGIN {
855 split(inodes, inode_list, " ")
856 for (i in inode_list) {
857 wanted["socket:[" inode_list[i] "]"] = 1
858 }
859 }
860 $2 in wanted {
861 split($1, path, "/")
862 print path[3]
863 }
864 ' | sort -u
865 )"
866
867 if [ -z "$pids" ]; then
868 printf "Port %s is in use, but no readable process owner was found.\n" "$port" >&2
869 return 1
870 fi
871
872 printf "Port %s is in use:\n" "$port"
873 for pid in $pids; do
874 if [ -r "/proc/$pid/cmdline" ]; then
875 printf " PID %-8s %s\n" "$pid" "$(tr '\0' ' ' < "/proc/$pid/cmdline")"
876 else
877 printf " PID %s\n" "$pid"
878 fi
879 done
880 fi
881
882 if [ "$action" = "kill" ]; then
883 for pid in $pids; do
884 if kill "-$signal" "$pid" 2>/dev/null; then
885 printf "Killed PID %s with SIG%s.\n" "$pid" "$signal"
886 else
887 printf "Error: failed to kill PID %s. Try with sudo or --force.\n" "$pid" >&2
888 return 1
889 fi
890 done
891 fi
892}
893
894# -----------------------------------------------------------------------------
895# Function: append_path (Adds to session PATH if exists)
896# -----------------------------------------------------------------------------
897append_path() {
898 local dir="$1"
899 if [ -d "$dir" ]; then
900 case ":$PATH:" in
901 *":$dir:"*) ;;
902 *) PATH="$PATH:$dir" ;;
903 esac
904 elif [ "${SUPPRESS_WARNINGS:-0}" -ne 1 ]; then
905 echo "Warning: $dir does not exist." >&2
906 fi
907}
908
909# -----------------------------------------------------------------------------
910# Function: add_path_to_config (Fixed awk/sed injection)
911# -----------------------------------------------------------------------------
912add_path_to_config() {
913 local new_path="$1"
914 local config_file="$HOME/.bashrc"
915 [[ "$SHELL" == *"zsh"* ]] && config_file="$HOME/.zshrc"
916
917 if [ -z "$new_path" ]; then
918 printf "Usage: add_path_to_config <directory>\n" >&2
919 return 1
920 fi
921
922 new_path="${new_path/#\~/$HOME}"
923
924 if [ ! -d "$new_path" ]; then
925 printf "Warning: '%s' does not exist. Add anyway? (y/N) " "$new_path"
926 read -r REPLY
927 [[ ! $REPLY =~ ^[Yy]$ ]] && return 1
928 fi
929
930 # Check if already exists in file
931 if grep -Fq "append_path \"$new_path\"" "$config_file"; then
932 printf "Notice: Already in %s.\n" "$config_file"
933 return 0
934 fi
935
936 # Robust Injection: Use sed to insert before export PATH or just append
937 if grep -q "^export PATH" "$config_file"; then
938 sed -i.bak "/^export PATH/i append_path \"$new_path\"" "$config_file"
939 else
940 echo "append_path \"$new_path\"" >> "$config_file"
941 echo "export PATH" >> "$config_file"
942 fi
943
944 printf "✅ Success: Added to %s\n" "$config_file"
945 append_path "$new_path" && export PATH
946}
947
pathrc Eredeti
1# =============================================================================
2# ENVIRONMENT & PATH CONFIGURATION
3# =============================================================================
4
5# 1. Source functions first
6if [[ -f "$HOME/.func" && -r "$HOME/.func" ]]; then
7 source "$HOME/.func"
8fi
9
10# 2. Define Root Variables
11export DOTNET_ROOT="$HOME/.dotnet"
12
13# 3. PATH INITIALIZATION
14# -----------------------------------------------------------------------------
15append_path "$HOME/.local/bin"
16append_path "$DOTNET_ROOT"
17append_path "$DOTNET_ROOT/tools"
18append_path "$HOME/.opencode/bin"
19append_path "$HOME/Flutter/bin"
20
21# macOS specific paths
22if [[ "$OSTYPE" == "darwin"* ]]; then
23 append_path "/Applications/Espanso.app/Contents/MacOS"
24fi
25
26# Finalize PATH
27export PATH
sourcerc Eredeti
1# =============================================================================
2# FILE: ~/.sourcerc
3# Description: Initializes third-party package managers and external tools.
4# =============================================================================
5
6# =============================================================================
7# GENERAL ENV
8# =============================================================================
9if [[ -f "$HOME/.local/bin/env" && -r "$HOME/.local/bin/env" ]]; then
10 source "$HOME/.local/bin/env"
11fi
12
13# =============================================================================
14# CLAUDE CODE / AI GATEWAY
15# =============================================================================
16export ANTHROPIC_BASE_URL="https://gateway.ai.cloudflare.com/v1/9a71825e3842e918e0dff9ad84f50484/claude-code-gateway/anthropic"
17
18# =============================================================================
19# SDKMAN (Java/Kotlin/Scala Version Manager)
20# =============================================================================
21export SDKMAN_DIR="$HOME/.sdkman"
22if [[ -f "$SDKMAN_DIR/bin/sdkman-init.sh" && -r "$SDKMAN_DIR/bin/sdkman-init.sh" ]]; then
23 source "$SDKMAN_DIR/bin/sdkman-init.sh"
24fi
25
26# =============================================================================
27# NVM (Node Version Manager)
28# =============================================================================
29export NVM_DIR="$HOME/.nvm"
30if [[ -f "$NVM_DIR/nvm.sh" && -r "$NVM_DIR/nvm.sh" ]]; then
31 source "$NVM_DIR/nvm.sh"
32fi
33if [[ -f "$NVM_DIR/bash_completion" && -r "$NVM_DIR/bash_completion" ]]; then
34 source "$NVM_DIR/bash_completion"
35fi
36
37# =============================================================================
38# GOOGLE CLOUD SDK
39# =============================================================================
40if [[ -f "/opt/google-cloud-sdk/path.zsh.inc" ]]; then
41 source "/opt/google-cloud-sdk/path.zsh.inc"
42fi
43
44if [[ -f "/opt/google-cloud-sdk/completion.zsh.inc" ]]; then
45 source "/opt/google-cloud-sdk/completion.zsh.inc"
46fi
47
starship.toml Eredeti
1"$schema" = 'https://starship.rs/config-schema.json'
2
3format = """
4[](red)\
5$os\
6$username\
7[](bg:peach fg:red)\
8$directory\
9[](bg:yellow fg:peach)\
10$git_branch\
11$git_status\
12[](fg:yellow bg:green)\
13$c\
14$rust\
15$golang\
16$nodejs\
17$bun\
18$php\
19$java\
20$kotlin\
21$haskell\
22$python\
23[](fg:green bg:sapphire)\
24$conda\
25[](fg:sapphire bg:lavender)\
26$time\
27[ ](fg:lavender)\
28$cmd_duration\
29$line_break\
30$character"""
31
32palette = 'catppuccin_mocha'
33
34[os]
35disabled = false
36style = "bg:red fg:crust"
37
38[os.symbols]
39Windows = ""
40Ubuntu = "󰕈"
41SUSE = ""
42Raspbian = "󰐿"
43Mint = "󰣭"
44Macos = "󰀵"
45Manjaro = ""
46Linux = "󰌽"
47Gentoo = "󰣨"
48Fedora = "󰣛"
49Alpine = ""
50Amazon = ""
51Android = ""
52AOSC = ""
53Arch = "󰣇"
54Artix = "󰣇"
55CentOS = ""
56Debian = "󰣚"
57Redhat = "󱄛"
58RedHatEnterprise = "󱄛"
59
60[username]
61show_always = true
62style_user = "bg:red fg:crust"
63style_root = "bg:red fg:crust"
64format = '[ $user]($style)'
65
66[directory]
67style = "bg:peach fg:crust"
68format = "[ $path ]($style)"
69truncation_length = 3
70truncation_symbol = "…/"
71
72[directory.substitutions]
73"Documents" = "󰈙 "
74"Downloads" = " "
75"Music" = "󰝚 "
76"Pictures" = " "
77"Developer" = "󰲋 "
78
79[git_branch]
80symbol = ""
81style = "bg:yellow"
82format = '[[ $symbol $branch ](fg:crust bg:yellow)]($style)'
83
84[git_status]
85style = "bg:yellow"
86format = '[[($all_status$ahead_behind )](fg:crust bg:yellow)]($style)'
87
88[nodejs]
89symbol = ""
90style = "bg:green"
91format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
92
93[bun]
94symbol = ""
95style = "bg:green"
96format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
97
98[c]
99symbol = " "
100style = "bg:green"
101format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
102
103[rust]
104symbol = ""
105style = "bg:green"
106format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
107
108[golang]
109symbol = ""
110style = "bg:green"
111format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
112
113[php]
114symbol = ""
115style = "bg:green"
116format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
117
118[java]
119symbol = " "
120style = "bg:green"
121format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
122
123[kotlin]
124symbol = ""
125style = "bg:green"
126format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
127
128[haskell]
129symbol = ""
130style = "bg:green"
131format = '[[ $symbol( $version) ](fg:crust bg:green)]($style)'
132
133[python]
134symbol = ""
135style = "bg:green"
136format = '[[ $symbol( $version)(\(#$virtualenv\)) ](fg:crust bg:green)]($style)'
137
138[docker_context]
139symbol = ""
140style = "bg:sapphire"
141format = '[[ $symbol( $context) ](fg:crust bg:sapphire)]($style)'
142
143[conda]
144symbol = "  "
145style = "fg:crust bg:sapphire"
146format = '[$symbol$environment ]($style)'
147ignore_base = false
148
149[time]
150disabled = false
151time_format = "%R"
152style = "bg:lavender"
153format = '[[  $time ](fg:crust bg:lavender)]($style)'
154
155[line_break]
156disabled = false
157
158[character]
159disabled = false
160success_symbol = '[❯](bold fg:green)'
161error_symbol = '[❯](bold fg:red)'
162vimcmd_symbol = '[❮](bold fg:green)'
163vimcmd_replace_one_symbol = '[❮](bold fg:lavender)'
164vimcmd_replace_symbol = '[❮](bold fg:lavender)'
165vimcmd_visual_symbol = '[❮](bold fg:yellow)'
166
167[cmd_duration]
168show_milliseconds = true
169format = " in $duration "
170style = "bg:lavender"
171disabled = false
172show_notifications = true
173min_time_to_notify = 45000
174
175[palettes.catppuccin_mocha]
176rosewater = "#f5e0dc"
177flamingo = "#f2cdcd"
178pink = "#f5c2e7"
179mauve = "#cba6f7"
180red = "#f38ba8"
181maroon = "#eba0ac"
182peach = "#fab387"
183yellow = "#f9e2af"
184green = "#a6e3a1"
185teal = "#94e2d5"
186sky = "#89dceb"
187sapphire = "#74c7ec"
188blue = "#89b4fa"
189lavender = "#b4befe"
190text = "#cdd6f4"
191subtext1 = "#bac2de"
192subtext0 = "#a6adc8"
193overlay2 = "#9399b2"
194overlay1 = "#7f849c"
195overlay0 = "#6c7086"
196surface2 = "#585b70"
197surface1 = "#45475a"
198surface0 = "#313244"
199base = "#1e1e2e"
200mantle = "#181825"
201crust = "#11111b"
202
203[palettes.catppuccin_frappe]
204rosewater = "#f2d5cf"
205flamingo = "#eebebe"
206pink = "#f4b8e4"
207mauve = "#ca9ee6"
208red = "#e78284"
209maroon = "#ea999c"
210peach = "#ef9f76"
211yellow = "#e5c890"
212green = "#a6d189"
213teal = "#81c8be"
214sky = "#99d1db"
215sapphire = "#85c1dc"
216blue = "#8caaee"
217lavender = "#babbf1"
218text = "#c6d0f5"
219subtext1 = "#b5bfe2"
220subtext0 = "#a5adce"
221overlay2 = "#949cbb"
222overlay1 = "#838ba7"
223overlay0 = "#737994"
224surface2 = "#626880"
225surface1 = "#51576d"
226surface0 = "#414559"
227base = "#303446"
228mantle = "#292c3c"
229crust = "#232634"
230
231[palettes.catppuccin_latte]
232rosewater = "#dc8a78"
233flamingo = "#dd7878"
234pink = "#ea76cb"
235mauve = "#8839ef"
236red = "#d20f39"
237maroon = "#e64553"
238peach = "#fe640b"
239yellow = "#df8e1d"
240green = "#40a02b"
241teal = "#179299"
242sky = "#04a5e5"
243sapphire = "#209fb5"
244blue = "#1e66f5"
245lavender = "#7287fd"
246text = "#4c4f69"
247subtext1 = "#5c5f77"
248subtext0 = "#6c6f85"
249overlay2 = "#7c7f93"
250overlay1 = "#8c8fa1"
251overlay0 = "#9ca0b0"
252surface2 = "#acb0be"
253surface1 = "#bcc0cc"
254surface0 = "#ccd0da"
255base = "#eff1f5"
256mantle = "#e6e9ef"
257crust = "#dce0e8"
258
259[palettes.catppuccin_macchiato]
260rosewater = "#f4dbd6"
261flamingo = "#f0c6c6"
262pink = "#f5bde6"
263mauve = "#c6a0f6"
264red = "#ed8796"
265maroon = "#ee99a0"
266peach = "#f5a97f"
267yellow = "#eed49f"
268green = "#a6da95"
269teal = "#8bd5ca"
270sky = "#91d7e3"
271sapphire = "#7dc4e4"
272blue = "#8aadf4"
273lavender = "#b7bdf8"
274text = "#cad3f5"
275subtext1 = "#b8c0e0"
276subtext0 = "#a5adcb"
277overlay2 = "#939ab7"
278overlay1 = "#8087a2"
279overlay0 = "#6e738d"
280surface2 = "#5b6078"
281surface1 = "#494d64"
282surface0 = "#363a4f"
283base = "#24273a"
284mantle = "#1e2030"
285crust = "#181926"
286
test_plan_build.zsh Eredeti
1#!/usr/bin/env zsh
2
3set -u
4
5repo_dir="${0:A:h}"
6source "$repo_dir/func"
7
8failures=0
9fixture_dir="$(mktemp -d "${TMPDIR:-/tmp}/plan build launcher.XXXXXX")" || exit 1
10source_dir="$(mktemp -d "${TMPDIR:-/tmp}/plan-build-source.XXXXXX")" || exit 1
11export PLAN_BUILD_CACHE_DIR="$fixture_dir/cache with spaces"
12export PLAN_BUILD_BASE_URL="file://$source_dir"
13export HOME="$fixture_dir/home with spaces"
14PLAN_BUILD_SKILLS_DIR="$HOME/.claude/skills"
15mkdir -p "$source_dir" "$PLAN_BUILD_SKILLS_DIR/plan-build" "$PLAN_BUILD_SKILLS_DIR/plan-build-architect"
16print -r -- "old standard" > "$PLAN_BUILD_SKILLS_DIR/plan-build/SKILL.md"
17print -r -- "old architect" > "$PLAN_BUILD_SKILLS_DIR/plan-build-architect/SKILL.md"
18trap 'rm -rf -- "$fixture_dir" "$source_dir"' EXIT
19
20fail() {
21 print -u2 -- "FAIL: $1"
22 failures=$((failures + 1))
23}
24
25assert_equal() {
26 [[ "$1" = "$2" ]] || fail "$3 (expected '$1', got '$2')"
27}
28
29assert_contains() {
30 [[ "$1" == *"$2"* ]] || fail "$3 (missing '$2')"
31}
32
33assert_file_contains() {
34 command grep -Fq -- "$2" "$1" || fail "$3"
35}
36
37assert_bundle_consistent() {
38 local release="$PLAN_BUILD_CACHE_DIR/current"
39 local script_generation skill_generation architect_generation
40 release="${release:A}"
41 [[ -L "$PLAN_BUILD_CACHE_DIR/current" ]] || fail "$1 current is a symlink"
42 [[ -d "$release" ]] || fail "$1 current resolves to a release"
43 script_generation="$(command sed -n 's/^# generation: //p' "$release/plan_build.zsh")"
44 skill_generation="$(command sed -n 's/ standard skill$//p' "$release/SKILL.md")"
45 architect_generation="$(command sed -n 's/ architect skill$//p' "$release/ARCHITECT.md")"
46 assert_equal "$script_generation" "$skill_generation" "$1 script/standard generation"
47 assert_equal "$script_generation" "$architect_generation" "$1 script/architect generation"
48}
49
50assert_skill_links() {
51 [[ -L "$PLAN_BUILD_SKILLS_DIR/plan-build/SKILL.md" ]] || fail "$1 standard path is symlink"
52 [[ -L "$PLAN_BUILD_SKILLS_DIR/plan-build-architect/SKILL.md" ]] || fail "$1 architect path is symlink"
53 assert_equal "$PLAN_BUILD_CACHE_DIR/current/SKILL.md" \
54 "$(command readlink "$PLAN_BUILD_SKILLS_DIR/plan-build/SKILL.md")" "$1 standard link target"
55 assert_equal "$PLAN_BUILD_CACHE_DIR/current/ARCHITECT.md" \
56 "$(command readlink "$PLAN_BUILD_SKILLS_DIR/plan-build-architect/SKILL.md")" "$1 architect link target"
57}
58
59write_bundle() {
60 local generation="$1"
61 local exit_code="${2:-0}"
62 local marker_file="${3:-}"
63 print -r -- '#!/usr/bin/env zsh' > "$source_dir/plan_build.zsh"
64 print -r -- "# generation: $generation" >> "$source_dir/plan_build.zsh"
65 print -r -- "print -r -- \"$generation:\${(j:|:)@}\"" >> "$source_dir/plan_build.zsh"
66 print -r -- "print -r -- \"path:\${0}\"" >> "$source_dir/plan_build.zsh"
67 print -r -- 'print -r -- "skills:${PLAN_BUILD_SKILL_PATH}|${PLAN_BUILD_ARCHITECT_SKILL_PATH}"' >> "$source_dir/plan_build.zsh"
68 [[ -n "$marker_file" ]] && print -r -- ": > ${(q)marker_file}" >> "$source_dir/plan_build.zsh"
69 print -r -- "exit $exit_code" >> "$source_dir/plan_build.zsh"
70 print -r -- "$generation standard skill" > "$source_dir/SKILL.md"
71 print -r -- "$generation architect skill" > "$source_dir/ARCHITECT.md"
72}
73
74run_plan_build() {
75 output="$(plan_build "$@" 2>&1)"
76 rc=$?
77}
78
79write_bundle initial
80run_plan_build alpha "two words"
81assert_equal 0 "$rc" "initial migration status"
82assert_contains "$output" "initial:alpha|two words" "argument forwarding"
83assert_skill_links "initial migration"
84assert_bundle_consistent "initial migration"
85assert_file_contains "$PLAN_BUILD_SKILLS_DIR/plan-build/SKILL.md" "initial standard" "initial standard content"
86assert_file_contains "$PLAN_BUILD_SKILLS_DIR/plan-build-architect/SKILL.md" "initial architect" "initial architect content"
87execution_path="${${(f)output}[(r)path:*]#path:}"
88[[ "$execution_path" == "$PLAN_BUILD_CACHE_DIR"/release.*/plan_build.zsh ]] ||
89 fail "execution uses an immutable release path"
90assert_contains "$output" "skills:${execution_path:h}/SKILL.md|${execution_path:h}/ARCHITECT.md" \
91 "execution binds immutable skill paths"
92
93old_release="$PLAN_BUILD_CACHE_DIR/current"
94old_release="${old_release:A}"
95write_bundle replacement 23
96run_plan_build forwarded
97assert_equal 23 "$rc" "canonical status forwarding"
98assert_contains "$output" "replacement:forwarded" "replacement executes"
99new_release="$PLAN_BUILD_CACHE_DIR/current"
100new_release="${new_release:A}"
101[[ "$new_release" != "$old_release" ]] || fail "refresh activates a unique release"
102assert_skill_links "replacement"
103assert_bundle_consistent "replacement"
104
105print -r -- 'if broken' > "$source_dir/plan_build.zsh"
106print -r -- "bad standard skill" > "$source_dir/SKILL.md"
107print -r -- "bad architect skill" > "$source_dir/ARCHITECT.md"
108run_plan_build fallback
109assert_equal 23 "$rc" "failed refresh fallback status"
110assert_contains "$output" "Warning: Unable to refresh" "failed refresh warning"
111assert_contains "$output" "replacement:fallback" "failed refresh executes current"
112preserved_release="$PLAN_BUILD_CACHE_DIR/current"
113preserved_release="${preserved_release:A}"
114assert_equal "$new_release" "$preserved_release" "failed refresh preserves current"
115assert_skill_links "failed refresh"
116assert_bundle_consistent "failed refresh"
117
118export PLAN_BUILD_CURL_COMMAND="definitely-missing-plan-build-curl"
119run_plan_build no-curl
120assert_equal 23 "$rc" "missing curl fallback status"
121assert_contains "$output" "curl is unavailable" "missing curl warning"
122assert_contains "$output" "replacement:no-curl" "missing curl executes current"
123rm -f "$PLAN_BUILD_SKILLS_DIR/plan-build/SKILL.md" "$PLAN_BUILD_SKILLS_DIR/plan-build-architect/SKILL.md"
124run_plan_build repaired-offline
125assert_equal 23 "$rc" "offline skill repair status"
126assert_skill_links "offline skill repair"
127unset PLAN_BUILD_CURL_COMMAND
128
129# An already selected immutable script must not change beneath a concurrent caller.
130ready_file="$fixture_dir/ready"
131go_file="$fixture_dir/go"
132first_output="$fixture_dir/first.out"
133print -r -- '#!/usr/bin/env zsh' > "$source_dir/plan_build.zsh"
134print -r -- '# generation: concurrent_first' >> "$source_dir/plan_build.zsh"
135print -r -- 'print -r -- "concurrent_first:${(j:|:)@}"' >> "$source_dir/plan_build.zsh"
136print -r -- ": > ${(q)ready_file}" >> "$source_dir/plan_build.zsh"
137print -r -- "while [[ ! -e ${(q)go_file} ]]; do sleep 0.01; done" >> "$source_dir/plan_build.zsh"
138print -r -- 'print -r -- "finished:first"' >> "$source_dir/plan_build.zsh"
139print -r -- "concurrent_first standard skill" > "$source_dir/SKILL.md"
140print -r -- "concurrent_first architect skill" > "$source_dir/ARCHITECT.md"
141(plan_build one > "$first_output" 2>&1) &
142first_pid=$!
143for attempt in {1..500}; do
144 [[ -e "$ready_file" ]] && break
145 sleep 0.01
146done
147[[ -e "$ready_file" ]] || fail "first concurrent call reached canonical execution"
148write_bundle concurrent_second
149run_plan_build two
150assert_equal 0 "$rc" "second concurrent status"
151assert_contains "$output" "concurrent_second:two" "second concurrent generation"
152: > "$go_file"
153wait "$first_pid" || fail "first concurrent status"
154first_text="$(<"$first_output")"
155assert_contains "$first_text" "concurrent_first:one" "first call retains selected release"
156assert_contains "$first_text" "finished:first" "first immutable script finishes"
157assert_bundle_consistent "concurrent final current"
158assert_skill_links "concurrent final links"
159
160# Cancellation while refreshing must clean staging and never execute canonical code.
161blocking_curl="$fixture_dir/blocking-curl"
162cancel_started="$fixture_dir/cancel.started"
163cancel_executed="$fixture_dir/cancel.executed"
164write_bundle cancellation-marker 0 "$cancel_executed"
165run_plan_build activate-cancellation-marker
166assert_equal 0 "$rc" "cancellation marker bundle activation"
167rm -f "$cancel_executed"
168{
169 print -r -- '#!/bin/sh'
170 print -r -- "touch ${(q)cancel_started}"
171 print -r -- 'while :; do sleep 1; done'
172} > "$blocking_curl"
173chmod +x "$blocking_curl"
174export PLAN_BUILD_CURL_COMMAND="$blocking_curl"
175(plan_build cancelled > "$fixture_dir/cancel.out" 2>&1; cancel_rc=$?; print -r -- "$cancel_rc" > "$fixture_dir/cancel.rc"; exit "$cancel_rc") &
176cancel_pid=$!
177for attempt in {1..500}; do
178 [[ -e "$cancel_started" ]] && break
179 sleep 0.01
180done
181kill -TERM "$cancel_pid"
182wait "$cancel_pid"
183cancel_wait_rc=$?
184cancel_recorded_rc=""
185[[ -s "$fixture_dir/cancel.rc" ]] && cancel_recorded_rc="$(<"$fixture_dir/cancel.rc")"
186[[ "$cancel_wait_rc" = 143 || "$cancel_recorded_rc" = 143 ]] ||
187 fail "TERM returns conventional status 143"
188[[ ! -e "$cancel_executed" ]] || fail "TERM does not execute canonical plan-build"
189unset PLAN_BUILD_CURL_COMMAND
190
191# A pre-existing lock file must not be mistaken for an active kernel lock.
192print -r -- "stale contents" > "$PLAN_BUILD_CACHE_DIR/.activate.lock"
193write_bundle stale-lock-recovery
194run_plan_build recovered
195assert_equal 0 "$rc" "stale activation lock recovery status"
196assert_contains "$output" "stale-lock-recovery:recovered" "stale activation lock recovery execution"
197
198# Cancellation while canonical code runs must terminate the child promptly.
199canonical_started="$fixture_dir/canonical.started"
200canonical_finished="$fixture_dir/canonical.finished"
201print -r -- '#!/usr/bin/env zsh' > "$source_dir/plan_build.zsh"
202print -r -- '# generation: canonical-cancel' >> "$source_dir/plan_build.zsh"
203print -r -- "trap 'exit 143' TERM" >> "$source_dir/plan_build.zsh"
204print -r -- ": > ${(q)canonical_started}" >> "$source_dir/plan_build.zsh"
205print -r -- 'while :; do sleep 1; done' >> "$source_dir/plan_build.zsh"
206print -r -- ": > ${(q)canonical_finished}" >> "$source_dir/plan_build.zsh"
207print -r -- "canonical-cancel standard skill" > "$source_dir/SKILL.md"
208print -r -- "canonical-cancel architect skill" > "$source_dir/ARCHITECT.md"
209(plan_build canonical-cancel > "$fixture_dir/canonical-cancel.out" 2>&1; print -r -- "$?" > "$fixture_dir/canonical-cancel.rc") &
210canonical_pid=$!
211for attempt in {1..500}; do
212 [[ -e "$canonical_started" ]] && break
213 sleep 0.01
214done
215[[ -e "$canonical_started" ]] || fail "canonical cancellation reached execution"
216kill -TERM "$canonical_pid"
217wait "$canonical_pid"
218assert_equal 143 "$(<"$fixture_dir/canonical-cancel.rc")" "canonical cancellation status"
219[[ ! -e "$canonical_finished" ]] || fail "canonical child continued after TERM"
220
221temp_count="$(command find "$PLAN_BUILD_CACHE_DIR" -maxdepth 1 \
222 \( -name '.stage.*' -o -name '.current.*' \) -print | command wc -l | command tr -d ' ')"
223assert_equal 0 "$temp_count" "cache staging and temporary links cleaned"
224skill_temp_count="$(command find "$PLAN_BUILD_SKILLS_DIR" \
225 \( -name '*.link.*' -o -name '*.backup.*' \) -print | command wc -l | command tr -d ' ')"
226assert_equal 0 "$skill_temp_count" "skill temporary links and backups cleaned"
227
228if (( failures )); then
229 exit 1
230fi
231
232print -- "PASS: plan_build launcher tests"
233
vimrc Eredeti
1" Enable line numbers
2set number
3
4" Enable relative line numbers
5set relativenumber
6
7" Enable syntax highlighting
8syntax on
9
10" Set colorscheme
11colorscheme slate
12
13" Enable file type detection and plugins
14filetype plugin indent on
15
16" Set the tab width to 4 spaces
17set tabstop=4
18set shiftwidth=4
19set expandtab
20
21" Enable auto-indentation
22set autoindent
23set smartindent
24
25" Highlight current line
26set cursorline
27
28" Show matching parentheses
29set showmatch
30
31" Enable line wrapping
32set wrap
33
34" Enable mouse support
35set mouse=a
36
37" Use Wayland's clipboard tools when this Vim lacks native clipboard support
38if !has('clipboard') && exists('v:clipproviders')
39 \ && executable('wl-copy') && executable('wl-paste')
40 function! s:WaylandCopy(register, type, lines) abort
41 let l:text = join(a:lines, "\n")
42 if a:type ==# 'V'
43 let l:text ..= "\n"
44 endif
45 call system('wl-copy', l:text)
46 endfunction
47
48 function! s:WaylandPaste(register) abort
49 return ['', systemlist('wl-paste --no-newline')]
50 endfunction
51
52 let v:clipproviders['wltools'] = {
53 \ 'copy': {
54 \ '+': function('s:WaylandCopy'),
55 \ '*': function('s:WaylandCopy')
56 \ },
57 \ 'paste': {
58 \ '+': function('s:WaylandPaste'),
59 \ '*': function('s:WaylandPaste')
60 \ }
61 \ }
62 set clipmethod^=wltools
63endif
64set clipboard=unnamedplus
65
66" Disable swap file
67set noswapfile
68
69" Enable incremental search
70set incsearch
71
72" Ignore case in search
73set ignorecase
74
75" Override ignorecase if search contains capital letters
76set smartcase
77
78" Display line and column number of the cursor position
79set ruler
80
81" Set the status line at the bottom
82set laststatus=2
83
84" Show command in bottom bar
85set showcmd
86
87" Set command height
88set cmdheight=2
89
90" Set history lines
91set history=1000
92
93" Disable backup file
94set nobackup
95
96" Enable persistent undo
97set undofile
98
99" Set maximum number of undo levels
100set undolevels=1000
101
102" Set undo directory
103if has("persistent_undo")
104 silent !mkdir ~/.vim/undodir > /dev/null 2>&1
105 set undodir=~/.vim/undodir
106endif
107
108" Set search highlighting
109set hlsearch
110
111" Enable visual bell
112set visualbell
113
114" Set default file encoding
115set encoding=utf-8
116
117" Set the leader key to space
118let mapleader = " "
119
120" Map <Leader>w to save the file
121nnoremap <Leader>w :w<CR>
122
123" Map <Leader>q to quit
124nnoremap <Leader>q :q<CR>
125
126" Map <Leader>x to save and quit
127nnoremap <Leader>x :wq<CR>
128
129" Enable folding
130set foldmethod=syntax
131set foldlevelstart=99
132
133" Enable line wrapping at 80 characters
134set textwidth=80
135set colorcolumn=80
136
137" Add some basic key mappings
138" Map jj to escape insert mode
139inoremap jj <Esc>
140
141" Map <Leader>n to toggle line numbers
142nnoremap <Leader>n :set number!<CR>
143
144" Map <Leader>r to toggle relative line numbers
145nnoremap <Leader>r :set relativenumber!<CR>
146
147" Configure plugins (if you use a plugin manager like vim-plug)
148" Example with vim-plug:
149" call plug#begin('~/.vim/plugged')
150" Plug 'tpope/vim-sensible'
151" Plug 'preservim/nerdtree'
152" Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
153" Plug 'airblade/vim-gitgutter'
154" call plug#end()
155
156" NERDTree key mappings
157" nnoremap <C-n> :NERDTreeToggle<CR>
158
159" Enable automatic hard wrapping at textwidth (80 chars)
160set formatoptions+=t " Auto-wrap text using textwidth
161set formatoptions+=c " Auto-wrap comments using textwidth
162set formatoptions+=r " Continue comments when pressing Enter
163set formatoptions+=o " Continue comments when using 'o' or 'O'
164set formatoptions+=q " Allow formatting of comments with 'gq'
165set formatoptions+=n " Recognize numbered lists
166set formatoptions+=l " Don't break lines that were already long
167
168" Enable syntax highlighting
169syntax on
170
171" Increase memory limit for complex syntax parsing (Prevents E363)
172set maxmempattern=20000
173
zsh_macos.sh Eredeti
1#!/bin/bash
2set -euo pipefail
3
4# =============================
5# COLORS & LOGGING
6# =============================
7RED='\033[0;31m'
8GREEN='\033[0;32m'
9YELLOW='\033[1;33m'
10BLUE='\033[0;34m'
11NC='\033[0m'
12
13log() { echo -e "${BLUE}[INFO]${NC} $*"; }
14ok() { echo -e "${GREEN}[OK]${NC} $*"; }
15warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
16err() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
17
18# =============================
19# CONFIG
20# =============================
21GIST_RAW_BASE="https://opengist.resetrix.work/weehong/f0d940c3c1214bf5b7996195199fdc09/raw/HEAD"
22
23CONFIG_FILES=(
24 ".alias"
25 ".func"
26 ".pathrc"
27 ".sourcerc"
28 ".vimrc"
29 ".zshrc"
30 ".config/starship.toml"
31)
32
33# =============================
34# REQUIREMENTS
35# =============================
36check_requirements() {
37 if [[ $EUID -eq 0 ]]; then
38 err "Do not run as root on macOS"
39 exit 1
40 fi
41}
42
43# =============================
44# INSTALLATION FUNCTIONS
45# =============================
46install_oh_my_zsh() {
47 log "Installing Oh My Zsh and plugins..."
48 export RUNZSH=no
49 export CHSH=no
50 export KEEP_ZSHRC=yes
51
52 if [[ ! -d "$HOME/.oh-my-zsh" ]]; then
53 sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" --unattended
54 else
55 ok "Oh My Zsh already installed"
56 fi
57
58 local custom="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}"
59 local plugin_dir="$custom/plugins"
60 mkdir -p "$plugin_dir"
61
62 [[ -d "$plugin_dir/zsh-autosuggestions" ]] || \
63 git clone https://github.com/zsh-users/zsh-autosuggestions "$plugin_dir/zsh-autosuggestions"
64
65 [[ -d "$plugin_dir/zsh-syntax-highlighting" ]] || \
66 git clone https://github.com/zsh-users/zsh-syntax-highlighting "$plugin_dir/zsh-syntax-highlighting"
67
68 ok "Oh My Zsh plugins installed to $plugin_dir"
69}
70
71install_starship() {
72 if command -v starship >/dev/null 2>&1 || [[ -f "$HOME/.local/bin/starship" ]]; then
73 ok "Starship already installed"
74 elif command -v brew >/dev/null 2>&1; then
75 log "Installing Starship with Homebrew..."
76 brew install starship
77 ok "Starship installed"
78 else
79 log "Installing Starship..."
80 mkdir -p "$HOME/.local/bin"
81 curl -fsSL https://starship.rs/install.sh | sh -s -- -y -b "$HOME/.local/bin"
82 ok "Starship installed"
83 fi
84}
85
86download_configs() {
87 log "Downloading custom config files..."
88 local backup="$HOME/.config_backup_$(date +%Y%m%d_%H%M%S)"
89 mkdir -p "$backup"
90
91 for f in "${CONFIG_FILES[@]}"; do
92 # Strip the leading dot for the download URL
93 local remote_file="${f#.}"
94 [[ "$f" == ".config/starship.toml" ]] && remote_file="starship.toml"
95 local url="$GIST_RAW_BASE/$remote_file"
96 local target="$HOME/$f"
97 local tmp="${target}.tmp.$$"
98
99 mkdir -p "$(dirname "$target")"
100
101 if [[ -f "$target" ]]; then
102 cp "$target" "$backup/"
103 fi
104
105 log "Fetching $remote_file -> $f ..."
106 if curl -fsSL "$url" -o "$tmp"; then
107 mv "$tmp" "$target"
108 else
109 rm -f "$tmp"
110 warn "Failed to download $remote_file"
111 fi
112 done
113
114 ok "Configs downloaded (Backup at $backup)"
115}
116
117configure_zshrc() {
118 local zshrc="$HOME/.zshrc"
119 log "Configuring .zshrc for Oh My Zsh and Starship..."
120
121 touch "$zshrc"
122 cp "$zshrc" "$HOME/.zshrc.backup_$(date +%Y%m%d_%H%M%S)"
123
124 cat > "$zshrc" <<'EOF'
125# =============================================================================
126# 1. HELPER FUNCTIONS & PATH
127# =============================================================================
128source_if_readable() {
129 local file="$1"
130 if [[ -f "$file" && -r "$file" ]]; then
131 source "$file"
132 fi
133}
134
135export PATH="$HOME/.local/bin:$PATH"
136
137# =============================================================================
138# 2. OH MY ZSH FRAMEWORK
139# =============================================================================
140export ZSH="${ZSH:-$HOME/.oh-my-zsh}"
141ZSH_THEME=""
142
143plugins=(
144 git
145 zsh-autosuggestions
146 zsh-syntax-highlighting
147)
148
149source_if_readable "$ZSH/oh-my-zsh.sh"
150
151# =============================================================================
152# 3. THIRD-PARTY INITIALIZATION & CUSTOM CONFIGS
153# =============================================================================
154source_if_readable "$HOME/.sourcerc"
155source_if_readable "$HOME/.func"
156source_if_readable "$HOME/.pathrc"
157source_if_readable "$HOME/.alias"
158
159# =============================================================================
160# 4. STARSHIP PROMPT
161# =============================================================================
162if [[ -z "${STARSHIP_CONFIG:-}" && -f "$HOME/.config/starship.toml" ]]; then
163 export STARSHIP_CONFIG="$HOME/.config/starship.toml"
164fi
165
166if command -v starship >/dev/null 2>&1; then
167 eval "$(starship init zsh)"
168elif [[ -x "$HOME/.local/bin/starship" ]]; then
169 eval "$("$HOME/.local/bin/starship" init zsh)"
170fi
171EOF
172
173 ok ".zshrc configured for Oh My Zsh framework with Starship prompt"
174}
175
176switch_shell() {
177 log "Starting Zsh session..."
178 echo -e "${YELLOW}Type 'exit' to return to this installer menu.${NC}"
179 echo "----------------------------------------"
180 zsh -l
181 echo "----------------------------------------"
182 ok "Returned from Zsh session"
183}
184
185# =============================
186# INTERACTIVE MENU
187# =============================
188show_menu() {
189 echo "==========================================="
190 echo "macOS Minimal Zsh Setup - Choose what to do"
191 echo "==========================================="
192 echo " 0) Run ALL steps (1-5)"
193 echo " 1) Install Oh My Zsh + plugins"
194 echo " 2) Install Starship prompt"
195 echo " 3) Download custom configs (~/.alias, .func, .vimrc, etc.)"
196 echo " 4) Configure ~/.zshrc (Oh My Zsh + Starship)"
197 echo " 5) Switch to Zsh (Temporary Sub-shell)"
198 echo " 6) Quit"
199 echo "==========================================="
200}
201
202run_choices() {
203 local input
204 read -p "Select: " input
205 input="${input//,/ }"
206
207 local -a to_run=()
208 local -a to_exclude=()
209
210 for item in $input; do
211 if [[ "$item" == !* ]]; then
212 to_exclude+=("${item:1}")
213 elif [[ "$item" == "0" ]]; then
214 to_run+=(1 2 3 4 5)
215 else
216 to_run+=("$item")
217 fi
218 done
219
220 if [[ ${#to_run[@]} -gt 0 ]]; then
221 for choice in "${to_run[@]}"; do
222 local skip=false
223
224 if [[ ${#to_exclude[@]} -gt 0 ]]; then
225 for ex in "${to_exclude[@]}"; do
226 if [[ "$choice" == "$ex" ]]; then
227 skip=true
228 break
229 fi
230 done
231 fi
232
233 $skip && continue
234
235 case "$choice" in
236 1) install_oh_my_zsh ;;
237 2) install_starship ;;
238 3) download_configs ;;
239 4) configure_zshrc ;;
240 5) switch_shell ;;
241 6) exit 0 ;;
242 *) warn "Skipping invalid option: $choice" ;;
243 esac
244 echo
245 done
246 fi
247}
248
249# =============================
250# MAIN
251# =============================
252main() {
253 check_requirements
254 while true; do
255 show_menu
256 run_choices
257 read -p "Do you want to run more options? (y/n): " again
258 [[ "$again" =~ ^[Yy]$ ]] || break
259 done
260 ok "macOS minimal Zsh configuration complete!"
261}
262
263main "$@"
264
zsh_ubuntu.sh Eredeti
1#!/bin/bash
2set -euo pipefail
3
4# =============================
5# COLORS & LOGGING
6# =============================
7RED='\033[0;31m'
8GREEN='\033[0;32m'
9YELLOW='\033[1;33m'
10BLUE='\033[0;34m'
11NC='\033[0m'
12
13log() { echo -e "${BLUE}[INFO]${NC} $*"; }
14ok() { echo -e "${GREEN}[OK]${NC} $*"; }
15warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
16err() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
17
18# =============================
19# FLAGS & CONFIG
20# =============================
21SKIP_PACKAGES=false
22SKIP_SHELL_CHANGE=false
23INSTALL_HOMEBREW=false
24
25GIST_RAW_BASE="https://opengist.resetrix.work/weehong/f0d940c3c1214bf5b7996195199fdc09/raw/HEAD"
26CONFIG_FILES=(
27 ".alias"
28 ".func"
29 ".pathrc"
30 ".sourcerc"
31 ".vimrc"
32 ".zshrc"
33 ".config/starship.toml"
34)
35
36# =============================
37# OS DETECTION
38# =============================
39detect_os() {
40 if [[ "$OSTYPE" == "darwin"* ]]; then
41 echo "macos"
42 elif [ -f /etc/os-release ]; then
43 . /etc/os-release
44 echo "$ID"
45 else
46 echo "unknown"
47 fi
48}
49
50# =============================
51# REQUIREMENTS
52# =============================
53check_requirements() {
54 if [[ $EUID -eq 0 ]]; then
55 err "Do not run as root. The script will request sudo when necessary."
56 exit 1
57 fi
58 if [[ "$(detect_os)" != "macos" ]] && ! command -v sudo >/dev/null 2>&1; then
59 err "sudo required on Linux"
60 exit 1
61 fi
62}
63
64# =============================
65# INSTALLATION FUNCTIONS
66# =============================
67update_system() {
68 $SKIP_PACKAGES && return
69 log "Updating system..."
70 local os=$(detect_os)
71
72 case "$os" in
73 macos)
74 brew update || warn "Homebrew update failed; continuing installer"
75 ;;
76 ubuntu|debian)
77 sudo apt-get update -y
78 if ! sudo apt-get upgrade -y; then
79 warn "System upgrade did not complete. This can happen when apt wants to downgrade a package."
80 warn "Continuing because the Zsh setup does not require OS package upgrades to finish."
81 fi
82 ;;
83 fedora)
84 sudo dnf upgrade -y || warn "System upgrade failed; continuing installer"
85 ;;
86 arch)
87 sudo pacman -Syu --noconfirm || warn "System upgrade failed; continuing installer"
88 ;;
89 *) warn "Auto-update not supported for OS: $os" ;;
90 esac
91 ok "System update step finished"
92}
93
94install_packages() {
95 $SKIP_PACKAGES && return
96 log "Installing core packages..."
97 local os=$(detect_os)
98
99 case "$os" in
100 macos) brew install zsh git vim curl wget unzip xz ;;
101 ubuntu|debian) sudo apt-get install -y zsh git vim curl wget unzip zip build-essential xz-utils ;;
102 fedora) sudo dnf install -y zsh git vim curl wget unzip zip @development-tools xz ;;
103 arch) sudo pacman -S --noconfirm zsh git vim curl wget unzip zip base-devel xz ;;
104 *) warn "Auto-install not supported for OS: $os. Please install zsh, git, vim, curl manually." ;;
105 esac
106 ok "Packages installed"
107}
108
109set_timezone() {
110 log "Setting timezone to Asia/Singapore..."
111 local os=$(detect_os)
112 if [[ "$os" == "macos" ]]; then
113 sudo systemsetup -settimezone Asia/Singapore >/dev/null
114 else
115 sudo timedatectl set-timezone Asia/Singapore
116 fi
117 ok "Timezone set to Asia/Singapore"
118}
119
120install_homebrew() {
121 ! $INSTALL_HOMEBREW && return
122 command -v brew >/dev/null 2>&1 && ok "Homebrew already installed" && return
123 log "Installing Homebrew..."
124 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
125 ok "Homebrew installed"
126}
127
128configure_shell() {
129 $SKIP_SHELL_CHANGE && return
130 log "Changing default shell to zsh..."
131 local zsh_path
132 zsh_path="$(command -v zsh)"
133
134 if ! grep -qx "$zsh_path" /etc/shells; then
135 echo "$zsh_path" | sudo tee -a /etc/shells >/dev/null
136 fi
137 chsh -s "$zsh_path"
138 ok "Shell changed (requires logout/login to take effect)"
139}
140
141install_oh_my_zsh() {
142 log "Installing Oh My Zsh and plugins..."
143 export RUNZSH=no
144 export CHSH=no
145 export KEEP_ZSHRC=yes
146
147 if [[ ! -d "$HOME/.oh-my-zsh" ]]; then
148 sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" --unattended
149 else
150 ok "Oh My Zsh already installed"
151 fi
152
153 local custom="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}"
154 local plugin_dir="$custom/plugins"
155 mkdir -p "$plugin_dir"
156
157 [[ -d "$plugin_dir/zsh-autosuggestions" ]] || git clone https://github.com/zsh-users/zsh-autosuggestions "$plugin_dir/zsh-autosuggestions"
158 [[ -d "$plugin_dir/zsh-syntax-highlighting" ]] || git clone https://github.com/zsh-users/zsh-syntax-highlighting "$plugin_dir/zsh-syntax-highlighting"
159
160 ok "Oh My Zsh plugins installed to $plugin_dir"
161}
162
163install_starship() {
164 if command -v starship >/dev/null 2>&1 || [[ -f "$HOME/.local/bin/starship" ]]; then
165 ok "Starship already installed"
166 else
167 log "Installing Starship prompt..."
168 if command -v brew >/dev/null 2>&1; then
169 brew install starship
170 else
171 mkdir -p "$HOME/.local/bin"
172 curl -fsSL https://starship.rs/install.sh | sh -s -- -y -b "$HOME/.local/bin"
173 fi
174 ok "Starship installed"
175 fi
176}
177
178download_configs() {
179 log "Downloading custom config files from OpenGist..."
180 local backup="$HOME/.config_backup_$(date +%Y%m%d_%H%M%S)"
181 mkdir -p "$backup"
182
183 for f in "${CONFIG_FILES[@]}"; do
184 local remote_file="${f#.}"
185 [[ "$f" == ".config/starship.toml" ]] && remote_file="starship.toml"
186 local url="$GIST_RAW_BASE/$remote_file"
187 local target="$HOME/$f"
188 local tmp="${target}.tmp.$$"
189
190 mkdir -p "$(dirname "$target")"
191
192 if [[ -f "$target" ]]; then
193 cp "$target" "$backup/"
194 fi
195
196 log "Fetching $remote_file -> $f ..."
197 if curl -fsSL "$url" -o "$tmp"; then
198 mv "$tmp" "$target"
199 else
200 rm -f "$tmp"
201 warn "Failed to download $remote_file"
202 fi
203 done
204
205 ok "Configs downloaded (Backup at $backup)"
206}
207
208configure_zshrc() {
209 local zshrc="$HOME/.zshrc"
210 log "Configuring .zshrc for Oh My Zsh and Starship..."
211
212 touch "$zshrc"
213 cp "$zshrc" "$HOME/.zshrc.backup_$(date +%Y%m%d_%H%M%S)"
214
215 cat > "$zshrc" <<'EOF'
216# =============================================================================
217# 1. HELPER FUNCTIONS & PATH
218# =============================================================================
219source_if_readable() {
220 local file="$1"
221 if [[ -f "$file" && -r "$file" ]]; then
222 source "$file"
223 fi
224}
225
226export PATH="$HOME/.local/bin:$PATH"
227
228# =============================================================================
229# 2. OH MY ZSH FRAMEWORK
230# =============================================================================
231export ZSH="${ZSH:-$HOME/.oh-my-zsh}"
232ZSH_THEME=""
233
234plugins=(
235 git
236 zsh-autosuggestions
237 zsh-syntax-highlighting
238)
239
240source_if_readable "$ZSH/oh-my-zsh.sh"
241
242# =============================================================================
243# 3. THIRD-PARTY INITIALIZATION & CUSTOM CONFIGS
244# =============================================================================
245source_if_readable "$HOME/.sourcerc"
246source_if_readable "$HOME/.func"
247source_if_readable "$HOME/.pathrc"
248source_if_readable "$HOME/.alias"
249
250# =============================================================================
251# 4. STARSHIP PROMPT
252# =============================================================================
253if [[ -z "${STARSHIP_CONFIG:-}" && -f "$HOME/.config/starship.toml" ]]; then
254 export STARSHIP_CONFIG="$HOME/.config/starship.toml"
255fi
256
257if command -v starship >/dev/null 2>&1; then
258 eval "$(starship init zsh)"
259elif [[ -x "$HOME/.local/bin/starship" ]]; then
260 eval "$("$HOME/.local/bin/starship" init zsh)"
261fi
262EOF
263
264 ok ".zshrc configured for Oh My Zsh framework with Starship prompt"
265}
266
267switch_shell() {
268 log "Starting Zsh session..."
269 echo -e "${YELLOW}Type 'exit' to return to this installer menu.${NC}"
270 echo "----------------------------------------"
271 zsh -l
272 echo "----------------------------------------"
273 ok "Returned from Zsh session"
274}
275
276# =============================
277# INTERACTIVE MENU
278# =============================
279show_menu() {
280 echo "==========================================="
281 echo "Minimal Zsh Installer - Choose what to do"
282 echo "==========================================="
283 echo " 0) Run ALL steps (1-10)"
284 echo " 1) Update system packages"
285 echo " 2) Install core packages (zsh, git, vim, etc.)"
286 echo " 3) Set Timezone (Asia/Singapore)"
287 echo " 4) Install Homebrew"
288 echo " 5) Configure shell (chsh - sets default shell)"
289 echo " 6) Install Oh My Zsh + plugins"
290 echo " 7) Install Starship prompt"
291 echo " 8) Download custom configs (from OpenGist)"
292 echo " 9) Configure ~/.zshrc (Oh My Zsh + Starship)"
293 echo "10) Switch to Zsh (Temporary Sub-shell)"
294 echo "11) Quit"
295 echo "==========================================="
296}
297
298run_choices() {
299 local input
300 read -p "Select: " input
301 input="${input//,/ }"
302
303 local -a to_run=()
304 local -a to_exclude=()
305
306 for item in $input; do
307 if [[ "$item" == !* ]]; then
308 to_exclude+=("${item:1}")
309 elif [[ "$item" == "0" ]]; then
310 to_run+=(1 2 3 4 5 6 7 8 9 10)
311 else
312 to_run+=("$item")
313 fi
314 done
315
316 for choice in "${to_run[@]}"; do
317 local skip=false
318
319 for ex in "${to_exclude[@]}"; do
320 if [[ "$choice" == "$ex" ]]; then
321 skip=true
322 break
323 fi
324 done
325
326 $skip && continue
327
328 case "$choice" in
329 1) update_system ;;
330 2) install_packages ;;
331 3) set_timezone ;;
332 4) install_homebrew ;;
333 5) configure_shell ;;
334 6) install_oh_my_zsh ;;
335 7) install_starship ;;
336 8) download_configs ;;
337 9) configure_zshrc ;;
338 10) switch_shell ;;
339 11) log "Exiting..."; exit 0 ;;
340 *) warn "Skipping invalid option: $choice" ;;
341 esac
342 echo
343 done
344}
345
346# =============================
347# MAIN
348# =============================
349main() {
350 check_requirements
351 while true; do
352 show_menu
353 run_choices
354 read -p "Do you want to run more options? (y/n): " again
355 [[ "$again" =~ ^[Yy]$ ]] || break
356 done
357 ok "Zsh installation/configuration complete!"
358}
359
360main "$@"
361
zsh_wsl.sh Eredeti
1#!/bin/bash
2set -euo pipefail
3
4# =============================
5# COLORS & LOGGING
6# =============================
7RED='\033[0;31m'
8GREEN='\033[0;32m'
9YELLOW='\033[1;33m'
10BLUE='\033[0;34m'
11NC='\033[0m'
12
13log() { echo -e "${BLUE}[INFO]${NC} $*"; }
14ok() { echo -e "${GREEN}[OK]${NC} $*"; }
15warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
16err() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
17
18# =============================
19# FLAGS & CONFIG
20# =============================
21SKIP_PACKAGES=false
22SKIP_SHELL_CHANGE=false
23INSTALL_HOMEBREW=false
24
25GIST_RAW_BASE="https://opengist.resetrix.work/weehong/f0d940c3c1214bf5b7996195199fdc09/raw/HEAD"
26CONFIG_FILES=(
27 ".alias"
28 ".func"
29 ".pathrc"
30 ".sourcerc"
31 ".vimrc"
32 ".zshrc"
33 ".config/starship.toml"
34)
35
36# =============================
37# PLATFORM DETECTION
38# =============================
39detect_os() {
40 if [ -f /etc/os-release ]; then
41 . /etc/os-release
42 echo "$ID"
43 else
44 echo "unknown"
45 fi
46}
47
48is_wsl() {
49 grep -qi "microsoft" /proc/version 2>/dev/null
50}
51
52# =============================
53# REQUIREMENTS
54# =============================
55check_requirements() {
56 if [[ $EUID -eq 0 ]]; then
57 err "Do not run as root. The script will request sudo when necessary."
58 exit 1
59 fi
60 if ! command -v sudo >/dev/null 2>&1; then
61 err "sudo required"
62 exit 1
63 fi
64 if ! is_wsl; then
65 err "This installer is intended for WSL"
66 exit 1
67 fi
68}
69
70# =============================
71# INSTALLATION FUNCTIONS
72# =============================
73update_system() {
74 $SKIP_PACKAGES && return
75 log "Updating system..."
76 local os=$(detect_os)
77
78 case "$os" in
79 ubuntu|debian)
80 sudo apt-get update -y
81 if ! sudo apt-get upgrade -y; then
82 warn "System upgrade did not complete. This can happen when apt wants to downgrade a package."
83 warn "Continuing because the Zsh setup does not require OS package upgrades to finish."
84 fi
85 ;;
86 fedora)
87 sudo dnf upgrade -y || warn "System upgrade failed; continuing installer"
88 ;;
89 arch)
90 sudo pacman -Syu --noconfirm || warn "System upgrade failed; continuing installer"
91 ;;
92 *) warn "Auto-update not supported for OS: $os" ;;
93 esac
94 ok "System update step finished"
95}
96
97install_packages() {
98 $SKIP_PACKAGES && return
99 log "Installing core packages..."
100 local os=$(detect_os)
101
102 case "$os" in
103 ubuntu|debian) sudo apt-get install -y zsh git vim curl wget unzip zip build-essential xz-utils ;;
104 fedora) sudo dnf install -y zsh git vim curl wget unzip zip @development-tools xz ;;
105 arch) sudo pacman -S --noconfirm zsh git vim curl wget unzip zip base-devel xz ;;
106 *) warn "Auto-install not supported for OS: $os. Please install zsh, git, vim, curl manually." ;;
107 esac
108 ok "Packages installed"
109}
110
111set_timezone() {
112 log "Checking timezone configuration..."
113 if command -v timedatectl >/dev/null 2>&1 && timedatectl status >/dev/null 2>&1; then
114 sudo timedatectl set-timezone Asia/Singapore
115 ok "Timezone set to Asia/Singapore"
116 return
117 fi
118
119 warn "Skipping timezone change: timedatectl is not available in this WSL environment"
120}
121
122install_homebrew() {
123 ! $INSTALL_HOMEBREW && return
124 command -v brew >/dev/null 2>&1 && ok "Homebrew already installed" && return
125 log "Installing Homebrew..."
126 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
127 ok "Homebrew installed"
128}
129
130configure_shell() {
131 $SKIP_SHELL_CHANGE && return
132 log "Changing default shell to zsh..."
133 local zsh_path
134 zsh_path="$(command -v zsh)"
135
136 if ! grep -qx "$zsh_path" /etc/shells; then
137 echo "$zsh_path" | sudo tee -a /etc/shells >/dev/null
138 fi
139 chsh -s "$zsh_path"
140 ok "Shell changed (open a new WSL session for it to take effect)"
141}
142
143install_oh_my_zsh() {
144 log "Installing Oh My Zsh and plugins..."
145 export RUNZSH=no
146 export CHSH=no
147 export KEEP_ZSHRC=yes
148
149 if [[ ! -d "$HOME/.oh-my-zsh" ]]; then
150 sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" --unattended
151 else
152 ok "Oh My Zsh already installed"
153 fi
154
155 local custom="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}"
156 local plugin_dir="$custom/plugins"
157 mkdir -p "$plugin_dir"
158
159 [[ -d "$plugin_dir/zsh-autosuggestions" ]] || git clone https://github.com/zsh-users/zsh-autosuggestions "$plugin_dir/zsh-autosuggestions"
160 [[ -d "$plugin_dir/zsh-syntax-highlighting" ]] || git clone https://github.com/zsh-users/zsh-syntax-highlighting "$plugin_dir/zsh-syntax-highlighting"
161
162 ok "Oh My Zsh plugins installed to $plugin_dir"
163}
164
165install_starship() {
166 if command -v starship >/dev/null 2>&1 || [[ -f "$HOME/.local/bin/starship" ]]; then
167 ok "Starship already installed"
168 else
169 log "Installing Starship prompt..."
170 if command -v brew >/dev/null 2>&1; then
171 brew install starship
172 else
173 mkdir -p "$HOME/.local/bin"
174 curl -fsSL https://starship.rs/install.sh | sh -s -- -y -b "$HOME/.local/bin"
175 fi
176 ok "Starship installed"
177 fi
178}
179
180download_configs() {
181 log "Downloading custom config files from OpenGist..."
182 local backup="$HOME/.config_backup_$(date +%Y%m%d_%H%M%S)"
183 mkdir -p "$backup"
184
185 for f in "${CONFIG_FILES[@]}"; do
186 local remote_file="${f#.}"
187 [[ "$f" == ".config/starship.toml" ]] && remote_file="starship.toml"
188 local url="$GIST_RAW_BASE/$remote_file"
189 local target="$HOME/$f"
190 local tmp="${target}.tmp.$$"
191
192 mkdir -p "$(dirname "$target")"
193
194 if [[ -f "$target" ]]; then
195 cp "$target" "$backup/"
196 fi
197
198 log "Fetching $remote_file -> $f ..."
199 if curl -fsSL "$url" -o "$tmp"; then
200 mv "$tmp" "$target"
201 else
202 rm -f "$tmp"
203 warn "Failed to download $remote_file"
204 fi
205 done
206
207 ok "Configs downloaded (Backup at $backup)"
208}
209
210configure_zshrc() {
211 local zshrc="$HOME/.zshrc"
212 log "Configuring .zshrc for Oh My Zsh and Starship..."
213
214 touch "$zshrc"
215 cp "$zshrc" "$HOME/.zshrc.backup_$(date +%Y%m%d_%H%M%S)"
216
217 cat > "$zshrc" <<'EOF'
218# =============================================================================
219# 1. HELPER FUNCTIONS & PATH
220# =============================================================================
221source_if_readable() {
222 local file="$1"
223 if [[ -f "$file" && -r "$file" ]]; then
224 source "$file"
225 fi
226}
227
228export PATH="$HOME/.local/bin:$PATH"
229
230# =============================================================================
231# 2. OH MY ZSH FRAMEWORK
232# =============================================================================
233export ZSH="${ZSH:-$HOME/.oh-my-zsh}"
234ZSH_THEME=""
235
236plugins=(
237 git
238 zsh-autosuggestions
239 zsh-syntax-highlighting
240)
241
242source_if_readable "$ZSH/oh-my-zsh.sh"
243
244# =============================================================================
245# 3. THIRD-PARTY INITIALIZATION & CUSTOM CONFIGS
246# =============================================================================
247source_if_readable "$HOME/.sourcerc"
248source_if_readable "$HOME/.func"
249source_if_readable "$HOME/.pathrc"
250source_if_readable "$HOME/.alias"
251
252# =============================================================================
253# 4. STARSHIP PROMPT
254# =============================================================================
255if [[ -z "${STARSHIP_CONFIG:-}" && -f "$HOME/.config/starship.toml" ]]; then
256 export STARSHIP_CONFIG="$HOME/.config/starship.toml"
257fi
258
259if command -v starship >/dev/null 2>&1; then
260 eval "$(starship init zsh)"
261elif [[ -x "$HOME/.local/bin/starship" ]]; then
262 eval "$("$HOME/.local/bin/starship" init zsh)"
263fi
264EOF
265
266 ok ".zshrc configured for Oh My Zsh framework with Starship prompt"
267}
268
269switch_shell() {
270 log "Starting Zsh session..."
271 echo -e "${YELLOW}Type 'exit' to return to this installer menu.${NC}"
272 echo "----------------------------------------"
273 zsh -l
274 echo "----------------------------------------"
275 ok "Returned from Zsh session"
276}
277
278# =============================
279# INTERACTIVE MENU
280# =============================
281show_menu() {
282 echo "==========================================="
283 echo "WSL Minimal Zsh Installer - Choose what to do"
284 echo "==========================================="
285 echo " 0) Run ALL steps (1-10)"
286 echo " 1) Update system packages"
287 echo " 2) Install core packages (zsh, git, vim, etc.)"
288 echo " 3) Set Timezone (best effort)"
289 echo " 4) Install Homebrew"
290 echo " 5) Configure shell (chsh - sets default shell)"
291 echo " 6) Install Oh My Zsh + plugins"
292 echo " 7) Install Starship prompt"
293 echo " 8) Download custom configs (from OpenGist)"
294 echo " 9) Configure ~/.zshrc (Oh My Zsh + Starship)"
295 echo "10) Switch to Zsh (Temporary Sub-shell)"
296 echo "11) Quit"
297 echo "==========================================="
298}
299
300run_choices() {
301 local input
302 read -p "Select: " input
303 input="${input//,/ }"
304
305 local -a to_run=()
306 local -a to_exclude=()
307
308 for item in $input; do
309 if [[ "$item" == !* ]]; then
310 to_exclude+=("${item:1}")
311 elif [[ "$item" == "0" ]]; then
312 to_run+=(1 2 3 4 5 6 7 8 9 10)
313 else
314 to_run+=("$item")
315 fi
316 done
317
318 for choice in "${to_run[@]}"; do
319 local skip=false
320
321 for ex in "${to_exclude[@]}"; do
322 if [[ "$choice" == "$ex" ]]; then
323 skip=true
324 break
325 fi
326 done
327
328 $skip && continue
329
330 case "$choice" in
331 1) update_system ;;
332 2) install_packages ;;
333 3) set_timezone ;;
334 4) install_homebrew ;;
335 5) configure_shell ;;
336 6) install_oh_my_zsh ;;
337 7) install_starship ;;
338 8) download_configs ;;
339 9) configure_zshrc ;;
340 10) switch_shell ;;
341 11) log "Exiting..."; exit 0 ;;
342 *) warn "Skipping invalid option: $choice" ;;
343 esac
344 echo
345 done
346}
347
348# =============================
349# MAIN
350# =============================
351main() {
352 check_requirements
353 while true; do
354 show_menu
355 run_choices
356 read -p "Do you want to run more options? (y/n): " again
357 [[ "$again" =~ ^[Yy]$ ]] || break
358 done
359 ok "WSL Zsh installation/configuration complete!"
360}
361
362main "$@"
363
zshrc Eredeti
1# =============================================================================
2# 1. HELPER FUNCTIONS & PATH
3# =============================================================================
4source_if_readable() {
5 local file="$1"
6 if [[ -f "$file" && -r "$file" ]]; then
7 source "$file"
8 fi
9}
10
11# Ensure local bin is in PATH early (catches manual Starship installations)
12export PATH="$HOME/.local/bin:$PATH"
13
14# =============================================================================
15# 2. OH MY ZSH FRAMEWORK
16# =============================================================================
17export ZSH="${ZSH:-$HOME/.oh-my-zsh}"
18ZSH_THEME=""
19
20plugins=(
21 git
22 zsh-autosuggestions
23 zsh-syntax-highlighting
24)
25
26source_if_readable "$ZSH/oh-my-zsh.sh"
27
28# =============================================================================
29# 3. THIRD-PARTY INITIALIZATION & CUSTOM CONFIGS
30# =============================================================================
31# Load external initializers (SDKMAN, NVM, etc.)
32source_if_readable "$HOME/.sourcerc"
33
34# Custom Functions (must load before Path Management)
35source_if_readable "$HOME/.func"
36
37# Path Management (Relies on append_path from .func)
38source_if_readable "$HOME/.pathrc"
39
40# Aliases (Loaded late so they override framework/system defaults)
41source_if_readable "$HOME/.alias"
42
43# =============================================================================
44# 4. STARSHIP PROMPT
45# =============================================================================
46if [[ -z "${STARSHIP_CONFIG:-}" && -f "$HOME/.config/starship.toml" ]]; then
47 export STARSHIP_CONFIG="$HOME/.config/starship.toml"
48fi
49
50# Starship owns the prompt. It must initialize after Oh My Zsh.
51if command -v starship >/dev/null 2>&1; then
52 eval "$(starship init zsh)"
53elif [[ -x "$HOME/.local/bin/starship" ]]; then
54 eval "$("$HOME/.local/bin/starship" init zsh)"
55fi
56