Compare commits

..

1 Commits

Author SHA1 Message Date
49e6df605d feat(scripts): Add --help flags to all flake apps
Add consistent --help/-h argument handling to update-doomemacs.sh,
rotate-wallpaper.sh, and upgrade.sh scripts. Each script now displays
usage information and a description of what it does.

update-claude-code already had --help support.
2026-01-10 12:56:36 -08:00
24 changed files with 266 additions and 674 deletions

View File

@@ -1,130 +0,0 @@
---
description: Import open Gitea issues as beads, skipping already-imported ones
---
# Import Gitea Issues as Beads
This skill imports open Gitea issues as beads, checking for duplicates to avoid re-importing already tracked issues.
## Prerequisites
- `tea` CLI must be installed and configured for the repository
- `bd` (beads) CLI must be installed
- Must be in a git repository with a Gitea/Forgejo remote
## Workflow
### Step 1: Get open Gitea issues
List all open issues using `tea`:
```bash
tea issues
```
This returns a table with columns: INDEX, TITLE, LABELS, MILESTONE
### Step 2: Get existing beads
List all current beads to check what's already imported:
```bash
bd list
```
Also check bead notes for issue URLs to identify imports:
```bash
bd list --json | jq -r '.[] | select(.notes != null) | .notes' | grep -oP 'issues/\K\d+'
```
### Step 3: Check for already-linked PRs
Check if any open PRs reference beads (skip these issues as they're being worked on):
```bash
tea pr list
```
Look for PRs with:
- Bead ID in title: `[nixos-configs-xxx]`
- Bead reference in body: `Implements bead:` or `Bead ID:`
### Step 4: For each untracked issue, create a bead
For each issue not already tracked:
1. **Get full issue details**:
```bash
tea issue [ISSUE_NUMBER]
```
2. **Determine bead type** based on issue content:
- "bug" - if issue mentions bug, error, broken, fix, crash
- "feature" - if issue mentions feature, add, new, enhancement
- "task" - default for other issues
3. **Create the bead**:
```bash
bd add "[ISSUE_TITLE]" \
--type=[TYPE] \
--priority=P2 \
--notes="Gitea issue: [ISSUE_URL]
Original issue description:
[ISSUE_BODY]"
```
Note: The `--notes` flag accepts multi-line content.
### Step 5: Report results
Present a summary:
```
## Gitea Issues Import Summary
### Imported as Beads
| Issue | Title | Bead ID | Type |
|-------|-------|---------|------|
| #5 | Add dark mode | nixos-configs-abc | feature |
| #3 | Config broken on reboot | nixos-configs-def | bug |
### Skipped (Already Tracked)
| Issue | Title | Reason |
|-------|-------|--------|
| #4 | Update flake | Existing bead: nixos-configs-xyz |
| #2 | Refactor roles | PR #7 references bead |
### Skipped (Other)
| Issue | Title | Reason |
|-------|-------|--------|
| #1 | Discussion: future plans | No actionable work |
```
## Type Detection Heuristics
Keywords to detect issue type:
**Bug indicators** (case-insensitive):
- bug, error, broken, fix, crash, fail, issue, problem, wrong, not working
**Feature indicators** (case-insensitive):
- feature, add, new, enhancement, implement, support, request, want, would be nice
**Task** (default):
- Anything not matching bug or feature patterns
## Error Handling
- **tea not configured**: Report error and exit
- **bd not available**: Report error and exit
- **Issue already has bead**: Skip and report in summary
- **Issue is a PR**: Skip (tea shows PRs and issues separately)
## Notes
- Default priority is P2; adjust manually after import if needed
- Issue labels from Gitea are not automatically mapped to bead tags
- Run this periodically to catch new issues
- After import, use `bd ready` to see which beads can be worked on

4
scripts/bootstrap.sh → bootstrap.sh Normal file → Executable file
View File

@@ -1,7 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# bootstrap.sh # bootstrap.sh
# Usage: nix run .#bootstrap -- <hostname> # Usage: sudo ./bootstrap.sh <hostname>
# Or: sudo ./scripts/bootstrap.sh <hostname>
set -euo pipefail set -euo pipefail
NEW_HOSTNAME="${1:?missing hostname}" NEW_HOSTNAME="${1:?missing hostname}"
@@ -9,3 +8,4 @@ FLAKE_URI="git+https://git.johnogle.info/johno/nixos-configs.git#${NEW_HOSTNAME}
export NIX_CONFIG="experimental-features = nix-command flakes" export NIX_CONFIG="experimental-features = nix-command flakes"
nixos-rebuild switch --flake "$FLAKE_URI" nixos-rebuild switch --flake "$FLAKE_URI"

19
build-liveusb.sh Executable file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/env bash
# Build Live USB ISO from flake configuration
# Creates an uncompressed ISO suitable for Ventoy and other USB boot tools
set -e
echo "Building Live USB ISO..."
nix build .#nixosConfigurations.live-usb.config.system.build.isoImage --show-trace
if [ -f "./result/iso/"*.iso ]; then
iso_file=$(ls ./result/iso/*.iso)
echo "✅ Build complete!"
echo "📁 ISO location: $iso_file"
echo "💾 Ready for Ventoy or dd to USB"
else
echo "❌ Build failed - no ISO file found"
exit 1
fi

101
flake.nix
View File

@@ -56,75 +56,94 @@
}; };
outputs = { self, nixpkgs, nixpkgs-unstable, nixos-wsl, ... } @ inputs: let outputs = { self, nixpkgs, nixpkgs-unstable, nixos-wsl, ... } @ inputs: let
# Shared overlay function to reduce duplication across module sets nixosModules = [
# Parameters: ./roles
# unstableOverlays: Additional overlays to apply when importing nixpkgs-unstable ] ++ [
mkBaseOverlay = { unstableOverlays ? [] }: (final: prev: { inputs.home-manager.nixosModules.home-manager
{
nixpkgs.overlays = [
(final: prev: {
unstable = import nixpkgs-unstable { unstable = import nixpkgs-unstable {
system = prev.stdenv.hostPlatform.system; system = prev.stdenv.hostPlatform.system;
config.allowUnfree = true; config.allowUnfree = true;
overlays = unstableOverlays;
}; };
custom = prev.callPackage ./packages {}; custom = prev.callPackage ./packages {};
# Compatibility: bitwarden renamed to bitwarden-desktop in unstable # Compatibility: bitwarden renamed to bitwarden-desktop in unstable
bitwarden-desktop = prev.bitwarden-desktop or prev.bitwarden; bitwarden-desktop = prev.bitwarden-desktop or prev.bitwarden;
}); })
];
# Shared home-manager configuration factory
# Parameters:
# sharedModules: Additional modules to include in home-manager.sharedModules
mkHomeManagerConfig = { sharedModules ? [] }: {
home-manager.useGlobalPkgs = true; home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true; home-manager.useUserPackages = true;
home-manager.sharedModules = sharedModules ++ [ home-manager.sharedModules = [
inputs.plasma-manager.homeModules.plasma-manager
inputs.nix-doom-emacs-unstraightened.homeModule inputs.nix-doom-emacs-unstraightened.homeModule
]; ];
home-manager.extraSpecialArgs = { home-manager.extraSpecialArgs = {
globalInputs = inputs; globalInputs = inputs;
}; };
};
nixosModules = [
./roles
inputs.home-manager.nixosModules.home-manager
{
nixpkgs.overlays = [ (mkBaseOverlay {}) ];
} }
(mkHomeManagerConfig {
sharedModules = [ inputs.plasma-manager.homeModules.plasma-manager ];
})
]; ];
# Modules for unstable-based systems (like nix-deck) # Modules for unstable-based systems (like nix-deck)
nixosModulesUnstable = [ nixosModulesUnstable = [
./roles ./roles
] ++ [
inputs.home-manager-unstable.nixosModules.home-manager inputs.home-manager-unstable.nixosModules.home-manager
inputs.jovian.nixosModules.jovian inputs.jovian.nixosModules.jovian
{ {
nixpkgs.overlays = [ (mkBaseOverlay {}) ]; nixpkgs.overlays = [
} (final: prev: {
(mkHomeManagerConfig { unstable = import nixpkgs-unstable {
sharedModules = [ inputs.plasma-manager-unstable.homeModules.plasma-manager ]; system = prev.stdenv.hostPlatform.system;
config.allowUnfree = true;
};
custom = prev.callPackage ./packages {};
# Compatibility: bitwarden renamed to bitwarden-desktop in unstable
bitwarden-desktop = prev.bitwarden-desktop or prev.bitwarden;
}) })
]; ];
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.sharedModules = [
inputs.plasma-manager-unstable.homeModules.plasma-manager
inputs.nix-doom-emacs-unstraightened.homeModule
];
home-manager.extraSpecialArgs = {
globalInputs = inputs;
};
}
];
darwinModules = [ darwinModules = [
./roles/darwin.nix ./roles/darwin.nix
] ++ [
inputs.home-manager.darwinModules.home-manager inputs.home-manager.darwinModules.home-manager
{ {
nixpkgs.overlays = [ nixpkgs.overlays = [
(mkBaseOverlay { (final: prev: {
unstable = import nixpkgs-unstable {
system = prev.stdenv.hostPlatform.system;
config.allowUnfree = true;
overlays = [
# Override claude-code in unstable to use our custom GCS-based build # Override claude-code in unstable to use our custom GCS-based build
# (needed for corporate networks that block npm registry) # (needed for corporate networks that block npm registry)
unstableOverlays = [
(ufinal: uprev: { (ufinal: uprev: {
claude-code = uprev.callPackage ./packages/claude-code {}; claude-code = prev.custom.claude-code or (prev.callPackage ./packages {}).claude-code;
}) })
]; ];
};
custom = prev.callPackage ./packages {};
# Compatibility: bitwarden renamed to bitwarden-desktop in unstable
bitwarden-desktop = prev.bitwarden-desktop or prev.bitwarden;
}) })
]; ];
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.sharedModules = [
inputs.nix-doom-emacs-unstraightened.homeModule
];
home-manager.extraSpecialArgs = {
globalInputs = inputs;
};
} }
(mkHomeManagerConfig { sharedModules = []; })
]; ];
in { in {
@@ -256,16 +275,6 @@
export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH" export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH"
${builtins.readFile ./scripts/upgrade.sh} ${builtins.readFile ./scripts/upgrade.sh}
''; '';
bootstrap = pkgs.writeShellScriptBin "bootstrap" ''
export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH"
${builtins.readFile ./scripts/bootstrap.sh}
'';
build-liveusb = pkgs.writeShellScriptBin "build-liveusb" ''
export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH"
${builtins.readFile ./scripts/build-liveusb.sh}
'';
in { in {
update-doomemacs = { update-doomemacs = {
type = "app"; type = "app";
@@ -283,14 +292,6 @@
type = "app"; type = "app";
program = "${upgrade}/bin/upgrade"; program = "${upgrade}/bin/upgrade";
}; };
bootstrap = {
type = "app";
program = "${bootstrap}/bin/bootstrap";
};
build-liveusb = {
type = "app";
program = "${build-liveusb}/bin/build-liveusb";
};
} }
); );
}; };

View File

@@ -11,7 +11,6 @@
base.enable = true; base.enable = true;
development.enable = true; development.enable = true;
emacs.enable = true; emacs.enable = true;
kubectl.enable = true;
starship.enable = true; starship.enable = true;
tmux.enable = true; tmux.enable = true;
}; };

View File

@@ -44,6 +44,7 @@ in
# Custom packages # Custom packages
pkgs.custom.tea-rbw pkgs.custom.tea-rbw
pkgs.custom.perles
]; ];
# Install Claude Code humanlayer command and agent plugins # Install Claude Code humanlayer command and agent plugins

View File

@@ -1,244 +0,0 @@
---
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

View File

@@ -167,20 +167,6 @@
claude-code-ide-window-side 'right claude-code-ide-window-side 'right
claude-code-ide-window-width 90)) claude-code-ide-window-width 90))
(use-package! beads
:commands (beads)
:init
(map! :leader
(:prefix ("o" . "open")
(:prefix ("B" . "beads")
:desc "List issues" "B" (cmd! (require 'beads) (beads-list))
:desc "Project issues" "p" (cmd! (require 'beads) (beads-project-list))
:desc "Activity feed" "a" (cmd! (require 'beads) (beads-activity))
:desc "Stale issues" "s" (cmd! (require 'beads) (beads-stale))
:desc "Orphaned issues" "o" (cmd! (require 'beads) (beads-orphans))
:desc "Find duplicates" "d" (cmd! (require 'beads) (beads-duplicates))
:desc "Lint issues" "l" (cmd! (require 'beads) (beads-lint))))))
(after! gptel (after! gptel
(require 'gptel-tool-library) (require 'gptel-tool-library)
(setq gptel-tool-library-use-maybe-safe t (setq gptel-tool-library-use-maybe-safe t

View File

@@ -26,7 +26,6 @@ with lib;
enable = true; enable = true;
autologin = true; autologin = true;
wayland = true; wayland = true;
appLauncherServer = true;
jellyfinScaleFactor = 1.0; jellyfinScaleFactor = 1.0;
}; };
nfs-mounts.enable = true; nfs-mounts.enable = true;

View File

@@ -104,23 +104,6 @@ with lib;
# User configuration # User configuration
roles.users.enable = true; roles.users.enable = true;
# k3s agent configuration
roles.k3s-node = {
enable = true;
role = "agent";
# serverAddr defaults to https://10.0.0.222:6443
# tokenFile defaults to /etc/k3s/token
extraFlags = [
# Node labels for workload scheduling
# fast-cpu: This node has a faster CPU than other cluster nodes
"--node-label=fast-cpu=true"
# fast-storage: This node is the NFS host with fast local storage access
"--node-label=fast-storage=true"
# k3s-upgrade=disabled: NixOS manages k3s upgrades via Nix, not system-upgrade-controller
"--node-label=k3s-upgrade=disabled"
];
};
# Time zone # Time zone
time.timeZone = "America/Los_Angeles"; # Adjust as needed time.timeZone = "America/Los_Angeles"; # Adjust as needed

View File

@@ -41,9 +41,14 @@
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 = { services.logind.settings.Login = {
HandleLidSwitch = "suspend-then-hibernate";
HandlePowerKey = "hibernate"; HandlePowerKey = "hibernate";
HandlePowerKeyLongPress = "poweroff"; 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.

View File

@@ -17,15 +17,6 @@
enable = true; enable = true;
wayland = true; wayland = true;
}; };
nvidia = {
enable = true;
package = "latest";
graphics.extraPackages = with pkgs; [
mesa
libvdpau-va-gl
libva-vdpau-driver
];
};
users.enable = true; users.enable = true;
}; };
@@ -38,13 +29,28 @@
wsl.wslConf.network.hostname = "wixos"; wsl.wslConf.network.hostname = "wixos";
wsl.wslConf.user.default = "johno"; wsl.wslConf.user.default = "johno";
# WSL-specific environment variables for graphics services.xserver.videoDrivers = [ "nvidia" ];
hardware.graphics = {
enable = true;
extraPackages = with pkgs; [
mesa
libvdpau-va-gl
libva-vdpau-driver
];
};
environment.sessionVariables = { environment.sessionVariables = {
LD_LIBRARY_PATH = [ LD_LIBRARY_PATH = [
"/usr/lib/wsl/lib" "/usr/lib/wsl/lib"
"/run/opengl-driver/lib" "/run/opengl-driver/lib"
]; ];
}; };
hardware.nvidia = {
modesetting.enable = true;
nvidiaSettings = true;
open = true;
package = config.boot.kernelPackages.nvidiaPackages.latest;
};
# This value determines the NixOS release from which the default # This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions # settings for stateful data, like file locations and database versions

View File

@@ -25,12 +25,8 @@ with lib;
wayland = true; wayland = true;
x11 = true; x11 = true;
}; };
kodi.enable = true;
nfs-mounts.enable = true; nfs-mounts.enable = true;
nvidia = { nvidia.enable = true;
enable = true;
graphics.enable32Bit = true;
};
printing.enable = true; printing.enable = true;
remote-build.enableBuilder = true; remote-build.enableBuilder = true;
users.enable = true; users.enable = true;
@@ -51,11 +47,27 @@ with lib;
# Fix dual boot clock sync - tell Linux to use local time for hardware clock # Fix dual boot clock sync - tell Linux to use local time for hardware clock
time.hardwareClockInLocalTime = true; time.hardwareClockInLocalTime = true;
# NVIDIA Graphics configuration
services.xserver.videoDrivers = [ "nvidia" ];
hardware.graphics.enable = true;
hardware.graphics.enable32Bit = true;
# Set DP-0 as primary display with 164.90Hz refresh rate # Set DP-0 as primary display with 164.90Hz refresh rate
services.xserver.displayManager.sessionCommands = '' services.xserver.displayManager.sessionCommands = ''
${pkgs.xorg.xrandr}/bin/xrandr --output DP-0 --mode 3440x1440 --rate 164.90 --primary ${pkgs.xorg.xrandr}/bin/xrandr --output DP-0 --mode 3440x1440 --rate 164.90 --primary
''; '';
hardware.nvidia = {
modesetting.enable = true;
nvidiaSettings = true;
package = pkgs.linuxPackages.nvidiaPackages.stable;
open = true;
# For gaming performance
powerManagement.enable = false;
powerManagement.finegrained = false;
};
services.ollama = { services.ollama = {
enable = true; enable = true;
acceleration = "cuda"; acceleration = "cuda";

View File

@@ -1,6 +1,8 @@
{ pkgs, ... }: { pkgs, ... }:
{ {
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 {}; claude-code = pkgs.callPackage ./claude-code {};
perles = pkgs.callPackage ./perles {};
} }

View 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";
};
}

View File

@@ -0,0 +1,34 @@
{ lib, stdenv, fetchFromGitHub, meson, pkg-config, vulkan-loader, ninja, writeText, vulkan-headers, vulkan-utility-libraries, jq, libX11, libXrandr, libxcb, wayland, wayland-scanner }:
stdenv.mkDerivation rec {
pname = "vulkan-hdr-layer";
version = "63d2eec";
src = (fetchFromGitHub {
owner = "Zamundaaa";
repo = "VK_hdr_layer";
rev = "869199cd2746e7f69cf19955153080842b6dacfc";
fetchSubmodules = true;
hash = "sha256-xfVYI+Aajmnf3BTaY2Ysg5fyDO6SwDFGyU0L+F+E3is=";
}).overrideAttrs (_: {
GIT_CONFIG_COUNT = 1;
GIT_CONFIG_KEY_0 = "url.https://github.com/.insteadOf";
GIT_CONFIG_VALUE_0 = "git@github.com:";
});
nativeBuildInputs = [ vulkan-headers meson ninja pkg-config jq ];
buildInputs = [ vulkan-headers vulkan-loader vulkan-utility-libraries libX11 libXrandr libxcb wayland wayland-scanner ];
# Help vulkan-loader find the validation layers
setupHook = writeText "setup-hook" ''
addToSearchPath XDG_DATA_DIRS @out@/share
'';
meta = with lib; {
description = "Layers providing Vulkan HDR";
homepage = "https://github.com/Zamundaaa/VK_hdr_layer";
platforms = platforms.linux;
license = licenses.mit;
};
}

View File

@@ -9,7 +9,6 @@ with lib;
./bluetooth ./bluetooth
./btrfs ./btrfs
./desktop ./desktop
./k3s-node
./kodi ./kodi
./nfs-mounts ./nfs-mounts
./nvidia ./nvidia

View File

@@ -1,81 +0,0 @@
{ lib, config, pkgs, ... }:
with lib;
let
cfg = config.roles.k3s-node;
in
{
options.roles.k3s-node = {
enable = mkEnableOption "Enable k3s node";
role = mkOption {
type = types.enum [ "server" "agent" ];
default = "agent";
description = "k3s role: server (control plane) or agent (worker)";
};
serverAddr = mkOption {
type = types.str;
default = "https://10.0.0.222:6443";
description = "URL of k3s server to join (required for agents, used for HA servers)";
};
tokenFile = mkOption {
type = types.path;
default = "/etc/k3s/token";
description = "Path to file containing the cluster join token";
};
clusterInit = mkOption {
type = types.bool;
default = false;
description = "Initialize a new cluster (first server only)";
};
extraFlags = mkOption {
type = types.listOf types.str;
default = [];
description = "Additional flags to pass to k3s";
};
gracefulNodeShutdown = mkOption {
type = types.bool;
default = true;
description = "Enable graceful node shutdown";
};
openFirewall = mkOption {
type = types.bool;
default = true;
description = "Open firewall ports for k3s";
};
};
config = mkIf cfg.enable {
# k3s service configuration
services.k3s = {
enable = true;
role = cfg.role;
tokenFile = cfg.tokenFile;
extraFlags = cfg.extraFlags;
gracefulNodeShutdown.enable = cfg.gracefulNodeShutdown;
serverAddr = if (cfg.role == "agent" || !cfg.clusterInit) then cfg.serverAddr else "";
clusterInit = cfg.role == "server" && cfg.clusterInit;
};
# Firewall rules for k3s
networking.firewall = mkIf cfg.openFirewall {
allowedTCPPorts = [
6443 # k3s API server
10250 # kubelet metrics
] ++ optionals (cfg.role == "server") [
2379 # etcd clients (HA)
2380 # etcd peers (HA)
];
allowedUDPPorts = [
8472 # flannel VXLAN
];
};
};
}

View File

@@ -22,7 +22,7 @@ in
appLauncherServer = { appLauncherServer = {
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = true;
description = "Enable HTTP app launcher server for remote control"; description = "Enable HTTP app launcher server for remote control";
}; };
port = mkOption { port = mkOption {

View File

@@ -8,89 +8,9 @@ in
{ {
options.roles.nvidia = { options.roles.nvidia = {
enable = mkEnableOption "Enable the nvidia role"; enable = mkEnableOption "Enable the nvidia role";
# Driver configuration options
open = mkOption {
type = types.bool;
default = true;
description = "Use the open source nvidia kernel driver (for Turing and newer GPUs).";
};
modesetting = mkOption {
type = types.bool;
default = true;
description = "Enable kernel modesetting for nvidia.";
};
nvidiaSettings = mkOption {
type = types.bool;
default = true;
description = "Enable the nvidia-settings GUI.";
};
package = mkOption {
type = types.enum [ "stable" "latest" "beta" "vulkan_beta" "production" ];
default = "stable";
description = "The nvidia driver package to use.";
};
powerManagement = {
enable = mkOption {
type = types.bool;
default = false;
description = "Enable nvidia power management (useful for laptops, not recommended for desktops).";
};
finegrained = mkOption {
type = types.bool;
default = false;
description = "Enable fine-grained power management for Turing and newer GPUs.";
};
};
graphics = {
enable = mkOption {
type = types.bool;
default = true;
description = "Enable hardware graphics support.";
};
enable32Bit = mkOption {
type = types.bool;
default = false;
description = "Enable 32-bit graphics libraries (needed for some games).";
};
extraPackages = mkOption {
type = types.listOf types.package;
default = [];
description = "Extra packages to add to hardware.graphics.extraPackages.";
};
};
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
# Set xserver video driver
services.xserver.videoDrivers = [ "nvidia" ];
# Graphics configuration
hardware.graphics = {
enable = cfg.graphics.enable;
enable32Bit = cfg.graphics.enable32Bit;
extraPackages = cfg.graphics.extraPackages;
};
# NVIDIA driver configuration
hardware.nvidia = {
modesetting.enable = cfg.modesetting;
nvidiaSettings = cfg.nvidiaSettings;
open = cfg.open;
package = config.boot.kernelPackages.nvidiaPackages.${cfg.package};
powerManagement.enable = cfg.powerManagement.enable;
powerManagement.finegrained = cfg.powerManagement.finegrained;
};
# Additional packages for nvidia support
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
libva-utils libva-utils
nvidia-vaapi-driver nvidia-vaapi-driver

View File

@@ -1,22 +0,0 @@
#!/usr/bin/env bash
# Build Live USB ISO from flake configuration
# Creates an uncompressed ISO suitable for Ventoy and other USB boot tools
# Usage: nix run .#build-liveusb
# Or: ./scripts/build-liveusb.sh
set -euo pipefail
REPO_ROOT="${REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
echo "Building Live USB ISO..."
nix build "${REPO_ROOT}#nixosConfigurations.live-usb.config.system.build.isoImage" --show-trace
if ls "${REPO_ROOT}/result/iso/"*.iso 1> /dev/null 2>&1; then
iso_file=$(ls "${REPO_ROOT}/result/iso/"*.iso)
echo "Build complete!"
echo "ISO location: $iso_file"
echo "Ready for Ventoy or dd to USB"
else
echo "Build failed - no ISO file found"
exit 1
fi

View File

@@ -1,6 +1,30 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--help|-h)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Rotate to the next wallpaper in the configured list."
echo ""
echo "This script increments the currentIndex in home/wallpapers/default.nix,"
echo "cycling through available wallpapers. Rebuild your system to apply"
echo "the new wallpaper."
echo ""
echo "Options:"
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 # Colors for output
RED='\033[0;31m' RED='\033[0;31m'
GREEN='\033[0;32m' GREEN='\033[0;32m'

View File

@@ -1,6 +1,30 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--help|-h)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Update Doom Emacs to the latest commit from the doomemacs repository."
echo ""
echo "This script fetches the latest commit SHA from the default branch,"
echo "updates the rev and sha256 in home/roles/emacs/default.nix, and"
echo "prepares the configuration for a system rebuild."
echo ""
echo "Options:"
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 # Colors for output
RED='\033[0;31m' RED='\033[0;31m'
GREEN='\033[0;32m' GREEN='\033[0;32m'

View File

@@ -1,6 +1,35 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--help|-h)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Perform a major upgrade of the NixOS configuration."
echo ""
echo "This script runs the following steps:"
echo " 1. Update all flake inputs (nix flake update)"
echo " 2. Update Doom Emacs to the latest commit"
echo " 3. Update Claude Code to the latest version"
echo " 4. Rotate to the next wallpaper"
echo ""
echo "After completion, review changes with 'git diff' and rebuild"
echo "your system with 'sudo nixos-rebuild switch --flake .'"
echo ""
echo "Options:"
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 # Colors for output
RED='\033[0;31m' RED='\033[0;31m'
GREEN='\033[0;32m' GREEN='\033[0;32m'