Merge pull request 'feat: first-run initialization routine' (#34) from feat/first-run-init into main
Reviewed-on: #34
This commit was merged in pull request #34.
This commit is contained in:
@@ -51,6 +51,7 @@ This config layers on top of the CachyOS base Fish configuration and adds:
|
|||||||
│ ├── theme.fish # Theme syntax highlighting colors
|
│ ├── theme.fish # Theme syntax highlighting colors
|
||||||
│ ├── done.fish # Done plugin (desktop notifications for long commands)
|
│ ├── done.fish # Done plugin (desktop notifications for long commands)
|
||||||
│ ├── tricks.fish # PATH, bang-bang helpers, bat man pages, system aliases, history/backup utilities
|
│ ├── tricks.fish # PATH, bang-bang helpers, bat man pages, system aliases, history/backup utilities
|
||||||
|
│ ├── first_run.fish # One-time initialization: Fisher bootstrap, theme, welcome message
|
||||||
│ ├── paru-wrapper.fish # Auto-generates ~/.local/bin/paru logging wrapper on first run
|
│ ├── paru-wrapper.fish # Auto-generates ~/.local/bin/paru logging wrapper on first run
|
||||||
│ ├── yay-wrapper.fish # Auto-generates ~/.local/bin/yay logging wrapper on first run
|
│ ├── yay-wrapper.fish # Auto-generates ~/.local/bin/yay logging wrapper on first run
|
||||||
│ ├── starship.fish # fish_prompt with OSC 133;A/B shell-integration markers
|
│ ├── starship.fish # fish_prompt with OSC 133;A/B shell-integration markers
|
||||||
@@ -86,7 +87,15 @@ Managed via [Fisher](https://github.com/jorgebucaran/fisher):
|
|||||||
| `nickeb96/puffer-fish` | Expand `...` to `../..`, `!!` to last command, etc. |
|
| `nickeb96/puffer-fish` | Expand `...` to `../..`, `!!` to last command, etc. |
|
||||||
| `jorgebucaran/spark.fish` | Sparkline bar charts in the terminal |
|
| `jorgebucaran/spark.fish` | Sparkline bar charts in the terminal |
|
||||||
|
|
||||||
Fisher and all listed plugins are installed automatically by the bootstrap script in `config.fish` upon launching the shell for the first time.
|
Fisher and all listed plugins are installed automatically by `conf.d/first_run.fish` on the first interactive session. This also applies the Catppuccin Mocha theme and prints a one-time welcome message. Subsequent launches are unaffected.
|
||||||
|
|
||||||
|
To re-trigger first-run initialization (e.g., after a fresh clone):
|
||||||
|
|
||||||
|
```fish
|
||||||
|
set -Ue __fish_config_first_run_complete
|
||||||
|
```
|
||||||
|
|
||||||
|
Then open a new shell.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# Copyright (C) 2026 Rootiest
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
# ╭──────────────────────────────────────────────────────────╮
|
||||||
|
# │ First-Run Initialization │
|
||||||
|
# ╰──────────────────────────────────────────────────────────╯
|
||||||
|
#
|
||||||
|
# Runs exactly once on the first interactive fish session after install.
|
||||||
|
# To reset for testing, run: set -Ue __fish_config_first_run_complete
|
||||||
|
|
||||||
|
# Exit early in non-interactive shells (scripts, completions, subshells)
|
||||||
|
if not status is-interactive
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Skip if this shell has already been initialized
|
||||||
|
if set -q __fish_config_first_run_complete
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Set the flag immediately — before actions — so a mid-run crash doesn't
|
||||||
|
# leave the shell in a state that re-triggers everything next session.
|
||||||
|
set -U __fish_config_first_run_complete 1
|
||||||
|
|
||||||
|
# ──────────────────────────── Welcome message ───────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo " Welcome to your fish shell configuration!"
|
||||||
|
echo " Run 'config-help' for offline documentation."
|
||||||
|
echo " Run 'fish-deps' to check and install dependencies."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# ──────────────────────────── Bootstrap Fisher ──────────────────────────
|
||||||
|
if not type -q fisher
|
||||||
|
echo " [first-run] Installing Fisher plugin manager..."
|
||||||
|
if curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source
|
||||||
|
echo " [first-run] Fisher installed."
|
||||||
|
if not fisher update 2>/dev/null
|
||||||
|
echo " [first-run] Plugin sync failed — run 'fisher update' manually." >&2
|
||||||
|
end
|
||||||
|
else
|
||||||
|
echo " [first-run] Fisher install failed — run 'fisher update' manually." >&2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# ───────────────────────────── Apply theme ──────────────────────────────
|
||||||
|
# Catppuccin Mocha theme ships with this config in themes/; it is always available.
|
||||||
|
if not fish_config theme choose "Catppuccin Mocha" 2>/dev/null
|
||||||
|
echo " [first-run] Could not apply Catppuccin Mocha theme — set manually with 'fish_config theme choose'." >&2
|
||||||
|
end
|
||||||
+1
-13
@@ -115,19 +115,7 @@ fish_add_path $HOME/.fzf/bin # Fuzzy Finder (fzf) core binary an
|
|||||||
set -gx CDPATH . $HOME/projects $HOME
|
set -gx CDPATH . $HOME/projects $HOME
|
||||||
|
|
||||||
# ──────────────────────────── Bootstrap Fisher ──────────────────────────
|
# ──────────────────────────── Bootstrap Fisher ──────────────────────────
|
||||||
if not type -q fisher
|
# Fisher is bootstrapped automatically on first run via conf.d/first_run.fish
|
||||||
echo "Fisher plugin manager not found."
|
|
||||||
read -l -P "Install Fisher and plugins now? [Y/n] " _fisher_reply
|
|
||||||
if test -z "$_fisher_reply" -o "$_fisher_reply" = Y -o "$_fisher_reply" = y
|
|
||||||
echo "Installing Fisher..."
|
|
||||||
curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source
|
|
||||||
fisher update
|
|
||||||
fish_config theme choose "Catppuccin Mocha"
|
|
||||||
else
|
|
||||||
echo "Skipping Fisher install. Some features may be unavailable."
|
|
||||||
end
|
|
||||||
set --erase _fisher_reply
|
|
||||||
end
|
|
||||||
|
|
||||||
# ─────────────────────── Visual/Interactive setup ───────────────────────
|
# ─────────────────────── Visual/Interactive setup ───────────────────────
|
||||||
# Run only if we're in an interactive session (not a script or non-interactive shell)
|
# Run only if we're in an interactive session (not a script or non-interactive shell)
|
||||||
|
|||||||
+12
-1
@@ -1196,7 +1196,18 @@ fish_variables.
|
|||||||
|
|
||||||
# 8. FISHER PLUGINS
|
# 8. FISHER PLUGINS
|
||||||
|
|
||||||
Fisher is bootstrapped automatically on first shell start if not present.
|
Fisher is bootstrapped automatically on the **first interactive session** via
|
||||||
|
`conf.d/first_run.fish`. This also applies the Catppuccin Mocha theme and
|
||||||
|
prints a one-time welcome message. Subsequent sessions skip all first-run
|
||||||
|
logic with zero overhead.
|
||||||
|
|
||||||
|
To re-trigger first-run initialization (e.g., after a fresh install or for
|
||||||
|
testing), run:
|
||||||
|
|
||||||
|
set -Ue __fish_config_first_run_complete
|
||||||
|
|
||||||
|
Then open a new shell.
|
||||||
|
|
||||||
The plugin list is maintained in fish_plugins at the config root.
|
The plugin list is maintained in fish_plugins at the config root.
|
||||||
|
|
||||||
jorgebucaran/fisher Plugin manager itself
|
jorgebucaran/fisher Plugin manager itself
|
||||||
|
|||||||
@@ -0,0 +1,328 @@
|
|||||||
|
# First-Run Initialization Routine — Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** Create `conf.d/first_run.fish` that runs exactly once on the first interactive fish session — showing a welcome message, auto-installing Fisher + plugins, and applying the Catppuccin Mocha theme.
|
||||||
|
|
||||||
|
**Architecture:** A universal variable (`__fish_config_first_run_complete`) acts as the persistent flag. `conf.d/first_run.fish` is auto-sourced by fish on every shell start; it exits immediately if the flag is already set. On first run it sets the flag first (crash-safe), then executes actions in order. The existing interactive Fisher bootstrap in `config.fish` is removed since `first_run.fish` owns that responsibility.
|
||||||
|
|
||||||
|
**Tech Stack:** fish shell 4.x, universal variables (`set -U`), `curl`, `fisher`, `fish_config theme choose`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File Map
|
||||||
|
|
||||||
|
| File | Action | Responsibility |
|
||||||
|
|------|--------|---------------|
|
||||||
|
| `conf.d/first_run.fish` | **Create** | State guard + all first-run actions |
|
||||||
|
| `config.fish` | **Modify** lines 117–130 | Remove interactive Fisher bootstrap block |
|
||||||
|
| `docs/fish-config.md` | **Modify** | Document first-run behavior |
|
||||||
|
| `AGENTS.md` | **Modify** | Check off Task #1 acceptance criteria |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: Remove the interactive Fisher bootstrap from `config.fish`
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `config.fish:117-130`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Delete the Fisher bootstrap block**
|
||||||
|
|
||||||
|
Open `config.fish`. Replace lines 117–130 (the entire Fisher bootstrap block) with a single comment:
|
||||||
|
|
||||||
|
```fish
|
||||||
|
# ──────────────────────────── Bootstrap Fisher ──────────────────────────
|
||||||
|
# Fisher is bootstrapped automatically on first run via conf.d/first_run.fish
|
||||||
|
```
|
||||||
|
|
||||||
|
The block being removed is:
|
||||||
|
```fish
|
||||||
|
# ──────────────────────────── Bootstrap Fisher ──────────────────────────
|
||||||
|
if not type -q fisher
|
||||||
|
echo "Fisher plugin manager not found."
|
||||||
|
read -l -P "Install Fisher and plugins now? [Y/n] " _fisher_reply
|
||||||
|
if test -z "$_fisher_reply" -o "$_fisher_reply" = Y -o "$_fisher_reply" = y
|
||||||
|
echo "Installing Fisher..."
|
||||||
|
curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source
|
||||||
|
fisher update
|
||||||
|
fish_config theme choose "Catppuccin Mocha"
|
||||||
|
else
|
||||||
|
echo "Skipping Fisher install. Some features may be unavailable."
|
||||||
|
end
|
||||||
|
set --erase _fisher_reply
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Verify config.fish still parses cleanly**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fish -n ~/.config/fish/config.fish
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected output: no output (no parse errors).
|
||||||
|
|
||||||
|
- [ ] **Step 3: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add config.fish
|
||||||
|
git commit -m "refactor: move Fisher bootstrap to first_run.fish"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 2: Create `conf.d/first_run.fish`
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `conf.d/first_run.fish`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Create the file with this exact content**
|
||||||
|
|
||||||
|
```fish
|
||||||
|
# Copyright (C) 2026 Rootiest
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
# ╭──────────────────────────────────────────────────────────╮
|
||||||
|
# │ First-Run Initialization │
|
||||||
|
# ╰──────────────────────────────────────────────────────────╯
|
||||||
|
#
|
||||||
|
# Runs exactly once on the first interactive fish session after install.
|
||||||
|
# To reset for testing, run: set -Ue __fish_config_first_run_complete
|
||||||
|
|
||||||
|
# Exit early in non-interactive shells (scripts, completions, subshells)
|
||||||
|
if not status is-interactive
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Skip if this shell has already been initialized
|
||||||
|
if set -q __fish_config_first_run_complete
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Set the flag immediately — before actions — so a mid-run crash doesn't
|
||||||
|
# leave the shell in a state that re-triggers everything next session.
|
||||||
|
set -U __fish_config_first_run_complete 1
|
||||||
|
|
||||||
|
# ──────────────────────────── Welcome message ───────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo " Welcome to your fish shell configuration!"
|
||||||
|
echo " Run 'config-help' for offline documentation."
|
||||||
|
echo " Run 'fish-deps' to check and install dependencies."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# ──────────────────────────── Bootstrap Fisher ──────────────────────────
|
||||||
|
if not type -q fisher
|
||||||
|
echo " [first-run] Installing Fisher plugin manager..."
|
||||||
|
if curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source
|
||||||
|
and fisher update 2>/dev/null
|
||||||
|
echo " [first-run] Fisher installed and plugins loaded."
|
||||||
|
else
|
||||||
|
echo " [first-run] Fisher install failed — run 'fisher update' manually." >&2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# ───────────────────────────── Apply theme ──────────────────────────────
|
||||||
|
# Catppuccin Mocha theme ships with this config in themes/; it is always available.
|
||||||
|
fish_config theme choose "Catppuccin Mocha" 2>/dev/null
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Verify the file parses cleanly**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fish -n ~/.config/fish/conf.d/first_run.fish
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected output: no output (no parse errors).
|
||||||
|
|
||||||
|
- [ ] **Step 3: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add conf.d/first_run.fish
|
||||||
|
git commit -m "feat: add first_run.fish for one-time shell initialization"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 3: Verify first-run behavior
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- No file changes — verification only
|
||||||
|
|
||||||
|
- [ ] **Step 1: Simulate a fresh install by clearing the flag**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fish -c "set -Ue __fish_config_first_run_complete"
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected output: no output (variable erased).
|
||||||
|
|
||||||
|
- [ ] **Step 2: Confirm the flag is gone**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fish -c "set -q __fish_config_first_run_complete; and echo SET; or echo UNSET"
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected output:
|
||||||
|
```
|
||||||
|
UNSET
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Open a new interactive fish shell and observe first-run output**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fish -i -c "exit" 2>/dev/null
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected to see (on the terminal — open a real new tab or run `fish` interactively):
|
||||||
|
```
|
||||||
|
|
||||||
|
Welcome to your fish shell configuration!
|
||||||
|
Run 'config-help' for offline documentation.
|
||||||
|
Run 'fish-deps' to check and install dependencies.
|
||||||
|
|
||||||
|
[first-run] Fisher installed and plugins loaded.
|
||||||
|
```
|
||||||
|
(Fisher output may vary; if Fisher is already installed the Fisher block is skipped.)
|
||||||
|
|
||||||
|
- [ ] **Step 4: Confirm the flag is now set**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fish -c "set -q __fish_config_first_run_complete; and echo SET; or echo UNSET"
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected output:
|
||||||
|
```
|
||||||
|
SET
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 5: Open another interactive shell — confirm no first-run output**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fish -i -c "exit" 2>/dev/null
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: no welcome message, no Fisher output. The routine is silent on repeat launches.
|
||||||
|
|
||||||
|
- [ ] **Step 6: Verify non-interactive shells are unaffected**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fish -c "echo hello"
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected output:
|
||||||
|
```
|
||||||
|
hello
|
||||||
|
```
|
||||||
|
No welcome message. The `status is-interactive` guard prevents any output.
|
||||||
|
|
||||||
|
- [ ] **Step 7: Commit verification note (no code change needed)**
|
||||||
|
|
||||||
|
If steps 1–6 all pass, no commit needed here — move to Task 4.
|
||||||
|
If a fix was required, commit it:
|
||||||
|
```bash
|
||||||
|
git add conf.d/first_run.fish
|
||||||
|
git commit -m "fix: correct first-run guard behavior"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 4: Update `docs/fish-config.md`
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `docs/fish-config.md`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Find the Fisher bootstrap section in the docs**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -n "Fisher\|fisher\|bootstrap\|first.run\|first_run" docs/fish-config.md | head -20
|
||||||
|
```
|
||||||
|
|
||||||
|
Note the line number of the Fisher bootstrap description (around line 1199 based on current state).
|
||||||
|
|
||||||
|
- [ ] **Step 2: Update the Fisher bootstrap description**
|
||||||
|
|
||||||
|
Find the existing text that says something like:
|
||||||
|
```
|
||||||
|
Fisher is bootstrapped automatically on first shell start if not present.
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace or expand it to read:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
Fisher is bootstrapped automatically on the **first interactive session** via
|
||||||
|
`conf.d/first_run.fish`. This also applies the Catppuccin Mocha theme and
|
||||||
|
prints a one-time welcome message. Subsequent sessions skip all first-run
|
||||||
|
logic with zero overhead.
|
||||||
|
|
||||||
|
To re-trigger first-run initialization (e.g., after a fresh install or for
|
||||||
|
testing), run:
|
||||||
|
|
||||||
|
```fish
|
||||||
|
set -Ue __fish_config_first_run_complete
|
||||||
|
```
|
||||||
|
|
||||||
|
Then open a new shell.
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Verify the docs file is valid (no broken markdown)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fish -c "bat --language=markdown docs/fish-config.md" 2>/dev/null | head -5
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: renders without errors (or just check the file opens cleanly).
|
||||||
|
|
||||||
|
- [ ] **Step 4: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add docs/fish-config.md
|
||||||
|
git commit -m "docs: document first-run initialization in fish-config.md"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 5: Mark acceptance criteria in AGENTS.md
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `AGENTS.md`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Check off the Task #1 acceptance criteria**
|
||||||
|
|
||||||
|
In `AGENTS.md`, find the "First-Run Initialization Routine" section and replace each `- [ ]` with `- [x]`:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
### 1. First-Run Initialization Routine
|
||||||
|
- [x] **State Detection:** Define a persistent universal state variable (`__fish_config_first_run_complete`) to identify if the environment is being initialized for the very first time.
|
||||||
|
- [x] **Execution Logic:** Create the structure for `~/.config/fish/conf.d/first_run.fish`.
|
||||||
|
- [x] **Integration:** Ensure the code inside executes ONLY when the universal variable is not set. It must immediately update the state variable upon execution to prevent running on subsequent interactive shell launches.
|
||||||
|
- [x] **Best Practices:** Ensure the script exits early if the shell is non-interactive to save performance. Include a commented-out example of how to manually reset the state variable for testing.
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add AGENTS.md
|
||||||
|
git commit -m "docs: mark first-run initialization task complete in AGENTS.md"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Self-Review
|
||||||
|
|
||||||
|
**Spec coverage check:**
|
||||||
|
|
||||||
|
| Spec requirement | Task |
|
||||||
|
|-----------------|------|
|
||||||
|
| Universal variable `__fish_config_first_run_complete` | Task 2 |
|
||||||
|
| `conf.d/first_run.fish` file | Task 2 |
|
||||||
|
| Executes only when variable is not set | Task 2 (guard pattern) |
|
||||||
|
| Sets variable immediately to prevent re-run | Task 2 (set before actions) |
|
||||||
|
| Exits early if non-interactive | Task 2 (first guard) |
|
||||||
|
| Commented reset example | Task 2 (top of file comment) |
|
||||||
|
| Welcome message | Task 2 |
|
||||||
|
| Fisher bootstrap (automatic, no prompt) | Task 2 |
|
||||||
|
| Theme setting | Task 2 |
|
||||||
|
| Remove old interactive Fisher prompt from config.fish | Task 1 |
|
||||||
|
| Docs updated | Task 4 |
|
||||||
|
| AGENTS.md checkboxes | Task 5 |
|
||||||
|
|
||||||
|
All spec requirements covered. No placeholders. No TBDs.
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
# First-Run Initialization Routine — Design Spec
|
||||||
|
|
||||||
|
**Date:** 2026-06-07
|
||||||
|
**Status:** Approved
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Provide a mechanism for code/actions that should run exactly once — on the first interactive fish session after the config is installed or reset. Subsequent sessions skip all first-run logic entirely with zero overhead.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### State detection
|
||||||
|
|
||||||
|
A fish **universal variable** (`__fish_config_first_run_complete`) acts as the persistent flag. Universal variables survive shell exits and are stored in `~/.config/fish/fish_variables`. The flag is set to `1` immediately before any first-run actions execute, so a crash mid-run does not re-trigger next session.
|
||||||
|
|
||||||
|
### File: `conf.d/first_run.fish`
|
||||||
|
|
||||||
|
A single auto-sourced file in `conf.d/`. Fish loads all `conf.d/` files before `config.fish`, so this file cannot rely on PATH additions made in `config.fish`. That is acceptable: all first-run actions only need system-level binaries (`curl`, `fish`) that are in PATH unconditionally.
|
||||||
|
|
||||||
|
### Guard pattern
|
||||||
|
|
||||||
|
```fish
|
||||||
|
if status is-interactive
|
||||||
|
if not set -q __fish_config_first_run_complete
|
||||||
|
set -U __fish_config_first_run_complete 1
|
||||||
|
# first-run actions here
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
The `status is-interactive` guard prevents the routine from firing in scripts, completions, or subshells.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## First-Run Actions (in order)
|
||||||
|
|
||||||
|
1. **Welcome message** — print a brief one-time greeting identifying the config and key commands.
|
||||||
|
2. **Fisher bootstrap** — automatically install Fisher and all plugins from `fish_plugins` (replaces the interactive Y/n prompt currently in `config.fish`).
|
||||||
|
3. **Theme** — apply `Catppuccin Mocha` via `fish_config theme choose`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Changes to `config.fish`
|
||||||
|
|
||||||
|
The existing interactive Fisher bootstrap block (lines ~118–130) is removed. `first_run.fish` owns that responsibility. The `config.fish` block was guarded by `not type -q fisher`; the new file guards by the universal variable instead, which is cleaner and avoids re-prompting if Fisher is uninstalled manually.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Reset mechanism
|
||||||
|
|
||||||
|
To re-trigger first-run (e.g., for testing):
|
||||||
|
|
||||||
|
```fish
|
||||||
|
set -Ue __fish_config_first_run_complete
|
||||||
|
```
|
||||||
|
|
||||||
|
A commented-out version of this command is included at the top of `first_run.fish`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Error handling
|
||||||
|
|
||||||
|
- Fisher install failure is surfaced to the user via stderr but does not abort the session.
|
||||||
|
- Theme application is guarded: only runs if `fish_config` is available.
|
||||||
|
- All first-run actions are wrapped in `if status is-interactive` to prevent execution in non-interactive contexts.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Files changed
|
||||||
|
|
||||||
|
| File | Change |
|
||||||
|
|------|--------|
|
||||||
|
| `conf.d/first_run.fish` | **New** — first-run guard and actions |
|
||||||
|
| `config.fish` | Remove interactive Fisher bootstrap block (~lines 118–130) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Success criteria
|
||||||
|
|
||||||
|
- First launch: welcome message printed, Fisher + plugins installed, theme set.
|
||||||
|
- Second launch: nothing extra runs.
|
||||||
|
- `set -Ue __fish_config_first_run_complete` followed by new shell re-triggers all actions.
|
||||||
|
- Non-interactive shells (`fish -c "echo hi"`) are unaffected.
|
||||||
Reference in New Issue
Block a user