Compare commits
216 Commits
codex/hypr
...
colonelpan
| Author | SHA1 | Date | |
|---|---|---|---|
| 686023e006 | |||
| f12285b7f7 | |||
| 0efb55f23f | |||
| 30fb74b13b | |||
| 9bb090bb35 | |||
| 9d09b33e3e | |||
| 8a00f33c75 | |||
| 7b9031d85f | |||
| 6216b54bfc | |||
| 01895cf518 | |||
| ae67cd4ca3 | |||
| b41a1d8e36 | |||
| 9bdc56c207 | |||
| 428ee71396 | |||
| d936b477cd | |||
| d552b3f89f | |||
| f755db41f5 | |||
| 3144fab895 | |||
| 2a3243b240 | |||
| 1869d3af8d | |||
| fe733a9eb4 | |||
| 7058c68e56 | |||
| 68be1cdd09 | |||
| da7a946d31 | |||
| b0df8ef27f | |||
| 4681f49d81 | |||
| 3ee11bcc14 | |||
| 2cfdb47469 | |||
| e0905eb651 | |||
| 5b4f605145 | |||
| 0336aa6e53 | |||
| ad567c3e3f | |||
| 3cb49b51bc | |||
| bd6e8d4e30 | |||
| 7713ad07bd | |||
| a5e3e650ae | |||
| 53becf8cc7 | |||
| 4e98850276 | |||
| 8054fce6a3 | |||
| 563208d03b | |||
| d29c361a9e | |||
| cd18fc2056 | |||
| 39b68274e3 | |||
| a2609b6f5b | |||
| 1955bbed68 | |||
| 942b987cc7 | |||
| fc280676f5 | |||
| dce3666521 | |||
| f3649945cb | |||
| 994291b969 | |||
| ec00711c85 | |||
| 16aa6ed735 | |||
| f36cbe0207 | |||
| 1c0377f3ad | |||
| 6290679406 | |||
| 18ec8a7809 | |||
| d21177b29c | |||
| 395f580645 | |||
| a957e78e25 | |||
| a4f648fef8 | |||
| 5eaaa39527 | |||
| 1ec67b7892 | |||
| c75cf6c29c | |||
| 5aa543209d | |||
| 7276109962 | |||
| 87422afae3 | |||
| ab49f6c079 | |||
| e6e0cd6d5e | |||
| 59fc652eab | |||
| 83ab75a12c | |||
| 85118f187e | |||
| 1da7188781 | |||
| bdd95370bd | |||
| 48369966b4 | |||
| 6bdfcb0c8d | |||
| f94572bda0 | |||
| 267bd10095 | |||
| 897c97c269 | |||
| d0f500daa8 | |||
| e740a657ab | |||
| 1f2a38a8f7 | |||
| 3da55b59d2 | |||
| 6ed6663b72 | |||
| 1d22e827b2 | |||
| 11cd44b3f5 | |||
| 8afbbce109 | |||
| 415b65d0ee | |||
| 66bbdab675 | |||
| 8ed33fc7e8 | |||
| ef3d19f1a4 | |||
| 7e07e768da | |||
| c368f98e9f | |||
| aee236e532 | |||
| acea28cc54 | |||
| 272e71a37c | |||
| 8c61bc4cee | |||
| ce7fd6b7a0 | |||
| 6d0c29a743 | |||
| 38a696cff2 | |||
| 4cc6bee526 | |||
| 1c9e470ff6 | |||
| 495a5cbca2 | |||
| 964ed7584e | |||
| be1ec8556c | |||
| b2942e2a07 | |||
| 34fd17a6a2 | |||
| 4a245306ed | |||
| 30a0ae47a8 | |||
| 2b3a600b1b | |||
| f6ab902015 | |||
| 7069d0af10 | |||
| b1a52b0401 | |||
| d260b7622c | |||
| 06eed9281d | |||
| 38d57d1c0e | |||
| 3e14320f36 | |||
| 6018cc6f1d | |||
| d90a6c7c63 | |||
| 507a306cbf | |||
| 44363cf0fb | |||
| 1b06280cb9 | |||
| 7c1185fa6e | |||
| 4188a6c0d8 | |||
| e6a5464520 | |||
| 58a55209fa | |||
| 9baa4c3d44 | |||
| 422826a62e | |||
| 32e69cbd01 | |||
| 59c7d4ba11 | |||
| 531ad1602b | |||
| 67859a5436 | |||
| b8cbf387fa | |||
| 29a0af4bde | |||
| 03536fbbb1 | |||
| 511d643063 | |||
| 81d4496fe4 | |||
| d6eb0f2e6c | |||
| 05bce81158 | |||
| 51de81b242 | |||
| 758a35c836 | |||
| 187edef30f | |||
| 3338b86b48 | |||
| 63f9ead9a3 | |||
| 4852985801 | |||
| e8612e3df0 | |||
| 798d5c0742 | |||
| 60fa81fecf | |||
| 78842c242d | |||
| e0b3eb9da8 | |||
| 2acbd0937f | |||
| fbec3e7380 | |||
| e4d4547bf1 | |||
| a81d1d2caf | |||
| 0105b52b7a | |||
| 715eb1e76d | |||
| 8360419d2c | |||
| 2bacf623cb | |||
| 443dfb0199 | |||
| 07cdc10ef0 | |||
| 850cddeeb0 | |||
| eec9f0ba0e | |||
| ff23cb8da6 | |||
| 79343c8160 | |||
| 1df5c22b75 | |||
| 81318ce0be | |||
| 680f8b4a91 | |||
| b7eb47a71d | |||
| a860b59e3f | |||
| dde547f694 | |||
| bf71d0ee39 | |||
| 2c22ccd01e | |||
| 348560eefe | |||
| 2573928706 | |||
| 18c293ec5f | |||
| 2e523750e2 | |||
| 72c9177f95 | |||
| 4360850f82 | |||
| d99ccdbd0c | |||
| a37780c443 | |||
| 2c53dda524 | |||
| c39c70f6ac | |||
| e407f009db | |||
| eee7434aca | |||
| 54ec7d3f0a | |||
| 0ee6c78de3 | |||
| c11f81cbf8 | |||
| deef8b8a07 | |||
| d57fda3dc9 | |||
| a8dab69126 | |||
| 2fb8951810 | |||
| b74bb07339 | |||
| 87a79e2c8a | |||
| 2d96b71594 | |||
| aed4d24ae7 | |||
| f3a10e0b66 | |||
| ddb854c362 | |||
| 8ae6f0d676 | |||
| 0c75df5085 | |||
| 1c0de36f52 | |||
| 874b83259d | |||
| 378fa8df34 | |||
| 243f64fade | |||
| 96b9b5cd85 | |||
| f2bb9c8278 | |||
| c121e07452 | |||
| 6c2183c9ae | |||
| b72dab7337 | |||
| 35191bedba | |||
| ba06ab1e00 | |||
| 6e21640e58 | |||
| beef3f8b84 | |||
| 875982b6c2 | |||
| 463cb9d24a | |||
| 8c31b53e33 | |||
| eda407c47d | |||
| ce29ee063d |
@@ -4,7 +4,10 @@
|
|||||||
"Bash(rg:*)",
|
"Bash(rg:*)",
|
||||||
"Bash(wmctrl:*)",
|
"Bash(wmctrl:*)",
|
||||||
"Bash(grep:*)",
|
"Bash(grep:*)",
|
||||||
"Bash(hyprctl:*)"
|
"Bash(hyprctl:*)",
|
||||||
|
"Bash(set_multiplexer_title 'dotfiles - Claude desktop icon fix')",
|
||||||
|
"Bash(nix eval *)",
|
||||||
|
"Read(//nix/store/xmgdj0242sc04hybgd3x6w0a7cw7kkwl-system-path/share/applications/**)"
|
||||||
],
|
],
|
||||||
"deny": []
|
"deny": []
|
||||||
}
|
}
|
||||||
|
|||||||
19
.github/workflows/cachix.yml
vendored
19
.github/workflows/cachix.yml
vendored
@@ -1,15 +1,23 @@
|
|||||||
name: Build and Push Cachix (imalison-taffybar)
|
name: Build and Push Cachix
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [master]
|
branches: [master]
|
||||||
paths:
|
paths:
|
||||||
- "dotfiles/config/taffybar/**"
|
- "dotfiles/config/taffybar/**"
|
||||||
|
- "dotfiles/config/hypr/**"
|
||||||
|
- "dotfiles/lib/bin/hypr_*"
|
||||||
|
- "dotfiles/lib/bin/hypr*"
|
||||||
|
- "nixos/**"
|
||||||
- ".github/workflows/cachix.yml"
|
- ".github/workflows/cachix.yml"
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [master]
|
branches: [master]
|
||||||
paths:
|
paths:
|
||||||
- "dotfiles/config/taffybar/**"
|
- "dotfiles/config/taffybar/**"
|
||||||
|
- "dotfiles/config/hypr/**"
|
||||||
|
- "dotfiles/lib/bin/hypr_*"
|
||||||
|
- "dotfiles/lib/bin/hypr*"
|
||||||
|
- "nixos/**"
|
||||||
- ".github/workflows/cachix.yml"
|
- ".github/workflows/cachix.yml"
|
||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
|
|
||||||
@@ -87,3 +95,12 @@ jobs:
|
|||||||
--no-link \
|
--no-link \
|
||||||
--print-build-logs \
|
--print-build-logs \
|
||||||
./dotfiles/config/taffybar#defaultPackage.x86_64-linux
|
./dotfiles/config/taffybar#defaultPackage.x86_64-linux
|
||||||
|
|
||||||
|
- name: Build Hyprland stuff
|
||||||
|
run: |
|
||||||
|
set -euxo pipefail
|
||||||
|
nix build \
|
||||||
|
--no-link \
|
||||||
|
--print-build-logs \
|
||||||
|
./nixos#hyprland-stuff \
|
||||||
|
--override-input railbird-secrets path:./nixos/ci/railbird-secrets-stub
|
||||||
|
|||||||
24
.gitignore
vendored
24
.gitignore
vendored
@@ -49,5 +49,29 @@ gotools
|
|||||||
|
|
||||||
# Local tool state
|
# Local tool state
|
||||||
/.playwright-cli/
|
/.playwright-cli/
|
||||||
|
/nixos/.playwright-cli/
|
||||||
/nixos/action-cache-dir/
|
/nixos/action-cache-dir/
|
||||||
/dotfiles/config/taffybar/dbus-menu/
|
/dotfiles/config/taffybar/dbus-menu/
|
||||||
|
|
||||||
|
# On nix-darwin, ~/.claude resolves into dotfiles/claude (HM out-of-store
|
||||||
|
# symlink), so the claude-history repo and live Claude Code state are nested
|
||||||
|
# inside this worktree there. Keep everything but the managed config out of
|
||||||
|
# the dotfiles repo so chat history can never be committed here.
|
||||||
|
/dotfiles/claude/*
|
||||||
|
!/dotfiles/claude/CLAUDE.md
|
||||||
|
!/dotfiles/claude/settings.json
|
||||||
|
!/dotfiles/claude/settings.local.json
|
||||||
|
!/dotfiles/claude/settings.local.json.example
|
||||||
|
# Expose the shared agent skills library to Claude Code, which only reads
|
||||||
|
# ~/.claude/skills. This is a symlink to ../agents/skills (the canonical
|
||||||
|
# store, also surfaced at ~/.agents/skills); without the allowlist the
|
||||||
|
# /dotfiles/claude/* rule above keeps it out of the flake source.
|
||||||
|
!/dotfiles/claude/skills
|
||||||
|
|
||||||
|
# Same story for Codex: ~/.codex resolves into dotfiles/codex on nix-darwin,
|
||||||
|
# so the codex-history repo and live Codex state nest inside this worktree.
|
||||||
|
# Allowlist only the HM-managed config.
|
||||||
|
/dotfiles/codex/*
|
||||||
|
!/dotfiles/codex/AGENTS.md
|
||||||
|
!/dotfiles/codex/config.toml
|
||||||
|
!/dotfiles/codex/skills
|
||||||
|
|||||||
22
README.org
22
README.org
@@ -31,9 +31,9 @@ published GitHub Pages site is still generated from that document.
|
|||||||
- Container and deployment configuration for personal org-agenda-api instances.
|
- Container and deployment configuration for personal org-agenda-api instances.
|
||||||
|
|
||||||
This is not intended to be a generic starter dotfiles repo. Many modules assume
|
This is not intended to be a generic starter dotfiles repo. Many modules assume
|
||||||
my users, hostnames, hardware, SSH keys, secrets layout, and local checkout path
|
my users, hostnames, hardware, SSH keys, secrets layout, and shared checkout
|
||||||
=(~/dotfiles=). It is still useful as a reference for how the pieces fit
|
path =/srv/dotfiles= on NixOS machines. It is still useful as a reference for
|
||||||
together.
|
how the pieces fit together.
|
||||||
|
|
||||||
* Layout
|
* Layout
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ The broad feature set is assembled by [[file:nixos/configuration.nix][nixos/conf
|
|||||||
Common workflow:
|
Common workflow:
|
||||||
|
|
||||||
#+begin_src sh
|
#+begin_src sh
|
||||||
cd ~/dotfiles/nixos
|
cd /etc/nixos
|
||||||
just switch
|
just switch
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ directly.
|
|||||||
Useful variants:
|
Useful variants:
|
||||||
|
|
||||||
#+begin_src sh
|
#+begin_src sh
|
||||||
cd ~/dotfiles/nixos
|
cd /etc/nixos
|
||||||
just switch-remote
|
just switch-remote
|
||||||
just switch-local-taffybar
|
just switch-local-taffybar
|
||||||
just remote-switch <host>
|
just remote-switch <host>
|
||||||
@@ -86,8 +86,8 @@ just remote-switch <host>
|
|||||||
Build/check examples:
|
Build/check examples:
|
||||||
|
|
||||||
#+begin_src sh
|
#+begin_src sh
|
||||||
nix flake check ~/dotfiles/nixos
|
nix flake check /etc/nixos
|
||||||
nix build ~/dotfiles/nixos#nixosConfigurations.strixi-minaj.config.system.build.toplevel
|
nix build /etc/nixos#nixosConfigurations.strixi-minaj.config.system.build.toplevel
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
The flake also exposes package/check outputs for Hyprland plugins and a
|
The flake also exposes package/check outputs for Hyprland plugins and a
|
||||||
@@ -102,7 +102,7 @@ nix-darwin, nix-homebrew, Home Manager, agenix, and the shared package list in
|
|||||||
Common workflow:
|
Common workflow:
|
||||||
|
|
||||||
#+begin_src sh
|
#+begin_src sh
|
||||||
cd ~/dotfiles/nix-darwin
|
cd /srv/dotfiles/nix-darwin
|
||||||
just switch
|
just switch
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ behind nginx with ACME certificates and Podman.
|
|||||||
To enter the deployment shell:
|
To enter the deployment shell:
|
||||||
|
|
||||||
#+begin_src sh
|
#+begin_src sh
|
||||||
nix develop ~/dotfiles/nixos#org-agenda-api
|
nix develop /etc/nixos#org-agenda-api
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
* Secrets
|
* Secrets
|
||||||
@@ -201,7 +201,9 @@ Some third-party or upstream projects are tracked as submodules:
|
|||||||
Clone with submodules when bootstrapping a new checkout:
|
Clone with submodules when bootstrapping a new checkout:
|
||||||
|
|
||||||
#+begin_src sh
|
#+begin_src sh
|
||||||
git clone --recurse-submodules git@github.com:IvanMalison/dotfiles.git ~/dotfiles
|
git clone --recurse-submodules git@github.com:IvanMalison/dotfiles.git /tmp/dotfiles
|
||||||
|
cd /tmp/dotfiles
|
||||||
|
just setup-shared-dotfiles
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
This repo also contains project-local git worktrees under =.worktrees/= during
|
This repo also contains project-local git worktrees under =.worktrees/= during
|
||||||
|
|||||||
33
docs/shared-dotfiles.md
Normal file
33
docs/shared-dotfiles.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Shared Dotfiles Worktree
|
||||||
|
|
||||||
|
This repo is intended to live at `/srv/dotfiles` on shared NixOS machines.
|
||||||
|
Home Manager links user dotfiles to that shared checkout instead of to
|
||||||
|
`$HOME/dotfiles`, so the links work consistently for every managed user.
|
||||||
|
|
||||||
|
Set it up from any existing checkout:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
just setup-shared-dotfiles
|
||||||
|
```
|
||||||
|
|
||||||
|
The setup command:
|
||||||
|
|
||||||
|
- copies the current checkout to `/srv/dotfiles` when needed
|
||||||
|
- makes the checkout readable by everyone
|
||||||
|
- makes it writable by the `wheel` group
|
||||||
|
- sets directory setgid/default ACLs so new files stay group-writable
|
||||||
|
- configures Git for group sharing
|
||||||
|
- creates `/etc/nixos -> /srv/dotfiles/nixos` when `/etc/nixos` is absent or already a symlink
|
||||||
|
|
||||||
|
Use a different target or group when needed:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
just setup-shared-dotfiles --target /srv/dotfiles --group wheel
|
||||||
|
```
|
||||||
|
|
||||||
|
If a machine has a real `/etc/nixos` directory and you want to replace it with
|
||||||
|
the shared checkout symlink:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
just setup-shared-dotfiles --force-etc-nixos
|
||||||
|
```
|
||||||
@@ -8,6 +8,65 @@ This document describes the tiling window manager experience I am targeting.
|
|||||||
- Important: expected for parity, but a rough first version is acceptable.
|
- Important: expected for parity, but a rough first version is acceptable.
|
||||||
- Nice: useful polish or compatibility.
|
- Nice: useful polish or compatibility.
|
||||||
|
|
||||||
|
Priority describes the target experience, not implementation order. A first
|
||||||
|
usable implementation may ship a smaller daily-driver subset as long as it does
|
||||||
|
not choose designs that block required behavior later.
|
||||||
|
|
||||||
|
## Implementation Phases
|
||||||
|
|
||||||
|
Phase 1 should establish the core daily-driver loop:
|
||||||
|
|
||||||
|
- Global numbered workspaces across monitors.
|
||||||
|
- Dynamic equal-width columns and tabbed/fullscreen-style layout.
|
||||||
|
- Directional window focus, directional movement, and directional monitor
|
||||||
|
focus.
|
||||||
|
- Direct numbered workspace move/follow bindings.
|
||||||
|
- Focus-follows-mouse and mouse-follows-focus.
|
||||||
|
- Basic rofi launcher, terminal, close, reload, and session-exit bindings.
|
||||||
|
- Basic status-bar workspace and focused-window state.
|
||||||
|
|
||||||
|
Phase 2 should restore high-frequency workflow parity:
|
||||||
|
|
||||||
|
- Per-monitor workspace history and history cycling.
|
||||||
|
- Scratchpads.
|
||||||
|
- Minimization.
|
||||||
|
- Go-to-window, bring-window, and replace-window pickers.
|
||||||
|
- Browser raise-or-spawn and class-aware gather workflows.
|
||||||
|
- Status-bar window lists, class/title/icon metadata, and special-workspace
|
||||||
|
filtering.
|
||||||
|
|
||||||
|
Phase 3 should add visual discovery and polish:
|
||||||
|
|
||||||
|
- Visual window overview.
|
||||||
|
- Visual workspace expose.
|
||||||
|
- Overview go/bring/replace actions.
|
||||||
|
- Smart gaps, smart borders, dimming, wallpaper, lock, screenshot, clipboard,
|
||||||
|
DDC/input switching, and other session utilities.
|
||||||
|
|
||||||
|
## Terms and Semantics
|
||||||
|
|
||||||
|
- First-class operation means the action has a direct command or binding. It
|
||||||
|
does not require opening a picker, manually moving focus, or chaining multiple
|
||||||
|
unrelated commands.
|
||||||
|
- Preserving useful focus means the operation leaves keyboard focus in a
|
||||||
|
predictable place. Non-following moves keep focus on the source monitor or
|
||||||
|
source workspace. Following moves focus the moved window on its destination.
|
||||||
|
- Directional focus uses visible window geometry when windows have distinct
|
||||||
|
rectangles. In tabbed or fullscreen-style layouts where geometry overlaps,
|
||||||
|
directional focus may use a stable logical order instead, but repeated
|
||||||
|
directional actions must cycle predictably through the windows.
|
||||||
|
- Near-fullscreen scratchpads are centered floating windows large enough to
|
||||||
|
dominate the current monitor without taking compositor fullscreen state.
|
||||||
|
- Robust scratchpad behavior means toggling a named scratchpad finds or
|
||||||
|
launches the intended app even when the app starts slowly, changes class or
|
||||||
|
title after launch, is minimized, or is currently on another workspace.
|
||||||
|
- Approximate window position means enough geometry or ordering information for
|
||||||
|
status-bar window strips and expose-like previews. Pixel-perfect compositor
|
||||||
|
geometry is useful but not required.
|
||||||
|
- Normal workspaces are the bounded user-facing workspaces. Special,
|
||||||
|
scratchpad, minimized, hidden, internal, and out-of-range workspaces are not
|
||||||
|
normal workspaces.
|
||||||
|
|
||||||
## Modifier Terminology
|
## Modifier Terminology
|
||||||
|
|
||||||
- `Super` names the physical modifier key often labeled Windows, Command, GUI,
|
- `Super` names the physical modifier key often labeled Windows, Command, GUI,
|
||||||
@@ -96,18 +155,10 @@ Required behavior:
|
|||||||
- Directional monitor focus is available.
|
- Directional monitor focus is available.
|
||||||
- Directional window movement between monitors is available.
|
- Directional window movement between monitors is available.
|
||||||
- Moving the focused window to an empty workspace on the monitor in a direction
|
- Moving the focused window to an empty workspace on the monitor in a direction
|
||||||
remains required behavior, but it should not require an extra `Hyper`
|
is available.
|
||||||
modifier beyond `Shift`.
|
- Directional bindings are defined in the Binding Appendix. Required
|
||||||
- `Super+w/a/s/d` focuses windows directionally.
|
directional actions must not depend on `Hyper+Ctrl`, because `Ctrl` may
|
||||||
- `Super+Shift+w/a/s/d` swaps or moves the focused window directionally.
|
already be part of the fallback `Hyper` chord.
|
||||||
- `Super+Ctrl+w/a/s/d` moves the focused window to the monitor in that
|
|
||||||
direction while preserving useful focus.
|
|
||||||
- `Super+Ctrl+Shift+w/a/s/d` moves the focused window to an empty workspace on
|
|
||||||
the monitor in that direction.
|
|
||||||
- `Hyper+w/a/s/d` focuses monitors directionally.
|
|
||||||
- `Hyper+Shift+w/a/s/d` swaps or moves windows between monitors directionally.
|
|
||||||
- Directional focus in tabbed/fullscreen mode should cycle predictably through
|
|
||||||
windows even though their screen geometry overlaps.
|
|
||||||
|
|
||||||
Important behavior:
|
Important behavior:
|
||||||
|
|
||||||
@@ -207,9 +258,12 @@ Required behavior:
|
|||||||
- A named scratchpad exists for spotify.
|
- A named scratchpad exists for spotify.
|
||||||
- A named scratchpad exists for transmission.
|
- A named scratchpad exists for transmission.
|
||||||
- A named scratchpad exists for volume.
|
- A named scratchpad exists for volume.
|
||||||
|
- A named scratchpad exists for x.com.
|
||||||
- Scratchpads appear near-fullscreen and centered by default.
|
- Scratchpads appear near-fullscreen and centered by default.
|
||||||
|
- The codex, claude, and x.com scratchpads can be tiled into the normal
|
||||||
|
workspace when desired, while retaining their summon/dismiss toggles.
|
||||||
- Toggling a scratchpad deactivates fullscreen/tabbed state first.
|
- Toggling a scratchpad deactivates fullscreen/tabbed state first.
|
||||||
- Scratchpads are hidden from normal workspace and window listings.
|
- Floating scratchpads are hidden from normal workspace and window listings.
|
||||||
|
|
||||||
Important behavior:
|
Important behavior:
|
||||||
|
|
||||||
@@ -329,8 +383,7 @@ Required behavior:
|
|||||||
- `Super+b` opens the bring-window picker.
|
- `Super+b` opens the bring-window picker.
|
||||||
- `Super+Shift+b` opens the replace-window picker.
|
- `Super+Shift+b` opens the replace-window picker.
|
||||||
- `Super+Shift+e` moves the focused window to the next empty workspace and
|
- `Super+Shift+e` moves the focused window to the next empty workspace and
|
||||||
follows it. This is the target replacement for the older `Super+Shift+h`
|
follows it.
|
||||||
binding.
|
|
||||||
- `Hyper+e` focuses the next empty workspace.
|
- `Hyper+e` focuses the next empty workspace.
|
||||||
- `Hyper+1` toggles inactive-window opacity reduction for the focused window.
|
- `Hyper+1` toggles inactive-window opacity reduction for the focused window.
|
||||||
- `Hyper+5` swaps the current workspace with a selected workspace.
|
- `Hyper+5` swaps the current workspace with a selected workspace.
|
||||||
@@ -366,10 +419,10 @@ Required behavior:
|
|||||||
- `Super+Shift+w/a/s/d` swaps or moves the focused window directionally.
|
- `Super+Shift+w/a/s/d` swaps or moves the focused window directionally.
|
||||||
- `Super+Ctrl+w/a/s/d` moves the focused window to the monitor in that
|
- `Super+Ctrl+w/a/s/d` moves the focused window to the monitor in that
|
||||||
direction while preserving useful focus.
|
direction while preserving useful focus.
|
||||||
|
- `Super+Ctrl+Shift+w/a/s/d` moves the focused window to an empty workspace on
|
||||||
|
the monitor in that direction.
|
||||||
- `Hyper+w/a/s/d` focuses monitors directionally.
|
- `Hyper+w/a/s/d` focuses monitors directionally.
|
||||||
- `Hyper+Shift+w/a/s/d` swaps or moves windows between monitors directionally.
|
- `Hyper+Shift+w/a/s/d` swaps or moves windows between monitors directionally.
|
||||||
- Moving the focused window to an empty workspace on the monitor in a direction
|
|
||||||
remains required behavior, but it should not require a `Hyper+Ctrl` binding.
|
|
||||||
- `Super+z` focuses the next monitor.
|
- `Super+z` focuses the next monitor.
|
||||||
- `Super+Shift+z` moves the focused window to the next monitor.
|
- `Super+Shift+z` moves the focused window to the next monitor.
|
||||||
|
|
||||||
@@ -387,13 +440,15 @@ Required behavior:
|
|||||||
|
|
||||||
Required behavior:
|
Required behavior:
|
||||||
|
|
||||||
- `Super+Alt+c` toggles the codex scratchpad.
|
- `Super+Alt+c` toggles the primary AI scratchpad.
|
||||||
|
- `Super+Alt+Shift+c` toggles the backup AI scratchpad.
|
||||||
- `Super+Alt+e` toggles the element scratchpad.
|
- `Super+Alt+e` toggles the element scratchpad.
|
||||||
- `Super+Alt+h` toggles the htop scratchpad.
|
- `Super+Alt+h` toggles the htop scratchpad.
|
||||||
- `Super+Alt+k` toggles the slack scratchpad.
|
- `Super+Alt+k` toggles the slack scratchpad.
|
||||||
- `Super+Alt+s` toggles the spotify scratchpad.
|
- `Super+Alt+s` toggles the spotify scratchpad.
|
||||||
- `Super+Alt+t` toggles the transmission scratchpad.
|
- `Super+Alt+t` toggles the transmission scratchpad.
|
||||||
- `Super+Alt+v` toggles the volume scratchpad.
|
- `Super+Alt+v` toggles the volume scratchpad.
|
||||||
|
- `Super+Alt+x` toggles the x.com scratchpad.
|
||||||
|
|
||||||
Important behavior:
|
Important behavior:
|
||||||
|
|
||||||
@@ -412,6 +467,8 @@ Required behavior:
|
|||||||
- `Hyper+p` opens the password picker with `rofi-pass`.
|
- `Hyper+p` opens the password picker with `rofi-pass`.
|
||||||
- `Hyper+h` opens the screenshot tool with the compositor/session-appropriate
|
- `Hyper+h` opens the screenshot tool with the compositor/session-appropriate
|
||||||
screenshot command.
|
screenshot command.
|
||||||
|
- `Hyper+n` opens a Codex Desktop project picker and starts a new thread in
|
||||||
|
the selected saved project root.
|
||||||
- `Hyper+c` opens the Codex launcher with `rofi_tmcodex.sh`.
|
- `Hyper+c` opens the Codex launcher with `rofi_tmcodex.sh`.
|
||||||
- `Hyper+Shift+c` opens the Codex launcher with `tmcodex resume`.
|
- `Hyper+Shift+c` opens the Codex launcher with `tmcodex resume`.
|
||||||
- `Hyper+k` opens the process killer with `rofi_kill_process.sh`.
|
- `Hyper+k` opens the process killer with `rofi_kill_process.sh`.
|
||||||
@@ -435,3 +492,8 @@ Important behavior:
|
|||||||
compositor-appropriate implementation.
|
compositor-appropriate implementation.
|
||||||
- Session-destructive operations use shifted or otherwise harder-to-hit
|
- Session-destructive operations use shifted or otherwise harder-to-hit
|
||||||
variants.
|
variants.
|
||||||
|
|
||||||
|
## Migration Notes
|
||||||
|
|
||||||
|
- `Super+Shift+e` is the target replacement for the older `Super+Shift+h`
|
||||||
|
move-to-next-empty-workspace-and-follow binding.
|
||||||
|
|||||||
@@ -1,23 +1,9 @@
|
|||||||
# Agentic Session Preferences
|
# Agentic Session Preferences
|
||||||
|
|
||||||
## Multiplexer session titling
|
## Sharing dev-server / preview links
|
||||||
- If the `TMUX` or `ZELLIJ` environment variable is set, treat this chat as the controller for the current tmux or zellij session.
|
- When sharing a local server or preview URL, always prefer this machine's Tailscale address over `127.0.0.1`/`localhost`/LAN IPs, so the link opens from any device on the tailnet.
|
||||||
- Use `set_multiplexer_title '<project> - <task>'` to update the title. The command detects tmux vs. zellij internally, prefers tmux when both are present, and no-ops outside a multiplexer.
|
- Get the address with `tailscale ip -4` (the `100.x.y.z` IP) or the MagicDNS hostname from `tailscale status`. Prefer the `100.x` IP when a server's `allowedHosts` might reject a hostname.
|
||||||
- Maintain a session/window/pane title that describes the durable purpose of the overall exchange.
|
- Start the server bound to all interfaces (e.g. vite's `--host 0.0.0.0` / a `dev:lan` script), not just localhost, or the Tailscale link won't connect. Verify reachability (`curl` the `100.x` URL) before handing it over.
|
||||||
- Prefer automatic titling: infer a concise <task> from the current user request and the existing chat context without asking.
|
|
||||||
- Choose holistic titles over granular turn summaries. The title should answer "what has this chat been for?" rather than describe the latest command, substep, clarification, or follow-up message.
|
|
||||||
- Preserve the existing <task> when the new user turn is a continuation, status check, refinement, or implementation detail within the same broader objective.
|
|
||||||
- Title format: "<project> - <task>".
|
|
||||||
- <project> is the basename of the current project directory.
|
|
||||||
- Prefer git repo root basename if available; otherwise use basename of the current working directory.
|
|
||||||
- <task> is a short, user-friendly description of what we are doing.
|
|
||||||
- Ask for a short descriptive <task> only when the task is ambiguous or you are not confident in an inferred title.
|
|
||||||
- When the broader objective changes substantially, update the <task> automatically if clear; otherwise ask for an updated <task>.
|
|
||||||
- When a title is provided or updated, immediately run `set_multiplexer_title '<project> - <task>'`; do not call raw tmux or zellij rename commands unless debugging the helper itself.
|
|
||||||
- For Claude Code sessions, a UserPromptSubmit hook may initialize titles automatically from the first substantive prompt, but it should not keep overwriting an established same-project title with the latest prompt.
|
|
||||||
|
|
||||||
## Pane usage
|
|
||||||
- Do not create extra panes or windows unless the user asks.
|
|
||||||
|
|
||||||
## Git worktrees
|
## Git worktrees
|
||||||
- Default to creating git worktrees under a project-local `.worktrees/` directory at the repository root.
|
- Default to creating git worktrees under a project-local `.worktrees/` directory at the repository root.
|
||||||
@@ -25,8 +11,14 @@
|
|||||||
- Create `.worktrees/` if needed before running `git worktree add`.
|
- Create `.worktrees/` if needed before running `git worktree add`.
|
||||||
- Only use a non-`.worktrees/` location when the user explicitly asks for a different path.
|
- Only use a non-`.worktrees/` location when the user explicitly asks for a different path.
|
||||||
|
|
||||||
|
## GitHub pull requests
|
||||||
|
- Default to creating pull requests as ready for review, not drafts.
|
||||||
|
- Do not add a `[codex]` prefix or any other agent/tool prefix to pull request titles.
|
||||||
|
- Create a draft pull request only when the user explicitly asks for a draft or when the remote platform requires draft status.
|
||||||
|
- If using a helper, skill, or CLI wrapper that defaults to draft PRs, override that default before creating the PR.
|
||||||
|
|
||||||
## NixOS workflow
|
## NixOS workflow
|
||||||
- This system is managed with a Nix flake at `~/dotfiles/nixos`.
|
- This system is managed with a Nix flake at `/srv/dotfiles/nixos`.
|
||||||
- Use `just switch` from that directory for rebuilds instead of plain `nixos-rebuild`.
|
- Use `just switch` from that directory for rebuilds instead of plain `nixos-rebuild`.
|
||||||
- Host configs live under `machines/`; choose the appropriate host when needed.
|
- Host configs live under `machines/`; choose the appropriate host when needed.
|
||||||
|
|
||||||
@@ -60,23 +52,6 @@
|
|||||||
|
|
||||||
This is an org-mode repository containing personal task management, calendars, habits, and project tracking files. It serves as the central hub for Ivan's personal organization.
|
This is an org-mode repository containing personal task management, calendars, habits, and project tracking files. It serves as the central hub for Ivan's personal organization.
|
||||||
|
|
||||||
## Available Tools
|
|
||||||
|
|
||||||
### Chrome DevTools MCP
|
|
||||||
A browser automation MCP is available for interacting with web pages. Use it to:
|
|
||||||
- Navigate to websites and fill out forms
|
|
||||||
- Take screenshots and snapshots of pages
|
|
||||||
- Click elements, type text, and interact with web UIs
|
|
||||||
- Read page content and extract information
|
|
||||||
- Automate multi-step web workflows (booking, purchasing, form submission, etc.)
|
|
||||||
|
|
||||||
### Google Workspace CLI (`gws`)
|
|
||||||
The local `gws` CLI is available for Google Workspace operations. Use it to:
|
|
||||||
- Search, read, and send Gmail messages
|
|
||||||
- Manage Gmail labels and filters
|
|
||||||
- Download attachments and inspect message payloads
|
|
||||||
- Access Drive, Calendar, Docs, Sheets, and other Google Workspace APIs
|
|
||||||
|
|
||||||
## Credentials via `pass`
|
## Credentials via `pass`
|
||||||
|
|
||||||
Many credentials and personal details are stored in `pass` (the standard unix password manager). There are hundreds of entries covering a wide range of things, so always search before asking the user for information. Use `pass find <keyword>` to search and `pass show <entry>` to retrieve values.
|
Many credentials and personal details are stored in `pass` (the standard unix password manager). There are hundreds of entries covering a wide range of things, so always search before asking the user for information. Use `pass find <keyword>` to search and `pass show <entry>` to retrieve values.
|
||||||
@@ -97,8 +72,6 @@ Examples of what's stored:
|
|||||||
## Guidelines
|
## Guidelines
|
||||||
|
|
||||||
- When filling out forms or making purchases, pull personal info from this file and credentials from `pass` rather than asking the user to provide them.
|
- When filling out forms or making purchases, pull personal info from this file and credentials from `pass` rather than asking the user to provide them.
|
||||||
- For web tasks, prefer using the Chrome DevTools MCP to automate interactions directly.
|
|
||||||
- For email tasks, prefer using `gws gmail` over navigating to Gmail in the browser.
|
|
||||||
- If a task requires a credential not found in `pass`, ask the user rather than guessing.
|
- If a task requires a credential not found in `pass`, ask the user rather than guessing.
|
||||||
- This repo's org files (gtd.org, calendar.org, habits.org, projects.org) contain task and scheduling data. The org-agenda-api skill/service can also be used to query agenda data programmatically.
|
- This repo's org files (gtd.org, calendar.org, habits.org, projects.org) contain task and scheduling data. The org-agenda-api skill/service can also be used to query agenda data programmatically.
|
||||||
|
|
||||||
@@ -124,3 +97,4 @@ Examples of what's stored:
|
|||||||
- `./project-guides/taffybar.md`
|
- `./project-guides/taffybar.md`
|
||||||
- `./project-guides/railbird.md`
|
- `./project-guides/railbird.md`
|
||||||
- `./project-guides/org-emacs-packages.md`
|
- `./project-guides/org-emacs-packages.md`
|
||||||
|
- `./project-guides/subtr-actor-rocket-sense-rlru.md`
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# Subtr Actor / Rocket Sense / rlru constellation
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
- Use this guide for requests involving Rocket League replay parsing, replay analytics, upload flows, or the `rlrml` projects around `subtr-actor`, `rocket-sense`, and `rlru`.
|
||||||
|
- Primary anchors are `subtr-actor` for replay-domain logic, `rocket-sense` for the hosted analytics service, and `rlru` for local replay discovery/upload and PsyNet integration.
|
||||||
|
|
||||||
|
## Related packages/projects (trigger list)
|
||||||
|
- If any of these names are mentioned, open this guide for context.
|
||||||
|
- `subtr-actor`: Rocket League replay processing core and source-of-truth replay domain model.
|
||||||
|
- `rocket-sense`: replay analytics backend and React/Vite web app built on `subtr-actor`.
|
||||||
|
- `rlru`: Rust-first Rocket League replay uploader and desktop client workspace.
|
||||||
|
- `psynet`: Psyonix PsyNet client crate inside the `rlru` workspace.
|
||||||
|
|
||||||
|
## Package inventory
|
||||||
|
- `subtr-actor` repo packages:
|
||||||
|
- Rust crates: `subtr-actor`, `subtr-actor-tools`, `subtr-actor-bakkesmod`, `rl-replay-subtr-actor`.
|
||||||
|
- Python package/crate: `subtr-actor-py` / `subtr_actor`.
|
||||||
|
- npm packages: `@rlrml/subtr-actor`, `@rlrml/player`, `@rlrml/stats-player`.
|
||||||
|
- `rocket-sense` repo packages:
|
||||||
|
- Rust crates: `rocket-sense-server`, `rocket-sense-db`, `rocket-sense-storage`.
|
||||||
|
- Web app package: `rocket-sense-web`.
|
||||||
|
- Vendored packages may appear under `vendor/subtr-actor`; prefer the standalone `subtr-actor` checkout for source-of-truth domain changes unless the user specifically asks about the vendored copy.
|
||||||
|
- `rlru` repo packages:
|
||||||
|
- Rust crates: `rlru`, `psynet`, `rlru-dioxus`.
|
||||||
|
- Apps/binaries: `rlru` CLI and `rlru-dioxus` desktop client.
|
||||||
|
|
||||||
|
## Symlink targets
|
||||||
|
- `./project-links/subtr-actor` -> primary `subtr-actor` repo.
|
||||||
|
- `./project-links/rocket-sense` -> primary `rocket-sense` repo.
|
||||||
|
- `./project-links/rlru` -> primary `rlru` repo.
|
||||||
|
|
||||||
|
## Discovery hints
|
||||||
|
- Start from `~/Projects`.
|
||||||
|
- Common local paths are:
|
||||||
|
- `~/Projects/subtr-actor`
|
||||||
|
- `~/Projects/rocket-sense`
|
||||||
|
- `~/Projects/rlru`
|
||||||
|
- `rocket-sense` may vendor `subtr-actor` under `vendor/subtr-actor`; prefer the standalone `subtr-actor` checkout for source-of-truth replay-domain changes unless the user specifically asks about the vendored copy.
|
||||||
|
|
||||||
|
## Read-first docs
|
||||||
|
- `./project-links/subtr-actor/AGENTS.md`
|
||||||
|
- `./project-links/subtr-actor/README.md`
|
||||||
|
- `./project-links/rocket-sense/AGENTS.md`
|
||||||
|
- `./project-links/rocket-sense/README.md`
|
||||||
|
- `./project-links/rlru/README.md`
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
- Treat `subtr-actor` as the source of truth for replay parsing, frame/state extraction, stats calculators, feature matrices, and JS/WASM replay-player data contracts.
|
||||||
|
- Treat `rocket-sense` as the service/UI layer for replay hosting, metadata, processing state, auth, storage, OpenAPI, and deployed analytics workflows.
|
||||||
|
- Treat `rlru` as the local uploader/client layer for replay discovery, account/auth state, upload destinations, Dioxus desktop UX, and the reusable `psynet` client.
|
||||||
|
- For cross-repo work, check each repo's own `AGENTS.md`, `README.md`, and `justfile` before choosing commands.
|
||||||
@@ -19,6 +19,7 @@ Bundled helpers:
|
|||||||
- Prioritize easy wins first (`nix-collect-garbage`, container prune, Cargo artifacts).
|
- Prioritize easy wins first (`nix-collect-garbage`, container prune, Cargo artifacts).
|
||||||
- Propose destructive actions with expected impact before running them.
|
- Propose destructive actions with expected impact before running them.
|
||||||
- Run destructive actions only after confirmation, unless the user explicitly requests immediate execution of obvious wins.
|
- Run destructive actions only after confirmation, unless the user explicitly requests immediate execution of obvious wins.
|
||||||
|
- For Rust build artifacts, do not repeatedly ask for confirmation before deleting explicit directories literally named `target` after `rust_target_dirs.py delete` validates them. Cargo targets are rebuildable artifacts; when the user asks to clean Rust target directories, validate with the helper, delete with `--yes`, and report the reclaimed space.
|
||||||
- Capture new reusable findings by updating this skill before finishing.
|
- Capture new reusable findings by updating this skill before finishing.
|
||||||
|
|
||||||
## Workflow
|
## Workflow
|
||||||
@@ -77,13 +78,13 @@ Do not start with a blind `find ~ -name target` or with hard-coded roots that ma
|
|||||||
Inventory the biggest candidates:
|
Inventory the biggest candidates:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python /home/imalison/dotfiles/dotfiles/agents/skills/disk-space-cleanup/scripts/rust_target_dirs.py list --min-size 500M --limit 30
|
python /srv/dotfiles/dotfiles/agents/skills/disk-space-cleanup/scripts/rust_target_dirs.py list --min-size 500M --limit 30
|
||||||
```
|
```
|
||||||
|
|
||||||
Focus on stale targets only:
|
Focus on stale targets only:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python /home/imalison/dotfiles/dotfiles/agents/skills/disk-space-cleanup/scripts/rust_target_dirs.py list --min-size 1G --older-than 14 --output tsv
|
python /srv/dotfiles/dotfiles/agents/skills/disk-space-cleanup/scripts/rust_target_dirs.py list --min-size 1G --older-than 14 --output tsv
|
||||||
```
|
```
|
||||||
|
|
||||||
Use `cargo-sweep` when the repo is still active and you want age/toolchain-aware cleanup inside a workspace:
|
Use `cargo-sweep` when the repo is still active and you want age/toolchain-aware cleanup inside a workspace:
|
||||||
@@ -98,13 +99,13 @@ nix run nixpkgs#cargo-sweep -- sweep -r -i <workspace-root>
|
|||||||
Use direct `target/` deletion when inventory shows a discrete stale directory, especially for inactive repos or project-local worktrees. The helper only deletes explicit paths named `target` that are beneath configured roots and a Cargo project:
|
Use direct `target/` deletion when inventory shows a discrete stale directory, especially for inactive repos or project-local worktrees. The helper only deletes explicit paths named `target` that are beneath configured roots and a Cargo project:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python /home/imalison/dotfiles/dotfiles/agents/skills/disk-space-cleanup/scripts/rust_target_dirs.py delete /abs/path/to/target
|
python /srv/dotfiles/dotfiles/agents/skills/disk-space-cleanup/scripts/rust_target_dirs.py delete /abs/path/to/target
|
||||||
python /home/imalison/dotfiles/dotfiles/agents/skills/disk-space-cleanup/scripts/rust_target_dirs.py delete /abs/path/to/target --yes
|
python /srv/dotfiles/dotfiles/agents/skills/disk-space-cleanup/scripts/rust_target_dirs.py delete /abs/path/to/target --yes
|
||||||
```
|
```
|
||||||
|
|
||||||
Recommended sequence:
|
Recommended sequence:
|
||||||
|
|
||||||
1. Run `rust_target_dirs.py list` to see the largest `target/` directories across `~/Projects`, `~/org`, `~/dotfiles`, and other configured roots.
|
1. Run `rust_target_dirs.py list` to see the largest `target/` directories across `~/Projects`, `~/org`, `/srv/dotfiles`, and other configured roots.
|
||||||
2. For active repos, prefer `cargo-sweep` from the workspace root.
|
2. For active repos, prefer `cargo-sweep` from the workspace root.
|
||||||
3. For inactive repos, abandoned branches, and `.worktrees/*/target`, prefer guarded direct deletion of the explicit `target/` directory.
|
3. For inactive repos, abandoned branches, and `.worktrees/*/target`, prefer guarded direct deletion of the explicit `target/` directory.
|
||||||
4. Re-run the list command after each deletion round to show reclaimed space.
|
4. Re-run the list command after each deletion round to show reclaimed space.
|
||||||
@@ -113,7 +114,10 @@ Machine-specific note:
|
|||||||
|
|
||||||
- Project-local `.worktrees/*/target` directories are common cleanup wins on this machine and are easy to miss with the old hard-coded workflow.
|
- Project-local `.worktrees/*/target` directories are common cleanup wins on this machine and are easy to miss with the old hard-coded workflow.
|
||||||
- `cargo-sweep` is installed through the NixOS `code.nix` package set, but stale manually-installed binaries under `~/.cargo/bin` can shadow `/run/current-system/sw/bin/cargo-sweep`. If `cargo sweep` fails with a missing loader or `No such file or directory`, run `type -a cargo-sweep` and remove the stale `~/.cargo/bin/cargo-sweep` entry.
|
- `cargo-sweep` is installed through the NixOS `code.nix` package set, but stale manually-installed binaries under `~/.cargo/bin` can shadow `/run/current-system/sw/bin/cargo-sweep`. If `cargo sweep` fails with a missing loader or `No such file or directory`, run `type -a cargo-sweep` and remove the stale `~/.cargo/bin/cargo-sweep` entry.
|
||||||
- `nixos/imalison.nix` defines a daily user timer, `cargo-sweep-rust-targets.timer`, that runs `cargo-sweep sweep -r --hidden --maxsize 15GB` across `/home/imalison/Projects`, `/home/imalison/org`, and `/home/imalison/dotfiles`.
|
- `cargo-sweep sweep -i/--installed` can fail when `rustup toolchain list` contains stale toolchains whose `rustc` no longer exists. On this machine, `1.68.2-x86_64-unknown-linux-gnu` caused `failed to determine fingerprint ... 'rustc': No such file or directory`.
|
||||||
|
- `/home/imalison/Projects/codex/codex-rs/target` can be dominated by current-looking `target/debug/incremental` data that `cargo-sweep sweep -a` and `--maxsize` report as not removable. If it is stale and space pressure is high, use the guarded `rust_target_dirs.py delete ... --yes` workflow for that explicit target directory.
|
||||||
|
- `/home/imalison/Projects/hypr-workspace-history/target` is a small non-Cargo false positive; the guarded delete workflow correctly rejects it because there is no Cargo project above the directory.
|
||||||
|
- `nixos/imalison.nix` defines a daily user timer, `cargo-sweep-rust-targets.timer`, that runs `cargo-sweep sweep -r --hidden --maxsize 15GB` across `/home/imalison/Projects`, `/home/imalison/org`, and `/srv/dotfiles`.
|
||||||
|
|
||||||
## Step 4: Investigation with `ncdu` and `du`
|
## Step 4: Investigation with `ncdu` and `du`
|
||||||
|
|
||||||
@@ -171,6 +175,11 @@ Machine-specific heavy hitters seen in practice:
|
|||||||
- Validated cleanup pattern: stop `gitea-runner-nix.service`, remove cache/work directories under `/var/lib/private/gitea-runner` (`.cache`, `.gradle`, `action-cache-dir`, `workspace`, stale nested `gitea-runner`, and nested `nix/.cache`/`nix/.local`), recreate `action-cache-dir`, `workspace`, and `.cache` owned by `gitea-runner:gitea-runner`, then restart the service.
|
- Validated cleanup pattern: stop `gitea-runner-nix.service`, remove cache/work directories under `/var/lib/private/gitea-runner` (`.cache`, `.gradle`, `action-cache-dir`, `workspace`, stale nested `gitea-runner`, and nested `nix/.cache`/`nix/.local`), recreate `action-cache-dir`, `workspace`, and `.cache` owned by `gitea-runner:gitea-runner`, then restart the service.
|
||||||
- Preserve registration/config-like files such as `/var/lib/private/gitea-runner/nix/.runner`, `/var/lib/private/gitea-runner/nix/.labels`, `/var/lib/private/gitea-runner/.docker/config.json`, and SSH/Kube material.
|
- Preserve registration/config-like files such as `/var/lib/private/gitea-runner/nix/.runner`, `/var/lib/private/gitea-runner/nix/.labels`, `/var/lib/private/gitea-runner/.docker/config.json`, and SSH/Kube material.
|
||||||
- `~/Projects/*/target` directories can dominate home usage. Recent example candidates included stale `target/` directories under `scrobble-scrubber`, `http-client-vcr`, `http-client`, `subtr-actor`, `http-types`, `subtr-actor-py`, `sdk`, and `async-h1`.
|
- `~/Projects/*/target` directories can dominate home usage. Recent example candidates included stale `target/` directories under `scrobble-scrubber`, `http-client-vcr`, `http-client`, `subtr-actor`, `http-types`, `subtr-actor-py`, `sdk`, and `async-h1`.
|
||||||
|
- 2026-05-26 cleanup: deleting explicit Cargo-backed targets under `~/Projects/{keepbook,subtr-actor,rlru,rocket-sense,boxcars,rumno}` plus stale `subtr-actor/.worktrees/*/target` reclaimed about 65G by helper sizing and moved `/` from 100% used to 89% used. A final all-depth scan left no `~/Projects` Rust `target/` directories over 500M.
|
||||||
|
- 2026-05-26 cleanup: when `cargo test` is actively running in `~/Projects/subtr-actor`, leave `subtr-actor/target` alone and delete only inactive Cargo-backed targets. Deleting `keepbook`, `rlru`, `rocket-sense`, `rumno`, and stale `subtr-actor/.worktrees/*/target` reclaimed about 24.5G by helper sizing.
|
||||||
|
- 2026-05-26 cleanup: `~/Projects/nixpkgs/.worktrees/*/result` symlinks pinned several GiB of Nix closures, and clean registered nixpkgs worktrees were about 460M each. Removing stale `result` symlinks, running GC, and removing clean worktrees while preserving dirty ones moved `/` from 100% used to about 90% used.
|
||||||
|
- 2026-05-27 cleanup: under `~/Projects`, `hypr-workspace-history/target` can be a Rust-style build cache even though the guarded helper rejects it because no `Cargo.toml` is present; inspect and remove that explicit cache manually if present. Preserve `~/Projects/Hyprland/src/layout/target`, which is source code, not a build artifact.
|
||||||
|
- 2026-06-18 cleanup: deleting helper-validated Rust targets under `.worktrees/*/target` and `.claude/worktrees/*/target`, plus stale `~/Projects/lastfm-edit/target`, removed 24 target directories totaling 67.1G by helper sizing and moved `/` from 99% used to 90% used. Remaining large targets were top-level project caches under `keepbook`, `rlru`, `subtr-actor`, `rocket-sense`, `rocket-sense-pr-73-ci`, `rocket-sense-subtr-viewer`, `rocket-sense-controlled-plays`, and `boxcars`.
|
||||||
|
|
||||||
## Step 5: `/nix/store` Deep Dive
|
## Step 5: `/nix/store` Deep Dive
|
||||||
|
|
||||||
@@ -195,7 +204,7 @@ nix-store --gc --print-roots | rg '(ghc|rust)'
|
|||||||
Resolve why a path is retained:
|
Resolve why a path is retained:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
/home/imalison/dotfiles/dotfiles/lib/functions/find_store_path_gc_roots /nix/store/<store-path>
|
/srv/dotfiles/dotfiles/lib/functions/find_store_path_gc_roots /nix/store/<store-path>
|
||||||
nix why-depends <consumer-store-path> <dependency-store-path>
|
nix why-depends <consumer-store-path> <dependency-store-path>
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -204,8 +213,9 @@ Common retention pattern on this machine:
|
|||||||
- Many `.direnv/flake-profile-*` symlinks under `~/Projects` and worktrees keep `nix-shell-env`/`ghc-shell-*` roots alive.
|
- Many `.direnv/flake-profile-*` symlinks under `~/Projects` and worktrees keep `nix-shell-env`/`ghc-shell-*` roots alive.
|
||||||
- Old taffybar constellation repos under `~/Projects` can pin large Haskell closures through `.direnv` and `result` symlinks. Deleting `gtk-sni-tray`, `status-notifier-item`, `dbus-menu`, `dbus-hslogger`, and `gtk-strut` and then rerunning `nix-collect-garbage -d` reclaimed about 11G of store data in one validated run.
|
- Old taffybar constellation repos under `~/Projects` can pin large Haskell closures through `.direnv` and `result` symlinks. Deleting `gtk-sni-tray`, `status-notifier-item`, `dbus-menu`, `dbus-hslogger`, and `gtk-strut` and then rerunning `nix-collect-garbage -d` reclaimed about 11G of store data in one validated run.
|
||||||
- `find_store_path_gc_roots` is especially useful for proving GHC retention: many large `ghc-9.10.3-with-packages` paths are unique per project, while the base `ghc-9.10.3` and docs paths are shared.
|
- `find_store_path_gc_roots` is especially useful for proving GHC retention: many large `ghc-9.10.3-with-packages` paths are unique per project, while the base `ghc-9.10.3` and docs paths are shared.
|
||||||
- NixOS system generations and a repo-root `nixos/result` symlink can pin multiple Android Studio and Android SDK versions. Check `/nix/var/nix/profiles/system-*-link`, `/run/current-system`, `/run/booted-system`, and `~/dotfiles/nixos/result` before assuming Android paths are pinned by project shells.
|
- NixOS system generations and a repo-root `nixos/result` symlink can pin multiple Android Studio and Android SDK versions. Check `/nix/var/nix/profiles/system-*-link`, `/run/current-system`, `/run/booted-system`, and `/srv/dotfiles/nixos/result` before assuming Android paths are pinned by project shells.
|
||||||
- `~/Projects/railbird-mobile/.direnv/flake-profile-*` can pin large Android SDK system images. Removing stale direnv profiles there is a more targeted first step than deleting Android store paths directly.
|
- `~/Projects/railbird-mobile/.direnv/flake-profile-*` can pin large Android SDK system images. Removing stale direnv profiles there is a more targeted first step than deleting Android store paths directly.
|
||||||
|
- 2026-05-27 Railbird GHC audit: the Railbird backend flake did not explicitly reference Haskell, but its dev shell had derivation-time GHC edges through `inputs.secrets.devShells.${system}.default -> agenix -> shellcheck -> ShellCheck -> ghc` and through `shell-packages.nix`'s `rdma-core -> pandoc-cli -> ghc`. Railbird Mobile had similar non-app-code GHC edges through `inputs.secrets`/`agenix` and `nixGLIntel -> shellcheck`. The `railbird/gql` and `railbird-mobile/src/gql` shells did not show GHC edges in their derivation graphs, only Rust/Cargo build tooling from packages such as `just`.
|
||||||
- For a repeatable `/nix/store` `ncdu` snapshot without driving the TUI, export and inspect it:
|
- For a repeatable `/nix/store` `ncdu` snapshot without driving the TUI, export and inspect it:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -240,7 +250,7 @@ nix-store --gc --print-roots | rg '/\\.direnv/flake-profile-' | awk -F' -> ' '{p
|
|||||||
|
|
||||||
- Do not delete user files directly unless explicitly requested.
|
- Do not delete user files directly unless explicitly requested.
|
||||||
- Prefer cleanup tools that understand ownership/metadata (`nix`, `docker`, `podman`, `cargo-sweep`) over `rm -rf`.
|
- Prefer cleanup tools that understand ownership/metadata (`nix`, `docker`, `podman`, `cargo-sweep`) over `rm -rf`.
|
||||||
- For Rust build artifacts, deleting an explicit directory literally named `target` is acceptable when it is discovered by the bundled helper; Cargo will rebuild it.
|
- For Rust build artifacts, deleting an explicit directory literally named `target` is acceptable when it is discovered and validated by the bundled helper; Cargo will rebuild it. Do not double-check with the user after helper validation when the active request is Rust target cleanup.
|
||||||
- Present a concise “proposed actions” list before high-impact deletes.
|
- Present a concise “proposed actions” list before high-impact deletes.
|
||||||
- If uncertain whether data is needed, stop at investigation and ask.
|
- If uncertain whether data is needed, stop at investigation and ask.
|
||||||
|
|
||||||
|
|||||||
@@ -3,4 +3,4 @@
|
|||||||
|
|
||||||
/home/imalison/Projects
|
/home/imalison/Projects
|
||||||
/home/imalison/org
|
/home/imalison/org
|
||||||
/home/imalison/dotfiles
|
/srv/dotfiles
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ description: Use when investigating production org-agenda-api state, testing end
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Access the production org-agenda-api instance at https://colonelpanic-org-agenda.fly.dev/ for debugging, testing, or verification.
|
Access the production org-agenda-api instance at https://org-agenda-api.rocket-sense.duckdns.org/ for debugging, testing, or verification.
|
||||||
|
|
||||||
## Credentials
|
## Credentials
|
||||||
|
|
||||||
@@ -20,10 +20,10 @@ Username is currently `imalison`.
|
|||||||
|
|
||||||
## Quick Access with just
|
## Quick Access with just
|
||||||
|
|
||||||
This repo includes a `justfile` under `~/dotfiles/org-agenda-api` with pre-configured commands:
|
This repo includes a `justfile` under `/srv/dotfiles/org-agenda-api` with pre-configured commands:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~/dotfiles/org-agenda-api
|
cd /srv/dotfiles/org-agenda-api
|
||||||
just health
|
just health
|
||||||
just get-all-todos
|
just get-all-todos
|
||||||
just get-todays-agenda
|
just get-todays-agenda
|
||||||
|
|||||||
@@ -11,16 +11,16 @@ HTTP API for org-mode agenda data. Use this skill when you need to query or modi
|
|||||||
|
|
||||||
Get credentials from pass:
|
Get credentials from pass:
|
||||||
```bash
|
```bash
|
||||||
pass show colonelpanic-org-agenda.fly.dev
|
pass show org-agenda-api-imalison
|
||||||
```
|
```
|
||||||
|
|
||||||
Returns: password on first line, then `user:` and `url:` fields.
|
Returns: password on first line. The username is currently `imalison`.
|
||||||
|
|
||||||
**Note:** The `url` field in pass may be outdated. Use the base URL below.
|
**Note:** The `url` field in pass may be outdated. Use the base URL below.
|
||||||
|
|
||||||
## Base URL
|
## Base URL
|
||||||
|
|
||||||
`https://colonelpanic-org-agenda.fly.dev`
|
`https://org-agenda-api.rocket-sense.duckdns.org`
|
||||||
|
|
||||||
All requests use Basic Auth with the credentials from pass.
|
All requests use Basic Auth with the credentials from pass.
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ cd ~/.config/taffybar/taffybar && nix flake update <pkg>
|
|||||||
cd ~/.config/taffybar && nix flake update <pkg> taffybar
|
cd ~/.config/taffybar && nix flake update <pkg> taffybar
|
||||||
|
|
||||||
# Top:
|
# Top:
|
||||||
cd ~/dotfiles/nixos && nix flake update imalison-taffybar
|
cd /srv/dotfiles/nixos && nix flake update imalison-taffybar
|
||||||
```
|
```
|
||||||
|
|
||||||
Not every change requires touching all three layers. Think about which flake.lock files actually contain stale references:
|
Not every change requires touching all three layers. Think about which flake.lock files actually contain stale references:
|
||||||
@@ -58,7 +58,7 @@ Not every change requires touching all three layers. Think about which flake.loc
|
|||||||
## Rebuilding
|
## Rebuilding
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~/dotfiles/nixos && just switch
|
cd /srv/dotfiles/nixos && just switch
|
||||||
```
|
```
|
||||||
|
|
||||||
If taffybar seems stale after a rebuild, check whether the flake.lock at each layer actually points at the expected revision — a missed cascade step is the usual cause.
|
If taffybar seems stale after a rebuild, check whether the flake.lock at each layer actually points at the expected revision — a missed cascade step is the usual cause.
|
||||||
|
|||||||
6
dotfiles/claude/.gitignore
vendored
6
dotfiles/claude/.gitignore
vendored
@@ -1,6 +0,0 @@
|
|||||||
*
|
|
||||||
!.gitignore
|
|
||||||
!CLAUDE.md
|
|
||||||
!settings.json
|
|
||||||
!settings.local.json
|
|
||||||
!settings.local.json.example
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../agents/AGENTS.md
|
|
||||||
1
dotfiles/claude/CLAUDE.md
Normal file
1
dotfiles/claude/CLAUDE.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@~/.agents/AGENTS.md
|
||||||
@@ -13,9 +13,12 @@
|
|||||||
},
|
},
|
||||||
"enabledPlugins": {
|
"enabledPlugins": {
|
||||||
"superpowers@superpowers-marketplace": true,
|
"superpowers@superpowers-marketplace": true,
|
||||||
"agent-browser@agent-browser": true
|
"agent-browser@agent-browser": true,
|
||||||
|
"chrome-devtools-mcp@claude-plugins-official": true
|
||||||
},
|
},
|
||||||
"effortLevel": "high",
|
"effortLevel": "high",
|
||||||
"skipDangerousModePermissionPrompt": true,
|
"skipDangerousModePermissionPrompt": true,
|
||||||
"remoteControlAtStartup": true
|
"remoteControlAtStartup": true,
|
||||||
|
"inputNeededNotifEnabled": true,
|
||||||
|
"agentPushNotifEnabled": true
|
||||||
}
|
}
|
||||||
|
|||||||
1
dotfiles/claude/skills
Symbolic link
1
dotfiles/claude/skills
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../agents/skills
|
||||||
8
dotfiles/codex/.gitignore
vendored
8
dotfiles/codex/.gitignore
vendored
@@ -1,8 +0,0 @@
|
|||||||
*
|
|
||||||
!.gitignore
|
|
||||||
!AGENTS.md
|
|
||||||
!config.toml
|
|
||||||
!skills
|
|
||||||
|
|
||||||
# Legacy generated/local Codex state under this repo stays ignored. Active
|
|
||||||
# host-local Codex fragments now live under ~/.codex.
|
|
||||||
@@ -9,12 +9,12 @@ suppress_unstable_features_warning = true
|
|||||||
# ~/.codex/config.local-state.toml.
|
# ~/.codex/config.local-state.toml.
|
||||||
|
|
||||||
[mcp_servers.chrome-devtools]
|
[mcp_servers.chrome-devtools]
|
||||||
command = "npx"
|
command = "/usr/bin/env"
|
||||||
args = ["-y", "chrome-devtools-mcp@latest", "--auto-connect"]
|
args = ["PATH=/etc/profiles/per-user/imalison/bin:/run/current-system/sw/bin:/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin", "npx", "-y", "chrome-devtools-mcp@latest", "--auto-connect"]
|
||||||
|
|
||||||
[mcp_servers.observability]
|
[mcp_servers.observability]
|
||||||
command = "npx"
|
command = "/usr/bin/env"
|
||||||
args = ["-y", "@google-cloud/observability-mcp"]
|
args = ["PATH=/etc/profiles/per-user/imalison/bin:/run/current-system/sw/bin:/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin", "npx", "-y", "@google-cloud/observability-mcp"]
|
||||||
|
|
||||||
[mcp_servers.openaiDeveloperDocs]
|
[mcp_servers.openaiDeveloperDocs]
|
||||||
url = "https://developers.openai.com/mcp"
|
url = "https://developers.openai.com/mcp"
|
||||||
|
|||||||
37
dotfiles/config/autorandr/jay-lenovo-with-benq/config
Normal file
37
dotfiles/config/autorandr/jay-lenovo-with-benq/config
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
output HDMI-A-0
|
||||||
|
off
|
||||||
|
output DisplayPort-1-1
|
||||||
|
off
|
||||||
|
output DisplayPort-1-2
|
||||||
|
off
|
||||||
|
output DisplayPort-1-3
|
||||||
|
off
|
||||||
|
output DisplayPort-1-4
|
||||||
|
off
|
||||||
|
output DisplayPort-0
|
||||||
|
crtc 1
|
||||||
|
mode 2560x1440
|
||||||
|
pos 0x0
|
||||||
|
rate 144.00
|
||||||
|
x-prop-colorspace Default
|
||||||
|
x-prop-max_bpc 16
|
||||||
|
x-prop-non_desktop 0
|
||||||
|
x-prop-scaling_mode None
|
||||||
|
x-prop-tearfree auto
|
||||||
|
x-prop-underscan off
|
||||||
|
x-prop-underscan_hborder 0
|
||||||
|
x-prop-underscan_vborder 0
|
||||||
|
output eDP
|
||||||
|
crtc 0
|
||||||
|
mode 2560x1600
|
||||||
|
pos 2560x0
|
||||||
|
primary
|
||||||
|
rate 165.00
|
||||||
|
x-prop-colorspace Default
|
||||||
|
x-prop-max_bpc 16
|
||||||
|
x-prop-non_desktop 0
|
||||||
|
x-prop-scaling_mode None
|
||||||
|
x-prop-tearfree auto
|
||||||
|
x-prop-underscan off
|
||||||
|
x-prop-underscan_hborder 0
|
||||||
|
x-prop-underscan_vborder 0
|
||||||
2
dotfiles/config/autorandr/jay-lenovo-with-benq/setup
Normal file
2
dotfiles/config/autorandr/jay-lenovo-with-benq/setup
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
DisplayPort-0 00ffffffffffff0009d1767f45540000281d0103803c22782a9325ad4f44a9260d5054a56b80d1fcd1e8d1c0b300a9c08180810081c0f8e300a0a0a032500820980455502100001a000000ff0033414b30313335343031390a20000000fd0028901ede3c000a202020202020000000fc0042656e5120455832373830510a0174020350f1515d5e5f60613f40101f22212004131203012309070783010000e200cf6d030c001000383c20006001020367d85dc401788003681a000001012890e6e305c301e40f180000e60605016262216fc200a0a0a055503020350055502100001e565e00a0a0a029502f20350055502100001a0000000000000000000000bf
|
||||||
|
eDP 00ffffffffffff0009e59b0a000000001c1e0104b5221578037ce5a4554c9f260f5054000000010101010101010101010101010101016b6e00a0a04084603020360058d71000001a000000fd0c3ca51f1f4e010a202020202020000000fe00424f452043510a202020202020000000fe004e4531363051444d2d4e59310a02d502031d00e3058000e60605016a6a246d1a000002033ca500046a246a240000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff7013790000030114a52f0185ff099f002f001f003f0683000200050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e90
|
||||||
@@ -5,6 +5,6 @@ general {
|
|||||||
|
|
||||||
listener {
|
listener {
|
||||||
timeout = 300
|
timeout = 300
|
||||||
on-timeout = /home/imalison/dotfiles/dotfiles/lib/bin/hypr-screensaver start
|
on-timeout = hypr-screensaver start
|
||||||
on-resume = /home/imalison/dotfiles/dotfiles/lib/bin/hypr-screensaver stop
|
on-resume = hypr-screensaver stop
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,16 +19,61 @@ package.path = table.concat({
|
|||||||
package.path,
|
package.path,
|
||||||
}, ";")
|
}, ";")
|
||||||
|
|
||||||
local modules = {
|
local function shell_quote(value)
|
||||||
"hyprland.state",
|
return "'" .. tostring(value):gsub("'", "'\\''") .. "'"
|
||||||
"hyprland.scratchpads",
|
end
|
||||||
"hyprland.core",
|
|
||||||
"hyprland.layouts",
|
local function module_load_phase(name)
|
||||||
"hyprland.windows",
|
if name == "state" then
|
||||||
"hyprland.settings",
|
return 0
|
||||||
"hyprland.binds",
|
elseif name == "binds" then
|
||||||
"hyprland.events",
|
return 20
|
||||||
}
|
elseif name == "events" then
|
||||||
|
return 30
|
||||||
|
end
|
||||||
|
|
||||||
|
return 10
|
||||||
|
end
|
||||||
|
|
||||||
|
local function discover_modules()
|
||||||
|
local modules_dir = base_dir .. "/hyprland"
|
||||||
|
local handle = assert(io.popen("find " .. shell_quote(modules_dir) .. " -maxdepth 1 -type f -name '*.lua' -print"))
|
||||||
|
local discovered = {}
|
||||||
|
|
||||||
|
for path in handle:lines() do
|
||||||
|
local name = path:match("/([^/]+)%.lua$")
|
||||||
|
if name then
|
||||||
|
discovered[#discovered + 1] = {
|
||||||
|
name = name,
|
||||||
|
module = "hyprland." .. name,
|
||||||
|
phase = module_load_phase(name),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
handle:close()
|
||||||
|
|
||||||
|
table.sort(discovered, function(left, right)
|
||||||
|
if left.phase ~= right.phase then
|
||||||
|
return left.phase < right.phase
|
||||||
|
end
|
||||||
|
|
||||||
|
return left.name < right.name
|
||||||
|
end)
|
||||||
|
|
||||||
|
local modules = {}
|
||||||
|
for _, item in ipairs(discovered) do
|
||||||
|
modules[#modules + 1] = item.module
|
||||||
|
end
|
||||||
|
|
||||||
|
if modules[1] ~= "hyprland.state" then
|
||||||
|
error("hyprland/state.lua is required")
|
||||||
|
end
|
||||||
|
|
||||||
|
return modules
|
||||||
|
end
|
||||||
|
|
||||||
|
local modules = discover_modules()
|
||||||
|
|
||||||
for _, module in ipairs(modules) do
|
for _, module in ipairs(modules) do
|
||||||
package.loaded[module] = nil
|
package.loaded[module] = nil
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ function M.setup(ctx)
|
|||||||
bind("XF86AudioRaiseVolume", exec("set_volume --unmute --change-volume +5"), desc("Raise volume", { repeating = true }))
|
bind("XF86AudioRaiseVolume", exec("set_volume --unmute --change-volume +5"), desc("Raise volume", { repeating = true }))
|
||||||
bind("XF86AudioLowerVolume", exec("set_volume --unmute --change-volume -5"), desc("Lower volume", { repeating = true }))
|
bind("XF86AudioLowerVolume", exec("set_volume --unmute --change-volume -5"), desc("Lower volume", { repeating = true }))
|
||||||
bind("XF86AudioMute", exec("set_volume --toggle-mute"), desc("Toggle mute"))
|
bind("XF86AudioMute", exec("set_volume --toggle-mute"), desc("Toggle mute"))
|
||||||
bind(hyper .. " + O", exec("/home/imalison/dotfiles/dotfiles/lib/functions/rofi_paswitch"), desc("Open PulseAudio output switcher"))
|
bind(hyper .. " + O", exec("rofi_paswitch"), desc("Open PulseAudio output switcher"))
|
||||||
bind(hyper .. " + SHIFT + O", exec("/home/imalison/dotfiles/dotfiles/lib/bin/kef-optical"), desc("Switch KEF speakers to optical input"))
|
bind(hyper .. " + SHIFT + O", exec("kef-optical"), desc("Switch KEF speakers to optical input"))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function setup_display_wallpaper_and_capture_bindings()
|
local function setup_display_wallpaper_and_capture_bindings()
|
||||||
@@ -58,16 +58,17 @@ function M.setup(ctx)
|
|||||||
bind("XF86MonBrightnessDown", exec("brightness.sh down"), desc("Lower display brightness", { repeating = true }))
|
bind("XF86MonBrightnessDown", exec("brightness.sh down"), desc("Lower display brightness", { repeating = true }))
|
||||||
bind("Print", exec("flameshot gui"), desc("Take screenshot"))
|
bind("Print", exec("flameshot gui"), desc("Take screenshot"))
|
||||||
bind(hyper .. " + H", exec("flameshot gui"), desc("Take screenshot"))
|
bind(hyper .. " + H", exec("flameshot gui"), desc("Take screenshot"))
|
||||||
bind(hyper .. " + backslash", exec("/home/imalison/dotfiles/dotfiles/lib/functions/mpg341cx_input toggle"), desc("Toggle monitor input"))
|
bind(hyper .. " + backslash", exec("mpg341cx_input toggle"), desc("Toggle monitor input"))
|
||||||
bind(hyper .. " + comma", exec("rofi_wallpaper.sh"), desc("Open wallpaper menu"))
|
bind(hyper .. " + comma", exec("rofi_wallpaper.sh"), desc("Open wallpaper menu"))
|
||||||
bind(hyper .. " + SHIFT + comma", exec("/home/imalison/dotfiles/dotfiles/lib/bin/neowall-wallpaper toggle"), desc("Toggle neowall wallpaper"))
|
bind(hyper .. " + SHIFT + comma", exec("neowall-wallpaper toggle"), desc("Toggle neowall wallpaper"))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function setup_rofi_and_tool_bindings()
|
local function setup_rofi_and_tool_bindings()
|
||||||
bind(main_mod .. " + X", exec("rofi_command.sh"), desc("Open command menu"))
|
bind(main_mod .. " + X", exec("rofi_command.sh"), desc("Open command menu"))
|
||||||
bind(hyper .. " + V", exec([[cliphist list | rofi -dmenu -p "Clipboard" | cliphist decode | wl-copy]]), desc("Open clipboard history"))
|
bind(hyper .. " + V", exec([[cliphist list | rofi -dmenu -p "Clipboard" | cliphist decode | wl-copy]]), desc("Open clipboard history"))
|
||||||
bind(hyper .. " + P", exec("rofi-pass"), desc("Open password menu"))
|
bind(hyper .. " + P", exec("rofi-pass"), desc("Open password menu"))
|
||||||
bind(hyper .. " + C", exec("rofi_tmcodex.sh"), desc("Open Codex session menu"))
|
bind(hyper .. " + N", exec("rofi_codex_desktop_project.sh"), desc("Start Codex Desktop thread from project"))
|
||||||
|
bind(hyper .. " + C", exec("rofi_ai_scratchpad.sh"), desc("Choose AI scratchpad (Codex/Claude)"))
|
||||||
bind(hyper .. " + SHIFT + C", exec("rofi_tmcodex.sh resume"), desc("Resume Codex session"))
|
bind(hyper .. " + SHIFT + C", exec("rofi_tmcodex.sh resume"), desc("Resume Codex session"))
|
||||||
bind(hyper .. " + L", exec("hypr_rofi_layout"), desc("Open Hyprland layout menu"))
|
bind(hyper .. " + L", exec("hypr_rofi_layout"), desc("Open Hyprland layout menu"))
|
||||||
bind(hyper .. " + K", exec("rofi_kill_process.sh"), desc("Open process kill menu"))
|
bind(hyper .. " + K", exec("rofi_kill_process.sh"), desc("Open process kill menu"))
|
||||||
@@ -87,9 +88,23 @@ function M.setup(ctx)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function setup_window_overview_bindings()
|
local function setup_window_overview_bindings()
|
||||||
|
local function toggle_hyprtasking()
|
||||||
|
if hl.plugin and hl.plugin.hyprtasking and hl.plugin.hyprtasking.toggle then
|
||||||
|
hl.plugin.hyprtasking.toggle("cursor")
|
||||||
|
else
|
||||||
|
hl.notification.create({
|
||||||
|
text = "hyprtasking is not loaded",
|
||||||
|
duration = 1800,
|
||||||
|
icon = notification_icons.warning,
|
||||||
|
color = "rgba(edb443ff)",
|
||||||
|
font_size = 13,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
bind(main_mod .. " + SHIFT + C", hl.dsp.window.close(), desc("Close active window"))
|
bind(main_mod .. " + SHIFT + C", hl.dsp.window.close(), desc("Close active window"))
|
||||||
bind(main_mod .. " + SHIFT + Q", hl.dsp.exit(), desc("Exit Hyprland"))
|
bind(main_mod .. " + SHIFT + Q", hl.dsp.exit(), desc("Exit Hyprland"))
|
||||||
bind(main_mod .. " + Tab", hyprexpo("toggle"), desc("Toggle hyprexpo workspace overview", overview_bind_opts))
|
bind(main_mod .. " + Tab", toggle_hyprtasking, desc("Toggle hyprtasking workspace overview", overview_bind_opts))
|
||||||
bind(main_mod .. " + SHIFT + Tab", hyprwinview({
|
bind(main_mod .. " + SHIFT + Tab", hyprwinview({
|
||||||
action = "show",
|
action = "show",
|
||||||
include_current_workspace = false,
|
include_current_workspace = false,
|
||||||
@@ -97,8 +112,7 @@ function M.setup(ctx)
|
|||||||
default_action = "bring",
|
default_action = "bring",
|
||||||
}), desc("Show all-workspace window overview", overview_bind_opts))
|
}), desc("Show all-workspace window overview", overview_bind_opts))
|
||||||
bind(main_mod .. " + SHIFT + slash", hyprwinview({ action = "toggle-filter" }), desc("Toggle window overview filter", overview_bind_opts))
|
bind(main_mod .. " + SHIFT + slash", hyprwinview({ action = "toggle-filter" }), desc("Toggle window overview filter", overview_bind_opts))
|
||||||
bind("ALT + Tab", hyprexpo("toggle"), desc("Toggle hyprexpo workspace overview", overview_bind_opts))
|
bind("ALT + Tab", toggle_hyprtasking, desc("Toggle hyprtasking workspace overview", overview_bind_opts))
|
||||||
bind("ALT + SHIFT + Tab", hyprexpo("on"), desc("Open hyprexpo workspace overview", overview_bind_opts))
|
|
||||||
bind(main_mod .. " + G", hyprwinview({
|
bind(main_mod .. " + G", hyprwinview({
|
||||||
action = "show",
|
action = "show",
|
||||||
start_in_filter_mode = true,
|
start_in_filter_mode = true,
|
||||||
@@ -227,7 +241,9 @@ function M.setup(ctx)
|
|||||||
bind(main_mod .. " + CTRL + Space", gather_workspace_into_tabbed_group, desc("Gather workspace into tabbed group"))
|
bind(main_mod .. " + CTRL + Space", gather_workspace_into_tabbed_group, desc("Gather workspace into tabbed group"))
|
||||||
bind(main_mod .. " + bracketright", monocle_next, desc("Focus next monocle window"))
|
bind(main_mod .. " + bracketright", monocle_next, desc("Focus next monocle window"))
|
||||||
bind(main_mod .. " + bracketleft", monocle_prev, desc("Focus previous monocle window"))
|
bind(main_mod .. " + bracketleft", monocle_prev, desc("Focus previous monocle window"))
|
||||||
bind(main_mod .. " + T", hl.dsp.window.float({ action = "disable" }), desc("Tile active window"))
|
bind(main_mod .. " + F", toggle_active_window_real_fullscreen, desc("Toggle active window real fullscreen"))
|
||||||
|
bind(main_mod .. " + SHIFT + F", toggle_active_window_gaming_mode, desc("Toggle active window gaming fullscreen"))
|
||||||
|
bind(main_mod .. " + T", tile_or_float_active_window, desc("Tile or float active window"))
|
||||||
bind(main_mod .. " + O", toggle_pinned_active_window, desc("Toggle pinned active window"))
|
bind(main_mod .. " + O", toggle_pinned_active_window, desc("Toggle pinned active window"))
|
||||||
bind(main_mod .. " + M", minimize_active_window, desc("Minimize active window"))
|
bind(main_mod .. " + M", minimize_active_window, desc("Minimize active window"))
|
||||||
bind(main_mod .. " + SHIFT + M", restore_last_minimized, desc("Restore last minimized window"))
|
bind(main_mod .. " + SHIFT + M", restore_last_minimized, desc("Restore last minimized window"))
|
||||||
@@ -249,9 +265,11 @@ function M.setup(ctx)
|
|||||||
|
|
||||||
local function setup_scratchpad_bindings()
|
local function setup_scratchpad_bindings()
|
||||||
bind(main_mod .. " + SHIFT + X", hl.dsp.workspace.toggle_special("NSP"), desc("Toggle NSP special workspace"))
|
bind(main_mod .. " + SHIFT + X", hl.dsp.workspace.toggle_special("NSP"), desc("Toggle NSP special workspace"))
|
||||||
bind(mod_alt .. " + C", function()
|
bind(mod_alt .. " + C", toggle_active_ai_scratchpad, desc("Toggle AI scratchpad (Codex/Claude)"))
|
||||||
toggle_scratchpad("codex")
|
bind(mod_alt .. " + SHIFT + C", toggle_backup_ai_scratchpad, desc("Toggle backup AI scratchpad (Codex/Claude)"))
|
||||||
end, desc("Toggle Codex scratchpad"))
|
bind(mod_alt .. " + D", function()
|
||||||
|
toggle_scratchpad("discord")
|
||||||
|
end, desc("Toggle Discord scratchpad"))
|
||||||
bind(mod_alt .. " + E", function()
|
bind(mod_alt .. " + E", function()
|
||||||
toggle_scratchpad("element")
|
toggle_scratchpad("element")
|
||||||
end, desc("Toggle Element scratchpad"))
|
end, desc("Toggle Element scratchpad"))
|
||||||
@@ -273,6 +291,9 @@ function M.setup(ctx)
|
|||||||
bind(mod_alt .. " + V", function()
|
bind(mod_alt .. " + V", function()
|
||||||
toggle_scratchpad("volume")
|
toggle_scratchpad("volume")
|
||||||
end, desc("Toggle volume scratchpad"))
|
end, desc("Toggle volume scratchpad"))
|
||||||
|
bind(mod_alt .. " + X", function()
|
||||||
|
toggle_scratchpad("x_com")
|
||||||
|
end, desc("Toggle X scratchpad"))
|
||||||
bind(mod_alt .. " + grave", function()
|
bind(mod_alt .. " + grave", function()
|
||||||
toggle_scratchpad("dropdown")
|
toggle_scratchpad("dropdown")
|
||||||
end, desc("Toggle dropdown scratchpad"))
|
end, desc("Toggle dropdown scratchpad"))
|
||||||
@@ -312,6 +333,7 @@ function M.setup(ctx)
|
|||||||
local function setup_mouse_bindings()
|
local function setup_mouse_bindings()
|
||||||
bind(main_mod .. " + mouse:272", float_and_drag_active_window, desc("Float and drag active window"))
|
bind(main_mod .. " + mouse:272", float_and_drag_active_window, desc("Float and drag active window"))
|
||||||
bind(main_mod .. " + mouse:273", float_and_resize_active_window, desc("Float and resize active window"))
|
bind(main_mod .. " + mouse:273", float_and_resize_active_window, desc("Float and resize active window"))
|
||||||
|
bind(hyper .. " + mouse:272", float_and_resize_active_window, desc("Float and resize active window"))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function setup_internal_window_manager_bindings()
|
local function setup_internal_window_manager_bindings()
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ function M.setup(ctx)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function apply_hyprexpo_config()
|
local function apply_hyprexpo_config()
|
||||||
if verify_config or not enable_hyprexpo then
|
if verify_config or not enable_hyprexpo or enable_hyprtasking then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -216,10 +216,18 @@ function M.setup(ctx)
|
|||||||
keynav_wrap_h = 1,
|
keynav_wrap_h = 1,
|
||||||
keynav_wrap_v = 1,
|
keynav_wrap_v = 1,
|
||||||
keynav_reading_order = 0,
|
keynav_reading_order = 0,
|
||||||
|
live_preview_follow_focus = 0,
|
||||||
border_width = 2,
|
border_width = 2,
|
||||||
border_color_current = "rgb(66ccff)",
|
border_color_current = "rgb(66ccff)",
|
||||||
border_color_focus = "rgb(edb443)",
|
border_color_focus = "rgb(edb443)",
|
||||||
border_color_hover = "rgb(aabbcc)",
|
border_color_hover = "rgb(aabbcc)",
|
||||||
|
window_icon_enable = 1,
|
||||||
|
window_icon_position = "bottom-right",
|
||||||
|
window_icon_size = 32,
|
||||||
|
window_icon_offset_x = 8,
|
||||||
|
window_icon_offset_y = 8,
|
||||||
|
window_icon_bg_enable = 1,
|
||||||
|
window_icon_bg_color = 0x88000000,
|
||||||
tile_rounding = 5,
|
tile_rounding = 5,
|
||||||
tile_rounding_power = 2.0,
|
tile_rounding_power = 2.0,
|
||||||
label_enable = 1,
|
label_enable = 1,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ function M.setup(ctx)
|
|||||||
}
|
}
|
||||||
fullscreen_states[address] = current
|
fullscreen_states[address] = current
|
||||||
|
|
||||||
if window.floating or current_layout == monocle_layout then
|
if window.floating or current_layout == monocle_layout or is_game_like_window(window) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -41,6 +41,7 @@ function M.setup(ctx)
|
|||||||
apply_hyprexpo_config()
|
apply_hyprexpo_config()
|
||||||
apply_hyprwinview_config()
|
apply_hyprwinview_config()
|
||||||
apply_hyprwobbly_config()
|
apply_hyprwobbly_config()
|
||||||
|
apply_dynamic_cursors_config()
|
||||||
apply_hyprglass_config()
|
apply_hyprglass_config()
|
||||||
apply_visual_performance_mode()
|
apply_visual_performance_mode()
|
||||||
apply_rules()
|
apply_rules()
|
||||||
@@ -60,6 +61,7 @@ function M.setup(ctx)
|
|||||||
hl.on("config.reloaded", apply_hyprexpo_config)
|
hl.on("config.reloaded", apply_hyprexpo_config)
|
||||||
hl.on("config.reloaded", apply_hyprwinview_config)
|
hl.on("config.reloaded", apply_hyprwinview_config)
|
||||||
hl.on("config.reloaded", apply_hyprwobbly_config)
|
hl.on("config.reloaded", apply_hyprwobbly_config)
|
||||||
|
hl.on("config.reloaded", apply_dynamic_cursors_config)
|
||||||
hl.on("config.reloaded", apply_hyprglass_config)
|
hl.on("config.reloaded", apply_hyprglass_config)
|
||||||
hl.on("config.reloaded", apply_visual_performance_mode)
|
hl.on("config.reloaded", apply_visual_performance_mode)
|
||||||
hl.on("config.reloaded", apply_rules)
|
hl.on("config.reloaded", apply_rules)
|
||||||
@@ -83,7 +85,6 @@ function M.setup(ctx)
|
|||||||
hl.on("window.move_to_workspace", update_monocle_notice)
|
hl.on("window.move_to_workspace", update_monocle_notice)
|
||||||
hl.on("window.fullscreen", reconcile_fullscreen_state)
|
hl.on("window.fullscreen", reconcile_fullscreen_state)
|
||||||
hl.on("window.update_rules", reconcile_fullscreen_state)
|
hl.on("window.update_rules", reconcile_fullscreen_state)
|
||||||
|
|
||||||
hl.on("window.open", adopt_matching_scratchpad_window)
|
hl.on("window.open", adopt_matching_scratchpad_window)
|
||||||
hl.on("window.class", adopt_matching_scratchpad_window)
|
hl.on("window.class", adopt_matching_scratchpad_window)
|
||||||
hl.on("window.title", adopt_matching_scratchpad_window)
|
hl.on("window.title", adopt_matching_scratchpad_window)
|
||||||
|
|||||||
@@ -2,18 +2,63 @@ local M = {}
|
|||||||
|
|
||||||
function M.setup(ctx)
|
function M.setup(ctx)
|
||||||
local _ENV = ctx
|
local _ENV = ctx
|
||||||
|
local configure_quadrants_master
|
||||||
|
local focus_workspace
|
||||||
|
local move_window_to_workspace
|
||||||
|
|
||||||
local function is_nstack_layout(layout)
|
local function is_nstack_layout(layout)
|
||||||
return layout == columns_layout or layout == grid_layout
|
return layout == columns_layout or layout == grid_layout
|
||||||
end
|
end
|
||||||
|
|
||||||
local function hyprland_layout(layout)
|
local function hyprland_layout(layout)
|
||||||
if layout == grid_layout then
|
if layout == quadrants_layout then
|
||||||
|
return large_main_layout
|
||||||
|
elseif layout == grid_layout then
|
||||||
return columns_layout
|
return columns_layout
|
||||||
end
|
end
|
||||||
return layout
|
return layout
|
||||||
end
|
end
|
||||||
|
|
||||||
|
configure_quadrants_master = function()
|
||||||
|
if quadrants_arranging or current_layout ~= quadrants_layout then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local workspace = active_workspace()
|
||||||
|
if not is_normal_workspace(workspace) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local windows = tiled_windows(workspace)
|
||||||
|
if #windows == 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
sort_windows_by_visual_position(windows)
|
||||||
|
|
||||||
|
quadrants_arranging = true
|
||||||
|
dispatch(hl.dsp.focus({ window = window_selector(windows[1]) }))
|
||||||
|
dispatch(hl.dsp.layout("orientationleft"))
|
||||||
|
dispatch(hl.dsp.layout("mfact exact 0.5"))
|
||||||
|
|
||||||
|
for _ = 1, #windows do
|
||||||
|
dispatch(hl.dsp.layout("removemaster"))
|
||||||
|
end
|
||||||
|
|
||||||
|
if #windows >= 3 then
|
||||||
|
dispatch(hl.dsp.layout("addmaster"))
|
||||||
|
end
|
||||||
|
|
||||||
|
quadrants_arranging = false
|
||||||
|
focus_workspace(workspace.id)
|
||||||
|
end
|
||||||
|
|
||||||
local function update_nstack_count()
|
local function update_nstack_count()
|
||||||
|
if current_layout == quadrants_layout then
|
||||||
|
configure_quadrants_master()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
if not enable_nstack or not is_nstack_layout(current_layout) then
|
if not enable_nstack or not is_nstack_layout(current_layout) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -98,7 +143,10 @@ function M.setup(ctx)
|
|||||||
hl.config({ general = { layout = hyprland_layout(layout) } })
|
hl.config({ general = { layout = hyprland_layout(layout) } })
|
||||||
write_layout_state()
|
write_layout_state()
|
||||||
|
|
||||||
if is_nstack_layout(layout) then
|
if layout == quadrants_layout then
|
||||||
|
dismiss_monocle_notice()
|
||||||
|
schedule_nstack_count_update()
|
||||||
|
elseif is_nstack_layout(layout) then
|
||||||
dismiss_monocle_notice()
|
dismiss_monocle_notice()
|
||||||
schedule_nstack_count_update()
|
schedule_nstack_count_update()
|
||||||
else
|
else
|
||||||
@@ -127,7 +175,10 @@ function M.setup(ctx)
|
|||||||
hl.config({ general = { layout = hyprland_layout(current_layout) } })
|
hl.config({ general = { layout = hyprland_layout(current_layout) } })
|
||||||
write_layout_state()
|
write_layout_state()
|
||||||
|
|
||||||
if is_nstack_layout(current_layout) then
|
if current_layout == quadrants_layout then
|
||||||
|
dismiss_monocle_notice()
|
||||||
|
schedule_nstack_count_update()
|
||||||
|
elseif is_nstack_layout(current_layout) then
|
||||||
dismiss_monocle_notice()
|
dismiss_monocle_notice()
|
||||||
schedule_nstack_count_update()
|
schedule_nstack_count_update()
|
||||||
else
|
else
|
||||||
@@ -210,11 +261,11 @@ function M.setup(ctx)
|
|||||||
dispatch(hl.dsp.window.swap({ direction = direction }))
|
dispatch(hl.dsp.window.swap({ direction = direction }))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function focus_workspace(workspace_id)
|
focus_workspace = function(workspace_id)
|
||||||
dispatch(hl.dsp.focus({ workspace = tostring(workspace_id), on_current_monitor = true }))
|
dispatch(hl.dsp.focus({ workspace = tostring(workspace_id), on_current_monitor = true }))
|
||||||
end
|
end
|
||||||
|
|
||||||
local function move_window_to_workspace(workspace_id, follow, window)
|
move_window_to_workspace = function(workspace_id, follow, window)
|
||||||
local target_window = window or hl.get_active_window()
|
local target_window = window or hl.get_active_window()
|
||||||
local target_selector = window_selector(target_window)
|
local target_selector = window_selector(target_window)
|
||||||
dispatch(hl.dsp.window.move({ workspace = tostring(workspace_id), follow = false, window = target_selector }))
|
dispatch(hl.dsp.window.move({ workspace = tostring(workspace_id), follow = false, window = target_selector }))
|
||||||
@@ -261,6 +312,50 @@ function M.setup(ctx)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function window_contains_point(window, x, y)
|
||||||
|
local at = window and window.at
|
||||||
|
local size = window and window.size
|
||||||
|
if not at or not size then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local left = tonumber(at.x or at[1])
|
||||||
|
local top = tonumber(at.y or at[2])
|
||||||
|
local width = tonumber(size.x or size[1])
|
||||||
|
local height = tonumber(size.y or size[2])
|
||||||
|
if not left or not top or not width or not height then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return x >= left and x < left + width and y >= top and y < top + height
|
||||||
|
end
|
||||||
|
|
||||||
|
-- With follow_mouse=1, a bare focus dispatch does not survive the next
|
||||||
|
-- pointer motion unless the cursor already sits inside the target window,
|
||||||
|
-- so warp the cursor into the window when needed.
|
||||||
|
local function focus_window_with_cursor(window)
|
||||||
|
local selector = window_selector(window)
|
||||||
|
if not selector then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local live = type(hl.get_window) == "function" and hl.get_window(selector) or window
|
||||||
|
if not live then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
dispatch(hl.dsp.focus({ window = selector }))
|
||||||
|
|
||||||
|
local cursor = hl.get_cursor_pos and hl.get_cursor_pos()
|
||||||
|
if cursor and window_contains_point(live, cursor.x, cursor.y) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local center_x, center_y = window_center(live)
|
||||||
|
dispatch(hl.dsp.cursor.move({ x = math.floor(center_x), y = math.floor(center_y) }))
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
local function find_tabbed_group_anchor(state)
|
local function find_tabbed_group_anchor(state)
|
||||||
local active = hl.get_active_window()
|
local active = hl.get_active_window()
|
||||||
if active and active.group and active.group.size and active.group.size > 1 then
|
if active and active.group and active.group.size and active.group.size > 1 then
|
||||||
@@ -271,8 +366,16 @@ function M.setup(ctx)
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local workspace = active_workspace()
|
||||||
for _, window in ipairs(hl.get_windows()) do
|
for _, window in ipairs(hl.get_windows()) do
|
||||||
if window and window.address == state.anchor and window.group and window.group.size and window.group.size > 1 then
|
if
|
||||||
|
window
|
||||||
|
and window.address == state.anchor
|
||||||
|
and same_workspace(window.workspace, workspace)
|
||||||
|
and window.group
|
||||||
|
and window.group.size
|
||||||
|
and window.group.size > 1
|
||||||
|
then
|
||||||
return window
|
return window
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -327,6 +430,7 @@ function M.setup(ctx)
|
|||||||
local function restore_workspace_tabbed_group()
|
local function restore_workspace_tabbed_group()
|
||||||
local key = workspace_key()
|
local key = workspace_key()
|
||||||
local state = tabbed_workspace_groups[key]
|
local state = tabbed_workspace_groups[key]
|
||||||
|
local entry_focused = hl.get_active_window()
|
||||||
local anchor = find_tabbed_group_anchor(state)
|
local anchor = find_tabbed_group_anchor(state)
|
||||||
local anchor_selector = window_selector(anchor)
|
local anchor_selector = window_selector(anchor)
|
||||||
local target_workspace_id = anchor and anchor.workspace and anchor.workspace.id
|
local target_workspace_id = anchor and anchor.workspace and anchor.workspace.id
|
||||||
@@ -343,7 +447,9 @@ function M.setup(ctx)
|
|||||||
tabbed_workspace_groups[key] = nil
|
tabbed_workspace_groups[key] = nil
|
||||||
set_layout(columns_layout)
|
set_layout(columns_layout)
|
||||||
restore_tabbed_group_window_order(state, target_workspace_id)
|
restore_tabbed_group_window_order(state, target_workspace_id)
|
||||||
dispatch(hl.dsp.focus({ window = anchor_selector }))
|
if not focus_window_with_cursor(entry_focused) then
|
||||||
|
focus_window_with_cursor(anchor)
|
||||||
|
end
|
||||||
schedule_nstack_count_update()
|
schedule_nstack_count_update()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -418,6 +524,9 @@ function M.setup(ctx)
|
|||||||
dispatch(hl.dsp.focus({ window = anchor_selector }))
|
dispatch(hl.dsp.focus({ window = anchor_selector }))
|
||||||
dispatch(hl.dsp.group.toggle({ window = anchor_selector }))
|
dispatch(hl.dsp.group.toggle({ window = anchor_selector }))
|
||||||
notify_tabbed_group("Unable to group tiled windows")
|
notify_tabbed_group("Unable to group tiled windows")
|
||||||
|
if not focus_window_with_cursor(focused) then
|
||||||
|
focus_window_with_cursor(anchor)
|
||||||
|
end
|
||||||
return
|
return
|
||||||
elseif grouped_count < #candidates then
|
elseif grouped_count < #candidates then
|
||||||
notify_tabbed_group("Grouped " .. tostring(grouped_count) .. " of " .. tostring(#candidates) .. " tiled windows")
|
notify_tabbed_group("Grouped " .. tostring(grouped_count) .. " of " .. tostring(#candidates) .. " tiled windows")
|
||||||
@@ -428,7 +537,9 @@ function M.setup(ctx)
|
|||||||
order = original_order,
|
order = original_order,
|
||||||
windows = candidate_addresses,
|
windows = candidate_addresses,
|
||||||
}
|
}
|
||||||
dispatch(hl.dsp.focus({ window = anchor_selector }))
|
if not focus_window_with_cursor(focused) then
|
||||||
|
focus_window_with_cursor(anchor)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function force_columns_layout()
|
local function force_columns_layout()
|
||||||
@@ -556,6 +667,7 @@ function M.setup(ctx)
|
|||||||
|
|
||||||
ctx.is_nstack_layout = is_nstack_layout
|
ctx.is_nstack_layout = is_nstack_layout
|
||||||
ctx.hyprland_layout = hyprland_layout
|
ctx.hyprland_layout = hyprland_layout
|
||||||
|
ctx.configure_quadrants_master = configure_quadrants_master
|
||||||
ctx.update_nstack_count = update_nstack_count
|
ctx.update_nstack_count = update_nstack_count
|
||||||
ctx.schedule_nstack_count_update = schedule_nstack_count_update
|
ctx.schedule_nstack_count_update = schedule_nstack_count_update
|
||||||
ctx.dismiss_monocle_notice = dismiss_monocle_notice
|
ctx.dismiss_monocle_notice = dismiss_monocle_notice
|
||||||
|
|||||||
@@ -15,11 +15,21 @@ function M.setup(ctx)
|
|||||||
codex = {
|
codex = {
|
||||||
command = "codex_desktop_scratchpad",
|
command = "codex_desktop_scratchpad",
|
||||||
class = "codex-desktop",
|
class = "codex-desktop",
|
||||||
|
allow_tiling = true,
|
||||||
|
},
|
||||||
|
claude = {
|
||||||
|
command = "claude-desktop",
|
||||||
|
class = "claude-desktop",
|
||||||
|
allow_tiling = true,
|
||||||
},
|
},
|
||||||
htop = {
|
htop = {
|
||||||
command = "alacritty --class htop-scratch --title htop -e htop",
|
command = "alacritty --class htop-scratch --title htop -e htop",
|
||||||
class = "htop-scratch",
|
class = "htop-scratch",
|
||||||
},
|
},
|
||||||
|
discord = {
|
||||||
|
command = "discord",
|
||||||
|
class = "discord",
|
||||||
|
},
|
||||||
volume = {
|
volume = {
|
||||||
command = "pavucontrol",
|
command = "pavucontrol",
|
||||||
class = "org.pulseaudio.pavucontrol",
|
class = "org.pulseaudio.pavucontrol",
|
||||||
@@ -41,6 +51,12 @@ function M.setup(ctx)
|
|||||||
command = "google-chrome-stable --profile-directory=Default --app=https://messages.google.com/web/conversations",
|
command = "google-chrome-stable --profile-directory=Default --app=https://messages.google.com/web/conversations",
|
||||||
class = "chrome-messages.google.com",
|
class = "chrome-messages.google.com",
|
||||||
},
|
},
|
||||||
|
x_com = {
|
||||||
|
command = "x-com-pwa",
|
||||||
|
classes = { "x-com-pwa", "chrome-x.com" },
|
||||||
|
title = "X",
|
||||||
|
allow_tiling = true,
|
||||||
|
},
|
||||||
transmission = {
|
transmission = {
|
||||||
command = "transmission-gtk",
|
command = "transmission-gtk",
|
||||||
class = "transmission-gtk",
|
class = "transmission-gtk",
|
||||||
@@ -82,9 +98,13 @@ function M.setup(ctx)
|
|||||||
and lower_contains(window.title, def.title)
|
and lower_contains(window.title, def.title)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function tiled_scratchpad_is_normal_window(window, def)
|
||||||
|
return def.allow_tiling and window and window.floating == false
|
||||||
|
end
|
||||||
|
|
||||||
local function is_scratchpad_window(window)
|
local function is_scratchpad_window(window)
|
||||||
for _, def in pairs(scratchpads) do
|
for _, def in pairs(scratchpads) do
|
||||||
if scratchpad_window_matches(window, def) then
|
if scratchpad_window_matches(window, def) and not tiled_scratchpad_is_normal_window(window, def) then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -101,7 +121,7 @@ function M.setup(ctx)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function scratchpad_workspace(name)
|
local function scratchpad_workspace(name)
|
||||||
return "special:scratch-" .. name
|
return "name:scratch-hidden-" .. name
|
||||||
end
|
end
|
||||||
|
|
||||||
local function as_number(value, default)
|
local function as_number(value, default)
|
||||||
@@ -238,6 +258,24 @@ function M.setup(ctx)
|
|||||||
return windows
|
return windows
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function default_scratchpad_geometry(target_monitor)
|
||||||
|
local monitor = target_monitor or hl.get_active_monitor()
|
||||||
|
if not monitor then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local workarea = monitor_workarea(monitor)
|
||||||
|
local width = math.floor(workarea.width * scratchpad_size_ratio)
|
||||||
|
local height = math.floor(workarea.height * scratchpad_size_ratio)
|
||||||
|
|
||||||
|
return {
|
||||||
|
width = width,
|
||||||
|
height = height,
|
||||||
|
x = workarea.x + math.floor((workarea.width - width) / 2),
|
||||||
|
y = workarea.y + math.floor((workarea.height - height) / 2),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
local function scratchpad_geometry(name, target_monitor, position)
|
local function scratchpad_geometry(name, target_monitor, position)
|
||||||
local def = scratchpads[name]
|
local def = scratchpads[name]
|
||||||
local monitor = target_monitor or hl.get_active_monitor()
|
local monitor = target_monitor or hl.get_active_monitor()
|
||||||
@@ -261,10 +299,7 @@ function M.setup(ctx)
|
|||||||
y = position
|
y = position
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
width = math.floor(workarea.width * scratchpad_size_ratio)
|
return default_scratchpad_geometry(monitor)
|
||||||
height = math.floor(workarea.height * scratchpad_size_ratio)
|
|
||||||
x = workarea.x + math.floor((workarea.width - width) / 2)
|
|
||||||
y = workarea.y + math.floor((workarea.height - height) / 2)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -275,6 +310,23 @@ function M.setup(ctx)
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function should_apply_scratchpad_geometry(name, window, opts)
|
||||||
|
local def = scratchpads[name]
|
||||||
|
if not def then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return (opts and opts.force_geometry) or def.dropdown or not tiled_scratchpad_is_normal_window(window, def)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function refreshed_window(window)
|
||||||
|
if not window or not window.address or type(hl.get_window) ~= "function" then
|
||||||
|
return window
|
||||||
|
end
|
||||||
|
|
||||||
|
return hl.get_window(window_selector(window)) or window
|
||||||
|
end
|
||||||
|
|
||||||
local function apply_scratchpad_geometry(name, window, target_monitor, position)
|
local function apply_scratchpad_geometry(name, window, target_monitor, position)
|
||||||
local def = scratchpads[name]
|
local def = scratchpads[name]
|
||||||
if not def or not window then
|
if not def or not window then
|
||||||
@@ -298,9 +350,12 @@ function M.setup(ctx)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function schedule_scratchpad_geometry(name, window, target_monitor, position, timeout)
|
local function schedule_scratchpad_geometry(name, window, target_monitor, position, timeout, opts)
|
||||||
hl.timer(function()
|
hl.timer(function()
|
||||||
apply_scratchpad_geometry(name, window, target_monitor, position)
|
local current_window = refreshed_window(window)
|
||||||
|
if should_apply_scratchpad_geometry(name, current_window, opts) then
|
||||||
|
apply_scratchpad_geometry(name, current_window, target_monitor, position)
|
||||||
|
end
|
||||||
end, { timeout = timeout or 50, type = "oneshot" })
|
end, { timeout = timeout or 50, type = "oneshot" })
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -332,8 +387,17 @@ function M.setup(ctx)
|
|||||||
move_window_to_workspace(scratchpad_workspace(name), false, window)
|
move_window_to_workspace(scratchpad_workspace(name), false, window)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function show_scratchpad_window(name, window, workspace, target_monitor)
|
local function scratchpad_show_workspace(workspace)
|
||||||
workspace = workspace or active_workspace()
|
workspace = workspace or active_workspace()
|
||||||
|
if is_normal_workspace(workspace) then
|
||||||
|
return workspace
|
||||||
|
end
|
||||||
|
|
||||||
|
return hl.get_workspace(tostring(active_workspace_id()))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function show_scratchpad_window(name, window, workspace, target_monitor, opts)
|
||||||
|
workspace = scratchpad_show_workspace(workspace)
|
||||||
if not workspace then
|
if not workspace then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -346,8 +410,8 @@ function M.setup(ctx)
|
|||||||
dispatch(hl.dsp.focus({ window = window_selector(window) }))
|
dispatch(hl.dsp.focus({ window = window_selector(window) }))
|
||||||
if scratchpads[name] and scratchpads[name].dropdown then
|
if scratchpads[name] and scratchpads[name].dropdown then
|
||||||
animate_dropdown_scratchpad_down(name, window, target_monitor or hl.get_active_monitor())
|
animate_dropdown_scratchpad_down(name, window, target_monitor or hl.get_active_monitor())
|
||||||
else
|
elseif should_apply_scratchpad_geometry(name, window, opts) then
|
||||||
schedule_scratchpad_geometry(name, window, target_monitor or hl.get_active_monitor())
|
schedule_scratchpad_geometry(name, window, target_monitor or hl.get_active_monitor(), nil, nil, opts)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -362,7 +426,12 @@ function M.setup(ctx)
|
|||||||
local windows = {}
|
local windows = {}
|
||||||
for _, window in ipairs(hl.get_windows()) do
|
for _, window in ipairs(hl.get_windows()) do
|
||||||
local name = matching_scratchpad_name(window)
|
local name = matching_scratchpad_name(window)
|
||||||
if name and name ~= except_name and scratchpad_is_visible(window) then
|
if
|
||||||
|
name
|
||||||
|
and name ~= except_name
|
||||||
|
and scratchpad_is_visible(window)
|
||||||
|
and not tiled_scratchpad_is_normal_window(window, scratchpads[name])
|
||||||
|
then
|
||||||
windows[#windows + 1] = {
|
windows[#windows + 1] = {
|
||||||
name = name,
|
name = name,
|
||||||
window = window,
|
window = window,
|
||||||
@@ -404,7 +473,9 @@ function M.setup(ctx)
|
|||||||
if scratchpad_pending[name] then
|
if scratchpad_pending[name] then
|
||||||
local pending = scratchpad_pending[name]
|
local pending = scratchpad_pending[name]
|
||||||
scratchpad_pending[name] = nil
|
scratchpad_pending[name] = nil
|
||||||
show_scratchpad_window(name, window, pending.workspace or active_workspace(), pending.monitor or hl.get_active_monitor())
|
show_scratchpad_window(name, window, pending.workspace or active_workspace(), pending.monitor or hl.get_active_monitor(), {
|
||||||
|
force_geometry = true,
|
||||||
|
})
|
||||||
elseif scratchpad_is_visible(window) then
|
elseif scratchpad_is_visible(window) then
|
||||||
schedule_scratchpad_geometry(name, window, hl.get_active_monitor())
|
schedule_scratchpad_geometry(name, window, hl.get_active_monitor())
|
||||||
end
|
end
|
||||||
@@ -424,10 +495,12 @@ function M.setup(ctx)
|
|||||||
|
|
||||||
local windows = matching_scratchpad_windows(name)
|
local windows = matching_scratchpad_windows(name)
|
||||||
if #windows == 0 then
|
if #windows == 0 then
|
||||||
|
local workspace = scratchpad_show_workspace()
|
||||||
|
local target_monitor = hl.get_active_monitor()
|
||||||
hide_active_scratchpads(name)
|
hide_active_scratchpads(name)
|
||||||
scratchpad_pending[name] = {
|
scratchpad_pending[name] = {
|
||||||
monitor = hl.get_active_monitor(),
|
monitor = target_monitor,
|
||||||
workspace = active_workspace(),
|
workspace = workspace,
|
||||||
}
|
}
|
||||||
hl.exec_cmd(def.command)
|
hl.exec_cmd(def.command)
|
||||||
return
|
return
|
||||||
@@ -446,18 +519,73 @@ function M.setup(ctx)
|
|||||||
hide_scratchpad_window(name, window)
|
hide_scratchpad_window(name, window)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
hide_active_scratchpads(name)
|
local workspace = scratchpad_show_workspace()
|
||||||
local workspace = active_workspace()
|
|
||||||
local target_monitor = hl.get_active_monitor()
|
local target_monitor = hl.get_active_monitor()
|
||||||
|
hide_active_scratchpads(name)
|
||||||
for _, window in ipairs(windows) do
|
for _, window in ipairs(windows) do
|
||||||
show_scratchpad_window(name, window, workspace, target_monitor)
|
show_scratchpad_window(name, window, workspace, target_monitor)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Which AI scratchpad SUPER+ALT+C targets. Selected at runtime (no reload)
|
||||||
|
-- by rofi_ai_scratchpad.sh, which writes the chosen name to this file.
|
||||||
|
local ai_scratchpad_default = "codex"
|
||||||
|
|
||||||
|
local function ai_scratchpad_state_path()
|
||||||
|
local base = os.getenv("XDG_STATE_HOME") or ((os.getenv("HOME") or "") .. "/.local/state")
|
||||||
|
return base .. "/hypr/ai-scratchpad"
|
||||||
|
end
|
||||||
|
|
||||||
|
local function active_ai_scratchpad()
|
||||||
|
local file = io.open(ai_scratchpad_state_path(), "r")
|
||||||
|
if not file then
|
||||||
|
return ai_scratchpad_default
|
||||||
|
end
|
||||||
|
|
||||||
|
local value = file:read("*l")
|
||||||
|
file:close()
|
||||||
|
value = value and value:gsub("%s+", "")
|
||||||
|
if scratchpads[value] then
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
return ai_scratchpad_default
|
||||||
|
end
|
||||||
|
|
||||||
|
local function toggle_active_ai_scratchpad()
|
||||||
|
toggle_scratchpad(active_ai_scratchpad())
|
||||||
|
end
|
||||||
|
|
||||||
|
local function backup_ai_scratchpad()
|
||||||
|
if active_ai_scratchpad() == "codex" then
|
||||||
|
return "claude"
|
||||||
|
end
|
||||||
|
return "codex"
|
||||||
|
end
|
||||||
|
|
||||||
|
local function toggle_backup_ai_scratchpad()
|
||||||
|
toggle_scratchpad(backup_ai_scratchpad())
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Used by rofi_ai_scratchpad.sh after a selection: bring the chosen
|
||||||
|
-- scratchpad into view if it isn't already, without hiding it when it is.
|
||||||
|
local function show_active_ai_scratchpad()
|
||||||
|
local name = active_ai_scratchpad()
|
||||||
|
for _, window in ipairs(matching_scratchpad_windows(name)) do
|
||||||
|
if scratchpad_is_visible(window) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
toggle_scratchpad(name)
|
||||||
|
end
|
||||||
|
|
||||||
|
_G.im_hyprland_toggle_ai_scratchpad = toggle_active_ai_scratchpad
|
||||||
|
_G.im_hyprland_show_ai_scratchpad = show_active_ai_scratchpad
|
||||||
|
|
||||||
ctx.lower_contains = lower_contains
|
ctx.lower_contains = lower_contains
|
||||||
ctx.lower_contains_any = lower_contains_any
|
ctx.lower_contains_any = lower_contains_any
|
||||||
ctx.scratchpad_window_matches = scratchpad_window_matches
|
ctx.scratchpad_window_matches = scratchpad_window_matches
|
||||||
|
ctx.tiled_scratchpad_is_normal_window = tiled_scratchpad_is_normal_window
|
||||||
ctx.is_scratchpad_window = is_scratchpad_window
|
ctx.is_scratchpad_window = is_scratchpad_window
|
||||||
ctx.matching_scratchpad_name = matching_scratchpad_name
|
ctx.matching_scratchpad_name = matching_scratchpad_name
|
||||||
ctx.scratchpad_workspace = scratchpad_workspace
|
ctx.scratchpad_workspace = scratchpad_workspace
|
||||||
@@ -470,12 +598,16 @@ function M.setup(ctx)
|
|||||||
ctx.refresh_monitor_reserved_cache = refresh_monitor_reserved_cache
|
ctx.refresh_monitor_reserved_cache = refresh_monitor_reserved_cache
|
||||||
ctx.monitor_workarea = monitor_workarea
|
ctx.monitor_workarea = monitor_workarea
|
||||||
ctx.scratchpad_geometry = scratchpad_geometry
|
ctx.scratchpad_geometry = scratchpad_geometry
|
||||||
|
ctx.should_apply_scratchpad_geometry = should_apply_scratchpad_geometry
|
||||||
|
ctx.refreshed_window = refreshed_window
|
||||||
ctx.matching_scratchpad_windows = matching_scratchpad_windows
|
ctx.matching_scratchpad_windows = matching_scratchpad_windows
|
||||||
|
ctx.default_scratchpad_geometry = default_scratchpad_geometry
|
||||||
ctx.apply_scratchpad_geometry = apply_scratchpad_geometry
|
ctx.apply_scratchpad_geometry = apply_scratchpad_geometry
|
||||||
ctx.schedule_scratchpad_geometry = schedule_scratchpad_geometry
|
ctx.schedule_scratchpad_geometry = schedule_scratchpad_geometry
|
||||||
ctx.dropdown_spring_progress = dropdown_spring_progress
|
ctx.dropdown_spring_progress = dropdown_spring_progress
|
||||||
ctx.animate_dropdown_scratchpad_down = animate_dropdown_scratchpad_down
|
ctx.animate_dropdown_scratchpad_down = animate_dropdown_scratchpad_down
|
||||||
ctx.hide_scratchpad_window = hide_scratchpad_window
|
ctx.hide_scratchpad_window = hide_scratchpad_window
|
||||||
|
ctx.scratchpad_show_workspace = scratchpad_show_workspace
|
||||||
ctx.show_scratchpad_window = show_scratchpad_window
|
ctx.show_scratchpad_window = show_scratchpad_window
|
||||||
ctx.scratchpad_is_visible = scratchpad_is_visible
|
ctx.scratchpad_is_visible = scratchpad_is_visible
|
||||||
ctx.active_scratchpad_windows = active_scratchpad_windows
|
ctx.active_scratchpad_windows = active_scratchpad_windows
|
||||||
@@ -485,6 +617,11 @@ function M.setup(ctx)
|
|||||||
ctx.refresh_shell_workarea_and_scratchpads = refresh_shell_workarea_and_scratchpads
|
ctx.refresh_shell_workarea_and_scratchpads = refresh_shell_workarea_and_scratchpads
|
||||||
ctx.adopt_matching_scratchpad_window = adopt_matching_scratchpad_window
|
ctx.adopt_matching_scratchpad_window = adopt_matching_scratchpad_window
|
||||||
ctx.toggle_scratchpad = toggle_scratchpad
|
ctx.toggle_scratchpad = toggle_scratchpad
|
||||||
|
ctx.active_ai_scratchpad = active_ai_scratchpad
|
||||||
|
ctx.backup_ai_scratchpad = backup_ai_scratchpad
|
||||||
|
ctx.toggle_active_ai_scratchpad = toggle_active_ai_scratchpad
|
||||||
|
ctx.toggle_backup_ai_scratchpad = toggle_backup_ai_scratchpad
|
||||||
|
ctx.show_active_ai_scratchpad = show_active_ai_scratchpad
|
||||||
end
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ local M = {}
|
|||||||
|
|
||||||
function M.setup(ctx)
|
function M.setup(ctx)
|
||||||
local _ENV = ctx
|
local _ENV = ctx
|
||||||
|
local file_chooser_class_rule = "^(xdg-desktop-portal-gtk|org\\.freedesktop\\.impl\\.portal\\.desktop\\.gtk)$"
|
||||||
local file_chooser_title_rule = "^(Open File|Open Files|Save File|Save Files|Save As|Select File|Select Files|Choose File|Choose Files|File Upload|Upload File|Upload Files|Select Folder|Choose Folder|Open Folder|Save Folder)$"
|
local file_chooser_title_rule = "^(Open File|Open Files|Save File|Save Files|Save As|Select File|Select Files|Choose File|Choose Files|File Upload|Upload File|Upload Files|Select Folder|Choose Folder|Open Folder|Save Folder)$"
|
||||||
|
|
||||||
local function lower_string(value)
|
local function lower_string(value)
|
||||||
@@ -41,9 +42,20 @@ function M.setup(ctx)
|
|||||||
or title:find("file picker", 1, true) ~= nil
|
or title:find("file picker", 1, true) ~= nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function class_indicates_file_chooser(class)
|
||||||
|
class = lower_string(class)
|
||||||
|
return class == "xdg-desktop-portal-gtk"
|
||||||
|
or class == "org.freedesktop.impl.portal.desktop.gtk"
|
||||||
|
end
|
||||||
|
|
||||||
local function is_file_chooser_window(window)
|
local function is_file_chooser_window(window)
|
||||||
return window
|
return window
|
||||||
and (title_indicates_file_chooser(window.title) or title_indicates_file_chooser(window.initial_title))
|
and (
|
||||||
|
title_indicates_file_chooser(window.title)
|
||||||
|
or title_indicates_file_chooser(window.initial_title)
|
||||||
|
or class_indicates_file_chooser(window.class)
|
||||||
|
or class_indicates_file_chooser(window.initial_class)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function raise_file_chooser_window(window)
|
local function raise_file_chooser_window(window)
|
||||||
@@ -72,24 +84,31 @@ function M.setup(ctx)
|
|||||||
if enable_nstack and not verify_config then
|
if enable_nstack and not verify_config then
|
||||||
hl.plugin.load("/run/current-system/sw/lib/libhyprNStack.so")
|
hl.plugin.load("/run/current-system/sw/lib/libhyprNStack.so")
|
||||||
end
|
end
|
||||||
if enable_hyprexpo and not verify_config then
|
|
||||||
hl.plugin.load("/run/current-system/sw/lib/libhyprexpo.so")
|
|
||||||
end
|
|
||||||
if enable_hyprwinview and not verify_config then
|
if enable_hyprwinview and not verify_config then
|
||||||
hl.plugin.load("/run/current-system/sw/lib/libhyprwinview.so")
|
hl.plugin.load("/run/current-system/sw/lib/libhyprwinview.so")
|
||||||
end
|
end
|
||||||
|
if enable_hyprtasking and not verify_config then
|
||||||
|
hl.plugin.load("/run/current-system/sw/lib/libhyprtasking.so")
|
||||||
|
os.execute("hyprctl eval 'hl.config({plugin={hyprtasking={full_render=true}}})' >/dev/null 2>&1 || true")
|
||||||
|
end
|
||||||
|
if enable_hyprexpo and not enable_hyprtasking and not verify_config then
|
||||||
|
hl.plugin.load("/run/current-system/sw/lib/libhyprexpo.so")
|
||||||
|
end
|
||||||
if enable_workspace_history and not verify_config then
|
if enable_workspace_history and not verify_config then
|
||||||
hl.plugin.load("/run/current-system/sw/lib/libhypr-workspace-history.so")
|
hl.plugin.load("/run/current-system/sw/lib/libhypr-workspace-history.so")
|
||||||
end
|
end
|
||||||
if enable_hyprwobbly and not verify_config then
|
if enable_hyprwobbly and not verify_config then
|
||||||
hl.plugin.load("/run/current-system/sw/lib/libhyprwobbly.so")
|
hl.plugin.load("/run/current-system/sw/lib/libhyprwobbly.so")
|
||||||
end
|
end
|
||||||
|
if enable_dynamic_cursors and not verify_config then
|
||||||
|
hl.plugin.load("/run/current-system/sw/lib/libhypr-dynamic-cursors.so")
|
||||||
|
end
|
||||||
if enable_hyprglass and not verify_config then
|
if enable_hyprglass and not verify_config then
|
||||||
hl.plugin.load("/run/current-system/sw/lib/hyprglass.so")
|
hl.plugin.load("/run/current-system/sw/lib/hyprglass.so")
|
||||||
end
|
end
|
||||||
|
|
||||||
hl.env("XCURSOR_SIZE", "24")
|
hl.env("XCURSOR_SIZE", tostring(hyprland_cursor_size))
|
||||||
hl.env("HYPRCURSOR_SIZE", "24")
|
hl.env("HYPRCURSOR_SIZE", tostring(hyprland_cursor_size))
|
||||||
hl.env("QT_QPA_PLATFORMTHEME", "qt5ct")
|
hl.env("QT_QPA_PLATFORMTHEME", "qt5ct")
|
||||||
hl.env("HYPR_MAX_WORKSPACE", "9")
|
hl.env("HYPR_MAX_WORKSPACE", "9")
|
||||||
|
|
||||||
@@ -110,8 +129,8 @@ function M.setup(ctx)
|
|||||||
persistent_warps = true,
|
persistent_warps = true,
|
||||||
},
|
},
|
||||||
general = {
|
general = {
|
||||||
gaps_in = 5,
|
gaps_in = hyprland_gaps_enabled and 5 or 0,
|
||||||
gaps_out = 10,
|
gaps_out = hyprland_gaps_enabled and 10 or 0,
|
||||||
border_size = 2,
|
border_size = 2,
|
||||||
col = {
|
col = {
|
||||||
active_border = { colors = { "rgba(3b82f6ee)", "rgba(33ccffee)" }, angle = 45 },
|
active_border = { colors = { "rgba(3b82f6ee)", "rgba(33ccffee)" }, angle = 45 },
|
||||||
@@ -166,6 +185,7 @@ function M.setup(ctx)
|
|||||||
force_default_wallpaper = 0,
|
force_default_wallpaper = 0,
|
||||||
disable_hyprland_logo = true,
|
disable_hyprland_logo = true,
|
||||||
exit_window_retains_fullscreen = true,
|
exit_window_retains_fullscreen = true,
|
||||||
|
focus_on_activate = true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -275,6 +295,45 @@ function M.setup(ctx)
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function apply_dynamic_cursors_config()
|
||||||
|
if verify_config or not enable_dynamic_cursors then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
hl.config({
|
||||||
|
plugin = {
|
||||||
|
dynamic_cursors = {
|
||||||
|
enabled = true,
|
||||||
|
mode = "tilt",
|
||||||
|
threshold = 2,
|
||||||
|
tilt = {
|
||||||
|
limit = 5000,
|
||||||
|
activation = "negative_quadratic",
|
||||||
|
window = 100,
|
||||||
|
full = 60,
|
||||||
|
},
|
||||||
|
shake = {
|
||||||
|
enabled = true,
|
||||||
|
threshold = 6.0,
|
||||||
|
base = 4.0,
|
||||||
|
speed = 4.0,
|
||||||
|
influence = 0.0,
|
||||||
|
limit = 0.0,
|
||||||
|
timeout = 2000,
|
||||||
|
effects = true,
|
||||||
|
ipc = false,
|
||||||
|
},
|
||||||
|
hyprcursor = {
|
||||||
|
nearest = 1,
|
||||||
|
enabled = true,
|
||||||
|
resolution = -1,
|
||||||
|
fallback = "clientside",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
local function apply_visual_performance_mode()
|
local function apply_visual_performance_mode()
|
||||||
if verify_config then
|
if verify_config then
|
||||||
return
|
return
|
||||||
@@ -323,6 +382,18 @@ function M.setup(ctx)
|
|||||||
hl.workspace_rule({ workspace = "w[tv1]s[false]", gaps_out = 0, gaps_in = 0 })
|
hl.workspace_rule({ workspace = "w[tv1]s[false]", gaps_out = 0, gaps_in = 0 })
|
||||||
hl.workspace_rule({ workspace = "f[1]s[false]", gaps_out = 0, gaps_in = 0 })
|
hl.workspace_rule({ workspace = "f[1]s[false]", gaps_out = 0, gaps_in = 0 })
|
||||||
|
|
||||||
|
hl.window_rule({
|
||||||
|
name = "tagged-gaming-window",
|
||||||
|
match = { tag = gaming_window_tag },
|
||||||
|
idle_inhibit = "fullscreen",
|
||||||
|
opaque = true,
|
||||||
|
no_blur = true,
|
||||||
|
no_shadow = true,
|
||||||
|
no_anim = true,
|
||||||
|
rounding = 0,
|
||||||
|
border_size = 0,
|
||||||
|
})
|
||||||
|
|
||||||
hl.window_rule({ match = { class = "^()$", title = "^()$" }, float = true })
|
hl.window_rule({ match = { class = "^()$", title = "^()$" }, float = true })
|
||||||
hl.window_rule({ match = { title = "^(Picture-in-Picture)$" }, float = true })
|
hl.window_rule({ match = { title = "^(Picture-in-Picture)$" }, float = true })
|
||||||
hl.window_rule({
|
hl.window_rule({
|
||||||
@@ -349,8 +420,30 @@ function M.setup(ctx)
|
|||||||
focus_on_activate = true,
|
focus_on_activate = true,
|
||||||
stay_focused = true,
|
stay_focused = true,
|
||||||
})
|
})
|
||||||
|
hl.window_rule({
|
||||||
|
name = "portal-gtk-dialogs",
|
||||||
|
match = { class = file_chooser_class_rule },
|
||||||
|
float = true,
|
||||||
|
center = true,
|
||||||
|
focus_on_activate = true,
|
||||||
|
stay_focused = true,
|
||||||
|
})
|
||||||
hl.window_rule({ match = { title = "^(Confirm)$" }, float = true })
|
hl.window_rule({ match = { title = "^(Confirm)$" }, float = true })
|
||||||
|
|
||||||
|
-- The AI desktop apps fire xdg-activation requests while streaming
|
||||||
|
-- responses; with misc:focus_on_activate=true that steals focus from
|
||||||
|
-- whatever window the user is actually working in. focus_on_activate is
|
||||||
|
-- a dynamic rule (applies to already-mapped windows on reload);
|
||||||
|
-- suppress_event only applies at map time.
|
||||||
|
for index, class in ipairs({ "^(claude-desktop)$", "^(codex-desktop)$" }) do
|
||||||
|
hl.window_rule({
|
||||||
|
name = "ai-app-no-activate-focus-" .. tostring(index),
|
||||||
|
match = { class = class },
|
||||||
|
focus_on_activate = false,
|
||||||
|
suppress_event = "activatefocus",
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
for index, match in ipairs({
|
for index, match in ipairs({
|
||||||
{ class = "^(flameshot)$" },
|
{ class = "^(flameshot)$" },
|
||||||
{ title = "^(flameshot)$" },
|
{ title = "^(flameshot)$" },
|
||||||
@@ -412,6 +505,7 @@ function M.setup(ctx)
|
|||||||
ctx.apply_rules = apply_rules
|
ctx.apply_rules = apply_rules
|
||||||
ctx.apply_hyprglass_config = apply_hyprglass_config
|
ctx.apply_hyprglass_config = apply_hyprglass_config
|
||||||
ctx.apply_hyprwobbly_config = apply_hyprwobbly_config
|
ctx.apply_hyprwobbly_config = apply_hyprwobbly_config
|
||||||
|
ctx.apply_dynamic_cursors_config = apply_dynamic_cursors_config
|
||||||
ctx.apply_visual_performance_mode = apply_visual_performance_mode
|
ctx.apply_visual_performance_mode = apply_visual_performance_mode
|
||||||
ctx.is_file_chooser_window = is_file_chooser_window
|
ctx.is_file_chooser_window = is_file_chooser_window
|
||||||
ctx.raise_file_chooser_window = raise_file_chooser_window
|
ctx.raise_file_chooser_window = raise_file_chooser_window
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ local shell_ui_command = "hypr_shell_ui"
|
|||||||
local columns_layout = "nStack"
|
local columns_layout = "nStack"
|
||||||
local large_main_layout = "master"
|
local large_main_layout = "master"
|
||||||
local grid_layout = "grid"
|
local grid_layout = "grid"
|
||||||
|
local quadrants_layout = "quadrants"
|
||||||
local monocle_layout = "monocle"
|
local monocle_layout = "monocle"
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -33,29 +34,50 @@ return {
|
|||||||
columns_layout = columns_layout,
|
columns_layout = columns_layout,
|
||||||
large_main_layout = large_main_layout,
|
large_main_layout = large_main_layout,
|
||||||
grid_layout = grid_layout,
|
grid_layout = grid_layout,
|
||||||
|
quadrants_layout = quadrants_layout,
|
||||||
monocle_layout = monocle_layout,
|
monocle_layout = monocle_layout,
|
||||||
layout_cycle = { columns_layout, large_main_layout, grid_layout },
|
layout_cycle = { columns_layout, large_main_layout, quadrants_layout, grid_layout },
|
||||||
layout_names = {
|
layout_names = {
|
||||||
[columns_layout] = "Columns",
|
[columns_layout] = "Columns",
|
||||||
[large_main_layout] = "Large main",
|
[large_main_layout] = "Large main",
|
||||||
|
[quadrants_layout] = "Quadrants",
|
||||||
[grid_layout] = "Grid",
|
[grid_layout] = "Grid",
|
||||||
[monocle_layout] = "Monocle",
|
[monocle_layout] = "Monocle",
|
||||||
},
|
},
|
||||||
minimized_workspace = "special:minimized",
|
minimized_workspace = "special:minimized",
|
||||||
inactive_opacity_override_tag = "no-inactive-opacity",
|
inactive_opacity_override_tag = "no-inactive-opacity",
|
||||||
|
gaming_window_tag = "gaming",
|
||||||
|
gaming_window_disabled_tag = "no-gaming",
|
||||||
|
gaming_window_class_patterns = {},
|
||||||
|
gaming_window_title_patterns = {},
|
||||||
|
gaming_window_excluded_class_patterns = {
|
||||||
|
"^[Hh]eroic$",
|
||||||
|
"^[Ss]team$",
|
||||||
|
},
|
||||||
|
gaming_window_excluded_title_patterns = {
|
||||||
|
"^Heroic Games Launcher$",
|
||||||
|
"^Steam$",
|
||||||
|
},
|
||||||
tabbed_group_restore_workspace_prefix = "special:tabbed-monocle-restore-",
|
tabbed_group_restore_workspace_prefix = "special:tabbed-monocle-restore-",
|
||||||
current_layout = columns_layout,
|
current_layout = columns_layout,
|
||||||
enable_nstack = true,
|
enable_nstack = true,
|
||||||
enable_hyprexpo = true,
|
-- Disabled 2026-06-11: live-preview backend SEGVs Hyprland (shouldRenderWindow
|
||||||
|
-- hook fires on every popup commit). Re-enable once fixed upstream.
|
||||||
|
enable_hyprexpo = false,
|
||||||
enable_hyprwinview = true,
|
enable_hyprwinview = true,
|
||||||
|
enable_hyprtasking = true,
|
||||||
enable_workspace_history = true,
|
enable_workspace_history = true,
|
||||||
enable_hyprwobbly = true,
|
enable_hyprwobbly = true,
|
||||||
|
enable_dynamic_cursors = true,
|
||||||
enable_hyprglass = false,
|
enable_hyprglass = false,
|
||||||
|
hyprland_gaps_enabled = os.getenv("IMALISON_HYPRLAND_GAPS") ~= "0",
|
||||||
|
hyprland_cursor_size = tonumber(os.getenv("IMALISON_HYPRLAND_CURSOR_SIZE")) or 24,
|
||||||
hypr_visual_performance_mode = false,
|
hypr_visual_performance_mode = false,
|
||||||
configure_nstack_plugin_from_lua = false,
|
configure_nstack_plugin_from_lua = false,
|
||||||
workspace_layouts = {},
|
workspace_layouts = {},
|
||||||
minimized_windows = {},
|
minimized_windows = {},
|
||||||
tabbed_workspace_groups = {},
|
tabbed_workspace_groups = {},
|
||||||
|
quadrants_arranging = false,
|
||||||
window_picker_mode = nil,
|
window_picker_mode = nil,
|
||||||
window_picker_candidates = {},
|
window_picker_candidates = {},
|
||||||
stack_update_timer = nil,
|
stack_update_timer = nil,
|
||||||
|
|||||||
@@ -122,6 +122,44 @@ function M.setup(ctx)
|
|||||||
dispatch(hl.dsp.window.resize())
|
dispatch(hl.dsp.window.resize())
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function float_active_window_to_default_scratchpad_geometry()
|
||||||
|
local window = hl.get_active_window()
|
||||||
|
local selector = window_selector(window)
|
||||||
|
if not selector then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local geometry = default_scratchpad_geometry(hl.get_active_monitor())
|
||||||
|
if not geometry then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
dispatch(hl.dsp.window.fullscreen_state({
|
||||||
|
internal = 0,
|
||||||
|
client = 0,
|
||||||
|
action = "set",
|
||||||
|
window = selector,
|
||||||
|
}))
|
||||||
|
dispatch(hl.dsp.window.float({ action = "enable", window = selector }))
|
||||||
|
dispatch(hl.dsp.window.resize({ x = geometry.width, y = geometry.height, relative = false, window = selector }))
|
||||||
|
dispatch(hl.dsp.window.move({ x = geometry.x, y = geometry.y, relative = false, window = selector }))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function tile_or_float_active_window()
|
||||||
|
local window = hl.get_active_window()
|
||||||
|
local selector = window_selector(window)
|
||||||
|
if not selector then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if window.floating then
|
||||||
|
dispatch(hl.dsp.window.float({ action = "disable", window = selector }))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
float_active_window_to_default_scratchpad_geometry()
|
||||||
|
end
|
||||||
|
|
||||||
local function toggle_pinned_active_window()
|
local function toggle_pinned_active_window()
|
||||||
local window = hl.get_active_window()
|
local window = hl.get_active_window()
|
||||||
local selector = window_selector(window)
|
local selector = window_selector(window)
|
||||||
@@ -365,6 +403,108 @@ function M.setup(ctx)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function value_matches_any_pattern(value, patterns)
|
||||||
|
value = tostring(value or "")
|
||||||
|
if value == "" then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, pattern in ipairs(patterns or {}) do
|
||||||
|
if value:find(pattern) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function is_game_like_window(window)
|
||||||
|
if not window then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if window_has_tag(window, gaming_window_disabled_tag) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if
|
||||||
|
value_matches_any_pattern(window.class, gaming_window_excluded_class_patterns)
|
||||||
|
or value_matches_any_pattern(window.initial_class, gaming_window_excluded_class_patterns)
|
||||||
|
or value_matches_any_pattern(window.title, gaming_window_excluded_title_patterns)
|
||||||
|
or value_matches_any_pattern(window.initial_title, gaming_window_excluded_title_patterns)
|
||||||
|
then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return tostring(window.content_type or window.content or "") == "game"
|
||||||
|
or window_has_tag(window, gaming_window_tag)
|
||||||
|
or value_matches_any_pattern(window.class, gaming_window_class_patterns)
|
||||||
|
or value_matches_any_pattern(window.initial_class, gaming_window_class_patterns)
|
||||||
|
or value_matches_any_pattern(window.title, gaming_window_title_patterns)
|
||||||
|
or value_matches_any_pattern(window.initial_title, gaming_window_title_patterns)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function set_window_gaming_mode(window, enabled, opts)
|
||||||
|
local selector = window_selector(window)
|
||||||
|
if not selector then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if enabled then
|
||||||
|
dispatch(hl.dsp.window.tag({ tag = "-" .. gaming_window_disabled_tag, window = selector }))
|
||||||
|
dispatch(hl.dsp.window.tag({ tag = "+" .. gaming_window_tag, window = selector }))
|
||||||
|
dispatch(hl.dsp.window.fullscreen_state({
|
||||||
|
internal = 2,
|
||||||
|
client = 2,
|
||||||
|
action = "set",
|
||||||
|
window = selector,
|
||||||
|
}))
|
||||||
|
else
|
||||||
|
dispatch(hl.dsp.window.tag({ tag = "-" .. gaming_window_tag, window = selector }))
|
||||||
|
dispatch(hl.dsp.window.tag({ tag = "+" .. gaming_window_disabled_tag, window = selector }))
|
||||||
|
dispatch(hl.dsp.window.fullscreen_state({
|
||||||
|
internal = 0,
|
||||||
|
client = 0,
|
||||||
|
action = "set",
|
||||||
|
window = selector,
|
||||||
|
}))
|
||||||
|
end
|
||||||
|
|
||||||
|
if not (opts and opts.quiet) then
|
||||||
|
hl.notification.create({
|
||||||
|
text = "Gaming fullscreen: " .. (enabled and "on" or "off"),
|
||||||
|
duration = 1600,
|
||||||
|
icon = enabled and notification_icons.ok or notification_icons.info,
|
||||||
|
color = enabled and "rgba(33ccffee)" or "rgba(edb443ff)",
|
||||||
|
font_size = 13,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function toggle_active_window_gaming_mode()
|
||||||
|
local window = hl.get_active_window()
|
||||||
|
if not window then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
set_window_gaming_mode(window, not window_has_tag(window, gaming_window_tag))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function toggle_active_window_real_fullscreen()
|
||||||
|
local window = hl.get_active_window()
|
||||||
|
if not window then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local fullscreen = tonumber(window.fullscreen) or 0
|
||||||
|
local fullscreen_client = tonumber(window.fullscreen_client) or 0
|
||||||
|
local enabling = fullscreen ~= 2 or fullscreen_client ~= 2
|
||||||
|
dispatch(hl.dsp.window.fullscreen_state({
|
||||||
|
internal = enabling and 2 or 0,
|
||||||
|
client = enabling and 2 or 0,
|
||||||
|
action = "set",
|
||||||
|
window = window_selector(window),
|
||||||
|
}))
|
||||||
|
end
|
||||||
|
|
||||||
local function toggle_inactive_opacity_for_active_window()
|
local function toggle_inactive_opacity_for_active_window()
|
||||||
local window = hl.get_active_window()
|
local window = hl.get_active_window()
|
||||||
local selector = window_selector(window)
|
local selector = window_selector(window)
|
||||||
@@ -481,6 +621,8 @@ function M.setup(ctx)
|
|||||||
ctx.float_active_window_preserving_tiled_geometry = float_active_window_preserving_tiled_geometry
|
ctx.float_active_window_preserving_tiled_geometry = float_active_window_preserving_tiled_geometry
|
||||||
ctx.float_and_drag_active_window = float_and_drag_active_window
|
ctx.float_and_drag_active_window = float_and_drag_active_window
|
||||||
ctx.float_and_resize_active_window = float_and_resize_active_window
|
ctx.float_and_resize_active_window = float_and_resize_active_window
|
||||||
|
ctx.float_active_window_to_default_scratchpad_geometry = float_active_window_to_default_scratchpad_geometry
|
||||||
|
ctx.tile_or_float_active_window = tile_or_float_active_window
|
||||||
ctx.toggle_pinned_active_window = toggle_pinned_active_window
|
ctx.toggle_pinned_active_window = toggle_pinned_active_window
|
||||||
ctx.current_minimized_windows = current_minimized_windows
|
ctx.current_minimized_windows = current_minimized_windows
|
||||||
ctx.restore_minimized_window = restore_minimized_window
|
ctx.restore_minimized_window = restore_minimized_window
|
||||||
@@ -490,6 +632,12 @@ function M.setup(ctx)
|
|||||||
ctx.gather_focused_class = gather_focused_class
|
ctx.gather_focused_class = gather_focused_class
|
||||||
ctx.focus_next_class = focus_next_class
|
ctx.focus_next_class = focus_next_class
|
||||||
ctx.show_active_window_info = show_active_window_info
|
ctx.show_active_window_info = show_active_window_info
|
||||||
|
ctx.window_has_tag = window_has_tag
|
||||||
|
ctx.value_matches_any_pattern = value_matches_any_pattern
|
||||||
|
ctx.is_game_like_window = is_game_like_window
|
||||||
|
ctx.set_window_gaming_mode = set_window_gaming_mode
|
||||||
|
ctx.toggle_active_window_gaming_mode = toggle_active_window_gaming_mode
|
||||||
|
ctx.toggle_active_window_real_fullscreen = toggle_active_window_real_fullscreen
|
||||||
ctx.toggle_inactive_opacity_for_active_window = toggle_inactive_opacity_for_active_window
|
ctx.toggle_inactive_opacity_for_active_window = toggle_inactive_opacity_for_active_window
|
||||||
ctx.raise_or_spawn = raise_or_spawn
|
ctx.raise_or_spawn = raise_or_spawn
|
||||||
ctx.minimize_active_window = minimize_active_window
|
ctx.minimize_active_window = minimize_active_window
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ spawnBindings =
|
|||||||
, key (super .|. alt) xK_s (toggleScratchpad "spotify")
|
, key (super .|. alt) xK_s (toggleScratchpad "spotify")
|
||||||
, key (super .|. alt) xK_t (toggleScratchpad "transmission")
|
, key (super .|. alt) xK_t (toggleScratchpad "transmission")
|
||||||
, key (super .|. alt) xK_v (toggleScratchpad "volume")
|
, key (super .|. alt) xK_v (toggleScratchpad "volume")
|
||||||
|
, key (super .|. alt) xK_x (toggleScratchpad "x-com")
|
||||||
, key (super .|. alt) xK_c (spawnAction "google-chrome-stable")
|
, key (super .|. alt) xK_c (spawnAction "google-chrome-stable")
|
||||||
, key super xK_e (spawnAction "emacsclient --eval '(emacs-everywhere)'")
|
, key super xK_e (spawnAction "emacsclient --eval '(emacs-everywhere)'")
|
||||||
, key (super .|. ctrl) xK_e (shiftFocusedToNextEmptyWorkspace False)
|
, key (super .|. ctrl) xK_e (shiftFocusedToNextEmptyWorkspace False)
|
||||||
@@ -165,7 +166,7 @@ spawnBindings =
|
|||||||
, key (hyper .|. shift) xK_k (spawnAction "rofi_kill_all.sh")
|
, key (hyper .|. shift) xK_k (spawnAction "rofi_kill_all.sh")
|
||||||
, key hyper xK_r (spawnAction "rofi_systemd_mono")
|
, key hyper xK_r (spawnAction "rofi_systemd_mono")
|
||||||
, key hyper xK_9 (spawnAction "start_synergy.sh")
|
, key hyper xK_9 (spawnAction "start_synergy.sh")
|
||||||
, key hyper xK_backslash (spawnAction "$HOME/dotfiles/dotfiles/lib/functions/mpg341cx_input toggle")
|
, key hyper xK_backslash (spawnAction "mpg341cx_input toggle")
|
||||||
, key hyper xK_i (spawnAction "rofi_select_input.hs")
|
, key hyper xK_i (spawnAction "rofi_select_input.hs")
|
||||||
, key hyper xK_o (spawnAction "rofi_paswitch")
|
, key hyper xK_o (spawnAction "rofi_paswitch")
|
||||||
, key hyper xK_comma (spawnAction "rofi_wallpaper.sh")
|
, key hyper xK_comma (spawnAction "rofi_wallpaper.sh")
|
||||||
@@ -297,6 +298,8 @@ scratchpadDefinitions =
|
|||||||
anyMatcher [titleContains "Transmission", appIdContains "transmission"]
|
anyMatcher [titleContains "Transmission", appIdContains "transmission"]
|
||||||
, ScratchpadDefinition "volume" "pavucontrol" $
|
, ScratchpadDefinition "volume" "pavucontrol" $
|
||||||
anyMatcher [appIdMatches "Pavucontrol", appIdContains "pavucontrol"]
|
anyMatcher [appIdMatches "Pavucontrol", appIdContains "pavucontrol"]
|
||||||
|
, ScratchpadDefinition "x-com" "x-com-pwa" $
|
||||||
|
anyMatcher [appIdMatches "x-com-pwa", appIdContains "chrome-x.com"]
|
||||||
]
|
]
|
||||||
|
|
||||||
anyMatcher :: [RiverWMWindowState -> Bool] -> RiverWMWindowState -> Bool
|
anyMatcher :: [RiverWMWindowState -> Bool] -> RiverWMWindowState -> Bool
|
||||||
|
|||||||
@@ -15,8 +15,11 @@ configuration {
|
|||||||
backdrop: #0b102026;
|
backdrop: #0b102026;
|
||||||
panel: #00000000;
|
panel: #00000000;
|
||||||
control: #ffffffe0;
|
control: #ffffffe0;
|
||||||
|
candidate-soft: #0b102018;
|
||||||
|
candidate-frost: #ffffff12;
|
||||||
candidate: #18203372;
|
candidate: #18203372;
|
||||||
candidate-active:#2430489c;
|
candidate-active:#0a84ffd9;
|
||||||
|
candidate-line: #ffffff16;
|
||||||
text: #111827ff;
|
text: #111827ff;
|
||||||
text-muted: #667085ff;
|
text-muted: #667085ff;
|
||||||
text-on-dark: #f8fafcff;
|
text-on-dark: #f8fafcff;
|
||||||
@@ -53,6 +56,7 @@ mainbox {
|
|||||||
inputbar {
|
inputbar {
|
||||||
background-color: @control;
|
background-color: @control;
|
||||||
text-color: @text;
|
text-color: @text;
|
||||||
|
height: 50px;
|
||||||
children: [ prompt, entry ];
|
children: [ prompt, entry ];
|
||||||
border: 1px;
|
border: 1px;
|
||||||
border-color: @hairline;
|
border-color: @hairline;
|
||||||
@@ -80,11 +84,10 @@ entry {
|
|||||||
listview {
|
listview {
|
||||||
background-color: @bg;
|
background-color: @bg;
|
||||||
columns: 1;
|
columns: 1;
|
||||||
lines: 10;
|
lines: 17;
|
||||||
spacing: 0px;
|
spacing: 0px;
|
||||||
border: 1px;
|
border: 0px;
|
||||||
border-color: @border;
|
border-radius: 0px 0px 14px 14px;
|
||||||
border-radius: 14px;
|
|
||||||
cycle: false;
|
cycle: false;
|
||||||
dynamic: true;
|
dynamic: true;
|
||||||
layout: vertical;
|
layout: vertical;
|
||||||
@@ -96,12 +99,24 @@ element {
|
|||||||
text-color: @text-on-dark;
|
text-color: @text-on-dark;
|
||||||
orientation: horizontal;
|
orientation: horizontal;
|
||||||
border: 0px 0px 1px 0px;
|
border: 0px 0px 1px 0px;
|
||||||
border-color: @hairline;
|
border-color: @candidate-line;
|
||||||
border-radius: 0px;
|
border-radius: 0px;
|
||||||
padding: 11px 11px;
|
/*
|
||||||
|
* Rofi percentages are monitor-relative. Derive padding from:
|
||||||
|
* 78% - 176px mainbox padding - 50px inputbar - 10px spacing - 2px border.
|
||||||
|
*/
|
||||||
|
padding: calc( ( 78% - 238px ) / 34 - 12px ) 11px calc( ( 78% - 238px ) / 34 - 13px ) 11px;
|
||||||
spacing: 10px;
|
spacing: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
element normal {
|
||||||
|
background-color: @candidate-soft;
|
||||||
|
}
|
||||||
|
|
||||||
|
element alternate {
|
||||||
|
background-color: @candidate-soft;
|
||||||
|
}
|
||||||
|
|
||||||
element-icon {
|
element-icon {
|
||||||
background-color: @bg;
|
background-color: @bg;
|
||||||
text-color: inherit;
|
text-color: inherit;
|
||||||
@@ -117,9 +132,10 @@ element-text {
|
|||||||
}
|
}
|
||||||
|
|
||||||
element selected {
|
element selected {
|
||||||
background-color: @candidate;
|
background-color: @candidate-active;
|
||||||
text-color: @text-on-dark;
|
text-color: @text-on-dark;
|
||||||
border-color: @border;
|
border: 0px 0px 1px 4px;
|
||||||
|
border-color: @accent-soft;
|
||||||
}
|
}
|
||||||
|
|
||||||
element selected element-text {
|
element selected element-text {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
- Do not create extra panes or windows unless the user asks.
|
- Do not create extra panes or windows unless the user asks.
|
||||||
|
|
||||||
## NixOS workflow
|
## NixOS workflow
|
||||||
- This system is managed with a Nix flake at `~/dotfiles/nixos`.
|
- This system is managed with a Nix flake at `/etc/nixos` (`/srv/dotfiles/nixos`).
|
||||||
- Use `just switch` from that directory for rebuilds instead of plain `nixos-rebuild`.
|
- Use `just switch` from that directory for rebuilds instead of plain `nixos-rebuild`.
|
||||||
- Host configs live under `machines/`; choose the appropriate host when needed.
|
- Host configs live under `machines/`; choose the appropriate host when needed.
|
||||||
|
|
||||||
|
|||||||
116
dotfiles/config/taffybar/TaffybarConfig/AIUsage.hs
Normal file
116
dotfiles/config/taffybar/TaffybarConfig/AIUsage.hs
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
|
-- | A usage widget that follows the Hyprland AI scratchpad selection.
|
||||||
|
--
|
||||||
|
-- The Hyprland config (scratchpads.lua) lets SUPER+ALT+C toggle whichever AI
|
||||||
|
-- app is currently selected via rofi_ai_scratchpad.sh, which records the
|
||||||
|
-- choice in $XDG_STATE_HOME/hypr/ai-scratchpad. This widget reads the same
|
||||||
|
-- state file and shows the matching provider's usage section (OpenAI for
|
||||||
|
-- "codex", Anthropic for "claude"), switching live when the file changes.
|
||||||
|
module TaffybarConfig.AIUsage
|
||||||
|
( aiUsageWidget,
|
||||||
|
)
|
||||||
|
where
|
||||||
|
|
||||||
|
import Control.Exception (IOException, try)
|
||||||
|
import Control.Monad (void)
|
||||||
|
import Control.Monad.IO.Class (liftIO)
|
||||||
|
import Data.Text (Text)
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import qualified GI.Gtk as Gtk
|
||||||
|
import qualified System.FSNotify as FSNotify
|
||||||
|
import System.Directory (createDirectoryIfMissing, getHomeDirectory)
|
||||||
|
import System.Environment (lookupEnv)
|
||||||
|
import System.FilePath (takeFileName, (</>))
|
||||||
|
import System.Taffybar.Context (TaffyIO)
|
||||||
|
import System.Taffybar.Util (postGUIASync)
|
||||||
|
import System.Taffybar.Widget.AnthropicUsage
|
||||||
|
( AnthropicUsageDisplayMode (AnthropicUsageDisplayRemaining),
|
||||||
|
AnthropicUsageStackConfig (..),
|
||||||
|
anthropicUsageSectionNewWith,
|
||||||
|
defaultAnthropicUsageStackConfig,
|
||||||
|
)
|
||||||
|
import System.Taffybar.Widget.OpenAIUsage
|
||||||
|
( OpenAIUsageDisplayMode (OpenAIUsageDisplayRemaining),
|
||||||
|
OpenAIUsageStackConfig (..),
|
||||||
|
defaultOpenAIUsageStackConfig,
|
||||||
|
openAIUsageSectionNewWith,
|
||||||
|
)
|
||||||
|
import TaffybarConfig.WidgetUtil (decorateWithClassAndBox, usageLogoWidget)
|
||||||
|
|
||||||
|
codexChild, claudeChild :: Text
|
||||||
|
codexChild = "codex"
|
||||||
|
claudeChild = "claude"
|
||||||
|
|
||||||
|
aiScratchpadStateDir :: IO FilePath
|
||||||
|
aiScratchpadStateDir = do
|
||||||
|
stateHome <- lookupEnv "XDG_STATE_HOME"
|
||||||
|
base <- case stateHome of
|
||||||
|
Just dir | not (null dir) -> pure dir
|
||||||
|
_ -> (</> ".local/state") <$> getHomeDirectory
|
||||||
|
pure (base </> "hypr")
|
||||||
|
|
||||||
|
aiScratchpadStateFile :: FilePath
|
||||||
|
aiScratchpadStateFile = "ai-scratchpad"
|
||||||
|
|
||||||
|
-- | Read the currently selected AI scratchpad, defaulting to codex like the
|
||||||
|
-- Hyprland side does.
|
||||||
|
readActiveAIScratchpad :: IO Text
|
||||||
|
readActiveAIScratchpad = do
|
||||||
|
dir <- aiScratchpadStateDir
|
||||||
|
result <- try (readFile (dir </> aiScratchpadStateFile)) :: IO (Either IOException String)
|
||||||
|
pure $ case result of
|
||||||
|
Right contents
|
||||||
|
| T.strip (T.pack contents) == claudeChild -> claudeChild
|
||||||
|
_ -> codexChild
|
||||||
|
|
||||||
|
openAIUsageSection :: TaffyIO Gtk.Widget
|
||||||
|
openAIUsageSection = do
|
||||||
|
iconWidget <- liftIO $ usageLogoWidget "openai-symbol.svg" "OpenAI usage"
|
||||||
|
openAIUsageSectionNewWith
|
||||||
|
iconWidget
|
||||||
|
defaultOpenAIUsageStackConfig
|
||||||
|
{ openAIUsageStackDefaultDisplayMode = OpenAIUsageDisplayRemaining
|
||||||
|
}
|
||||||
|
|
||||||
|
anthropicUsageSection :: TaffyIO Gtk.Widget
|
||||||
|
anthropicUsageSection = do
|
||||||
|
iconWidget <- liftIO $ usageLogoWidget "claude-symbol.svg" "Claude usage"
|
||||||
|
anthropicUsageSectionNewWith
|
||||||
|
iconWidget
|
||||||
|
defaultAnthropicUsageStackConfig
|
||||||
|
{ anthropicUsageStackDefaultDisplayMode = AnthropicUsageDisplayRemaining
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | Show usage for whichever AI app the Hyprland AI scratchpad currently
|
||||||
|
-- targets, switching live when the selection changes.
|
||||||
|
aiUsageWidget :: TaffyIO Gtk.Widget
|
||||||
|
aiUsageWidget = do
|
||||||
|
openAIWidget <- openAIUsageSection
|
||||||
|
anthropicWidget <- anthropicUsageSection
|
||||||
|
stackWidget <- liftIO $ do
|
||||||
|
stack <- Gtk.stackNew
|
||||||
|
Gtk.stackAddNamed stack openAIWidget codexChild
|
||||||
|
Gtk.stackAddNamed stack anthropicWidget claudeChild
|
||||||
|
readActiveAIScratchpad >>= Gtk.stackSetVisibleChildName stack
|
||||||
|
|
||||||
|
let syncVisibleChild =
|
||||||
|
readActiveAIScratchpad
|
||||||
|
>>= \name -> postGUIASync (Gtk.stackSetVisibleChildName stack name)
|
||||||
|
|
||||||
|
void $ Gtk.onWidgetRealize stack $ do
|
||||||
|
stateDir <- aiScratchpadStateDir
|
||||||
|
createDirectoryIfMissing True stateDir
|
||||||
|
manager <- FSNotify.startManager
|
||||||
|
void $
|
||||||
|
FSNotify.watchDir
|
||||||
|
manager
|
||||||
|
stateDir
|
||||||
|
((== aiScratchpadStateFile) . takeFileName . FSNotify.eventPath)
|
||||||
|
(const syncVisibleChild)
|
||||||
|
syncVisibleChild
|
||||||
|
void $ Gtk.onWidgetUnrealize stack $ FSNotify.stopManager manager
|
||||||
|
|
||||||
|
Gtk.widgetShowAll stack
|
||||||
|
Gtk.toWidget stack
|
||||||
|
decorateWithClassAndBox "ai-usage" stackWidget
|
||||||
@@ -10,8 +10,8 @@ module TaffybarConfig.ChromeFavicons
|
|||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Control.Exception (IOException, try)
|
import Control.Exception (IOException, SomeException, try)
|
||||||
import Control.Monad (unless, when)
|
import Control.Monad (unless, void)
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO)
|
||||||
import Data.Char (isAlphaNum)
|
import Data.Char (isAlphaNum)
|
||||||
import Data.Int (Int32)
|
import Data.Int (Int32)
|
||||||
@@ -24,6 +24,7 @@ import System.Directory
|
|||||||
( createDirectoryIfMissing,
|
( createDirectoryIfMissing,
|
||||||
doesFileExist,
|
doesFileExist,
|
||||||
getFileSize,
|
getFileSize,
|
||||||
|
removeFile,
|
||||||
renameFile,
|
renameFile,
|
||||||
)
|
)
|
||||||
import System.Environment.XDG.BaseDir (getUserCacheDir)
|
import System.Environment.XDG.BaseDir (getUserCacheDir)
|
||||||
@@ -204,10 +205,11 @@ loadCachedFavicon size url = do
|
|||||||
path <- ensureCachedFavicon url
|
path <- ensureCachedFavicon url
|
||||||
case path of
|
case path of
|
||||||
Just faviconPath ->
|
Just faviconPath ->
|
||||||
try @IOException (Gdk.pixbufNewFromFileAtScale faviconPath size size True) >>= \case
|
loadPixbuf faviconPath size >>= \case
|
||||||
Right (Just pixbuf) -> pure (Just pixbuf)
|
Just pixbuf -> pure (Just pixbuf)
|
||||||
Right Nothing -> pure Nothing
|
Nothing -> do
|
||||||
Left _ -> pure Nothing
|
removeCachedFavicon faviconPath
|
||||||
|
pure Nothing
|
||||||
Nothing -> pure Nothing
|
Nothing -> pure Nothing
|
||||||
|
|
||||||
ensureCachedFavicon :: Text -> IO (Maybe FilePath)
|
ensureCachedFavicon :: Text -> IO (Maybe FilePath)
|
||||||
@@ -254,21 +256,28 @@ faviconExtension url =
|
|||||||
downloadFavicon :: Text -> FilePath -> IO ()
|
downloadFavicon :: Text -> FilePath -> IO ()
|
||||||
downloadFavicon url path = do
|
downloadFavicon url path = do
|
||||||
let tmp = path <> ".tmp"
|
let tmp = path <> ".tmp"
|
||||||
(code, _, _) <-
|
removeCachedFavicon tmp
|
||||||
readProcessWithExitCode
|
result <-
|
||||||
"curl"
|
try @IOException $
|
||||||
[ "-fsSL",
|
readProcessWithExitCode
|
||||||
"--max-time",
|
"curl"
|
||||||
"10",
|
[ "-fsSL",
|
||||||
"--retry",
|
"--max-time",
|
||||||
"1",
|
"10",
|
||||||
"-o",
|
"--retry",
|
||||||
tmp,
|
"1",
|
||||||
T.unpack url
|
"-o",
|
||||||
]
|
tmp,
|
||||||
""
|
T.unpack url
|
||||||
when (code == ExitSuccess) $
|
]
|
||||||
renameFile tmp path
|
""
|
||||||
|
case result of
|
||||||
|
Right (ExitSuccess, _, _) -> do
|
||||||
|
mPixbuf <- loadPixbuf tmp 1
|
||||||
|
case mPixbuf of
|
||||||
|
Just _ -> renameFile tmp path
|
||||||
|
Nothing -> removeCachedFavicon tmp
|
||||||
|
_ -> removeCachedFavicon tmp
|
||||||
|
|
||||||
nonEmptyFileExists :: FilePath -> IO Bool
|
nonEmptyFileExists :: FilePath -> IO Bool
|
||||||
nonEmptyFileExists path = do
|
nonEmptyFileExists path = do
|
||||||
@@ -318,3 +327,13 @@ composeChromeFavicon cfg size favicon chromeIcon = do
|
|||||||
scalePixbuf :: Int32 -> Gdk.Pixbuf -> IO Gdk.Pixbuf
|
scalePixbuf :: Int32 -> Gdk.Pixbuf -> IO Gdk.Pixbuf
|
||||||
scalePixbuf size pixbuf =
|
scalePixbuf size pixbuf =
|
||||||
fromMaybe pixbuf <$> Gdk.pixbufScaleSimple pixbuf size size GdkPixbuf.InterpTypeBilinear
|
fromMaybe pixbuf <$> Gdk.pixbufScaleSimple pixbuf size size GdkPixbuf.InterpTypeBilinear
|
||||||
|
|
||||||
|
loadPixbuf :: FilePath -> Int32 -> IO (Maybe Gdk.Pixbuf)
|
||||||
|
loadPixbuf path size =
|
||||||
|
try @SomeException (Gdk.pixbufNewFromFileAtScale path size size True) >>= \case
|
||||||
|
Right pixbuf -> pure pixbuf
|
||||||
|
Left _ -> pure Nothing
|
||||||
|
|
||||||
|
removeCachedFavicon :: FilePath -> IO ()
|
||||||
|
removeCachedFavicon path =
|
||||||
|
void $ try @IOException (removeFile path)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ module TaffybarConfig.Config
|
|||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import TaffybarConfig.Host (compactBarHosts, smallBarHosts)
|
import TaffybarConfig.Host (compactBarHosts, smallBarHosts, tinyBarHosts)
|
||||||
import TaffybarConfig.Widgets (clockWidget, endWidgetsForHost, startWidgetsForHostAndBackend)
|
import TaffybarConfig.Widgets (clockWidget, endWidgetsForHost, startWidgetsForHostAndBackend)
|
||||||
import System.Taffybar.Context (Backend)
|
import System.Taffybar.Context (Backend)
|
||||||
import System.Taffybar.SimpleConfig
|
import System.Taffybar.SimpleConfig
|
||||||
@@ -18,18 +18,24 @@ mkSimpleTaffyConfig hostName backend cssFiles =
|
|||||||
barPosition = Top,
|
barPosition = Top,
|
||||||
widgetSpacing = 0,
|
widgetSpacing = 0,
|
||||||
barPadding =
|
barPadding =
|
||||||
if hostName `elem` smallBarHosts
|
if hostName `elem` tinyBarHosts
|
||||||
then 1
|
then 0
|
||||||
else
|
else
|
||||||
if hostName `elem` compactBarHosts
|
if hostName `elem` smallBarHosts
|
||||||
then 2
|
then 1
|
||||||
else 4,
|
else
|
||||||
|
if hostName `elem` compactBarHosts
|
||||||
|
then 2
|
||||||
|
else 4,
|
||||||
barHeight =
|
barHeight =
|
||||||
if hostName `elem` smallBarHosts
|
if hostName `elem` tinyBarHosts
|
||||||
then ScreenRatio $ 1 / 48
|
then ScreenRatio $ 1 / 90
|
||||||
else
|
else
|
||||||
if hostName `elem` compactBarHosts
|
if hostName `elem` smallBarHosts
|
||||||
then ScreenRatio $ 1 / 40
|
then ScreenRatio $ 1 / 72
|
||||||
else ScreenRatio $ 1 / 33,
|
else
|
||||||
|
if hostName `elem` compactBarHosts
|
||||||
|
then ScreenRatio $ 1 / 60
|
||||||
|
else ScreenRatio $ 2 / 99,
|
||||||
cssPaths = cssFiles
|
cssPaths = cssFiles
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ module TaffybarConfig.Host
|
|||||||
cssFilesForHost,
|
cssFilesForHost,
|
||||||
laptopHosts,
|
laptopHosts,
|
||||||
smallBarHosts,
|
smallBarHosts,
|
||||||
|
tinyBarHosts,
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@@ -16,7 +17,8 @@ defaultCssFiles = ["taffybar.css"]
|
|||||||
|
|
||||||
cssFilesByHostname :: [(String, [FilePath])]
|
cssFilesByHostname :: [(String, [FilePath])]
|
||||||
cssFilesByHostname =
|
cssFilesByHostname =
|
||||||
[ ("ryzen-shine", ["ryzen-shine.css"]),
|
[ ("jay-lenovo", ["jay-lenovo.css"]),
|
||||||
|
("ryzen-shine", ["ryzen-shine.css"]),
|
||||||
("strixi-minaj", ["strixi-minaj.css"])
|
("strixi-minaj", ["strixi-minaj.css"])
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -28,6 +30,10 @@ smallBarHosts :: [String]
|
|||||||
smallBarHosts =
|
smallBarHosts =
|
||||||
["strixi-minaj"]
|
["strixi-minaj"]
|
||||||
|
|
||||||
|
tinyBarHosts :: [String]
|
||||||
|
tinyBarHosts =
|
||||||
|
["jay-lenovo"]
|
||||||
|
|
||||||
laptopHosts :: [String]
|
laptopHosts :: [String]
|
||||||
laptopHosts =
|
laptopHosts =
|
||||||
[ "adell",
|
[ "adell",
|
||||||
|
|||||||
@@ -33,12 +33,6 @@ import qualified System.Taffybar.Widget.Audio as Audio
|
|||||||
import System.Taffybar.Widget.CPUMonitor (cpuMonitorNew)
|
import System.Taffybar.Widget.CPUMonitor (cpuMonitorNew)
|
||||||
import System.Taffybar.Widget.Generic.Graph (GraphConfig (..), GraphDirection (..), GraphStyle (..), defaultGraphConfig)
|
import System.Taffybar.Widget.Generic.Graph (GraphConfig (..), GraphDirection (..), GraphStyle (..), defaultGraphConfig)
|
||||||
import qualified System.Taffybar.Widget.NetworkManager as NetworkManager
|
import qualified System.Taffybar.Widget.NetworkManager as NetworkManager
|
||||||
import System.Taffybar.Widget.OpenAIUsage
|
|
||||||
( OpenAIUsageDisplayMode (OpenAIUsageDisplayRemaining),
|
|
||||||
OpenAIUsageStackConfig (..),
|
|
||||||
defaultOpenAIUsageStackConfig,
|
|
||||||
openAIUsageSectionNewWith,
|
|
||||||
)
|
|
||||||
import System.Taffybar.Widget.SNIMenu (withNmAppletMenu)
|
import System.Taffybar.Widget.SNIMenu (withNmAppletMenu)
|
||||||
import System.Taffybar.Widget.SNITray
|
import System.Taffybar.Widget.SNITray
|
||||||
( CollapsibleSNITrayParams (..),
|
( CollapsibleSNITrayParams (..),
|
||||||
@@ -60,6 +54,7 @@ import System.Taffybar.Widget.Util
|
|||||||
)
|
)
|
||||||
import qualified System.Taffybar.Widget.Wlsunset as Wlsunset
|
import qualified System.Taffybar.Widget.Wlsunset as Wlsunset
|
||||||
import qualified System.Taffybar.Widget.Workspaces as Workspaces
|
import qualified System.Taffybar.Widget.Workspaces as Workspaces
|
||||||
|
import TaffybarConfig.AIUsage (aiUsageWidget)
|
||||||
import TaffybarConfig.Host (laptopHosts)
|
import TaffybarConfig.Host (laptopHosts)
|
||||||
import TaffybarConfig.WidgetUtil
|
import TaffybarConfig.WidgetUtil
|
||||||
( decorateWithClassAndBox,
|
( decorateWithClassAndBox,
|
||||||
@@ -355,9 +350,9 @@ omniMenuWidget =
|
|||||||
OmniMenuSection
|
OmniMenuSection
|
||||||
"System"
|
"System"
|
||||||
[ omniMenuItem "Lock" "system-lock-screen" "loginctl lock-session",
|
[ omniMenuItem "Lock" "system-lock-screen" "loginctl lock-session",
|
||||||
omniMenuItem "Toggle screensaver" "video-display" "/home/imalison/dotfiles/dotfiles/lib/bin/hypr-screensaver toggle",
|
omniMenuItem "Toggle screensaver" "video-display" "hypr-screensaver toggle",
|
||||||
omniMenuItem "Reload WM" "view-refresh" "sh -lc 'hyprctl reload || xmonad --restart || river-xmonad-restart'",
|
omniMenuItem "Reload WM" "view-refresh" "sh -lc 'hyprctl reload || xmonad --restart || river-xmonad-restart'",
|
||||||
omniMenuItem "Restart taffybar" "view-refresh-symbolic" "/home/imalison/dotfiles/dotfiles/config/taffybar/scripts/taffybar-restart",
|
omniMenuItem "Restart taffybar" "view-refresh-symbolic" "/srv/dotfiles/dotfiles/config/taffybar/scripts/taffybar-restart",
|
||||||
omniMenuItem "Logout" "system-log-out" "sh -lc 'hyprctl dispatch exit || riverctl exit'",
|
omniMenuItem "Logout" "system-log-out" "sh -lc 'hyprctl dispatch exit || riverctl exit'",
|
||||||
omniMenuItem "Suspend" "media-playback-pause" "systemctl suspend",
|
omniMenuItem "Suspend" "media-playback-pause" "systemctl suspend",
|
||||||
omniMenuItem "Reboot" "system-reboot" "systemctl reboot",
|
omniMenuItem "Reboot" "system-reboot" "systemctl reboot",
|
||||||
@@ -375,16 +370,6 @@ usageSectionWidget klass iconFile tooltip stackBuilder =
|
|||||||
section <- buildIconLabelBox iconWidget stack
|
section <- buildIconLabelBox iconWidget stack
|
||||||
widgetSetClassGI section "usage-section"
|
widgetSetClassGI section "usage-section"
|
||||||
|
|
||||||
openAIUsageWidget :: TaffyIO Gtk.Widget
|
|
||||||
openAIUsageWidget = do
|
|
||||||
iconWidget <- liftIO $ usageLogoWidget "openai-symbol.svg" "OpenAI usage"
|
|
||||||
decorateWithClassAndBoxM "openai-usage" $
|
|
||||||
openAIUsageSectionNewWith
|
|
||||||
iconWidget
|
|
||||||
defaultOpenAIUsageStackConfig
|
|
||||||
{ openAIUsageStackDefaultDisplayMode = OpenAIUsageDisplayRemaining
|
|
||||||
}
|
|
||||||
|
|
||||||
sniPriorityVisibilityThresholdDefault :: Int
|
sniPriorityVisibilityThresholdDefault :: Int
|
||||||
sniPriorityVisibilityThresholdDefault = 0
|
sniPriorityVisibilityThresholdDefault = 0
|
||||||
|
|
||||||
@@ -445,7 +430,7 @@ endWidgetsForHost hostName =
|
|||||||
let baseEndWidgets =
|
let baseEndWidgets =
|
||||||
[ sniTrayWidget,
|
[ sniTrayWidget,
|
||||||
audioWidget,
|
audioWidget,
|
||||||
openAIUsageWidget,
|
aiUsageWidget,
|
||||||
cpuWidget,
|
cpuWidget,
|
||||||
ramSwapWidget,
|
ramSwapWidget,
|
||||||
diskUsageWidget,
|
diskUsageWidget,
|
||||||
@@ -458,7 +443,7 @@ endWidgetsForHost hostName =
|
|||||||
sniTrayWidget,
|
sniTrayWidget,
|
||||||
asusDiskUsageWidget,
|
asusDiskUsageWidget,
|
||||||
audioBacklightWidget,
|
audioBacklightWidget,
|
||||||
openAIUsageWidget,
|
aiUsageWidget,
|
||||||
cpuWidget,
|
cpuWidget,
|
||||||
ramSwapWidget,
|
ramSwapWidget,
|
||||||
sunLockWidget,
|
sunLockWidget,
|
||||||
|
|||||||
@@ -191,6 +191,5 @@ workspaceWindowIconGetter :: Workspaces.WindowIconPixbufGetter
|
|||||||
workspaceWindowIconGetter =
|
workspaceWindowIconGetter =
|
||||||
chromeFaviconIconGetter chromeFaviconConfig
|
chromeFaviconIconGetter chromeFaviconConfig
|
||||||
<|||> workspaceManualIconGetter
|
<|||> workspaceManualIconGetter
|
||||||
<|||> Workspaces.getWindowIconPixbufFromChrome
|
|
||||||
<|||> Workspaces.defaultGetWindowIconPixbuf
|
<|||> Workspaces.defaultGetWindowIconPixbuf
|
||||||
<|||> workspaceFallbackIcon
|
<|||> workspaceFallbackIcon
|
||||||
|
|||||||
7
dotfiles/config/taffybar/flake.lock
generated
7
dotfiles/config/taffybar/flake.lock
generated
@@ -136,15 +136,16 @@
|
|||||||
"xmonad-contrib": "xmonad-contrib"
|
"xmonad-contrib": "xmonad-contrib"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1778673962,
|
"lastModified": 1781172310,
|
||||||
"narHash": "sha256-GmHRMdrUIQpMf6k5gRjP9Mvx2WO0FvIEF1SPlxEpnas=",
|
"narHash": "sha256-mBd3obUUS+ICqL+U2bOanGwaGl2rfbMZdGzAFiqRSaE=",
|
||||||
"owner": "taffybar",
|
"owner": "taffybar",
|
||||||
"repo": "taffybar",
|
"repo": "taffybar",
|
||||||
"rev": "08125b267c03232c560fce6259264cc9283d582e",
|
"rev": "7beecc89928df669281977e41ceed213c5ede88f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "taffybar",
|
"owner": "taffybar",
|
||||||
|
"ref": "anthropic-usage-rate-limit-backoff",
|
||||||
"repo": "taffybar",
|
"repo": "taffybar",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,13 @@
|
|||||||
taffybar = {
|
taffybar = {
|
||||||
# Keep the default source usable in CI. Local iteration uses
|
# Keep the default source usable in CI. Local iteration uses
|
||||||
# IMALISON_TAFFYBAR_LIVE_CHECKOUT below via `just switch-local-taffybar`.
|
# IMALISON_TAFFYBAR_LIVE_CHECKOUT below via `just switch-local-taffybar`.
|
||||||
url = "github:taffybar/taffybar";
|
# Pinned to the rate-limit-backoff PR branch (taffybar/taffybar#681);
|
||||||
inputs.weeder-nix.inputs.pre-commit-hooks.inputs.nixpkgs.follows = "nixpkgs";
|
# revert to master after it merges.
|
||||||
|
url = "github:taffybar/taffybar/anthropic-usage-rate-limit-backoff";
|
||||||
|
inputs.weeder-nix = {
|
||||||
|
url = "github:NorfairKing/weeder-nix";
|
||||||
|
inputs.pre-commit-hooks.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
# Follow the vendored taffybar flake's pins so the config shell and the
|
# Follow the vendored taffybar flake's pins so the config shell and the
|
||||||
# library shell mostly share their nixpkgs/Haskell dependency graph.
|
# library shell mostly share their nixpkgs/Haskell dependency graph.
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ cabal-version: >=1.10
|
|||||||
executable taffybar
|
executable taffybar
|
||||||
hs-source-dirs: .
|
hs-source-dirs: .
|
||||||
main-is: taffybar.hs
|
main-is: taffybar.hs
|
||||||
other-modules: TaffybarConfig.Config
|
other-modules: TaffybarConfig.AIUsage
|
||||||
|
, TaffybarConfig.Config
|
||||||
, TaffybarConfig.ChromeFavicons
|
, TaffybarConfig.ChromeFavicons
|
||||||
, TaffybarConfig.Host
|
, TaffybarConfig.Host
|
||||||
, TaffybarConfig.Widgets
|
, TaffybarConfig.Widgets
|
||||||
@@ -27,6 +28,7 @@ executable taffybar
|
|||||||
, containers
|
, containers
|
||||||
, directory
|
, directory
|
||||||
, filepath
|
, filepath
|
||||||
|
, fsnotify
|
||||||
, gi-gdk3
|
, gi-gdk3
|
||||||
, gi-gtk3
|
, gi-gtk3
|
||||||
, gi-gdkpixbuf
|
, gi-gdkpixbuf
|
||||||
|
|||||||
68
dotfiles/config/taffybar/jay-lenovo.css
Normal file
68
dotfiles/config/taffybar/jay-lenovo.css
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
@import url("taffybar.css");
|
||||||
|
|
||||||
|
/* Host-specific density tweak for jay-lenovo. */
|
||||||
|
.taffy-box {
|
||||||
|
font-size: 8.5pt;
|
||||||
|
border-radius: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outer-pad,
|
||||||
|
.workspaces .outer-pad {
|
||||||
|
border-radius: 7px;
|
||||||
|
margin: 2px 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-pad,
|
||||||
|
.workspaces .inner-pad {
|
||||||
|
border-radius: 6px;
|
||||||
|
padding-top: 0px;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-pad {
|
||||||
|
padding-left: 8px;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workspaces .inner-pad {
|
||||||
|
padding-left: 8px;
|
||||||
|
padding-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workspaces .contents {
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0px 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workspace-label {
|
||||||
|
font-size: 8pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workspaces .overlay-box .workspace-label {
|
||||||
|
padding: 0px 3px 3px 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.visible .contents,
|
||||||
|
.workspaces .window-icon-container,
|
||||||
|
.workspaces .window-icon-container.active {
|
||||||
|
padding-top: 0px;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auto-size-image,
|
||||||
|
.sni-tray {
|
||||||
|
padding-top: 0px;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-label > .icon,
|
||||||
|
.usage-section.icon-label > .icon,
|
||||||
|
.ram-swap .icon-label > .icon {
|
||||||
|
padding-right: 6px;
|
||||||
|
min-width: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sun-lock .wlsunset,
|
||||||
|
.sun-lock .screen-lock {
|
||||||
|
padding: 0px 3px;
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ priorities:
|
|||||||
priority: 0
|
priority: 0
|
||||||
- key: item-id:flameshot
|
- key: item-id:flameshot
|
||||||
priority: 0
|
priority: 0
|
||||||
- key: item-id:keepbook-sync-daemon
|
- key: item-id:keepbook-dioxus
|
||||||
priority: 0
|
priority: 0
|
||||||
- key: item-id:udiskie
|
- key: item-id:udiskie
|
||||||
priority: 0
|
priority: 0
|
||||||
@@ -41,6 +41,8 @@ priorities:
|
|||||||
priority: -1
|
priority: -1
|
||||||
- key: item-id:tailscale
|
- key: item-id:tailscale
|
||||||
priority: -1
|
priority: -1
|
||||||
|
- key: process:git-sync-rs
|
||||||
|
priority: -1
|
||||||
- key: process:tailscale
|
- key: process:tailscale
|
||||||
priority: -1
|
priority: -1
|
||||||
- key: item-id:spotify-client
|
- key: item-id:spotify-client
|
||||||
|
|||||||
Submodule dotfiles/config/taffybar/taffybar updated: 4c612d4457...feab5bf025
@@ -237,12 +237,18 @@ chromeSelectorBase = isChromeClass <$> className
|
|||||||
|
|
||||||
chromeSelector = chromeSelectorBase
|
chromeSelector = chromeSelectorBase
|
||||||
codexSelector = className =? "codex-desktop"
|
codexSelector = className =? "codex-desktop"
|
||||||
|
discordSelector = className =? "Discord" <||> className =? "discord"
|
||||||
elementSelector = className =? "Element"
|
elementSelector = className =? "Element"
|
||||||
emacsSelector = className =? "Emacs"
|
emacsSelector = className =? "Emacs"
|
||||||
slackSelector = className =? "Slack"
|
slackSelector = className =? "Slack"
|
||||||
spotifySelector = className =? "Spotify"
|
spotifySelector = className =? "Spotify"
|
||||||
transmissionSelector = fmap (isPrefixOf "Transmission") title
|
transmissionSelector = fmap (isPrefixOf "Transmission") title
|
||||||
volumeSelector = className =? "Pavucontrol"
|
volumeSelector = className =? "Pavucontrol"
|
||||||
|
xComSelector =
|
||||||
|
className =? "x-com-pwa"
|
||||||
|
<||> fmap ("chrome-x.com" `isInfixOf`) className
|
||||||
|
<||> (chromeSelectorBase <&&> title =? "X")
|
||||||
|
<||> fmap ("x.com" `isInfixOf`) title
|
||||||
|
|
||||||
virtualClasses =
|
virtualClasses =
|
||||||
[ (chromeSelector, "Chrome")
|
[ (chromeSelector, "Chrome")
|
||||||
@@ -252,6 +258,7 @@ virtualClasses =
|
|||||||
-- Commands
|
-- Commands
|
||||||
|
|
||||||
codexCommand = "codex_desktop_scratchpad"
|
codexCommand = "codex_desktop_scratchpad"
|
||||||
|
discordCommand = "discord"
|
||||||
elementCommand = "element-desktop"
|
elementCommand = "element-desktop"
|
||||||
emacsCommand = "emacsclient -c"
|
emacsCommand = "emacsclient -c"
|
||||||
htopCommand = "ghostty --title=htop -e htop"
|
htopCommand = "ghostty --title=htop -e htop"
|
||||||
@@ -259,6 +266,7 @@ slackCommand = "slack"
|
|||||||
spotifyCommand = "spotify"
|
spotifyCommand = "spotify"
|
||||||
transmissionCommand = "transmission-gtk"
|
transmissionCommand = "transmission-gtk"
|
||||||
volumeCommand = "pavucontrol"
|
volumeCommand = "pavucontrol"
|
||||||
|
xComCommand = "x-com-pwa"
|
||||||
|
|
||||||
-- Startup hook
|
-- Startup hook
|
||||||
|
|
||||||
@@ -802,12 +810,14 @@ nearFullFloat = customFloating $ W.RationalRect l t w h
|
|||||||
|
|
||||||
scratchpads =
|
scratchpads =
|
||||||
[ NS "codex" codexCommand codexSelector nearFullFloat
|
[ NS "codex" codexCommand codexSelector nearFullFloat
|
||||||
|
, NS "discord" discordCommand discordSelector nearFullFloat
|
||||||
, NS "element" elementCommand elementSelector nearFullFloat
|
, NS "element" elementCommand elementSelector nearFullFloat
|
||||||
, NS "htop" htopCommand (title =? "htop") nearFullFloat
|
, NS "htop" htopCommand (title =? "htop") nearFullFloat
|
||||||
, NS "slack" slackCommand slackSelector nearFullFloat
|
, NS "slack" slackCommand slackSelector nearFullFloat
|
||||||
, NS "spotify" spotifyCommand spotifySelector nearFullFloat
|
, NS "spotify" spotifyCommand spotifySelector nearFullFloat
|
||||||
, NS "transmission" transmissionCommand transmissionSelector nearFullFloat
|
, NS "transmission" transmissionCommand transmissionSelector nearFullFloat
|
||||||
, NS "volume" volumeCommand volumeSelector nearFullFloat
|
, NS "volume" volumeCommand volumeSelector nearFullFloat
|
||||||
|
, NS "x-com" xComCommand xComSelector nearFullFloat
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -1008,12 +1018,14 @@ addKeys conf@XConfig { modMask = modm } =
|
|||||||
|
|
||||||
-- ScratchPads
|
-- ScratchPads
|
||||||
[ ((modalt, xK_c), doScratchpad "codex")
|
[ ((modalt, xK_c), doScratchpad "codex")
|
||||||
|
, ((modalt, xK_d), doScratchpad "discord")
|
||||||
, ((modalt, xK_e), doScratchpad "element")
|
, ((modalt, xK_e), doScratchpad "element")
|
||||||
, ((modalt, xK_h), doScratchpad "htop")
|
, ((modalt, xK_h), doScratchpad "htop")
|
||||||
, ((modalt, xK_k), doScratchpad "slack")
|
, ((modalt, xK_k), doScratchpad "slack")
|
||||||
, ((modalt, xK_s), doScratchpad "spotify")
|
, ((modalt, xK_s), doScratchpad "spotify")
|
||||||
, ((modalt, xK_t), doScratchpad "transmission")
|
, ((modalt, xK_t), doScratchpad "transmission")
|
||||||
, ((modalt, xK_v), doScratchpad "volume")
|
, ((modalt, xK_v), doScratchpad "volume")
|
||||||
|
, ((modalt, xK_x), doScratchpad "x-com")
|
||||||
|
|
||||||
-- Specific program spawning
|
-- Specific program spawning
|
||||||
|
|
||||||
@@ -1071,6 +1083,7 @@ addKeys conf@XConfig { modMask = modm } =
|
|||||||
, ((hyper, xK_p), spawn "rofi-pass")
|
, ((hyper, xK_p), spawn "rofi-pass")
|
||||||
, ((0, xK_Print), spawn "flameshot gui")
|
, ((0, xK_Print), spawn "flameshot gui")
|
||||||
, ((hyper, xK_h), spawn "flameshot gui")
|
, ((hyper, xK_h), spawn "flameshot gui")
|
||||||
|
, ((hyper, xK_n), spawn "rofi_codex_desktop_project.sh")
|
||||||
, ((hyper, xK_c), spawn "rofi_tmcodex.sh")
|
, ((hyper, xK_c), spawn "rofi_tmcodex.sh")
|
||||||
, ((hyper .|. shiftMask, xK_c), spawn "rofi_tmcodex.sh resume")
|
, ((hyper .|. shiftMask, xK_c), spawn "rofi_tmcodex.sh resume")
|
||||||
, ((hyper .|. shiftMask, xK_l), spawn "dm-tool lock")
|
, ((hyper .|. shiftMask, xK_l), spawn "dm-tool lock")
|
||||||
@@ -1080,11 +1093,11 @@ addKeys conf@XConfig { modMask = modm } =
|
|||||||
, ((hyper, xK_r), spawn "rofi_systemd_mono")
|
, ((hyper, xK_r), spawn "rofi_systemd_mono")
|
||||||
, ((hyper, xK_9), spawn "start_synergy.sh")
|
, ((hyper, xK_9), spawn "start_synergy.sh")
|
||||||
, ((hyper, xK_slash), spawn "toggle_taffybar")
|
, ((hyper, xK_slash), spawn "toggle_taffybar")
|
||||||
, ((hyper, xK_backslash), spawn "$HOME/dotfiles/dotfiles/lib/functions/mpg341cx_input toggle")
|
, ((hyper, xK_backslash), spawn "mpg341cx_input toggle")
|
||||||
, ((hyper, xK_space), spawn "skippy-xd")
|
, ((hyper, xK_space), spawn "skippy-xd")
|
||||||
, ((hyper, xK_i), spawn "rofi_select_input.hs")
|
, ((hyper, xK_i), spawn "rofi_select_input.hs")
|
||||||
, ((hyper, xK_o), spawn "rofi_paswitch")
|
, ((hyper, xK_o), spawn "rofi_paswitch")
|
||||||
, ((hyper .|. shiftMask, xK_o), spawn "$HOME/dotfiles/dotfiles/lib/bin/kef-optical")
|
, ((hyper .|. shiftMask, xK_o), spawn "kef-optical")
|
||||||
, ((hyper, xK_comma), spawn "rofi_wallpaper.sh")
|
, ((hyper, xK_comma), spawn "rofi_wallpaper.sh")
|
||||||
, ((hyper, xK_y), spawn "rofi_agentic_skill")
|
, ((hyper, xK_y), spawn "rofi_agentic_skill")
|
||||||
, ((modm, xK_e), spawn "emacsclient --eval '(emacs-everywhere)'")
|
, ((modm, xK_e), spawn "emacsclient --eval '(emacs-everywhere)'")
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ keybinds {
|
|||||||
tmux {
|
tmux {
|
||||||
// Ctrl-b C: start a Codex pane from the current zellij tab.
|
// Ctrl-b C: start a Codex pane from the current zellij tab.
|
||||||
bind "C" {
|
bind "C" {
|
||||||
Run "codex" "--dangerously-bypass-approvals-and-sandbox" {
|
Run "codex" "--dangerously-bypass-approvals-and-sandbox" "--cd" "." {
|
||||||
name "codex"
|
name "codex"
|
||||||
}
|
}
|
||||||
SwitchToMode "Normal"
|
SwitchToMode "Normal"
|
||||||
|
|||||||
@@ -1383,8 +1383,12 @@ Paradox is a package.el extension. I have no use for it now that I use straight.
|
|||||||
#+END_SRC
|
#+END_SRC
|
||||||
** load-dir
|
** load-dir
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
|
(elpaca `(load-dir :host github :repo "emacs-straight/load-dir"
|
||||||
|
:branch "master"
|
||||||
|
:protocol https
|
||||||
|
:wait t))
|
||||||
(use-package load-dir
|
(use-package load-dir
|
||||||
:ensure (:host github :repo "emacs-straight/load-dir")
|
:ensure nil
|
||||||
:demand t
|
:demand t
|
||||||
:config
|
:config
|
||||||
(progn
|
(progn
|
||||||
@@ -1462,7 +1466,8 @@ The file server file for this emacs instance no longer exists.")
|
|||||||
#+END_SRC
|
#+END_SRC
|
||||||
** discover-my-major
|
** discover-my-major
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(use-package discover-my-major)
|
(use-package discover-my-major
|
||||||
|
:disabled t)
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
** refine
|
** refine
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
@@ -4037,6 +4042,7 @@ This is useful with server mode when editing gmail messages. I think that it is
|
|||||||
** android-mode
|
** android-mode
|
||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(use-package android-mode
|
(use-package android-mode
|
||||||
|
:ensure (:protocol https)
|
||||||
:defer t
|
:defer t
|
||||||
:config
|
:config
|
||||||
(progn
|
(progn
|
||||||
@@ -4110,7 +4116,8 @@ Ensure all themes that I use are installed:
|
|||||||
forest-blue-theme flatland-theme afternoon-theme
|
forest-blue-theme flatland-theme afternoon-theme
|
||||||
cyberpunk-theme dracula-theme))
|
cyberpunk-theme dracula-theme))
|
||||||
|
|
||||||
(mapcar #'elpaca-try packages-appearance)
|
(dolist (package packages-appearance)
|
||||||
|
(eval `(use-package ,package :defer t) t))
|
||||||
|
|
||||||
(use-package doom-themes
|
(use-package doom-themes
|
||||||
:defer t)
|
:defer t)
|
||||||
@@ -4282,8 +4289,22 @@ load-theme hook (See the heading below).
|
|||||||
#+BEGIN_SRC emacs-lisp
|
#+BEGIN_SRC emacs-lisp
|
||||||
(defvar imalison:appearance-setup-done nil)
|
(defvar imalison:appearance-setup-done nil)
|
||||||
|
|
||||||
|
(defun imalison:ensure-theme-load-path (theme)
|
||||||
|
(when (boundp 'elpaca-builds-directory)
|
||||||
|
(when-let ((theme-dir
|
||||||
|
(seq-find
|
||||||
|
(lambda (dir)
|
||||||
|
(file-exists-p
|
||||||
|
(expand-file-name (format "%s-theme.el" theme) dir)))
|
||||||
|
(directory-files
|
||||||
|
elpaca-builds-directory
|
||||||
|
t
|
||||||
|
directory-files-no-dot-files-regexp))))
|
||||||
|
(add-to-list 'custom-theme-load-path theme-dir))))
|
||||||
|
|
||||||
(defun imalison:appearance-setup-hook (&rest args)
|
(defun imalison:appearance-setup-hook (&rest args)
|
||||||
(unless imalison:appearance-setup-done
|
(unless imalison:appearance-setup-done
|
||||||
|
(imalison:ensure-theme-load-path imalison:dark-theme)
|
||||||
(unless (member imalison:dark-theme custom-enabled-themes)
|
(unless (member imalison:dark-theme custom-enabled-themes)
|
||||||
(load-theme imalison:dark-theme t))
|
(load-theme imalison:dark-theme t))
|
||||||
(apply 'imalison:appearance args)
|
(apply 'imalison:appearance args)
|
||||||
|
|||||||
@@ -135,13 +135,18 @@
|
|||||||
;; Some split packages fall through the active menus in this config. Give
|
;; Some split packages fall through the active menus in this config. Give
|
||||||
;; Elpaca an explicit source so startup doesn't get stuck on recipe lookup or
|
;; Elpaca an explicit source so startup doesn't get stuck on recipe lookup or
|
||||||
;; stale branch-mapped clones.
|
;; stale branch-mapped clones.
|
||||||
(elpaca `(queue :host github :repo "emacs-straight/queue"))
|
(elpaca `(queue :host github :repo "emacs-straight/queue"
|
||||||
|
:branch "master"
|
||||||
|
:protocol https))
|
||||||
(elpaca `(with-editor :host github :repo "magit/with-editor"
|
(elpaca `(with-editor :host github :repo "magit/with-editor"
|
||||||
:branch "main"))
|
:branch "main"
|
||||||
|
:protocol https))
|
||||||
(elpaca `(git-commit :host github :repo "magit/magit"
|
(elpaca `(git-commit :host github :repo "magit/magit"
|
||||||
:files ("lisp/git-commit.el" "lisp/git-commit-pkg.el")))
|
:files ("lisp/git-commit.el" "lisp/git-commit-pkg.el")
|
||||||
|
:protocol https))
|
||||||
(elpaca `(magit-section :host github :repo "magit/magit"
|
(elpaca `(magit-section :host github :repo "magit/magit"
|
||||||
:files ("lisp/magit-section.el" "lisp/magit-section-pkg.el")))
|
:files ("lisp/magit-section.el" "lisp/magit-section-pkg.el")
|
||||||
|
:protocol https))
|
||||||
|
|
||||||
(use-package gh
|
(use-package gh
|
||||||
:defer t
|
:defer t
|
||||||
|
|||||||
@@ -102,10 +102,10 @@
|
|||||||
required = true
|
required = true
|
||||||
[credential "https://github.com"]
|
[credential "https://github.com"]
|
||||||
helper =
|
helper =
|
||||||
helper = !/usr/bin/env gh auth git-credential
|
helper = !/nix/store/fxvyz1dx5wp87qgbd6dfkmqqb4fypm3b-gh-2.93.0/bin/.gh-wrapped auth git-credential
|
||||||
[credential "https://gist.github.com"]
|
[credential "https://gist.github.com"]
|
||||||
helper =
|
helper =
|
||||||
helper = !/usr/bin/env gh auth git-credential
|
helper = !/nix/store/fxvyz1dx5wp87qgbd6dfkmqqb4fypm3b-gh-2.93.0/bin/.gh-wrapped auth git-credential
|
||||||
[includeIf "gitdir:~/Projects/org-agenda-api/"]
|
[includeIf "gitdir:~/Projects/org-agenda-api/"]
|
||||||
path = ~/.gitconfig.org-agenda-api
|
path = ~/.gitconfig.org-agenda-api
|
||||||
[includeIf "gitdir:~/Projects/dotfiles/org-agenda-api/"]
|
[includeIf "gitdir:~/Projects/dotfiles/org-agenda-api/"]
|
||||||
@@ -116,3 +116,6 @@
|
|||||||
directory = /tmp/tmp.zfvv44RquC/runtime/data/org
|
directory = /tmp/tmp.zfvv44RquC/runtime/data/org
|
||||||
directory = /tmp/tmp.zFdvVnKk4B/runtime/data/org
|
directory = /tmp/tmp.zFdvVnKk4B/runtime/data/org
|
||||||
directory = /tmp/tmp.PQTdI3UzS3/runtime/data/org
|
directory = /tmp/tmp.PQTdI3UzS3/runtime/data/org
|
||||||
|
directory = /srv/dotfiles/dotfiles/config/taffybar/taffybar
|
||||||
|
directory = /srv/dotfiles
|
||||||
|
directory = /srv/dotfiles/.worktrees/taffybar-week-old
|
||||||
|
|||||||
@@ -80,3 +80,5 @@ cabal.project.local
|
|||||||
/untracked
|
/untracked
|
||||||
|
|
||||||
railbird-infra-*.json
|
railbird-infra-*.json
|
||||||
|
|
||||||
|
**/.claude/settings.local.json
|
||||||
|
|||||||
@@ -348,7 +348,7 @@ local function toggleMonitorInput()
|
|||||||
end
|
end
|
||||||
end, {
|
end, {
|
||||||
"-lc",
|
"-lc",
|
||||||
"export PATH=\"$HOME/.nix-profile/bin:/run/current-system/sw/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH\"; \"$HOME/dotfiles/dotfiles/lib/functions/mpg341cx_input\" toggle",
|
"export PATH=\"$HOME/.nix-profile/bin:/run/current-system/sw/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH\"; \"${DOTFILES_WORKTREE:-$HOME/dotfiles}/dotfiles/lib/functions/mpg341cx_input\" toggle",
|
||||||
}):start()
|
}):start()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ sendNotification brightness = do
|
|||||||
rawSystem "sh" ["-c", "command -v rumno >/dev/null 2>&1"]
|
rawSystem "sh" ["-c", "command -v rumno >/dev/null 2>&1"]
|
||||||
if rumnoExists
|
if rumnoExists
|
||||||
then do
|
then do
|
||||||
_ <- readProcess "rumno" ["notify", "-t", timeoutSeconds, "-b", show brightness] ""
|
_ <- readProcess "rumno" ["-t", timeoutSeconds, "-b", show brightness] ""
|
||||||
return ()
|
return ()
|
||||||
else putStrLn (show brightness)
|
else putStrLn (show brightness)
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ RUMNO_TIMEOUT="${RUMNO_TIMEOUT:-2.5}"
|
|||||||
|
|
||||||
# Show notification if rumno is available
|
# Show notification if rumno is available
|
||||||
if command -v rumno &> /dev/null; then
|
if command -v rumno &> /dev/null; then
|
||||||
rumno notify -t "$RUMNO_TIMEOUT" -b "$BRIGHTNESS"
|
rumno -t "$RUMNO_TIMEOUT" -b "$BRIGHTNESS"
|
||||||
else
|
else
|
||||||
echo "$BRIGHTNESS"
|
echo "$BRIGHTNESS"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -17,6 +17,218 @@ pid_is_alive() {
|
|||||||
[ -e "/proc/$pid/exe" ]
|
[ -e "/proc/$pid/exe" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pid_is_current_user() {
|
||||||
|
local pid="${1:-}"
|
||||||
|
local uid
|
||||||
|
|
||||||
|
uid="$(stat -c %u "/proc/$pid" 2>/dev/null || true)"
|
||||||
|
[ -n "$uid" ] && [ "$uid" = "$(id -u)" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_cmdline() {
|
||||||
|
local pid="$1"
|
||||||
|
|
||||||
|
tr '\0' ' ' < "/proc/$pid/cmdline" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_is_main_codex_desktop() {
|
||||||
|
local pid="$1"
|
||||||
|
local exe
|
||||||
|
local cmdline
|
||||||
|
|
||||||
|
pid_is_alive "$pid" || return 1
|
||||||
|
pid_is_current_user "$pid" || return 1
|
||||||
|
exe="$(readlink -f "/proc/$pid/exe" 2>/dev/null || true)"
|
||||||
|
[ -n "$exe" ] || return 1
|
||||||
|
[ "$(basename "$exe")" = "electron" ] || return 1
|
||||||
|
[ -x "$(dirname "$exe")/start.sh" ] || return 1
|
||||||
|
|
||||||
|
cmdline="$(pid_cmdline "$pid")"
|
||||||
|
case " $cmdline " in
|
||||||
|
*" --class=$app_id "*) ;;
|
||||||
|
*) return 1 ;;
|
||||||
|
esac
|
||||||
|
case " $cmdline " in
|
||||||
|
*" --app-id=$app_id "*) ;;
|
||||||
|
*) return 1 ;;
|
||||||
|
esac
|
||||||
|
case " $cmdline " in
|
||||||
|
*" --type="*) return 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
find_running_app() {
|
||||||
|
local proc_exe
|
||||||
|
local pid
|
||||||
|
local exe
|
||||||
|
|
||||||
|
for proc_exe in /proc/[0-9]*/exe; do
|
||||||
|
[ -e "$proc_exe" ] || continue
|
||||||
|
pid="${proc_exe#/proc/}"
|
||||||
|
pid="${pid%/exe}"
|
||||||
|
if pid_is_main_codex_desktop "$pid"; then
|
||||||
|
exe="$(readlink -f "$proc_exe" 2>/dev/null || true)"
|
||||||
|
printf '%s\t%s\n' "$pid" "$(dirname "$exe")"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
find_recorded_running_app() {
|
||||||
|
local pid
|
||||||
|
local exe
|
||||||
|
|
||||||
|
[ -r "$pid_file" ] || return 1
|
||||||
|
pid="$(cat "$pid_file" 2>/dev/null || true)"
|
||||||
|
pid_is_main_codex_desktop "$pid" || return 1
|
||||||
|
exe="$(readlink -f "/proc/$pid/exe" 2>/dev/null || true)"
|
||||||
|
[ -n "$exe" ] || return 1
|
||||||
|
printf '%s\t%s\n' "$pid" "$(dirname "$exe")"
|
||||||
|
}
|
||||||
|
|
||||||
|
dbus_names_for_pid() {
|
||||||
|
local pid="$1"
|
||||||
|
|
||||||
|
command -v busctl >/dev/null 2>&1 || return 0
|
||||||
|
busctl --user list --no-legend 2>/dev/null \
|
||||||
|
| awk -v pid="$pid" '$2 == pid && ($1 ~ /^:/ || $1 ~ /^org[.]kde[.]StatusNotifierItem-/) { print $1 }'
|
||||||
|
}
|
||||||
|
|
||||||
|
dbus_property_object_path() {
|
||||||
|
local service="$1"
|
||||||
|
local path="$2"
|
||||||
|
local interface="$3"
|
||||||
|
local property="$4"
|
||||||
|
|
||||||
|
timeout 3 busctl --user call "$service" "$path" org.freedesktop.DBus.Properties Get ss "$interface" "$property" 2>/dev/null \
|
||||||
|
| awk '$1 == "v" && $2 == "o" { gsub(/"/, "", $3); print $3; exit }'
|
||||||
|
}
|
||||||
|
|
||||||
|
dbus_name_has_status_notifier_item() {
|
||||||
|
local service="$1"
|
||||||
|
|
||||||
|
timeout 1 busctl --user tree "$service" 2>/dev/null | grep -q '/StatusNotifierItem'
|
||||||
|
}
|
||||||
|
|
||||||
|
open_codex_menu_item_id() {
|
||||||
|
local layout
|
||||||
|
|
||||||
|
layout="$(cat)"
|
||||||
|
CODEX_DBUSMENU_LAYOUT="$layout" python3 - <<'PY'
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
layout = os.environ.get("CODEX_DBUSMENU_LAYOUT", "")
|
||||||
|
for record in layout.split("(ia{sv}av)")[1:]:
|
||||||
|
item_id = re.match(r"\s+([0-9]+)\s+", record)
|
||||||
|
if item_id and re.search(r'"label"\s+s\s+"Open Codex"(?:\s|$)', record):
|
||||||
|
print(item_id.group(1))
|
||||||
|
break
|
||||||
|
PY
|
||||||
|
}
|
||||||
|
|
||||||
|
activate_codex_dbus_menu_item_for_service() {
|
||||||
|
local service="$1"
|
||||||
|
local menu_path
|
||||||
|
local layout
|
||||||
|
local item_id
|
||||||
|
|
||||||
|
command -v busctl >/dev/null 2>&1 || return 1
|
||||||
|
command -v timeout >/dev/null 2>&1 || return 1
|
||||||
|
|
||||||
|
menu_path="$(dbus_property_object_path "$service" /StatusNotifierItem org.kde.StatusNotifierItem Menu || true)"
|
||||||
|
[ -n "$menu_path" ] || menu_path=/com/canonical/dbusmenu
|
||||||
|
|
||||||
|
layout="$(timeout 3 busctl --user call "$service" "$menu_path" com.canonical.dbusmenu GetLayout iias 0 -- -1 0 2>/dev/null || true)"
|
||||||
|
[ -n "$layout" ] || return 1
|
||||||
|
|
||||||
|
item_id="$(printf '%s\n' "$layout" | open_codex_menu_item_id)"
|
||||||
|
[ -n "$item_id" ] || return 1
|
||||||
|
|
||||||
|
timeout 3 busctl --user call "$service" "$menu_path" com.canonical.dbusmenu Event isvu "$item_id" clicked v i 0 0 >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
activate_codex_tray_menu_item() {
|
||||||
|
local pid="$1"
|
||||||
|
local service
|
||||||
|
|
||||||
|
while IFS= read -r service; do
|
||||||
|
[ -n "$service" ] || continue
|
||||||
|
dbus_name_has_status_notifier_item "$service" || continue
|
||||||
|
if activate_codex_dbus_menu_item_for_service "$service"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done < <(dbus_names_for_pid "$pid" | awk '!seen[$0]++')
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
activate_status_notifier_item() {
|
||||||
|
local pid="$1"
|
||||||
|
local qdbus_cmd
|
||||||
|
local service
|
||||||
|
local path
|
||||||
|
|
||||||
|
qdbus_cmd="$(command -v qdbus || command -v qdbus6 || true)"
|
||||||
|
[ -n "$qdbus_cmd" ] || return 1
|
||||||
|
|
||||||
|
while IFS= read -r service; do
|
||||||
|
[ -n "$service" ] || continue
|
||||||
|
while IFS= read -r path; do
|
||||||
|
case "$path" in
|
||||||
|
*/StatusNotifierItem)
|
||||||
|
if "$qdbus_cmd" "$service" "$path" org.kde.StatusNotifierItem.Activate 0 0 >/dev/null 2>&1; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done < <("$qdbus_cmd" "$service" 2>/dev/null || true)
|
||||||
|
done < <("$qdbus_cmd" 2>/dev/null | grep -E "^org\\.kde\\.StatusNotifierItem-${pid}-" || true)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
focus_hyprland_window() {
|
||||||
|
local pid="$1"
|
||||||
|
local address
|
||||||
|
local output
|
||||||
|
|
||||||
|
command -v hyprctl >/dev/null 2>&1 || return 1
|
||||||
|
address="$(
|
||||||
|
HYPR_FOCUS_PID="$pid" python3 - <<'PY'
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
target_pid = int(os.environ["HYPR_FOCUS_PID"])
|
||||||
|
try:
|
||||||
|
clients = json.loads(subprocess.check_output(["hyprctl", "clients", "-j"], text=True, stderr=subprocess.DEVNULL))
|
||||||
|
except Exception:
|
||||||
|
raise SystemExit(1)
|
||||||
|
|
||||||
|
for client in clients:
|
||||||
|
if client.get("pid") == target_pid and client.get("address") and client.get("mapped", True) and not client.get("hidden", False):
|
||||||
|
print(client["address"])
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise SystemExit(1)
|
||||||
|
PY
|
||||||
|
)" || return 1
|
||||||
|
[ -n "$address" ] || return 1
|
||||||
|
|
||||||
|
output="$(hyprctl dispatch "hl.dsp.focus({ window = \"address:$address\" })" 2>&1)" || return 1
|
||||||
|
[ "$output" = "ok" ] || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
start_second_instance_handoff() {
|
||||||
|
(
|
||||||
|
exec codex-desktop "$@"
|
||||||
|
) >/dev/null 2>&1 &
|
||||||
|
}
|
||||||
|
|
||||||
running_app_is_alive() {
|
running_app_is_alive() {
|
||||||
local pid
|
local pid
|
||||||
|
|
||||||
@@ -56,4 +268,17 @@ if send_launch_action "$@"; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if running_app="$(find_recorded_running_app || find_running_app)"; then
|
||||||
|
running_pid="${running_app%% *}"
|
||||||
|
mkdir -p "$state_dir"
|
||||||
|
printf '%s\n' "$running_pid" > "$pid_file"
|
||||||
|
send_launch_action "$@" && exit 0
|
||||||
|
activate_codex_tray_menu_item "$running_pid" && exit 0
|
||||||
|
activate_status_notifier_item "$running_pid" && exit 0
|
||||||
|
focus_hyprland_window "$running_pid" && exit 0
|
||||||
|
start_second_instance_handoff "$@" && exit 0
|
||||||
|
notify-send "Codex is already running" "No warm-start socket, tray activation, or second-instance restore path was available." >/dev/null 2>&1 || true
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
exec codex-desktop "$@"
|
exec codex-desktop "$@"
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ from pathlib import Path
|
|||||||
|
|
||||||
|
|
||||||
PROMPT = "Hyprland action"
|
PROMPT = "Hyprland action"
|
||||||
|
HYPER_MODIFIERS = {"SUPER", "CTRL", "ALT"}
|
||||||
|
MODIFIER_ORDER = ["SHIFT", "SUPER", "CTRL", "ALT"]
|
||||||
|
|
||||||
|
|
||||||
def ensure_hyprland_instance():
|
def ensure_hyprland_instance():
|
||||||
@@ -51,6 +53,32 @@ def rofi_index(entries):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def display_keys(keys):
|
||||||
|
parts = [part.strip() for part in keys.split("+")]
|
||||||
|
parts = [part for part in parts if part]
|
||||||
|
modifier_counts = {}
|
||||||
|
non_modifiers = []
|
||||||
|
|
||||||
|
for part in parts:
|
||||||
|
canonical = part.upper()
|
||||||
|
if canonical in MODIFIER_ORDER:
|
||||||
|
modifier_counts[canonical] = modifier_counts.get(canonical, 0) + 1
|
||||||
|
else:
|
||||||
|
non_modifiers.append(part)
|
||||||
|
|
||||||
|
modifiers = set(modifier_counts)
|
||||||
|
if not HYPER_MODIFIERS.issubset(modifiers):
|
||||||
|
return keys
|
||||||
|
|
||||||
|
remaining_modifiers = [
|
||||||
|
modifier
|
||||||
|
for modifier in MODIFIER_ORDER
|
||||||
|
if modifier not in HYPER_MODIFIERS and modifier in modifiers
|
||||||
|
]
|
||||||
|
display_parts = ["Hyper", *remaining_modifiers, *non_modifiers]
|
||||||
|
return " + ".join(display_parts)
|
||||||
|
|
||||||
|
|
||||||
def notify(message):
|
def notify(message):
|
||||||
if shutil.which("notify-send"):
|
if shutil.which("notify-send"):
|
||||||
subprocess.run(["notify-send", "Hyprland action", message], check=False)
|
subprocess.run(["notify-send", "Hyprland action", message], check=False)
|
||||||
@@ -104,7 +132,7 @@ def main():
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
width = min(max(len(action["description"]) for action in actions), 48)
|
width = min(max(len(action["description"]) for action in actions), 48)
|
||||||
labels = [f"{action['description']:<{width}} {action['keys']}" for action in actions]
|
labels = [f"{action['description']:<{width}} {display_keys(action['keys'])}" for action in actions]
|
||||||
index = rofi_index(labels)
|
index = rofi_index(labels)
|
||||||
if index is None:
|
if index is None:
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ ensure_hyprland_instance
|
|||||||
layouts=(
|
layouts=(
|
||||||
"nStack Columns"
|
"nStack Columns"
|
||||||
"master Large main"
|
"master Large main"
|
||||||
|
"quadrants Quadrants"
|
||||||
"grid Grid"
|
"grid Grid"
|
||||||
"monocle Monocle"
|
"monocle Monocle"
|
||||||
)
|
)
|
||||||
@@ -64,7 +65,7 @@ for entry in "${layouts[@]}"; do
|
|||||||
label="${entry#*$'\t'}"
|
label="${entry#*$'\t'}"
|
||||||
|
|
||||||
if [[ "$label" == "$selection" ]]; then
|
if [[ "$label" == "$selection" ]]; then
|
||||||
hyprctl dispatch "_G.im_hyprland_set_layout(\"$layout\")" >/dev/null
|
hyprctl -q eval "_G.im_hyprland_set_layout(\"$layout\")"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ tray_services=(
|
|||||||
flameshot.service
|
flameshot.service
|
||||||
kanshi-sni.service
|
kanshi-sni.service
|
||||||
kdeconnect-indicator.service
|
kdeconnect-indicator.service
|
||||||
keepbook-sync-daemon.service
|
keepbook-dioxus.service
|
||||||
network-manager-applet.service
|
network-manager-applet.service
|
||||||
notifications-tray-icon-gitea.service
|
notifications-tray-icon-gitea.service
|
||||||
notifications-tray-icon-github.service
|
notifications-tray-icon-github.service
|
||||||
|
|||||||
241
dotfiles/lib/bin/rocket-league-bakkesmod
Executable file
241
dotfiles/lib/bin/rocket-league-bakkesmod
Executable file
@@ -0,0 +1,241 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
app_name="${HEROIC_ROCKET_LEAGUE_APP_NAME:-Sugar}"
|
||||||
|
heroic_config_dir="${HEROIC_CONFIG_DIR:-$HOME/.config/heroic}"
|
||||||
|
game_config="${HEROIC_ROCKET_LEAGUE_CONFIG:-$heroic_config_dir/GamesConfig/$app_name.json}"
|
||||||
|
installed_json="${HEROIC_LEGENDARY_INSTALLED_JSON:-$heroic_config_dir/legendaryConfig/legendary/installed.json}"
|
||||||
|
download_url="${BAKKESMOD_SETUP_URL:-https://github.com/bakkesmodorg/BakkesModInjectorCpp/releases/latest/download/BakkesModSetup.zip}"
|
||||||
|
cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/rocket-league-bakkesmod"
|
||||||
|
|
||||||
|
die() {
|
||||||
|
printf 'rocket-league-bakkesmod: %s\n' "$*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
need_command() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 || die "missing required command: $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
jq_value() {
|
||||||
|
local filter="$1"
|
||||||
|
local file="$2"
|
||||||
|
jq -er "$filter // empty" "$file" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
heroic_value() {
|
||||||
|
local filter="$1"
|
||||||
|
jq_value ".$app_name.$filter" "$game_config"
|
||||||
|
}
|
||||||
|
|
||||||
|
installed_value() {
|
||||||
|
jq_value ".$app_name.$1" "$installed_json"
|
||||||
|
}
|
||||||
|
|
||||||
|
require_heroic_metadata() {
|
||||||
|
[ -f "$game_config" ] || die "missing Heroic game config: $game_config"
|
||||||
|
[ -f "$installed_json" ] || die "missing Legendary installed metadata: $installed_json"
|
||||||
|
}
|
||||||
|
|
||||||
|
rocket_league_dir() {
|
||||||
|
local value
|
||||||
|
value="${ROCKET_LEAGUE_DIR:-}"
|
||||||
|
if [ -z "$value" ]; then
|
||||||
|
value="$(installed_value install_path)"
|
||||||
|
fi
|
||||||
|
if [ -z "$value" ]; then
|
||||||
|
value="$HOME/Games/Heroic/rocketleague"
|
||||||
|
fi
|
||||||
|
printf '%s\n' "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
rocket_league_prefix() {
|
||||||
|
local value
|
||||||
|
value="${ROCKET_LEAGUE_PREFIX:-}"
|
||||||
|
if [ -z "$value" ]; then
|
||||||
|
value="$(heroic_value winePrefix)"
|
||||||
|
fi
|
||||||
|
[ -n "$value" ] || die "could not determine Heroic wine prefix from $game_config"
|
||||||
|
printf '%s\n' "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
rocket_league_proton() {
|
||||||
|
local value
|
||||||
|
value="${ROCKET_LEAGUE_PROTON:-}"
|
||||||
|
if [ -z "$value" ]; then
|
||||||
|
value="$(heroic_value 'wineVersion.bin')"
|
||||||
|
fi
|
||||||
|
[ -n "$value" ] || die "could not determine Heroic Proton binary from $game_config"
|
||||||
|
printf '%s\n' "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_paths() {
|
||||||
|
need_command jq
|
||||||
|
require_heroic_metadata
|
||||||
|
|
||||||
|
rl_dir="$(rocket_league_dir)"
|
||||||
|
rl_prefix="$(rocket_league_prefix)"
|
||||||
|
proton_bin="$(rocket_league_proton)"
|
||||||
|
|
||||||
|
[ -d "$rl_dir" ] || die "Rocket League install directory does not exist: $rl_dir"
|
||||||
|
[ -d "$rl_prefix" ] || die "Rocket League prefix does not exist: $rl_prefix"
|
||||||
|
[ -x "$proton_bin" ] || die "Proton binary is not executable: $proton_bin"
|
||||||
|
}
|
||||||
|
|
||||||
|
proton_run() {
|
||||||
|
export STEAM_COMPAT_DATA_PATH="$rl_prefix"
|
||||||
|
export STEAM_COMPAT_CLIENT_INSTALL_PATH="${STEAM_COMPAT_CLIENT_INSTALL_PATH:-$HOME/.steam/root}"
|
||||||
|
export WINEESYNC="${WINEESYNC:-1}"
|
||||||
|
export WINEFSYNC="${WINEFSYNC:-1}"
|
||||||
|
|
||||||
|
if command -v steam-run >/dev/null 2>&1; then
|
||||||
|
steam-run "$proton_bin" run "$@"
|
||||||
|
else
|
||||||
|
NIXPKGS_ALLOW_UNFREE=1 nix run --impure nixpkgs#steam-run -- "$proton_bin" run "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
bakkesmod_exe() {
|
||||||
|
local candidates=(
|
||||||
|
"$rl_prefix/pfx/drive_c/Program Files/BakkesMod/BakkesMod.exe"
|
||||||
|
"$rl_prefix/drive_c/Program Files/BakkesMod/BakkesMod.exe"
|
||||||
|
"$rl_prefix/pfx/drive_c/users/$USER/AppData/Roaming/bakkesmod/bakkesmod/BakkesMod.exe"
|
||||||
|
"$rl_prefix/drive_c/users/$USER/AppData/Roaming/bakkesmod/bakkesmod/BakkesMod.exe"
|
||||||
|
)
|
||||||
|
|
||||||
|
local candidate
|
||||||
|
for candidate in "${candidates[@]}"; do
|
||||||
|
if [ -f "$candidate" ]; then
|
||||||
|
printf '%s\n' "$candidate"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
find "$rl_prefix" -iname BakkesMod.exe -print -quit 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
write_bat_launcher() {
|
||||||
|
local bat_path="$rl_dir/run_with_bakkesmod.bat"
|
||||||
|
local bakkes_dir="C:\\Program Files\\BakkesMod"
|
||||||
|
|
||||||
|
cat >"$bat_path" <<EOF
|
||||||
|
@echo off
|
||||||
|
set RL_PATH=%cd%\\Binaries\\Win64
|
||||||
|
|
||||||
|
echo Launching BakkesMod...
|
||||||
|
C:
|
||||||
|
cd "$bakkes_dir"
|
||||||
|
start BakkesMod.exe
|
||||||
|
|
||||||
|
echo Launching Rocket League without Easy Anti-Cheat: %RL_PATH%
|
||||||
|
Z:
|
||||||
|
cd %RL_PATH%
|
||||||
|
Launcher.exe -noeac %*
|
||||||
|
EOF
|
||||||
|
|
||||||
|
printf '%s\n' "$bat_path"
|
||||||
|
}
|
||||||
|
|
||||||
|
download_setup() {
|
||||||
|
need_command wget
|
||||||
|
need_command unzip
|
||||||
|
|
||||||
|
local zip setup
|
||||||
|
mkdir -p "$cache_dir"
|
||||||
|
rm -rf "$cache_dir/setup"
|
||||||
|
zip="$cache_dir/BakkesModSetup.zip"
|
||||||
|
wget -q --no-server-response -O "$zip" "$download_url"
|
||||||
|
unzip -oq "$zip" -d "$cache_dir/setup"
|
||||||
|
setup="$(find "$cache_dir/setup" -iname 'BakkesModSetup.exe' -o -iname 'BakkesMod.exe' | head -1)"
|
||||||
|
[ -n "$setup" ] || die "download did not contain BakkesModSetup.exe or BakkesMod.exe"
|
||||||
|
printf '%s\n' "$setup"
|
||||||
|
}
|
||||||
|
|
||||||
|
status() {
|
||||||
|
ensure_paths
|
||||||
|
|
||||||
|
printf 'Rocket League dir: %s\n' "$rl_dir"
|
||||||
|
printf 'Heroic prefix: %s\n' "$rl_prefix"
|
||||||
|
printf 'Proton: %s\n' "$proton_bin"
|
||||||
|
printf 'No-EAC launcher: %s\n' "$rl_dir/run_with_bakkesmod.bat"
|
||||||
|
|
||||||
|
local bakkes
|
||||||
|
bakkes="$(bakkesmod_exe)"
|
||||||
|
if [ -n "$bakkes" ]; then
|
||||||
|
printf 'BakkesMod exe: %s\n' "$bakkes"
|
||||||
|
else
|
||||||
|
printf 'BakkesMod exe: not installed in this prefix\n'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
ensure_paths
|
||||||
|
write_bat_launcher >/dev/null
|
||||||
|
status
|
||||||
|
}
|
||||||
|
|
||||||
|
install() {
|
||||||
|
ensure_paths
|
||||||
|
write_bat_launcher >/dev/null
|
||||||
|
|
||||||
|
local silent=false
|
||||||
|
if [ "${1:-}" = "--silent" ]; then
|
||||||
|
silent=true
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
|
local setup_exe
|
||||||
|
setup_exe="$(download_setup)"
|
||||||
|
printf 'Running BakkesMod installer in Rocket League prefix...\n'
|
||||||
|
if $silent; then
|
||||||
|
if ! proton_run "$setup_exe" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART "$@"; then
|
||||||
|
die "installer failed; use Heroic > Rocket League > Settings > Wine > Run EXE in Prefix and select: $setup_exe"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if ! proton_run "$setup_exe" "$@"; then
|
||||||
|
die "installer failed; use Heroic > Rocket League > Settings > Wine > Run EXE in Prefix and select: $setup_exe"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run() {
|
||||||
|
ensure_paths
|
||||||
|
local bat_path
|
||||||
|
bat_path="$(write_bat_launcher)"
|
||||||
|
|
||||||
|
local bakkes
|
||||||
|
bakkes="$(bakkesmod_exe)"
|
||||||
|
[ -n "$bakkes" ] || die "BakkesMod is not installed in the Rocket League prefix; run: rocket-league-bakkesmod install"
|
||||||
|
|
||||||
|
(
|
||||||
|
cd "$rl_dir"
|
||||||
|
proton_run "$bat_path" "$@"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: rocket-league-bakkesmod <command> [rocket-league-args...]
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
status Show detected Heroic Rocket League, Proton, and BakkesMod paths.
|
||||||
|
setup Write the Heroic-compatible no-EAC BakkesMod .bat launcher.
|
||||||
|
install Download and run the BakkesMod installer inside the Rocket League prefix.
|
||||||
|
Use install --silent for unattended Inno Setup installation.
|
||||||
|
run Start BakkesMod, then launch Rocket League with -noeac for offline/local play.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
command_name="${1:-status}"
|
||||||
|
if [ "$#" -gt 0 ]; then
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$command_name" in
|
||||||
|
status) status "$@" ;;
|
||||||
|
setup) setup "$@" ;;
|
||||||
|
install) install "$@" ;;
|
||||||
|
run) run "$@" ;;
|
||||||
|
help|--help|-h) usage ;;
|
||||||
|
*) usage >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
39
dotfiles/lib/bin/rofi_ai_scratchpad.sh
Executable file
39
dotfiles/lib/bin/rofi_ai_scratchpad.sh
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/usr/bin/env zsh
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Choose which AI app SUPER+ALT+C toggles as a scratchpad: Codex or Claude
|
||||||
|
# Desktop. The choice is written to a state file that the Hyprland Lua config
|
||||||
|
# reads at keypress time, so switching is dynamic and needs no reload.
|
||||||
|
|
||||||
|
state_file="${XDG_STATE_HOME:-$HOME/.local/state}/hypr/ai-scratchpad"
|
||||||
|
mkdir -p "${state_file:h}"
|
||||||
|
|
||||||
|
names=(codex claude)
|
||||||
|
labels=("Codex" "Claude Desktop")
|
||||||
|
|
||||||
|
current=codex
|
||||||
|
[[ -r "$state_file" ]] && current="$(<"$state_file")"
|
||||||
|
|
||||||
|
menu=""
|
||||||
|
for i in {1..${#names}}; do
|
||||||
|
marker=" "
|
||||||
|
[[ "${names[$i]}" == "$current" ]] && marker="● "
|
||||||
|
menu+="${marker}${labels[$i]}\n"
|
||||||
|
done
|
||||||
|
|
||||||
|
index="$(printf "$menu" | rofi -dmenu -i -p "AI scratchpad" -format i)" || exit 0
|
||||||
|
[[ -n "$index" ]] || exit 0
|
||||||
|
|
||||||
|
selected="${names[$((index + 1))]}"
|
||||||
|
[[ -n "$selected" ]] || exit 0
|
||||||
|
|
||||||
|
print -r -- "$selected" > "$state_file"
|
||||||
|
|
||||||
|
# Bring the freshly selected scratchpad into view (no-op if already visible).
|
||||||
|
if command -v hyprctl >/dev/null 2>&1; then
|
||||||
|
hyprctl -q eval "_G.im_hyprland_show_ai_scratchpad()" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v notify-send >/dev/null 2>&1; then
|
||||||
|
notify-send "AI scratchpad" "Super+Alt+C now toggles ${labels[$((index + 1))]}" || true
|
||||||
|
fi
|
||||||
81
dotfiles/lib/bin/rofi_codex_desktop_project.sh
Executable file
81
dotfiles/lib/bin/rofi_codex_desktop_project.sh
Executable file
@@ -0,0 +1,81 @@
|
|||||||
|
#!/usr/bin/env zsh
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Pick a saved Codex Desktop project root via rofi, then start a new desktop
|
||||||
|
# thread in that project using the documented codex:// deep link.
|
||||||
|
|
||||||
|
codex_home="${CODEX_HOME:-$HOME/.codex}"
|
||||||
|
state_file="${CODEX_DESKTOP_STATE_FILE:-$codex_home/.codex-global-state.json}"
|
||||||
|
prompt="${CODEX_DESKTOP_PROJECT_PROMPT:-Codex project}"
|
||||||
|
|
||||||
|
notify() {
|
||||||
|
if command -v notify-send >/dev/null 2>&1; then
|
||||||
|
notify-send "Codex Desktop launcher" "$1"
|
||||||
|
else
|
||||||
|
printf '%s\n' "$1" >&2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
emit_candidates() {
|
||||||
|
if [[ ! -r "$state_file" ]]; then
|
||||||
|
notify "Cannot read Codex Desktop state: $state_file"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
jq -r '
|
||||||
|
def local_paths($key):
|
||||||
|
.[$key] // []
|
||||||
|
| .[]?
|
||||||
|
| select(type == "string" and startswith("/"));
|
||||||
|
|
||||||
|
local_paths("pinned-project-ids"),
|
||||||
|
local_paths("electron-saved-workspace-roots"),
|
||||||
|
local_paths("project-order")
|
||||||
|
' "$state_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
dedup() {
|
||||||
|
awk 'NF && !seen[$0]++'
|
||||||
|
}
|
||||||
|
|
||||||
|
existing_dirs() {
|
||||||
|
local dir
|
||||||
|
while IFS= read -r dir; do
|
||||||
|
[[ -d "$dir" ]] && printf '%s\n' "$dir"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "${1:-}" == "--print-candidates" ]]; then
|
||||||
|
emit_candidates | dedup | existing_dirs
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
selected_dir="$(
|
||||||
|
emit_candidates | dedup | existing_dirs | rofi -dmenu -i -p "$prompt" || true
|
||||||
|
)"
|
||||||
|
|
||||||
|
[[ -n "$selected_dir" ]] || exit 0
|
||||||
|
|
||||||
|
case "$selected_dir" in
|
||||||
|
"~"|"~/"*)
|
||||||
|
selected_dir="$HOME${selected_dir:1}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if command -v realpath >/dev/null 2>&1; then
|
||||||
|
selected_dir="$(realpath -m -- "$selected_dir" 2>/dev/null || printf '%s' "$selected_dir")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -d "$selected_dir" ]]; then
|
||||||
|
notify "Directory not found: $selected_dir"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
encoded_path="$(jq -rn --arg path "$selected_dir" '$path | @uri')"
|
||||||
|
|
||||||
|
if ! command -v xdg-open >/dev/null 2>&1; then
|
||||||
|
notify "xdg-open is not available"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
xdg-open "codex://threads/new?path=$encoded_path" >/dev/null 2>&1 &!
|
||||||
@@ -10,6 +10,7 @@ state_dir="${XDG_STATE_HOME:-$HOME/.local/state}/rofi-tmcodex"
|
|||||||
history_file="$state_dir/dirs"
|
history_file="$state_dir/dirs"
|
||||||
codex_home="${CODEX_HOME:-$HOME/.codex}"
|
codex_home="${CODEX_HOME:-$HOME/.codex}"
|
||||||
terminal="${TMCODEX_TERMINAL:-${TERMINAL:-ghostty}}"
|
terminal="${TMCODEX_TERMINAL:-${TERMINAL:-ghostty}}"
|
||||||
|
dotfiles_root="${DOTFILES_WORKTREE:-/srv/dotfiles}"
|
||||||
debug_log="$state_dir/debug.log"
|
debug_log="$state_dir/debug.log"
|
||||||
tmcodex_args=("$@")
|
tmcodex_args=("$@")
|
||||||
mkdir -p "$state_dir"
|
mkdir -p "$state_dir"
|
||||||
@@ -29,8 +30,8 @@ emit_candidates() {
|
|||||||
# 2) A few common roots. Keep these before slow/best-effort discovery so
|
# 2) A few common roots. Keep these before slow/best-effort discovery so
|
||||||
# rofi still has useful entries if a metadata scan breaks.
|
# rofi still has useful entries if a metadata scan breaks.
|
||||||
for d in \
|
for d in \
|
||||||
"$HOME/dotfiles" \
|
"$dotfiles_root" \
|
||||||
"$HOME/dotfiles/nixos" \
|
"$dotfiles_root/nixos" \
|
||||||
"$HOME/Projects" \
|
"$HOME/Projects" \
|
||||||
"$HOME/config" \
|
"$HOME/config" \
|
||||||
"$HOME/org"
|
"$HOME/org"
|
||||||
@@ -43,7 +44,7 @@ emit_candidates() {
|
|||||||
|
|
||||||
# 4) Shallow git repo discovery under a few likely roots.
|
# 4) Shallow git repo discovery under a few likely roots.
|
||||||
if command -v fd >/dev/null 2>&1; then
|
if command -v fd >/dev/null 2>&1; then
|
||||||
for root in "$HOME/Projects" "$HOME/dotfiles" "$HOME/config" "$HOME/org"; do
|
for root in "$HOME/Projects" "$dotfiles_root" "$HOME/config" "$HOME/org"; do
|
||||||
[[ -d "$root" ]] || continue
|
[[ -d "$root" ]] || continue
|
||||||
# Find ".git" directories; print their parent (repo root).
|
# Find ".git" directories; print their parent (repo root).
|
||||||
# Keep it shallow for speed.
|
# Keep it shallow for speed.
|
||||||
|
|||||||
123
dotfiles/lib/bin/setup-shared-dotfiles
Executable file
123
dotfiles/lib/bin/setup-shared-dotfiles
Executable file
@@ -0,0 +1,123 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: setup-shared-dotfiles [--target /srv/dotfiles] [--group wheel] [--no-etc-nixos] [--force-etc-nixos]
|
||||||
|
|
||||||
|
Copies this dotfiles checkout to an absent or empty shared machine-local
|
||||||
|
worktree, then configures permissions so everyone can read it and sudoers can
|
||||||
|
edit it without sudo. When the target already contains a git checkout, this
|
||||||
|
repairs permissions/config only and does not overwrite local changes.
|
||||||
|
|
||||||
|
Defaults:
|
||||||
|
target: /srv/dotfiles
|
||||||
|
group: wheel
|
||||||
|
|
||||||
|
The script also creates /etc/nixos -> <target>/nixos when /etc/nixos is absent
|
||||||
|
or already a symlink. Use --force-etc-nixos to replace an existing /etc/nixos
|
||||||
|
path with the symlink.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
target=/srv/dotfiles
|
||||||
|
group=wheel
|
||||||
|
manage_etc_nixos=1
|
||||||
|
force_etc_nixos=0
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--target)
|
||||||
|
target="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--group)
|
||||||
|
group="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--no-etc-nixos)
|
||||||
|
manage_etc_nixos=0
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--force-etc-nixos)
|
||||||
|
force_etc_nixos=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown argument: $1" >&2
|
||||||
|
usage >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
source_root="$(git -C "$script_dir" rev-parse --show-toplevel)"
|
||||||
|
target="$(realpath -m "$target")"
|
||||||
|
|
||||||
|
if ! getent group "$group" >/dev/null; then
|
||||||
|
echo "Group '$group' does not exist" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo install -d -m 2775 -o root -g "$group" "$(dirname "$target")"
|
||||||
|
|
||||||
|
if [[ "$source_root" != "$target" ]]; then
|
||||||
|
target_has_content=0
|
||||||
|
if [[ -d "$target" ]] && find "$target" -mindepth 1 -maxdepth 1 -print -quit | grep -q .; then
|
||||||
|
target_has_content=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$target_has_content" == 1 && ! -d "$target/.git" ]]; then
|
||||||
|
echo "Refusing to copy into non-empty non-git target: $target" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$target_has_content" == 0 ]]; then
|
||||||
|
sudo install -d -m 2775 -o root -g "$group" "$target"
|
||||||
|
sudo rsync -a --chown="root:$group" "$source_root/" "$target/"
|
||||||
|
else
|
||||||
|
echo "Existing git checkout found at $target; repairing permissions only."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo chown -R "root:$group" "$target"
|
||||||
|
sudo find "$target" -type d -exec chmod 2775 {} +
|
||||||
|
sudo find "$target" -type f -exec chmod u+rw,g+rw,o+r {} +
|
||||||
|
|
||||||
|
if command -v setfacl >/dev/null; then
|
||||||
|
sudo setfacl -R -m "g::rwX,o::rX,m::rwX" "$target"
|
||||||
|
sudo setfacl -R -d -m "g::rwX,o::rX,m::rwX" "$target"
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo git -C "$target" config core.sharedRepository group
|
||||||
|
if ! sudo git config --system --get-all safe.directory 2>/dev/null | grep -Fx -- "$target" >/dev/null; then
|
||||||
|
sudo git config --system --add safe.directory "$target" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$manage_etc_nixos" == 1 ]]; then
|
||||||
|
nixos_target="$target/nixos"
|
||||||
|
if [[ ! -d "$nixos_target" ]]; then
|
||||||
|
echo "Expected NixOS flake directory is missing: $nixos_target" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -L /etc/nixos || ! -e /etc/nixos ]]; then
|
||||||
|
sudo rm -rf /etc/nixos
|
||||||
|
sudo ln -s "$nixos_target" /etc/nixos
|
||||||
|
elif [[ "$force_etc_nixos" == 1 ]]; then
|
||||||
|
backup="/etc/nixos.backup.$(date +%Y%m%d-%H%M%S)"
|
||||||
|
sudo mv /etc/nixos "$backup"
|
||||||
|
sudo ln -s "$nixos_target" /etc/nixos
|
||||||
|
echo "Moved previous /etc/nixos to $backup"
|
||||||
|
else
|
||||||
|
echo "Leaving existing /etc/nixos in place; pass --force-etc-nixos to replace it." >&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Shared dotfiles worktree ready: $target"
|
||||||
|
echo "Nix/Home Manager should use dotfiles-worktree = \"$target\"."
|
||||||
@@ -3,12 +3,12 @@
|
|||||||
function pashowvolume {
|
function pashowvolume {
|
||||||
timeout="${RUMNO_TIMEOUT:-2.5}"
|
timeout="${RUMNO_TIMEOUT:-2.5}"
|
||||||
if paismuted; then
|
if paismuted; then
|
||||||
rumno notify -t "$timeout" -m
|
rumno -t "$timeout" -m true
|
||||||
else
|
else
|
||||||
actual=$(pavolume)
|
actual=$(pavolume)
|
||||||
max=100
|
max=100
|
||||||
show=$(( actual < max ? actual : max ))
|
show=$(( actual < max ? actual : max ))
|
||||||
rumno notify -t "$timeout" -v "$show"
|
rumno -t "$timeout" -v "$show"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,16 +10,50 @@ set_multiplexer_title() {
|
|||||||
|
|
||||||
title="$*"
|
title="$*"
|
||||||
|
|
||||||
|
tmux_socket=""
|
||||||
|
tmux_session_target=""
|
||||||
|
tmux_window_target=""
|
||||||
|
tmux_pane_target=""
|
||||||
|
|
||||||
if [ -n "${TMUX:-}" ]; then
|
if [ -n "${TMUX:-}" ]; then
|
||||||
multiplexer="tmux"
|
multiplexer="tmux"
|
||||||
|
tmux_socket=${TMUX%%,*}
|
||||||
elif [ -n "${ZELLIJ:-}" ]; then
|
elif [ -n "${ZELLIJ:-}" ]; then
|
||||||
multiplexer="zellij"
|
multiplexer="zellij"
|
||||||
else
|
else
|
||||||
return 0
|
tmux_socket="/tmp/tmux-$(id -u)/default"
|
||||||
|
if command -v tmux >/dev/null 2>&1 && [ -S "$tmux_socket" ]; then
|
||||||
|
# Newer Codex tool calls may be serviced by an app-server process
|
||||||
|
# that is not a child of the visible tmux pane, so TMUX is absent.
|
||||||
|
# Recover the likely pane by matching attached Codex panes in the
|
||||||
|
# current working directory and taking the newest matching client.
|
||||||
|
tmux_client=$(
|
||||||
|
tmux -S "$tmux_socket" list-clients -F '#{session_id}|#{window_id}|#{pane_id}|#{pane_pid}|#{pane_current_path}|#{pane_current_command}' 2>/dev/null |
|
||||||
|
awk -F '|' -v cwd="$PWD" '$5 == cwd && ($6 == "codex" || $6 == "codex-raw") { line = $0 } END { print line }'
|
||||||
|
)
|
||||||
|
if [ -n "$tmux_client" ]; then
|
||||||
|
multiplexer="tmux"
|
||||||
|
tmux_session_target=${tmux_client%%|*}
|
||||||
|
rest=${tmux_client#*|}
|
||||||
|
tmux_window_target=${rest%%|*}
|
||||||
|
rest=${rest#*|}
|
||||||
|
tmux_pane_target=${rest%%|*}
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
state_dir="${HOME}/.agents/state"
|
state_dir="${HOME}/.agents/state"
|
||||||
state_file="$state_dir/${multiplexer}-title"
|
state_key="$multiplexer"
|
||||||
|
if [ -n "$tmux_pane_target" ]; then
|
||||||
|
state_key="${state_key}-${tmux_pane_target#%}"
|
||||||
|
elif [ -n "$tmux_socket" ]; then
|
||||||
|
state_key="${state_key}-$(printf '%s' "$tmux_socket" | tr '/.,:' '____')"
|
||||||
|
fi
|
||||||
|
state_file="$state_dir/${state_key}-title"
|
||||||
mkdir -p "$state_dir"
|
mkdir -p "$state_dir"
|
||||||
|
|
||||||
if [ -f "$state_file" ]; then
|
if [ -f "$state_file" ]; then
|
||||||
@@ -30,7 +64,14 @@ set_multiplexer_title() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$multiplexer" = "tmux" ]; then
|
if [ "$multiplexer" = "tmux" ]; then
|
||||||
tmux rename-session "$title" \; rename-window "$title" \; select-pane -T "$title"
|
if [ -n "$tmux_pane_target" ]; then
|
||||||
|
tmux -S "$tmux_socket" \
|
||||||
|
rename-session -t "$tmux_session_target" "$title" \; \
|
||||||
|
rename-window -t "$tmux_window_target" "$title" \; \
|
||||||
|
select-pane -t "$tmux_pane_target" -T "$title"
|
||||||
|
else
|
||||||
|
tmux rename-session "$title" \; rename-window "$title" \; select-pane -T "$title"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
zellij action rename-session "$title" &&
|
zellij action rename-session "$title" &&
|
||||||
zellij action rename-tab "$title" &&
|
zellij action rename-tab "$title" &&
|
||||||
|
|||||||
@@ -1,22 +1,93 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
function _tmcodex_expand_dir {
|
||||||
|
case "$1" in
|
||||||
|
"~")
|
||||||
|
printf '%s\n' "$HOME"
|
||||||
|
;;
|
||||||
|
"~/"*)
|
||||||
|
printf '%s\n' "$HOME/${1#"~/"}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf '%s\n' "$1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
function _tmcodex_resolve_dir {
|
||||||
|
dir="$(_tmcodex_expand_dir "$1")"
|
||||||
|
if [ ! -d "$dir" ]; then
|
||||||
|
echo "tmcodex: directory not found: $1" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd -- "$dir" && pwd -P
|
||||||
|
}
|
||||||
|
|
||||||
|
function _tmcodex_has_remote_arg {
|
||||||
|
while [ "$#" -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--remote|--remote=*)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
function tmcodex {
|
function tmcodex {
|
||||||
|
launch_dir="$PWD"
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
-C|--cd)
|
||||||
|
if [ -z "${2:-}" ]; then
|
||||||
|
echo "tmcodex: $1 requires a directory" >&2
|
||||||
|
return 2
|
||||||
|
fi
|
||||||
|
launch_dir="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--cd=*)
|
||||||
|
launch_dir="${1#--cd=}"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
expanded_first_arg="$(_tmcodex_expand_dir "${1:-}")"
|
||||||
|
if [ -n "${1:-}" ] && [ -d "$expanded_first_arg" ]; then
|
||||||
|
launch_dir="$1"
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
launch_dir="$(_tmcodex_resolve_dir "$launch_dir")" || return
|
||||||
|
|
||||||
# Record launch directories so rofi_tmcodex can offer good defaults.
|
# Record launch directories so rofi_tmcodex can offer good defaults.
|
||||||
state_dir="${XDG_STATE_HOME:-$HOME/.local/state}/rofi-tmcodex"
|
state_dir="${XDG_STATE_HOME:-$HOME/.local/state}/rofi-tmcodex"
|
||||||
history_file="$state_dir/dirs"
|
history_file="$state_dir/dirs"
|
||||||
mkdir -p "$state_dir" 2>/dev/null || true
|
mkdir -p "$state_dir" 2>/dev/null || true
|
||||||
if [ -d "$PWD" ]; then
|
if [ -d "$launch_dir" ]; then
|
||||||
tmp="$(mktemp 2>/dev/null || true)"
|
tmp="$(mktemp 2>/dev/null || true)"
|
||||||
if [ -n "$tmp" ]; then
|
if [ -n "$tmp" ]; then
|
||||||
{ printf '%s\n' "$PWD"; cat "$history_file" 2>/dev/null || true; } \
|
{ printf '%s\n' "$launch_dir"; cat "$history_file" 2>/dev/null || true; } \
|
||||||
| awk 'NF && !seen[$0]++' \
|
| awk 'NF && !seen[$0]++' \
|
||||||
| head -n 200 >"$tmp" 2>/dev/null || true
|
| head -n 200 >"$tmp" 2>/dev/null || true
|
||||||
mv -f "$tmp" "$history_file" 2>/dev/null || true
|
mv -f "$tmp" "$history_file" 2>/dev/null || true
|
||||||
else
|
else
|
||||||
printf '%s\n' "$PWD" >>"$history_file" 2>/dev/null || true
|
printf '%s\n' "$launch_dir" >>"$history_file" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
trw codex --dangerously-bypass-approvals-and-sandbox "$@"
|
|
||||||
|
(
|
||||||
|
cd -- "$launch_dir" || exit
|
||||||
|
if _tmcodex_has_remote_arg "$@"; then
|
||||||
|
trw codex --dangerously-bypass-approvals-and-sandbox --cd "$launch_dir" "$@"
|
||||||
|
else
|
||||||
|
trw codex --remote "${TMCODEX_REMOTE:-unix://}" --dangerously-bypass-approvals-and-sandbox --cd "$launch_dir" "$@"
|
||||||
|
fi
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
tmcodex "$@"
|
tmcodex "$@"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
function windows_toast {
|
function windows_toast {
|
||||||
powershell.exe -File ~/dotfiles/dotfiles/lib/bin/windows-toast.ps1 -Title "$@" 2>/dev/null
|
powershell.exe -File "${DOTFILES_WORKTREE:-/srv/dotfiles}/dotfiles/lib/bin/windows-toast.ps1" -Title "$@" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
windows_toast "$@"
|
windows_toast "$@"
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ function zcodex {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ZRW_NAME=codex zrw codex --dangerously-bypass-approvals-and-sandbox "$@"
|
ZRW_NAME=codex zrw codex --dangerously-bypass-approvals-and-sandbox --cd "$PWD" "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
zcodex "$@"
|
zcodex "$@"
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# Create a new Codex session from the current pane path and switch to it.
|
# Create a new Codex session from the current pane path and switch to it.
|
||||||
# Prefix + C starts a new session without prompting for a name.
|
# Prefix + C starts a new session without prompting for a name.
|
||||||
bind-key C new-session -c '#{pane_current_path}' 'codex --dangerously-bypass-approvals-and-sandbox'
|
bind-key C new-session -c '#{pane_current_path}' 'codex --dangerously-bypass-approvals-and-sandbox --cd "$PWD"'
|
||||||
|
|
||||||
source-file -q /etc/tmux-host-style.conf
|
source-file -q /etc/tmux-host-style.conf
|
||||||
|
|
||||||
set -g status-right '#($HOME/dotfiles/dotfiles/lib/functions/multiplexer_host_label --tmux 2>/dev/null || multiplexer_host_label --tmux 2>/dev/null || hostname -s) #{?window_bigger,[#{window_offset_x}#,#{window_offset_y}] ,}"#{=21:pane_title}" %H:%M %d-%b-%y'
|
set -g status-right '#(multiplexer_host_label --tmux 2>/dev/null || hostname -s) #{?window_bigger,[#{window_offset_x}#,#{window_offset_y}] ,}"#{=21:pane_title}" %H:%M %d-%b-%y'
|
||||||
set -g status-right-length 150
|
set -g status-right-length 150
|
||||||
set -g set-titles on
|
set -g set-titles on
|
||||||
set -g set-titles-string '#{?#{==:#{session_name},#{window_name}},#{session_name},#{session_name}:#{window_name}}#{?pane_title, - #{pane_title},}'
|
set -g set-titles-string '#{?#{==:#{session_name},#{window_name}},#{session_name},#{session_name}:#{window_name}}#{?pane_title, - #{pane_title},}'
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ set -g status-interval 2
|
|||||||
set -g status-justify left
|
set -g status-justify left
|
||||||
set -g status-left-length 150
|
set -g status-left-length 150
|
||||||
set -g status-right-length 150
|
set -g status-right-length 150
|
||||||
set -g status-right '#($HOME/dotfiles/dotfiles/lib/functions/multiplexer_host_label --tmux 2>/dev/null || multiplexer_host_label --tmux 2>/dev/null || hostname -s) #(eval $POWERLINE_COMMAND tmux right -R pane_id=`tmux display -p "#D"`)'
|
set -g status-right '#(multiplexer_host_label --tmux 2>/dev/null || hostname -s) #(eval $POWERLINE_COMMAND tmux right -R pane_id=`tmux display -p "#D"`)'
|
||||||
set -g window-status-format "#[fg=white] #[fg=white,bg=black]#I #[fg=white] #[default]#W "
|
set -g window-status-format "#[fg=white] #[fg=white,bg=black]#I #[fg=white] #[default]#W "
|
||||||
set -g window-status-current-format "#[fg=black,bg=blue]#[fg=white,bg=blue] #I #[fg=white,bold]#W #[fg=blue,bg=black,nobold]"
|
set -g window-status-current-format "#[fg=black,bg=blue]#[fg=white,bg=blue] #I #[fg=white,bold]#W #[fg=blue,bg=black,nobold]"
|
||||||
set-window-option -g window-status-fg white
|
set-window-option -g window-status-fg white
|
||||||
|
|||||||
9
justfile
9
justfile
@@ -53,3 +53,12 @@ cachix-auth-from-clipboard:
|
|||||||
if command -v wl-paste >/dev/null; then wl-paste --no-newline | cachix authtoken --stdin; printf '' | wl-copy; \
|
if command -v wl-paste >/dev/null; then wl-paste --no-newline | cachix authtoken --stdin; printf '' | wl-copy; \
|
||||||
elif command -v xclip >/dev/null; then xclip -o -selection clipboard | tr -d '\n' | cachix authtoken --stdin; printf '' | xclip -selection clipboard; \
|
elif command -v xclip >/dev/null; then xclip -o -selection clipboard | tr -d '\n' | cachix authtoken --stdin; printf '' | xclip -selection clipboard; \
|
||||||
else echo "No clipboard tool found (expected wl-paste or xclip)." >&2; exit 1; fi
|
else echo "No clipboard tool found (expected wl-paste or xclip)." >&2; exit 1; fi
|
||||||
|
|
||||||
|
# Install or re-permission the repo as a shared machine-local checkout.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# - `just setup-shared-dotfiles`
|
||||||
|
# - `just setup-shared-dotfiles --target /srv/dotfiles --group wheel`
|
||||||
|
# - `just setup-shared-dotfiles --force-etc-nixos`
|
||||||
|
setup-shared-dotfiles *args:
|
||||||
|
./dotfiles/lib/bin/setup-shared-dotfiles {{args}}
|
||||||
|
|||||||
62
nix-darwin/flake.lock
generated
62
nix-darwin/flake.lock
generated
@@ -67,16 +67,16 @@
|
|||||||
"brew-src_2": {
|
"brew-src_2": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1778146321,
|
"lastModified": 1779646357,
|
||||||
"narHash": "sha256-HeBwuJmuBioZHyZqDOcf7W/xsMFupSD583v6I5Cl7a8=",
|
"narHash": "sha256-rnnAaESXxItX4D9xCMGvs3hfDBjbbTYht7OluRcvT8k=",
|
||||||
"owner": "Homebrew",
|
"owner": "Homebrew",
|
||||||
"repo": "brew",
|
"repo": "brew",
|
||||||
"rev": "af835384ac574f76025adb38b292b04cecee1f1f",
|
"rev": "10a163ac127624caa80cc5cc5a705e97f3615b0e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "Homebrew",
|
"owner": "Homebrew",
|
||||||
"ref": "5.1.10",
|
"ref": "5.1.14",
|
||||||
"repo": "brew",
|
"repo": "brew",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
@@ -89,11 +89,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1778621214,
|
"lastModified": 1780440050,
|
||||||
"narHash": "sha256-a01yQHAvpKSEgo22bKBtHOWtDb49U92dIBDV7WVIaEA=",
|
"narHash": "sha256-GUwh7tKnK1ZibdzRIbZ2CrKz9/PJ6BQUXW6Ru3rn56g=",
|
||||||
"owner": "sadjow",
|
"owner": "sadjow",
|
||||||
"repo": "claude-code-nix",
|
"repo": "claude-code-nix",
|
||||||
"rev": "6c8a73cc749fff4b45ae26d86dbfc82e2093d12c",
|
"rev": "fcf0beee92892f9193ad52549ed265091bbefde7",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -110,11 +110,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1778282716,
|
"lastModified": 1780345858,
|
||||||
"narHash": "sha256-fHo9PlYWu970hmdVkDB2Jqeu0VmhmqQ5iKOnPjf/I1E=",
|
"narHash": "sha256-t3dxFjzEFbuMd7o8LWtbnqfOkXDKjzvHXUiXQwvwXtk=",
|
||||||
"owner": "sadjow",
|
"owner": "sadjow",
|
||||||
"repo": "codex-cli-nix",
|
"repo": "codex-cli-nix",
|
||||||
"rev": "7f0f3802287581e04501e2fea26b56d63df18ebd",
|
"rev": "ea8119de14a2263330da99363e6303db10a0f84b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -377,11 +377,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1778628724,
|
"lastModified": 1780515920,
|
||||||
"narHash": "sha256-VNG6hJ146VEenXcDrB3t6MVnrMx+gtyCWTCDkzOp9Qs=",
|
"narHash": "sha256-8KX2hEeOX6KP3hBBJJI8dGWVrzbOOf1rBPmg/GUG24U=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "6a0bbd6b4720da1c9ce7ebf35ff5c41a82db367a",
|
"rev": "4c5c1e8ba14f1c7475fa31ff11bc1c19cd220974",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -415,11 +415,11 @@
|
|||||||
"homebrew-cask": {
|
"homebrew-cask": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1778665161,
|
"lastModified": 1780507130,
|
||||||
"narHash": "sha256-iffsbk5uf+xkPJY0DQzfBCTo58lCFxoLSmtFdhKwAuo=",
|
"narHash": "sha256-C9O84NflGNor0YiyBdm6+YhaoXU1TrAFFdub9upbfx0=",
|
||||||
"owner": "homebrew",
|
"owner": "homebrew",
|
||||||
"repo": "homebrew-cask",
|
"repo": "homebrew-cask",
|
||||||
"rev": "41670e2c6ba14d92acf86c22fccc26d9bd972212",
|
"rev": "dd4fb4043764201c941e8b992942330fc3d60175",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -431,11 +431,11 @@
|
|||||||
"homebrew-core": {
|
"homebrew-core": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1778667551,
|
"lastModified": 1780517143,
|
||||||
"narHash": "sha256-1KftBpiQRi6t2/jn7kiCXWp9Ov4FVD19wrHNvJVmDeI=",
|
"narHash": "sha256-ktdHmOdXbpvI4JGd3K3Z7dHAFrqkycJSRqIuPR9YHvw=",
|
||||||
"owner": "homebrew",
|
"owner": "homebrew",
|
||||||
"repo": "homebrew-core",
|
"repo": "homebrew-core",
|
||||||
"rev": "ec249d9026c15d9444d27346352ff8b228ad4af9",
|
"rev": "750a96ef95383f9da433dc665bd441eb4e796f01",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -455,11 +455,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1778406464,
|
"lastModified": 1780477777,
|
||||||
"narHash": "sha256-xCzb78zzv3DJbA5+/NyA8WVUzWwWyHCginbFN7AoIHo=",
|
"narHash": "sha256-0tkMA17QnFbr/8G9kkak8Y7vE6LGBJgbO1W/8jfmpvo=",
|
||||||
"owner": "colonelpanic8",
|
"owner": "colonelpanic8",
|
||||||
"repo": "keepbook",
|
"repo": "keepbook",
|
||||||
"rev": "b591f97904a3fe0d89516efbf6f4fee1abc58e8c",
|
"rev": "dda99c6e00d9c99744ff9c9dd1fd5a64436e05b7",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -475,11 +475,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1777780666,
|
"lastModified": 1779036909,
|
||||||
"narHash": "sha256-8wURyQMdDkGUarSTKOGdCuFfYiwa3HbzwscUfn3STDE=",
|
"narHash": "sha256-zXcwYQGCT6pzinK+1dBB2ekTVtfxGZAapb3Evdcu4fY=",
|
||||||
"owner": "LnL7",
|
"owner": "LnL7",
|
||||||
"repo": "nix-darwin",
|
"repo": "nix-darwin",
|
||||||
"rev": "8c62fba0854ba15c8917aed18894dbccb48a3777",
|
"rev": "56c666e108467d87d13508936aade6d567f2a501",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -493,11 +493,11 @@
|
|||||||
"brew-src": "brew-src_2"
|
"brew-src": "brew-src_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1778332591,
|
"lastModified": 1780492467,
|
||||||
"narHash": "sha256-ctJ3ADtugrnbMfMBobA645gCqXVIyHnsCNMkVaIuSiM=",
|
"narHash": "sha256-zMEJwtQPmsPPgPczFkyjWHgd1z0HagOPS2Wt2WDYLJY=",
|
||||||
"owner": "zhaofengli-wip",
|
"owner": "zhaofengli-wip",
|
||||||
"repo": "nix-homebrew",
|
"repo": "nix-homebrew",
|
||||||
"rev": "7d0038b5bb60568ec41f5f4ef5067cd221ca7c0d",
|
"rev": "562332f97de9f5ba51aa647d70462e88222b2988",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -524,11 +524,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1778580735,
|
"lastModified": 1780336545,
|
||||||
"narHash": "sha256-t+8AVV8ExvOmslz2sLIgw/hJBKlyl65rJvxjvvjHgpE=",
|
"narHash": "sha256-vhVhuXzFrIOfcssC/9hDHx7MHzDKjF3keHuREOQqQiQ=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "48d91f2c0ce7b9e589f967d4f685153dd765dcdd",
|
"rev": "4df1b885d76a54e1aa1a318f8d16fd6005b6401f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -284,7 +284,16 @@
|
|||||||
(final: prev: {
|
(final: prev: {
|
||||||
codex = inputs.codex-cli-nix.packages.${prev.stdenv.hostPlatform.system}.default;
|
codex = inputs.codex-cli-nix.packages.${prev.stdenv.hostPlatform.system}.default;
|
||||||
claude-code = inputs.claude-code-nix.packages.${prev.stdenv.hostPlatform.system}.default;
|
claude-code = inputs.claude-code-nix.packages.${prev.stdenv.hostPlatform.system}.default;
|
||||||
git-sync-rs = git-sync-rs.packages.${prev.stdenv.hostPlatform.system}.default;
|
git-sync-rs = git-sync-rs.packages.${prev.stdenv.hostPlatform.system}.default.overrideAttrs (old: {
|
||||||
|
checkFlags =
|
||||||
|
(old.checkFlags or [])
|
||||||
|
++ [
|
||||||
|
# Git can auto-detect the Darwin Nix build user's identity, so this
|
||||||
|
# test does not exercise git-sync-rs's missing-identity fallback here.
|
||||||
|
"--skip"
|
||||||
|
"sync::transport::tests::commit_retries_with_fallback_identity_when_git_identity_missing"
|
||||||
|
];
|
||||||
|
});
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
environment.systemPackages =
|
environment.systemPackages =
|
||||||
@@ -316,9 +325,6 @@
|
|||||||
"spotify"
|
"spotify"
|
||||||
"vlc"
|
"vlc"
|
||||||
];
|
];
|
||||||
masApps = {
|
|
||||||
Xcode = 497799835;
|
|
||||||
};
|
|
||||||
greedyCasks = true;
|
greedyCasks = true;
|
||||||
onActivation = {
|
onActivation = {
|
||||||
cleanup = "zap";
|
cleanup = "zap";
|
||||||
|
|||||||
@@ -66,7 +66,7 @@
|
|||||||
--passphrase-file "$passphrase_path" \
|
--passphrase-file "$passphrase_path" \
|
||||||
--import "$normalized_key_file"
|
--import "$normalized_key_file"
|
||||||
'';
|
'';
|
||||||
multiplexerAliases = import ../../shared/multiplexer-aliases.nix;
|
multiplexerAliases = import ../../nix-shared/multiplexer-aliases.nix;
|
||||||
|
|
||||||
excludedTopLevelEntries = [
|
excludedTopLevelEntries = [
|
||||||
"codex"
|
"codex"
|
||||||
@@ -200,18 +200,18 @@ in {
|
|||||||
programs.ssh = {
|
programs.ssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
enableDefaultConfig = false;
|
enableDefaultConfig = false;
|
||||||
matchBlocks = {
|
settings = {
|
||||||
"*" = {
|
"*" = {
|
||||||
forwardAgent = true;
|
ForwardAgent = true;
|
||||||
addKeysToAgent = "no";
|
AddKeysToAgent = "no";
|
||||||
compression = false;
|
Compression = false;
|
||||||
serverAliveInterval = 0;
|
ServerAliveInterval = 0;
|
||||||
serverAliveCountMax = 3;
|
ServerAliveCountMax = 3;
|
||||||
hashKnownHosts = false;
|
HashKnownHosts = false;
|
||||||
userKnownHostsFile = "~/.ssh/known_hosts";
|
UserKnownHostsFile = "~/.ssh/known_hosts";
|
||||||
controlMaster = "no";
|
ControlMaster = "no";
|
||||||
controlPath = "~/.ssh/master-%r@%n:%p";
|
ControlPath = "~/.ssh/master-%r@%n:%p";
|
||||||
controlPersist = "no";
|
ControlPersist = "no";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -283,6 +283,7 @@ in {
|
|||||||
|
|
||||||
programs.zsh = {
|
programs.zsh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
dotDir = "${config.home.homeDirectory}/.zsh";
|
||||||
autosuggestion.enable = true;
|
autosuggestion.enable = true;
|
||||||
oh-my-zsh = {
|
oh-my-zsh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
else pkgs.git-sync;
|
else pkgs.git-sync;
|
||||||
orgPath = "${config.home.homeDirectory}/org";
|
orgPath = "${config.home.homeDirectory}/org";
|
||||||
passwordStorePath = "${config.home.homeDirectory}/.password-store";
|
passwordStorePath = "${config.home.homeDirectory}/.password-store";
|
||||||
|
claudePath = "${config.home.homeDirectory}/.claude";
|
||||||
in {
|
in {
|
||||||
services.git-sync = {
|
services.git-sync = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@@ -24,6 +25,16 @@ in {
|
|||||||
path = passwordStorePath;
|
path = passwordStorePath;
|
||||||
uri = "git@github.com:colonelpanic8/.password-store.git";
|
uri = "git@github.com:colonelpanic8/.password-store.git";
|
||||||
};
|
};
|
||||||
|
claude-history = {
|
||||||
|
path = claudePath;
|
||||||
|
uri = "git@github.com:colonelpanic8/claude-history.git";
|
||||||
|
interval = 600;
|
||||||
|
};
|
||||||
|
# NB: codex-history is intentionally NOT synced on mac-demarco-mini.
|
||||||
|
# The codex archive is ~1GB and this machine runs chronically near full
|
||||||
|
# (APFS container ~94% used); cloning it would break every darwin
|
||||||
|
# rebuild. mac's own Codex sessions are already merged into the repo —
|
||||||
|
# it just doesn't receive. Re-enable once the disk has headroom.
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -33,5 +44,9 @@ in {
|
|||||||
lib.mkForce ["${gitSyncPackage}/bin/git-sync" "-d" orgPath];
|
lib.mkForce ["${gitSyncPackage}/bin/git-sync" "-d" orgPath];
|
||||||
git-sync-password-store.config.ProgramArguments =
|
git-sync-password-store.config.ProgramArguments =
|
||||||
lib.mkForce ["${gitSyncPackage}/bin/git-sync" "-d" passwordStorePath];
|
lib.mkForce ["${gitSyncPackage}/bin/git-sync" "-d" passwordStorePath];
|
||||||
|
# Live Claude sessions append to their transcript constantly; sync
|
||||||
|
# untracked session files and throttle event-driven syncs.
|
||||||
|
git-sync-claude-history.config.ProgramArguments =
|
||||||
|
lib.mkForce ["${gitSyncPackage}/bin/git-sync-rs" "-d" claudePath "watch" "--new-files" "true" "--min-interval" "300"];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,10 @@
|
|||||||
}: let
|
}: let
|
||||||
cfg = config.myModules.codexGeneratedSkills;
|
cfg = config.myModules.codexGeneratedSkills;
|
||||||
oos = config.lib.file.mkOutOfStoreSymlink;
|
oos = config.lib.file.mkOutOfStoreSymlink;
|
||||||
|
managedConfig = pkgs.writeText "codex-managed-config.toml" ''
|
||||||
|
[mcp_servers.nixos]
|
||||||
|
command = "${lib.getExe pkgs.mcp-nixos}"
|
||||||
|
'';
|
||||||
in {
|
in {
|
||||||
options.myModules.codexGeneratedSkills = {
|
options.myModules.codexGeneratedSkills = {
|
||||||
enable = lib.mkEnableOption "Codex home setup";
|
enable = lib.mkEnableOption "Codex home setup";
|
||||||
@@ -22,6 +26,12 @@ in {
|
|||||||
description = "Codex dotfiles directory in the live worktree.";
|
description = "Codex dotfiles directory in the live worktree.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sourceCodexDir = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "${cfg.worktreeCodexDir}";
|
||||||
|
description = "Readable fallback Codex dotfiles directory from the flake source.";
|
||||||
|
};
|
||||||
|
|
||||||
localConfig = lib.mkOption {
|
localConfig = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = "${cfg.codexHome}/config.local.toml";
|
default = "${cfg.codexHome}/config.local.toml";
|
||||||
@@ -49,10 +59,11 @@ in {
|
|||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
home.file = {
|
home.file = {
|
||||||
".codex/.gitignore" = {
|
# NB: ~/.codex/.gitignore is intentionally NOT managed here. ~/.codex is
|
||||||
force = true;
|
# a git-sync-rs checkout of the codex-history repo, which ships its own
|
||||||
source = oos "${cfg.worktreeCodexDir}/.gitignore";
|
# real .gitignore — git refuses to read a symlinked ignore file, so an
|
||||||
};
|
# HM-managed symlink here would silently disable ignore rules and risk
|
||||||
|
# committing auth.json/sqlite state. Leave it to the repo.
|
||||||
|
|
||||||
".codex/AGENTS.md" = {
|
".codex/AGENTS.md" = {
|
||||||
force = true;
|
force = true;
|
||||||
@@ -103,6 +114,8 @@ in {
|
|||||||
home.activation.generateCodexConfig = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
home.activation.generateCodexConfig = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
||||||
codex_home=${lib.escapeShellArg cfg.codexHome}
|
codex_home=${lib.escapeShellArg cfg.codexHome}
|
||||||
base=${lib.escapeShellArg "${cfg.worktreeCodexDir}/config.toml"}
|
base=${lib.escapeShellArg "${cfg.worktreeCodexDir}/config.toml"}
|
||||||
|
source_base=${lib.escapeShellArg "${cfg.sourceCodexDir}/config.toml"}
|
||||||
|
managed_config=${lib.escapeShellArg managedConfig}
|
||||||
local_config=${lib.escapeShellArg cfg.localConfig}
|
local_config=${lib.escapeShellArg cfg.localConfig}
|
||||||
local_state_config=${lib.escapeShellArg cfg.generatedStateConfig}
|
local_state_config=${lib.escapeShellArg cfg.generatedStateConfig}
|
||||||
target="$codex_home/config.toml"
|
target="$codex_home/config.toml"
|
||||||
@@ -115,8 +128,12 @@ in {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
if [ ! -r "$base" ]; then
|
if [ ! -r "$base" ]; then
|
||||||
echo "Missing shared Codex config at $base" >&2
|
if [ -r "$source_base" ]; then
|
||||||
exit 1
|
base="$source_base"
|
||||||
|
else
|
||||||
|
echo "Missing shared Codex config at $base and $source_base" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$codex_home"
|
mkdir -p "$codex_home"
|
||||||
@@ -129,7 +146,7 @@ in {
|
|||||||
-v begin_marker="$begin_marker" \
|
-v begin_marker="$begin_marker" \
|
||||||
-v end_marker="$end_marker" \
|
-v end_marker="$end_marker" \
|
||||||
-v rejected_prefixes="$rejected_project_prefixes" '
|
-v rejected_prefixes="$rejected_project_prefixes" '
|
||||||
FNR == NR {
|
ARGIND < ARGC - 1 {
|
||||||
if ($0 ~ /^\[[^]]+\]$/) {
|
if ($0 ~ /^\[[^]]+\]$/) {
|
||||||
base_sections[$0] = 1
|
base_sections[$0] = 1
|
||||||
}
|
}
|
||||||
@@ -183,7 +200,7 @@ in {
|
|||||||
END {
|
END {
|
||||||
flush_block()
|
flush_block()
|
||||||
}
|
}
|
||||||
' "$base" "$target" \
|
' "$base" "$managed_config" "$target" \
|
||||||
| ${lib.getExe pkgs.perl} -0pe 's/\n{3,}/\n\n/g' \
|
| ${lib.getExe pkgs.perl} -0pe 's/\n{3,}/\n\n/g' \
|
||||||
> "$local_state"
|
> "$local_state"
|
||||||
|
|
||||||
@@ -200,6 +217,8 @@ in {
|
|||||||
chmod 600 "$tmp"
|
chmod 600 "$tmp"
|
||||||
|
|
||||||
cat "$base" > "$tmp"
|
cat "$base" > "$tmp"
|
||||||
|
printf '\n' >> "$tmp"
|
||||||
|
cat "$managed_config" >> "$tmp"
|
||||||
if [ -r "$local_config" ]; then
|
if [ -r "$local_config" ]; then
|
||||||
printf '\n' >> "$tmp"
|
printf '\n' >> "$tmp"
|
||||||
cat "$local_config" >> "$tmp"
|
cat "$local_config" >> "$tmp"
|
||||||
@@ -221,30 +240,37 @@ in {
|
|||||||
home.activation.linkCodexDotfileSkills = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
home.activation.linkCodexDotfileSkills = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
||||||
skills_dir=${lib.escapeShellArg cfg.skillsDir}
|
skills_dir=${lib.escapeShellArg cfg.skillsDir}
|
||||||
worktree_skills=${lib.escapeShellArg "${cfg.worktreeCodexDir}/skills"}
|
worktree_skills=${lib.escapeShellArg "${cfg.worktreeCodexDir}/skills"}
|
||||||
|
source_skills=${lib.escapeShellArg "${cfg.sourceCodexDir}/skills"}
|
||||||
|
|
||||||
if [ ! -d "$worktree_skills" ]; then
|
if [ ! -d "$worktree_skills" ]; then
|
||||||
echo "Skipping Codex dotfile skills setup because $worktree_skills is not a directory" >&2
|
if [ -d "$source_skills" ]; then
|
||||||
exit 1
|
worktree_skills="$source_skills"
|
||||||
|
else
|
||||||
|
echo "Skipping Codex dotfile skills setup because neither $worktree_skills nor $source_skills is a directory" >&2
|
||||||
|
worktree_skills=
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$skills_dir"
|
mkdir -p "$skills_dir"
|
||||||
|
|
||||||
for skill in "$worktree_skills"/*; do
|
if [ -n "$worktree_skills" ]; then
|
||||||
[ -d "$skill" ] || continue
|
for skill in "$worktree_skills"/*; do
|
||||||
[ -r "$skill/SKILL.md" ] || continue
|
[ -d "$skill" ] || continue
|
||||||
|
[ -r "$skill/SKILL.md" ] || continue
|
||||||
|
|
||||||
name="$(basename "$skill")"
|
name="$(basename "$skill")"
|
||||||
case "$name" in
|
case "$name" in
|
||||||
.system|codex-primary-runtime) continue ;;
|
.system|codex-primary-runtime) continue ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
target="$skills_dir/$name"
|
target="$skills_dir/$name"
|
||||||
if [ -L "$target" ] || [ ! -e "$target" ]; then
|
if [ -L "$target" ] || [ ! -e "$target" ]; then
|
||||||
ln -sfn "$skill" "$target"
|
ln -sfn "$skill" "$target"
|
||||||
elif [ ! -d "$target" ]; then
|
elif [ ! -d "$target" ]; then
|
||||||
echo "Skipping Codex skill $name because $target exists and is not a directory" >&2
|
echo "Skipping Codex skill $name because $target exists and is not a directory" >&2
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
fi
|
||||||
'';
|
'';
|
||||||
|
|
||||||
home.activation.setupCodexGeneratedSkills = lib.hm.dag.entryAfter ["linkCodexDotfileSkills"] ''
|
home.activation.setupCodexGeneratedSkills = lib.hm.dag.entryAfter ["linkCodexDotfileSkills"] ''
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
final: prev:
|
final: prev: {
|
||||||
let
|
|
||||||
# XXX: codex and claude-code are now provided by dedicated flakes in nix.nix:
|
# XXX: codex and claude-code are now provided by dedicated flakes in nix.nix:
|
||||||
# - inputs.codex-cli-nix (github:sadjow/codex-cli-nix)
|
# - inputs.codex-cli-nix (github:sadjow/codex-cli-nix)
|
||||||
# - inputs.claude-code-nix (github:sadjow/claude-code-nix)
|
# - inputs.claude-code-nix (github:sadjow/claude-code-nix)
|
||||||
@@ -30,46 +29,6 @@ let
|
|||||||
# hash = "sha256-OqvLiwB5TwZaxDvyN/+/+eueBdWNaYxd81cd5AZK/mA=";
|
# hash = "sha256-OqvLiwB5TwZaxDvyN/+/+eueBdWNaYxd81cd5AZK/mA=";
|
||||||
# npmDepsHash = "sha256-vy7osk3UAOEgsJx9jdcGe2wICOk5Urzxh1WLAHyHM+U=";
|
# npmDepsHash = "sha256-vy7osk3UAOEgsJx9jdcGe2wICOk5Urzxh1WLAHyHM+U=";
|
||||||
# };
|
# };
|
||||||
# Chrome 136+ ignores remote debugging switches on the default profile.
|
|
||||||
# Keep the wrapper in place, but do not inject remote debugging flags into
|
|
||||||
# the normal Chrome launcher. The supported path for a real profile is the
|
|
||||||
# Chrome remote debugging permission flow used by chrome-devtools-mcp
|
|
||||||
# --auto-connect.
|
|
||||||
chromeRemoteDebuggingFlags = [];
|
|
||||||
placeholder = null; # Dummy binding to keep let block valid
|
|
||||||
in
|
|
||||||
{
|
|
||||||
google-chrome = prev.symlinkJoin {
|
|
||||||
name = prev.google-chrome.name;
|
|
||||||
paths = [ prev.google-chrome ];
|
|
||||||
nativeBuildInputs = [ final.makeWrapper ];
|
|
||||||
postBuild = ''
|
|
||||||
rm "$out/bin/google-chrome" "$out/bin/google-chrome-stable"
|
|
||||||
|
|
||||||
makeWrapper ${prev.google-chrome}/bin/google-chrome "$out/bin/google-chrome" \
|
|
||||||
${final.lib.concatMapStringsSep " " (flag: "--add-flags ${final.lib.escapeShellArg flag}") chromeRemoteDebuggingFlags}
|
|
||||||
|
|
||||||
makeWrapper ${prev.google-chrome}/bin/google-chrome-stable "$out/bin/google-chrome-stable" \
|
|
||||||
${final.lib.concatMapStringsSep " " (flag: "--add-flags ${final.lib.escapeShellArg flag}") chromeRemoteDebuggingFlags}
|
|
||||||
|
|
||||||
for desktopName in google-chrome.desktop com.google.Chrome.desktop; do
|
|
||||||
desktopFile="$out/share/applications/$desktopName"
|
|
||||||
if [ -f "$desktopFile" ]; then
|
|
||||||
rm "$desktopFile"
|
|
||||||
cp "${prev.google-chrome}/share/applications/$desktopName" "$desktopFile"
|
|
||||||
substituteInPlace "$desktopFile" \
|
|
||||||
--replace-fail "${prev.google-chrome}/bin/google-chrome-stable" "$out/bin/google-chrome-stable"
|
|
||||||
substituteInPlace "$desktopFile" \
|
|
||||||
--replace-fail "image/gif;" "" \
|
|
||||||
--replace-fail "image/jpeg;" "" \
|
|
||||||
--replace-fail "image/png;" "" \
|
|
||||||
--replace-fail "image/webp;" ""
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
'';
|
|
||||||
meta = prev.google-chrome.meta;
|
|
||||||
};
|
|
||||||
|
|
||||||
# Fix poetry pbs-installer version constraint issue
|
# Fix poetry pbs-installer version constraint issue
|
||||||
poetry = prev.poetry.overrideAttrs (oldAttrs: {
|
poetry = prev.poetry.overrideAttrs (oldAttrs: {
|
||||||
dontCheckRuntimeDeps = true;
|
dontCheckRuntimeDeps = true;
|
||||||
@@ -88,6 +47,18 @@ in
|
|||||||
oldAttrs.preConfigure;
|
oldAttrs.preConfigure;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
vte = prev.vte.overrideAttrs (oldAttrs: {
|
||||||
|
# The termite compatibility patch in nixpkgs still uses a helper that VTE
|
||||||
|
# removed. VTE 0.84 builds as C++23 and already uses std::to_underlying.
|
||||||
|
postPatch = (oldAttrs.postPatch or "") + ''
|
||||||
|
if grep -q "vte::to_integral(vte::platform::ClipboardType::PRIMARY)" src/vtegtk.cc; then
|
||||||
|
substituteInPlace src/vtegtk.cc \
|
||||||
|
--replace-fail "vte::to_integral(vte::platform::ClipboardType::PRIMARY)" \
|
||||||
|
"std::to_underlying(vte::platform::ClipboardType::PRIMARY)"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
|
||||||
# XXX: codex and claude-code are now provided by flakes in nix.nix
|
# XXX: codex and claude-code are now provided by flakes in nix.nix
|
||||||
# See the overlay at the end of nixpkgs.overlays in nix.nix
|
# See the overlay at the end of nixpkgs.overlays in nix.nix
|
||||||
|
|
||||||
@@ -311,7 +282,6 @@ from transformers import (/' \
|
|||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
|
|
||||||
happy-coder = final.callPackage ../../nixos/packages/happy-coder { };
|
|
||||||
playwright-cli = final.callPackage ../../nixos/packages/playwright-cli { };
|
playwright-cli = final.callPackage ../../nixos/packages/playwright-cli { };
|
||||||
t3code = final.callPackage ../../nixos/packages/t3code { };
|
t3code = final.callPackage ../../nixos/packages/t3code { };
|
||||||
# Custom Waybar fork for workspace taskbar support + external SNI watcher option.
|
# Custom Waybar fork for workspace taskbar support + external SNI watcher option.
|
||||||
|
|||||||
@@ -60,7 +60,6 @@
|
|||||||
pstree
|
pstree
|
||||||
rclone
|
rclone
|
||||||
ripgrep
|
ripgrep
|
||||||
silver-searcher
|
|
||||||
skim
|
skim
|
||||||
tmux
|
tmux
|
||||||
zellij
|
zellij
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ description: Use when user asks to bump, update, or upgrade claude-code or codex
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Updates claude-code and/or codex to latest versions in `~/dotfiles/nixos/overlay.nix`. Nix requires correct hashes which must be discovered through failed builds.
|
Updates claude-code and/or codex to latest versions in `/etc/nixos/overlay.nix`. Nix requires correct hashes which must be discovered through failed builds.
|
||||||
|
|
||||||
## Quick Reference
|
## Quick Reference
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ curl -s "https://api.github.com/repos/openai/codex/releases/latest" | jq -r '.ta
|
|||||||
|
|
||||||
### 2. Update Version and Clear Hashes
|
### 2. Update Version and Clear Hashes
|
||||||
|
|
||||||
In `~/dotfiles/nixos/overlay.nix`:
|
In `/etc/nixos/overlay.nix`:
|
||||||
|
|
||||||
**For claude-code:**
|
**For claude-code:**
|
||||||
```nix
|
```nix
|
||||||
@@ -77,4 +77,4 @@ enableClaudeCodeOverride = true; # Set false to use nixpkgs claude-code
|
|||||||
|
|
||||||
## File Location
|
## File Location
|
||||||
|
|
||||||
`~/dotfiles/nixos/overlay.nix`
|
`/etc/nixos/overlay.nix`
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
[ 305ms] [ERROR] Failed to load resource: the server responded with a status of 403 () @ https://www.reddit.com/r/hyprland/comments/1t74dt6/pre055_discussion_share_your_new_lua_scripts_that/?solution=c0ac3501a8dec997c0ac3501a8dec997&js_challenge=1&token=bbbe4bf1c9a2b5160829c4be34da586130c27f161a9c565bc73f58c2dec5bfa9&jsc_orig_r=:0
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
- generic [active] [ref=e1]:
|
|
||||||
- link [ref=e3] [cursor=pointer]:
|
|
||||||
- /url: https://www.reddit.com
|
|
||||||
- img [ref=e4]
|
|
||||||
- generic [ref=e5]:
|
|
||||||
- img [ref=e6]
|
|
||||||
- heading "Prove your humanity" [level=1] [ref=e8]
|
|
||||||
- paragraph [ref=e9]: We’re committed to safety and security. But not for bots. Complete the challenge below and let us know you’re a real person.
|
|
||||||
- iframe [ref=e14]:
|
|
||||||
- generic [ref=f1e2]:
|
|
||||||
- generic [ref=f1e3]:
|
|
||||||
- checkbox "I'm not a robot" [ref=f1e7]
|
|
||||||
- generic [ref=f1e11]: I'm not a robot
|
|
||||||
- generic [ref=f1e15]: reCAPTCHA
|
|
||||||
- generic [ref=e15]:
|
|
||||||
- link "Reddit, Inc. © \"2026\". All rights reserved." [ref=e16] [cursor=pointer]:
|
|
||||||
- /url: https://www.redditinc.com/
|
|
||||||
- generic [ref=e17]:
|
|
||||||
- link "User Agreement" [ref=e18] [cursor=pointer]:
|
|
||||||
- /url: https://www.reddit.com/help/useragreement
|
|
||||||
- link "Privacy Policy" [ref=e19] [cursor=pointer]:
|
|
||||||
- /url: https://www.reddit.com/help/privacypolicy
|
|
||||||
- link "Content Policy" [ref=e20] [cursor=pointer]:
|
|
||||||
- /url: https://www.reddit.com/help/contentpolicy
|
|
||||||
- link "Help" [ref=e21] [cursor=pointer]:
|
|
||||||
- /url: https://support.reddithelp.com/hc/en-us
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
- generic [ref=e3]:
|
|
||||||
- img [ref=e5]
|
|
||||||
- generic [ref=e7]:
|
|
||||||
- generic [ref=e8]: You've been blocked by network security.
|
|
||||||
- generic [ref=e10]:
|
|
||||||
- text: If you think you've been blocked by mistake, file a ticket below and we'll look into it.
|
|
||||||
- link "File a ticket" [ref=e12] [cursor=pointer]:
|
|
||||||
- /url: https://support.reddithelp.com/hc/en-us/requests/new?ticket_form_id=21879292693140
|
|
||||||
- generic [ref=e14]: File a ticket
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
- generic [ref=e3]:
|
|
||||||
- img [ref=e5]
|
|
||||||
- generic [ref=e7]:
|
|
||||||
- generic [ref=e8]: You've been blocked by network security.
|
|
||||||
- generic [ref=e10]:
|
|
||||||
- text: If you think you've been blocked by mistake, file a ticket below and we'll look into it.
|
|
||||||
- link "File a ticket" [ref=e12] [cursor=pointer]:
|
|
||||||
- /url: https://support.reddithelp.com/hc/en-us/requests/new?ticket_form_id=21879292693140
|
|
||||||
- generic [ref=e14]: File a ticket
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Agent Notes (dotfiles/nixos)
|
# Agent Notes (dotfiles/nixos)
|
||||||
|
|
||||||
This repository is a single git repo rooted at `~/dotfiles`. This `nixos/` directory is the NixOS flake, but most "user command" scripts and shell functions live outside of it.
|
This repository is a single git repo rooted at `/srv/dotfiles` on NixOS machines. This `nixos/` directory is the NixOS flake, but most "user command" scripts and shell functions live outside of it.
|
||||||
|
|
||||||
## Where To Put Things
|
## Where To Put Things
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ Avoid dropping scripts in `~/bin` or `~/.local/bin` unless the user explicitly a
|
|||||||
|
|
||||||
## NixOS Rebuild Workflow
|
## NixOS Rebuild Workflow
|
||||||
|
|
||||||
- Run `just switch` from `~/dotfiles/nixos` (not `nixos-rebuild` directly).
|
- Run `just switch` from `/etc/nixos` or `/srv/dotfiles/nixos` (not `nixos-rebuild` directly).
|
||||||
- Host configs live under `machines/`.
|
- Host configs live under `machines/`.
|
||||||
|
|
||||||
## Rofi/Tmux Integration Pointers
|
## Rofi/Tmux Integration Pointers
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ makeEnable config "myModules.base" true {
|
|||||||
"electron-12.2.3"
|
"electron-12.2.3"
|
||||||
"electron-19.1.9"
|
"electron-19.1.9"
|
||||||
"electron-32.3.3"
|
"electron-32.3.3"
|
||||||
|
"electron-39.8.10"
|
||||||
"etcher"
|
"etcher"
|
||||||
"nix-2.16.2"
|
"nix-2.16.2"
|
||||||
"openssl-1.0.2u"
|
"openssl-1.0.2u"
|
||||||
@@ -39,10 +40,12 @@ makeEnable config "myModules.base" true {
|
|||||||
networking.nameservers = ["8.8.8.8" "8.8.4.4"];
|
networking.nameservers = ["8.8.8.8" "8.8.4.4"];
|
||||||
networking.networkmanager = {
|
networking.networkmanager = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
dns = "systemd-resolved";
|
||||||
plugins = [pkgs.networkmanager-l2tp pkgs.networkmanager-openvpn];
|
plugins = [pkgs.networkmanager-l2tp pkgs.networkmanager-openvpn];
|
||||||
settings.main.rc-manager = "symlink";
|
settings.main.rc-manager = "symlink";
|
||||||
};
|
};
|
||||||
networking.resolvconf.enable = false;
|
networking.resolvconf.enable = false;
|
||||||
|
services.resolved.enable = true;
|
||||||
services.mullvad-vpn.enable = true;
|
services.mullvad-vpn.enable = true;
|
||||||
|
|
||||||
# Audio
|
# Audio
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
{pkgs, ...}: {
|
|
||||||
imports = [
|
|
||||||
../nix-shared/system/essential.nix
|
|
||||||
];
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
emacs-auto
|
|
||||||
];
|
|
||||||
programs.zsh.enable = true;
|
|
||||||
networking.firewall.enable = false;
|
|
||||||
networking.networkmanager = {
|
|
||||||
enable = true;
|
|
||||||
extraConfig = ''
|
|
||||||
[main]
|
|
||||||
rc-manager=resolvconf
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
nixpkgs.config.allowUnfree = true;
|
|
||||||
services.xserver = {
|
|
||||||
exportConfiguration = true;
|
|
||||||
enable = true;
|
|
||||||
layout = "us";
|
|
||||||
desktopManager = {
|
|
||||||
plasma6.enable = true;
|
|
||||||
};
|
|
||||||
displayManager = {
|
|
||||||
sddm = {
|
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
sessionCommands = ''
|
|
||||||
systemctl --user import-environment GDK_PIXBUF_MODULE_FILE DBUS_SESSION_BUS_ADDRESS PATH
|
|
||||||
'';
|
|
||||||
setupCommands = ''
|
|
||||||
autorandr -c
|
|
||||||
systemctl restart autorandr.service
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
nix = {
|
|
||||||
extraOptions = ''
|
|
||||||
experimental-features = nix-command flakes
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
users.users = {
|
|
||||||
imalison = {
|
|
||||||
extraGroups = [
|
|
||||||
"audio"
|
|
||||||
"adbusers"
|
|
||||||
"disk"
|
|
||||||
"docker"
|
|
||||||
"networkmanager"
|
|
||||||
"openrazer"
|
|
||||||
"plugdev"
|
|
||||||
"syncthing"
|
|
||||||
"systemd-journal"
|
|
||||||
"video"
|
|
||||||
"wheel"
|
|
||||||
];
|
|
||||||
group = "users";
|
|
||||||
isNormalUser = true;
|
|
||||||
createHome = true;
|
|
||||||
shell = pkgs.zsh;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
985
nixos/bootstrap/flake.lock
generated
985
nixos/bootstrap/flake.lock
generated
@@ -1,985 +0,0 @@
|
|||||||
{
|
|
||||||
"nodes": {
|
|
||||||
"flake-compat": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1673956053,
|
|
||||||
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
|
||||||
"owner": "edolstra",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "edolstra",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-compat_2": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1673956053,
|
|
||||||
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
|
||||||
"owner": "edolstra",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "edolstra",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-parts": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs-lib": [
|
|
||||||
"nixified-ai",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1677714448,
|
|
||||||
"narHash": "sha256-Hq8qLs8xFu28aDjytfxjdC96bZ6pds21Yy09mSC156I=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"rev": "dc531e3a9ce757041e1afaff8ee932725ca60002",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-parts_2": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs-lib": "nixpkgs-lib"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1673362319,
|
|
||||||
"narHash": "sha256-Pjp45Vnj7S/b3BRpZEVfdu8sqqA6nvVjvYu59okhOyI=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"rev": "82c16f1682cf50c01cb0280b38a1eed202b3fe9f",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"id": "flake-parts",
|
|
||||||
"type": "indirect"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-parts_3": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs-lib": [
|
|
||||||
"nixified-ai",
|
|
||||||
"hercules-ci-effects",
|
|
||||||
"hercules-ci-agent",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1666885127,
|
|
||||||
"narHash": "sha256-uXA/3lhLhwOTBMn9a5zJODKqaRT+SuL5cpEmOz2ULoo=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"rev": "0e101dbae756d35a376a5e1faea532608e4a4b9a",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "flake-parts",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": [
|
|
||||||
"systems"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1689068808,
|
|
||||||
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils_2": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1667077288,
|
|
||||||
"narHash": "sha256-bdC8sFNDpT0HK74u9fUkpbf1MEzVYJ+ka7NXCdgBoaA=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "6ee9ebb6b1ee695d2cacc4faa053a7b9baa76817",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils_3": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": "systems"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1689068808,
|
|
||||||
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils_4": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": "systems_3"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1689068808,
|
|
||||||
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils_5": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": "systems_4"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1689068808,
|
|
||||||
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"git-ignore-nix": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1660459072,
|
|
||||||
"narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "gitignore.nix",
|
|
||||||
"rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "gitignore.nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"git-ignore-nix_2": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": "nixpkgs_6"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1660459072,
|
|
||||||
"narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "gitignore.nix",
|
|
||||||
"rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"ref": "master",
|
|
||||||
"repo": "gitignore.nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"git-ignore-nix_3": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": "nixpkgs_8"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1660459072,
|
|
||||||
"narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "gitignore.nix",
|
|
||||||
"rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"ref": "master",
|
|
||||||
"repo": "gitignore.nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"gtk-sni-tray": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": [
|
|
||||||
"taffybar",
|
|
||||||
"flake-utils"
|
|
||||||
],
|
|
||||||
"git-ignore-nix": [
|
|
||||||
"taffybar",
|
|
||||||
"git-ignore-nix"
|
|
||||||
],
|
|
||||||
"nixpkgs": [
|
|
||||||
"taffybar",
|
|
||||||
"nixpkgs"
|
|
||||||
],
|
|
||||||
"status-notifier-item": [
|
|
||||||
"taffybar",
|
|
||||||
"status-notifier-item"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1663379298,
|
|
||||||
"narHash": "sha256-m18+G7V1N+g/pPeKJG9hkblGA5c8QTnUYnsU5t14sOw=",
|
|
||||||
"owner": "taffybar",
|
|
||||||
"repo": "gtk-sni-tray",
|
|
||||||
"rev": "1927d86308d34b5d21a709cf8ff5332ec5d37de4",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "taffybar",
|
|
||||||
"ref": "master",
|
|
||||||
"repo": "gtk-sni-tray",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"gtk-strut": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": [
|
|
||||||
"taffybar",
|
|
||||||
"flake-utils"
|
|
||||||
],
|
|
||||||
"git-ignore-nix": [
|
|
||||||
"taffybar",
|
|
||||||
"git-ignore-nix"
|
|
||||||
],
|
|
||||||
"nixpkgs": [
|
|
||||||
"taffybar",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1663377859,
|
|
||||||
"narHash": "sha256-UrBd+R3NaJIDC2lt5gMafS3KBeLs83emm2YorX2cFCo=",
|
|
||||||
"owner": "taffybar",
|
|
||||||
"repo": "gtk-strut",
|
|
||||||
"rev": "d946eb230cdccf5afc063642b3215723e555990b",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "taffybar",
|
|
||||||
"ref": "master",
|
|
||||||
"repo": "gtk-strut",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"hercules-ci-agent": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-parts": "flake-parts_3",
|
|
||||||
"nix-darwin": "nix-darwin",
|
|
||||||
"nixpkgs": "nixpkgs_2",
|
|
||||||
"pre-commit-hooks-nix": "pre-commit-hooks-nix"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1673183923,
|
|
||||||
"narHash": "sha256-vb+AEQJAW4Xn4oHsfsx8H12XQU0aK8VYLtWYJm/ol28=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "hercules-ci-agent",
|
|
||||||
"rev": "b3f8aa8e4a8b22dbbe92cc5a89e6881090b933b3",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"id": "hercules-ci-agent",
|
|
||||||
"type": "indirect"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"hercules-ci-effects": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-parts": "flake-parts_2",
|
|
||||||
"hercules-ci-agent": "hercules-ci-agent",
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixified-ai",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1676558019,
|
|
||||||
"narHash": "sha256-obUHCMMWbffb3k0b9YIChsJ2Z281BcDYnTPTbJRP6vs=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "hercules-ci-effects",
|
|
||||||
"rev": "fdbc15b55db8d037504934d3af52f788e0593380",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "hercules-ci-effects",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"home-manager": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1692503956,
|
|
||||||
"narHash": "sha256-MOA6FKc1YgfGP3ESnjSYfsyJ1BXlwV5pGlY/u5XdJfY=",
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "home-manager",
|
|
||||||
"rev": "958c06303f43cf0625694326b7f7e5475b1a2d5c",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "home-manager",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"invokeai-src": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1677475057,
|
|
||||||
"narHash": "sha256-REtyVcyRgspn1yYvB4vIHdOrPRZRNSSraepHik9MfgE=",
|
|
||||||
"owner": "invoke-ai",
|
|
||||||
"repo": "InvokeAI",
|
|
||||||
"rev": "650f4bb58ceca458bff1410f35cd6d6caad399c6",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "invoke-ai",
|
|
||||||
"ref": "v2.3.1.post2",
|
|
||||||
"repo": "InvokeAI",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"koboldai-src": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1668957963,
|
|
||||||
"narHash": "sha256-fKQ/6LiMmrfSWczC5kcf6M9cpuF9dDYl2gJ4+6ZLSdY=",
|
|
||||||
"owner": "koboldai",
|
|
||||||
"repo": "koboldai-client",
|
|
||||||
"rev": "f2077b8e58db6bd47a62bf9ed2649bb0711f9678",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "koboldai",
|
|
||||||
"ref": "1.19.2",
|
|
||||||
"repo": "koboldai-client",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lowdown-src": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1633514407,
|
|
||||||
"narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=",
|
|
||||||
"owner": "kristapsdz",
|
|
||||||
"repo": "lowdown",
|
|
||||||
"rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "kristapsdz",
|
|
||||||
"repo": "lowdown",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nix": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": "flake-compat",
|
|
||||||
"lowdown-src": "lowdown-src",
|
|
||||||
"nixpkgs": "nixpkgs",
|
|
||||||
"nixpkgs-regression": "nixpkgs-regression"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1690515062,
|
|
||||||
"narHash": "sha256-PyvvANcbsjHAjvUsrGDyxk0b/CVExcrJAlCEQRp9HWc=",
|
|
||||||
"owner": "IvanMalison",
|
|
||||||
"repo": "nix",
|
|
||||||
"rev": "bedf108a183191519fdfa99a913f766090515d34",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "IvanMalison",
|
|
||||||
"ref": "my2.15.1",
|
|
||||||
"repo": "nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nix-darwin": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixified-ai",
|
|
||||||
"hercules-ci-effects",
|
|
||||||
"hercules-ci-agent",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1667419884,
|
|
||||||
"narHash": "sha256-oLNw87ZI5NxTMlNQBv1wG2N27CUzo9admaFlnmavpiY=",
|
|
||||||
"owner": "LnL7",
|
|
||||||
"repo": "nix-darwin",
|
|
||||||
"rev": "cfc0125eafadc9569d3d6a16ee928375b77e3100",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "LnL7",
|
|
||||||
"repo": "nix-darwin",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixified-ai": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-parts": "flake-parts",
|
|
||||||
"hercules-ci-effects": "hercules-ci-effects",
|
|
||||||
"invokeai-src": "invokeai-src",
|
|
||||||
"koboldai-src": "koboldai-src",
|
|
||||||
"nixpkgs": "nixpkgs_3"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1685671845,
|
|
||||||
"narHash": "sha256-qVA3wIxPb9PIFqa9Wf2a9jRMeMhE4kWw2y3oPSuRHU4=",
|
|
||||||
"owner": "nixified-ai",
|
|
||||||
"repo": "flake",
|
|
||||||
"rev": "0c58f8cba3fb42c54f2a7bf9bd45ee4cbc9f2477",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nixified-ai",
|
|
||||||
"repo": "flake",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixos-hardware": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1692373088,
|
|
||||||
"narHash": "sha256-EPgCecdc9I8aTdmDNoO1l7R72r2WPhZRcesV4nzxBj8=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixos-hardware",
|
|
||||||
"rev": "7f1836531b126cfcf584e7d7d71bf8758bb58969",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixos-hardware",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixos-wsl": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": "flake-compat_2",
|
|
||||||
"flake-utils": "flake-utils_3",
|
|
||||||
"nixpkgs": "nixpkgs_4"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1692543835,
|
|
||||||
"narHash": "sha256-1fR7+IhSSEHRbRW1w3nXb38/4kFfpmCDzMsK+ApqZCk=",
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "NixOS-WSL",
|
|
||||||
"rev": "faab3194692c5b6b351e33fc8d5e7f15f22d1d15",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "NixOS-WSL",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1670461440,
|
|
||||||
"narHash": "sha256-jy1LB8HOMKGJEGXgzFRLDU1CBGL0/LlkolgnqIsF0D8=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "04a75b2eecc0acf6239acf9dd04485ff8d14f425",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-22.11-small",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs-lib": {
|
|
||||||
"locked": {
|
|
||||||
"dir": "lib",
|
|
||||||
"lastModified": 1672350804,
|
|
||||||
"narHash": "sha256-jo6zkiCabUBn3ObuKXHGqqORUMH27gYDIFFfLq5P4wg=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "677ed08a50931e38382dbef01cba08a8f7eac8f6",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"dir": "lib",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs-regression": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1643052045,
|
|
||||||
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_2": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1672262501,
|
|
||||||
"narHash": "sha256-ZNXqX9lwYo1tOFAqrVtKTLcJ2QMKCr3WuIvpN8emp7I=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "e182da8622a354d44c39b3d7a542dc12cd7baa5f",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_3": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1677932085,
|
|
||||||
"narHash": "sha256-+AB4dYllWig8iO6vAiGGYl0NEgmMgGHpy9gzWJ3322g=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "3c5319ad3aa51551182ac82ea17ab1c6b0f0df89",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_4": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1690470004,
|
|
||||||
"narHash": "sha256-l57RmPhPz9r1LGDg/0v8bYgJO8R+GGTQZtkIxE7negU=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "9462344318b376e157c94fa60c20a25b913b2381",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-23.05",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_5": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1692447944,
|
|
||||||
"narHash": "sha256-fkJGNjEmTPvqBs215EQU4r9ivecV5Qge5cF/QDLVn3U=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "d680ded26da5cf104dd2735a51e88d2d8f487b4d",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_6": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1632846328,
|
|
||||||
"narHash": "sha256-sFi6YtlGK30TBB9o6CW7LG9mYHkgtKeWbSLAjjrNTX0=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "2b71ddd869ad592510553d09fe89c9709fa26b2b",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"id": "nixpkgs",
|
|
||||||
"type": "indirect"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_7": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1692557222,
|
|
||||||
"narHash": "sha256-TCOtZaioLf/jTEgfa+nyg0Nwq5Uc610Z+OFV75yUgGw=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "0b07d4957ee1bd7fd3bdfd12db5f361bd70175a6",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"id": "nixpkgs",
|
|
||||||
"type": "indirect"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_8": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1632846328,
|
|
||||||
"narHash": "sha256-sFi6YtlGK30TBB9o6CW7LG9mYHkgtKeWbSLAjjrNTX0=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "2b71ddd869ad592510553d09fe89c9709fa26b2b",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"id": "nixpkgs",
|
|
||||||
"type": "indirect"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_9": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1692557222,
|
|
||||||
"narHash": "sha256-TCOtZaioLf/jTEgfa+nyg0Nwq5Uc610Z+OFV75yUgGw=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "0b07d4957ee1bd7fd3bdfd12db5f361bd70175a6",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"id": "nixpkgs",
|
|
||||||
"type": "indirect"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notifications-tray-icon": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": [
|
|
||||||
"flake-utils"
|
|
||||||
],
|
|
||||||
"git-ignore-nix": [
|
|
||||||
"git-ignore-nix"
|
|
||||||
],
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1688066969,
|
|
||||||
"narHash": "sha256-h0ENXHgNMUgjD14ceNPWeNU6+cDR+6itQpfobf/CVUA=",
|
|
||||||
"owner": "IvanMalison",
|
|
||||||
"repo": "notifications-tray-icon",
|
|
||||||
"rev": "e3bae70029b7b4be8385ceccd89ad67c334071c2",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "IvanMalison",
|
|
||||||
"repo": "notifications-tray-icon",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pre-commit-hooks-nix": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": "flake-utils_2",
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixified-ai",
|
|
||||||
"hercules-ci-effects",
|
|
||||||
"hercules-ci-agent",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1667760143,
|
|
||||||
"narHash": "sha256-+X5CyeNEKp41bY/I1AJgW/fn69q5cLJ1bgiaMMCKB3M=",
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "pre-commit-hooks.nix",
|
|
||||||
"rev": "06f48d63d473516ce5b8abe70d15be96a0147fcd",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "cachix",
|
|
||||||
"repo": "pre-commit-hooks.nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": "flake-utils",
|
|
||||||
"git-ignore-nix": "git-ignore-nix",
|
|
||||||
"home-manager": "home-manager",
|
|
||||||
"nix": "nix",
|
|
||||||
"nixified-ai": "nixified-ai",
|
|
||||||
"nixos-hardware": "nixos-hardware",
|
|
||||||
"nixos-wsl": "nixos-wsl",
|
|
||||||
"nixpkgs": "nixpkgs_5",
|
|
||||||
"notifications-tray-icon": "notifications-tray-icon",
|
|
||||||
"systems": "systems_2",
|
|
||||||
"taffybar": "taffybar",
|
|
||||||
"xmonad": "xmonad",
|
|
||||||
"xmonad-contrib": "xmonad-contrib"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"status-notifier-item": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": [
|
|
||||||
"taffybar",
|
|
||||||
"flake-utils"
|
|
||||||
],
|
|
||||||
"git-ignore-nix": [
|
|
||||||
"taffybar",
|
|
||||||
"git-ignore-nix"
|
|
||||||
],
|
|
||||||
"nixpkgs": [
|
|
||||||
"taffybar",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1770953113,
|
|
||||||
"narHash": "sha256-E9HHKMMZStzKeXqKLPh32fA1q0aOrHg+v+gBw3dNwR4=",
|
|
||||||
"ref": "refs/heads/master",
|
|
||||||
"rev": "d62b44beb1b189bf4a97b7f632b2cb41d3addacb",
|
|
||||||
"revCount": 117,
|
|
||||||
"type": "git",
|
|
||||||
"url": "file:///home/imalison/Projects/status-notifier-item"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "taffybar",
|
|
||||||
"repo": "status-notifier-item",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"systems_3": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681028828,
|
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"systems_4": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681028828,
|
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"taffybar": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": [
|
|
||||||
"flake-utils"
|
|
||||||
],
|
|
||||||
"git-ignore-nix": [
|
|
||||||
"git-ignore-nix"
|
|
||||||
],
|
|
||||||
"gtk-sni-tray": "gtk-sni-tray",
|
|
||||||
"gtk-strut": "gtk-strut",
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
],
|
|
||||||
"status-notifier-item": "status-notifier-item",
|
|
||||||
"xmonad": [
|
|
||||||
"xmonad"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1690672871,
|
|
||||||
"narHash": "sha256-BlSP4JJ1pYvGtiuvYh7royLWoyC9xts6WS28c4KeIgQ=",
|
|
||||||
"owner": "taffybar",
|
|
||||||
"repo": "taffybar",
|
|
||||||
"rev": "175f0ee5c8c599cb72332c42516ef59ed6189e66",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "taffybar",
|
|
||||||
"repo": "taffybar",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"unstable": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1692447944,
|
|
||||||
"narHash": "sha256-fkJGNjEmTPvqBs215EQU4r9ivecV5Qge5cF/QDLVn3U=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "d680ded26da5cf104dd2735a51e88d2d8f487b4d",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"unstable_2": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1692447944,
|
|
||||||
"narHash": "sha256-fkJGNjEmTPvqBs215EQU4r9ivecV5Qge5cF/QDLVn3U=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "d680ded26da5cf104dd2735a51e88d2d8f487b4d",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"xmonad": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": [
|
|
||||||
"flake-utils"
|
|
||||||
],
|
|
||||||
"git-ignore-nix": [
|
|
||||||
"git-ignore-nix"
|
|
||||||
],
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
],
|
|
||||||
"unstable": "unstable"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1691842937,
|
|
||||||
"narHash": "sha256-dOrvPpypuNn/fAWY2XjMacpsAXEiMZ4Dll3Ot81iQL4=",
|
|
||||||
"owner": "xmonad",
|
|
||||||
"repo": "xmonad",
|
|
||||||
"rev": "5c2ba069026666998a8932832bc8f3fce24f42e9",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "xmonad",
|
|
||||||
"repo": "xmonad",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"xmonad-contrib": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": "flake-utils_4",
|
|
||||||
"git-ignore-nix": "git-ignore-nix_2",
|
|
||||||
"nixpkgs": "nixpkgs_7",
|
|
||||||
"xmonad": "xmonad_2"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1691842946,
|
|
||||||
"narHash": "sha256-XEZ+Z/23ZueKygLgg/ps4KD9lgiBSxh7/WygqAbZsq0=",
|
|
||||||
"owner": "xmonad",
|
|
||||||
"repo": "xmonad-contrib",
|
|
||||||
"rev": "2df26cf9f8d93d3b3fc2b1ac853d31280e9fa916",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "xmonad",
|
|
||||||
"repo": "xmonad-contrib",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"xmonad_2": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": "flake-utils_5",
|
|
||||||
"git-ignore-nix": "git-ignore-nix_3",
|
|
||||||
"nixpkgs": "nixpkgs_9",
|
|
||||||
"unstable": "unstable_2"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1691842937,
|
|
||||||
"narHash": "sha256-dOrvPpypuNn/fAWY2XjMacpsAXEiMZ4Dll3Ot81iQL4=",
|
|
||||||
"owner": "xmonad",
|
|
||||||
"repo": "xmonad",
|
|
||||||
"rev": "5c2ba069026666998a8932832bc8f3fce24f42e9",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "xmonad",
|
|
||||||
"repo": "xmonad",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": "root",
|
|
||||||
"version": 7
|
|
||||||
}
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
{
|
|
||||||
inputs = {
|
|
||||||
nixos-hardware = {url = github:NixOS/nixos-hardware;};
|
|
||||||
|
|
||||||
nixpkgs = {url = github:NixOS/nixpkgs/nixos-unstable;};
|
|
||||||
|
|
||||||
home-manager = {
|
|
||||||
url = github:nix-community/home-manager;
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
};
|
|
||||||
|
|
||||||
nix = {
|
|
||||||
url = github:IvanMalison/nix/my2.15.1;
|
|
||||||
};
|
|
||||||
|
|
||||||
flake-utils = {
|
|
||||||
url = github:numtide/flake-utils;
|
|
||||||
inputs.systems.follows = "systems";
|
|
||||||
};
|
|
||||||
|
|
||||||
systems = {url = github:nix-systems/default;};
|
|
||||||
|
|
||||||
git-ignore-nix = {
|
|
||||||
url = github:hercules-ci/gitignore.nix;
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
};
|
|
||||||
nixos-wsl = {url = github:nix-community/NixOS-WSL;};
|
|
||||||
|
|
||||||
taffybar = {
|
|
||||||
url = "github:taffybar/taffybar";
|
|
||||||
inputs = {
|
|
||||||
nixpkgs.follows = "nixpkgs";
|
|
||||||
flake-utils.follows = "flake-utils";
|
|
||||||
git-ignore-nix.follows = "git-ignore-nix";
|
|
||||||
xmonad.follows = "xmonad";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
xmonad = {
|
|
||||||
url = "github:xmonad/xmonad";
|
|
||||||
inputs = {
|
|
||||||
nixpkgs.follows = "nixpkgs";
|
|
||||||
flake-utils.follows = "flake-utils";
|
|
||||||
git-ignore-nix.follows = "git-ignore-nix";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
xmonad-contrib = {
|
|
||||||
url = "github:xmonad/xmonad-contrib";
|
|
||||||
};
|
|
||||||
|
|
||||||
notifications-tray-icon = {
|
|
||||||
url = "github:IvanMalison/notifications-tray-icon";
|
|
||||||
inputs.flake-utils.follows = "flake-utils";
|
|
||||||
inputs.git-ignore-nix.follows = "git-ignore-nix";
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
};
|
|
||||||
|
|
||||||
nixified-ai = {url = "github:nixified-ai/flake";};
|
|
||||||
};
|
|
||||||
|
|
||||||
outputs = inputs @ {
|
|
||||||
self,
|
|
||||||
nixpkgs,
|
|
||||||
nixos-hardware,
|
|
||||||
home-manager,
|
|
||||||
nix,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
machinesPath = ../machines;
|
|
||||||
machineFilenames = builtins.attrNames (builtins.readDir machinesPath);
|
|
||||||
machineNameFromFilename = filename: builtins.head (builtins.split "\\." filename);
|
|
||||||
machineNames = map machineNameFromFilename machineFilenames;
|
|
||||||
mkConfigurationParams = filename: {
|
|
||||||
name = machineNameFromFilename filename;
|
|
||||||
value = {
|
|
||||||
modules = [(machinesPath + ("/" + filename))];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
defaultConfigurationParams =
|
|
||||||
builtins.listToAttrs (map mkConfigurationParams machineFilenames);
|
|
||||||
customParams = {
|
|
||||||
biskcomp = {
|
|
||||||
system = "aarch64-linux";
|
|
||||||
};
|
|
||||||
air-gapped-pi = {
|
|
||||||
system = "aarch64-linux";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
mkConfig = args @ {
|
|
||||||
system ? "x86_64-linux",
|
|
||||||
baseModules ? [],
|
|
||||||
modules ? [],
|
|
||||||
specialArgs ? {},
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
nixpkgs.lib.nixosSystem (args
|
|
||||||
// {
|
|
||||||
inherit system;
|
|
||||||
modules = baseModules ++ modules;
|
|
||||||
specialArgs =
|
|
||||||
rec {
|
|
||||||
inherit inputs machineNames;
|
|
||||||
makeEnable = (import ../make-enable.nix) nixpkgs.lib;
|
|
||||||
realUsers = ["root" "imalison" "kat" "dean" "alex" "ben"];
|
|
||||||
}
|
|
||||||
// specialArgs // (import ../keys.nix);
|
|
||||||
});
|
|
||||||
in {
|
|
||||||
nixosConfigurations =
|
|
||||||
builtins.mapAttrs (
|
|
||||||
machineName: params: let
|
|
||||||
machineParams =
|
|
||||||
if builtins.hasAttr machineName customParams
|
|
||||||
then (builtins.getAttr machineName customParams)
|
|
||||||
else {};
|
|
||||||
in
|
|
||||||
mkConfig (params // machineParams)
|
|
||||||
)
|
|
||||||
defaultConfigurationParams;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -72,6 +72,12 @@ in
|
|||||||
recursive = true;
|
recursive = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
home.file."chrome-favicon-dbus-extension" = {
|
||||||
|
source = extensionSource;
|
||||||
|
recursive = true;
|
||||||
|
force = true;
|
||||||
|
};
|
||||||
|
|
||||||
xdg.configFile."google-chrome/External Extensions/${extensionId}.json".text = builtins.toJSON {
|
xdg.configFile."google-chrome/External Extensions/${extensionId}.json".text = builtins.toJSON {
|
||||||
external_crx = "${extensionPackage}/chrome-favicon-dbus.crx";
|
external_crx = "${extensionPackage}/chrome-favicon-dbus.crx";
|
||||||
external_version = extensionVersion;
|
external_version = extensionVersion;
|
||||||
|
|||||||
58
nixos/claude-mcp.nix
Normal file
58
nixos/claude-mcp.nix
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
makeEnable,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
# The MCP-NixOS server (https://mcp-nixos.io) — gives Claude accurate NixOS
|
||||||
|
# package/option/Home-Manager/flake search instead of hallucinated names.
|
||||||
|
# Pinned by Nix from nixpkgs, so no runtime `uvx`/`nix run` fetch is needed.
|
||||||
|
mcpNixosBin = "${pkgs.mcp-nixos}/bin/mcp-nixos";
|
||||||
|
|
||||||
|
# Claude Code reads MCP server *definitions* from the top-level `mcpServers`
|
||||||
|
# key of ~/.claude.json (the user scope). That is the only scope that applies
|
||||||
|
# to every project without an approval prompt while remaining additive:
|
||||||
|
# - settings.json (our nix-managed dotfiles file) cannot define servers,
|
||||||
|
# only filter them (enabled/disabledMcpjsonServers).
|
||||||
|
# - /etc/claude-code/managed-mcp.json would take *exclusive* control and
|
||||||
|
# disable every other server (per-project playwright, future `mcp add`).
|
||||||
|
# So we merge into the user config rather than owning a whole file.
|
||||||
|
serverJson = builtins.toJSON {
|
||||||
|
type = "stdio";
|
||||||
|
command = mcpNixosBin;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
makeEnable config "myModules.claudeMcpNixos" true {
|
||||||
|
# Also expose the pinned binary on PATH for manual `claude mcp` use / Codex.
|
||||||
|
environment.systemPackages = [pkgs.mcp-nixos];
|
||||||
|
|
||||||
|
# Use a module function so `lib` here is home-manager's lib (which carries
|
||||||
|
# `lib.hm.dag`), not the plain NixOS lib.
|
||||||
|
home-manager.users.imalison = {lib, ...}: {
|
||||||
|
# ~/.claude.json is mutable state owned by Claude Code, so it can't be
|
||||||
|
# managed as a whole file. Instead idempotently merge our server into it
|
||||||
|
# on every switch with jq, preserving all other (per-project, user-added)
|
||||||
|
# servers and state. This module is the declarative source of truth:
|
||||||
|
# `claude mcp remove nixos` is re-applied on the next switch.
|
||||||
|
home.activation.registerMcpNixos = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
||||||
|
config="$HOME/.claude.json"
|
||||||
|
server=${lib.escapeShellArg serverJson}
|
||||||
|
if [ -f "$config" ]; then
|
||||||
|
tmp="$(mktemp)"
|
||||||
|
if ${pkgs.jq}/bin/jq --argjson srv "$server" \
|
||||||
|
'.mcpServers = ((.mcpServers // {}) + {nixos: $srv})' \
|
||||||
|
"$config" > "$tmp"; then
|
||||||
|
mv -f "$tmp" "$config"
|
||||||
|
else
|
||||||
|
rm -f "$tmp"
|
||||||
|
echo "claude-mcp: failed to update $config; left unchanged" >&2
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
${pkgs.jq}/bin/jq -n --argjson srv "$server" \
|
||||||
|
'{mcpServers: {nixos: $srv}}' > "$config"
|
||||||
|
chmod 600 "$config"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
64
nixos/claude-remote-control.nix
Normal file
64
nixos/claude-remote-control.nix
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
makeEnable,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
# Working directory the always-on session is pinned to. Ad-hoc sessions in
|
||||||
|
# other directories are handled by the `tmclaude` shell function instead.
|
||||||
|
workingDirectory = "/srv/dotfiles";
|
||||||
|
|
||||||
|
# Dedicated tmux socket + session name so the service owns its own tmux
|
||||||
|
# server (independent of the interactive one). Attach locally with:
|
||||||
|
# tmux -L claude-rc attach -t claude-rc
|
||||||
|
socket = "claude-rc";
|
||||||
|
sessionName = "claude-rc";
|
||||||
|
|
||||||
|
# Name the session registers under for native Remote Control (phone/web).
|
||||||
|
remoteName = config.networking.hostName;
|
||||||
|
|
||||||
|
# claude shells out to these for its tools; give the service a clean PATH.
|
||||||
|
servicePath = lib.makeBinPath (with pkgs; [
|
||||||
|
claude-code
|
||||||
|
tmux
|
||||||
|
bashInteractive
|
||||||
|
coreutils
|
||||||
|
findutils
|
||||||
|
git
|
||||||
|
gnugrep
|
||||||
|
gnused
|
||||||
|
nix
|
||||||
|
nodejs
|
||||||
|
openssh
|
||||||
|
ripgrep
|
||||||
|
zsh
|
||||||
|
]);
|
||||||
|
in
|
||||||
|
makeEnable config "myModules.claudeRemoteControl" false {
|
||||||
|
home-manager.users.imalison = {
|
||||||
|
systemd.user.services.claude-remote-control = {
|
||||||
|
Unit = {
|
||||||
|
Description = "Claude Code remote-control session";
|
||||||
|
After = ["network.target"];
|
||||||
|
};
|
||||||
|
Service = {
|
||||||
|
# tmux new-session -d daemonizes the server and returns.
|
||||||
|
Type = "forking";
|
||||||
|
Environment = ["PATH=${servicePath}"];
|
||||||
|
ExecStart = lib.concatStringsSep " " [
|
||||||
|
"${pkgs.tmux}/bin/tmux -L ${socket} new-session -d"
|
||||||
|
"-s ${sessionName} -c ${workingDirectory}"
|
||||||
|
"${pkgs.claude-code}/bin/claude --remote-control ${remoteName} --dangerously-skip-permissions"
|
||||||
|
];
|
||||||
|
ExecStop = "${pkgs.tmux}/bin/tmux -L ${socket} kill-server";
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = 5;
|
||||||
|
};
|
||||||
|
Install.WantedBy = ["default.target"];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Convenience: attach to the always-on session from any directory.
|
||||||
|
home.shellAliases.claude-rc-attach = "tmux -L ${socket} attach -t ${sessionName}";
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -7,8 +7,35 @@
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
codexDesktop =
|
codexDesktopLinuxSource = pkgs.applyPatches {
|
||||||
inputs.codex-desktop-linux.packages.${pkgs.stdenv.hostPlatform.system}."codex-desktop-computer-use-ui-remote-mobile-control";
|
name = "codex-desktop-linux-patched";
|
||||||
|
src = inputs.codex-desktop-linux;
|
||||||
|
patches = [ ./patches/codex-desktop-linux-gsettings-schemas.patch ];
|
||||||
|
};
|
||||||
|
claudeDesktopSource = inputs.claude-desktop;
|
||||||
|
claudeDesktopNodePty = pkgs.callPackage "${claudeDesktopSource}/nix/node-pty.nix" {};
|
||||||
|
claudeDesktop = pkgs.callPackage "${claudeDesktopSource}/nix/claude-desktop.nix" {
|
||||||
|
node-pty = claudeDesktopNodePty;
|
||||||
|
};
|
||||||
|
claudeDesktopFhs = pkgs.callPackage "${claudeDesktopSource}/nix/fhs.nix" {
|
||||||
|
claude-desktop = claudeDesktop;
|
||||||
|
};
|
||||||
|
codexDesktopLinux =
|
||||||
|
let
|
||||||
|
flake = import "${codexDesktopLinuxSource}/flake.nix";
|
||||||
|
self' =
|
||||||
|
(flake.outputs {
|
||||||
|
self = self';
|
||||||
|
nixpkgs = inputs.nixpkgs;
|
||||||
|
flake-utils = inputs.flake-utils;
|
||||||
|
})
|
||||||
|
// {
|
||||||
|
outPath = "${codexDesktopLinuxSource}";
|
||||||
|
rev = inputs.codex-desktop-linux.rev or "";
|
||||||
|
lastModified = inputs.codex-desktop-linux.lastModified or 1;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
self';
|
||||||
in
|
in
|
||||||
makeEnable config "myModules.code" true {
|
makeEnable config "myModules.code" true {
|
||||||
programs.direnv = {
|
programs.direnv = {
|
||||||
@@ -24,6 +51,7 @@ makeEnable config "myModules.code" true {
|
|||||||
};
|
};
|
||||||
|
|
||||||
home-manager.sharedModules = lib.mkIf config.myModules.desktop.enable [
|
home-manager.sharedModules = lib.mkIf config.myModules.desktop.enable [
|
||||||
|
codexDesktopLinux.homeManagerModules.default
|
||||||
{
|
{
|
||||||
home.sessionVariables.YDOTOOL_SOCKET = "/run/ydotoold/socket";
|
home.sessionVariables.YDOTOOL_SOCKET = "/run/ydotoold/socket";
|
||||||
systemd.user.sessionVariables.YDOTOOL_SOCKET = "/run/ydotoold/socket";
|
systemd.user.sessionVariables.YDOTOOL_SOCKET = "/run/ydotoold/socket";
|
||||||
@@ -40,6 +68,16 @@ makeEnable config "myModules.code" true {
|
|||||||
programs.codex = {
|
programs.codex = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = pkgs.codex;
|
package = pkgs.codex;
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.codexDesktopLinux = {
|
||||||
|
enable = true;
|
||||||
|
# Bake CODEX_CLI_PATH into the launcher so Codex Desktop always finds this
|
||||||
|
# CLI, regardless of how it is started (GUI autostart, app launcher,
|
||||||
|
# terminal, or warm-start handoff) and without needing a re-login.
|
||||||
|
cliPackage = pkgs.codex;
|
||||||
|
computerUseUi.enable = true;
|
||||||
|
remoteMobileControl.enable = true;
|
||||||
remoteControl = {
|
remoteControl = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = pkgs.codex;
|
package = pkgs.codex;
|
||||||
@@ -51,7 +89,10 @@ makeEnable config "myModules.code" true {
|
|||||||
gnugrep
|
gnugrep
|
||||||
gnused
|
gnused
|
||||||
nix
|
nix
|
||||||
|
nodejs
|
||||||
openssh
|
openssh
|
||||||
|
ripgrep
|
||||||
|
zsh
|
||||||
];
|
];
|
||||||
listen = "unix://";
|
listen = "unix://";
|
||||||
};
|
};
|
||||||
@@ -61,12 +102,11 @@ makeEnable config "myModules.code" true {
|
|||||||
environment.systemPackages = with pkgs;
|
environment.systemPackages = with pkgs;
|
||||||
[
|
[
|
||||||
# LLM Tools
|
# LLM Tools
|
||||||
antigravity
|
# antigravity
|
||||||
claude-code
|
claude-code
|
||||||
|
claudeDesktopFhs
|
||||||
codex
|
codex
|
||||||
codexDesktop
|
|
||||||
gemini-cli
|
gemini-cli
|
||||||
happy-coder
|
|
||||||
opencode
|
opencode
|
||||||
t3code
|
t3code
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
./cache-server.nix
|
./cache-server.nix
|
||||||
./cache.nix
|
./cache.nix
|
||||||
./chrome-favicon-dbus.nix
|
./chrome-favicon-dbus.nix
|
||||||
|
./claude-mcp.nix
|
||||||
|
./claude-remote-control.nix
|
||||||
./code.nix
|
./code.nix
|
||||||
./cua.nix
|
./cua.nix
|
||||||
./desktop.nix
|
./desktop.nix
|
||||||
@@ -67,6 +69,10 @@
|
|||||||
{
|
{
|
||||||
system.autoUpgrade.flake = "github:colonelpanic8/dotfiles?dir=nixos#${config.networking.hostName}";
|
system.autoUpgrade.flake = "github:colonelpanic8/dotfiles?dir=nixos#${config.networking.hostName}";
|
||||||
}
|
}
|
||||||
|
(lib.mkIf config.services.rumno.enable {
|
||||||
|
# Do not let rumno's forking/PIDFile startup gate the whole graphical session.
|
||||||
|
systemd.user.services.rumno.unitConfig.After = lib.mkForce ["graphical-session.target"];
|
||||||
|
})
|
||||||
(lib.mkIf config.features.full.enable {
|
(lib.mkIf config.features.full.enable {
|
||||||
myModules.base.enable = true;
|
myModules.base.enable = true;
|
||||||
myModules.desktop.enable = true;
|
myModules.desktop.enable = true;
|
||||||
|
|||||||
@@ -18,25 +18,170 @@
|
|||||||
exec ${../dotfiles/lib/bin/desktop_shell_ui} "$@"
|
exec ${../dotfiles/lib/bin/desktop_shell_ui} "$@"
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
googleChrome = pkgs.symlinkJoin {
|
chromeCommandLineFlags =
|
||||||
name = "google-chrome-wayland-fractional-scale-workaround";
|
[
|
||||||
paths = [pkgs.google-chrome];
|
"--disable-features=WaylandFractionalScaleV1"
|
||||||
nativeBuildInputs = [pkgs.makeWrapper];
|
]
|
||||||
postBuild = ''
|
++ lib.optionals config.myModules.chrome-favicon-dbus.enable [
|
||||||
wrapProgram "$out/bin/google-chrome-stable" \
|
"--load-extension=${inputs.chrome-favicon-dbus}/extension"
|
||||||
--add-flags "--disable-features=WaylandFractionalScaleV1"
|
];
|
||||||
|
googleChromeWrapperArgs = lib.concatMapStringsSep " " (flag: "--add-flags ${lib.escapeShellArg flag}") chromeCommandLineFlags;
|
||||||
|
googleChromeCommandWrappers = pkgs.runCommand "google-chrome-command-wrappers" {nativeBuildInputs = [pkgs.makeWrapper];} ''
|
||||||
|
mkdir -p "$out/bin"
|
||||||
|
makeWrapper ${pkgs.google-chrome}/bin/google-chrome "$out/bin/google-chrome" \
|
||||||
|
${googleChromeWrapperArgs}
|
||||||
|
makeWrapper ${pkgs.google-chrome}/bin/google-chrome-stable "$out/bin/google-chrome-stable" \
|
||||||
|
${googleChromeWrapperArgs}
|
||||||
|
'';
|
||||||
|
googleChromeProfileWindow = pkgs.writeShellApplication {
|
||||||
|
name = "google-chrome-profile-window";
|
||||||
|
runtimeInputs = [
|
||||||
|
googleChromeCommandWrappers
|
||||||
|
pkgs.gawk
|
||||||
|
pkgs.jq
|
||||||
|
pkgs.rofi
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
if [ "$#" -gt 0 ]; then
|
||||||
|
exec google-chrome-stable "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
desktop_file="$out/share/applications/google-chrome.desktop"
|
local_state="''${CHROME_USER_DATA_DIR:-$HOME/.config/google-chrome}/Local State"
|
||||||
rm "$desktop_file"
|
|
||||||
cp "${pkgs.google-chrome}/share/applications/google-chrome.desktop" "$desktop_file"
|
|
||||||
chmod u+w "$desktop_file"
|
|
||||||
|
|
||||||
substituteInPlace "$desktop_file" \
|
if [ ! -r "$local_state" ]; then
|
||||||
--replace-fail \
|
exec google-chrome-stable --new-window
|
||||||
"Exec=${pkgs.google-chrome}/bin/google-chrome-stable" \
|
fi
|
||||||
"Exec=$out/bin/google-chrome-stable"
|
|
||||||
|
profiles="$(
|
||||||
|
jq -r '
|
||||||
|
(.profile.info_cache // {})
|
||||||
|
| to_entries
|
||||||
|
| sort_by(if .key == "Default" then 0 else 1 end, -(.value.active_time // 0))[]
|
||||||
|
| [.value.name, .value.user_name, .key]
|
||||||
|
| @tsv
|
||||||
|
' "$local_state" \
|
||||||
|
| awk -F '\t' '{
|
||||||
|
label = $1
|
||||||
|
if ($2 != "") {
|
||||||
|
label = label " <" $2 ">"
|
||||||
|
}
|
||||||
|
print label "\t" $3
|
||||||
|
}'
|
||||||
|
)"
|
||||||
|
|
||||||
|
if [ -z "$profiles" ]; then
|
||||||
|
exec google-chrome-stable --new-window
|
||||||
|
fi
|
||||||
|
|
||||||
|
selection="$(printf '%s\n' "$profiles" | rofi -dmenu -i -p 'Chrome profile' || true)"
|
||||||
|
if [ -z "$selection" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
profile_dir="$(printf '%s\n' "$selection" | awk -F '\t' '{print $NF}')"
|
||||||
|
if [ -z "$profile_dir" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec google-chrome-stable --profile-directory="$profile_dir" --new-window
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
xComPwa = pkgs.writeShellApplication {
|
||||||
|
name = "x-com-pwa";
|
||||||
|
runtimeInputs = [
|
||||||
|
googleChromeCommandWrappers
|
||||||
|
pkgs.jq
|
||||||
|
];
|
||||||
|
text = ''
|
||||||
|
profile_args=()
|
||||||
|
local_state="''${CHROME_USER_DATA_DIR:-$HOME/.config/google-chrome}/Local State"
|
||||||
|
|
||||||
|
if [ -r "$local_state" ]; then
|
||||||
|
profile_dir="$(
|
||||||
|
jq -r '
|
||||||
|
(.profile.info_cache // {})
|
||||||
|
| to_entries
|
||||||
|
| sort_by(if .key == "Default" then 0 else 1 end, -(.value.active_time // 0))
|
||||||
|
| .[0].key // empty
|
||||||
|
' "$local_state" 2>/dev/null || true
|
||||||
|
)"
|
||||||
|
|
||||||
|
if [ -n "$profile_dir" ]; then
|
||||||
|
profile_args+=(--profile-directory="$profile_dir")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec google-chrome-stable "''${profile_args[@]}" --class=x-com-pwa --app=https://x.com/
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
googleChromeDesktopEntries = pkgs.runCommand "google-chrome-desktop-entries" {nativeBuildInputs = [pkgs.gnused];} ''
|
||||||
|
mkdir -p "$out/share/applications"
|
||||||
|
|
||||||
|
for desktop_name in google-chrome.desktop com.google.Chrome.desktop; do
|
||||||
|
source_file="${pkgs.google-chrome}/share/applications/$desktop_name"
|
||||||
|
if [ -f "$source_file" ]; then
|
||||||
|
desktop_file="$out/share/applications/$desktop_name"
|
||||||
|
cp "$source_file" "$desktop_file"
|
||||||
|
chmod u+w "$desktop_file"
|
||||||
|
|
||||||
|
substituteInPlace "$desktop_file" \
|
||||||
|
--replace-fail "${pkgs.google-chrome}/bin/google-chrome-stable" "google-chrome-stable"
|
||||||
|
|
||||||
|
${pkgs.gnused}/bin/sed -i \
|
||||||
|
-e 's,application/pdf;,,g' \
|
||||||
|
-e 's,image/gif;,,g' \
|
||||||
|
-e 's,image/jpeg;,,g' \
|
||||||
|
-e 's,image/png;,,g' \
|
||||||
|
-e 's,image/webp;,,g' \
|
||||||
|
"$desktop_file"
|
||||||
|
|
||||||
|
${pkgs.gnused}/bin/sed -i \
|
||||||
|
-e 's#^Exec=.*google-chrome-stable *%U$#Exec=google-chrome-profile-window %U#' \
|
||||||
|
-e '/^\[Desktop Action new-window\]/,/^\[Desktop Action / s#^Exec=.*google-chrome-stable.*$#Exec=google-chrome-profile-window#' \
|
||||||
|
"$desktop_file"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
spotifyWaylandFlags = [
|
||||||
|
"--enable-features=UseOzonePlatform,WaylandWindowDecorations"
|
||||||
|
"--ozone-platform=wayland"
|
||||||
|
"--enable-wayland-ime=true"
|
||||||
|
];
|
||||||
|
spotifyWaylandWrapperArgs = lib.concatMapStringsSep " " (flag: "--add-flags ${lib.escapeShellArg flag}") spotifyWaylandFlags;
|
||||||
|
spotifyWaylandPatch = lib.hiPrio (pkgs.runCommand "${pkgs.spotify.name}-wayland-patch" {
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pkgs.gnused
|
||||||
|
pkgs.makeWrapper
|
||||||
|
];
|
||||||
|
} ''
|
||||||
|
mkdir -p "$out/bin" "$out/share/applications"
|
||||||
|
|
||||||
|
makeWrapper ${pkgs.spotify}/bin/spotify "$out/bin/spotify" \
|
||||||
|
--unset NIXOS_OZONE_WL \
|
||||||
|
${spotifyWaylandWrapperArgs}
|
||||||
|
|
||||||
|
cp ${pkgs.spotify}/share/applications/spotify.desktop "$out/share/applications/spotify.desktop"
|
||||||
|
chmod u+w "$out/share/applications/spotify.desktop"
|
||||||
|
|
||||||
|
${pkgs.gnused}/bin/sed -i \
|
||||||
|
-e "s#^TryExec=.*spotify\$#TryExec=$out/bin/spotify#" \
|
||||||
|
-e "s#^Exec=.*spotify\\( .*\\)\\?\$#Exec=$out/bin/spotify\\1#" \
|
||||||
|
"$out/share/applications/spotify.desktop"
|
||||||
|
'');
|
||||||
|
rlruPackages = inputs.rlru.packages.${pkgs.stdenv.hostPlatform.system};
|
||||||
|
rlruDioxusDesktopBase = rlruPackages.rlru-dioxus-desktop.overrideAttrs (_: {
|
||||||
|
# Rust 1.95 can otherwise ICE/SEGV while compiling rlru's desktop dependency
|
||||||
|
# graph in release mode.
|
||||||
|
RUST_MIN_STACK = "2147483648";
|
||||||
|
});
|
||||||
|
rlruDioxusDesktop = pkgs.symlinkJoin {
|
||||||
|
name = "${rlruDioxusDesktopBase.name}-single-desktop-entry";
|
||||||
|
paths = [rlruDioxusDesktopBase];
|
||||||
|
postBuild = ''
|
||||||
|
rm -f "$out/share/applications/rlru-dioxus.desktop"
|
||||||
|
'';
|
||||||
|
meta = rlruDioxusDesktopBase.meta;
|
||||||
|
};
|
||||||
enabledModule = makeEnable config "myModules.desktop" true {
|
enabledModule = makeEnable config "myModules.desktop" true {
|
||||||
services.greenclip.enable = true;
|
services.greenclip.enable = true;
|
||||||
imports = [
|
imports = [
|
||||||
@@ -66,19 +211,35 @@
|
|||||||
environment.sessionVariables = {
|
environment.sessionVariables = {
|
||||||
# This is for the benefit of VSCODE running natively in wayland
|
# This is for the benefit of VSCODE running natively in wayland
|
||||||
NIXOS_OZONE_WL = "1";
|
NIXOS_OZONE_WL = "1";
|
||||||
|
# Claude Desktop's launcher (claude-desktop-debian flake) ignores
|
||||||
|
# NIXOS_OZONE_WL/ELECTRON_OZONE_PLATFORM_HINT and hardcodes
|
||||||
|
# --ozone-platform=x11 by default. This is the only knob it honors;
|
||||||
|
# it switches the launcher to native Wayland (loses global hotkeys).
|
||||||
|
CLAUDE_USE_WAYLAND = "1";
|
||||||
IM_HYPRLAND_SHELL_UI = cfg.shellUi;
|
IM_HYPRLAND_SHELL_UI = cfg.shellUi;
|
||||||
};
|
};
|
||||||
|
|
||||||
system.activationScripts.playwrightChromeCompat.text = lib.optionalString (pkgs.stdenv.hostPlatform.system == "x86_64-linux") ''
|
system.activationScripts.playwrightChromeCompat.text = lib.optionalString (pkgs.stdenv.hostPlatform.system == "x86_64-linux") ''
|
||||||
# Playwright's Chrome channel lookup expects the FHS path below.
|
# Playwright's Chrome channel lookup expects the FHS path below.
|
||||||
mkdir -p /opt/google/chrome
|
mkdir -p /opt/google/chrome
|
||||||
ln -sfn ${googleChrome}/bin/google-chrome-stable /opt/google/chrome/chrome
|
ln -sfn ${googleChromeCommandWrappers}/bin/google-chrome-stable /opt/google/chrome/chrome
|
||||||
'';
|
'';
|
||||||
|
|
||||||
services.gnome.at-spi2-core.enable = true;
|
services.gnome.at-spi2-core.enable = true;
|
||||||
|
|
||||||
services.gnome.gnome-keyring.enable = true;
|
services.gnome.gnome-keyring.enable = true;
|
||||||
|
|
||||||
|
home-manager.users.imalison = {
|
||||||
|
imports = [
|
||||||
|
inputs.rlru.homeManagerModules.default
|
||||||
|
];
|
||||||
|
|
||||||
|
services.rlru = {
|
||||||
|
enable = true;
|
||||||
|
package = rlruDioxusDesktop;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
home-manager.sharedModules = [
|
home-manager.sharedModules = [
|
||||||
{
|
{
|
||||||
imports = [./dunst.nix];
|
imports = [./dunst.nix];
|
||||||
@@ -109,6 +270,21 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
xdg.desktopEntries.x-com-pwa = {
|
||||||
|
name = "X";
|
||||||
|
genericName = "Social Network";
|
||||||
|
comment = "Open x.com in a dedicated Chrome app window";
|
||||||
|
icon = "google-chrome";
|
||||||
|
terminal = false;
|
||||||
|
type = "Application";
|
||||||
|
categories = ["Network"];
|
||||||
|
startupNotify = true;
|
||||||
|
exec = "${xComPwa}/bin/x-com-pwa";
|
||||||
|
settings = {
|
||||||
|
StartupWMClass = "x-com-pwa";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
xdg.configFile."ghostty/config" = {
|
xdg.configFile."ghostty/config" = {
|
||||||
force = true;
|
force = true;
|
||||||
text = ''
|
text = ''
|
||||||
@@ -182,7 +358,7 @@
|
|||||||
pinentry-gnome3
|
pinentry-gnome3
|
||||||
# mission-center
|
# mission-center
|
||||||
quassel
|
quassel
|
||||||
remmina
|
# remmina
|
||||||
rofi
|
rofi
|
||||||
wofi
|
wofi
|
||||||
rofi-pass
|
rofi-pass
|
||||||
@@ -212,13 +388,17 @@
|
|||||||
if pkgs.stdenv.hostPlatform.system == "x86_64-linux"
|
if pkgs.stdenv.hostPlatform.system == "x86_64-linux"
|
||||||
then
|
then
|
||||||
with pkgs; [
|
with pkgs; [
|
||||||
googleChrome
|
googleChromeCommandWrappers
|
||||||
|
googleChromeDesktopEntries
|
||||||
|
googleChromeProfileWindow
|
||||||
pommed_light
|
pommed_light
|
||||||
slack
|
slack
|
||||||
spicetify-cli
|
spicetify-cli
|
||||||
spotify
|
spotify
|
||||||
|
spotifyWaylandPatch
|
||||||
tor-browser
|
tor-browser
|
||||||
vscode
|
xComPwa
|
||||||
|
# vscode
|
||||||
zulip
|
zulip
|
||||||
]
|
]
|
||||||
else []
|
else []
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
|
nixos,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
# Replicate the useful part of rcm/rcup:
|
# Replicate the useful part of rcm/rcup:
|
||||||
# - dotfiles live in ~/dotfiles/dotfiles (no leading dots in the repo)
|
# - dotfiles live in <dotfiles-worktree>/dotfiles (no leading dots in the repo)
|
||||||
# - links in $HOME add a leading '.' to the first path component
|
# - links in $HOME add a leading '.' to the first path component
|
||||||
# - link files individually so unmanaged state can coexist (e.g. ~/.cabal/store)
|
# - link files individually so unmanaged state can coexist (e.g. ~/.cabal/store)
|
||||||
#
|
#
|
||||||
@@ -13,11 +14,15 @@
|
|||||||
oos = config.lib.file.mkOutOfStoreSymlink;
|
oos = config.lib.file.mkOutOfStoreSymlink;
|
||||||
|
|
||||||
# Where the checked-out repo lives at runtime (activation time).
|
# Where the checked-out repo lives at runtime (activation time).
|
||||||
worktreeDotfiles = "${config.home.homeDirectory}/dotfiles/dotfiles";
|
# Keep this outside individual home directories so links work for every
|
||||||
|
# managed user on a shared machine.
|
||||||
|
worktreeRoot = nixos.config.dotfiles-worktree or "/srv/dotfiles";
|
||||||
|
worktreeDotfiles = "${worktreeRoot}/dotfiles";
|
||||||
|
|
||||||
# Use the flake source for enumeration (pure), but point links at the worktree.
|
# Use the flake source for enumeration (pure), but point links at the worktree.
|
||||||
srcDotfiles = ../dotfiles;
|
srcDotfiles = ../dotfiles;
|
||||||
srcConfig = srcDotfiles + "/config";
|
srcConfig = srcDotfiles + "/config";
|
||||||
|
srcCodex = srcDotfiles + "/codex";
|
||||||
|
|
||||||
excludedTop = [
|
excludedTop = [
|
||||||
# Managed by nix-shared/home-manager/codex-generated-skills.nix so
|
# Managed by nix-shared/home-manager/codex-generated-skills.nix so
|
||||||
@@ -86,6 +91,11 @@ in {
|
|||||||
builtins.listToAttrs (map mkConfigDir configDirNames);
|
builtins.listToAttrs (map mkConfigDir configDirNames);
|
||||||
|
|
||||||
myModules.codexGeneratedSkills.enable = true;
|
myModules.codexGeneratedSkills.enable = true;
|
||||||
|
myModules.codexGeneratedSkills.sourceCodexDir = "${srcCodex}";
|
||||||
|
# Point the Codex module at the live worktree (e.g. /srv/dotfiles) like the
|
||||||
|
# links above, not its ~/dotfiles default. Without this, ~/.codex/AGENTS.md
|
||||||
|
# and ~/.codex/skills/* dangle when the checkout lives outside ~/dotfiles.
|
||||||
|
myModules.codexGeneratedSkills.worktreeCodexDir = "${worktreeDotfiles}/codex";
|
||||||
|
|
||||||
# Home Manager directory links for .emacs.d resolve through the store on this
|
# Home Manager directory links for .emacs.d resolve through the store on this
|
||||||
# machine, which breaks Elpaca's writable state under ~/.emacs.d/elpaca.
|
# machine, which breaks Elpaca's writable state under ~/.emacs.d/elpaca.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user