Compare commits
105 Commits
nix-deck-s
...
bead/nixos
| Author | SHA1 | Date | |
|---|---|---|---|
| f52b1c1d27 | |||
| 1d9249ea83 | |||
| 2fdd2d5345 | |||
| 722cb315dc | |||
| e042acff16 | |||
| 4fe531f87f | |||
| 266dee9f8f | |||
| 38395c238f | |||
| e4a1771f48 | |||
| ff1fb245ac | |||
| 82fb1738c1 | |||
| 425e4f4cee | |||
| 0e5b11e55d | |||
| 1ba1a8fc9d | |||
| 009b84656f | |||
| ef4e4509d3 | |||
| cd6b528692 | |||
| 3914b54c73 | |||
| 9aa74258f9 | |||
| 64dda20aa4 | |||
| ac01548e89 | |||
| bb7f79843b | |||
| c1d6663a36 | |||
| 3cf4403ffa | |||
| 4e6123de9a | |||
| 19ee298b71 | |||
| 537f7831a7 | |||
| bf0d16fe1a | |||
| 858b6009ae | |||
| 40b323dcfd | |||
| 60bd89b02c | |||
| 5a5de7353b | |||
| e25aa7acab | |||
| 4a284de8a1 | |||
| 7be694ef66 | |||
| 0ccfc30c73 | |||
| dab96a1c50 | |||
| 7898def044 | |||
| 4ce48313f6 | |||
| 2c70504c43 | |||
| a22c7fec28 | |||
| ef3e9b8c82 | |||
| 0590dad71e | |||
| c81594af01 | |||
| 6f999882d3 | |||
| 8bb20bf05e | |||
| c480bcdd1d | |||
| 05fed3ede1 | |||
| 0a9de8d159 | |||
| 055d6ab421 | |||
| d5c6342b84 | |||
| e04dacdf65 | |||
| 7d74917bdc | |||
| 5a4ab71849 | |||
| bcebf9b376 | |||
| 0f76939983 | |||
| a1da2f5cc1 | |||
| 175da48170 | |||
| ac956ef48c | |||
| 0c1190f39c | |||
| 00f05d1bb2 | |||
| 4e6c6ab81d | |||
| 04e1a8563c | |||
| 7278dc8306 | |||
| 066eea2999 | |||
| 80633142fb | |||
| 3029e3d9a8 | |||
| 3483e26bce | |||
| b3add6ddf8 | |||
| 89994e3fc8 | |||
| 0e9671a45f | |||
| f4078970b2 | |||
| 0ae4d84ca2 | |||
| 7c877fde84 | |||
| d53286e04c | |||
| bc42c4dc77 | |||
| 445b0cd558 | |||
| 6d9686f14b | |||
| 4164832eea | |||
| 585f9ef5c7 | |||
| ade60ba5ec | |||
| 48fb7cdada | |||
| 2d8cfe75a0 | |||
| 385fd798de | |||
| fe6558e0c1 | |||
| b9c48f9dd1 | |||
| 34351403d1 | |||
| 12820ce9ff | |||
| 0f5eb2e572 | |||
| f356c91fdb | |||
| 6b42612135 | |||
| 50a8c44d10 | |||
| 7011fb27a5 | |||
| 1ff8b81f44 | |||
| 55f13dfb08 | |||
| 63bf19b85f | |||
| 1f9e9138ab | |||
| e218822566 | |||
| e88f3580e9 | |||
| 5451e75480 | |||
| fc9474a7c9 | |||
| 20daebbd61 | |||
| 3be23304c4 | |||
| 9059a739a0 | |||
| 977125645b |
39
.beads/.gitignore
vendored
Normal file
39
.beads/.gitignore
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# SQLite databases
|
||||||
|
*.db
|
||||||
|
*.db?*
|
||||||
|
*.db-journal
|
||||||
|
*.db-wal
|
||||||
|
*.db-shm
|
||||||
|
|
||||||
|
# Daemon runtime files
|
||||||
|
daemon.lock
|
||||||
|
daemon.log
|
||||||
|
daemon.pid
|
||||||
|
bd.sock
|
||||||
|
sync-state.json
|
||||||
|
last-touched
|
||||||
|
|
||||||
|
# Local version tracking (prevents upgrade notification spam after git ops)
|
||||||
|
.local_version
|
||||||
|
|
||||||
|
# Legacy database files
|
||||||
|
db.sqlite
|
||||||
|
bd.db
|
||||||
|
|
||||||
|
# Worktree redirect file (contains relative path to main repo's .beads/)
|
||||||
|
# Must not be committed as paths would be wrong in other clones
|
||||||
|
redirect
|
||||||
|
|
||||||
|
# Merge artifacts (temporary files from 3-way merge)
|
||||||
|
beads.base.jsonl
|
||||||
|
beads.base.meta.json
|
||||||
|
beads.left.jsonl
|
||||||
|
beads.left.meta.json
|
||||||
|
beads.right.jsonl
|
||||||
|
beads.right.meta.json
|
||||||
|
|
||||||
|
# NOTE: Do NOT add negation patterns (e.g., !issues.jsonl) here.
|
||||||
|
# They would override fork protection in .git/info/exclude, allowing
|
||||||
|
# contributors to accidentally commit upstream issue databases.
|
||||||
|
# The JSONL files (issues.jsonl, interactions.jsonl) and config files
|
||||||
|
# are tracked by git by default since no pattern above ignores them.
|
||||||
0
.beads/.sync.lock
Normal file
0
.beads/.sync.lock
Normal file
81
.beads/README.md
Normal file
81
.beads/README.md
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
# Beads - AI-Native Issue Tracking
|
||||||
|
|
||||||
|
Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code.
|
||||||
|
|
||||||
|
## What is Beads?
|
||||||
|
|
||||||
|
Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git.
|
||||||
|
|
||||||
|
**Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads)
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Essential Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create new issues
|
||||||
|
bd create "Add user authentication"
|
||||||
|
|
||||||
|
# View all issues
|
||||||
|
bd list
|
||||||
|
|
||||||
|
# View issue details
|
||||||
|
bd show <issue-id>
|
||||||
|
|
||||||
|
# Update issue status
|
||||||
|
bd update <issue-id> --status in_progress
|
||||||
|
bd update <issue-id> --status done
|
||||||
|
|
||||||
|
# Sync with git remote
|
||||||
|
bd sync
|
||||||
|
```
|
||||||
|
|
||||||
|
### Working with Issues
|
||||||
|
|
||||||
|
Issues in Beads are:
|
||||||
|
- **Git-native**: Stored in `.beads/issues.jsonl` and synced like code
|
||||||
|
- **AI-friendly**: CLI-first design works perfectly with AI coding agents
|
||||||
|
- **Branch-aware**: Issues can follow your branch workflow
|
||||||
|
- **Always in sync**: Auto-syncs with your commits
|
||||||
|
|
||||||
|
## Why Beads?
|
||||||
|
|
||||||
|
✨ **AI-Native Design**
|
||||||
|
- Built specifically for AI-assisted development workflows
|
||||||
|
- CLI-first interface works seamlessly with AI coding agents
|
||||||
|
- No context switching to web UIs
|
||||||
|
|
||||||
|
🚀 **Developer Focused**
|
||||||
|
- Issues live in your repo, right next to your code
|
||||||
|
- Works offline, syncs when you push
|
||||||
|
- Fast, lightweight, and stays out of your way
|
||||||
|
|
||||||
|
🔧 **Git Integration**
|
||||||
|
- Automatic sync with git commits
|
||||||
|
- Branch-aware issue tracking
|
||||||
|
- Intelligent JSONL merge resolution
|
||||||
|
|
||||||
|
## Get Started with Beads
|
||||||
|
|
||||||
|
Try Beads in your own projects:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install Beads
|
||||||
|
curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
|
||||||
|
|
||||||
|
# Initialize in your repo
|
||||||
|
bd init
|
||||||
|
|
||||||
|
# Create your first issue
|
||||||
|
bd create "Try out Beads"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Learn More
|
||||||
|
|
||||||
|
- **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs)
|
||||||
|
- **Quick Start Guide**: Run `bd quickstart`
|
||||||
|
- **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Beads: Issue tracking that moves at the speed of thought* ⚡
|
||||||
62
.beads/config.yaml
Normal file
62
.beads/config.yaml
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# Beads Configuration File
|
||||||
|
# This file configures default behavior for all bd commands in this repository
|
||||||
|
# All settings can also be set via environment variables (BD_* prefix)
|
||||||
|
# or overridden with command-line flags
|
||||||
|
|
||||||
|
# Issue prefix for this repository (used by bd init)
|
||||||
|
# If not set, bd init will auto-detect from directory name
|
||||||
|
# Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc.
|
||||||
|
# issue-prefix: ""
|
||||||
|
|
||||||
|
# Use no-db mode: load from JSONL, no SQLite, write back after each command
|
||||||
|
# When true, bd will use .beads/issues.jsonl as the source of truth
|
||||||
|
# instead of SQLite database
|
||||||
|
# no-db: false
|
||||||
|
|
||||||
|
# Disable daemon for RPC communication (forces direct database access)
|
||||||
|
# no-daemon: false
|
||||||
|
|
||||||
|
# Disable auto-flush of database to JSONL after mutations
|
||||||
|
# no-auto-flush: false
|
||||||
|
|
||||||
|
# Disable auto-import from JSONL when it's newer than database
|
||||||
|
# no-auto-import: false
|
||||||
|
|
||||||
|
# Enable JSON output by default
|
||||||
|
# json: false
|
||||||
|
|
||||||
|
# Default actor for audit trails (overridden by BD_ACTOR or --actor)
|
||||||
|
# actor: ""
|
||||||
|
|
||||||
|
# Path to database (overridden by BEADS_DB or --db)
|
||||||
|
# db: ""
|
||||||
|
|
||||||
|
# Auto-start daemon if not running (can also use BEADS_AUTO_START_DAEMON)
|
||||||
|
# auto-start-daemon: true
|
||||||
|
|
||||||
|
# Debounce interval for auto-flush (can also use BEADS_FLUSH_DEBOUNCE)
|
||||||
|
# flush-debounce: "5s"
|
||||||
|
|
||||||
|
# Git branch for beads commits (bd sync will commit to this branch)
|
||||||
|
# IMPORTANT: Set this for team projects so all clones use the same sync branch.
|
||||||
|
# This setting persists across clones (unlike database config which is gitignored).
|
||||||
|
# Can also use BEADS_SYNC_BRANCH env var for local override.
|
||||||
|
# If not set, bd sync will require you to run 'bd config set sync.branch <branch>'.
|
||||||
|
sync-branch: "beads-sync"
|
||||||
|
|
||||||
|
# Multi-repo configuration (experimental - bd-307)
|
||||||
|
# Allows hydrating from multiple repositories and routing writes to the correct JSONL
|
||||||
|
# repos:
|
||||||
|
# primary: "." # Primary repo (where this database lives)
|
||||||
|
# additional: # Additional repos to hydrate from (read-only)
|
||||||
|
# - ~/beads-planning # Personal planning repo
|
||||||
|
# - ~/work-planning # Work planning repo
|
||||||
|
|
||||||
|
# Integration settings (access with 'bd config get/set')
|
||||||
|
# These are stored in the database, not in this file:
|
||||||
|
# - jira.url
|
||||||
|
# - jira.project
|
||||||
|
# - linear.url
|
||||||
|
# - linear.api-key
|
||||||
|
# - github.org
|
||||||
|
# - github.repo
|
||||||
0
.beads/interactions.jsonl
Normal file
0
.beads/interactions.jsonl
Normal file
4
.beads/metadata.json
Normal file
4
.beads/metadata.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"database": "beads.db",
|
||||||
|
"jsonl_export": "sync_base.jsonl"
|
||||||
|
}
|
||||||
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
# Use bd merge for beads JSONL files
|
||||||
|
.beads/issues.jsonl merge=beads
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1 +1,3 @@
|
|||||||
result
|
result
|
||||||
|
thoughts
|
||||||
|
.beads
|
||||||
|
|||||||
52
AGENTS.md
52
AGENTS.md
@@ -172,6 +172,58 @@ Creates an ISO suitable for Ventoy and other USB boot tools in `./result/iso/`.
|
|||||||
- **Garbage collection**: Automatic, deletes older than 10 days
|
- **Garbage collection**: Automatic, deletes older than 10 days
|
||||||
- **Unfree packages**: Allowed globally
|
- **Unfree packages**: Allowed globally
|
||||||
|
|
||||||
|
## Issue Tracking (Gitea)
|
||||||
|
|
||||||
|
**Tea CLI for Gitea:**
|
||||||
|
```bash
|
||||||
|
# Note: When using tea CLI, you must specify --repo johno/nixos-configs
|
||||||
|
# The CLI doesn't automatically detect the repo from git remote
|
||||||
|
|
||||||
|
# List all issues (open by default)
|
||||||
|
tea issues --repo johno/nixos-configs
|
||||||
|
|
||||||
|
# List closed issues
|
||||||
|
tea issues --repo johno/nixos-configs --state closed
|
||||||
|
|
||||||
|
# View specific issue
|
||||||
|
tea issue --repo johno/nixos-configs 2
|
||||||
|
|
||||||
|
# Create new issue
|
||||||
|
tea issues create --repo johno/nixos-configs --title "Issue title" --body "Description"
|
||||||
|
|
||||||
|
# Add comment to issue
|
||||||
|
tea comment --repo johno/nixos-configs 2 "Comment text"
|
||||||
|
|
||||||
|
# Close issue (note: 'issues' is plural, issue number comes last)
|
||||||
|
tea issues close --repo johno/nixos-configs 2
|
||||||
|
```
|
||||||
|
|
||||||
## Important Notes
|
## Important Notes
|
||||||
|
|
||||||
- **Sudo access**: Claude Code does not have sudo access. Ask the user to run elevated commands like `sudo nixos-rebuild switch`
|
- **Sudo access**: Claude Code does not have sudo access. Ask the user to run elevated commands like `sudo nixos-rebuild switch`
|
||||||
|
|
||||||
|
## Landing the Plane (Session Completion)
|
||||||
|
|
||||||
|
**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
|
||||||
|
|
||||||
|
**MANDATORY WORKFLOW:**
|
||||||
|
|
||||||
|
1. **File issues for remaining work** - Create issues for anything that needs follow-up
|
||||||
|
2. **Run quality gates** (if code changed) - Tests, linters, builds
|
||||||
|
3. **Update issue status** - Close finished work, update in-progress items
|
||||||
|
4. **PUSH TO REMOTE** - This is MANDATORY:
|
||||||
|
```bash
|
||||||
|
git pull --rebase
|
||||||
|
bd sync
|
||||||
|
git push
|
||||||
|
git status # MUST show "up to date with origin"
|
||||||
|
```
|
||||||
|
5. **Clean up** - Clear stashes, prune remote branches
|
||||||
|
6. **Verify** - All changes committed AND pushed
|
||||||
|
7. **Hand off** - Provide context for next session
|
||||||
|
|
||||||
|
**CRITICAL RULES:**
|
||||||
|
- Work is NOT complete until `git push` succeeds
|
||||||
|
- NEVER stop before pushing - that leaves work stranded locally
|
||||||
|
- NEVER say "ready to push when you are" - YOU must push
|
||||||
|
- If push fails, resolve and retry until it succeeds
|
||||||
|
|||||||
@@ -1,280 +0,0 @@
|
|||||||
# Steam Deck (nix-deck) Jovian-NixOS Setup Guide
|
|
||||||
|
|
||||||
This document describes the setup for installing and maintaining NixOS with Jovian-NixOS on a Steam Deck.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
The `nix-deck` configuration provides:
|
|
||||||
- **Jovian-NixOS integration** for Steam Deck hardware support
|
|
||||||
- **Remote building** using `zix790prors` as the build host
|
|
||||||
- **SteamOS role** for easy Steam Deck UI configuration
|
|
||||||
- **Compatibility shim** for using Jovian on NixOS 25.05 stable
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
### Remote Building
|
|
||||||
|
|
||||||
The setup uses distributed builds to avoid slow compilation on the Steam Deck:
|
|
||||||
|
|
||||||
- **Build Host**: `zix790prors` (powerful desktop)
|
|
||||||
- Runs as a dedicated `nix-builder` user (not root)
|
|
||||||
- Accepts SSH connections from client machines
|
|
||||||
- Performs all heavy compilation work
|
|
||||||
|
|
||||||
- **Build Clients**: `nix-book` and `nix-deck`
|
|
||||||
- Automatically offload builds to `zix790prors`
|
|
||||||
- Fall back to local building if remote builder is unavailable
|
|
||||||
- Steam Deck heavily prefers remote (speedFactor=4)
|
|
||||||
|
|
||||||
### Jovian-NixOS Integration
|
|
||||||
|
|
||||||
- **Jovian module**: Provides Steam Deck hardware support, drivers, and Steam UI
|
|
||||||
- **Compatibility layer**: `roles/jovian-compat.nix` provides `services.logind.settings` for NixOS 25.05
|
|
||||||
- **IMPORTANT**: Remove this when upgrading to NixOS 25.11+
|
|
||||||
- An assertion will fail the build if used on 25.11+
|
|
||||||
|
|
||||||
- **SteamOS role**: `roles.desktop.steamos` abstracts Jovian configuration
|
|
||||||
```nix
|
|
||||||
roles.desktop.steamos = {
|
|
||||||
enable = true;
|
|
||||||
autoStart = false; # Set to true to boot directly to Steam UI
|
|
||||||
desktopSession = "plasmawayland";
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## Initial Installation
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
1. Steam Deck in recovery mode or booted to a live Linux environment
|
|
||||||
2. SSH access enabled on the Steam Deck
|
|
||||||
3. SSH key set up for passwordless authentication
|
|
||||||
|
|
||||||
### Option 1: Using nixos-anywhere (Initial Install Only)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# From your main machine
|
|
||||||
nix run github:nix-community/nixos-anywhere -- \
|
|
||||||
--flake .#nix-deck \
|
|
||||||
root@<steam-deck-ip>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note**: This is only for the initial install. For updates, see below.
|
|
||||||
|
|
||||||
### Option 2: Manual Installation
|
|
||||||
|
|
||||||
1. Boot Steam Deck from NixOS installer USB
|
|
||||||
2. Partition and format the disk
|
|
||||||
3. Mount filesystems
|
|
||||||
4. Clone this repository
|
|
||||||
5. Generate hardware config:
|
|
||||||
```bash
|
|
||||||
nixos-generate-config --show-hardware-config > /tmp/hw.nix
|
|
||||||
```
|
|
||||||
6. Copy the hardware config content to `machines/nix-deck/hardware-configuration.nix`
|
|
||||||
7. Keep the `jovian.devices.steamdeck` settings in the file
|
|
||||||
8. Install:
|
|
||||||
```bash
|
|
||||||
nixos-install --flake .#nix-deck
|
|
||||||
```
|
|
||||||
|
|
||||||
## Updates and Rebuilds
|
|
||||||
|
|
||||||
### Method 1: Remote Build and Deploy (Recommended)
|
|
||||||
|
|
||||||
Build on your main machine, deploy to Steam Deck:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# From nix-book or zix790prors
|
|
||||||
nixos-rebuild switch \
|
|
||||||
--flake .#nix-deck \
|
|
||||||
--target-host root@nix-deck \
|
|
||||||
--build-host localhost
|
|
||||||
```
|
|
||||||
|
|
||||||
### Method 2: On-Device Rebuild (Uses Remote Builder)
|
|
||||||
|
|
||||||
The Steam Deck is configured to automatically use `zix790prors` as a remote builder:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# SSH into the Steam Deck
|
|
||||||
ssh root@nix-deck
|
|
||||||
|
|
||||||
# This will automatically build on zix790prors
|
|
||||||
nixos-rebuild switch --flake /path/to/nixos-configs#nix-deck
|
|
||||||
```
|
|
||||||
|
|
||||||
The build will automatically happen on `zix790prors` and be deployed locally.
|
|
||||||
|
|
||||||
## Remote Builder Setup
|
|
||||||
|
|
||||||
### On the Build Host (zix790prors)
|
|
||||||
|
|
||||||
The configuration creates a `nix-builder` user that client machines connect to:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
roles.remote-build.enableBuilder = true;
|
|
||||||
```
|
|
||||||
|
|
||||||
### On Client Machines (nix-book, nix-deck)
|
|
||||||
|
|
||||||
Configure the remote builder:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
roles.remote-build.builders = [{
|
|
||||||
hostName = "zix790prors";
|
|
||||||
maxJobs = 16;
|
|
||||||
speedFactor = 4; # Higher = prefer remote more
|
|
||||||
}];
|
|
||||||
```
|
|
||||||
|
|
||||||
### SSH Key Setup
|
|
||||||
|
|
||||||
1. Generate SSH key on the builder host for the `nix-builder` user:
|
|
||||||
```bash
|
|
||||||
sudo -u nix-builder ssh-keygen -t ed25519 -f /var/lib/nix-builder/.ssh/id_ed25519
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Copy the public key to client machines:
|
|
||||||
```bash
|
|
||||||
# Add to /var/lib/nix-builder/.ssh/authorized_keys on zix790prors
|
|
||||||
```
|
|
||||||
|
|
||||||
3. On client machines, ensure you can connect:
|
|
||||||
```bash
|
|
||||||
ssh nix-builder@zix790prors
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration Files
|
|
||||||
|
|
||||||
### Key Files Created/Modified
|
|
||||||
|
|
||||||
- `flake.nix` - Added Jovian input and nix-deck configuration
|
|
||||||
- `roles/jovian-compat.nix` - Compatibility shim (remove in 25.11+)
|
|
||||||
- `roles/desktop/steamos.nix` - SteamOS/Jovian role abstraction
|
|
||||||
- `roles/remote-build/default.nix` - Remote builder role
|
|
||||||
- `machines/nix-deck/configuration.nix` - Steam Deck system config
|
|
||||||
- `machines/nix-deck/hardware-configuration.nix` - Hardware config (placeholder)
|
|
||||||
|
|
||||||
### Example Configuration
|
|
||||||
|
|
||||||
```nix
|
|
||||||
# machines/nix-deck/configuration.nix
|
|
||||||
{
|
|
||||||
roles = {
|
|
||||||
desktop = {
|
|
||||||
enable = true;
|
|
||||||
wayland = true;
|
|
||||||
gaming.enable = true;
|
|
||||||
kde = true;
|
|
||||||
sddm = true;
|
|
||||||
steamos = {
|
|
||||||
enable = true;
|
|
||||||
autoStart = false; # or true to boot to Steam UI
|
|
||||||
desktopSession = "plasmawayland";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
remote-build.builders = [{
|
|
||||||
hostName = "zix790prors";
|
|
||||||
maxJobs = 16;
|
|
||||||
speedFactor = 4;
|
|
||||||
}];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Jovian Features
|
|
||||||
|
|
||||||
### Enabled by Default
|
|
||||||
|
|
||||||
- Steam Deck hardware support (`jovian.devices.steamdeck.enable`)
|
|
||||||
- Steam UI (`jovian.steam.enable`)
|
|
||||||
- Decky Loader plugin system (`jovian.decky-loader.enable`)
|
|
||||||
|
|
||||||
### Optional Features
|
|
||||||
|
|
||||||
Set in the hardware-configuration.nix:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
jovian.devices.steamdeck = {
|
|
||||||
enable = true;
|
|
||||||
autoUpdate = false; # Auto-update BIOS/controller firmware
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Manual Firmware Updates
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# BIOS update
|
|
||||||
sudo jupiter-biosupdate
|
|
||||||
|
|
||||||
# Controller update
|
|
||||||
sudo jupiter-controller-update
|
|
||||||
|
|
||||||
# Docking station (connect via USB-C first)
|
|
||||||
jupiter-dock-updater
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### Remote Builds Not Working
|
|
||||||
|
|
||||||
1. Check SSH connectivity:
|
|
||||||
```bash
|
|
||||||
ssh nix-builder@zix790prors
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Verify builder is trusted:
|
|
||||||
```bash
|
|
||||||
# On zix790prors
|
|
||||||
nix show-config | grep trusted-users
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Check build logs:
|
|
||||||
```bash
|
|
||||||
journalctl -u nix-daemon -f
|
|
||||||
```
|
|
||||||
|
|
||||||
### Jovian Not Working
|
|
||||||
|
|
||||||
1. Ensure you're on NixOS 25.05 or the compatibility layer is removed for 25.11+
|
|
||||||
2. Check Jovian is imported in flake.nix
|
|
||||||
3. Verify hardware config has `jovian.devices.steamdeck.enable = true`
|
|
||||||
|
|
||||||
### Compatibility Layer Issues
|
|
||||||
|
|
||||||
If you see an error about `jovian-compat.nix` being incompatible:
|
|
||||||
|
|
||||||
1. You're running NixOS 25.11 or later
|
|
||||||
2. Remove `./roles/jovian-compat.nix` from `flake.nix`
|
|
||||||
3. Jovian should work natively on 25.11+
|
|
||||||
|
|
||||||
## Future Upgrades
|
|
||||||
|
|
||||||
### Upgrading to NixOS 25.11
|
|
||||||
|
|
||||||
1. Update `nixpkgs` input in flake.nix to 25.11
|
|
||||||
2. Remove `./roles/jovian-compat.nix` from flake.nix imports
|
|
||||||
3. The assertion in jovian-compat.nix will prevent accidental use
|
|
||||||
4. Test the build
|
|
||||||
5. Deploy
|
|
||||||
|
|
||||||
### Switching to Unstable
|
|
||||||
|
|
||||||
If you need Jovian to follow unstable nixpkgs:
|
|
||||||
|
|
||||||
1. Edit `flake.nix`:
|
|
||||||
```nix
|
|
||||||
jovian = {
|
|
||||||
url = "github:Jovian-Experiments/Jovian-NixOS";
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs-unstable";
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
2. This only affects Jovian packages, not your base system
|
|
||||||
|
|
||||||
## Additional Resources
|
|
||||||
|
|
||||||
- [Jovian-NixOS Documentation](https://jovian-experiments.github.io/Jovian-NixOS/)
|
|
||||||
- [Jovian Steam Deck Guide](https://jovian-experiments.github.io/Jovian-NixOS/devices/valve-steam-deck/)
|
|
||||||
- [NixOS Remote Builds](https://nixos.org/manual/nix/stable/advanced-topics/distributed-builds.html)
|
|
||||||
203
flake.lock
generated
203
flake.lock
generated
@@ -1,13 +1,73 @@
|
|||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
|
"beads": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs-unstable"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1767911810,
|
||||||
|
"narHash": "sha256-0L4ATr01UsmBC0rSW62VIMVVSUihAQu2+ZOoHk9BQnA=",
|
||||||
|
"owner": "steveyegge",
|
||||||
|
"repo": "beads",
|
||||||
|
"rev": "28ff9fe9919a9665a0f00f5b3fcd084b43fb6cc3",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "steveyegge",
|
||||||
|
"repo": "beads",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"doomemacs": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1767773143,
|
||||||
|
"narHash": "sha256-QL/t9v2kFNxBDyNJb/s411o3mxujan+QX5IZglTdpTk=",
|
||||||
|
"owner": "doomemacs",
|
||||||
|
"repo": "doomemacs",
|
||||||
|
"rev": "3e15fb36d7f94f0a218bda977be4d3f5da983a71",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "doomemacs",
|
||||||
|
"repo": "doomemacs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"emacs-overlay": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nix-doom-emacs-unstraightened"
|
||||||
|
],
|
||||||
|
"nixpkgs-stable": [
|
||||||
|
"nix-doom-emacs-unstraightened"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1768011937,
|
||||||
|
"narHash": "sha256-SnU2XTo34vwVaijs+4VwcXTNwMWO4nwzzs08N39UagA=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "emacs-overlay",
|
||||||
|
"rev": "79abf71d9897cf3b5189f7175cda1b1102abc65c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "emacs-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761588595,
|
"lastModified": 1765121682,
|
||||||
"narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=",
|
"narHash": "sha256-4VBOP18BFeiPkyhy9o4ssBNQEvfvv1kXkasAYd0+rrA=",
|
||||||
"owner": "edolstra",
|
"owner": "edolstra",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-compat",
|
||||||
"rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5",
|
"rev": "65f23138d8d09a92e30f1e5c87611b23ef451bf3",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -16,6 +76,24 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"google-cookie-retrieval": {
|
"google-cookie-retrieval": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -43,16 +121,16 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1758463745,
|
"lastModified": 1767514898,
|
||||||
"narHash": "sha256-uhzsV0Q0I9j2y/rfweWeGif5AWe0MGrgZ/3TjpDYdGA=",
|
"narHash": "sha256-ONYqnKrPzfKEEPChoJ9qPcfvBqW9ZgieDKD7UezWPg4=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "3b955f5f0a942f9f60cdc9cacb7844335d0f21c3",
|
"rev": "7a06e8a2f844e128d3b210a000a62716b6040b7f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"ref": "release-25.05",
|
"ref": "release-25.11",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
@@ -64,11 +142,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1763416652,
|
"lastModified": 1767556355,
|
||||||
"narHash": "sha256-8EBEEvtzQ11LCxpQHMNEBQAGtQiCu/pqP9zSovDSbNM=",
|
"narHash": "sha256-RDTUBDQBi9D4eD9iJQWtUDN/13MDLX+KmE+TwwNUp2s=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "ea164b7c9ccdc2321379c2ff78fd4317b4c41312",
|
"rev": "f894bc4ffde179d178d8deb374fcf9855d1a82b7",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -86,11 +164,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1763223001,
|
"lastModified": 1767082077,
|
||||||
"narHash": "sha256-Hi6XxTJJjKsDrO+D0fYXS88ehCYzQkZlp9qxX1zoM1s=",
|
"narHash": "sha256-2tL1mRb9uFJThUNfuDm/ehrnPvImL/QDtCxfn71IEz4=",
|
||||||
"owner": "Jovian-Experiments",
|
"owner": "Jovian-Experiments",
|
||||||
"repo": "Jovian-NixOS",
|
"repo": "Jovian-NixOS",
|
||||||
"rev": "68a1bcc019378272e601558719f82005a80ddab0",
|
"rev": "efd4b22e6fdc6d7fb4e186ae333a4b74e03da440",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -106,20 +184,41 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1762912391,
|
"lastModified": 1765066094,
|
||||||
"narHash": "sha256-4hpBE7bGd24SfD28rzMdUGXsLsNEYxCCrTipFdoqoNM=",
|
"narHash": "sha256-0YSU35gfRFJzx/lTGgOt6ubP8K6LeW0vaywzNNqxkl4=",
|
||||||
"owner": "nix-darwin",
|
"owner": "nix-darwin",
|
||||||
"repo": "nix-darwin",
|
"repo": "nix-darwin",
|
||||||
"rev": "d76299b2cd01837c4c271a7b5186e3d5d8ebd126",
|
"rev": "688427b1aab9afb478ca07989dc754fa543e03d5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nix-darwin",
|
"owner": "nix-darwin",
|
||||||
"ref": "nix-darwin-25.05",
|
"ref": "nix-darwin-25.11",
|
||||||
"repo": "nix-darwin",
|
"repo": "nix-darwin",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nix-doom-emacs-unstraightened": {
|
||||||
|
"inputs": {
|
||||||
|
"doomemacs": "doomemacs",
|
||||||
|
"emacs-overlay": "emacs-overlay",
|
||||||
|
"nixpkgs": [],
|
||||||
|
"systems": "systems_2"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1768034604,
|
||||||
|
"narHash": "sha256-62pIZMvGHhYJmMiiBsxHqZt/dFyENPcFHlJq5NJF3Sw=",
|
||||||
|
"owner": "marienz",
|
||||||
|
"repo": "nix-doom-emacs-unstraightened",
|
||||||
|
"rev": "9b3b8044fe4ccdcbb2d6f733d7dbe4d5feea18bc",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "marienz",
|
||||||
|
"repo": "nix-doom-emacs-unstraightened",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nix-github-actions": {
|
"nix-github-actions": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -148,11 +247,11 @@
|
|||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1763385941,
|
"lastModified": 1765841014,
|
||||||
"narHash": "sha256-99CBNgyMvg3Zu/hxqixtShevrF4Kfr/qjtizQ6oseVI=",
|
"narHash": "sha256-55V0AJ36V5Egh4kMhWtDh117eE3GOjwq5LhwxDn9eHg=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "NixOS-WSL",
|
"repo": "NixOS-WSL",
|
||||||
"rev": "cc6483354b236c2fc95cc1d4ba1f0f40b7345e69",
|
"rev": "be4af8042e7a61fa12fda58fe9a3b3babdefe17b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -164,11 +263,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1762977756,
|
"lastModified": 1765472234,
|
||||||
"narHash": "sha256-4PqRErxfe+2toFJFgcRKZ0UI9NSIOJa+7RXVtBhy4KE=",
|
"narHash": "sha256-9VvC20PJPsleGMewwcWYKGzDIyjckEz8uWmT0vCDYK0=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "c5ae371f1a6a7fd27823bc500d9390b38c05fa55",
|
"rev": "2fbfb1d73d239d2402a8fe03963e37aab15abe8b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -180,11 +279,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-unstable": {
|
"nixpkgs-unstable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1763283776,
|
"lastModified": 1767379071,
|
||||||
"narHash": "sha256-Y7TDFPK4GlqrKrivOcsHG8xSGqQx3A6c+i7novT85Uk=",
|
"narHash": "sha256-EgE0pxsrW9jp9YFMkHL9JMXxcqi/OoumPJYwf+Okucw=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "50a96edd8d0db6cc8db57dab6bb6d6ee1f3dc49a",
|
"rev": "fb7944c166a3b630f177938e478f0378e64ce108",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -196,16 +295,16 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1763049705,
|
"lastModified": 1767480499,
|
||||||
"narHash": "sha256-A5LS0AJZ1yDPTa2fHxufZN++n8MCmtgrJDtxFxrH4S8=",
|
"narHash": "sha256-8IQQUorUGiSmFaPnLSo2+T+rjHtiNWc+OAzeHck7N48=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "3acb677ea67d4c6218f33de0db0955f116b7588c",
|
"rev": "30a3c519afcf3f99e2c6df3b359aec5692054d92",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"ref": "nixos-25.05",
|
"ref": "nixos-25.11",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
@@ -220,11 +319,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1762784320,
|
"lastModified": 1763909441,
|
||||||
"narHash": "sha256-odsk96Erywk5hs0dhArF38zb7Oe0q6LZ70gXbxAPKno=",
|
"narHash": "sha256-56LwV51TX/FhgX+5LCG6akQ5KrOWuKgcJa+eUsRMxsc=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "plasma-manager",
|
"repo": "plasma-manager",
|
||||||
"rev": "7911a0f8a44c7e8b29d031be3149ee8943144321",
|
"rev": "b24ed4b272256dfc1cc2291f89a9821d5f9e14b4",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -243,11 +342,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1762784320,
|
"lastModified": 1763909441,
|
||||||
"narHash": "sha256-odsk96Erywk5hs0dhArF38zb7Oe0q6LZ70gXbxAPKno=",
|
"narHash": "sha256-56LwV51TX/FhgX+5LCG6akQ5KrOWuKgcJa+eUsRMxsc=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "plasma-manager",
|
"repo": "plasma-manager",
|
||||||
"rev": "7911a0f8a44c7e8b29d031be3149ee8943144321",
|
"rev": "b24ed4b272256dfc1cc2291f89a9821d5f9e14b4",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -258,17 +357,49 @@
|
|||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"beads": "beads",
|
||||||
"google-cookie-retrieval": "google-cookie-retrieval",
|
"google-cookie-retrieval": "google-cookie-retrieval",
|
||||||
"home-manager": "home-manager",
|
"home-manager": "home-manager",
|
||||||
"home-manager-unstable": "home-manager-unstable",
|
"home-manager-unstable": "home-manager-unstable",
|
||||||
"jovian": "jovian",
|
"jovian": "jovian",
|
||||||
"nix-darwin": "nix-darwin",
|
"nix-darwin": "nix-darwin",
|
||||||
|
"nix-doom-emacs-unstraightened": "nix-doom-emacs-unstraightened",
|
||||||
"nixos-wsl": "nixos-wsl",
|
"nixos-wsl": "nixos-wsl",
|
||||||
"nixpkgs": "nixpkgs_2",
|
"nixpkgs": "nixpkgs_2",
|
||||||
"nixpkgs-unstable": "nixpkgs-unstable",
|
"nixpkgs-unstable": "nixpkgs-unstable",
|
||||||
"plasma-manager": "plasma-manager",
|
"plasma-manager": "plasma-manager",
|
||||||
"plasma-manager-unstable": "plasma-manager-unstable"
|
"plasma-manager-unstable": "plasma-manager-unstable"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
|||||||
98
flake.nix
98
flake.nix
@@ -2,17 +2,17 @@
|
|||||||
description = "A very basic flake";
|
description = "A very basic flake";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
|
||||||
nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
|
nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
nixos-wsl.url = "github:nix-community/NixOS-WSL/main";
|
nixos-wsl.url = "github:nix-community/NixOS-WSL/main";
|
||||||
|
|
||||||
nix-darwin = {
|
nix-darwin = {
|
||||||
url = "github:nix-darwin/nix-darwin/nix-darwin-25.05";
|
url = "github:nix-darwin/nix-darwin/nix-darwin-25.11";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
home-manager = {
|
home-manager = {
|
||||||
url = "github:nix-community/home-manager/release-25.05";
|
url = "github:nix-community/home-manager/release-25.11";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -42,19 +42,29 @@
|
|||||||
url = "github:Jovian-Experiments/Jovian-NixOS";
|
url = "github:Jovian-Experiments/Jovian-NixOS";
|
||||||
inputs.nixpkgs.follows = "nixpkgs-unstable";
|
inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
beads = {
|
||||||
|
url = "github:steveyegge/beads";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
nix-doom-emacs-unstraightened = {
|
||||||
|
url = "github:marienz/nix-doom-emacs-unstraightened";
|
||||||
|
# Don't follow nixpkgs to avoid rebuild issues with emacs-overlay
|
||||||
|
inputs.nixpkgs.follows = "";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, nixpkgs-unstable, nixos-wsl, ... } @ inputs: let
|
outputs = { self, nixpkgs, nixpkgs-unstable, nixos-wsl, ... } @ inputs: let
|
||||||
nixosModules = [
|
nixosModules = [
|
||||||
./roles
|
./roles
|
||||||
] ++ [
|
] ++ [
|
||||||
./roles/jovian-compat.nix
|
|
||||||
inputs.home-manager.nixosModules.home-manager
|
inputs.home-manager.nixosModules.home-manager
|
||||||
{
|
{
|
||||||
nixpkgs.overlays = [
|
nixpkgs.overlays = [
|
||||||
(final: prev: {
|
(final: prev: {
|
||||||
unstable = import nixpkgs-unstable {
|
unstable = import nixpkgs-unstable {
|
||||||
system = prev.system;
|
system = prev.stdenv.hostPlatform.system;
|
||||||
config.allowUnfree = true;
|
config.allowUnfree = true;
|
||||||
};
|
};
|
||||||
custom = prev.callPackage ./packages {};
|
custom = prev.callPackage ./packages {};
|
||||||
@@ -66,6 +76,7 @@
|
|||||||
home-manager.useUserPackages = true;
|
home-manager.useUserPackages = true;
|
||||||
home-manager.sharedModules = [
|
home-manager.sharedModules = [
|
||||||
inputs.plasma-manager.homeModules.plasma-manager
|
inputs.plasma-manager.homeModules.plasma-manager
|
||||||
|
inputs.nix-doom-emacs-unstraightened.homeModule
|
||||||
];
|
];
|
||||||
home-manager.extraSpecialArgs = {
|
home-manager.extraSpecialArgs = {
|
||||||
globalInputs = inputs;
|
globalInputs = inputs;
|
||||||
@@ -82,7 +93,7 @@
|
|||||||
nixpkgs.overlays = [
|
nixpkgs.overlays = [
|
||||||
(final: prev: {
|
(final: prev: {
|
||||||
unstable = import nixpkgs-unstable {
|
unstable = import nixpkgs-unstable {
|
||||||
system = prev.system;
|
system = prev.stdenv.hostPlatform.system;
|
||||||
config.allowUnfree = true;
|
config.allowUnfree = true;
|
||||||
};
|
};
|
||||||
custom = prev.callPackage ./packages {};
|
custom = prev.callPackage ./packages {};
|
||||||
@@ -94,6 +105,7 @@
|
|||||||
home-manager.useUserPackages = true;
|
home-manager.useUserPackages = true;
|
||||||
home-manager.sharedModules = [
|
home-manager.sharedModules = [
|
||||||
inputs.plasma-manager-unstable.homeModules.plasma-manager
|
inputs.plasma-manager-unstable.homeModules.plasma-manager
|
||||||
|
inputs.nix-doom-emacs-unstraightened.homeModule
|
||||||
];
|
];
|
||||||
home-manager.extraSpecialArgs = {
|
home-manager.extraSpecialArgs = {
|
||||||
globalInputs = inputs;
|
globalInputs = inputs;
|
||||||
@@ -108,8 +120,15 @@
|
|||||||
nixpkgs.overlays = [
|
nixpkgs.overlays = [
|
||||||
(final: prev: {
|
(final: prev: {
|
||||||
unstable = import nixpkgs-unstable {
|
unstable = import nixpkgs-unstable {
|
||||||
system = prev.system;
|
system = prev.stdenv.hostPlatform.system;
|
||||||
config.allowUnfree = true;
|
config.allowUnfree = true;
|
||||||
|
overlays = [
|
||||||
|
# Override claude-code in unstable to use our custom GCS-based build
|
||||||
|
# (needed for corporate networks that block npm registry)
|
||||||
|
(ufinal: uprev: {
|
||||||
|
claude-code = prev.custom.claude-code or (prev.callPackage ./packages {}).claude-code;
|
||||||
|
})
|
||||||
|
];
|
||||||
};
|
};
|
||||||
custom = prev.callPackage ./packages {};
|
custom = prev.callPackage ./packages {};
|
||||||
# Compatibility: bitwarden renamed to bitwarden-desktop in unstable
|
# Compatibility: bitwarden renamed to bitwarden-desktop in unstable
|
||||||
@@ -118,6 +137,9 @@
|
|||||||
];
|
];
|
||||||
home-manager.useGlobalPkgs = true;
|
home-manager.useGlobalPkgs = true;
|
||||||
home-manager.useUserPackages = true;
|
home-manager.useUserPackages = true;
|
||||||
|
home-manager.sharedModules = [
|
||||||
|
inputs.nix-doom-emacs-unstraightened.homeModule
|
||||||
|
];
|
||||||
home-manager.extraSpecialArgs = {
|
home-manager.extraSpecialArgs = {
|
||||||
globalInputs = inputs;
|
globalInputs = inputs;
|
||||||
};
|
};
|
||||||
@@ -133,7 +155,7 @@
|
|||||||
home-manager.users.johno = {
|
home-manager.users.johno = {
|
||||||
imports = [ ./home/home-laptop-compact.nix ];
|
imports = [ ./home/home-laptop-compact.nix ];
|
||||||
# Machine-specific overrides
|
# Machine-specific overrides
|
||||||
home.i3_sway.extraSwayConfig = {
|
home.roles.i3_sway.extraSwayConfig = {
|
||||||
output.eDP-1.scale = "1.75";
|
output.eDP-1.scale = "1.75";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -146,9 +168,9 @@
|
|||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
modules = nixosModules ++ [
|
modules = nixosModules ++ [
|
||||||
./machines/boxy/configuration.nix
|
./machines/boxy/configuration.nix
|
||||||
inputs.home-manager.nixosModules.home-manager
|
|
||||||
{
|
{
|
||||||
home-manager.users.johno = import ./home/home-media-center.nix;
|
home-manager.users.johno = import ./home/home-media-center.nix;
|
||||||
|
home-manager.users.kodi = import ./home/home-kodi.nix;
|
||||||
home-manager.extraSpecialArgs = { inherit system; };
|
home-manager.extraSpecialArgs = { inherit system; };
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@@ -203,6 +225,19 @@
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# ZFS/NFS server configuration
|
||||||
|
nixosConfigurations.john-endesktop = nixpkgs.lib.nixosSystem rec {
|
||||||
|
system = "x86_64-linux";
|
||||||
|
modules = nixosModules ++ [
|
||||||
|
./machines/john-endesktop/configuration.nix
|
||||||
|
inputs.home-manager.nixosModules.home-manager
|
||||||
|
{
|
||||||
|
home-manager.users.johno = import ./home/home-server.nix;
|
||||||
|
home-manager.extraSpecialArgs = { inherit system; };
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
# Darwin/macOS configurations
|
# Darwin/macOS configurations
|
||||||
darwinConfigurations."blkfv4yf49kt7" = inputs.nix-darwin.lib.darwinSystem rec {
|
darwinConfigurations."blkfv4yf49kt7" = inputs.nix-darwin.lib.darwinSystem rec {
|
||||||
system = "aarch64-darwin";
|
system = "aarch64-darwin";
|
||||||
@@ -214,5 +249,50 @@
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Flake apps
|
||||||
|
apps = nixpkgs.lib.genAttrs [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" ] (system:
|
||||||
|
let
|
||||||
|
pkgs = import nixpkgs { inherit system; };
|
||||||
|
commonDeps = [ pkgs.curl pkgs.jq pkgs.nix pkgs.git pkgs.gnused pkgs.gnugrep pkgs.coreutils pkgs.gawk ];
|
||||||
|
|
||||||
|
update-doomemacs = pkgs.writeShellScriptBin "update-doomemacs" ''
|
||||||
|
export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH"
|
||||||
|
${builtins.readFile ./scripts/update-doomemacs.sh}
|
||||||
|
'';
|
||||||
|
|
||||||
|
update-claude-code = pkgs.writeShellScriptBin "update-claude-code" ''
|
||||||
|
export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH"
|
||||||
|
${builtins.readFile ./packages/claude-code/update.sh}
|
||||||
|
'';
|
||||||
|
|
||||||
|
rotate-wallpaper = pkgs.writeShellScriptBin "rotate-wallpaper" ''
|
||||||
|
export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH"
|
||||||
|
${builtins.readFile ./scripts/rotate-wallpaper.sh}
|
||||||
|
'';
|
||||||
|
|
||||||
|
upgrade = pkgs.writeShellScriptBin "upgrade" ''
|
||||||
|
export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH"
|
||||||
|
${builtins.readFile ./scripts/upgrade.sh}
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
update-doomemacs = {
|
||||||
|
type = "app";
|
||||||
|
program = "${update-doomemacs}/bin/update-doomemacs";
|
||||||
|
};
|
||||||
|
update-claude-code = {
|
||||||
|
type = "app";
|
||||||
|
program = "${update-claude-code}/bin/update-claude-code";
|
||||||
|
};
|
||||||
|
rotate-wallpaper = {
|
||||||
|
type = "app";
|
||||||
|
program = "${rotate-wallpaper}/bin/rotate-wallpaper";
|
||||||
|
};
|
||||||
|
upgrade = {
|
||||||
|
type = "app";
|
||||||
|
program = "${upgrade}/bin/upgrade";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
{ config, lib, pkgs, globalInputs, system, ... }:
|
{ config, lib, pkgs, globalInputs, system, ... }:
|
||||||
|
|
||||||
let
|
|
||||||
leader = "cmd"; # Change this to experiment with different leader keys (e.g., "cmd", "ctrl")
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
# Home Manager configuration for Darwin work laptop
|
# Home Manager configuration for Darwin work laptop
|
||||||
# Corporate-friendly setup with essential development tools
|
# Corporate-friendly setup with essential development tools
|
||||||
@@ -13,39 +10,11 @@ in
|
|||||||
|
|
||||||
# System packages
|
# System packages
|
||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
autoraise
|
google-cloud-sdk
|
||||||
];
|
];
|
||||||
|
|
||||||
# Note: ghostty installed via Homebrew (managed outside of nix)
|
# Note: ghostty installed via Homebrew (managed outside of nix)
|
||||||
|
|
||||||
# Auto-start autoraise on login
|
|
||||||
launchd.agents.autoraise = {
|
|
||||||
enable = true;
|
|
||||||
config = {
|
|
||||||
ProgramArguments = [
|
|
||||||
"${pkgs.autoraise}/bin/AutoRaise"
|
|
||||||
"-pollMillis" "50"
|
|
||||||
"-delay" "2"
|
|
||||||
"-focusDelay" "2"
|
|
||||||
];
|
|
||||||
RunAtLoad = true;
|
|
||||||
KeepAlive = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# Auto-start aerospace on login
|
|
||||||
# NOTE: In 25.11+, this can be simplified to `programs.aerospace.launchd.enable = true`
|
|
||||||
launchd.agents.aerospace = {
|
|
||||||
enable = true;
|
|
||||||
config = {
|
|
||||||
Program = "${pkgs.aerospace}/Applications/AeroSpace.app/Contents/MacOS/AeroSpace";
|
|
||||||
RunAtLoad = true;
|
|
||||||
KeepAlive = true;
|
|
||||||
StandardOutPath = "/tmp/aerospace.log";
|
|
||||||
StandardErrorPath = "/tmp/aerospace.err.log";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# Override Darwin-incompatible settings from base role
|
# Override Darwin-incompatible settings from base role
|
||||||
programs.rbw.settings.pinentry = lib.mkForce pkgs.pinentry_mac;
|
programs.rbw.settings.pinentry = lib.mkForce pkgs.pinentry_mac;
|
||||||
|
|
||||||
@@ -127,107 +96,28 @@ in
|
|||||||
|
|
||||||
home.shell.enableShellIntegration = true;
|
home.shell.enableShellIntegration = true;
|
||||||
|
|
||||||
# TODO: Move this to its own role and/or module
|
|
||||||
programs.aerospace = {
|
|
||||||
enable = true;
|
|
||||||
userSettings.mode.main.binding = {
|
|
||||||
"${leader}-slash" = "layout tiles horizontal vertical";
|
|
||||||
"${leader}-comma" = "layout accordion horizontal vertical";
|
|
||||||
"${leader}-shift-q" = "close";
|
|
||||||
"${leader}-shift-f" = "fullscreen";
|
|
||||||
"${leader}-h" = "focus left";
|
|
||||||
"${leader}-j" = "focus down";
|
|
||||||
"${leader}-k" = "focus up";
|
|
||||||
"${leader}-l" = "focus right";
|
|
||||||
"${leader}-shift-h" = "move left";
|
|
||||||
"${leader}-shift-j" = "move down";
|
|
||||||
"${leader}-shift-k" = "move up";
|
|
||||||
"${leader}-shift-l" = "move right";
|
|
||||||
"${leader}-minus" = "resize smart -50";
|
|
||||||
"${leader}-equal" = "resize smart +50";
|
|
||||||
"${leader}-1" = "workspace 1";
|
|
||||||
"${leader}-2" = "workspace 2";
|
|
||||||
"${leader}-3" = "workspace 3";
|
|
||||||
"${leader}-4" = "workspace 4";
|
|
||||||
"${leader}-5" = "workspace 5";
|
|
||||||
"${leader}-6" = "workspace 6";
|
|
||||||
"${leader}-7" = "workspace 7";
|
|
||||||
"${leader}-8" = "workspace 8";
|
|
||||||
"${leader}-9" = "workspace 9";
|
|
||||||
"${leader}-0" = "workspace 10";
|
|
||||||
"${leader}-shift-1" = "move-node-to-workspace 1";
|
|
||||||
"${leader}-shift-2" = "move-node-to-workspace 2";
|
|
||||||
"${leader}-shift-3" = "move-node-to-workspace 3";
|
|
||||||
"${leader}-shift-4" = "move-node-to-workspace 4";
|
|
||||||
"${leader}-shift-5" = "move-node-to-workspace 5";
|
|
||||||
"${leader}-shift-6" = "move-node-to-workspace 6";
|
|
||||||
"${leader}-shift-7" = "move-node-to-workspace 7";
|
|
||||||
"${leader}-shift-8" = "move-node-to-workspace 8";
|
|
||||||
"${leader}-shift-9" = "move-node-to-workspace 9";
|
|
||||||
"${leader}-shift-0" = "move-node-to-workspace 10";
|
|
||||||
"${leader}-tab" = "workspace-back-and-forth";
|
|
||||||
"${leader}-shift-tab" = "move-workspace-to-monitor --wrap-around next";
|
|
||||||
|
|
||||||
"${leader}-enter" = ''
|
|
||||||
exec-and-forget osascript <<'APPLESCRIPT'
|
|
||||||
tell application "Ghostty"
|
|
||||||
activate
|
|
||||||
tell application "System Events"
|
|
||||||
keystroke "n" using {command down}
|
|
||||||
end tell
|
|
||||||
end tell
|
|
||||||
APPLESCRIPT
|
|
||||||
'';
|
|
||||||
|
|
||||||
"${leader}-shift-enter" = ''
|
|
||||||
exec-and-forget osascript <<'APPLESCRIPT'
|
|
||||||
tell application "Google Chrome"
|
|
||||||
set newWindow to make new window
|
|
||||||
activate
|
|
||||||
tell newWindow to set index to 1
|
|
||||||
end tell
|
|
||||||
APPLESCRIPT
|
|
||||||
'';
|
|
||||||
|
|
||||||
"${leader}-shift-e" = "exec-and-forget zsh --login -c \"emacsclient -c -n\"";
|
|
||||||
|
|
||||||
# Service mode: Deliberate aerospace window management
|
|
||||||
"${leader}-i" = "mode service";
|
|
||||||
|
|
||||||
# Passthrough mode: Temporarily disable aerospace to use macOS shortcuts
|
|
||||||
# Press Cmd-P, then use any macOS shortcut (like Cmd-K in Slack), then press Cmd-P again to exit
|
|
||||||
"${leader}-p" = "mode passthrough";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Service mode: For deliberate aerospace window management operations
|
|
||||||
userSettings.mode.service.binding = {
|
|
||||||
esc = ["reload-config" "mode main"];
|
|
||||||
r = ["flatten-workspace-tree" "mode main"]; # reset layout
|
|
||||||
f = ["layout floating tiling" "mode main"]; # Toggle between floating and tiling layout
|
|
||||||
backspace = ["close-all-windows-but-current" "mode main"];
|
|
||||||
|
|
||||||
"${leader}-shift-h" = ["join-with left" "mode main"];
|
|
||||||
"${leader}-shift-j" = ["join-with down" "mode main"];
|
|
||||||
"${leader}-shift-k" = ["join-with up" "mode main"];
|
|
||||||
"${leader}-shift-l" = ["join-with right" "mode main"];
|
|
||||||
};
|
|
||||||
|
|
||||||
# Passthrough mode: All shortcuts pass through to macOS
|
|
||||||
# This mode has minimal bindings - just ways to exit back to main mode
|
|
||||||
userSettings.mode.passthrough.binding = {
|
|
||||||
esc = "mode main";
|
|
||||||
"${leader}-p" = "mode main"; # Toggle back with same key (Cmd-P)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
home.roles = {
|
home.roles = {
|
||||||
base.enable = true;
|
base.enable = true;
|
||||||
|
development = {
|
||||||
|
enable = true;
|
||||||
|
allowArbitraryClaudeCodeModelSelection = true;
|
||||||
|
};
|
||||||
|
tmux.enable = true;
|
||||||
|
emacs.enable = true;
|
||||||
|
aerospace = {
|
||||||
|
enable = true;
|
||||||
|
leader = "cmd";
|
||||||
|
ctrlShortcuts.enable = true;
|
||||||
|
sketchybar.enable = true;
|
||||||
|
# Optional: Add per-machine userSettings overrides
|
||||||
|
# userSettings = {
|
||||||
|
# mode.main.binding."${leader}-custom" = "custom-command";
|
||||||
|
# };
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
./roles
|
./roles
|
||||||
./modules/emacs
|
./roles/base-darwin
|
||||||
./modules/kubectl
|
|
||||||
./modules/tmux
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,22 @@
|
|||||||
|
|
||||||
# Enable all desktop roles for full-featured experience
|
# Enable all desktop roles for full-featured experience
|
||||||
home.roles = {
|
home.roles = {
|
||||||
|
"3d-printing".enable = true;
|
||||||
base.enable = true;
|
base.enable = true;
|
||||||
desktop.enable = true;
|
desktop.enable = true;
|
||||||
|
emacs.enable = true;
|
||||||
|
email.enable = true;
|
||||||
|
i3_sway.enable = true;
|
||||||
office.enable = true;
|
office.enable = true;
|
||||||
media.enable = true;
|
media.enable = true;
|
||||||
development.enable = true;
|
development.enable = true;
|
||||||
communication.enable = true;
|
communication.enable = true;
|
||||||
sync.enable = true;
|
sync.enable = true;
|
||||||
kdeconnect.enable = true;
|
kdeconnect.enable = true;
|
||||||
|
kubectl.enable = true;
|
||||||
|
tmux.enable = true;
|
||||||
|
plasma-manager.enable = true;
|
||||||
|
starship.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
targets.genericLinux.enable = true;
|
targets.genericLinux.enable = true;
|
||||||
@@ -24,10 +32,6 @@
|
|||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
./roles
|
./roles
|
||||||
./modules/emacs
|
./roles/base-linux
|
||||||
./modules/i3+sway
|
|
||||||
./modules/kubectl
|
|
||||||
./modules/plasma-manager
|
|
||||||
./modules/tmux
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
28
home/home-kodi.nix
Normal file
28
home/home-kodi.nix
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{ pkgs, globalInputs, system, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# Home Manager configuration for kodi user on boxy
|
||||||
|
# Focused on media center volume control via Home Assistant
|
||||||
|
|
||||||
|
home.username = "kodi";
|
||||||
|
home.homeDirectory = "/home/kodi";
|
||||||
|
home.stateVersion = "24.05";
|
||||||
|
|
||||||
|
# Enable minimal roles for kodi user
|
||||||
|
home.roles = {
|
||||||
|
base.enable = true;
|
||||||
|
plasma-manager-kodi.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
kdePackages.kconfig
|
||||||
|
];
|
||||||
|
|
||||||
|
targets.genericLinux.enable = true;
|
||||||
|
home.sessionVariables = {};
|
||||||
|
home.sessionPath = [];
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
./roles
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -14,10 +14,24 @@
|
|||||||
desktop.enable = true;
|
desktop.enable = true;
|
||||||
development.enable = true;
|
development.enable = true;
|
||||||
communication.enable = true;
|
communication.enable = true;
|
||||||
|
email.enable = true;
|
||||||
kdeconnect.enable = true;
|
kdeconnect.enable = true;
|
||||||
media.enable = true;
|
media.enable = true;
|
||||||
sync.enable = true;
|
sync.enable = true;
|
||||||
# office.enable = false; # Excluded for storage constraints
|
kubectl.enable = true;
|
||||||
|
tmux.enable = true;
|
||||||
|
plasma-manager.enable = true;
|
||||||
|
emacs.enable = true;
|
||||||
|
i3_sway.enable = true;
|
||||||
|
starship.enable = true;
|
||||||
|
|
||||||
|
# Launcher wrappers for excluded/optional packages
|
||||||
|
launchers = {
|
||||||
|
enable = true;
|
||||||
|
packages = [
|
||||||
|
"libreoffice"
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
targets.genericLinux.enable = true;
|
targets.genericLinux.enable = true;
|
||||||
@@ -26,11 +40,6 @@
|
|||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
./roles
|
./roles
|
||||||
./modules/emacs
|
./roles/base-linux
|
||||||
./modules/i3+sway
|
|
||||||
./modules/kubectl
|
|
||||||
./modules/plasma-manager
|
|
||||||
./modules/tmux
|
|
||||||
];
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,16 @@
|
|||||||
home.roles = {
|
home.roles = {
|
||||||
base.enable = true;
|
base.enable = true;
|
||||||
desktop.enable = true;
|
desktop.enable = true;
|
||||||
|
tmux.enable = true;
|
||||||
|
plasma-manager.enable = true;
|
||||||
|
emacs = {
|
||||||
|
enable = true;
|
||||||
|
# Use pre-built Doom Emacs - all packages built at nix build time
|
||||||
|
# This means no doom sync is needed after booting the live USB
|
||||||
|
prebuiltDoom = true;
|
||||||
|
};
|
||||||
|
i3_sway.enable = true;
|
||||||
|
starship.enable = true;
|
||||||
# development.enable = false; # Not needed for live USB
|
# development.enable = false; # Not needed for live USB
|
||||||
# communication.enable = false; # Not needed for live USB
|
# communication.enable = false; # Not needed for live USB
|
||||||
# office.enable = false; # Not needed for live USB
|
# office.enable = false; # Not needed for live USB
|
||||||
@@ -26,11 +36,7 @@
|
|||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
./roles
|
./roles
|
||||||
./modules/emacs
|
./roles/base-linux
|
||||||
./modules/i3+sway
|
|
||||||
./modules/kubectl
|
|
||||||
./modules/plasma-manager
|
|
||||||
./modules/tmux
|
|
||||||
];
|
];
|
||||||
|
|
||||||
# Live USB specific overrides can go here if needed
|
# Live USB specific overrides can go here if needed
|
||||||
|
|||||||
@@ -16,6 +16,11 @@
|
|||||||
communication.enable = true;
|
communication.enable = true;
|
||||||
kdeconnect.enable = true;
|
kdeconnect.enable = true;
|
||||||
development.enable = true;
|
development.enable = true;
|
||||||
|
tmux.enable = true;
|
||||||
|
plasma-manager.enable = true;
|
||||||
|
emacs.enable = true;
|
||||||
|
i3_sway.enable = true;
|
||||||
|
starship.enable = true;
|
||||||
# office.enable = false; # Not needed for media center
|
# office.enable = false; # Not needed for media center
|
||||||
# sync.enable = false; # Shared machine, no personal file sync
|
# sync.enable = false; # Shared machine, no personal file sync
|
||||||
};
|
};
|
||||||
@@ -26,11 +31,7 @@
|
|||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
./roles
|
./roles
|
||||||
./modules/emacs
|
./roles/base-linux
|
||||||
./modules/i3+sway
|
|
||||||
./modules/kubectl
|
|
||||||
./modules/plasma-manager
|
|
||||||
./modules/tmux
|
|
||||||
];
|
];
|
||||||
|
|
||||||
# Media center specific overrides can go here if needed
|
# Media center specific overrides can go here if needed
|
||||||
|
|||||||
26
home/home-server.nix
Normal file
26
home/home-server.nix
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{ pkgs, globalInputs, system, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
# Home Manager configuration for servers (minimal with development tools)
|
||||||
|
home.username = "johno";
|
||||||
|
home.homeDirectory = "/home/johno";
|
||||||
|
home.stateVersion = "24.05";
|
||||||
|
|
||||||
|
# Minimal roles for server with development capability
|
||||||
|
home.roles = {
|
||||||
|
base.enable = true;
|
||||||
|
development.enable = true;
|
||||||
|
emacs.enable = true;
|
||||||
|
starship.enable = true;
|
||||||
|
tmux.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
targets.genericLinux.enable = true;
|
||||||
|
home.sessionVariables = {};
|
||||||
|
home.sessionPath = [];
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
./roles
|
||||||
|
./roles/base-linux
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
with lib;
|
|
||||||
|
|
||||||
let
|
|
||||||
doomEmacs = pkgs.fetchFromGitHub {
|
|
||||||
owner = "doomemacs";
|
|
||||||
repo = "doomemacs";
|
|
||||||
rev = "8f55404781edacf66fa330205533b002de3fb5ee";
|
|
||||||
sha256 = "sha256-vHwgENjip2+AFzs4oZfnKEAJKwf5Zid7fakImvxxQUw=";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Shared emacs packages
|
|
||||||
emacsPackages = epkgs: [
|
|
||||||
epkgs.vterm
|
|
||||||
epkgs.treesit-grammars.with-all-grammars
|
|
||||||
];
|
|
||||||
|
|
||||||
# Default emacs configuration with vterm support
|
|
||||||
defaultEmacsPackage =
|
|
||||||
if pkgs.stdenv.isDarwin
|
|
||||||
then pkgs.emacs-macport.pkgs.withPackages emacsPackages
|
|
||||||
else pkgs.emacs.pkgs.withPackages emacsPackages;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
config = {
|
|
||||||
home.packages = [
|
|
||||||
pkgs.emacs-all-the-icons-fonts
|
|
||||||
pkgs.fira-code
|
|
||||||
pkgs.fontconfig
|
|
||||||
pkgs.graphviz
|
|
||||||
pkgs.isort
|
|
||||||
#pkgs.libvterm # native vterm library
|
|
||||||
pkgs.nerd-fonts.fira-code
|
|
||||||
pkgs.nerd-fonts.droid-sans-mono
|
|
||||||
pkgs.nil # nix lsp language server
|
|
||||||
pkgs.nixfmt-rfc-style
|
|
||||||
(pkgs.ripgrep.override {withPCRE2 = true;})
|
|
||||||
pkgs.pipenv
|
|
||||||
pkgs.poetry
|
|
||||||
pkgs.python3
|
|
||||||
];
|
|
||||||
|
|
||||||
programs.emacs = {
|
|
||||||
enable = true;
|
|
||||||
package = defaultEmacsPackage;
|
|
||||||
};
|
|
||||||
|
|
||||||
fonts.fontconfig.enable = true;
|
|
||||||
|
|
||||||
# Mount emacs and tree-sitter grammars from nix store
|
|
||||||
home.file = {
|
|
||||||
"${config.xdg.configHome}/emacs".source = doomEmacs;
|
|
||||||
};
|
|
||||||
|
|
||||||
home.sessionPath = [
|
|
||||||
"${config.xdg.configHome}/emacs/bin"
|
|
||||||
];
|
|
||||||
|
|
||||||
home.sessionVariables = {
|
|
||||||
DOOMDIR = "${config.xdg.configHome}/doom";
|
|
||||||
DOOMLOCALDIR = "${config.xdg.dataHome}/doom";
|
|
||||||
};
|
|
||||||
|
|
||||||
# TODO: Use mkOutOfStoreSymlink instead?
|
|
||||||
home.activation.doomConfig = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
|
||||||
# Always remove and recreate the symlink to ensure it points to the source directory
|
|
||||||
rm -rf "${config.xdg.configHome}/doom"
|
|
||||||
ln -sf "${config.home.homeDirectory}/nixos-configs/home/modules/emacs/doom" "${config.xdg.configHome}/doom"
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,178 +0,0 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
|
|
||||||
# The current KDE config can be output with the command:
|
|
||||||
# nix run github:nix-community/plasma-manager
|
|
||||||
#
|
|
||||||
# Plasma-manager options documentation
|
|
||||||
# https://nix-community.github.io/plasma-manager/options.xhtml
|
|
||||||
#
|
|
||||||
# TODO: (ambitious) Add Kmail support to plasma-manager
|
|
||||||
{
|
|
||||||
programs.plasma = {
|
|
||||||
enable = true;
|
|
||||||
overrideConfig = true;
|
|
||||||
|
|
||||||
hotkeys.commands."launch-ghostty" = {
|
|
||||||
name = "Launch Ghostty";
|
|
||||||
key = "Meta+Return";
|
|
||||||
command = "ghostty";
|
|
||||||
};
|
|
||||||
|
|
||||||
shortcuts = {
|
|
||||||
kmix = {
|
|
||||||
"decrease_microphone_volume" = "Microphone Volume Down";
|
|
||||||
"decrease_volume" = "Volume Down";
|
|
||||||
"decrease_volume_small" = "Shift+Volume Down";
|
|
||||||
"increase_microphone_volume" = "Microphone Volume Up";
|
|
||||||
"increase_volume" = "Volume Up";
|
|
||||||
"increase_volume_small" = "Shift+Volume Up";
|
|
||||||
"mic_mute" = ["Microphone Mute" "Meta+Volume Mute,Microphone Mute" "Meta+Volume Mute,Mute Microphone"];
|
|
||||||
"mute" = "Volume Mute";
|
|
||||||
};
|
|
||||||
|
|
||||||
mediacontrol = {
|
|
||||||
"mediavolumedown" = "none,,Media volume down";
|
|
||||||
"mediavolumeup" = "none,,Media volume up";
|
|
||||||
"nextmedia" = "Media Next";
|
|
||||||
"pausemedia" = "Media Pause";
|
|
||||||
"playmedia" = "none,,Play media playback";
|
|
||||||
"playpausemedia" = "Media Play";
|
|
||||||
"previousmedia" = "Media Previous";
|
|
||||||
"stopmedia" = "Media Stop";
|
|
||||||
};
|
|
||||||
|
|
||||||
ksmserver = {
|
|
||||||
"Lock Session" = ["Meta+Ctrl+Q" "Screensaver" "Screensaver,Lock Session"];
|
|
||||||
};
|
|
||||||
|
|
||||||
kwin = {
|
|
||||||
"Window Close" = "Meta+Shift+Q";
|
|
||||||
"Kill Window" = "Meta+Ctrl+Esc";
|
|
||||||
"Window Operations Menu" = "Alt+F3";
|
|
||||||
"Window Resize" = "Meta+R,,Resize Window";
|
|
||||||
|
|
||||||
"Overview" = "Meta+Ctrl+W";
|
|
||||||
"Grid View" = "Meta+G";
|
|
||||||
"Edit Tiles" = "Meta+T";
|
|
||||||
|
|
||||||
"Activate Window Demanding Attention" = "Meta+Ctrl+A";
|
|
||||||
|
|
||||||
"Show Desktop" = "Meta+Ctrl+D";
|
|
||||||
|
|
||||||
"Walk Through Windows" = "Alt+Tab";
|
|
||||||
"Walk Through Windows (Reverse)" = "Alt+Shift+Tab";
|
|
||||||
"Walk Through Windows of Current Application" = "Alt+`";
|
|
||||||
"Walk Through Windows of Current Application (Reverse)" = "Alt+~";
|
|
||||||
|
|
||||||
"Window Quick Tile Bottom" = "Meta+Down";
|
|
||||||
"Window Quick Tile Left" = "Meta+Left";
|
|
||||||
"Window Quick Tile Right" = "Meta+Right";
|
|
||||||
"Window Quick Tile Top" = "Meta+Up";
|
|
||||||
|
|
||||||
"Switch to Desktop 1" = "Meta+1";
|
|
||||||
"Switch to Desktop 2" = "Meta+2";
|
|
||||||
"Switch to Desktop 3" = "Meta+3";
|
|
||||||
"Switch to Desktop 4" = "Meta+4";
|
|
||||||
"Switch to Desktop 5" = "Meta+5";
|
|
||||||
"Switch to Desktop 6" = "Meta+6";
|
|
||||||
"Switch to Desktop 7" = "Meta+7";
|
|
||||||
"Switch to Desktop 8" = "Meta+8";
|
|
||||||
"Switch to Desktop 9" = "Meta+9";
|
|
||||||
"Switch to Desktop 10" = "Meta+0";
|
|
||||||
|
|
||||||
"Window to Desktop 1" = "Meta+!"; # Meta+Shift+1
|
|
||||||
"Window to Desktop 2" = "Meta+@"; # Meta+Shift+2
|
|
||||||
"Window to Desktop 3" = "Meta+#"; # Meta+Shift+3
|
|
||||||
"Window to Desktop 4" = "Meta+$"; # Meta+Shift+4
|
|
||||||
"Window to Desktop 5" = "Meta+%"; # Meta+Shift+5
|
|
||||||
"Window to Desktop 6" = "Meta+^"; # Meta+Shift+6
|
|
||||||
"Window to Desktop 7" = "Meta+&"; # Meta+Shift+7
|
|
||||||
"Window to Desktop 8" = "Meta+*"; # Meta+Shift+8
|
|
||||||
"Window to Desktop 9" = "Meta+("; # Meta+Shift+9
|
|
||||||
"Window to Desktop 10" = "Meta+)"; # Meta+Shift+0
|
|
||||||
|
|
||||||
"view_actual_size" = "Meta+Ctrl+=";
|
|
||||||
"view_zoom_in" = ["Meta++" "Meta+=,Meta++" "Meta+=,Zoom In"];
|
|
||||||
"view_zoom_out" = "Meta+-";
|
|
||||||
};
|
|
||||||
"org_kde_powerdevil"."Decrease Keyboard Brightness" = "Keyboard Brightness Down";
|
|
||||||
"org_kde_powerdevil"."Decrease Screen Brightness" = "Monitor Brightness Down";
|
|
||||||
"org_kde_powerdevil"."Decrease Screen Brightness Small" = "Shift+Monitor Brightness Down";
|
|
||||||
"org_kde_powerdevil"."Hibernate" = "Hibernate";
|
|
||||||
"org_kde_powerdevil"."Increase Keyboard Brightness" = "Keyboard Brightness Up";
|
|
||||||
"org_kde_powerdevil"."Increase Screen Brightness" = "Monitor Brightness Up";
|
|
||||||
"org_kde_powerdevil"."Increase Screen Brightness Small" = "Shift+Monitor Brightness Up";
|
|
||||||
"org_kde_powerdevil"."PowerDown" = "Power Down";
|
|
||||||
"org_kde_powerdevil"."PowerOff" = "Power Off";
|
|
||||||
"org_kde_powerdevil"."Sleep" = "Sleep";
|
|
||||||
"org_kde_powerdevil"."Toggle Keyboard Backlight" = "Keyboard Light On/Off";
|
|
||||||
"org_kde_powerdevil"."Turn Off Screen" = [ ];
|
|
||||||
"org_kde_powerdevil"."powerProfile" = ["Battery" "Meta+B,Battery" "Meta+B,Switch Power Profile"];
|
|
||||||
|
|
||||||
plasmashell = {
|
|
||||||
"activate application launcher" = ["Meta" "Alt+F1,Meta" "Alt+F1,Activate Application Launcher"];
|
|
||||||
"activate task manager entry 1" = "none,,";
|
|
||||||
"activate task manager entry 2" = "none,,";
|
|
||||||
"activate task manager entry 3" = "none,,";
|
|
||||||
"activate task manager entry 4" = "none,,";
|
|
||||||
"activate task manager entry 5" = "none,,";
|
|
||||||
"activate task manager entry 6" = "none,,";
|
|
||||||
"activate task manager entry 7" = "none,,";
|
|
||||||
"activate task manager entry 8" = "none,,";
|
|
||||||
"activate task manager entry 9" = "none,,";
|
|
||||||
"activate task manager entry 10" = "none,,";
|
|
||||||
"show activity switcher" = "none,,";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
configFile = {
|
|
||||||
kwinrc.Desktops.Number = {
|
|
||||||
value = 10;
|
|
||||||
immutable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
# Enable KWin tiling features
|
|
||||||
kwinrc.Tiling = {
|
|
||||||
# Enable tiling functionality
|
|
||||||
"padding" = 4;
|
|
||||||
};
|
|
||||||
|
|
||||||
# Enable krohnkite plugin automatically
|
|
||||||
kwinrc.Plugins = {
|
|
||||||
krohnkiteEnabled = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
kwinrc.Effect-overview = {
|
|
||||||
# Configure overview effect for better tiling workflow
|
|
||||||
BorderActivate = 9; # Top-left corner activation
|
|
||||||
};
|
|
||||||
|
|
||||||
kcminputrc.Libinput = {
|
|
||||||
AccelerationProfile = "adaptive";
|
|
||||||
PointerAcceleration = 0.5;
|
|
||||||
};
|
|
||||||
|
|
||||||
kcminputrc.Mouse = {
|
|
||||||
X11LibInputXAccelProfileFlat = false;
|
|
||||||
XLbInptAccelProfileFlat = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
kdeglobals.KDE.LookAndFeelPackage = "org.kde.breezedark.desktop";
|
|
||||||
|
|
||||||
# Focus follows mouse configuration
|
|
||||||
kwinrc.Windows = {
|
|
||||||
FocusPolicy = "FocusFollowsMouse";
|
|
||||||
AutoRaise = true; # Set to true if you want windows to auto-raise on focus
|
|
||||||
AutoRaiseInterval = 750; # Delay in ms before auto-raise (if enabled)
|
|
||||||
DelayFocusInterval = 0; # Delay in ms before focus follows mouse
|
|
||||||
};
|
|
||||||
|
|
||||||
# Desktop wallpaper configuration
|
|
||||||
plasma-localerc.Formats.LANG = "en_US.UTF-8";
|
|
||||||
|
|
||||||
# Set wallpaper for all desktops
|
|
||||||
plasmarc.Wallpapers.usersWallpapers = "${../../wallpapers/metroid-samus-returns-kz-3440x1440.jpg}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
tokyo-night = pkgs.tmuxPlugins.mkTmuxPlugin {
|
|
||||||
pluginName = "tokyo-night";
|
|
||||||
rtpFilePath = "tokyo-night.tmux";
|
|
||||||
version = "1.6.1";
|
|
||||||
src = pkgs.fetchFromGitHub {
|
|
||||||
owner = "janoamaral";
|
|
||||||
repo = "tokyo-night-tmux";
|
|
||||||
rev = "d610ced20d5f602a7995854931440e4a1e0ab780";
|
|
||||||
sha256 = "sha256-17vEgkL7C51p/l5gpT9dkOy0bY9n8l0/LV51mR1k+V8=";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
programs.tmux.enable = true;
|
|
||||||
programs.tmux.terminal = "tmux-direct";
|
|
||||||
programs.tmux.keyMode = "vi";
|
|
||||||
programs.tmux.escapeTime = 0;
|
|
||||||
programs.tmux.mouse = true;
|
|
||||||
programs.tmux.newSession = true;
|
|
||||||
programs.tmux.historyLimit = 50000;
|
|
||||||
programs.tmux.clock24 = true;
|
|
||||||
programs.tmux.baseIndex = 1;
|
|
||||||
programs.tmux.prefix = "M-\\\\";
|
|
||||||
|
|
||||||
programs.tmux.plugins = with pkgs; [
|
|
||||||
tmuxPlugins.cpu
|
|
||||||
tmuxPlugins.battery
|
|
||||||
tmuxPlugins.better-mouse-mode
|
|
||||||
tmuxPlugins.net-speed
|
|
||||||
tmuxPlugins.online-status
|
|
||||||
tmuxPlugins.pain-control
|
|
||||||
tmuxPlugins.tilish
|
|
||||||
tmuxPlugins.yank
|
|
||||||
|
|
||||||
{
|
|
||||||
plugin = tmuxPlugins.resurrect;
|
|
||||||
extraConfig = "set -g @resurrect-strategy-nvim 'session'";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
plugin = tmuxPlugins.continuum;
|
|
||||||
extraConfig = ''
|
|
||||||
set -g @continuum-restore 'on'
|
|
||||||
set -g @continuum-save-interval '15' # minutes
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
|
|
||||||
tokyo-night
|
|
||||||
];
|
|
||||||
}
|
|
||||||
22
home/roles/3d-printing/default.nix
Normal file
22
home/roles/3d-printing/default.nix
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.home.roles."3d-printing";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.home.roles."3d-printing" = {
|
||||||
|
enable = mkEnableOption "Enable 3D printing applications and tools";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
# 3D Slicing Software
|
||||||
|
orca-slicer # G-code generator for 3D printers (Bambu, Prusa, Voron, etc.)
|
||||||
|
|
||||||
|
# 3D Modeling Software
|
||||||
|
openscad-unstable # 3D parametric model compiler (nightly build)
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
727
home/roles/aerospace/default.nix
Normal file
727
home/roles/aerospace/default.nix
Normal file
@@ -0,0 +1,727 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.home.roles.aerospace;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.home.roles.aerospace = {
|
||||||
|
enable = mkEnableOption "AeroSpace tiling window manager for macOS";
|
||||||
|
|
||||||
|
leader = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "cmd";
|
||||||
|
description = "Leader key for aerospace shortcuts (e.g., 'cmd', 'ctrl', 'alt')";
|
||||||
|
example = "ctrl";
|
||||||
|
};
|
||||||
|
|
||||||
|
launchd.enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Whether to enable launchd agent for auto-starting aerospace";
|
||||||
|
};
|
||||||
|
|
||||||
|
userSettings = mkOption {
|
||||||
|
type = types.attrs;
|
||||||
|
default = {};
|
||||||
|
description = ''
|
||||||
|
Additional aerospace configuration settings to merge with defaults.
|
||||||
|
Use this to override or extend the default configuration on a per-machine basis.
|
||||||
|
'';
|
||||||
|
example = literalExpression ''
|
||||||
|
{
|
||||||
|
mode.main.binding."''${leader}-custom" = "custom-command";
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
autoraise = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Whether to enable autoraise (auto-focus window on hover)";
|
||||||
|
};
|
||||||
|
|
||||||
|
pollMillis = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 50;
|
||||||
|
description = "Polling interval in milliseconds";
|
||||||
|
};
|
||||||
|
|
||||||
|
delay = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 2;
|
||||||
|
description = "Delay before raising window";
|
||||||
|
};
|
||||||
|
|
||||||
|
focusDelay = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 2;
|
||||||
|
description = "Delay before focusing window";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
enableSpansDisplays = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
Configure macOS Spaces to span displays (required for aerospace multi-monitor support).
|
||||||
|
Sets com.apple.spaces.spans-displays to true.
|
||||||
|
|
||||||
|
NOTE: This was previously set at the system level in modules/aerospace.nix,
|
||||||
|
but has been moved to home-manager for better modularity.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
ctrlShortcuts = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Remap common macOS Cmd shortcuts to Ctrl equivalents for all operations.
|
||||||
|
This makes macOS behave more like Linux.
|
||||||
|
|
||||||
|
Shortcuts remapped globally:
|
||||||
|
- Ctrl+N: New Window
|
||||||
|
- Ctrl+T: New Tab
|
||||||
|
- Ctrl+W: Close Tab
|
||||||
|
- Ctrl+S: Save / Save As
|
||||||
|
- Ctrl+O: Open
|
||||||
|
- Ctrl+F: Find
|
||||||
|
- Ctrl+H: Find and Replace
|
||||||
|
- Ctrl+P: Print
|
||||||
|
- Ctrl+C/V/X: Copy/Paste/Cut
|
||||||
|
- Ctrl+Z: Undo
|
||||||
|
|
||||||
|
NOTE: Terminal emulators like Ghostty require per-app overrides (configured separately)
|
||||||
|
to preserve Ctrl+C as SIGINT instead of Copy.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sketchybar = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Whether to enable SketchyBar status bar";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
# Only apply on Darwin systems
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = pkgs.stdenv.isDarwin;
|
||||||
|
message = "Aerospace role is only supported on macOS (Darwin) systems";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# Configure macOS preferences via targets.darwin.defaults
|
||||||
|
targets.darwin.defaults = mkMerge [
|
||||||
|
# Spaces span displays (required for multi-monitor aerospace)
|
||||||
|
(mkIf cfg.enableSpansDisplays {
|
||||||
|
"com.apple.spaces" = {
|
||||||
|
spans-displays = true;
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
# Ctrl shortcuts to make macOS behave more like Linux
|
||||||
|
(mkIf cfg.ctrlShortcuts.enable {
|
||||||
|
NSGlobalDomain.NSUserKeyEquivalents = {
|
||||||
|
# Window/Tab operations
|
||||||
|
"New Window" = "^n";
|
||||||
|
"New Tab" = "^t";
|
||||||
|
"Close Tab" = "^w";
|
||||||
|
# File operations
|
||||||
|
"Save" = "^s";
|
||||||
|
"Save As…" = "^$s"; # Ctrl+Shift+S
|
||||||
|
"Open" = "^o";
|
||||||
|
"Open…" = "^o";
|
||||||
|
# Find operations
|
||||||
|
"Find" = "^f";
|
||||||
|
"Find…" = "^f";
|
||||||
|
"Find and Replace" = "^h";
|
||||||
|
"Find and Replace…" = "^h";
|
||||||
|
# Print
|
||||||
|
"Print" = "^p";
|
||||||
|
"Print…" = "^p";
|
||||||
|
# Clipboard operations
|
||||||
|
"Copy" = "^c";
|
||||||
|
"Paste" = "^v";
|
||||||
|
"Cut" = "^x";
|
||||||
|
# Undo/Redo
|
||||||
|
"Undo" = "^z";
|
||||||
|
"Redo" = "^$z"; # Ctrl+Shift+Z
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
# Ghostty-specific overrides to preserve terminal behavior
|
||||||
|
# Remap clipboard operations back to Cmd (macOS default) so Ctrl+C remains SIGINT
|
||||||
|
(mkIf cfg.ctrlShortcuts.enable {
|
||||||
|
"com.mitchellh.ghostty".NSUserKeyEquivalents = {
|
||||||
|
# Remap back to Cmd for clipboard operations
|
||||||
|
"Copy" = "@c"; # Cmd+C
|
||||||
|
"Paste" = "@v"; # Cmd+V
|
||||||
|
"Cut" = "@x"; # Cmd+X
|
||||||
|
"Undo" = "@z"; # Cmd+Z
|
||||||
|
"Redo" = "@$z"; # Cmd+Shift+Z
|
||||||
|
};
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
# Install aerospace package and optional tools if enabled
|
||||||
|
home.packages = [ pkgs.aerospace ]
|
||||||
|
++ optionals cfg.autoraise.enable [ pkgs.autoraise ]
|
||||||
|
++ optionals cfg.sketchybar.enable [ pkgs.sketchybar pkgs.sketchybar-app-font ];
|
||||||
|
|
||||||
|
# Enable and configure aerospace
|
||||||
|
programs.aerospace.enable = true;
|
||||||
|
programs.aerospace.launchd.enable = cfg.launchd.enable;
|
||||||
|
programs.aerospace.userSettings = mkMerge [
|
||||||
|
# Default configuration with leader key substitution
|
||||||
|
{
|
||||||
|
# Disable normalizations for i3-like behavior
|
||||||
|
enable-normalization-flatten-containers = false;
|
||||||
|
enable-normalization-opposite-orientation-for-nested-containers = false;
|
||||||
|
|
||||||
|
mode.main.binding = {
|
||||||
|
"${cfg.leader}-w" = "layout accordion horizontal"; # tabbed
|
||||||
|
"${cfg.leader}-s" = "layout accordion vertical"; # stacking
|
||||||
|
"${cfg.leader}-e" = "layout tiles horizontal vertical"; # tiles, toggles orientation
|
||||||
|
"${cfg.leader}-shift-q" = "close";
|
||||||
|
"${cfg.leader}-shift-f" = "fullscreen";
|
||||||
|
"${cfg.leader}-h" = "focus left";
|
||||||
|
"${cfg.leader}-j" = "focus down";
|
||||||
|
"${cfg.leader}-k" = "focus up";
|
||||||
|
"${cfg.leader}-l" = "focus right";
|
||||||
|
"${cfg.leader}-shift-h" = "move left";
|
||||||
|
"${cfg.leader}-shift-j" = "move down";
|
||||||
|
"${cfg.leader}-shift-k" = "move up";
|
||||||
|
"${cfg.leader}-shift-l" = "move right";
|
||||||
|
"${cfg.leader}-r" = "mode resize";
|
||||||
|
"${cfg.leader}-1" = "workspace 1";
|
||||||
|
"${cfg.leader}-2" = "workspace 2";
|
||||||
|
"${cfg.leader}-3" = "workspace 3";
|
||||||
|
"${cfg.leader}-4" = "workspace 4";
|
||||||
|
"${cfg.leader}-5" = "workspace 5";
|
||||||
|
"${cfg.leader}-6" = "workspace 6";
|
||||||
|
"${cfg.leader}-7" = "workspace 7";
|
||||||
|
"${cfg.leader}-8" = "workspace 8";
|
||||||
|
"${cfg.leader}-9" = "workspace 9";
|
||||||
|
"${cfg.leader}-0" = "workspace 10";
|
||||||
|
"${cfg.leader}-shift-1" = "move-node-to-workspace 1";
|
||||||
|
"${cfg.leader}-shift-2" = "move-node-to-workspace 2";
|
||||||
|
"${cfg.leader}-shift-3" = "move-node-to-workspace 3";
|
||||||
|
"${cfg.leader}-shift-4" = "move-node-to-workspace 4";
|
||||||
|
"${cfg.leader}-shift-5" = "move-node-to-workspace 5";
|
||||||
|
"${cfg.leader}-shift-6" = "move-node-to-workspace 6";
|
||||||
|
"${cfg.leader}-shift-7" = "move-node-to-workspace 7";
|
||||||
|
"${cfg.leader}-shift-8" = "move-node-to-workspace 8";
|
||||||
|
"${cfg.leader}-shift-9" = "move-node-to-workspace 9";
|
||||||
|
"${cfg.leader}-shift-0" = "move-node-to-workspace 10";
|
||||||
|
"${cfg.leader}-tab" = "workspace-back-and-forth";
|
||||||
|
"${cfg.leader}-shift-tab" = "move-workspace-to-monitor --wrap-around next";
|
||||||
|
|
||||||
|
"${cfg.leader}-enter" = ''
|
||||||
|
exec-and-forget osascript <<'APPLESCRIPT'
|
||||||
|
tell application "Ghostty"
|
||||||
|
activate
|
||||||
|
tell application "System Events"
|
||||||
|
keystroke "n" using {command down}
|
||||||
|
end tell
|
||||||
|
end tell
|
||||||
|
APPLESCRIPT
|
||||||
|
'';
|
||||||
|
|
||||||
|
"${cfg.leader}-shift-enter" = ''
|
||||||
|
exec-and-forget osascript <<'APPLESCRIPT'
|
||||||
|
tell application "Google Chrome"
|
||||||
|
set newWindow to make new window
|
||||||
|
activate
|
||||||
|
tell newWindow to set index to 1
|
||||||
|
end tell
|
||||||
|
APPLESCRIPT
|
||||||
|
'';
|
||||||
|
|
||||||
|
"${cfg.leader}-shift-e" = "exec-and-forget zsh --login -c \"emacsclient -c -n\"";
|
||||||
|
|
||||||
|
# Service mode: Deliberate aerospace window management
|
||||||
|
"${cfg.leader}-i" = "mode service";
|
||||||
|
|
||||||
|
# Passthrough mode: Temporarily disable aerospace to use macOS shortcuts
|
||||||
|
"${cfg.leader}-p" = "mode passthrough";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Resize mode: For window resizing operations
|
||||||
|
mode.resize.binding = {
|
||||||
|
h = "resize width -50";
|
||||||
|
j = "resize height +50";
|
||||||
|
k = "resize height -50";
|
||||||
|
l = "resize width +50";
|
||||||
|
|
||||||
|
minus = "resize smart -50";
|
||||||
|
equal = "resize smart +50";
|
||||||
|
|
||||||
|
esc = "mode main";
|
||||||
|
enter = "mode main";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Service mode: For deliberate aerospace window management operations
|
||||||
|
mode.service.binding = {
|
||||||
|
esc = ["reload-config" "mode main"];
|
||||||
|
r = ["flatten-workspace-tree" "mode main"]; # reset layout
|
||||||
|
f = ["layout floating tiling" "mode main"]; # Toggle between floating and tiling layout
|
||||||
|
backspace = ["close-all-windows-but-current" "mode main"];
|
||||||
|
|
||||||
|
"${cfg.leader}-shift-h" = ["join-with left" "mode main"];
|
||||||
|
"${cfg.leader}-shift-j" = ["join-with down" "mode main"];
|
||||||
|
"${cfg.leader}-shift-k" = ["join-with up" "mode main"];
|
||||||
|
"${cfg.leader}-shift-l" = ["join-with right" "mode main"];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Passthrough mode: All shortcuts pass through to macOS
|
||||||
|
mode.passthrough.binding = {
|
||||||
|
esc = "mode main";
|
||||||
|
"${cfg.leader}-p" = "mode main";
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar integration - notify bar of workspace changes
|
||||||
|
exec-on-workspace-change = mkIf cfg.sketchybar.enable [
|
||||||
|
"/bin/bash" "-c"
|
||||||
|
"${pkgs.sketchybar}/bin/sketchybar --trigger aerospace_workspace_change FOCUSED=$AEROSPACE_FOCUSED_WORKSPACE PREV=$AEROSPACE_PREV_WORKSPACE"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
# Gaps configuration - prevent windows from overlapping SketchyBar
|
||||||
|
(mkIf cfg.sketchybar.enable {
|
||||||
|
gaps = {
|
||||||
|
outer = {
|
||||||
|
top = 0;
|
||||||
|
bottom = 38;
|
||||||
|
left = 0;
|
||||||
|
right = 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
cfg.userSettings
|
||||||
|
];
|
||||||
|
|
||||||
|
# Launchd agent for autoraise
|
||||||
|
launchd.agents.autoraise = mkIf cfg.autoraise.enable {
|
||||||
|
enable = true;
|
||||||
|
config = {
|
||||||
|
ProgramArguments = [
|
||||||
|
"${pkgs.autoraise}/bin/AutoRaise"
|
||||||
|
"-pollMillis" (toString cfg.autoraise.pollMillis)
|
||||||
|
"-delay" (toString cfg.autoraise.delay)
|
||||||
|
"-focusDelay" (toString cfg.autoraise.focusDelay)
|
||||||
|
];
|
||||||
|
RunAtLoad = true;
|
||||||
|
KeepAlive = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar configuration
|
||||||
|
home.file.".config/sketchybar/sketchybarrc" = mkIf cfg.sketchybar.enable {
|
||||||
|
executable = true;
|
||||||
|
onChange = "${pkgs.sketchybar}/bin/sketchybar --reload";
|
||||||
|
text = ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Plugin directory
|
||||||
|
PLUGIN_DIR="$HOME/.config/sketchybar/plugins"
|
||||||
|
|
||||||
|
# Colors - i3/sway theme with exact color matching
|
||||||
|
# Focused window/workspace color from i3/sway
|
||||||
|
FOCUSED=0xff285577
|
||||||
|
|
||||||
|
# Background colors matching i3blocks bar
|
||||||
|
BAR_BG=0xff333333 # Dark gray
|
||||||
|
ITEM_BG=0xff333333 # Dark gray matching bar
|
||||||
|
|
||||||
|
# Text colors
|
||||||
|
TEXT=0xffffffff # White text
|
||||||
|
GRAY=0xff888888 # Muted text for inactive items
|
||||||
|
|
||||||
|
# Accent colors for warnings
|
||||||
|
WARNING=0xffff9900
|
||||||
|
CRITICAL=0xff900000
|
||||||
|
|
||||||
|
# Configure the bar appearance
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --bar \
|
||||||
|
position=bottom \
|
||||||
|
height=30 \
|
||||||
|
color=$BAR_BG \
|
||||||
|
border_width=0 \
|
||||||
|
corner_radius=0 \
|
||||||
|
padding_left=10 \
|
||||||
|
padding_right=10 \
|
||||||
|
shadow=off \
|
||||||
|
topmost=on \
|
||||||
|
sticky=on
|
||||||
|
|
||||||
|
# Set default properties for all items
|
||||||
|
# Using monospace font to match waybar's Fira Code styling
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --default \
|
||||||
|
updates=when_shown \
|
||||||
|
icon.font="Fira Code:Regular:13.0" \
|
||||||
|
icon.color=$TEXT \
|
||||||
|
icon.padding_left=4 \
|
||||||
|
icon.padding_right=4 \
|
||||||
|
label.font="Fira Code:Regular:13.0" \
|
||||||
|
label.color=$TEXT \
|
||||||
|
label.padding_left=4 \
|
||||||
|
label.padding_right=4 \
|
||||||
|
padding_left=4 \
|
||||||
|
padding_right=4 \
|
||||||
|
background.corner_radius=0 \
|
||||||
|
background.height=30
|
||||||
|
|
||||||
|
# Register aerospace workspace change event
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add event aerospace_workspace_change
|
||||||
|
|
||||||
|
# Create workspace indicators for workspaces 1-10
|
||||||
|
for sid in 1 2 3 4 5 6 7 8 9 10; do
|
||||||
|
# Display "0" for workspace 10
|
||||||
|
if [ "$sid" = "10" ]; then
|
||||||
|
display="0"
|
||||||
|
else
|
||||||
|
display="$sid"
|
||||||
|
fi
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add item space.$sid left \
|
||||||
|
--subscribe space.$sid aerospace_workspace_change \
|
||||||
|
--set space.$sid \
|
||||||
|
drawing=on \
|
||||||
|
update_freq=2 \
|
||||||
|
width=32 \
|
||||||
|
background.color=$ITEM_BG \
|
||||||
|
background.corner_radius=0 \
|
||||||
|
background.height=30 \
|
||||||
|
background.drawing=on \
|
||||||
|
icon="$display" \
|
||||||
|
icon.padding_left=13 \
|
||||||
|
icon.padding_right=11 \
|
||||||
|
icon.align=center \
|
||||||
|
label.drawing=off \
|
||||||
|
click_script="${pkgs.aerospace}/bin/aerospace workspace $sid" \
|
||||||
|
script="$PLUGIN_DIR/aerospace.sh $sid"
|
||||||
|
done
|
||||||
|
|
||||||
|
# System monitoring modules (right side)
|
||||||
|
# Note: Items added to 'right' appear in reverse order (last added = leftmost)
|
||||||
|
# Adding in reverse to get: disk | cpu | memory | battery | volume | calendar
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add item calendar right \
|
||||||
|
--set calendar \
|
||||||
|
icon="📅" \
|
||||||
|
update_freq=30 \
|
||||||
|
background.color=$ITEM_BG \
|
||||||
|
background.drawing=on \
|
||||||
|
script="$PLUGIN_DIR/calendar.sh"
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add item volume right \
|
||||||
|
--set volume \
|
||||||
|
background.color=$ITEM_BG \
|
||||||
|
background.drawing=on \
|
||||||
|
script="$PLUGIN_DIR/volume.sh" \
|
||||||
|
--subscribe volume volume_change
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add item battery right \
|
||||||
|
--set battery \
|
||||||
|
update_freq=120 \
|
||||||
|
background.color=$ITEM_BG \
|
||||||
|
background.drawing=on \
|
||||||
|
script="$PLUGIN_DIR/battery.sh" \
|
||||||
|
--subscribe battery system_woke power_source_change
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add item memory right \
|
||||||
|
--set memory \
|
||||||
|
update_freq=5 \
|
||||||
|
icon="🐏" \
|
||||||
|
background.color=$ITEM_BG \
|
||||||
|
background.drawing=on \
|
||||||
|
script="$PLUGIN_DIR/memory.sh"
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add item cpu right \
|
||||||
|
--set cpu \
|
||||||
|
update_freq=2 \
|
||||||
|
icon="🧠" \
|
||||||
|
background.color=$ITEM_BG \
|
||||||
|
background.drawing=on \
|
||||||
|
script="$PLUGIN_DIR/cpu.sh"
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add item disk right \
|
||||||
|
--set disk \
|
||||||
|
update_freq=60 \
|
||||||
|
icon="💾" \
|
||||||
|
background.color=$ITEM_BG \
|
||||||
|
background.drawing=on \
|
||||||
|
script="$PLUGIN_DIR/disk.sh"
|
||||||
|
|
||||||
|
# Menu bar extras / system tray items (rightmost)
|
||||||
|
# Note: Requires Screen Recording permission for SketchyBar in System Settings
|
||||||
|
# Use 'sketchybar --query default_menu_items' to discover available items
|
||||||
|
|
||||||
|
# Bluetooth
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add alias "Control Center,Bluetooth" right \
|
||||||
|
--set "Control Center,Bluetooth" \
|
||||||
|
alias.update_freq=1 \
|
||||||
|
padding_left=0 \
|
||||||
|
padding_right=0
|
||||||
|
|
||||||
|
# WiFi
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --add alias "Control Center,WiFi" right \
|
||||||
|
--set "Control Center,WiFi" \
|
||||||
|
alias.update_freq=1 \
|
||||||
|
padding_left=0 \
|
||||||
|
padding_right=0
|
||||||
|
|
||||||
|
# Add other menu bar apps as discovered
|
||||||
|
# Common examples:
|
||||||
|
# - Cloudflare WARP: --add alias "Cloudflare WARP,Item-0" right
|
||||||
|
# - Notion Calendar: --add alias "Notion Calendar,Item-0" right
|
||||||
|
# Run 'sketchybar --query default_menu_items' to find exact names
|
||||||
|
|
||||||
|
# Update the bar
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --update
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar aerospace workspace plugin
|
||||||
|
home.file.".config/sketchybar/plugins/aerospace.sh" = mkIf cfg.sketchybar.enable {
|
||||||
|
executable = true;
|
||||||
|
text = ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
FOCUSED_COLOR=0xff285577
|
||||||
|
ITEM_BG=0xff333333
|
||||||
|
TEXT=0xffffffff
|
||||||
|
GRAY=0xff555555
|
||||||
|
|
||||||
|
# Get the currently focused workspace directly from aerospace
|
||||||
|
# Trim whitespace to ensure clean comparison
|
||||||
|
FOCUSED=$(${pkgs.aerospace}/bin/aerospace list-workspaces --focused | tr -d ' \n\r')
|
||||||
|
|
||||||
|
# Get list of empty workspaces
|
||||||
|
EMPTY_WORKSPACES=$(${pkgs.aerospace}/bin/aerospace list-workspaces --monitor all --empty)
|
||||||
|
|
||||||
|
# Get workspace number - from $1 if provided (event-triggered), otherwise extract from $NAME (routine update)
|
||||||
|
# $NAME is always available (e.g., "space.1", "space.2", etc.)
|
||||||
|
# $1 is only available when called via event trigger with positional argument
|
||||||
|
if [ -n "$1" ]; then
|
||||||
|
WORKSPACE_NUM=$(echo "$1" | tr -d ' \n\r')
|
||||||
|
else
|
||||||
|
# Extract number from item name: "space.1" -> "1", "space.10" -> "10"
|
||||||
|
WORKSPACE_NUM=$(echo "$NAME" | sed 's/space\.//')
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if workspace has windows (is NOT empty)
|
||||||
|
IS_EMPTY=false
|
||||||
|
if echo "$EMPTY_WORKSPACES" | grep -q "^$WORKSPACE_NUM$"; then
|
||||||
|
IS_EMPTY=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if this workspace is focused
|
||||||
|
IS_FOCUSED=false
|
||||||
|
if [ "$WORKSPACE_NUM" = "$FOCUSED" ]; then
|
||||||
|
IS_FOCUSED=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine display value (workspace 10 displays as "0")
|
||||||
|
if [ "$WORKSPACE_NUM" = "10" ]; then
|
||||||
|
DISPLAY="0"
|
||||||
|
else
|
||||||
|
DISPLAY="$WORKSPACE_NUM"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Determine visibility and styling
|
||||||
|
# Always show focused workspace (even if empty) with fixed width
|
||||||
|
# Hide non-focused empty workspaces by setting width to 0 (collapsed)
|
||||||
|
# Show non-focused non-empty workspaces with fixed width and inactive styling
|
||||||
|
|
||||||
|
if [ "$IS_FOCUSED" = "true" ]; then
|
||||||
|
# Focused workspace - always show with focused styling and bold font
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set space.$WORKSPACE_NUM \
|
||||||
|
drawing=on \
|
||||||
|
icon="$DISPLAY" \
|
||||||
|
width=32 \
|
||||||
|
icon.padding_left=13 \
|
||||||
|
icon.padding_right=11 \
|
||||||
|
icon.align=center \
|
||||||
|
background.color=$FOCUSED_COLOR \
|
||||||
|
background.drawing=on \
|
||||||
|
icon.color=$TEXT \
|
||||||
|
icon.font="Fira Code:Bold:13.0"
|
||||||
|
elif [ "$IS_EMPTY" = "true" ]; then
|
||||||
|
# Empty workspace (not focused) - hide by collapsing width and clearing content
|
||||||
|
# Using width=0 with drawing=on so updates=when_shown continues to run the script
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set space.$WORKSPACE_NUM \
|
||||||
|
drawing=on \
|
||||||
|
icon="" \
|
||||||
|
label="" \
|
||||||
|
width=0 \
|
||||||
|
icon.padding_left=0 \
|
||||||
|
icon.padding_right=0 \
|
||||||
|
background.drawing=off
|
||||||
|
else
|
||||||
|
# Non-empty workspace (not focused) - show with inactive styling and white text
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set space.$WORKSPACE_NUM \
|
||||||
|
drawing=on \
|
||||||
|
icon="$DISPLAY" \
|
||||||
|
width=32 \
|
||||||
|
icon.padding_left=13 \
|
||||||
|
icon.padding_right=11 \
|
||||||
|
icon.align=center \
|
||||||
|
background.color=$ITEM_BG \
|
||||||
|
background.drawing=on \
|
||||||
|
icon.color=$TEXT \
|
||||||
|
icon.font="Fira Code:Regular:13.0"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar CPU monitoring plugin
|
||||||
|
home.file.".config/sketchybar/plugins/cpu.sh" = mkIf cfg.sketchybar.enable {
|
||||||
|
executable = true;
|
||||||
|
text = ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
CORE_COUNT=$(sysctl -n machdep.cpu.thread_count)
|
||||||
|
CPU_INFO=$(ps -eo pcpu,user)
|
||||||
|
CPU_SYS=$(echo "$CPU_INFO" | grep -v $(whoami) | sed "s/[^ 0-9\.]//g" | awk "{sum+=\$1} END {print sum/(100.0 * $CORE_COUNT)}")
|
||||||
|
CPU_USER=$(echo "$CPU_INFO" | grep $(whoami) | sed "s/[^ 0-9\.]//g" | awk "{sum+=\$1} END {print sum/(100.0 * $CORE_COUNT)}")
|
||||||
|
CPU_PERCENT="$(echo "$CPU_SYS $CPU_USER" | awk '{printf "%.0f\n", ($1 + $2)*100}')"
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set $NAME label="$CPU_PERCENT%"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar memory monitoring plugin
|
||||||
|
# Shows actual memory pressure (excludes file cache/inactive pages)
|
||||||
|
home.file.".config/sketchybar/plugins/memory.sh" = mkIf cfg.sketchybar.enable {
|
||||||
|
executable = true;
|
||||||
|
text = ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Use awk for all arithmetic to avoid bash integer overflow on large RAM systems
|
||||||
|
# Memory pressure = Anonymous (app memory) + Wired + Compressor RAM
|
||||||
|
# - Anonymous pages: app-allocated memory (heap, stack) - matches Activity Monitor's "App Memory"
|
||||||
|
# - Wired: kernel/system memory that can't be paged out
|
||||||
|
# - Pages occupied by compressor: actual RAM used by compressor (NOT "stored in compressor")
|
||||||
|
TOTAL_RAM=$(sysctl -n hw.memsize)
|
||||||
|
MEMORY_PERCENT=$(vm_stat | awk -v total_ram="$TOTAL_RAM" '
|
||||||
|
/page size of/ { page_size = $8 }
|
||||||
|
/Anonymous pages/ { anon = $3 + 0 }
|
||||||
|
/Pages wired/ { wired = $4 + 0 }
|
||||||
|
/Pages occupied by compressor/ { compressor = $5 + 0 }
|
||||||
|
END {
|
||||||
|
used = (anon + wired + compressor) * page_size
|
||||||
|
printf "%.0f", used / total_ram * 100
|
||||||
|
}
|
||||||
|
')
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set $NAME label="$MEMORY_PERCENT%"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar disk monitoring plugin
|
||||||
|
home.file.".config/sketchybar/plugins/disk.sh" = mkIf cfg.sketchybar.enable {
|
||||||
|
executable = true;
|
||||||
|
text = ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
DISK_USAGE=$(df -H / | grep -v Filesystem | awk '{print $5}')
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set $NAME label="$DISK_USAGE"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar battery monitoring plugin
|
||||||
|
home.file.".config/sketchybar/plugins/battery.sh" = mkIf cfg.sketchybar.enable {
|
||||||
|
executable = true;
|
||||||
|
text = ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
PERCENTAGE=$(pmset -g batt | grep -Eo "\d+%" | cut -d% -f1)
|
||||||
|
CHARGING=$(pmset -g batt | grep 'AC Power')
|
||||||
|
|
||||||
|
if [ "$PERCENTAGE" = "" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Select icon based on battery level
|
||||||
|
case ''${PERCENTAGE} in
|
||||||
|
9[0-9]|100) ICON="🔋"
|
||||||
|
;;
|
||||||
|
[6-8][0-9]) ICON="🔋"
|
||||||
|
;;
|
||||||
|
[3-5][0-9]) ICON="🔋"
|
||||||
|
;;
|
||||||
|
[1-2][0-9]) ICON="🔋"
|
||||||
|
;;
|
||||||
|
*) ICON="🪫"
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Show charging icon if connected to power
|
||||||
|
if [[ $CHARGING != "" ]]; then
|
||||||
|
ICON="⚡"
|
||||||
|
fi
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set $NAME icon="$ICON" label="''${PERCENTAGE}%"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar volume monitoring plugin
|
||||||
|
home.file.".config/sketchybar/plugins/volume.sh" = mkIf cfg.sketchybar.enable {
|
||||||
|
executable = true;
|
||||||
|
text = ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ "$SENDER" = "volume_change" ]; then
|
||||||
|
VOLUME=$(osascript -e "output volume of (get volume settings)")
|
||||||
|
MUTED=$(osascript -e "output muted of (get volume settings)")
|
||||||
|
|
||||||
|
if [ "$MUTED" = "true" ]; then
|
||||||
|
ICON="🔇"
|
||||||
|
LABEL=""
|
||||||
|
else
|
||||||
|
case $VOLUME in
|
||||||
|
[6-9][0-9]|100) ICON="🔊"
|
||||||
|
;;
|
||||||
|
[3-5][0-9]) ICON="🔉"
|
||||||
|
;;
|
||||||
|
*) ICON="🔈"
|
||||||
|
esac
|
||||||
|
LABEL="$VOLUME%"
|
||||||
|
fi
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set $NAME icon="$ICON" label="$LABEL"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# SketchyBar calendar/clock plugin
|
||||||
|
home.file.".config/sketchybar/plugins/calendar.sh" = mkIf cfg.sketchybar.enable {
|
||||||
|
executable = true;
|
||||||
|
text = ''
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
${pkgs.sketchybar}/bin/sketchybar --set $NAME label="$(date '+%Y-%m-%d %H:%M')"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Launchd agent for auto-starting sketchybar
|
||||||
|
launchd.agents.sketchybar = mkIf cfg.sketchybar.enable {
|
||||||
|
enable = true;
|
||||||
|
config = {
|
||||||
|
ProgramArguments = [ "${pkgs.sketchybar}/bin/sketchybar" ];
|
||||||
|
RunAtLoad = true;
|
||||||
|
KeepAlive = true;
|
||||||
|
StandardOutPath = "/tmp/sketchybar.log";
|
||||||
|
StandardErrorPath = "/tmp/sketchybar.err.log";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
11
home/roles/base-darwin/default.nix
Normal file
11
home/roles/base-darwin/default.nix
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
# Base imports for Darwin home configurations
|
||||||
|
# Includes Darwin-specific roles that only work on macOS
|
||||||
|
imports = [
|
||||||
|
../aerospace
|
||||||
|
];
|
||||||
|
|
||||||
|
# Override to use -d instead of --delete-older-than on Darwin due to launchd bug
|
||||||
|
# https://github.com/nix-community/home-manager/issues/7211
|
||||||
|
nix.gc.options = "-d";
|
||||||
|
}
|
||||||
8
home/roles/base-linux/default.nix
Normal file
8
home/roles/base-linux/default.nix
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
# Base imports for Linux home configurations
|
||||||
|
# Includes Linux-specific roles that require Linux-only home-manager modules
|
||||||
|
imports = [
|
||||||
|
../plasma-manager
|
||||||
|
../i3+sway
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -24,6 +24,17 @@ in
|
|||||||
tree
|
tree
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# Automatic garbage collection for user profile (home-manager generations).
|
||||||
|
# This complements system-level gc which only cleans system generations.
|
||||||
|
# - Linux: Uses --delete-older-than to keep 10-day rollback window
|
||||||
|
# - Darwin: Overridden to use -d in base-darwin role to avoid launchd bug
|
||||||
|
# (https://github.com/nix-community/home-manager/issues/7211)
|
||||||
|
nix.gc = {
|
||||||
|
automatic = true;
|
||||||
|
randomizedDelaySec = mkIf pkgs.stdenv.isLinux "14m";
|
||||||
|
options = lib.mkDefault "--delete-older-than 10d";
|
||||||
|
};
|
||||||
|
|
||||||
# Essential programs everyone needs
|
# Essential programs everyone needs
|
||||||
programs.bash = {
|
programs.bash = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@@ -41,9 +52,9 @@ in
|
|||||||
|
|
||||||
programs.git = {
|
programs.git = {
|
||||||
enable = true;
|
enable = true;
|
||||||
userName = "John Ogle";
|
settings = {
|
||||||
userEmail = "john@ogle.fyi";
|
user.name = "John Ogle";
|
||||||
extraConfig = {
|
user.email = "john@ogle.fyi";
|
||||||
safe.directory = "/etc/nixos";
|
safe.directory = "/etc/nixos";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -58,8 +69,11 @@ in
|
|||||||
|
|
||||||
programs.ssh = {
|
programs.ssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
addKeysToAgent = "yes";
|
enableDefaultConfig = false;
|
||||||
matchBlocks = {
|
matchBlocks = {
|
||||||
|
"*" = {
|
||||||
|
addKeysToAgent = "yes";
|
||||||
|
};
|
||||||
"nucdeb1" = {
|
"nucdeb1" = {
|
||||||
hostname = "nucdeb1.oglehome";
|
hostname = "nucdeb1.oglehome";
|
||||||
user = "root";
|
user = "root";
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ in
|
|||||||
home.packages = [
|
home.packages = [
|
||||||
# Communication apps
|
# Communication apps
|
||||||
pkgs.element-desktop
|
pkgs.element-desktop
|
||||||
#pkgs.fluffychat #marked insecure as of nixos 25.05
|
# Re-enabled in 25.11 after security issues were resolved
|
||||||
|
pkgs.fluffychat
|
||||||
pkgs.nextcloud-talk-desktop
|
pkgs.nextcloud-talk-desktop
|
||||||
|
|
||||||
# For logging back into google chat
|
# For logging back into google chat
|
||||||
|
|||||||
@@ -1,13 +1,24 @@
|
|||||||
{
|
{
|
||||||
|
# Shared roles that work across all platforms (Linux, Darwin, etc.)
|
||||||
|
# Platform-specific roles are imported via base-linux or base-darwin
|
||||||
|
# in each home configuration file
|
||||||
imports = [
|
imports = [
|
||||||
|
./3d-printing
|
||||||
./base
|
./base
|
||||||
./communication
|
./communication
|
||||||
./desktop
|
./desktop
|
||||||
./development
|
./development
|
||||||
|
./email
|
||||||
./gaming
|
./gaming
|
||||||
./kdeconnect
|
./kdeconnect
|
||||||
|
./kubectl
|
||||||
|
./launchers
|
||||||
./media
|
./media
|
||||||
./office
|
./office
|
||||||
|
./plasma-manager-kodi
|
||||||
./sync
|
./sync
|
||||||
|
./tmux
|
||||||
|
./emacs
|
||||||
|
./starship
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,45 @@ in
|
|||||||
enable = true;
|
enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# rbw vault unlock on login and resume from suspend
|
||||||
|
systemd.user.services.rbw-unlock-on-login = {
|
||||||
|
Unit = {
|
||||||
|
Description = "Unlock rbw vault at login";
|
||||||
|
After = [ "graphical-session.target" ];
|
||||||
|
};
|
||||||
|
Service = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${pkgs.rbw}/bin/rbw unlock";
|
||||||
|
Environment = "RBW_AGENT=${pkgs.rbw}/bin/rbw-agent";
|
||||||
|
# KillMode = "process" prevents systemd from killing the rbw-agent daemon
|
||||||
|
# when this oneshot service completes. The agent is spawned by rbw unlock
|
||||||
|
# and needs to persist after the service exits.
|
||||||
|
KillMode = "process";
|
||||||
|
};
|
||||||
|
Install = {
|
||||||
|
WantedBy = [ "graphical-session.target" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.user.services.rbw-unlock-on-resume = {
|
||||||
|
Unit = {
|
||||||
|
Description = "Unlock rbw vault after resume from suspend";
|
||||||
|
After = [ "suspend.target" ];
|
||||||
|
};
|
||||||
|
Service = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${pkgs.rbw}/bin/rbw unlock";
|
||||||
|
Environment = "RBW_AGENT=${pkgs.rbw}/bin/rbw-agent";
|
||||||
|
# KillMode = "process" prevents systemd from killing the rbw-agent daemon
|
||||||
|
# when this oneshot service completes. The agent is spawned by rbw unlock
|
||||||
|
# and needs to persist after the service exits.
|
||||||
|
KillMode = "process";
|
||||||
|
};
|
||||||
|
Install = {
|
||||||
|
WantedBy = [ "suspend.target" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
# KDE environment variables for proper integration
|
# KDE environment variables for proper integration
|
||||||
home.sessionVariables = {
|
home.sessionVariables = {
|
||||||
QT_QPA_PLATFORMTHEME = "kde";
|
QT_QPA_PLATFORMTHEME = "kde";
|
||||||
|
|||||||
@@ -4,22 +4,117 @@ with lib;
|
|||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.home.roles.development;
|
cfg = config.home.roles.development;
|
||||||
|
|
||||||
|
# Fetch the claude-plugins repository (for humanlayer commands/agents)
|
||||||
|
# Update the rev to get newer versions of the commands
|
||||||
|
claudePluginsRepo = builtins.fetchGit {
|
||||||
|
url = "https://github.com/jeffh/claude-plugins.git";
|
||||||
|
# To update: change this to the latest commit hash
|
||||||
|
# You can find the latest commit at: https://github.com/jeffh/claude-plugins/commits/main
|
||||||
|
rev = "5e3e4d937162185b6d78c62022cbfd1c8ad42c4c";
|
||||||
|
ref = "main";
|
||||||
|
};
|
||||||
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.home.roles.development = {
|
options.home.roles.development = {
|
||||||
enable = mkEnableOption "Enable development tools and utilities";
|
enable = mkEnableOption "Enable development tools and utilities";
|
||||||
|
|
||||||
|
allowArbitraryClaudeCodeModelSelection = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Whether to preserve model specifications in Claude Code humanlayer commands and agents.
|
||||||
|
|
||||||
|
When false (default), the model: line is stripped from frontmatter, allowing Claude Code
|
||||||
|
to use its default model selection.
|
||||||
|
|
||||||
|
When true, the model: specifications from the source files are preserved, allowing
|
||||||
|
commands to specify opus/sonnet/haiku explicitly.
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
home.packages = [
|
home.packages = [
|
||||||
|
globalInputs.beads.packages.${system}.default
|
||||||
pkgs.unstable.claude-code
|
pkgs.unstable.claude-code
|
||||||
pkgs.codex
|
pkgs.unstable.claude-code-router
|
||||||
|
pkgs.unstable.codex
|
||||||
|
|
||||||
# Custom packages
|
# Custom packages
|
||||||
pkgs.custom.tea-rbw
|
pkgs.custom.tea-rbw
|
||||||
|
pkgs.custom.perles
|
||||||
];
|
];
|
||||||
|
|
||||||
programs.kubectl-secure.enable = true;
|
# Install Claude Code humanlayer command and agent plugins
|
||||||
|
home.activation.claudeCodeCommands = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
||||||
|
# Clean up old plugin-installed commands and agents to avoid duplicates
|
||||||
|
rm -f ~/.claude/commands/humanlayer:* 2>/dev/null || true
|
||||||
|
rm -f ~/.claude/agents/humanlayer:* 2>/dev/null || true
|
||||||
|
|
||||||
|
# Create directories if they don't exist
|
||||||
|
mkdir -p ~/.claude/commands
|
||||||
|
mkdir -p ~/.claude/agents
|
||||||
|
|
||||||
|
# Copy all humanlayer command files and remove model specifications
|
||||||
|
for file in ${claudePluginsRepo}/humanlayer/commands/*.md; do
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
filename=$(basename "$file" .md)
|
||||||
|
dest="$HOME/.claude/commands/humanlayer:''${filename}.md"
|
||||||
|
|
||||||
|
# Copy file and conditionally remove the "model:" line from frontmatter
|
||||||
|
${if cfg.allowArbitraryClaudeCodeModelSelection
|
||||||
|
then "cp \"$file\" \"$dest\""
|
||||||
|
else "${pkgs.gnused}/bin/sed '/^model:/d' \"$file\" > \"$dest\""
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Copy all humanlayer agent files and remove model specifications
|
||||||
|
for file in ${claudePluginsRepo}/humanlayer/agents/*.md; do
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
filename=$(basename "$file" .md)
|
||||||
|
dest="$HOME/.claude/agents/humanlayer:''${filename}.md"
|
||||||
|
|
||||||
|
# Copy file and conditionally remove the "model:" line from frontmatter
|
||||||
|
${if cfg.allowArbitraryClaudeCodeModelSelection
|
||||||
|
then "cp \"$file\" \"$dest\""
|
||||||
|
else "${pkgs.gnused}/bin/sed '/^model:/d' \"$file\" > \"$dest\""
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Copy local skills from this repo (with retry for race conditions with running Claude)
|
||||||
|
for file in ${./skills}/*.md; do
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
filename=$(basename "$file" .md)
|
||||||
|
dest="$HOME/.claude/commands/''${filename}.md"
|
||||||
|
# Remove existing file first, then copy with retry on failure
|
||||||
|
rm -f "$dest" 2>/dev/null || true
|
||||||
|
if ! cp "$file" "$dest" 2>/dev/null; then
|
||||||
|
sleep 0.5
|
||||||
|
cp "$file" "$dest" || echo "Warning: Failed to copy $filename.md to commands"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
$DRY_RUN_CMD echo "Claude Code humanlayer commands and agents installed successfully${
|
||||||
|
if cfg.allowArbitraryClaudeCodeModelSelection
|
||||||
|
then " (model specifications preserved)"
|
||||||
|
else " (model selection removed)"
|
||||||
|
} + local skills"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Set up beads Claude Code integration (hooks for SessionStart/PreCompact)
|
||||||
|
# This uses the CLI + hooks approach which is recommended over MCP for Claude Code
|
||||||
|
home.activation.claudeCodeBeadsSetup = lib.hm.dag.entryAfter ["writeBoundary" "claudeCodeCommands"] ''
|
||||||
|
# Run bd setup claude to install hooks into ~/.claude/settings.json
|
||||||
|
# This is idempotent - safe to run multiple times
|
||||||
|
${globalInputs.beads.packages.${system}.default}/bin/bd setup claude 2>/dev/null || true
|
||||||
|
|
||||||
|
$DRY_RUN_CMD echo "Claude Code beads integration configured (hooks installed)"
|
||||||
|
'';
|
||||||
|
|
||||||
# Note: modules must be imported at top-level home config
|
# Note: modules must be imported at top-level home config
|
||||||
};
|
};
|
||||||
|
|||||||
244
home/roles/development/skills/gitea_pr_review.md
Normal file
244
home/roles/development/skills/gitea_pr_review.md
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
---
|
||||||
|
description: Manage and respond to Gitea/Forgejo PR review comments
|
||||||
|
---
|
||||||
|
|
||||||
|
# Gitea PR Review Comments
|
||||||
|
|
||||||
|
This skill enables reading PR review comments and posting inline thread replies on Gitea/Forgejo instances.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- `tea` CLI configured with a Gitea/Forgejo instance
|
||||||
|
- Access token from tea config: `~/.config/tea/config.yml`
|
||||||
|
- Repository must be a Gitea/Forgejo remote (not GitHub)
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Get the Gitea instance URL and token from tea config:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Get the default login URL and token
|
||||||
|
yq -r '.logins[] | select(.name == "default") | .url' ~/.config/tea/config.yml
|
||||||
|
yq -r '.logins[] | select(.name == "default") | .token' ~/.config/tea/config.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Or if you have a specific login name:
|
||||||
|
```bash
|
||||||
|
yq -r '.logins[] | select(.name == "YOUR_LOGIN") | .url' ~/.config/tea/config.yml
|
||||||
|
yq -r '.logins[] | select(.name == "YOUR_LOGIN") | .token' ~/.config/tea/config.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
### 1. List PR Review Comments
|
||||||
|
|
||||||
|
Fetch all reviews and their comments for a PR:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Set environment variables
|
||||||
|
GITEA_URL="https://git.johnogle.info"
|
||||||
|
TOKEN="<your-token>"
|
||||||
|
OWNER="<repo-owner>"
|
||||||
|
REPO="<repo-name>"
|
||||||
|
PR_NUMBER="<pr-number>"
|
||||||
|
|
||||||
|
# Get all reviews for the PR
|
||||||
|
curl -s -H "Authorization: token $TOKEN" \
|
||||||
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews" | jq
|
||||||
|
|
||||||
|
# Get comments for a specific review
|
||||||
|
REVIEW_ID="<review-id>"
|
||||||
|
curl -s -H "Authorization: token $TOKEN" \
|
||||||
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews/$REVIEW_ID/comments" | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. View All Review Comments (Combined)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Get all reviews and their comments in one view
|
||||||
|
curl -s -H "Authorization: token $TOKEN" \
|
||||||
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews" | \
|
||||||
|
jq -r '.[] | "Review \(.id) by \(.user.login): \(.state)\n Body: \(.body)"'
|
||||||
|
|
||||||
|
# For each review, show inline comments
|
||||||
|
for REVIEW_ID in $(curl -s -H "Authorization: token $TOKEN" \
|
||||||
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews" | jq -r '.[].id'); do
|
||||||
|
echo "=== Review $REVIEW_ID comments ==="
|
||||||
|
curl -s -H "Authorization: token $TOKEN" \
|
||||||
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews/$REVIEW_ID/comments" | \
|
||||||
|
jq -r '.[] | "[\(.path):\(.line)] \(.body)"'
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Reply to Review Comments (Web Endpoint Method)
|
||||||
|
|
||||||
|
The Gitea REST API does not support replying to review comment threads. The web UI uses a different endpoint:
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /{owner}/{repo}/pulls/{pr_number}/files/reviews/comments
|
||||||
|
Content-Type: multipart/form-data
|
||||||
|
```
|
||||||
|
|
||||||
|
**Required form fields:**
|
||||||
|
- `reply`: Review ID to reply to
|
||||||
|
- `content`: The reply message
|
||||||
|
- `path`: File path
|
||||||
|
- `line`: Line number
|
||||||
|
- `side`: `proposed` or `original`
|
||||||
|
- `single_review`: `true`
|
||||||
|
- `origin`: `timeline`
|
||||||
|
- `_csrf`: CSRF token (required for web endpoint)
|
||||||
|
|
||||||
|
**Authentication Challenge:**
|
||||||
|
This endpoint requires session-based authentication, not API tokens. Options:
|
||||||
|
|
||||||
|
#### Option A: Use Browser Session (Recommended)
|
||||||
|
|
||||||
|
1. Log in to Gitea in your browser
|
||||||
|
2. Open browser developer tools and copy cookies
|
||||||
|
3. Use the session cookies with curl
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# First, get CSRF token from the PR page
|
||||||
|
CSRF=$(curl -s -c cookies.txt -b cookies.txt \
|
||||||
|
"$GITEA_URL/$OWNER/$REPO/pulls/$PR_NUMBER/files" | \
|
||||||
|
grep -oP 'name="_csrf" value="\K[^"]+')
|
||||||
|
|
||||||
|
# Post the reply
|
||||||
|
curl -s -b cookies.txt \
|
||||||
|
-F "reply=$REVIEW_ID" \
|
||||||
|
-F "content=Your reply message here" \
|
||||||
|
-F "path=$FILE_PATH" \
|
||||||
|
-F "line=$LINE_NUMBER" \
|
||||||
|
-F "side=proposed" \
|
||||||
|
-F "single_review=true" \
|
||||||
|
-F "origin=timeline" \
|
||||||
|
-F "_csrf=$CSRF" \
|
||||||
|
"$GITEA_URL/$OWNER/$REPO/pulls/$PR_NUMBER/files/reviews/comments"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Option B: Create Top-Level Comment (Fallback)
|
||||||
|
|
||||||
|
If thread replies are not critical, use the API to create a top-level comment:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create a top-level comment mentioning the review context
|
||||||
|
curl -s -X POST \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"body\": \"Re: @reviewer's comment on $FILE_PATH:$LINE_NUMBER\n\nYour reply here\"}" \
|
||||||
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/issues/$PR_NUMBER/comments"
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use tea CLI:
|
||||||
|
```bash
|
||||||
|
tea comment $PR_NUMBER "Re: @reviewer's comment on $FILE_PATH:$LINE_NUMBER
|
||||||
|
|
||||||
|
Your reply here"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Submit a New Review
|
||||||
|
|
||||||
|
Create a new review with inline comments:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -X POST \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"body": "Overall review comments",
|
||||||
|
"event": "COMMENT",
|
||||||
|
"comments": [
|
||||||
|
{
|
||||||
|
"path": "path/to/file.py",
|
||||||
|
"body": "Comment on this line",
|
||||||
|
"new_position": 10
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}' \
|
||||||
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews"
|
||||||
|
```
|
||||||
|
|
||||||
|
Event types: `COMMENT`, `APPROVE`, `REQUEST_CHANGES`
|
||||||
|
|
||||||
|
## Workflow Example
|
||||||
|
|
||||||
|
### Reading and Responding to Reviews
|
||||||
|
|
||||||
|
1. **Set up environment**:
|
||||||
|
```bash
|
||||||
|
export GITEA_URL=$(yq -r '.logins[] | select(.name == "default") | .url' ~/.config/tea/config.yml)
|
||||||
|
export TOKEN=$(yq -r '.logins[] | select(.name == "default") | .token' ~/.config/tea/config.yml)
|
||||||
|
export OWNER="johno"
|
||||||
|
export REPO="nixos-configs"
|
||||||
|
export PR_NUMBER="5"
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **List all pending review comments**:
|
||||||
|
```bash
|
||||||
|
# Get reviews
|
||||||
|
curl -s -H "Authorization: token $TOKEN" \
|
||||||
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews" | \
|
||||||
|
jq -r '.[] | select(.state == "REQUEST_CHANGES" or .state == "COMMENT") |
|
||||||
|
"Review \(.id) by \(.user.login) (\(.state)):\n\(.body)\n"'
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Get detailed comments for a review**:
|
||||||
|
```bash
|
||||||
|
REVIEW_ID="2"
|
||||||
|
curl -s -H "Authorization: token $TOKEN" \
|
||||||
|
"$GITEA_URL/api/v1/repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews/$REVIEW_ID/comments" | \
|
||||||
|
jq -r '.[] | "File: \(.path):\(.line)\nComment: \(.body)\nID: \(.id)\n---"'
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Respond using top-level comment** (most reliable):
|
||||||
|
```bash
|
||||||
|
tea comment $PR_NUMBER "Addressing review feedback:
|
||||||
|
|
||||||
|
- File \`path/to/file.py\` line 10: Fixed the issue by...
|
||||||
|
- File \`other/file.py\` line 25: Updated as suggested..."
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Reference
|
||||||
|
|
||||||
|
### Endpoints
|
||||||
|
|
||||||
|
| Action | Method | Endpoint |
|
||||||
|
|--------|--------|----------|
|
||||||
|
| List reviews | GET | `/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews` |
|
||||||
|
| Get review | GET | `/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}` |
|
||||||
|
| Get review comments | GET | `/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments` |
|
||||||
|
| Create review | POST | `/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews` |
|
||||||
|
| Submit review | POST | `/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}` |
|
||||||
|
| Delete review | DELETE | `/api/v1/repos/{owner}/{repo}/pulls/{index}/reviews/{id}` |
|
||||||
|
| Create issue comment | POST | `/api/v1/repos/{owner}/{repo}/issues/{index}/comments` |
|
||||||
|
|
||||||
|
### Review States
|
||||||
|
|
||||||
|
- `PENDING` - Draft review not yet submitted
|
||||||
|
- `COMMENT` - General comment without approval/rejection
|
||||||
|
- `APPROVE` - Approving the changes
|
||||||
|
- `REQUEST_CHANGES` - Requesting changes before merge
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
1. **Thread replies**: The Gitea REST API does not support replying directly to review comment threads. This is a known limitation. Workarounds:
|
||||||
|
- Use top-level comments with context
|
||||||
|
- Use the web UI manually for thread replies
|
||||||
|
- Implement session-based authentication to use the web endpoint
|
||||||
|
|
||||||
|
2. **CSRF tokens**: The web endpoint for thread replies requires CSRF tokens, which expire and need to be fetched from the page.
|
||||||
|
|
||||||
|
3. **Session auth**: API tokens work for REST API but not for web endpoints that require session cookies.
|
||||||
|
|
||||||
|
## Tips
|
||||||
|
|
||||||
|
- Always quote file paths and line numbers when responding via top-level comments
|
||||||
|
- Use `tea pr view $PR_NUMBER --comments` to see all comments
|
||||||
|
- Use `tea open pulls/$PR_NUMBER` to open the PR in browser for manual thread replies
|
||||||
|
- Consider using `tea pr approve $PR_NUMBER` after addressing all comments
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- Gitea API Documentation: https://docs.gitea.com/api/1.20/
|
||||||
|
- `tea` CLI: https://gitea.com/gitea/tea
|
||||||
205
home/roles/development/skills/parallel_beads.md
Normal file
205
home/roles/development/skills/parallel_beads.md
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
---
|
||||||
|
description: Orchestrate parallel bead processing with worktrees, PRs, and reviews
|
||||||
|
---
|
||||||
|
|
||||||
|
# Parallel Beads Workflow
|
||||||
|
|
||||||
|
This skill orchestrates parallel bead processing using subagents. Each bead gets its own worktree, implementation, PR, and review.
|
||||||
|
|
||||||
|
## Phase 1: Selection
|
||||||
|
|
||||||
|
1. **Get ready beads**: Run `bd ready` to list all beads with no blockers
|
||||||
|
2. **Present selection**: Use `AskUserQuestion` with `multiSelect: true` to let the user choose which beads to work on
|
||||||
|
- Include bead ID and title for each option
|
||||||
|
- Allow selection of multiple beads
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
AskUserQuestion with:
|
||||||
|
- question: "Which beads do you want to work on in parallel?"
|
||||||
|
- multiSelect: true
|
||||||
|
- options from bd ready output
|
||||||
|
```
|
||||||
|
|
||||||
|
## Phase 2: Parallel Implementation
|
||||||
|
|
||||||
|
For each selected bead, launch a subagent using the Task tool. All subagents should be launched in parallel (single message with multiple Task tool calls).
|
||||||
|
|
||||||
|
### Subagent Instructions Template
|
||||||
|
|
||||||
|
Each implementation subagent should receive these instructions:
|
||||||
|
|
||||||
|
```
|
||||||
|
Work on bead [BEAD_ID]: [BEAD_TITLE]
|
||||||
|
|
||||||
|
1. **Create worktree**:
|
||||||
|
- Branch name: `bead/[BEAD_ID]`
|
||||||
|
- Worktree path: `~/wt/[REPO_NAME]/[BEAD_ID]`
|
||||||
|
- Command: `git worktree add -b bead/[BEAD_ID] ~/wt/[REPO_NAME]/[BEAD_ID]`
|
||||||
|
|
||||||
|
2. **Review the bead requirements**:
|
||||||
|
- Run `bd show [BEAD_ID]` to understand the acceptance criteria
|
||||||
|
- Note any external issue references (GitHub issues, Linear tickets, etc.)
|
||||||
|
|
||||||
|
3. **Implement the changes**:
|
||||||
|
- Work in the worktree directory
|
||||||
|
- Complete all acceptance criteria listed in the bead
|
||||||
|
- Run any relevant tests or checks
|
||||||
|
|
||||||
|
4. **Commit and push**:
|
||||||
|
- Stage all changes: `git add -A`
|
||||||
|
- Create a descriptive commit message
|
||||||
|
- Push the branch: `git push -u origin bead/[BEAD_ID]`
|
||||||
|
|
||||||
|
5. **Create a PR**:
|
||||||
|
- Detect hosting provider from origin URL: `git remote get-url origin`
|
||||||
|
- If URL contains `github.com`, use `gh`; otherwise use `tea` (Gitea/Forgejo)
|
||||||
|
- PR title: "[BEAD_ID] [BEAD_TITLE]"
|
||||||
|
- PR body must include:
|
||||||
|
- Reference to bead ID: "Implements bead: [BEAD_ID]"
|
||||||
|
- Any external issue references from the bead (e.g., "Closes #123")
|
||||||
|
- Summary of changes
|
||||||
|
- For GitHub (`gh`):
|
||||||
|
```bash
|
||||||
|
gh pr create --title "[BEAD_ID] [BEAD_TITLE]" --body "$(cat <<'EOF'
|
||||||
|
## Summary
|
||||||
|
[Brief description of changes]
|
||||||
|
|
||||||
|
## Bead Reference
|
||||||
|
Implements bead: [BEAD_ID]
|
||||||
|
|
||||||
|
## External Issues
|
||||||
|
[Any linked issues from the bead]
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
- [List of changes made]
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
```
|
||||||
|
- For Gitea (`tea`):
|
||||||
|
```bash
|
||||||
|
tea pr create --head bead/[BEAD_ID] --base main \
|
||||||
|
--title "[BEAD_ID] [BEAD_TITLE]" \
|
||||||
|
--description "## Summary
|
||||||
|
[Brief description of changes]
|
||||||
|
|
||||||
|
## Bead Reference
|
||||||
|
Implements bead: [BEAD_ID]
|
||||||
|
|
||||||
|
## External Issues
|
||||||
|
[Any linked issues from the bead]
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
- [List of changes made]"
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **Update bead status**:
|
||||||
|
- Mark the bead as "in_review": `bd update [BEAD_ID] --status=in_review`
|
||||||
|
- Add the PR URL to the bead notes: `bd update [BEAD_ID] --notes="$(bd show [BEAD_ID] --json | jq -r '.notes')
|
||||||
|
|
||||||
|
PR: [PR_URL]"`
|
||||||
|
|
||||||
|
7. **Report results**:
|
||||||
|
- Return: PR URL, bead ID, success/failure status
|
||||||
|
- If blocked or unable to complete, explain what's blocking progress
|
||||||
|
```
|
||||||
|
|
||||||
|
### Launching Subagents
|
||||||
|
|
||||||
|
Use `subagent_type: "general-purpose"` for implementation subagents. Launch all selected beads' subagents in a single message for parallel execution:
|
||||||
|
|
||||||
|
```
|
||||||
|
<Task calls for each selected bead - all in one message>
|
||||||
|
```
|
||||||
|
|
||||||
|
Collect results from all subagents before proceeding.
|
||||||
|
|
||||||
|
## Phase 3: Parallel Review
|
||||||
|
|
||||||
|
After all implementation subagents complete, launch review subagents for each PR.
|
||||||
|
|
||||||
|
### Review Subagent Instructions Template
|
||||||
|
|
||||||
|
```
|
||||||
|
Review PR for bead [BEAD_ID]
|
||||||
|
|
||||||
|
1. **Detect hosting provider**: Run `git remote get-url origin` - if it contains `github.com` use `gh`, otherwise use `tea`
|
||||||
|
|
||||||
|
2. **Read the PR**:
|
||||||
|
- For GitHub: `gh pr view [PR_NUMBER] --json title,body,additions,deletions,files`
|
||||||
|
- For Gitea: `tea pr view [PR_NUMBER]`
|
||||||
|
- View the diff: `git diff main...bead/[BEAD_ID]`
|
||||||
|
|
||||||
|
3. **Review against acceptance criteria**:
|
||||||
|
- Run `bd show [BEAD_ID]` to get the acceptance criteria
|
||||||
|
- Verify each criterion is addressed
|
||||||
|
|
||||||
|
4. **Leave review comments**:
|
||||||
|
- For GitHub: `gh pr review [PR_NUMBER] --comment --body "[COMMENTS]"`
|
||||||
|
- For Gitea: `tea pr review [PR_NUMBER] --comment "[COMMENTS]"`
|
||||||
|
- Include:
|
||||||
|
- Acceptance criteria checklist (which are met, which might be missing)
|
||||||
|
- Code quality observations
|
||||||
|
- Suggestions for improvement
|
||||||
|
|
||||||
|
5. **Return summary**:
|
||||||
|
- Overall assessment (ready to merge / needs changes)
|
||||||
|
- Key findings
|
||||||
|
```
|
||||||
|
|
||||||
|
Launch all review subagents in parallel.
|
||||||
|
|
||||||
|
## Phase 4: Cleanup and Summary
|
||||||
|
|
||||||
|
After reviews complete:
|
||||||
|
|
||||||
|
1. **Clean up worktrees**:
|
||||||
|
```bash
|
||||||
|
git worktree remove ~/wt/[REPO_NAME]/[BEAD_ID] --force
|
||||||
|
```
|
||||||
|
Do this for each bead's worktree.
|
||||||
|
|
||||||
|
2. **Provide final summary**:
|
||||||
|
Present a table or list with:
|
||||||
|
- Bead ID
|
||||||
|
- PR URL
|
||||||
|
- Status (success / failed / blocked)
|
||||||
|
- Review summary
|
||||||
|
- Any failures or blockers encountered
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
```
|
||||||
|
## Parallel Beads Summary
|
||||||
|
|
||||||
|
| Bead | PR | Bead Status | Review |
|
||||||
|
|------|-----|-------------|--------|
|
||||||
|
| beads-abc | #123 | in_review | Approved |
|
||||||
|
| beads-xyz | #124 | in_review | Needs changes |
|
||||||
|
| beads-123 | - | open (failed) | Blocked by missing dependency |
|
||||||
|
|
||||||
|
### Failures/Blockers
|
||||||
|
- beads-123: Could not complete because [reason]
|
||||||
|
|
||||||
|
### Next Steps
|
||||||
|
- Review PRs that need changes
|
||||||
|
- Address blockers for failed beads
|
||||||
|
- Run `/reconcile_beads` after PRs are merged to close beads
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
- **Subagent failures**: If a subagent fails or times out, note it in the summary but continue with other beads
|
||||||
|
- **PR creation failures**: Report the error but continue with reviews of successful PRs
|
||||||
|
- **Worktree conflicts**: If a worktree already exists, ask the user if they want to remove it or skip that bead
|
||||||
|
|
||||||
|
## Resource Limits
|
||||||
|
|
||||||
|
- Consider limiting concurrent subagents to 3-5 to avoid overwhelming system resources
|
||||||
|
- If user selects more beads than the limit, process them in batches
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- This workflow integrates with the beads system (`bd` commands)
|
||||||
|
- Worktrees are created in `~/wt/[REPO_NAME]/` by convention
|
||||||
|
- Each bead gets its own isolated branch and worktree
|
||||||
|
- PRs automatically reference the bead ID for traceability
|
||||||
88
home/roles/development/skills/reconcile_beads.md
Normal file
88
home/roles/development/skills/reconcile_beads.md
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
---
|
||||||
|
description: Reconcile beads with merged PRs and close completed beads
|
||||||
|
---
|
||||||
|
|
||||||
|
# Reconcile Beads Workflow
|
||||||
|
|
||||||
|
This skill reconciles beads that are in `in_review` status with their corresponding PRs. If a PR has been merged, the bead is closed.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Custom status `in_review` must be configured: `bd config set status.custom "in_review"`
|
||||||
|
- Beads in `in_review` status should have a PR URL in their notes
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
### Step 1: Find beads in review
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bd list --status=in_review
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: For each bead, check PR status
|
||||||
|
|
||||||
|
1. **Get the PR URL from bead notes**:
|
||||||
|
```bash
|
||||||
|
bd show [BEAD_ID] --json | jq -r '.[0].notes'
|
||||||
|
```
|
||||||
|
Note: `bd show --json` returns an array, so use `.[0]` to access the first element.
|
||||||
|
Extract the PR URL (look for lines starting with "PR:" or containing pull request URLs).
|
||||||
|
Extract the PR number: `echo "$NOTES" | grep -oP '/pulls/\K\d+'`
|
||||||
|
|
||||||
|
2. **Detect hosting provider**:
|
||||||
|
- Run `git remote get-url origin`
|
||||||
|
- If URL contains `github.com`, use `gh`; otherwise use `tea` (Gitea/Forgejo)
|
||||||
|
|
||||||
|
3. **Check PR status**:
|
||||||
|
- For GitHub:
|
||||||
|
```bash
|
||||||
|
gh pr view [PR_NUMBER] --json state,merged
|
||||||
|
```
|
||||||
|
- For Gitea:
|
||||||
|
```bash
|
||||||
|
tea pr list --state=closed
|
||||||
|
```
|
||||||
|
Look for the PR number in the INDEX column with STATE "merged".
|
||||||
|
Note: `tea pr view [PR_NUMBER]` lists all PRs, not a specific one. Use `tea pr list --state=closed` and look for your PR number in the results.
|
||||||
|
|
||||||
|
### Step 3: Close merged beads
|
||||||
|
|
||||||
|
If the PR is merged:
|
||||||
|
```bash
|
||||||
|
bd close [BEAD_ID] --reason="PR merged: [PR_URL]"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Report summary
|
||||||
|
|
||||||
|
Present results:
|
||||||
|
|
||||||
|
```
|
||||||
|
## Beads Reconciliation Summary
|
||||||
|
|
||||||
|
### Closed (PR Merged)
|
||||||
|
| Bead | PR | Title |
|
||||||
|
|------|-----|-------|
|
||||||
|
| beads-abc | #123 | Feature X |
|
||||||
|
| beads-xyz | #456 | Bug fix Y |
|
||||||
|
|
||||||
|
### Still in Review
|
||||||
|
| Bead | PR | Status | Title |
|
||||||
|
|------|-----|--------|-------|
|
||||||
|
| beads-def | #789 | Open | Feature Z |
|
||||||
|
|
||||||
|
### Issues Found
|
||||||
|
- beads-ghi: No PR URL found in notes
|
||||||
|
- beads-jkl: PR #999 not found (may have been deleted)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
- **Missing PR URL**: Skip the bead and report it
|
||||||
|
- **PR not found**: Report the error but continue with other beads
|
||||||
|
- **API errors**: Report and continue
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- This skill complements `/parallel_beads` which sets beads to `in_review` status
|
||||||
|
- Run this skill periodically or after merging PRs to keep beads in sync
|
||||||
|
- Beads with closed (but not merged) PRs are not automatically closed - they may need rework
|
||||||
112
home/roles/emacs/default.nix
Normal file
112
home/roles/emacs/default.nix
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.home.roles.emacs;
|
||||||
|
|
||||||
|
doomEmacs = pkgs.fetchFromGitHub {
|
||||||
|
owner = "doomemacs";
|
||||||
|
repo = "doomemacs";
|
||||||
|
rev = "38d94da67dc84897a4318714dcc48494c016d8c4";
|
||||||
|
sha256 = "sha256-Uc6qONH3jjUVDgW+pPBCGC7mh88ZY05u1y37fQrsxq0=";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Shared emacs packages
|
||||||
|
emacsPackages = epkgs: [
|
||||||
|
epkgs.vterm
|
||||||
|
epkgs.treesit-grammars.with-all-grammars
|
||||||
|
];
|
||||||
|
|
||||||
|
# Default emacs configuration with vterm support
|
||||||
|
defaultEmacsPackage =
|
||||||
|
if pkgs.stdenv.isDarwin
|
||||||
|
then pkgs.emacs-macport.pkgs.withPackages emacsPackages
|
||||||
|
else pkgs.emacs.pkgs.withPackages emacsPackages;
|
||||||
|
|
||||||
|
# Path to doom config directory (relative to this file)
|
||||||
|
doomConfigDir = ./doom;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.home.roles.emacs = {
|
||||||
|
enable = mkEnableOption "Doom Emacs with vterm and tree-sitter support";
|
||||||
|
|
||||||
|
prebuiltDoom = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Use nix-doom-emacs-unstraightened to pre-build all Doom packages at
|
||||||
|
nix build time. This eliminates the need to run `doom sync` after
|
||||||
|
first boot, making it ideal for live USB images or immutable systems.
|
||||||
|
|
||||||
|
When enabled, the doom configuration is read-only (stored in nix store).
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable (mkMerge [
|
||||||
|
# Common configuration for both modes
|
||||||
|
{
|
||||||
|
home.packages = [
|
||||||
|
pkgs.emacs-all-the-icons-fonts
|
||||||
|
pkgs.fira-code
|
||||||
|
pkgs.fontconfig
|
||||||
|
pkgs.graphviz
|
||||||
|
pkgs.isort
|
||||||
|
pkgs.nerd-fonts.fira-code
|
||||||
|
pkgs.nerd-fonts.droid-sans-mono
|
||||||
|
pkgs.nil # nix lsp language server
|
||||||
|
pkgs.nixfmt-rfc-style
|
||||||
|
(pkgs.ripgrep.override {withPCRE2 = true;})
|
||||||
|
pkgs.pipenv
|
||||||
|
pkgs.poetry
|
||||||
|
pkgs.python3
|
||||||
|
];
|
||||||
|
|
||||||
|
fonts.fontconfig.enable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Standard Doom Emacs mode (requires doom sync at runtime)
|
||||||
|
(mkIf (!cfg.prebuiltDoom) {
|
||||||
|
programs.emacs = {
|
||||||
|
enable = true;
|
||||||
|
package = defaultEmacsPackage;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Mount emacs and tree-sitter grammars from nix store
|
||||||
|
home.file = {
|
||||||
|
"${config.xdg.configHome}/emacs".source = doomEmacs;
|
||||||
|
};
|
||||||
|
|
||||||
|
home.sessionPath = [
|
||||||
|
"${config.xdg.configHome}/emacs/bin"
|
||||||
|
];
|
||||||
|
|
||||||
|
home.sessionVariables = {
|
||||||
|
DOOMDIR = "${config.xdg.configHome}/doom";
|
||||||
|
DOOMLOCALDIR = "${config.xdg.dataHome}/doom";
|
||||||
|
};
|
||||||
|
|
||||||
|
# TODO: Use mkOutOfStoreSymlink instead?
|
||||||
|
home.activation.doomConfig = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
||||||
|
# Always remove and recreate the symlink to ensure it points to the source directory
|
||||||
|
rm -rf "${config.xdg.configHome}/doom"
|
||||||
|
ln -sf "${config.home.homeDirectory}/nixos-configs/home/roles/emacs/doom" "${config.xdg.configHome}/doom"
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
|
||||||
|
# Pre-built Doom Emacs mode (no doom sync needed - ideal for live USB)
|
||||||
|
(mkIf cfg.prebuiltDoom {
|
||||||
|
programs.doom-emacs = {
|
||||||
|
enable = true;
|
||||||
|
doomDir = doomConfigDir;
|
||||||
|
doomLocalDir = "${config.xdg.dataHome}/doom";
|
||||||
|
# Add extra packages that aren't part of Doom but needed for our config
|
||||||
|
extraPackages = epkgs: [
|
||||||
|
epkgs.vterm
|
||||||
|
epkgs.treesit-grammars.with-all-grammars
|
||||||
|
];
|
||||||
|
};
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
}
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
;; up, `M-x eval-region' to execute elisp code, and 'M-x doom/reload-font' to
|
;; up, `M-x eval-region' to execute elisp code, and 'M-x doom/reload-font' to
|
||||||
;; refresh your font settings. If Emacs still can't find your font, it likely
|
;; refresh your font settings. If Emacs still can't find your font, it likely
|
||||||
;; wasn't installed correctly. Font issues are rarely Doom issues!
|
;; wasn't installed correctly. Font issues are rarely Doom issues!
|
||||||
(setq doom-font (font-spec :family "Fira Code"))
|
(setq doom-font (font-spec :family "Fira Code" :size 16))
|
||||||
|
|
||||||
;; Auto-install nerd-icons fonts if they're missing
|
;; Auto-install nerd-icons fonts if they're missing
|
||||||
(defun my/ensure-nerd-icons-fonts ()
|
(defun my/ensure-nerd-icons-fonts ()
|
||||||
@@ -71,7 +71,10 @@
|
|||||||
org-journal-file-format "%Y-%m-%d.org"
|
org-journal-file-format "%Y-%m-%d.org"
|
||||||
org-capture-templates
|
org-capture-templates
|
||||||
'(("t" "Todo" entry (file+headline "~/org/todo.org" "Inbox")
|
'(("t" "Todo" entry (file+headline "~/org/todo.org" "Inbox")
|
||||||
"* TODO %? \n %i \n%a" :prepend t))))
|
"* TODO %? \n %i \n%a" :prepend t)))
|
||||||
|
;; Make blocked tasks more visible in agenda (they have subtasks to do!)
|
||||||
|
(custom-set-faces!
|
||||||
|
'(org-agenda-dimmed-todo-face :foreground "#bb9af7" :weight normal)))
|
||||||
|
|
||||||
(map! :after org-agenda
|
(map! :after org-agenda
|
||||||
:map org-agenda-mode-map
|
:map org-agenda-mode-map
|
||||||
@@ -145,12 +148,24 @@
|
|||||||
:args (list '(:name "dirpath" :type "string" :description "Directory path to list"))))
|
:args (list '(:name "dirpath" :type "string" :description "Directory path to list"))))
|
||||||
|
|
||||||
(use-package! claude-code-ide
|
(use-package! claude-code-ide
|
||||||
:defer t
|
:commands (claude-code-ide-menu claude-code-ide-open-here)
|
||||||
:config
|
:init
|
||||||
(claude-code-ide-emacs-tools-setup)
|
|
||||||
(map! :leader
|
(map! :leader
|
||||||
(:prefix ("o" . "open")
|
(:prefix ("o" . "open")
|
||||||
:desc "Claude Code IDE" "c" #'claude-code-ide-menu)))
|
:desc "Claude Code IDE" "c" #'claude-code-ide-menu))
|
||||||
|
:config
|
||||||
|
(claude-code-ide-emacs-tools-setup)
|
||||||
|
(setq claude-code-ide-cli-path "claude"
|
||||||
|
claude-code-ide-cli-extra-flags "--dangerously-skip-permissions"
|
||||||
|
claude-code-ide-focus-claude-after-ediff t
|
||||||
|
claude-code-ide-focus-on-open t
|
||||||
|
claude-code-ide-show-claude-window-in-ediff t
|
||||||
|
claude-code-ide-switch-tab-on-ediff t
|
||||||
|
claude-code-ide-use-ide-diff t
|
||||||
|
claude-code-ide-use-side-window t
|
||||||
|
claude-code-ide-window-height 20
|
||||||
|
claude-code-ide-window-side 'right
|
||||||
|
claude-code-ide-window-width 90))
|
||||||
|
|
||||||
(after! gptel
|
(after! gptel
|
||||||
(require 'gptel-tool-library)
|
(require 'gptel-tool-library)
|
||||||
@@ -159,6 +174,49 @@
|
|||||||
(dolist (module '("bbdb" "buffer" "elisp" "emacs" "gnus" "os" "search-and-replace" "url"))
|
(dolist (module '("bbdb" "buffer" "elisp" "emacs" "gnus" "os" "search-and-replace" "url"))
|
||||||
(gptel-tool-library-load-module module)))
|
(gptel-tool-library-load-module module)))
|
||||||
|
|
||||||
|
;; mu4e email configuration
|
||||||
|
;; Add NixOS mu4e to load-path (installed via mu.mu4e package)
|
||||||
|
(when-let ((mu-path (executable-find "mu")))
|
||||||
|
(add-to-list 'load-path
|
||||||
|
(expand-file-name "../share/emacs/site-lisp/mu4e"
|
||||||
|
(file-name-directory mu-path))))
|
||||||
|
|
||||||
|
(after! mu4e
|
||||||
|
;; User identity
|
||||||
|
(setq user-mail-address "john@ogle.fyi"
|
||||||
|
user-full-name "John Ogle")
|
||||||
|
|
||||||
|
;; Maildir location (no account prefix - single account)
|
||||||
|
(setq mu4e-maildir "~/Mail"
|
||||||
|
mu4e-attachment-dir "~/Downloads")
|
||||||
|
|
||||||
|
;; Folder config (matches ~/Mail/INBOX, ~/Mail/Sent, etc.)
|
||||||
|
(setq mu4e-sent-folder "/Sent"
|
||||||
|
mu4e-drafts-folder "/Drafts"
|
||||||
|
mu4e-trash-folder "/Trash"
|
||||||
|
mu4e-refile-folder "/Archive")
|
||||||
|
|
||||||
|
;; Shortcuts for common folders
|
||||||
|
(setq mu4e-maildir-shortcuts
|
||||||
|
'((:maildir "/INBOX" :key ?i)
|
||||||
|
(:maildir "/Archive" :key ?a)
|
||||||
|
(:maildir "/Sent" :key ?s)
|
||||||
|
(:maildir "/Trash" :key ?t)))
|
||||||
|
|
||||||
|
;; Behavior settings
|
||||||
|
(setq mu4e-get-mail-command "mbsync -a"
|
||||||
|
mu4e-update-interval 300 ; 5 minutes (matches systemd timer)
|
||||||
|
mu4e-change-filenames-when-moving t ; required for mbsync
|
||||||
|
mu4e-headers-date-format "%Y-%m-%d"
|
||||||
|
mu4e-headers-time-format "%H:%M")
|
||||||
|
|
||||||
|
;; Sending mail via msmtp
|
||||||
|
(setq message-send-mail-function 'message-send-mail-with-sendmail
|
||||||
|
sendmail-program (executable-find "msmtp")
|
||||||
|
message-sendmail-envelope-from 'header
|
||||||
|
mail-envelope-from 'header
|
||||||
|
mail-specify-envelope-from t))
|
||||||
|
|
||||||
;; Whenever you reconfigure a package, make sure to wrap your config in an
|
;; Whenever you reconfigure a package, make sure to wrap your config in an
|
||||||
;; `after!' block, otherwise Doom's defaults may override your settings. E.g.
|
;; `after!' block, otherwise Doom's defaults may override your settings. E.g.
|
||||||
;;
|
;;
|
||||||
@@ -176,7 +176,7 @@
|
|||||||
;;zig ; C, but simpler
|
;;zig ; C, but simpler
|
||||||
|
|
||||||
:email
|
:email
|
||||||
;;(mu4e +org +gmail)
|
(mu4e +org)
|
||||||
;;notmuch
|
;;notmuch
|
||||||
;;(wanderlust +gmail)
|
;;(wanderlust +gmail)
|
||||||
|
|
||||||
@@ -51,11 +51,21 @@
|
|||||||
|
|
||||||
;; (package! org-caldav)
|
;; (package! org-caldav)
|
||||||
|
|
||||||
|
;; Note: Packages with custom recipes must be pinned for nix-doom-emacs-unstraightened
|
||||||
|
;; to build deterministically. Update pins when upgrading packages.
|
||||||
|
|
||||||
(package! gptel :recipe (:nonrecursive t))
|
(package! gptel :recipe (:nonrecursive t))
|
||||||
|
|
||||||
(package! claude-code-ide
|
(package! claude-code-ide
|
||||||
:recipe (:host github :repo "manzaltu/claude-code-ide.el"))
|
:recipe (:host github :repo "manzaltu/claude-code-ide.el")
|
||||||
|
:pin "760240d7f03ff16f90ede9d4f4243cd94f3fed73")
|
||||||
|
|
||||||
(package! gptel-tool-library
|
(package! gptel-tool-library
|
||||||
:recipe (:host github :repo "aard-fi/gptel-tool-library"
|
:recipe (:host github :repo "aard-fi/gptel-tool-library"
|
||||||
:files ("*.el")))
|
:files ("*.el"))
|
||||||
|
:pin "baffc3b0d74a2b7cbda0d5cd6dd7726d6ccaca83")
|
||||||
|
|
||||||
|
(package! beads
|
||||||
|
:recipe (:type git :repo "https://codeberg.org/ctietze/beads.el.git"
|
||||||
|
:files ("lisp/*.el"))
|
||||||
|
:pin "f40a6461d3c0fa0969311bbb6a1e30d1bba86c88")
|
||||||
123
home/roles/email/default.nix
Normal file
123
home/roles/email/default.nix
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.home.roles.email;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.home.roles.email = {
|
||||||
|
enable = mkEnableOption "Enable email with mu4e, mbsync, and msmtp";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
isync # provides mbsync for IMAP sync
|
||||||
|
msmtp # for SMTP sending
|
||||||
|
mu # email indexer for mu4e
|
||||||
|
mu.mu4e # mu4e elisp files for Emacs
|
||||||
|
openssl # for certificate management
|
||||||
|
];
|
||||||
|
|
||||||
|
# Ensure Mail directory exists
|
||||||
|
home.file."Mail/.keep".text = "";
|
||||||
|
|
||||||
|
# mbsync configuration
|
||||||
|
home.file.".mbsyncrc".text = ''
|
||||||
|
# IMAP Account Configuration
|
||||||
|
IMAPAccount proton
|
||||||
|
Host proton.johnogle.info
|
||||||
|
Port 143
|
||||||
|
User john@ogle.fyi
|
||||||
|
PassCmd "${pkgs.rbw}/bin/rbw get proton.johnogle.info"
|
||||||
|
TLSType STARTTLS
|
||||||
|
AuthMechs PLAIN
|
||||||
|
|
||||||
|
# Remote Storage
|
||||||
|
IMAPStore proton-remote
|
||||||
|
Account proton
|
||||||
|
|
||||||
|
# Local Storage
|
||||||
|
MaildirStore proton-local
|
||||||
|
Path ~/Mail/
|
||||||
|
Inbox ~/Mail/INBOX
|
||||||
|
SubFolders Verbatim
|
||||||
|
|
||||||
|
# Channel Configuration - Main (excludes Sent)
|
||||||
|
Channel proton-main
|
||||||
|
Far :proton-remote:
|
||||||
|
Near :proton-local:
|
||||||
|
Patterns * !Sent
|
||||||
|
Create Both
|
||||||
|
Expunge Both
|
||||||
|
SyncState *
|
||||||
|
|
||||||
|
# Channel Configuration - Sent (pull only)
|
||||||
|
Channel proton-sent
|
||||||
|
Far :proton-remote:Sent
|
||||||
|
Near :proton-local:Sent
|
||||||
|
Create Near
|
||||||
|
Expunge Near
|
||||||
|
Sync Pull
|
||||||
|
SyncState *
|
||||||
|
|
||||||
|
# Group both channels
|
||||||
|
Group proton
|
||||||
|
Channel proton-main
|
||||||
|
Channel proton-sent
|
||||||
|
'';
|
||||||
|
|
||||||
|
# msmtp configuration
|
||||||
|
home.file.".msmtprc".text = ''
|
||||||
|
# Default settings
|
||||||
|
defaults
|
||||||
|
auth plain
|
||||||
|
tls on
|
||||||
|
tls_starttls on
|
||||||
|
tls_trust_file /etc/ssl/certs/ca-certificates.crt
|
||||||
|
logfile ${config.home.homeDirectory}/.msmtp.log
|
||||||
|
|
||||||
|
# Proton mail account
|
||||||
|
account proton
|
||||||
|
host proton.johnogle.info
|
||||||
|
port 25
|
||||||
|
from john@ogle.fyi
|
||||||
|
user john@ogle.fyi
|
||||||
|
passwordeval rbw get proton.johnogle.info
|
||||||
|
|
||||||
|
# Set default account
|
||||||
|
account default : proton
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Systemd service for mail sync
|
||||||
|
systemd.user.services.mbsync = {
|
||||||
|
Unit = {
|
||||||
|
Description = "Mailbox synchronization service";
|
||||||
|
After = [ "network-online.target" ];
|
||||||
|
Wants = [ "network-online.target" ];
|
||||||
|
};
|
||||||
|
Service = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${pkgs.bash}/bin/bash -c 'mkdir -p ~/Mail && ${pkgs.isync}/bin/mbsync -a && (${pkgs.mu}/bin/mu info >/dev/null 2>&1 || ${pkgs.mu}/bin/mu init --maildir ~/Mail --personal-address=john@ogle.fyi) && ${pkgs.mu}/bin/mu index'";
|
||||||
|
Environment = "PATH=${pkgs.rbw}/bin:${pkgs.coreutils}/bin";
|
||||||
|
StandardOutput = "journal";
|
||||||
|
StandardError = "journal";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Systemd timer for automatic sync
|
||||||
|
systemd.user.timers.mbsync = {
|
||||||
|
Unit = {
|
||||||
|
Description = "Mailbox synchronization timer";
|
||||||
|
};
|
||||||
|
Timer = {
|
||||||
|
OnBootSec = "2min";
|
||||||
|
OnUnitActiveSec = "5min";
|
||||||
|
Unit = "mbsync.service";
|
||||||
|
};
|
||||||
|
Install = {
|
||||||
|
WantedBy = [ "timers.target" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -3,7 +3,9 @@
|
|||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.home.i3_sway;
|
cfg = config.home.roles.i3_sway;
|
||||||
|
wallpaperConfig = import ../../wallpapers;
|
||||||
|
currentWallpaper = builtins.elemAt wallpaperConfig.wallpapers wallpaperConfig.currentIndex;
|
||||||
|
|
||||||
shared_config = recursiveUpdate rec {
|
shared_config = recursiveUpdate rec {
|
||||||
modifier = "Mod4";
|
modifier = "Mod4";
|
||||||
@@ -12,8 +14,12 @@ let
|
|||||||
|
|
||||||
keybindings = {
|
keybindings = {
|
||||||
"${shared_config.modifier}+Return" = "exec ${terminal}";
|
"${shared_config.modifier}+Return" = "exec ${terminal}";
|
||||||
|
"${shared_config.modifier}+Shift+Return" = "exec ${cfg.browser}";
|
||||||
"${shared_config.modifier}+Shift+q" = "kill";
|
"${shared_config.modifier}+Shift+q" = "kill";
|
||||||
|
|
||||||
|
"${shared_config.modifier}+a" = "focus parent";
|
||||||
|
"${shared_config.modifier}+Shift+a" = "focus child";
|
||||||
|
|
||||||
"${shared_config.modifier}+h" = "focus left";
|
"${shared_config.modifier}+h" = "focus left";
|
||||||
"${shared_config.modifier}+j" = "focus down";
|
"${shared_config.modifier}+j" = "focus down";
|
||||||
"${shared_config.modifier}+k" = "focus up";
|
"${shared_config.modifier}+k" = "focus up";
|
||||||
@@ -45,8 +51,6 @@ let
|
|||||||
"${shared_config.modifier}+Shift+space" = "floating toggle";
|
"${shared_config.modifier}+Shift+space" = "floating toggle";
|
||||||
"${shared_config.modifier}+space" = "focus mode_toggle";
|
"${shared_config.modifier}+space" = "focus mode_toggle";
|
||||||
|
|
||||||
"${shared_config.modifier}+a" = "focus parent";
|
|
||||||
|
|
||||||
"${shared_config.modifier}+Shift+minus" = "move scratchpad";
|
"${shared_config.modifier}+Shift+minus" = "move scratchpad";
|
||||||
"${shared_config.modifier}+minus" = "scratchpad show";
|
"${shared_config.modifier}+minus" = "scratchpad show";
|
||||||
|
|
||||||
@@ -92,19 +96,35 @@ let
|
|||||||
};
|
};
|
||||||
} cfg.extraSharedConfig;
|
} cfg.extraSharedConfig;
|
||||||
in {
|
in {
|
||||||
options.home.i3_sway = {
|
options.home.roles.i3_sway = {
|
||||||
|
enable = mkEnableOption "i3 and Sway tiling window managers with waybar and rofi";
|
||||||
|
|
||||||
|
browser = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "firefox --new-window";
|
||||||
|
description = "Browser to use for new window keybinding";
|
||||||
|
};
|
||||||
|
|
||||||
extraSharedConfig = mkOption {
|
extraSharedConfig = mkOption {
|
||||||
|
type = types.attrs;
|
||||||
default = {};
|
default = {};
|
||||||
|
description = "Extra configuration shared between i3 and sway";
|
||||||
};
|
};
|
||||||
|
|
||||||
extraI3Config = mkOption {
|
extraI3Config = mkOption {
|
||||||
|
type = types.attrs;
|
||||||
default = {};
|
default = {};
|
||||||
|
description = "Extra i3-specific configuration";
|
||||||
};
|
};
|
||||||
|
|
||||||
extraSwayConfig = mkOption {
|
extraSwayConfig = mkOption {
|
||||||
|
type = types.attrs;
|
||||||
default = {};
|
default = {};
|
||||||
|
description = "Extra sway-specific configuration";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = mkIf cfg.enable {
|
||||||
# i3blocks configuration file
|
# i3blocks configuration file
|
||||||
home.file.".config/i3blocks/config".text = ''
|
home.file.".config/i3blocks/config".text = ''
|
||||||
# i3blocks config - replicating waybar setup
|
# i3blocks config - replicating waybar setup
|
||||||
@@ -270,7 +290,7 @@ in {
|
|||||||
}
|
}
|
||||||
# Set wallpaper with feh
|
# Set wallpaper with feh
|
||||||
{
|
{
|
||||||
command = "feh --bg-scale ${../../wallpapers/metroid-samus-returns-kz-3440x1440.jpg}";
|
command = "feh ${currentWallpaper.feh} ${currentWallpaper.file}";
|
||||||
always = false;
|
always = false;
|
||||||
notification = false;
|
notification = false;
|
||||||
}
|
}
|
||||||
@@ -303,7 +323,7 @@ in {
|
|||||||
};
|
};
|
||||||
output = {
|
output = {
|
||||||
"*" = {
|
"*" = {
|
||||||
bg = "${../../wallpapers/metroid-samus-returns-kz-3440x1440.jpg} fill";
|
bg = "${currentWallpaper.file} ${currentWallpaper.sway}";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
startup = [
|
startup = [
|
||||||
@@ -316,6 +336,7 @@ in {
|
|||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
extraOptions = [ "--unsupported-gpu" ];
|
||||||
config = recursiveUpdate base_sway_config cfg.extraSwayConfig;
|
config = recursiveUpdate base_sway_config cfg.extraSwayConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -331,7 +352,7 @@ in {
|
|||||||
|
|
||||||
modules-left = [ "sway/workspaces" "sway/mode" ];
|
modules-left = [ "sway/workspaces" "sway/mode" ];
|
||||||
modules-center = [ ];
|
modules-center = [ ];
|
||||||
modules-right = [ "disk" "cpu" "memory" "pulseaudio" "backlight" "network" "battery" "tray" "clock" ];
|
modules-right = [ "disk" "cpu" "memory" "pulseaudio" "custom/backlight-ddc" "backlight" "network" "battery" "tray" "clock" ];
|
||||||
|
|
||||||
"sway/workspaces" = {
|
"sway/workspaces" = {
|
||||||
disable-scroll = true;
|
disable-scroll = true;
|
||||||
@@ -388,6 +409,23 @@ in {
|
|||||||
tooltip = false;
|
tooltip = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"custom/backlight-ddc" = {
|
||||||
|
exec = pkgs.writeShellScript "waybar-backlight-ddc" ''
|
||||||
|
if command -v ddcutil &>/dev/null; then
|
||||||
|
# Display current brightness
|
||||||
|
brightness=$(ddcutil getvcp 10 --brief 2>/dev/null | awk '{print $4}')
|
||||||
|
if [ -n "$brightness" ]; then
|
||||||
|
echo "☀️ $brightness%"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
interval = 5;
|
||||||
|
format = "{}";
|
||||||
|
on-scroll-up = "ddcutil setvcp 10 + 5 2>/dev/null &";
|
||||||
|
on-scroll-down = "ddcutil setvcp 10 - 5 2>/dev/null &";
|
||||||
|
tooltip = false;
|
||||||
|
};
|
||||||
|
|
||||||
"network" = {
|
"network" = {
|
||||||
format-wifi = "📶 {essid} ({signalStrength}%)";
|
format-wifi = "📶 {essid} ({signalStrength}%)";
|
||||||
format-ethernet = "🔌 {ipaddr}";
|
format-ethernet = "🔌 {ipaddr}";
|
||||||
@@ -419,7 +457,7 @@ in {
|
|||||||
|
|
||||||
#workspaces button {
|
#workspaces button {
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
background-color: transparent;
|
background-color: #333333;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, globalInputs, system, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.programs.kubectl-secure;
|
cfg = config.home.roles.kubectl;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.programs.kubectl-secure = {
|
options.home.roles.kubectl = {
|
||||||
enable = mkEnableOption "secure kubectl configuration with Bitwarden integration";
|
enable = mkEnableOption "management tools for the homelab k3s oglenet cluster with secure Bitwarden integration";
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
@@ -172,12 +172,6 @@ in
|
|||||||
|
|
||||||
echo "✓ Loaded kubectl context: $context (session: $$)"
|
echo "✓ Loaded kubectl context: $context (session: $$)"
|
||||||
echo " Config location: $KUBECONFIG"
|
echo " Config location: $KUBECONFIG"
|
||||||
|
|
||||||
# Optional: Set timeout cleanup
|
|
||||||
if [[ ${toString cfg.sessionTimeout} -gt 0 ]]; then
|
|
||||||
(sleep ${toString cfg.sessionTimeout}; kube-clear 2>/dev/null) &
|
|
||||||
export KUBECTL_TIMEOUT_PID=$!
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kube-list() {
|
kube-list() {
|
||||||
36
home/roles/launchers/default.nix
Normal file
36
home/roles/launchers/default.nix
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.home.roles.launchers;
|
||||||
|
|
||||||
|
# Generate a wrapper script for a package
|
||||||
|
makeLauncher = packageName: pkgs.writeShellScriptBin packageName ''
|
||||||
|
exec env NIXPKGS_ALLOW_UNFREE=1 ${pkgs.nix}/bin/nix run --impure nixpkgs#${packageName} -- "$@"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Generate all launcher scripts from the package list
|
||||||
|
launcherPackages = map makeLauncher cfg.packages;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.home.roles.launchers = {
|
||||||
|
enable = mkEnableOption "wrapper launchers for excluded packages";
|
||||||
|
|
||||||
|
packages = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [];
|
||||||
|
example = [ "steam" "libreoffice" "lutris" ];
|
||||||
|
description = ''
|
||||||
|
List of package names to create launcher wrappers for.
|
||||||
|
Each wrapper will run: NIXPKGS_ALLOW_UNFREE=1 nix run --impure nixpkgs#<package>
|
||||||
|
|
||||||
|
This is useful for occasionally running packages without permanently installing them.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
home.packages = launcherPackages;
|
||||||
|
};
|
||||||
|
}
|
||||||
199
home/roles/plasma-manager-kodi/default.nix
Normal file
199
home/roles/plasma-manager-kodi/default.nix
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.home.roles.plasma-manager-kodi;
|
||||||
|
|
||||||
|
# Define the volume control scripts as derivations
|
||||||
|
volumeUpScript = pkgs.writeShellScript "avr-volume-up" ''
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
HA_URL="https://home-assistant.johnogle.info"
|
||||||
|
ENTITY_ID="media_player.denon_avr_s970h_2"
|
||||||
|
MAX_RETRIES=3
|
||||||
|
|
||||||
|
# Read token from KDE Wallet and strip whitespace
|
||||||
|
TOKEN=$(${pkgs.kdePackages.kwallet}/bin/kwallet-query -r ha_avr_token kdewallet -f Passwords 2>/dev/null | tr -d '[:space:]')
|
||||||
|
|
||||||
|
if [ -z "$TOKEN" ]; then
|
||||||
|
${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to retrieve Home Assistant token from KDE Wallet"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Send volume up command with retry logic
|
||||||
|
for i in $(seq 1 $MAX_RETRIES); do
|
||||||
|
RESPONSE=$(${pkgs.curl}/bin/curl -s -w "\n%{http_code}" -X POST \
|
||||||
|
-H "Authorization: Bearer $TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"entity_id\": \"$ENTITY_ID\"}" \
|
||||||
|
"$HA_URL/api/services/media_player/volume_up" 2>&1)
|
||||||
|
|
||||||
|
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
||||||
|
|
||||||
|
if [ "$HTTP_CODE" = "200" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Wait before retry (except on last attempt)
|
||||||
|
if [ $i -lt $MAX_RETRIES ]; then
|
||||||
|
sleep 0.5
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# All retries failed
|
||||||
|
${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to increase volume after $MAX_RETRIES attempts"
|
||||||
|
exit 1
|
||||||
|
'';
|
||||||
|
|
||||||
|
volumeDownScript = pkgs.writeShellScript "avr-volume-down" ''
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
HA_URL="https://home-assistant.johnogle.info"
|
||||||
|
ENTITY_ID="media_player.denon_avr_s970h_2"
|
||||||
|
MAX_RETRIES=3
|
||||||
|
|
||||||
|
# Read token from KDE Wallet and strip whitespace
|
||||||
|
TOKEN=$(${pkgs.kdePackages.kwallet}/bin/kwallet-query -r ha_avr_token kdewallet -f Passwords 2>/dev/null | tr -d '[:space:]')
|
||||||
|
|
||||||
|
if [ -z "$TOKEN" ]; then
|
||||||
|
${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to retrieve Home Assistant token from KDE Wallet"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Send volume down command with retry logic
|
||||||
|
for i in $(seq 1 $MAX_RETRIES); do
|
||||||
|
RESPONSE=$(${pkgs.curl}/bin/curl -s -w "\n%{http_code}" -X POST \
|
||||||
|
-H "Authorization: Bearer $TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"entity_id\": \"$ENTITY_ID\"}" \
|
||||||
|
"$HA_URL/api/services/media_player/volume_down" 2>&1)
|
||||||
|
|
||||||
|
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
||||||
|
|
||||||
|
if [ "$HTTP_CODE" = "200" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Wait before retry (except on last attempt)
|
||||||
|
if [ $i -lt $MAX_RETRIES ]; then
|
||||||
|
sleep 0.5
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# All retries failed
|
||||||
|
${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to decrease volume after $MAX_RETRIES attempts"
|
||||||
|
exit 1
|
||||||
|
'';
|
||||||
|
|
||||||
|
volumeMuteScript = pkgs.writeShellScript "avr-volume-mute" ''
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
HA_URL="https://home-assistant.johnogle.info"
|
||||||
|
ENTITY_ID="media_player.denon_avr_s970h_2"
|
||||||
|
MAX_RETRIES=3
|
||||||
|
|
||||||
|
# Read token from KDE Wallet and strip whitespace
|
||||||
|
TOKEN=$(${pkgs.kdePackages.kwallet}/bin/kwallet-query -r ha_avr_token kdewallet -f Passwords 2>/dev/null | tr -d '[:space:]')
|
||||||
|
|
||||||
|
if [ -z "$TOKEN" ]; then
|
||||||
|
${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to retrieve Home Assistant token from KDE Wallet"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get current mute state
|
||||||
|
STATE_RESPONSE=$(${pkgs.curl}/bin/curl -s -H "Authorization: Bearer $TOKEN" \
|
||||||
|
"$HA_URL/api/states/$ENTITY_ID")
|
||||||
|
|
||||||
|
CURRENT_MUTE=$(echo "$STATE_RESPONSE" | ${pkgs.jq}/bin/jq -r '.attributes.is_volume_muted // false')
|
||||||
|
|
||||||
|
# Toggle: if currently muted (true), unmute (false), and vice versa
|
||||||
|
if [ "$CURRENT_MUTE" = "true" ]; then
|
||||||
|
NEW_MUTE="false"
|
||||||
|
NOTIFY_MSG="Unmuted"
|
||||||
|
else
|
||||||
|
NEW_MUTE="true"
|
||||||
|
NOTIFY_MSG="Muted"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Send mute toggle command with retry logic
|
||||||
|
for i in $(seq 1 $MAX_RETRIES); do
|
||||||
|
RESPONSE=$(${pkgs.curl}/bin/curl -s -w "\n%{http_code}" -X POST \
|
||||||
|
-H "Authorization: Bearer $TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"entity_id\": \"$ENTITY_ID\", \"is_volume_muted\": $NEW_MUTE}" \
|
||||||
|
"$HA_URL/api/services/media_player/volume_mute" 2>&1)
|
||||||
|
|
||||||
|
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
||||||
|
|
||||||
|
if [ "$HTTP_CODE" = "200" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Wait before retry (except on last attempt)
|
||||||
|
if [ $i -lt $MAX_RETRIES ]; then
|
||||||
|
sleep 0.5
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# All retries failed
|
||||||
|
${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to toggle mute after $MAX_RETRIES attempts"
|
||||||
|
exit 1
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.home.roles.plasma-manager-kodi = {
|
||||||
|
enable = mkEnableOption "KDE Plasma volume control for kodi user via Home Assistant";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
programs.plasma = {
|
||||||
|
enable = true;
|
||||||
|
overrideConfig = true;
|
||||||
|
|
||||||
|
# Disable default kmix volume shortcuts to prevent conflicts
|
||||||
|
shortcuts.kmix = {
|
||||||
|
"increase_volume" = "none";
|
||||||
|
"decrease_volume" = "none";
|
||||||
|
"mute" = "none";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Define custom volume control commands with key bindings
|
||||||
|
hotkeys.commands = {
|
||||||
|
"volume-up-avr" = {
|
||||||
|
name = "Volume Up AVR";
|
||||||
|
key = "Volume Up";
|
||||||
|
command = toString volumeUpScript;
|
||||||
|
};
|
||||||
|
|
||||||
|
"volume-down-avr" = {
|
||||||
|
name = "Volume Down AVR";
|
||||||
|
key = "Volume Down";
|
||||||
|
command = toString volumeDownScript;
|
||||||
|
};
|
||||||
|
|
||||||
|
"volume-mute-avr" = {
|
||||||
|
name = "Mute Toggle AVR";
|
||||||
|
key = "Volume Mute";
|
||||||
|
command = toString volumeMuteScript;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# KDE Settings customization
|
||||||
|
configFile = {
|
||||||
|
# Session restore settings
|
||||||
|
"ksmserverrc"."General"."loginMode" = "emptySession";
|
||||||
|
|
||||||
|
# Screen locking settings
|
||||||
|
"kscreenlockerrc"."Daemon"."Autolock" = false;
|
||||||
|
"kscreenlockerrc"."Daemon"."LockOnResume" = false;
|
||||||
|
|
||||||
|
# Theme settings
|
||||||
|
"kdeglobals"."KDE"."LookAndFeelPackage" = "org.kde.breezedark.desktop";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
190
home/roles/plasma-manager/default.nix
Normal file
190
home/roles/plasma-manager/default.nix
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.home.roles.plasma-manager;
|
||||||
|
wallpaperConfig = import ../../wallpapers;
|
||||||
|
currentWallpaper = builtins.elemAt wallpaperConfig.wallpapers wallpaperConfig.currentIndex;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.home.roles.plasma-manager = {
|
||||||
|
enable = mkEnableOption "KDE Plasma desktop environment configuration";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
# The current KDE config can be output with the command:
|
||||||
|
# nix run github:nix-community/plasma-manager
|
||||||
|
#
|
||||||
|
# Plasma-manager options documentation
|
||||||
|
# https://nix-community.github.io/plasma-manager/options.xhtml
|
||||||
|
#
|
||||||
|
# TODO: (ambitious) Add Kmail support to plasma-manager
|
||||||
|
programs.plasma = {
|
||||||
|
enable = true;
|
||||||
|
overrideConfig = true;
|
||||||
|
|
||||||
|
hotkeys.commands."launch-ghostty" = {
|
||||||
|
name = "Launch Ghostty";
|
||||||
|
key = "Meta+Return";
|
||||||
|
command = "ghostty";
|
||||||
|
};
|
||||||
|
|
||||||
|
shortcuts = {
|
||||||
|
kmix = {
|
||||||
|
"decrease_microphone_volume" = "Microphone Volume Down";
|
||||||
|
"decrease_volume" = "Volume Down";
|
||||||
|
"decrease_volume_small" = "Shift+Volume Down";
|
||||||
|
"increase_microphone_volume" = "Microphone Volume Up";
|
||||||
|
"increase_volume" = "Volume Up";
|
||||||
|
"increase_volume_small" = "Shift+Volume Up";
|
||||||
|
"mic_mute" = ["Microphone Mute" "Meta+Volume Mute,Microphone Mute" "Meta+Volume Mute,Mute Microphone"];
|
||||||
|
"mute" = "Volume Mute";
|
||||||
|
};
|
||||||
|
|
||||||
|
mediacontrol = {
|
||||||
|
"mediavolumedown" = "none,,Media volume down";
|
||||||
|
"mediavolumeup" = "none,,Media volume up";
|
||||||
|
"nextmedia" = "Media Next";
|
||||||
|
"pausemedia" = "Media Pause";
|
||||||
|
"playmedia" = "none,,Play media playback";
|
||||||
|
"playpausemedia" = "Media Play";
|
||||||
|
"previousmedia" = "Media Previous";
|
||||||
|
"stopmedia" = "Media Stop";
|
||||||
|
};
|
||||||
|
|
||||||
|
ksmserver = {
|
||||||
|
"Lock Session" = ["Meta+Ctrl+Q" "Screensaver" "Screensaver,Lock Session"];
|
||||||
|
};
|
||||||
|
|
||||||
|
kwin = {
|
||||||
|
"Window Close" = "Meta+Shift+Q";
|
||||||
|
"Kill Window" = "Meta+Ctrl+Esc";
|
||||||
|
"Window Operations Menu" = "Alt+F3";
|
||||||
|
"Window Resize" = "Meta+R,,Resize Window";
|
||||||
|
|
||||||
|
"Overview" = "Meta+Ctrl+W";
|
||||||
|
"Grid View" = "Meta+G";
|
||||||
|
"Edit Tiles" = "Meta+T";
|
||||||
|
|
||||||
|
"Activate Window Demanding Attention" = "Meta+Ctrl+A";
|
||||||
|
|
||||||
|
"Show Desktop" = "Meta+Ctrl+D";
|
||||||
|
|
||||||
|
"Walk Through Windows" = "Alt+Tab";
|
||||||
|
"Walk Through Windows (Reverse)" = "Alt+Shift+Tab";
|
||||||
|
"Walk Through Windows of Current Application" = "Alt+`";
|
||||||
|
"Walk Through Windows of Current Application (Reverse)" = "Alt+~";
|
||||||
|
|
||||||
|
"Window Quick Tile Bottom" = "Meta+Down";
|
||||||
|
"Window Quick Tile Left" = "Meta+Left";
|
||||||
|
"Window Quick Tile Right" = "Meta+Right";
|
||||||
|
"Window Quick Tile Top" = "Meta+Up";
|
||||||
|
|
||||||
|
"Switch to Desktop 1" = "Meta+1";
|
||||||
|
"Switch to Desktop 2" = "Meta+2";
|
||||||
|
"Switch to Desktop 3" = "Meta+3";
|
||||||
|
"Switch to Desktop 4" = "Meta+4";
|
||||||
|
"Switch to Desktop 5" = "Meta+5";
|
||||||
|
"Switch to Desktop 6" = "Meta+6";
|
||||||
|
"Switch to Desktop 7" = "Meta+7";
|
||||||
|
"Switch to Desktop 8" = "Meta+8";
|
||||||
|
"Switch to Desktop 9" = "Meta+9";
|
||||||
|
"Switch to Desktop 10" = "Meta+0";
|
||||||
|
|
||||||
|
"Window to Desktop 1" = "Meta+!"; # Meta+Shift+1
|
||||||
|
"Window to Desktop 2" = "Meta+@"; # Meta+Shift+2
|
||||||
|
"Window to Desktop 3" = "Meta+#"; # Meta+Shift+3
|
||||||
|
"Window to Desktop 4" = "Meta+$"; # Meta+Shift+4
|
||||||
|
"Window to Desktop 5" = "Meta+%"; # Meta+Shift+5
|
||||||
|
"Window to Desktop 6" = "Meta+^"; # Meta+Shift+6
|
||||||
|
"Window to Desktop 7" = "Meta+&"; # Meta+Shift+7
|
||||||
|
"Window to Desktop 8" = "Meta+*"; # Meta+Shift+8
|
||||||
|
"Window to Desktop 9" = "Meta+("; # Meta+Shift+9
|
||||||
|
"Window to Desktop 10" = "Meta+)"; # Meta+Shift+0
|
||||||
|
|
||||||
|
"view_actual_size" = "Meta+Ctrl+=";
|
||||||
|
"view_zoom_in" = ["Meta++" "Meta+=,Meta++" "Meta+=,Zoom In"];
|
||||||
|
"view_zoom_out" = "Meta+-";
|
||||||
|
};
|
||||||
|
"org_kde_powerdevil"."Decrease Keyboard Brightness" = "Keyboard Brightness Down";
|
||||||
|
"org_kde_powerdevil"."Decrease Screen Brightness" = "Monitor Brightness Down";
|
||||||
|
"org_kde_powerdevil"."Decrease Screen Brightness Small" = "Shift+Monitor Brightness Down";
|
||||||
|
"org_kde_powerdevil"."Hibernate" = "Hibernate";
|
||||||
|
"org_kde_powerdevil"."Increase Keyboard Brightness" = "Keyboard Brightness Up";
|
||||||
|
"org_kde_powerdevil"."Increase Screen Brightness" = "Monitor Brightness Up";
|
||||||
|
"org_kde_powerdevil"."Increase Screen Brightness Small" = "Shift+Monitor Brightness Up";
|
||||||
|
"org_kde_powerdevil"."PowerDown" = "Power Down";
|
||||||
|
"org_kde_powerdevil"."PowerOff" = "Power Off";
|
||||||
|
"org_kde_powerdevil"."Sleep" = "Sleep";
|
||||||
|
"org_kde_powerdevil"."Toggle Keyboard Backlight" = "Keyboard Light On/Off";
|
||||||
|
"org_kde_powerdevil"."Turn Off Screen" = [ ];
|
||||||
|
"org_kde_powerdevil"."powerProfile" = ["Battery" "Meta+B,Battery" "Meta+B,Switch Power Profile"];
|
||||||
|
|
||||||
|
plasmashell = {
|
||||||
|
"activate application launcher" = ["Meta" "Alt+F1,Meta" "Alt+F1,Activate Application Launcher"];
|
||||||
|
"activate task manager entry 1" = "none,,";
|
||||||
|
"activate task manager entry 2" = "none,,";
|
||||||
|
"activate task manager entry 3" = "none,,";
|
||||||
|
"activate task manager entry 4" = "none,,";
|
||||||
|
"activate task manager entry 5" = "none,,";
|
||||||
|
"activate task manager entry 6" = "none,,";
|
||||||
|
"activate task manager entry 7" = "none,,";
|
||||||
|
"activate task manager entry 8" = "none,,";
|
||||||
|
"activate task manager entry 9" = "none,,";
|
||||||
|
"activate task manager entry 10" = "none,,";
|
||||||
|
"show activity switcher" = "none,,";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
configFile = {
|
||||||
|
kwinrc.Desktops.Number = {
|
||||||
|
value = 10;
|
||||||
|
immutable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Enable KWin tiling features
|
||||||
|
kwinrc.Tiling = {
|
||||||
|
# Enable tiling functionality
|
||||||
|
"padding" = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Enable krohnkite plugin automatically
|
||||||
|
kwinrc.Plugins = {
|
||||||
|
krohnkiteEnabled = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
kwinrc.Effect-overview = {
|
||||||
|
# Configure overview effect for better tiling workflow
|
||||||
|
BorderActivate = 9; # Top-left corner activation
|
||||||
|
};
|
||||||
|
|
||||||
|
kcminputrc.Libinput = {
|
||||||
|
AccelerationProfile = "adaptive";
|
||||||
|
PointerAcceleration = 0.5;
|
||||||
|
};
|
||||||
|
|
||||||
|
kcminputrc.Mouse = {
|
||||||
|
X11LibInputXAccelProfileFlat = false;
|
||||||
|
XLbInptAccelProfileFlat = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
kdeglobals.KDE.LookAndFeelPackage = "org.kde.breezedark.desktop";
|
||||||
|
|
||||||
|
# Focus follows mouse configuration
|
||||||
|
kwinrc.Windows = {
|
||||||
|
FocusPolicy = "FocusFollowsMouse";
|
||||||
|
AutoRaise = true; # Set to true if you want windows to auto-raise on focus
|
||||||
|
AutoRaiseInterval = 750; # Delay in ms before auto-raise (if enabled)
|
||||||
|
DelayFocusInterval = 0; # Delay in ms before focus follows mouse
|
||||||
|
};
|
||||||
|
|
||||||
|
# Desktop wallpaper configuration
|
||||||
|
plasma-localerc.Formats.LANG = "en_US.UTF-8";
|
||||||
|
|
||||||
|
# Set wallpaper for all desktops
|
||||||
|
plasmarc.Wallpapers.usersWallpapers = "${currentWallpaper.file}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
72
home/roles/starship/default.nix
Normal file
72
home/roles/starship/default.nix
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.home.roles.starship;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.home.roles.starship = {
|
||||||
|
enable = mkEnableOption "starship cross-shell prompt";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
programs.starship = {
|
||||||
|
enable = true;
|
||||||
|
enableBashIntegration = true;
|
||||||
|
enableZshIntegration = true;
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
add_newline = true;
|
||||||
|
|
||||||
|
character = {
|
||||||
|
success_symbol = "[>](bold green)";
|
||||||
|
error_symbol = "[x](bold red)";
|
||||||
|
vimcmd_symbol = "[<](bold green)";
|
||||||
|
};
|
||||||
|
|
||||||
|
directory = {
|
||||||
|
truncation_length = 4;
|
||||||
|
truncate_to_repo = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
git_branch = {
|
||||||
|
symbol = "";
|
||||||
|
format = "[$symbol$branch(:$remote_branch)]($style) ";
|
||||||
|
};
|
||||||
|
|
||||||
|
git_status = {
|
||||||
|
format = "([$all_status$ahead_behind]($style) )";
|
||||||
|
};
|
||||||
|
|
||||||
|
nix_shell = {
|
||||||
|
symbol = "";
|
||||||
|
format = "[$symbol$state( \\($name\\))]($style) ";
|
||||||
|
};
|
||||||
|
|
||||||
|
cmd_duration = {
|
||||||
|
min_time = 2000;
|
||||||
|
format = "[$duration]($style) ";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Disable modules that are noisy or rarely needed
|
||||||
|
package.disabled = true;
|
||||||
|
nodejs.disabled = true;
|
||||||
|
python.disabled = true;
|
||||||
|
ruby.disabled = true;
|
||||||
|
java.disabled = true;
|
||||||
|
golang.disabled = true;
|
||||||
|
rust.disabled = true;
|
||||||
|
php.disabled = true;
|
||||||
|
lua.disabled = true;
|
||||||
|
perl.disabled = true;
|
||||||
|
terraform.disabled = true;
|
||||||
|
kubernetes.disabled = true;
|
||||||
|
docker_context.disabled = true;
|
||||||
|
aws.disabled = true;
|
||||||
|
gcloud.disabled = true;
|
||||||
|
azure.disabled = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
62
home/roles/tmux/default.nix
Normal file
62
home/roles/tmux/default.nix
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.home.roles.tmux;
|
||||||
|
|
||||||
|
tokyo-night = pkgs.tmuxPlugins.mkTmuxPlugin {
|
||||||
|
pluginName = "tokyo-night";
|
||||||
|
rtpFilePath = "tokyo-night.tmux";
|
||||||
|
version = "1.6.1";
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "janoamaral";
|
||||||
|
repo = "tokyo-night-tmux";
|
||||||
|
rev = "d610ced20d5f602a7995854931440e4a1e0ab780";
|
||||||
|
sha256 = "sha256-17vEgkL7C51p/l5gpT9dkOy0bY9n8l0/LV51mR1k+V8=";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.home.roles.tmux = {
|
||||||
|
enable = mkEnableOption "tmux terminal multiplexer with Tokyo Night theme";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
programs.tmux.enable = true;
|
||||||
|
programs.tmux.terminal = "tmux-direct";
|
||||||
|
programs.tmux.keyMode = "vi";
|
||||||
|
programs.tmux.escapeTime = 0;
|
||||||
|
programs.tmux.mouse = true;
|
||||||
|
programs.tmux.newSession = true;
|
||||||
|
programs.tmux.historyLimit = 50000;
|
||||||
|
programs.tmux.clock24 = true;
|
||||||
|
programs.tmux.baseIndex = 1;
|
||||||
|
programs.tmux.prefix = "M-\\\\";
|
||||||
|
|
||||||
|
programs.tmux.plugins = with pkgs; [
|
||||||
|
tmuxPlugins.cpu
|
||||||
|
tmuxPlugins.battery
|
||||||
|
tmuxPlugins.better-mouse-mode
|
||||||
|
tmuxPlugins.net-speed
|
||||||
|
tmuxPlugins.online-status
|
||||||
|
tmuxPlugins.pain-control
|
||||||
|
tmuxPlugins.tilish
|
||||||
|
tmuxPlugins.yank
|
||||||
|
|
||||||
|
{
|
||||||
|
plugin = tmuxPlugins.resurrect;
|
||||||
|
extraConfig = "set -g @resurrect-strategy-nvim 'session'";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
plugin = tmuxPlugins.continuum;
|
||||||
|
extraConfig = ''
|
||||||
|
set -g @continuum-restore 'on'
|
||||||
|
set -g @continuum-save-interval '15' # minutes
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
|
||||||
|
tokyo-night
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
45
home/wallpapers/default.nix
Normal file
45
home/wallpapers/default.nix
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# Wallpaper rotation system
|
||||||
|
# The currentIndex is incremented by `nix run .#rotate-wallpaper`
|
||||||
|
# and gets committed as part of `nix run .#upgrade`
|
||||||
|
{
|
||||||
|
currentIndex = 1; # Index into wallpapers list
|
||||||
|
|
||||||
|
wallpapers = [
|
||||||
|
{
|
||||||
|
name = "metroid-samus-returns";
|
||||||
|
file = ./metroid-samus-returns-kz-3440x1440.jpg;
|
||||||
|
sway = "fill";
|
||||||
|
feh = "--bg-fill";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "metroid3_map";
|
||||||
|
file = ./metroid3_map.gif;
|
||||||
|
sway = "fit";
|
||||||
|
feh = "--bg-max";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "super-metroid-gunship-cavern";
|
||||||
|
file = ./super-metroid-gunship-cavern.jpg;
|
||||||
|
sway = "fit";
|
||||||
|
feh = "--bg-max";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "super-metroid-samus-statue";
|
||||||
|
file = ./super-metroid-samus-statue.png;
|
||||||
|
sway = "fit";
|
||||||
|
feh = "--bg-max";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "metroid-samus-action-4k";
|
||||||
|
file = ./metroid-samus-action-4k.jpg;
|
||||||
|
sway = "fit";
|
||||||
|
feh = "--bg-max";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "metroid-creature-minimalist";
|
||||||
|
file = ./metroid-creature-minimalist.jpg;
|
||||||
|
sway = "fit";
|
||||||
|
feh = "--bg-max";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
BIN
home/wallpapers/metroid-creature-minimalist.jpg
Normal file
BIN
home/wallpapers/metroid-creature-minimalist.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
BIN
home/wallpapers/metroid-samus-action-4k.jpg
Normal file
BIN
home/wallpapers/metroid-samus-action-4k.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.2 MiB |
BIN
home/wallpapers/metroid3_map.gif
Normal file
BIN
home/wallpapers/metroid3_map.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 132 KiB |
BIN
home/wallpapers/super-metroid-gunship-cavern.jpg
Normal file
BIN
home/wallpapers/super-metroid-gunship-cavern.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 210 KiB |
BIN
home/wallpapers/super-metroid-samus-statue.png
Normal file
BIN
home/wallpapers/super-metroid-samus-statue.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.8 MiB |
@@ -26,10 +26,20 @@ with lib;
|
|||||||
enable = true;
|
enable = true;
|
||||||
autologin = true;
|
autologin = true;
|
||||||
wayland = true;
|
wayland = true;
|
||||||
|
jellyfinScaleFactor = 1.0;
|
||||||
};
|
};
|
||||||
|
nfs-mounts.enable = true;
|
||||||
users.enable = true;
|
users.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Enable KDE Wallet PAM integration for auto-unlock
|
||||||
|
security.pam.services.sddm = {
|
||||||
|
kwallet = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.kdePackages.kwallet-pam;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
# Use the systemd-boot EFI boot loader.
|
# Use the systemd-boot EFI boot loader.
|
||||||
boot.loader.systemd-boot.enable = true;
|
boot.loader.systemd-boot.enable = true;
|
||||||
boot.loader.efi.canTouchEfiVariables = true;
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
@@ -39,12 +49,7 @@ with lib;
|
|||||||
services.xserver.videoDrivers = [ "amdgpu" ];
|
services.xserver.videoDrivers = [ "amdgpu" ];
|
||||||
hardware.graphics.enable = true;
|
hardware.graphics.enable = true;
|
||||||
hardware.graphics.enable32Bit = true;
|
hardware.graphics.enable32Bit = true;
|
||||||
hardware.graphics.extraPackages = with pkgs; [
|
# RADV (AMD's Vulkan driver) is now enabled by default, amdvlk was removed
|
||||||
amdvlk
|
|
||||||
];
|
|
||||||
hardware.graphics.extraPackages32 = with pkgs; [
|
|
||||||
driversi686Linux.amdvlk
|
|
||||||
];
|
|
||||||
|
|
||||||
# This option defines the first version of NixOS you have installed on this particular machine,
|
# This option defines the first version of NixOS you have installed on this particular machine,
|
||||||
# and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
|
# and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
|
||||||
|
|||||||
424
machines/john-endesktop/MIGRATION_PLAN.md
Normal file
424
machines/john-endesktop/MIGRATION_PLAN.md
Normal file
@@ -0,0 +1,424 @@
|
|||||||
|
# Migration Plan: Arch Linux to NixOS on john-endesktop (ZFS/NFS Server)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
This document outlines the plan to migrate the john-endesktop server from Arch Linux to NixOS while maintaining the existing ZFS pools and NFS exports that serve your k3s cluster.
|
||||||
|
|
||||||
|
## Current System State
|
||||||
|
|
||||||
|
### Hardware
|
||||||
|
- **Boot disk**: nvme0n1
|
||||||
|
- nvme0n1p3: 1000M EFI partition (UUID: F5C6-D570)
|
||||||
|
- nvme0n1p4: 120GB ext4 / (current Arch root)
|
||||||
|
- nvme0n1p5: 810GB - **Target for NixOS** (being removed from media pool)
|
||||||
|
- **Network**: enp0s31f6 @ 10.0.0.43/24 (DHCP)
|
||||||
|
|
||||||
|
### ZFS Pools
|
||||||
|
- **media**: ~3.5TB JBOD pool (2 drives after nvme0n1p5 removal)
|
||||||
|
- wwn-0x50014ee2ba653d70-part2
|
||||||
|
- ata-WDC_WD20EZBX-00AYRA0_WD-WX62D627X7Z8-part2
|
||||||
|
- Contains: /media/media/nix (bind mounted to /nix on Arch)
|
||||||
|
- NFS: Shared to 10.0.0.0/24 via ZFS sharenfs property
|
||||||
|
|
||||||
|
- **swarmvols**: 928GB mirror pool - **PRODUCTION DATA**
|
||||||
|
- wwn-0x5002538f52707e2d-part2
|
||||||
|
- wwn-0x5002538f52707e81-part2
|
||||||
|
- Contains: iocage jails and k3s persistent volumes
|
||||||
|
- NFS: Shared to 10.0.0.0/24 via ZFS sharenfs property
|
||||||
|
- Backed up nightly to remote borg
|
||||||
|
|
||||||
|
### Services
|
||||||
|
- NFS server exporting /media and /swarmvols to k3s cluster
|
||||||
|
- ZFS managing pools with automatic exports via sharenfs property
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
### Before Starting
|
||||||
|
1. ✅ Ensure nvme0n1p5 removal from media pool is complete
|
||||||
|
```bash
|
||||||
|
ssh 10.0.0.43 "zpool status media"
|
||||||
|
# Should show no "removing" devices
|
||||||
|
```
|
||||||
|
|
||||||
|
2. ✅ Verify recent backups exist
|
||||||
|
```bash
|
||||||
|
# Verify swarmvols backup is recent (< 24 hours)
|
||||||
|
# Check your borg backup system
|
||||||
|
```
|
||||||
|
|
||||||
|
3. ✅ Notify k3s cluster users of planned maintenance window
|
||||||
|
- NFS shares will be unavailable during migration
|
||||||
|
- Estimate: 30-60 minutes downtime
|
||||||
|
|
||||||
|
4. ✅ Build NixOS configuration from your workstation
|
||||||
|
```bash
|
||||||
|
cd ~/nixos-configs
|
||||||
|
nix build .#nixosConfigurations.john-endesktop.config.system.build.toplevel
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration Steps
|
||||||
|
|
||||||
|
### Phase 1: Prepare NixOS Installation Media
|
||||||
|
|
||||||
|
1. **Download NixOS minimal ISO**
|
||||||
|
```bash
|
||||||
|
wget https://channels.nixos.org/nixos-25.11/latest-nixos-minimal-x86_64-linux.iso
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Create bootable USB**
|
||||||
|
```bash
|
||||||
|
# Identify USB device (e.g., /dev/sdb)
|
||||||
|
lsblk
|
||||||
|
# Write ISO to USB
|
||||||
|
sudo dd if=latest-nixos-minimal-x86_64-linux.iso of=/dev/sdX bs=4M status=progress
|
||||||
|
sudo sync
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 2: Backup and Shutdown
|
||||||
|
|
||||||
|
1. **On the server, verify ZFS pool status**
|
||||||
|
```bash
|
||||||
|
ssh 10.0.0.43 "zpool status"
|
||||||
|
ssh 10.0.0.43 "zfs list"
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Export ZFS pools cleanly**
|
||||||
|
```bash
|
||||||
|
ssh 10.0.0.43 "sudo zpool export media"
|
||||||
|
ssh 10.0.0.43 "sudo zpool export swarmvols"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Shutdown Arch Linux**
|
||||||
|
```bash
|
||||||
|
ssh 10.0.0.43 "sudo shutdown -h now"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 3: Install NixOS
|
||||||
|
|
||||||
|
1. **Boot from NixOS USB**
|
||||||
|
- Insert USB drive
|
||||||
|
- Power on and select USB in boot menu
|
||||||
|
|
||||||
|
2. **Connect to network**
|
||||||
|
```bash
|
||||||
|
# If DHCP doesn't work automatically:
|
||||||
|
sudo systemctl start dhcpcd
|
||||||
|
ip a # Verify you have 10.0.0.43 or another IP
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Enable SSH for remote installation (recommended)**
|
||||||
|
```bash
|
||||||
|
# Set password for nixos user
|
||||||
|
sudo passwd nixos
|
||||||
|
# Start SSH
|
||||||
|
sudo systemctl start sshd
|
||||||
|
# From your workstation:
|
||||||
|
ssh nixos@10.0.0.43
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Partition nvme0n1p5 with btrfs**
|
||||||
|
```bash
|
||||||
|
# Verify the device is clear
|
||||||
|
lsblk
|
||||||
|
sudo wipefs -a /dev/nvme0n1p5
|
||||||
|
|
||||||
|
# Create btrfs filesystem
|
||||||
|
sudo mkfs.btrfs -L nixos /dev/nvme0n1p5
|
||||||
|
|
||||||
|
# Mount and create subvolumes
|
||||||
|
sudo mount /dev/nvme0n1p5 /mnt
|
||||||
|
sudo btrfs subvolume create /mnt/@
|
||||||
|
sudo btrfs subvolume create /mnt/@home
|
||||||
|
sudo btrfs subvolume create /mnt/@nix
|
||||||
|
sudo btrfs subvolume create /mnt/@log
|
||||||
|
sudo umount /mnt
|
||||||
|
|
||||||
|
# Mount root subvolume
|
||||||
|
sudo mount -o subvol=@,compress=zstd,noatime /dev/nvme0n1p5 /mnt
|
||||||
|
|
||||||
|
# Create mount points
|
||||||
|
sudo mkdir -p /mnt/{boot,home,nix,var/log}
|
||||||
|
|
||||||
|
# Mount other subvolumes
|
||||||
|
sudo mount -o subvol=@home,compress=zstd,noatime /dev/nvme0n1p5 /mnt/home
|
||||||
|
sudo mount -o subvol=@nix,compress=zstd,noatime /dev/nvme0n1p5 /mnt/nix
|
||||||
|
sudo mount -o subvol=@log,compress=zstd,noatime /dev/nvme0n1p5 /mnt/var/log
|
||||||
|
|
||||||
|
# Mount EFI partition
|
||||||
|
sudo mount /dev/nvme0n1p3 /mnt/boot
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Import ZFS pools**
|
||||||
|
```bash
|
||||||
|
# Import pools (should be visible)
|
||||||
|
sudo zpool import
|
||||||
|
|
||||||
|
# Import with force if needed due to hostid
|
||||||
|
sudo zpool import -f media
|
||||||
|
sudo zpool import -f swarmvols
|
||||||
|
|
||||||
|
# Verify pools are mounted
|
||||||
|
zfs list
|
||||||
|
ls -la /media /swarmvols
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **Generate initial hardware configuration**
|
||||||
|
```bash
|
||||||
|
sudo nixos-generate-config --root /mnt
|
||||||
|
```
|
||||||
|
|
||||||
|
7. **Get the new root filesystem UUID**
|
||||||
|
```bash
|
||||||
|
blkid /dev/nvme0n1p5
|
||||||
|
# Note the UUID for updating hardware-configuration.nix
|
||||||
|
/dev/nvme0n1p5: LABEL="nixos" UUID="5f4ad025-bfab-4aed-a933-6638348059e5" UUID_SUB="4734d820-7b8a-4b7f-853a-026021c1d204" BLOCK_SIZE="4096" TYPE="btrfs" PARTLABEL="data" PARTUUID="9ea025df-cdb7-48fd-b5d4-37cd5d8588eb"
|
||||||
|
```
|
||||||
|
|
||||||
|
8. **Copy your NixOS configuration to the server**
|
||||||
|
```bash
|
||||||
|
# From your workstation:
|
||||||
|
scp -r ~/nixos-configs/machines/john-endesktop/* nixos@10.0.0.43:/tmp/
|
||||||
|
|
||||||
|
# On server:
|
||||||
|
sudo mkdir -p /mnt/etc/nixos
|
||||||
|
sudo cp /tmp/configuration.nix /mnt/etc/nixos/
|
||||||
|
sudo cp /tmp/hardware-configuration.nix /mnt/etc/nixos/
|
||||||
|
|
||||||
|
# Edit hardware-configuration.nix to update the root filesystem UUID
|
||||||
|
sudo nano /mnt/etc/nixos/hardware-configuration.nix
|
||||||
|
# Change: device = "/dev/disk/by-uuid/CHANGE-THIS-TO-YOUR-UUID";
|
||||||
|
# To: device = "/dev/disk/by-uuid/[UUID from blkid]";
|
||||||
|
```
|
||||||
|
|
||||||
|
9. **Install NixOS**
|
||||||
|
```bash
|
||||||
|
sudo nixos-install
|
||||||
|
|
||||||
|
# Set root password when prompted
|
||||||
|
# Set user password
|
||||||
|
sudo nixos-install --no-root-passwd
|
||||||
|
```
|
||||||
|
|
||||||
|
10. **Reboot into NixOS**
|
||||||
|
```bash
|
||||||
|
sudo reboot
|
||||||
|
# Remove USB drive
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 4: Post-Installation Verification
|
||||||
|
|
||||||
|
1. **Boot into NixOS and verify system**
|
||||||
|
```bash
|
||||||
|
ssh johno@10.0.0.43
|
||||||
|
|
||||||
|
# Check NixOS version
|
||||||
|
nixos-version
|
||||||
|
|
||||||
|
# Verify hostname
|
||||||
|
hostname # Should be: john-endesktop
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Verify ZFS pools imported correctly**
|
||||||
|
```bash
|
||||||
|
zpool status
|
||||||
|
zpool list
|
||||||
|
zfs list
|
||||||
|
|
||||||
|
# Check for hostid mismatch warnings (should be gone)
|
||||||
|
# Verify both pools show ONLINE status
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Verify NFS exports are active**
|
||||||
|
```bash
|
||||||
|
sudo exportfs -v
|
||||||
|
systemctl status nfs-server
|
||||||
|
|
||||||
|
# Should see /media and /swarmvols exported to 10.0.0.0/24
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Test NFS mount from another machine**
|
||||||
|
```bash
|
||||||
|
# From a k3s node or your workstation:
|
||||||
|
sudo mount -t nfs 10.0.0.43:/swarmvols /mnt
|
||||||
|
ls -la /mnt
|
||||||
|
sudo umount /mnt
|
||||||
|
|
||||||
|
sudo mount -t nfs 10.0.0.43:/media /mnt
|
||||||
|
ls -la /mnt
|
||||||
|
sudo umount /mnt
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Verify ZFS sharenfs properties preserved**
|
||||||
|
```bash
|
||||||
|
zfs get sharenfs media
|
||||||
|
zfs get sharenfs swarmvols
|
||||||
|
|
||||||
|
# Should show: sec=sys,mountpoint,no_subtree_check,no_root_squash,rw=@10.0.0.0/24
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **Check swap device**
|
||||||
|
```bash
|
||||||
|
swapon --show
|
||||||
|
free -h
|
||||||
|
# Should show /dev/zvol/media/swap
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 5: Restore k3s Cluster Access
|
||||||
|
|
||||||
|
1. **Restart k3s nodes or remount NFS shares**
|
||||||
|
```bash
|
||||||
|
# On each k3s node:
|
||||||
|
sudo systemctl restart k3s # or k3s-agent
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Verify k3s pods have access to persistent volumes**
|
||||||
|
```bash
|
||||||
|
# On k3s master:
|
||||||
|
kubectl get pv
|
||||||
|
kubectl get pvc
|
||||||
|
# Check that volumes are bound and accessible
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rollback Plan
|
||||||
|
|
||||||
|
If something goes wrong during migration, you can roll back to Arch Linux:
|
||||||
|
|
||||||
|
### Quick Rollback (If NixOS won't boot)
|
||||||
|
|
||||||
|
1. **Boot from NixOS USB (or Arch USB)**
|
||||||
|
|
||||||
|
2. **Import ZFS pools**
|
||||||
|
```bash
|
||||||
|
sudo zpool import -f media
|
||||||
|
sudo zpool import -f swarmvols
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Start NFS manually (temporary)**
|
||||||
|
```bash
|
||||||
|
sudo mkdir -p /media /swarmvols
|
||||||
|
sudo systemctl start nfs-server
|
||||||
|
sudo exportfs -o rw,sync,no_subtree_check,no_root_squash 10.0.0.0/24:/media
|
||||||
|
sudo exportfs -o rw,sync,no_subtree_check,no_root_squash 10.0.0.0/24:/swarmvols
|
||||||
|
sudo exportfs -v
|
||||||
|
```
|
||||||
|
This will restore k3s cluster access immediately while you diagnose.
|
||||||
|
|
||||||
|
4. **Boot back into Arch Linux**
|
||||||
|
```bash
|
||||||
|
# Reboot and select nvme0n1p4 (Arch) in GRUB/boot menu
|
||||||
|
sudo reboot
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Verify Arch boots and services start**
|
||||||
|
```bash
|
||||||
|
ssh johno@10.0.0.43
|
||||||
|
zpool status
|
||||||
|
systemctl status nfs-server
|
||||||
|
```
|
||||||
|
|
||||||
|
### Full Rollback (If needed)
|
||||||
|
|
||||||
|
1. **Follow Quick Rollback steps above**
|
||||||
|
|
||||||
|
2. **Re-add nvme0n1p5 to media pool (if desired)**
|
||||||
|
```bash
|
||||||
|
# Only if you want to restore the original configuration
|
||||||
|
sudo zpool add media /dev/nvme0n1p5
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Clean up NixOS partition**
|
||||||
|
```bash
|
||||||
|
# If you want to reclaim nvme0n1p5 for other uses
|
||||||
|
sudo wipefs -a /dev/nvme0n1p5
|
||||||
|
```
|
||||||
|
|
||||||
|
## Risk Mitigation
|
||||||
|
|
||||||
|
### Data Safety
|
||||||
|
- ✅ **swarmvols** (production): Mirrored + nightly borg backups
|
||||||
|
- ⚠️ **media** (important): JBOD - no redundancy, but not catastrophic
|
||||||
|
- ✅ **NixOS install**: Separate partition, doesn't touch ZFS pools
|
||||||
|
- ✅ **Arch Linux**: Remains bootable on nvme0n1p4 until verified
|
||||||
|
|
||||||
|
### Service Continuity
|
||||||
|
- Downtime: 30-60 minutes expected
|
||||||
|
- k3s cluster: Will reconnect automatically when NFS returns
|
||||||
|
- Rollback time: < 10 minutes to restore Arch
|
||||||
|
|
||||||
|
### Testing Approach
|
||||||
|
1. Test NFS exports from NixOS live environment before installation
|
||||||
|
2. Test single NFS mount from k3s node before full cluster restart
|
||||||
|
3. Keep Arch Linux boot option until 24-48 hours of stable NixOS operation
|
||||||
|
|
||||||
|
## Post-Migration Tasks
|
||||||
|
|
||||||
|
After successful migration and 24-48 hours of stable operation:
|
||||||
|
|
||||||
|
1. **Update k3s NFS mounts (if needed)**
|
||||||
|
- Verify no hardcoded references to old system
|
||||||
|
|
||||||
|
2. **Optional: Repurpose Arch partition**
|
||||||
|
```bash
|
||||||
|
# After you're confident NixOS is stable
|
||||||
|
# You can wipe nvme0n1p4 and repurpose it
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Update documentation**
|
||||||
|
- Update infrastructure docs with NixOS configuration
|
||||||
|
- Document any deviations from this plan
|
||||||
|
|
||||||
|
4. **Consider setting up NixOS remote deployment**
|
||||||
|
```bash
|
||||||
|
# From your workstation:
|
||||||
|
nixos-rebuild switch --target-host johno@10.0.0.43 --flake .#john-endesktop
|
||||||
|
```
|
||||||
|
|
||||||
|
## Timeline
|
||||||
|
|
||||||
|
- **Preparation**: 1-2 hours (testing config build, downloading ISO)
|
||||||
|
- **Migration window**: 1-2 hours (installation + verification)
|
||||||
|
- **Verification period**: 24-48 hours (before removing Arch)
|
||||||
|
- **Total**: ~3 days from start to declaring success
|
||||||
|
|
||||||
|
## Emergency Contacts
|
||||||
|
|
||||||
|
- Borg backup location: [Document your borg repo location]
|
||||||
|
- K3s cluster nodes: [Document your k3s nodes]
|
||||||
|
- Critical services on k3s: [Document what's running that depends on these NFS shares]
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
Pre-migration:
|
||||||
|
- [x] nvme0n1p5 removal from media pool complete
|
||||||
|
- [x] Recent backup verified (< 24 hours)
|
||||||
|
- [x] Maintenance window scheduled
|
||||||
|
- [x] NixOS ISO downloaded
|
||||||
|
- [x] Bootable USB created
|
||||||
|
- [x] NixOS config builds successfully
|
||||||
|
|
||||||
|
During migration:
|
||||||
|
- [ ] ZFS pools exported
|
||||||
|
- [ ] Arch Linux shutdown cleanly
|
||||||
|
- [ ] Booted from NixOS USB
|
||||||
|
- [ ] nvme0n1p5 formatted with btrfs
|
||||||
|
- [ ] Btrfs subvolumes created
|
||||||
|
- [ ] ZFS pools imported
|
||||||
|
- [ ] NixOS installed
|
||||||
|
- [ ] Root password set
|
||||||
|
|
||||||
|
Post-migration:
|
||||||
|
- [ ] NixOS boots successfully
|
||||||
|
- [ ] ZFS pools mounted automatically
|
||||||
|
- [ ] NFS server running
|
||||||
|
- [ ] NFS exports verified
|
||||||
|
- [ ] Test mount from k3s node successful
|
||||||
|
- [ ] k3s cluster reconnected
|
||||||
|
- [ ] Persistent volumes accessible
|
||||||
|
- [ ] No hostid warnings in zpool status
|
||||||
|
- [ ] Arch Linux still bootable (for rollback)
|
||||||
|
|
||||||
|
Final verification (after 24-48 hours):
|
||||||
|
- [ ] All services stable
|
||||||
|
- [ ] No unexpected issues
|
||||||
|
- [ ] Performance acceptable
|
||||||
|
- [ ] Ready to remove Arch partition (optional)
|
||||||
|
- [ ] Ready to remove /swarmvols/media-backup (optional)
|
||||||
112
machines/john-endesktop/configuration.nix
Normal file
112
machines/john-endesktop/configuration.nix
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
# NixOS configuration for john-endesktop (ZFS/NFS server)
|
||||||
|
# Migrated from Arch Linux to provide ZFS pools via NFS to k3s cluster
|
||||||
|
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./hardware-configuration.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
# Boot configuration
|
||||||
|
boot.loader.systemd-boot.enable = true;
|
||||||
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
|
||||||
|
# ZFS support
|
||||||
|
boot.supportedFilesystems = [ "zfs" ];
|
||||||
|
boot.zfs.forceImportRoot = false;
|
||||||
|
boot.zfs.extraPools = [ "media" "swarmvols" ];
|
||||||
|
|
||||||
|
# Set ZFS hostid to match current system (from Arch Linux)
|
||||||
|
# This resolves the hostid mismatch warnings
|
||||||
|
networking.hostId = "007f0101";
|
||||||
|
|
||||||
|
# Hostname
|
||||||
|
networking.hostName = "john-endesktop";
|
||||||
|
|
||||||
|
# Network configuration - using DHCP on enp0s31f6
|
||||||
|
networking.useDHCP = false;
|
||||||
|
networking.interfaces.enp0s31f6.useDHCP = true;
|
||||||
|
|
||||||
|
# NFS Server configuration
|
||||||
|
services.nfs.server = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
# NFS protocol versions
|
||||||
|
# v3 for broader compatibility, v4 for better performance
|
||||||
|
exports = ''
|
||||||
|
# These are managed by ZFS sharenfs properties
|
||||||
|
# but we enable the NFS server here
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Enable NFS4 with proper configuration
|
||||||
|
services.rpcbind.enable = true;
|
||||||
|
|
||||||
|
# Firewall configuration for NFS
|
||||||
|
networking.firewall = {
|
||||||
|
enable = true;
|
||||||
|
allowedTCPPorts = [
|
||||||
|
111 # rpcbind
|
||||||
|
2049 # nfs
|
||||||
|
4000 # nfs callback
|
||||||
|
4001 # nlockmgr
|
||||||
|
4002 # mountd
|
||||||
|
20048 # mountd
|
||||||
|
];
|
||||||
|
allowedUDPPorts = [
|
||||||
|
111 # rpcbind
|
||||||
|
2049 # nfs
|
||||||
|
4000 # nfs callback
|
||||||
|
4001 # nlockmgr
|
||||||
|
4002 # mountd
|
||||||
|
20048 # mountd
|
||||||
|
];
|
||||||
|
# Allow NFS from local network
|
||||||
|
extraCommands = ''
|
||||||
|
iptables -A nixos-fw -p tcp -s 10.0.0.0/24 -j ACCEPT
|
||||||
|
iptables -A nixos-fw -p udp -s 10.0.0.0/24 -j ACCEPT
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# ZFS maintenance
|
||||||
|
services.zfs = {
|
||||||
|
autoScrub = {
|
||||||
|
enable = true;
|
||||||
|
interval = "monthly";
|
||||||
|
};
|
||||||
|
trim = {
|
||||||
|
enable = true;
|
||||||
|
interval = "weekly";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Basic system packages
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
vim
|
||||||
|
git
|
||||||
|
htop
|
||||||
|
tmux
|
||||||
|
zfs
|
||||||
|
];
|
||||||
|
|
||||||
|
# Enable SSH
|
||||||
|
services.openssh = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
PermitRootLogin = "no";
|
||||||
|
PasswordAuthentication = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# User configuration
|
||||||
|
roles.users.enable = true;
|
||||||
|
|
||||||
|
# Time zone
|
||||||
|
time.timeZone = "America/Los_Angeles"; # Adjust as needed
|
||||||
|
|
||||||
|
# NixOS version
|
||||||
|
system.stateVersion = "25.11";
|
||||||
|
}
|
||||||
63
machines/john-endesktop/hardware-configuration.nix
Normal file
63
machines/john-endesktop/hardware-configuration.nix
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# Hardware configuration for john-endesktop
|
||||||
|
# This file should be regenerated after NixOS installation using:
|
||||||
|
# nixos-generate-config --show-hardware-config
|
||||||
|
|
||||||
|
{ config, lib, pkgs, modulesPath, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
(modulesPath + "/installer/scan/not-detected.nix")
|
||||||
|
];
|
||||||
|
|
||||||
|
# Boot configuration
|
||||||
|
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" ];
|
||||||
|
boot.initrd.kernelModules = [ ];
|
||||||
|
boot.kernelModules = [ "kvm-intel" ];
|
||||||
|
boot.extraModulePackages = [ ];
|
||||||
|
|
||||||
|
# File systems - these will need to be updated after installation
|
||||||
|
# The nvme0n1p5 partition will be formatted as btrfs for NixOS root
|
||||||
|
fileSystems."/" = {
|
||||||
|
device = "/dev/disk/by-uuid/5f4ad025-bfab-4aed-a933-6638348059e5";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "subvol=@" "compress=zstd" "noatime" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/home" = {
|
||||||
|
device = "/dev/disk/by-uuid/5f4ad025-bfab-4aed-a933-6638348059e5";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "subvol=@home" "compress=zstd" "noatime" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/nix" = {
|
||||||
|
device = "/dev/disk/by-uuid/5f4ad025-bfab-4aed-a933-6638348059e5";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "subvol=@nix" "compress=zstd" "noatime" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/var/log" = {
|
||||||
|
device = "/dev/disk/by-uuid/5f4ad025-bfab-4aed-a933-6638348059e5";
|
||||||
|
fsType = "btrfs";
|
||||||
|
options = [ "subvol=@log" "compress=zstd" "noatime" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/boot" = {
|
||||||
|
# This should match your current EFI partition
|
||||||
|
device = "/dev/disk/by-uuid/F5C6-D570";
|
||||||
|
fsType = "vfat";
|
||||||
|
options = [ "fmask=0022" "dmask=0022" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# ZFS pools - these are imported by ZFS, not managed by fileSystems
|
||||||
|
# The pools should be imported automatically via boot.zfs.extraPools
|
||||||
|
# /media and /swarmvols will be mounted by ZFS
|
||||||
|
|
||||||
|
# No swap needed - 23GB RAM is sufficient for this NFS/ZFS server
|
||||||
|
swapDevices = [ ];
|
||||||
|
|
||||||
|
# CPU microcode
|
||||||
|
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||||
|
|
||||||
|
# Networking
|
||||||
|
networking.useDHCP = lib.mkDefault true;
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
desktop = {
|
desktop = {
|
||||||
enable = true;
|
enable = true;
|
||||||
wayland = true;
|
wayland = true;
|
||||||
gaming.enable = false;
|
gaming.enable = true;
|
||||||
kde = true;
|
kde = true;
|
||||||
sddm = true;
|
sddm = true;
|
||||||
};
|
};
|
||||||
@@ -39,6 +39,17 @@
|
|||||||
boot.loader.efi.canTouchEfiVariables = true;
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
|
||||||
boot.initrd.luks.devices."luks-b614167b-9045-4234-a441-ac6f60a96d81".device = "/dev/disk/by-uuid/b614167b-9045-4234-a441-ac6f60a96d81";
|
boot.initrd.luks.devices."luks-b614167b-9045-4234-a441-ac6f60a96d81".device = "/dev/disk/by-uuid/b614167b-9045-4234-a441-ac6f60a96d81";
|
||||||
|
|
||||||
|
services.logind.settings.Login = {
|
||||||
|
HandleLidSwitch = "suspend-then-hibernate";
|
||||||
|
HandlePowerKey = "hibernate";
|
||||||
|
HandlePowerKeyLongPress = "poweroff";
|
||||||
|
};
|
||||||
|
systemd.sleep.extraConfig = ''
|
||||||
|
HibernateDelaySec=30m
|
||||||
|
SuspendState=mem
|
||||||
|
'';
|
||||||
|
|
||||||
networking.hostName = "nix-book"; # Define your hostname.
|
networking.hostName = "nix-book"; # Define your hostname.
|
||||||
# networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
|
# networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./hardware-configuration.nix
|
./hardware-configuration.nix
|
||||||
|
../../roles/desktop/steamos.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
roles = {
|
roles = {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
extraPackages = with pkgs; [
|
extraPackages = with pkgs; [
|
||||||
mesa
|
mesa
|
||||||
libvdpau-va-gl
|
libvdpau-va-gl
|
||||||
vaapiVdpau
|
libva-vdpau-driver
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
environment.sessionVariables = {
|
environment.sessionVariables = {
|
||||||
|
|||||||
@@ -7,10 +7,10 @@
|
|||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
{
|
{
|
||||||
imports =
|
imports = [
|
||||||
[ # Include the results of the hardware scan.
|
./hardware-configuration.nix
|
||||||
./hardware-configuration.nix
|
#./virtual-surround.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
roles = {
|
roles = {
|
||||||
audio.enable = true;
|
audio.enable = true;
|
||||||
|
|||||||
132
machines/zix790prors/virtual-surround.nix
Normal file
132
machines/zix790prors/virtual-surround.nix
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
# Virtual 4.1 surround sound setup
|
||||||
|
# Routes FL/FR to AmazonBasics USB speaker, RL/RR to Fosi BT20A PRO Bluetooth speaker
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
services.pipewire.extraConfig.pipewire."10-virtual-surround" = {
|
||||||
|
"context.objects" = [
|
||||||
|
{
|
||||||
|
factory = "adapter";
|
||||||
|
args = {
|
||||||
|
"factory.name" = "support.null-audio-sink";
|
||||||
|
"node.name" = "virtual_surround_sink";
|
||||||
|
"node.description" = "Virtual 4.1 Surround (AmazonBasics + Fosi)";
|
||||||
|
"media.class" = "Audio/Sink";
|
||||||
|
"audio.position" = [ "FL" "FR" "RL" "RR" "LFE" ];
|
||||||
|
"monitor.channel-volumes" = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
"context.modules" = [
|
||||||
|
{
|
||||||
|
name = "libpipewire-module-loopback";
|
||||||
|
args = {
|
||||||
|
"node.description" = "Route Front to AmazonBasics";
|
||||||
|
"capture.props" = {
|
||||||
|
"node.name" = "route_front_capture";
|
||||||
|
"audio.position" = [ "FL" "FR" ];
|
||||||
|
"stream.dont-remix" = true;
|
||||||
|
"node.passive" = true;
|
||||||
|
};
|
||||||
|
"playback.props" = {
|
||||||
|
"node.name" = "route_front_playback";
|
||||||
|
"node.target" = "alsa_output.usb-C-Media_Electronics_Inc._AmazonBasics_Professional_Mic_2-00.analog-stereo";
|
||||||
|
"audio.position" = [ "FL" "FR" ];
|
||||||
|
"stream.dont-remix" = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "libpipewire-module-loopback";
|
||||||
|
args = {
|
||||||
|
"node.description" = "Route Rear to Fosi Audio";
|
||||||
|
"capture.props" = {
|
||||||
|
"node.name" = "route_rear_capture";
|
||||||
|
"audio.position" = [ "RL" "RR" ];
|
||||||
|
"stream.dont-remix" = true;
|
||||||
|
"node.passive" = true;
|
||||||
|
};
|
||||||
|
"playback.props" = {
|
||||||
|
"node.name" = "route_rear_playback";
|
||||||
|
"node.target" = "bluez_output.F4_4E_FD_FB_58_62.1";
|
||||||
|
"audio.position" = [ "FL" "FR" ];
|
||||||
|
"stream.dont-remix" = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "libpipewire-module-loopback";
|
||||||
|
args = {
|
||||||
|
"node.description" = "Route Subwoofer to AmazonBasics";
|
||||||
|
"capture.props" = {
|
||||||
|
"node.name" = "route_lfe_capture";
|
||||||
|
"audio.position" = [ "LFE" ];
|
||||||
|
"stream.dont-remix" = true;
|
||||||
|
"node.passive" = true;
|
||||||
|
};
|
||||||
|
"playback.props" = {
|
||||||
|
"node.name" = "route_lfe_playback";
|
||||||
|
"node.target" = "alsa_output.usb-C-Media_Electronics_Inc._AmazonBasics_Professional_Mic_2-00.analog-stereo";
|
||||||
|
"audio.position" = [ "MONO" ];
|
||||||
|
"stream.dont-remix" = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Systemd services to fix PipeWire loopback routing for virtual surround
|
||||||
|
systemd.user.services.pipewire-surround-link = {
|
||||||
|
description = "Link virtual surround sink to loopback captures";
|
||||||
|
after = [ "pipewire.service" "wireplumber.service" ];
|
||||||
|
requires = [ "pipewire.service" "wireplumber.service" ];
|
||||||
|
wantedBy = [ "pipewire.service" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = false;
|
||||||
|
ExecStart = pkgs.writeShellScript "surround-link" ''
|
||||||
|
sleep 2
|
||||||
|
# Disconnect wrong connections
|
||||||
|
${pkgs.pipewire}/bin/pw-link -d alsa_input.pci-0000_00_1f.3.pro-input-2:capture_AUX0 route_front_capture:input_FL 2>/dev/null || true
|
||||||
|
${pkgs.pipewire}/bin/pw-link -d alsa_input.pci-0000_00_1f.3.pro-input-2:capture_AUX1 route_front_capture:input_FR 2>/dev/null || true
|
||||||
|
${pkgs.pipewire}/bin/pw-link -d alsa_input.pci-0000_00_1f.3.pro-input-2:capture_AUX0 route_rear_capture:input_RL 2>/dev/null || true
|
||||||
|
${pkgs.pipewire}/bin/pw-link -d alsa_input.pci-0000_00_1f.3.pro-input-2:capture_AUX1 route_rear_capture:input_RR 2>/dev/null || true
|
||||||
|
${pkgs.pipewire}/bin/pw-link -d alsa_input.pci-0000_00_1f.3.pro-input-2:capture_AUX0 route_lfe_capture:input_LFE 2>/dev/null || true
|
||||||
|
# Create correct connections
|
||||||
|
${pkgs.pipewire}/bin/pw-link virtual_surround_sink:monitor_FL route_front_capture:input_FL 2>/dev/null || true
|
||||||
|
${pkgs.pipewire}/bin/pw-link virtual_surround_sink:monitor_FR route_front_capture:input_FR 2>/dev/null || true
|
||||||
|
${pkgs.pipewire}/bin/pw-link virtual_surround_sink:monitor_RL route_rear_capture:input_RL 2>/dev/null || true
|
||||||
|
${pkgs.pipewire}/bin/pw-link virtual_surround_sink:monitor_RR route_rear_capture:input_RR 2>/dev/null || true
|
||||||
|
${pkgs.pipewire}/bin/pw-link virtual_surround_sink:monitor_LFE route_lfe_capture:input_LFE 2>/dev/null || true
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.user.services.pipewire-surround-link-check = {
|
||||||
|
description = "Check and fix surround sink links";
|
||||||
|
after = [ "pipewire.service" "wireplumber.service" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = pkgs.writeShellScript "surround-link-check" ''
|
||||||
|
if ${pkgs.pipewire}/bin/pw-cli ls Node 2>/dev/null | grep -q "bluez_output.F4_4E_FD_FB_58_62"; then
|
||||||
|
if ${pkgs.pipewire}/bin/pw-link -l 2>/dev/null | grep -q "route_front_capture:input_FL.*alsa_input"; then
|
||||||
|
${pkgs.systemd}/bin/systemctl --user start pipewire-surround-link.service
|
||||||
|
fi
|
||||||
|
if ! ${pkgs.pipewire}/bin/pw-link -l 2>/dev/null | grep -q "virtual_surround_sink:monitor_FL.*route_front_capture"; then
|
||||||
|
${pkgs.systemd}/bin/systemctl --user start pipewire-surround-link.service
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.user.timers.pipewire-surround-link-check = {
|
||||||
|
description = "Periodically check surround sink links";
|
||||||
|
wantedBy = [ "default.target" ];
|
||||||
|
timerConfig = {
|
||||||
|
OnStartupSec = "10s";
|
||||||
|
OnUnitActiveSec = "10s";
|
||||||
|
Unit = "pipewire-surround-link-check.service";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
116
packages/claude-code/README.md
Normal file
116
packages/claude-code/README.md
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
# claude-cli
|
||||||
|
|
||||||
|
Custom Nix package for Claude Code CLI.
|
||||||
|
|
||||||
|
## Why This Package Exists
|
||||||
|
|
||||||
|
The official `claude-code` package in nixpkgs tries to fetch from npm registry, which is blocked by Block's corporate security (Cloudflare Teams dependency confusion protection). This custom package fetches directly from Anthropic's Google Cloud Storage distribution, bypassing the npm registry entirely.
|
||||||
|
|
||||||
|
## Updating to a New Version
|
||||||
|
|
||||||
|
### Automated Update (Recommended)
|
||||||
|
|
||||||
|
Run the update script to automatically fetch and update to the latest version:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd packages/claude-cli
|
||||||
|
./update.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The script will:
|
||||||
|
- Fetch the latest version from Homebrew cask
|
||||||
|
- Update version and all SHA256 hashes in default.nix
|
||||||
|
- Show you what changed
|
||||||
|
|
||||||
|
For a dry-run to see what would change:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./update.sh --dry-run
|
||||||
|
```
|
||||||
|
|
||||||
|
After the script completes, follow the "Test the Build" steps below.
|
||||||
|
|
||||||
|
### Manual Update
|
||||||
|
|
||||||
|
If you prefer to update manually, or if the automated script fails:
|
||||||
|
|
||||||
|
#### 1. Find the Latest Version and Hashes
|
||||||
|
|
||||||
|
Check the Homebrew cask formula for the latest version info:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s "https://raw.githubusercontent.com/Homebrew/homebrew-cask/HEAD/Casks/c/claude-code.rb" | head -50
|
||||||
|
```
|
||||||
|
|
||||||
|
This will show:
|
||||||
|
- The latest `version` number
|
||||||
|
- SHA256 hashes for all platforms (`arm64`, `x86_64`, `x86_64_linux`, `arm64_linux`)
|
||||||
|
|
||||||
|
#### 2. Update default.nix
|
||||||
|
|
||||||
|
Edit `default.nix` and update:
|
||||||
|
|
||||||
|
1. The `version` variable (line 9):
|
||||||
|
```nix
|
||||||
|
version = "2.0.51"; # Update this
|
||||||
|
```
|
||||||
|
|
||||||
|
2. All four platform sha256 hashes in the `srcs` attribute set (lines 11-27):
|
||||||
|
```nix
|
||||||
|
aarch64-darwin = {
|
||||||
|
sha256 = "..."; # Update from Homebrew cask "arm:" value
|
||||||
|
};
|
||||||
|
x86_64-darwin = {
|
||||||
|
sha256 = "..."; # Update from Homebrew cask "x86_64:" value
|
||||||
|
};
|
||||||
|
x86_64-linux = {
|
||||||
|
sha256 = "..."; # Update from Homebrew cask "x86_64_linux:" value
|
||||||
|
};
|
||||||
|
aarch64-linux = {
|
||||||
|
sha256 = "..."; # Update from Homebrew cask "arm64_linux:" value
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. Test the Build
|
||||||
|
|
||||||
|
Before committing, test that the package builds successfully:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
NIXPKGS_ALLOW_UNFREE=1 nix-build -E 'with import <nixpkgs> { config.allowUnfree = true; }; callPackage ./packages/claude-cli {}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify the version:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./result/bin/claude --version
|
||||||
|
```
|
||||||
|
|
||||||
|
Clean up the test build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm result
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4. Deploy
|
||||||
|
|
||||||
|
Commit your changes and rebuild:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add packages/claude-cli/
|
||||||
|
git commit -m "claude-cli: Update to version X.Y.Z"
|
||||||
|
darwin-rebuild switch --flake .#blkfv4yf49kt7
|
||||||
|
```
|
||||||
|
|
||||||
|
## Alternative: Automated Hash Fetching
|
||||||
|
|
||||||
|
If you prefer to fetch hashes automatically, you can use `nix-prefetch-url`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# For macOS ARM64 (your current platform)
|
||||||
|
nix-prefetch-url "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/VERSION/darwin-arm64/claude"
|
||||||
|
|
||||||
|
# For other platforms, replace VERSION and adjust the platform string:
|
||||||
|
# darwin-x64, linux-x64, linux-arm64
|
||||||
|
```
|
||||||
|
|
||||||
|
This will download the file and output the SHA256 hash.
|
||||||
60
packages/claude-code/default.nix
Normal file
60
packages/claude-code/default.nix
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
{ lib
|
||||||
|
, stdenv
|
||||||
|
, fetchurl
|
||||||
|
, autoPatchelfHook
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
version = "2.0.76";
|
||||||
|
|
||||||
|
srcs = {
|
||||||
|
aarch64-darwin = {
|
||||||
|
url = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/${version}/darwin-arm64/claude";
|
||||||
|
sha256 = "b76f6d4d09233e67295897b0a1ed2e22d7afa406431529d8b1b532b63b8cbcbd";
|
||||||
|
};
|
||||||
|
x86_64-darwin = {
|
||||||
|
url = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/${version}/darwin-x64/claude";
|
||||||
|
sha256 = "9d94582f0af5d2201f1c907bf24ff8d216104b897ee0b24795a6c081f40e08d7";
|
||||||
|
};
|
||||||
|
x86_64-linux = {
|
||||||
|
url = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/${version}/linux-x64/claude";
|
||||||
|
sha256 = "5dcdb480f91ba0df0bc8bd6aff148d3dfd3883f0899eeb5b9427a8b0abe7a687";
|
||||||
|
};
|
||||||
|
aarch64-linux = {
|
||||||
|
url = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/${version}/linux-arm64/claude";
|
||||||
|
sha256 = "f64a994c8e5bfb84d7242cebbec75d6919db2ee46d50b8fc7a88d5066db193f9";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
src = srcs.${stdenv.hostPlatform.system} or (throw "Unsupported system: ${stdenv.hostPlatform.system}");
|
||||||
|
|
||||||
|
in stdenv.mkDerivation {
|
||||||
|
pname = "claude-code";
|
||||||
|
inherit version;
|
||||||
|
|
||||||
|
src = fetchurl {
|
||||||
|
inherit (src) url sha256;
|
||||||
|
};
|
||||||
|
|
||||||
|
dontUnpack = true;
|
||||||
|
dontBuild = true;
|
||||||
|
|
||||||
|
nativeBuildInputs = lib.optionals stdenv.isLinux [ autoPatchelfHook ];
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
|
||||||
|
install -Dm755 $src $out/bin/claude
|
||||||
|
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Terminal-based AI coding assistant from Anthropic";
|
||||||
|
homepage = "https://www.anthropic.com/claude-code";
|
||||||
|
license = licenses.unfree;
|
||||||
|
maintainers = [ ];
|
||||||
|
platforms = [ "aarch64-darwin" "x86_64-darwin" "x86_64-linux" "aarch64-linux" ];
|
||||||
|
mainProgram = "claude";
|
||||||
|
};
|
||||||
|
}
|
||||||
34
packages/claude-code/npm.nix
Normal file
34
packages/claude-code/npm.nix
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{ lib
|
||||||
|
, buildNpmPackage
|
||||||
|
, fetchurl
|
||||||
|
, nodejs_18
|
||||||
|
}:
|
||||||
|
|
||||||
|
buildNpmPackage {
|
||||||
|
pname = "claude-cli";
|
||||||
|
version = "0.2.65";
|
||||||
|
|
||||||
|
src = fetchurl {
|
||||||
|
url = "https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-0.2.65.tgz";
|
||||||
|
sha256 = "0wwaqq7k9p5aw4vqhfpdgf3da09x64q55wibqaprk6kjvn130i92";
|
||||||
|
};
|
||||||
|
|
||||||
|
npmDepsHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; # Will be updated after first build
|
||||||
|
|
||||||
|
nodejs = nodejs_18;
|
||||||
|
|
||||||
|
# Don't run npm audit or other network operations during build
|
||||||
|
npmConfigHook = ''
|
||||||
|
npm config set audit false
|
||||||
|
npm config set fund false
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Terminal-based AI coding assistant from Anthropic (npm distribution)";
|
||||||
|
homepage = "https://www.anthropic.com/claude-code";
|
||||||
|
license = licenses.unfree;
|
||||||
|
maintainers = [ ];
|
||||||
|
platforms = platforms.all;
|
||||||
|
mainProgram = "claude";
|
||||||
|
};
|
||||||
|
}
|
||||||
133
packages/claude-code/update.sh
Executable file
133
packages/claude-code/update.sh
Executable file
@@ -0,0 +1,133 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DRY_RUN=false
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--dry-run|-n)
|
||||||
|
DRY_RUN=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--help|-h)
|
||||||
|
echo "Usage: $0 [OPTIONS]"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " --dry-run, -n Show what would be updated without making changes"
|
||||||
|
echo " --help, -h Show this help message"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $1"
|
||||||
|
echo "Use --help for usage information"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
CASK_URL="https://raw.githubusercontent.com/Homebrew/homebrew-cask/HEAD/Casks/c/claude-code.rb"
|
||||||
|
REPO_ROOT="${REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
|
||||||
|
NIX_FILE="$REPO_ROOT/packages/claude-code/default.nix"
|
||||||
|
|
||||||
|
echo "Fetching latest claude-code version from Homebrew cask..."
|
||||||
|
|
||||||
|
# Fetch the cask file
|
||||||
|
CASK_CONTENT=$(curl -fsSL "$CASK_URL")
|
||||||
|
|
||||||
|
# Extract version (format: version "X.Y.Z")
|
||||||
|
NEW_VERSION=$(echo "$CASK_CONTENT" | grep -m1 'version' | sed -E 's/.*version "([^"]+)".*/\1/')
|
||||||
|
|
||||||
|
# Extract SHA256 hashes (be specific to match sha256 lines only)
|
||||||
|
SHA_ARM=$(echo "$CASK_CONTENT" | grep 'sha256 arm:' | sed -E 's/.*"([a-f0-9]{64})".*/\1/')
|
||||||
|
SHA_X86_64=$(echo "$CASK_CONTENT" | grep 'x86_64:' | sed -E 's/.*"([a-f0-9]{64})".*/\1/')
|
||||||
|
SHA_X86_64_LINUX=$(echo "$CASK_CONTENT" | grep 'x86_64_linux:' | sed -E 's/.*"([a-f0-9]{64})".*/\1/')
|
||||||
|
SHA_ARM64_LINUX=$(echo "$CASK_CONTENT" | grep 'arm64_linux:' | sed -E 's/.*"([a-f0-9]{64})".*/\1/')
|
||||||
|
|
||||||
|
# Get current version
|
||||||
|
CURRENT_VERSION=$(grep -m1 'version = ' "$NIX_FILE" | sed -E 's/.*version = "([^"]+)".*/\1/')
|
||||||
|
|
||||||
|
# Validate extracted data
|
||||||
|
if [ -z "$NEW_VERSION" ] || [ -z "$SHA_ARM" ] || [ -z "$SHA_X86_64" ] || [ -z "$SHA_X86_64_LINUX" ] || [ -z "$SHA_ARM64_LINUX" ]; then
|
||||||
|
echo -e "${RED}Error: Failed to extract all required values from Homebrew cask${NC}"
|
||||||
|
echo "Version: $NEW_VERSION"
|
||||||
|
echo "ARM: $SHA_ARM"
|
||||||
|
echo "x86_64: $SHA_X86_64"
|
||||||
|
echo "x86_64_linux: $SHA_X86_64_LINUX"
|
||||||
|
echo "arm64_linux: $SHA_ARM64_LINUX"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if update is needed
|
||||||
|
if [ "$CURRENT_VERSION" = "$NEW_VERSION" ]; then
|
||||||
|
echo -e "${GREEN}Already up to date: $CURRENT_VERSION${NC}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${YELLOW}Updating from $CURRENT_VERSION to $NEW_VERSION${NC}"
|
||||||
|
|
||||||
|
if [ "$DRY_RUN" = true ]; then
|
||||||
|
echo -e "${YELLOW}DRY RUN - No changes will be made${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "Would update:"
|
||||||
|
echo " Version: $CURRENT_VERSION -> $NEW_VERSION"
|
||||||
|
echo " aarch64-darwin SHA: $SHA_ARM"
|
||||||
|
echo " x86_64-darwin SHA: $SHA_X86_64"
|
||||||
|
echo " x86_64-linux SHA: $SHA_X86_64_LINUX"
|
||||||
|
echo " aarch64-linux SHA: $SHA_ARM64_LINUX"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Update version
|
||||||
|
sed -i.tmp "s/version = \".*\";/version = \"$NEW_VERSION\";/" "$NIX_FILE"
|
||||||
|
|
||||||
|
# Update SHA256 hashes using awk for more reliable parsing
|
||||||
|
awk -v sha_arm="$SHA_ARM" -v sha_x86="$SHA_X86_64" -v sha_x86_linux="$SHA_X86_64_LINUX" -v sha_arm_linux="$SHA_ARM64_LINUX" '
|
||||||
|
/aarch64-darwin = {/ { in_arm = 1 }
|
||||||
|
/x86_64-darwin = {/ { in_x86 = 1 }
|
||||||
|
/x86_64-linux = {/ { in_x86_linux = 1 }
|
||||||
|
/aarch64-linux = {/ { in_arm_linux = 1 }
|
||||||
|
/};/ {
|
||||||
|
in_arm = 0
|
||||||
|
in_x86 = 0
|
||||||
|
in_x86_linux = 0
|
||||||
|
in_arm_linux = 0
|
||||||
|
}
|
||||||
|
/sha256 = / {
|
||||||
|
if (in_arm) {
|
||||||
|
sub(/sha256 = ".*";/, "sha256 = \"" sha_arm "\";")
|
||||||
|
} else if (in_x86) {
|
||||||
|
sub(/sha256 = ".*";/, "sha256 = \"" sha_x86 "\";")
|
||||||
|
} else if (in_x86_linux) {
|
||||||
|
sub(/sha256 = ".*";/, "sha256 = \"" sha_x86_linux "\";")
|
||||||
|
} else if (in_arm_linux) {
|
||||||
|
sub(/sha256 = ".*";/, "sha256 = \"" sha_arm_linux "\";")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{ print }
|
||||||
|
' "$NIX_FILE" > "$NIX_FILE.new"
|
||||||
|
|
||||||
|
mv "$NIX_FILE.new" "$NIX_FILE"
|
||||||
|
|
||||||
|
# Clean up temp files
|
||||||
|
rm -f "$NIX_FILE.tmp"
|
||||||
|
|
||||||
|
echo -e "${GREEN}Successfully updated to version $NEW_VERSION${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "Updated SHA256 hashes:"
|
||||||
|
echo " aarch64-darwin: $SHA_ARM"
|
||||||
|
echo " x86_64-darwin: $SHA_X86_64"
|
||||||
|
echo " x86_64-linux: $SHA_X86_64_LINUX"
|
||||||
|
echo " aarch64-linux: $SHA_ARM64_LINUX"
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo " 1. Review changes: git diff $NIX_FILE"
|
||||||
|
echo " 2. Test build: NIXPKGS_ALLOW_UNFREE=1 nix-build -E 'with import <nixpkgs> { config.allowUnfree = true; }; callPackage ./packages/claude-code {}'"
|
||||||
|
echo " 3. Verify version: ./result/bin/claude --version"
|
||||||
|
echo " 4. Commit: git add $NIX_FILE && git commit -m 'claude-code: Update to version $NEW_VERSION'"
|
||||||
@@ -3,4 +3,6 @@
|
|||||||
vulkanHDRLayer = pkgs.callPackage ./vulkan-hdr-layer {};
|
vulkanHDRLayer = pkgs.callPackage ./vulkan-hdr-layer {};
|
||||||
tea-rbw = pkgs.callPackage ./tea-rbw {};
|
tea-rbw = pkgs.callPackage ./tea-rbw {};
|
||||||
app-launcher-server = pkgs.callPackage ./app-launcher-server {};
|
app-launcher-server = pkgs.callPackage ./app-launcher-server {};
|
||||||
|
claude-code = pkgs.callPackage ./claude-code {};
|
||||||
|
perles = pkgs.callPackage ./perles {};
|
||||||
}
|
}
|
||||||
|
|||||||
26
packages/perles/default.nix
Normal file
26
packages/perles/default.nix
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{ lib, buildGoModule, fetchFromGitHub }:
|
||||||
|
|
||||||
|
buildGoModule rec {
|
||||||
|
pname = "perles";
|
||||||
|
version = "unstable-2025-01-09";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "zjrosen";
|
||||||
|
repo = "perles";
|
||||||
|
rev = "main";
|
||||||
|
hash = "sha256-JgRayb4+mJ1r0AtdnQfqAw2+QRte+licsfZOaRgYqcs=";
|
||||||
|
};
|
||||||
|
|
||||||
|
vendorHash = "sha256-R7UWTdBuPteneRqxrWK51nqLtZwDsqQoMAcohN4fyak=";
|
||||||
|
|
||||||
|
# Tests require a real git repository context
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "A TUI for the Beads issue tracking system with BQL query language";
|
||||||
|
homepage = "https://github.com/zjrosen/perles";
|
||||||
|
license = licenses.mit;
|
||||||
|
maintainers = [ ];
|
||||||
|
mainProgram = "perles";
|
||||||
|
};
|
||||||
|
}
|
||||||
35
roles/common.nix
Normal file
35
roles/common.nix
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Common configuration shared between NixOS and Darwin
|
||||||
|
{ lib, pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
config = {
|
||||||
|
time.timeZone = "America/Los_Angeles";
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
git
|
||||||
|
glances
|
||||||
|
pciutils
|
||||||
|
tree
|
||||||
|
usbutils
|
||||||
|
vim
|
||||||
|
];
|
||||||
|
|
||||||
|
nix = {
|
||||||
|
package = pkgs.nix;
|
||||||
|
settings = {
|
||||||
|
experimental-features = [ "nix-command" "flakes" ];
|
||||||
|
max-jobs = "auto";
|
||||||
|
trusted-users = [ "johno" ];
|
||||||
|
substituters = [
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
gc = {
|
||||||
|
automatic = true;
|
||||||
|
options = "--delete-older-than 10d";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nixpkgs.config.allowUnfree = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -7,6 +7,10 @@ let
|
|||||||
setEnvironmentPath = "${config.system.build.setEnvironment}";
|
setEnvironmentPath = "${config.system.build.setEnvironment}";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
imports = [
|
||||||
|
./common.nix
|
||||||
|
];
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
# Salt manages /etc/bashrc, /etc/zshrc, /etc/zshenv
|
# Salt manages /etc/bashrc, /etc/zshrc, /etc/zshenv
|
||||||
# nix-darwin writes to .local variants for nix-specific configuration
|
# nix-darwin writes to .local variants for nix-specific configuration
|
||||||
@@ -43,8 +47,6 @@ in
|
|||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
|
|
||||||
time.timeZone = "America/Los_Angeles";
|
|
||||||
|
|
||||||
# System preferences
|
# System preferences
|
||||||
system.defaults = {
|
system.defaults = {
|
||||||
# Custom keyboard shortcuts
|
# Custom keyboard shortcuts
|
||||||
@@ -79,42 +81,5 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
git
|
|
||||||
glances
|
|
||||||
pciutils
|
|
||||||
tree
|
|
||||||
usbutils
|
|
||||||
vim
|
|
||||||
];
|
|
||||||
|
|
||||||
nix = {
|
|
||||||
package = pkgs.nix;
|
|
||||||
# distributedBuilds = true;
|
|
||||||
# buildMachines = [{
|
|
||||||
# hostName = "z790prors.oglehome";
|
|
||||||
# system = "x86_64-linux";
|
|
||||||
# protocol = "ssh-ng";
|
|
||||||
# sshUser = "johno";
|
|
||||||
# sshKey = "/root/.ssh/id_ed25519";
|
|
||||||
# maxJobs = 3;
|
|
||||||
# speedFactor = 2;
|
|
||||||
# }];
|
|
||||||
settings = {
|
|
||||||
experimental-features = [ "nix-command" "flakes" ];
|
|
||||||
max-jobs = "auto";
|
|
||||||
trusted-users = [ "johno" ];
|
|
||||||
substituters = [
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
gc = {
|
|
||||||
automatic = true;
|
|
||||||
options = "--delete-older-than 10d";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
nixpkgs.config.allowUnfree = true;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@ with lib;
|
|||||||
|
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
|
./common.nix
|
||||||
./audio
|
./audio
|
||||||
./bluetooth
|
./bluetooth
|
||||||
./btrfs
|
./btrfs
|
||||||
@@ -31,7 +32,6 @@ with lib;
|
|||||||
LC_TELEPHONE = "en_US.UTF-8";
|
LC_TELEPHONE = "en_US.UTF-8";
|
||||||
LC_TIME = "en_US.UTF-8";
|
LC_TIME = "en_US.UTF-8";
|
||||||
};
|
};
|
||||||
time.timeZone = "America/Los_Angeles";
|
|
||||||
|
|
||||||
services.xserver.xkb = {
|
services.xserver.xkb = {
|
||||||
layout = "us";
|
layout = "us";
|
||||||
@@ -49,42 +49,7 @@ with lib;
|
|||||||
# Enable the OpenSSH daemon.
|
# Enable the OpenSSH daemon.
|
||||||
services.openssh.enable = true;
|
services.openssh.enable = true;
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
# NixOS-specific gc option (not available on Darwin)
|
||||||
git
|
nix.gc.randomizedDelaySec = "14m";
|
||||||
glances
|
|
||||||
pciutils
|
|
||||||
tree
|
|
||||||
usbutils
|
|
||||||
vim
|
|
||||||
];
|
|
||||||
|
|
||||||
nix = {
|
|
||||||
package = pkgs.nix;
|
|
||||||
# distributedBuilds = true;
|
|
||||||
# buildMachines = [{
|
|
||||||
# hostName = "z790prors.oglehome";
|
|
||||||
# system = "x86_64-linux";
|
|
||||||
# protocol = "ssh-ng";
|
|
||||||
# sshUser = "johno";
|
|
||||||
# sshKey = "/root/.ssh/id_ed25519";
|
|
||||||
# maxJobs = 3;
|
|
||||||
# speedFactor = 2;
|
|
||||||
# }];
|
|
||||||
settings = {
|
|
||||||
experimental-features = [ "nix-command" "flakes" ];
|
|
||||||
max-jobs = "auto";
|
|
||||||
trusted-users = [ "johno" ];
|
|
||||||
substituters = [
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
gc = {
|
|
||||||
automatic = true;
|
|
||||||
randomizedDelaySec = "14m";
|
|
||||||
options = "--delete-older-than 10d";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
nixpkgs.config.allowUnfree = true;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,5 @@ with lib;
|
|||||||
./kde.nix
|
./kde.nix
|
||||||
./programs.nix
|
./programs.nix
|
||||||
./sddm.nix
|
./sddm.nix
|
||||||
./steamos.nix
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,24 +9,29 @@ in
|
|||||||
config = mkMerge [
|
config = mkMerge [
|
||||||
(mkIf (cfg.enable && cfg.gaming.enable) {
|
(mkIf (cfg.enable && cfg.gaming.enable) {
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
steam
|
|
||||||
lutris
|
lutris
|
||||||
moonlight
|
moonlight
|
||||||
|
|
||||||
# Emulators
|
# Emulators
|
||||||
dolphin-emu
|
dolphin-emu
|
||||||
dolphin-emu-primehack
|
|
||||||
retroarch-full
|
|
||||||
ryubing
|
|
||||||
];
|
|
||||||
# TODO: Remove me once dolphin-emu and dolphin-emu-primehack update
|
|
||||||
# dependencies to mbedtls from mbedtls_2 (which is currently)
|
|
||||||
# unmaintained
|
|
||||||
nixpkgs.config.permittedInsecurePackages = [ "mbedtls-2.28.10" ];
|
|
||||||
|
|
||||||
warnings = [
|
# Re-enabled in 25.11 after binary build was fixed
|
||||||
"Using insecure mbedtls-2.28.10 for Dolphin Emu - check for updates regularly"
|
dolphin-emu-primehack
|
||||||
|
|
||||||
|
# Experimenting with just using the steam version + downloading
|
||||||
|
# indiviudal cores
|
||||||
|
#retroarch-full
|
||||||
|
ryubing
|
||||||
|
|
||||||
|
yarg
|
||||||
];
|
];
|
||||||
|
|
||||||
|
programs.steam = {
|
||||||
|
enable = true;
|
||||||
|
remotePlay.openFirewall = true;
|
||||||
|
dedicatedServer.openFirewall = true;
|
||||||
|
localNetworkGameTransfers.openFirewall = true;
|
||||||
|
};
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
{ lib, config, ... }:
|
|
||||||
|
|
||||||
# Minimal Jovian compatibility layer for NixOS stable (25.05)
|
|
||||||
# Defines only the Jovian options used by roles/desktop/steamos.nix
|
|
||||||
# No actual implementation - just option definitions to prevent evaluation errors
|
|
||||||
# REMOVE THIS FILE when all systems are on NixOS 25.11+ or unstable
|
|
||||||
|
|
||||||
with lib;
|
|
||||||
|
|
||||||
let
|
|
||||||
nixosVersion = config.system.nixos.release;
|
|
||||||
isCompatibleVersion = versionOlder nixosVersion "25.11";
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.jovian = {
|
|
||||||
steam = {
|
|
||||||
enable = mkEnableOption "Steam (jovian-compat stub)";
|
|
||||||
|
|
||||||
autoStart = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = "Auto-start Steam (jovian-compat stub)";
|
|
||||||
};
|
|
||||||
|
|
||||||
user = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "user";
|
|
||||||
description = "Steam user (jovian-compat stub)";
|
|
||||||
};
|
|
||||||
|
|
||||||
desktopSession = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = "Desktop session (jovian-compat stub)";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
decky-loader = {
|
|
||||||
enable = mkEnableOption "Decky Loader (jovian-compat stub)";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkMerge [
|
|
||||||
{
|
|
||||||
assertions = [
|
|
||||||
{
|
|
||||||
assertion = isCompatibleVersion;
|
|
||||||
message = ''
|
|
||||||
The Jovian compatibility shim (roles/jovian-compat.nix) is only needed for NixOS 25.05 and earlier.
|
|
||||||
You are running NixOS ${nixosVersion}.
|
|
||||||
Please remove 'roles/jovian-compat.nix' from your flake.nix nixosModules list.
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
# No config implementation - these options do nothing on stable systems
|
|
||||||
# steamos role is only enabled on nix-deck which uses unstable anyway
|
|
||||||
(mkIf config.jovian.steam.enable {
|
|
||||||
warnings = [
|
|
||||||
"Jovian is enabled but you're using the compatibility stub. This won't work correctly. Use NixOS unstable for Jovian support."
|
|
||||||
];
|
|
||||||
})
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -14,6 +14,11 @@ in
|
|||||||
wayland = mkOption {
|
wayland = mkOption {
|
||||||
default = true;
|
default = true;
|
||||||
};
|
};
|
||||||
|
jellyfinScaleFactor = mkOption {
|
||||||
|
type = types.nullOr types.float;
|
||||||
|
default = null;
|
||||||
|
description = "Scale factor for Jellyfin Media Player UI (e.g., 1.5 for 150% scaling)";
|
||||||
|
};
|
||||||
appLauncherServer = {
|
appLauncherServer = {
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
@@ -37,6 +42,28 @@ in
|
|||||||
steam-library
|
steam-library
|
||||||
youtube
|
youtube
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
jellyfinMediaPlayerPkg =
|
||||||
|
if cfg.jellyfinScaleFactor != null
|
||||||
|
then pkgs.symlinkJoin {
|
||||||
|
name = "jellyfin-media-player-scaled";
|
||||||
|
paths = [ pkgs.jellyfin-media-player ];
|
||||||
|
nativeBuildInputs = [ pkgs.makeWrapper ];
|
||||||
|
postBuild = ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
rm -f $out/bin/jellyfin-desktop
|
||||||
|
makeWrapper ${pkgs.jellyfin-media-player}/bin/jellyfin-desktop $out/bin/jellyfin-desktop \
|
||||||
|
--add-flags "--tv --scale-factor ${toString cfg.jellyfinScaleFactor}"
|
||||||
|
|
||||||
|
# Update .desktop file to include scale factor and TV mode arguments
|
||||||
|
mkdir -p $out/share/applications
|
||||||
|
rm -f $out/share/applications/org.jellyfin.JellyfinDesktop.desktop
|
||||||
|
substitute ${pkgs.jellyfin-media-player}/share/applications/org.jellyfin.JellyfinDesktop.desktop \
|
||||||
|
$out/share/applications/org.jellyfin.JellyfinDesktop.desktop \
|
||||||
|
--replace-fail "Exec=jellyfin-desktop" "Exec=jellyfin-desktop --tv --scale-factor ${toString cfg.jellyfinScaleFactor}"
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
else pkgs.jellyfin-media-player;
|
||||||
in mkIf cfg.enable
|
in mkIf cfg.enable
|
||||||
{
|
{
|
||||||
users.extraUsers.kodi = {
|
users.extraUsers.kodi = {
|
||||||
@@ -50,11 +77,18 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
|
jellyfinMediaPlayerPkg
|
||||||
kodiPkg
|
kodiPkg
|
||||||
wget
|
wget
|
||||||
firefox
|
firefox
|
||||||
] ++ optional cfg.appLauncherServer.enable pkgs.custom.app-launcher-server;
|
] ++ optional cfg.appLauncherServer.enable pkgs.custom.app-launcher-server;
|
||||||
|
|
||||||
|
nixpkgs.config.permittedInsecurePackages = lib.warn
|
||||||
|
"Allowing insecure package qtwebengine-5.15.19 as a jellyfin-media-player dependency. Remove this once jellyfin is updated to use qt6"
|
||||||
|
[
|
||||||
|
"qtwebengine-5.15.19"
|
||||||
|
];
|
||||||
|
|
||||||
programs.kdeconnect.enable = true;
|
programs.kdeconnect.enable = true;
|
||||||
|
|
||||||
systemd.user.services = mkIf cfg.appLauncherServer.enable {
|
systemd.user.services = mkIf cfg.appLauncherServer.enable {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ in
|
|||||||
users.users.johno = {
|
users.users.johno = {
|
||||||
isNormalUser = true;
|
isNormalUser = true;
|
||||||
description = "John Ogle";
|
description = "John Ogle";
|
||||||
extraGroups = [ "wheel" "networkmanager" "audio" "video" ] ++ cfg.extraGroups;
|
extraGroups = [ "wheel" "networkmanager" "audio" "video" "i2c" ] ++ cfg.extraGroups;
|
||||||
};
|
};
|
||||||
|
|
||||||
users.users.eli = mkIf cfg.kids {
|
users.users.eli = mkIf cfg.kids {
|
||||||
|
|||||||
41
scripts/rotate-wallpaper.sh
Normal file
41
scripts/rotate-wallpaper.sh
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
REPO_ROOT="${REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
|
||||||
|
WALLPAPER_FILE="$REPO_ROOT/home/wallpapers/default.nix"
|
||||||
|
|
||||||
|
echo -e "${GREEN}Rotating wallpaper...${NC}"
|
||||||
|
|
||||||
|
# Check if file exists
|
||||||
|
if [[ ! -f "$WALLPAPER_FILE" ]]; then
|
||||||
|
echo -e "${RED}Error: $WALLPAPER_FILE not found${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get current index
|
||||||
|
CURRENT_INDEX=$(grep -oP 'currentIndex = \K\d+' "$WALLPAPER_FILE")
|
||||||
|
echo -e "Current index: ${YELLOW}$CURRENT_INDEX${NC}"
|
||||||
|
|
||||||
|
# Count wallpapers (count occurrences of "name = " in the wallpapers list)
|
||||||
|
WALLPAPER_COUNT=$(grep -c 'name = "' "$WALLPAPER_FILE")
|
||||||
|
echo -e "Total wallpapers: ${YELLOW}$WALLPAPER_COUNT${NC}"
|
||||||
|
|
||||||
|
# Calculate next index (wrap around)
|
||||||
|
NEXT_INDEX=$(( (CURRENT_INDEX + 1) % WALLPAPER_COUNT ))
|
||||||
|
echo -e "Next index: ${YELLOW}$NEXT_INDEX${NC}"
|
||||||
|
|
||||||
|
# Update the currentIndex
|
||||||
|
sed -i "s/currentIndex = $CURRENT_INDEX;/currentIndex = $NEXT_INDEX;/" "$WALLPAPER_FILE"
|
||||||
|
|
||||||
|
echo -e "${GREEN}Successfully rotated wallpaper!${NC}"
|
||||||
|
echo -e " Old index: ${YELLOW}$CURRENT_INDEX${NC}"
|
||||||
|
echo -e " New index: ${YELLOW}$NEXT_INDEX${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "Rebuild your system to apply the new wallpaper."
|
||||||
82
scripts/update-doomemacs.sh
Executable file
82
scripts/update-doomemacs.sh
Executable file
@@ -0,0 +1,82 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
OWNER="doomemacs"
|
||||||
|
REPO="doomemacs"
|
||||||
|
FILE="home/roles/emacs/default.nix"
|
||||||
|
# Use current working directory as repo root (allows running from anywhere in the repo)
|
||||||
|
REPO_ROOT="${REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
|
||||||
|
TARGET_FILE="$REPO_ROOT/$FILE"
|
||||||
|
|
||||||
|
echo -e "${GREEN}Updating DoomEmacs to latest commit...${NC}"
|
||||||
|
|
||||||
|
# Check if file exists
|
||||||
|
if [[ ! -f "$TARGET_FILE" ]]; then
|
||||||
|
echo -e "${RED}Error: $TARGET_FILE not found${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the default branch first
|
||||||
|
echo "Fetching repository information..."
|
||||||
|
DEFAULT_BRANCH=$(curl -s "https://api.github.com/repos/$OWNER/$REPO" | jq -r '.default_branch')
|
||||||
|
|
||||||
|
if [[ -z "$DEFAULT_BRANCH" ]] || [[ "$DEFAULT_BRANCH" == "null" ]]; then
|
||||||
|
echo -e "${RED}Error: Failed to fetch default branch${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the latest commit SHA from GitHub
|
||||||
|
echo "Fetching latest commit SHA from $DEFAULT_BRANCH branch..."
|
||||||
|
LATEST_SHA=$(curl -s "https://api.github.com/repos/$OWNER/$REPO/commits/$DEFAULT_BRANCH" | jq -r '.sha')
|
||||||
|
|
||||||
|
if [[ -z "$LATEST_SHA" ]] || [[ "$LATEST_SHA" == "null" ]]; then
|
||||||
|
echo -e "${RED}Error: Failed to fetch latest commit SHA${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "Latest commit: ${YELLOW}$LATEST_SHA${NC}"
|
||||||
|
|
||||||
|
# Get current SHA from file
|
||||||
|
CURRENT_SHA=$(grep -oP 'rev = "\K[^"]+' "$TARGET_FILE")
|
||||||
|
echo -e "Current commit: ${YELLOW}$CURRENT_SHA${NC}"
|
||||||
|
|
||||||
|
if [[ "$CURRENT_SHA" == "$LATEST_SHA" ]]; then
|
||||||
|
echo -e "${GREEN}Already up to date!${NC}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Update the rev field
|
||||||
|
echo "Updating rev in $FILE..."
|
||||||
|
sed -i "s/rev = \".*\"/rev = \"$LATEST_SHA\"/" "$TARGET_FILE"
|
||||||
|
|
||||||
|
# Fetch the new sha256 hash using nix-prefetch
|
||||||
|
echo "Fetching new sha256 hash..."
|
||||||
|
NEW_SHA256=$(nix-prefetch-url --unpack "https://github.com/$OWNER/$REPO/archive/$LATEST_SHA.tar.gz" 2>/dev/null)
|
||||||
|
|
||||||
|
if [[ -z "$NEW_SHA256" ]]; then
|
||||||
|
echo -e "${RED}Error: Failed to fetch sha256 hash${NC}"
|
||||||
|
# Revert the rev change
|
||||||
|
sed -i "s/rev = \".*\"/rev = \"$CURRENT_SHA\"/" "$TARGET_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Convert to SRI hash format
|
||||||
|
SRI_HASH=$(nix hash to-sri --type sha256 "$NEW_SHA256")
|
||||||
|
echo -e "New sha256: ${YELLOW}$SRI_HASH${NC}"
|
||||||
|
|
||||||
|
# Update the sha256 field
|
||||||
|
sed -i "s|sha256 = \".*\"|sha256 = \"$SRI_HASH\"|" "$TARGET_FILE"
|
||||||
|
|
||||||
|
echo -e "${GREEN}Successfully updated DoomEmacs!${NC}"
|
||||||
|
echo -e " Old commit: ${YELLOW}$CURRENT_SHA${NC}"
|
||||||
|
echo -e " New commit: ${YELLOW}$LATEST_SHA${NC}"
|
||||||
|
echo -e " New sha256: ${YELLOW}$SRI_HASH${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "You can now rebuild your system with the updated DoomEmacs."
|
||||||
46
scripts/upgrade.sh
Normal file
46
scripts/upgrade.sh
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
REPO_ROOT="${REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
|
||||||
|
|
||||||
|
echo -e "${BLUE}========================================${NC}"
|
||||||
|
echo -e "${BLUE} NixOS Configuration Major Upgrade${NC}"
|
||||||
|
echo -e "${BLUE}========================================${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Step 1: Update flake inputs
|
||||||
|
echo -e "${GREEN}[1/4] Updating flake inputs...${NC}"
|
||||||
|
cd "$REPO_ROOT"
|
||||||
|
nix flake update
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Step 2: Update Doom Emacs
|
||||||
|
echo -e "${GREEN}[2/4] Updating Doom Emacs...${NC}"
|
||||||
|
"$REPO_ROOT/scripts/update-doomemacs.sh"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Step 3: Update Claude Code
|
||||||
|
echo -e "${GREEN}[3/4] Updating Claude Code...${NC}"
|
||||||
|
"$REPO_ROOT/packages/claude-code/update.sh"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Step 4: Rotate wallpaper
|
||||||
|
echo -e "${GREEN}[4/4] Rotating wallpaper...${NC}"
|
||||||
|
"$REPO_ROOT/scripts/rotate-wallpaper.sh"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo -e "${BLUE}========================================${NC}"
|
||||||
|
echo -e "${GREEN}Upgrade complete!${NC}"
|
||||||
|
echo -e "${BLUE}========================================${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo " 1. Review changes: git diff"
|
||||||
|
echo " 2. Rebuild system: sudo nixos-rebuild switch --flake ."
|
||||||
|
echo " 3. If satisfied, commit: git add -A && git commit -m 'chore: Major upgrade'"
|
||||||
Reference in New Issue
Block a user