diff --git a/.beads/interactions.jsonl b/.beads/interactions.jsonl index 018b5eb..0109a82 100644 --- a/.beads/interactions.jsonl +++ b/.beads/interactions.jsonl @@ -19,3 +19,6 @@ {"id":"int-ec238d3e","kind":"field_change","created_at":"2026-08-09T18:53:14.795389276Z","actor":"Prad Nukala","issue_id":"chezmoi-21v","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Closed"}} {"id":"int-1e6b9af3","kind":"field_change","created_at":"2026-08-09T18:53:15.496566548Z","actor":"Prad Nukala","issue_id":"chezmoi-a2k","extra":{"field":"status","new_value":"in_progress","old_value":"open"}} {"id":"int-bcfce2e0","kind":"field_change","created_at":"2026-08-09T18:53:15.63271081Z","actor":"Prad Nukala","issue_id":"chezmoi-exq","extra":{"field":"status","new_value":"in_progress","old_value":"open"}} +{"id":"int-bca8b819","kind":"field_change","created_at":"2026-08-09T18:53:47.081117456Z","actor":"Prad Nukala","issue_id":"chezmoi-a2k","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}} +{"id":"int-35ca5bf4","kind":"field_change","created_at":"2026-08-09T18:53:47.230104215Z","actor":"Prad Nukala","issue_id":"chezmoi-exq","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Closed"}} +{"id":"int-e46b03b9","kind":"field_change","created_at":"2026-08-09T18:53:55.604366711Z","actor":"Prad Nukala","issue_id":"chezmoi-9sg","extra":{"field":"status","new_value":"in_progress","old_value":"open"}} diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 300160b..36a6bf1 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -3,13 +3,13 @@ {"_type":"issue","id":"chezmoi-rnv","title":"Inventory: disposition table for all dotstate synced paths","description":"Parse .dotstate-profiles.toml (Noctalia/Inir/Rogz/Vertical-Rogz_AppleStudio). Every synced path gets decision: universal / arch-gated / defer / drop / secret. Output table in MIGRATION-NOTES.md. Blocks all content.","status":"closed","priority":1,"issue_type":"task","owner":"prad@sonr.io","created_at":"2026-08-09T18:41:50Z","created_by":"Prad Nukala","updated_at":"2026-08-09T18:45:28Z","started_at":"2026-08-09T18:44:23Z","closed_at":"2026-08-09T18:45:28Z","close_reason":"Closed","dependency_count":0,"dependent_count":13,"comment_count":0} {"_type":"issue","id":"chezmoi-42m","title":"Validation: Arch fresh bring-up in container","description":"docker run archlinux: bootstrap one-liner, packages install, chezmoi doctor clean, niri validate, fish -n all files, nvim --headless +Lazy! sync, tmux -f cfg new -d; kill-server, gh extension list matches manifest. Plus live machine chezmoi diff ~ empty.","status":"open","priority":2,"issue_type":"task","owner":"prad@sonr.io","created_at":"2026-08-09T18:42:17Z","created_by":"Prad Nukala","updated_at":"2026-08-09T18:42:17Z","dependencies":[{"issue_id":"chezmoi-42m","depends_on_id":"chezmoi-21v","type":"blocks","created_at":"2026-08-09T14:42:58Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-42m","depends_on_id":"chezmoi-4sj","type":"blocks","created_at":"2026-08-09T14:42:58Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-42m","depends_on_id":"chezmoi-9sg","type":"blocks","created_at":"2026-08-09T14:42:59Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-42m","depends_on_id":"chezmoi-a2k","type":"blocks","created_at":"2026-08-09T14:42:59Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-42m","depends_on_id":"chezmoi-exq","type":"blocks","created_at":"2026-08-09T14:42:59Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-42m","depends_on_id":"chezmoi-fde","type":"blocks","created_at":"2026-08-09T14:42:59Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-42m","depends_on_id":"chezmoi-hou","type":"blocks","created_at":"2026-08-09T14:42:58Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-42m","depends_on_id":"chezmoi-iu2","type":"blocks","created_at":"2026-08-09T14:42:59Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-42m","depends_on_id":"chezmoi-sd9","type":"blocks","created_at":"2026-08-09T14:42:58Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-42m","depends_on_id":"chezmoi-utl","type":"blocks","created_at":"2026-08-09T14:42:58Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-42m","depends_on_id":"chezmoi-uw2","type":"blocks","created_at":"2026-08-09T14:42:57Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-42m","depends_on_id":"chezmoi-x7f","type":"blocks","created_at":"2026-08-09T14:42:58Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-42m","depends_on_id":"chezmoi-xi5","type":"blocks","created_at":"2026-08-09T14:42:58Z","created_by":"Prad Nukala","metadata":"{}"}],"dependency_count":13,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"chezmoi-5by","title":"Cutover: freeze dotstate for migrated paths","description":"After both validations: remove migrated paths from .dotstate-profiles.toml, tag dotstate pre-chezmoi-freeze, stop Dolt sync for those paths. Archive, never delete.","status":"open","priority":2,"issue_type":"task","owner":"prad@sonr.io","created_at":"2026-08-09T18:42:17Z","created_by":"Prad Nukala","updated_at":"2026-08-09T18:42:17Z","dependencies":[{"issue_id":"chezmoi-5by","depends_on_id":"chezmoi-42m","type":"blocks","created_at":"2026-08-09T14:42:25Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-5by","depends_on_id":"chezmoi-udp","type":"blocks","created_at":"2026-08-09T14:42:25Z","created_by":"Prad Nukala","metadata":"{}"}],"dependency_count":2,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"chezmoi-9sg","title":"Arch layer: niri, noctalia, fontconfig, mimeapps, systemd user units — linux-gated","description":"niri config.d split preserved with exact_ dir; noctalia; fontconfig; mimeapps.list; systemd user units; foot/alacritty if live. All gated in .chezmoiignore.tmpl for darwin. niri validate must pass.","status":"open","priority":2,"issue_type":"task","owner":"prad@sonr.io","created_at":"2026-08-09T18:42:17Z","created_by":"Prad Nukala","updated_at":"2026-08-09T18:42:17Z","dependencies":[{"issue_id":"chezmoi-9sg","depends_on_id":"chezmoi-byc","type":"blocks","created_at":"2026-08-09T14:42:52Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-9sg","depends_on_id":"chezmoi-rnv","type":"blocks","created_at":"2026-08-09T14:42:52Z","created_by":"Prad Nukala","metadata":"{}"}],"dependency_count":2,"dependent_count":2,"comment_count":0} +{"_type":"issue","id":"chezmoi-9sg","title":"Arch layer: niri, noctalia, fontconfig, mimeapps, systemd user units — linux-gated","description":"niri config.d split preserved with exact_ dir; noctalia; fontconfig; mimeapps.list; systemd user units; foot/alacritty if live. All gated in .chezmoiignore.tmpl for darwin. niri validate must pass.","status":"in_progress","priority":2,"issue_type":"task","owner":"prad@sonr.io","created_at":"2026-08-09T18:42:17Z","created_by":"Prad Nukala","updated_at":"2026-08-09T18:53:56Z","started_at":"2026-08-09T18:53:56Z","dependencies":[{"issue_id":"chezmoi-9sg","depends_on_id":"chezmoi-byc","type":"blocks","created_at":"2026-08-09T14:42:52Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-9sg","depends_on_id":"chezmoi-rnv","type":"blocks","created_at":"2026-08-09T14:42:52Z","created_by":"Prad Nukala","metadata":"{}"}],"dependency_count":2,"dependent_count":2,"comment_count":0} {"_type":"issue","id":"chezmoi-iu2","title":"packages.yaml: translate dotstate manifests + live state into declarative manifest","description":"Curate Noctalia pacman list (drop base-system noise), custom installers, cargo/go tools, shared gh_extensions; darwin brew/cask section. Install scripts run_onchange keyed on yaml hash: pacman --needed + paru | brew loop; gh extension install loop; linux systemctl --user enable; post: fc-cache, bat cache.","status":"open","priority":2,"issue_type":"task","owner":"prad@sonr.io","created_at":"2026-08-09T18:42:17Z","created_by":"Prad Nukala","updated_at":"2026-08-09T18:42:17Z","dependencies":[{"issue_id":"chezmoi-iu2","depends_on_id":"chezmoi-byc","type":"blocks","created_at":"2026-08-09T14:42:53Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-iu2","depends_on_id":"chezmoi-rnv","type":"blocks","created_at":"2026-08-09T14:42:53Z","created_by":"Prad Nukala","metadata":"{}"}],"dependency_count":2,"dependent_count":2,"comment_count":0} {"_type":"issue","id":"chezmoi-udp","title":"Validation: darwin simulation","description":"chezmoi execute-template with os=darwin on every .tmpl; darwin-mode dry-run apply writes zero linux-gated paths, errors on nothing. Full Mac apply deferred until hardware available.","status":"open","priority":2,"issue_type":"task","owner":"prad@sonr.io","created_at":"2026-08-09T18:42:17Z","created_by":"Prad Nukala","updated_at":"2026-08-09T18:42:17Z","dependencies":[{"issue_id":"chezmoi-udp","depends_on_id":"chezmoi-21v","type":"blocks","created_at":"2026-08-09T14:43:01Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-udp","depends_on_id":"chezmoi-4sj","type":"blocks","created_at":"2026-08-09T14:43:00Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-udp","depends_on_id":"chezmoi-9sg","type":"blocks","created_at":"2026-08-09T14:43:01Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-udp","depends_on_id":"chezmoi-a2k","type":"blocks","created_at":"2026-08-09T14:43:01Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-udp","depends_on_id":"chezmoi-exq","type":"blocks","created_at":"2026-08-09T14:43:01Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-udp","depends_on_id":"chezmoi-fde","type":"blocks","created_at":"2026-08-09T14:43:01Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-udp","depends_on_id":"chezmoi-hou","type":"blocks","created_at":"2026-08-09T14:43:00Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-udp","depends_on_id":"chezmoi-iu2","type":"blocks","created_at":"2026-08-09T14:43:01Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-udp","depends_on_id":"chezmoi-sd9","type":"blocks","created_at":"2026-08-09T14:43:00Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-udp","depends_on_id":"chezmoi-utl","type":"blocks","created_at":"2026-08-09T14:43:00Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-udp","depends_on_id":"chezmoi-uw2","type":"blocks","created_at":"2026-08-09T14:42:59Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-udp","depends_on_id":"chezmoi-x7f","type":"blocks","created_at":"2026-08-09T14:43:00Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-udp","depends_on_id":"chezmoi-xi5","type":"blocks","created_at":"2026-08-09T14:43:00Z","created_by":"Prad Nukala","metadata":"{}"}],"dependency_count":13,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"chezmoi-21v","title":"gh: config file + declarative extension list","description":"~/.config/gh config.yml (hosts.yml has oauth token - exclude/encrypt). Extensions: clean-branches, commit, dash, notify into packages.yaml shared.gh_extensions.","status":"closed","priority":2,"issue_type":"task","owner":"prad@sonr.io","created_at":"2026-08-09T18:42:06Z","created_by":"Prad Nukala","updated_at":"2026-08-09T18:53:15Z","closed_at":"2026-08-09T18:53:15Z","close_reason":"Closed","dependencies":[{"issue_id":"chezmoi-21v","depends_on_id":"chezmoi-1a0","type":"blocks","created_at":"2026-08-09T14:42:24Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-21v","depends_on_id":"chezmoi-byc","type":"blocks","created_at":"2026-08-09T14:42:51Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-21v","depends_on_id":"chezmoi-rnv","type":"blocks","created_at":"2026-08-09T14:42:51Z","created_by":"Prad Nukala","metadata":"{}"}],"dependency_count":3,"dependent_count":2,"comment_count":0} {"_type":"issue","id":"chezmoi-4sj","title":"lazydocker: static config from live","description":"~/.config/lazydocker (not in dotstate).","status":"closed","priority":2,"issue_type":"task","owner":"prad@sonr.io","created_at":"2026-08-09T18:42:06Z","created_by":"Prad Nukala","updated_at":"2026-08-09T18:53:15Z","closed_at":"2026-08-09T18:53:15Z","close_reason":"Closed","dependencies":[{"issue_id":"chezmoi-4sj","depends_on_id":"chezmoi-byc","type":"blocks","created_at":"2026-08-09T14:42:51Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-4sj","depends_on_id":"chezmoi-rnv","type":"blocks","created_at":"2026-08-09T14:42:51Z","created_by":"Prad Nukala","metadata":"{}"}],"dependency_count":2,"dependent_count":2,"comment_count":0} -{"_type":"issue","id":"chezmoi-a2k","title":"claude: settings, commands, agents, hooks, skills only","description":"~/.claude: settings.json, commands/, hooks/, skills/, CLAUDE.md. Never credentials/history/projects/sessions.","status":"in_progress","priority":2,"issue_type":"task","owner":"prad@sonr.io","created_at":"2026-08-09T18:42:06Z","created_by":"Prad Nukala","updated_at":"2026-08-09T18:53:15Z","started_at":"2026-08-09T18:53:15Z","dependencies":[{"issue_id":"chezmoi-a2k","depends_on_id":"chezmoi-1a0","type":"blocks","created_at":"2026-08-09T14:42:24Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-a2k","depends_on_id":"chezmoi-byc","type":"blocks","created_at":"2026-08-09T14:42:52Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-a2k","depends_on_id":"chezmoi-rnv","type":"blocks","created_at":"2026-08-09T14:42:52Z","created_by":"Prad Nukala","metadata":"{}"}],"dependency_count":3,"dependent_count":2,"comment_count":0} -{"_type":"issue","id":"chezmoi-exq","title":"git: dot_gitconfig.tmpl with templated email/signing key","description":"~/.gitconfig from live; email + signing key from chezmoi data.","status":"in_progress","priority":2,"issue_type":"task","owner":"prad@sonr.io","created_at":"2026-08-09T18:42:06Z","created_by":"Prad Nukala","updated_at":"2026-08-09T18:53:16Z","started_at":"2026-08-09T18:53:16Z","dependencies":[{"issue_id":"chezmoi-exq","depends_on_id":"chezmoi-byc","type":"blocks","created_at":"2026-08-09T14:42:52Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-exq","depends_on_id":"chezmoi-rnv","type":"blocks","created_at":"2026-08-09T14:42:52Z","created_by":"Prad Nukala","metadata":"{}"}],"dependency_count":2,"dependent_count":2,"comment_count":0} +{"_type":"issue","id":"chezmoi-a2k","title":"claude: settings, commands, agents, hooks, skills only","description":"~/.claude: settings.json, commands/, hooks/, skills/, CLAUDE.md. Never credentials/history/projects/sessions.","status":"closed","priority":2,"issue_type":"task","owner":"prad@sonr.io","created_at":"2026-08-09T18:42:06Z","created_by":"Prad Nukala","updated_at":"2026-08-09T18:53:47Z","started_at":"2026-08-09T18:53:15Z","closed_at":"2026-08-09T18:53:47Z","close_reason":"Closed","dependencies":[{"issue_id":"chezmoi-a2k","depends_on_id":"chezmoi-1a0","type":"blocks","created_at":"2026-08-09T14:42:24Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-a2k","depends_on_id":"chezmoi-byc","type":"blocks","created_at":"2026-08-09T14:42:52Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-a2k","depends_on_id":"chezmoi-rnv","type":"blocks","created_at":"2026-08-09T14:42:52Z","created_by":"Prad Nukala","metadata":"{}"}],"dependency_count":3,"dependent_count":2,"comment_count":0} +{"_type":"issue","id":"chezmoi-exq","title":"git: dot_gitconfig.tmpl with templated email/signing key","description":"~/.gitconfig from live; email + signing key from chezmoi data.","status":"closed","priority":2,"issue_type":"task","owner":"prad@sonr.io","created_at":"2026-08-09T18:42:06Z","created_by":"Prad Nukala","updated_at":"2026-08-09T18:53:47Z","started_at":"2026-08-09T18:53:16Z","closed_at":"2026-08-09T18:53:47Z","close_reason":"Closed","dependencies":[{"issue_id":"chezmoi-exq","depends_on_id":"chezmoi-byc","type":"blocks","created_at":"2026-08-09T14:42:52Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-exq","depends_on_id":"chezmoi-rnv","type":"blocks","created_at":"2026-08-09T14:42:52Z","created_by":"Prad Nukala","metadata":"{}"}],"dependency_count":2,"dependent_count":2,"comment_count":0} {"_type":"issue","id":"chezmoi-fde","title":"starship: prompt config, universal","description":"Keep starship (user decision — omp dropped). dot_config/starship.toml from live; starship in packages.yaml both OSes. Noctalia palette block is auto-generated on linux — noctalia rewrites it in place; acceptable drift, noted.","status":"closed","priority":2,"issue_type":"task","owner":"prad@sonr.io","created_at":"2026-08-09T18:42:06Z","created_by":"Prad Nukala","updated_at":"2026-08-09T18:51:26Z","closed_at":"2026-08-09T18:51:26Z","close_reason":"starship.toml added from live; packages updated","dependencies":[{"issue_id":"chezmoi-fde","depends_on_id":"chezmoi-byc","type":"blocks","created_at":"2026-08-09T14:42:52Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-fde","depends_on_id":"chezmoi-rnv","type":"blocks","created_at":"2026-08-09T14:42:51Z","created_by":"Prad Nukala","metadata":"{}"}],"dependency_count":2,"dependent_count":2,"comment_count":0} {"_type":"issue","id":"chezmoi-x7f","title":"lazygit: static config","description":"~/.config/lazygit. Already partially in repo — reconcile.","status":"closed","priority":2,"issue_type":"task","owner":"prad@sonr.io","created_at":"2026-08-09T18:42:06Z","created_by":"Prad Nukala","updated_at":"2026-08-09T18:53:14Z","closed_at":"2026-08-09T18:53:14Z","close_reason":"Closed","dependencies":[{"issue_id":"chezmoi-x7f","depends_on_id":"chezmoi-byc","type":"blocks","created_at":"2026-08-09T14:42:51Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-x7f","depends_on_id":"chezmoi-rnv","type":"blocks","created_at":"2026-08-09T14:42:50Z","created_by":"Prad Nukala","metadata":"{}"}],"dependency_count":2,"dependent_count":2,"comment_count":0} {"_type":"issue","id":"chezmoi-hou","title":"yazi: config, opener rules OS-branched","description":"~/.config/yazi. open vs xdg-open template branch.","status":"closed","priority":2,"issue_type":"task","owner":"prad@sonr.io","created_at":"2026-08-09T18:42:05Z","created_by":"Prad Nukala","updated_at":"2026-08-09T18:53:14Z","closed_at":"2026-08-09T18:53:14Z","close_reason":"Closed","dependencies":[{"issue_id":"chezmoi-hou","depends_on_id":"chezmoi-byc","type":"blocks","created_at":"2026-08-09T14:42:50Z","created_by":"Prad Nukala","metadata":"{}"},{"issue_id":"chezmoi-hou","depends_on_id":"chezmoi-rnv","type":"blocks","created_at":"2026-08-09T14:42:50Z","created_by":"Prad Nukala","metadata":"{}"}],"dependency_count":2,"dependent_count":2,"comment_count":0} diff --git a/.chezmoiscripts/run_once_after_30-user-services.sh.tmpl b/.chezmoiscripts/run_once_after_30-user-services.sh.tmpl new file mode 100644 index 0000000..dbe35d5 --- /dev/null +++ b/.chezmoiscripts/run_once_after_30-user-services.sh.tmpl @@ -0,0 +1,15 @@ +{{ if eq .chezmoi.os "linux" -}} +#!/bin/sh +# Enable session-critical user services. Personal automation units +# (brain-lens, omp-loop, rclone, hermes, voxtype) ship as files only — +# enable manually per machine. See MIGRATION-NOTES.md. +set -eu + +if [ -f "$HOME/.config/systemd/user/nirinit.service" ] && command -v systemctl >/dev/null 2>&1; then + systemctl --user daemon-reload || true + systemctl --user enable nirinit.service || true +fi +{{ else -}} +#!/bin/sh +exit 0 +{{ end -}} diff --git a/.chezmoiscripts/run_onchange_after_20-gh-extensions.sh.tmpl b/.chezmoiscripts/run_onchange_after_20-gh-extensions.sh.tmpl new file mode 100644 index 0000000..4182694 --- /dev/null +++ b/.chezmoiscripts/run_onchange_after_20-gh-extensions.sh.tmpl @@ -0,0 +1,12 @@ +#!/bin/sh +# Install gh extensions declared in .chezmoidata/packages.yaml. +# gh_extensions hash: {{ .packages.shared.gh_extensions | toJson | sha256sum }} +set -eu + +command -v gh >/dev/null 2>&1 || { echo "warning: gh not installed — skipping extensions" >&2; exit 0; } +gh auth status >/dev/null 2>&1 || { echo "warning: gh not authenticated — run 'gh auth login', then 'chezmoi apply' again" >&2; exit 0; } + +installed=$(gh extension list 2>/dev/null | cut -f2 || true) +{{ range .packages.shared.gh_extensions }} +echo "$installed" | grep -qxF "{{ . }}" || gh extension install "{{ . }}" +{{ end }} diff --git a/.chezmoiscripts/run_onchange_after_40-post.sh.tmpl b/.chezmoiscripts/run_onchange_after_40-post.sh.tmpl new file mode 100644 index 0000000..3990826 --- /dev/null +++ b/.chezmoiscripts/run_onchange_after_40-post.sh.tmpl @@ -0,0 +1,14 @@ +#!/bin/sh +# Post-apply housekeeping. Re-runs when this file's rendered content changes. +set -eu + +# tmux plugin manager — tmux.conf expects tpm at this path +if command -v tmux >/dev/null 2>&1 && [ ! -d "$HOME/.config/tmux/plugins/tpm" ]; then + git clone --depth=1 https://github.com/tmux-plugins/tpm "$HOME/.config/tmux/plugins/tpm" || true +fi + +if command -v bat >/dev/null 2>&1; then bat cache --build >/dev/null || true; fi + +{{ if eq .chezmoi.os "linux" -}} +if command -v fc-cache >/dev/null 2>&1; then fc-cache -f >/dev/null || true; fi +{{ end -}} diff --git a/.chezmoiscripts/run_onchange_before_10-packages.sh.tmpl b/.chezmoiscripts/run_onchange_before_10-packages.sh.tmpl new file mode 100644 index 0000000..d9b59e5 --- /dev/null +++ b/.chezmoiscripts/run_onchange_before_10-packages.sh.tmpl @@ -0,0 +1,44 @@ +#!/bin/sh +# Install packages declared in .chezmoidata/packages.yaml. +# packages.yaml hash: {{ include ".chezmoidata/packages.yaml" | sha256sum }} +set -eu + +{{ if eq .chezmoi.os "linux" -}} +if [ "$(id -u)" -eq 0 ]; then PACMAN="pacman"; else PACMAN="sudo pacman"; fi + +# shellcheck disable=SC2086 # word splitting intended +$PACMAN -S --needed --noconfirm \ +{{ range .packages.arch.pacman }} {{ . }} \ +{{ end }} && true + +{{ if or (eq .role "desktop") (eq .role "laptop") -}} +$PACMAN -S --needed --noconfirm \ +{{ range .packages.arch.desktop.pacman }} {{ . }} \ +{{ end }} && true + +aur_pkgs="{{ range .packages.arch.desktop.aur }}{{ . }} {{ end }}{{ range .packages.arch.aur }}{{ . }} {{ end }}" +{{ else -}} +aur_pkgs="{{ range .packages.arch.aur }}{{ . }} {{ end }}" +{{ end -}} +if [ -n "$(echo "$aur_pkgs" | tr -d ' ')" ]; then + if command -v paru >/dev/null 2>&1; then + # shellcheck disable=SC2086 + paru -S --needed --noconfirm $aur_pkgs + else + echo "warning: paru not found — skipping AUR packages: $aur_pkgs" >&2 + fi +fi + +{{ else if eq .chezmoi.os "darwin" -}} +if ! command -v brew >/dev/null 2>&1; then + echo "error: homebrew not installed — https://brew.sh" >&2 + exit 1 +fi +brew install \ +{{ range .packages.darwin.brew }} {{ . }} \ +{{ end }} && true + +brew install --cask \ +{{ range .packages.darwin.cask }} {{ . }} \ +{{ end }} && true +{{ end -}} diff --git a/dot_config/fontconfig/fonts.conf b/dot_config/fontconfig/fonts.conf new file mode 100644 index 0000000..f450859 --- /dev/null +++ b/dot_config/fontconfig/fonts.conf @@ -0,0 +1,9 @@ + + + + + + none + + + diff --git a/dot_config/mimeapps.list b/dot_config/mimeapps.list new file mode 100644 index 0000000..68d1685 --- /dev/null +++ b/dot_config/mimeapps.list @@ -0,0 +1,51 @@ +[Default Applications] +text/plain=vim.desktop +text/x-shellscript=vim.desktop +text/x-python=vim.desktop +text/x-script.python=vim.desktop +text/html=brave-origin-nightly.desktop +x-scheme-handler/http=brave-origin-nightly.desktop +x-scheme-handler/https=brave-origin-nightly.desktop +x-scheme-handler/about=chromium.desktop +x-scheme-handler/unknown=chromium.desktop +x-scheme-handler/chrome=brave-origin-nightly.desktop +application/x-extension-htm=brave-origin-nightly.desktop +application/x-extension-html=brave-origin-nightly.desktop +application/x-extension-shtml=brave-origin-nightly.desktop +application/xhtml+xml=brave-origin-nightly.desktop +application/x-extension-xhtml=brave-origin-nightly.desktop +application/x-extension-xht=brave-origin-nightly.desktop +x-scheme-handler/figma=figma-linux.desktop +x-scheme-handler/claude=com.anthropic.Claude.desktop +x-scheme-handler/claude-cli=claude-code-url-handler.desktop +x-scheme-handler/com.todoist=todoist.desktop +x-scheme-handler/todoist=todoist.desktop +x-scheme-handler/openhuman=OpenHuman-handler.desktop +application/vnd.microsoft.portable-executable=wine.desktop +x-scheme-handler/slack=slack.desktop +x-scheme-handler/mailto=userapp-Evolution-PCEYQ3.desktop +x-scheme-handler/anytype=anytype.desktop +x-scheme-handler/piebald=piebald-handler.desktop +x-scheme-handler/discord-647066573147996161=discord-647066573147996161.desktop +x-scheme-handler/tolaria=tolaria-handler.desktop +x-scheme-handler/antigravity=antigravity.desktop +application/pdf=com.brave.Origin.nightly.desktop +x-scheme-handler/opencode=ai.opencode.desktop.desktop +x-scheme-handler/follow=folo.desktop +x-scheme-handler/folo=folo.desktop + +[Added Associations] +x-scheme-handler/http=brave-origin-nightly.desktop;userapp-Floorp-9MTFP3.desktop; +x-scheme-handler/https=brave-origin-nightly.desktop;userapp-Floorp-9MTFP3.desktop; +x-scheme-handler/chrome=brave-origin-nightly.desktop;userapp-Floorp-9MTFP3.desktop; +text/html=brave-origin-nightly.desktop;userapp-Floorp-9MTFP3.desktop; +application/x-extension-htm=brave-origin-nightly.desktop;userapp-Floorp-9MTFP3.desktop; +application/x-extension-html=brave-origin-nightly.desktop;userapp-Floorp-9MTFP3.desktop; +application/x-extension-shtml=brave-origin-nightly.desktop;userapp-Floorp-9MTFP3.desktop; +application/xhtml+xml=brave-origin-nightly.desktop;userapp-Floorp-9MTFP3.desktop; +application/x-extension-xhtml=brave-origin-nightly.desktop;userapp-Floorp-9MTFP3.desktop; +application/x-extension-xht=brave-origin-nightly.desktop;userapp-Floorp-9MTFP3.desktop; +application/vnd.microsoft.portable-executable=wine.desktop; +x-scheme-handler/mailto=userapp-Evolution-PCEYQ3.desktop; +application/pdf=com.brave.Origin.nightly.desktop; +x-scheme-handler/opencode=ai.opencode.desktop.desktop; diff --git a/dot_config/niri-dynamic-workspaces/config.toml b/dot_config/niri-dynamic-workspaces/config.toml new file mode 100644 index 0000000..989ace7 --- /dev/null +++ b/dot_config/niri-dynamic-workspaces/config.toml @@ -0,0 +1,76 @@ +[general] +workspace_prefix = "ndw-" # prefix for dynamic workspace names +default_programs = ["kitty"] # programs launched when creating any new workspace +auto_delete_empty = true # daemon: auto-delete empty unfocused workspaces +hover_preview = false # preview workspaces by hovering over cards +layout = "qwerty" # keyboard layout for the overlay (see table below) + +[keybinds] +close = ["Escape", "Ctrl+c", "Ctrl+w", "Ctrl+q"] # keys to dismiss the overlay + +[workspace.y] # digit workspaces work too +name = "YouTube" +programs = ["vicinae vicinae://launch/applications/WebApp-YouTube7881"] + +[workspace.m] # digit workspaces work too +name = "Messages" +programs = [ + "vicinae vicinae://launch/applications/beeper", + "vicinae vicinae://launch/applications/org.gnome.Evolution", +] + +[workspace.l] # digit workspaces work too +name = "Linear" +programs = ["vicinae vicinae://launch/applications/WebApp-Linear3312"] + +[workspace.d] # digit workspaces work too +name = "Chrome" +programs = ["vicinae vicinae://launch/applications/google-chrome"] + +[workspace.x] # digit workspaces work too +name = "Twitter" +programs = ["vicinae vicinae://launch/applications/WebApp-X1000"] + +[workspace.h] +name = "Herdr" +programs = ["kitty --class kitty-herdr -e herdr"] + +# digit workspaces work too +[workspace.f] +name = "Frontend" +programs = [ + "kitty-nvim walletbases/website", + "kitty-claude walletbases/website", +] + +[workspace.c] +name = "Contracts" +programs = [ + "kitty-nvim walletbases/contracts", + "kitty --class kitty-claude -d /home/prad/Developer/github.com/walletbases/contracts -e claude", +] + + +[workspace.b] +name = "Backend" +programs = [ + "kitty --class kitty-nvim -d /home/prad/Developer/github.com/walletbases/backend -e nvim", + "kitty --class kitty-claude -d /home/prad/Developer/github.com/walletbases/backend -e claude", +] + +[workspace.s] +name = "SDK" +programs = [ + "kitty --class kitty-nvim -d /home/prad/Developer/github.com/walletbases/core -e nvim", + "kitty --class kitty-claude -d /home/prad/Developer/github.com/walletbases/core -e claude", +] + +[workspace.w] +name = "Web" +programs = [ + "kitty --class kitty-nvim -d /home/prad/Developer/github.com/walletbases/website -e nvim", + "kitty --class kitty-claude -d /home/prad/Developer/github.com/walletbases/website -e claude", +] + +[hooks] +on_create = ['''~/.config/niri/scripts/ndw-route-workspace.sh'''] diff --git a/dot_config/niri/config.kdl b/dot_config/niri/config.kdl new file mode 100644 index 0000000..08726e8 --- /dev/null +++ b/dot_config/niri/config.kdl @@ -0,0 +1,195 @@ +// ============================================================================ +// NIRI CONFIGURATION - Base for iNiR (ii) +// ============================================================================ +// Minimal base config - customize to your needs +// Wiki: https://github.com/YaLTeR/niri/wiki/Configuration:-Introduction +// ============================================================================ + + +hotkey-overlay { + skip-at-startup +} + +screenshot-path "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png" + +include "config.d/10-input-and-cursor.kdl" + +include "config.d/20-layout-and-overview.kdl" + +include "config.d/30-window-rules.kdl" + +include "config.d/40-environment.kdl" + +include "config.d/50-startup.kdl" + +include "config.d/60-animations.kdl" + +include "config.d/70-binds.kdl" + +include "config.d/80-layer-rules.kdl" + +include "config.d/90-outputs.kdl" + +// ============================================================================ +// Layer rules added by iNiR (required for backdrop in overview) +// ============================================================================ + +input { + keyboard { + xkb { + layout "us" + } + repeat-delay 400 + repeat-rate 50 + } + touchpad { + natural-scroll + tap + tap-button-map "left-right-middle" + } + + mod-key "Super" + mod-key-nested "Alt" +} + +// ============================================================================ +// LAYOUT +// ============================================================================ + +layout { + background-color "transparent" + default-column-width { proportion 0.5; } + + preset-column-widths { + proportion 0.33333 + proportion 0.5 + proportion 0.66667 + } + + focus-ring { + width 1.5 + active-color "#7fc8ff" + inactive-color "transparent" + } + + border { + off + width 1.5 + active-color "#ffc87f" + inactive-color "transparent" + urgent-color "#9b0000" + } + + shadow { + off + softness 30 + spread 5 + offset x=0 y=5 + color "#0007" + } + + tab-indicator { + place-within-column + hide-when-single-tab + position "left" // Can be "left", "right", "top", or "bottom" + } + +} + +gestures { + hot-corners { + off + } +} + +cursor { + xcursor-theme "capitaine-cursors-light" + xcursor-size 24 + hide-when-typing +} + +overview { + zoom 0.4 + workspace-shadow { off; } +} +// ============================================================================ +// WINDOW RULES +// ============================================================================ + +window-rule { + geometry-corner-radius 8 + clip-to-geometry true +} + +// ============================================================================ +// ANIMATIONS +// ============================================================================ +// Tuned to complement quickshell's expressive Material motion curves +// QS uses ~500ms for main movements, ~400ms enter, ~200ms exit + +animations { + workspace-switch { + spring damping-ratio=0.78 stiffness=1350 epsilon=0.0001 + } + window-open { + spring damping-ratio=0.82 stiffness=1125 epsilon=0.0001 + } + window-close { + spring damping-ratio=0.88 stiffness=2025 epsilon=0.0001 + } + horizontal-view-movement { + spring damping-ratio=0.80 stiffness=1238 epsilon=0.0001 + } + window-movement { + spring damping-ratio=0.85 stiffness=1463 epsilon=0.0001 + } + window-resize { + spring damping-ratio=0.88 stiffness=1575 epsilon=0.0001 + } + config-notification-open-close { + spring damping-ratio=0.90 stiffness=1800 epsilon=0.0001 + } + screenshot-ui-open { + spring damping-ratio=0.85 stiffness=1688 epsilon=0.0001 + } +} + +// ============================================================================ +// ENVIRONMENT +// ============================================================================ + +environment { + XDG_CURRENT_DESKTOP "niri" + XDG_MENU_PREFIX "plasma-" // Required for Dolphin/KDE app file associations + QT_QPA_PLATFORM "wayland" + ELECTRON_OZONE_PLATFORM_HINT "auto" + QT_LOGGING_RULES "quickshell.dbus.properties=false" + + // Qt theming: kde platform reads colors from kdeglobals (requires plasma-integration pkg) + // The installer falls back to qt6ct only if plasma-integration is not installed + QT_QPA_PLATFORMTHEME "kde" + QT_STYLE_OVERRIDE "Darkly" + + // Quickshell Python virtual environment + INIR_VENV "$HOME/.local/state/quickshell/.venv" + ILLOGICAL_IMPULSE_VIRTUAL_ENV "$HOME/.local/state/quickshell/.venv" +} + +// ============================================================================ +// STARTUP — commands live in config.d/50-startup.kdl +// ============================================================================ + +// Noctalia v5: allows notification actions and window activation from Noctalia. +debug { + honor-xdg-activation-with-invalid-serial +} + + +// ============================================================================ +// KEYBINDINGS +// ============================================================================ + + +include "./noctalia.kdl" + +prefer-no-csd diff --git a/dot_config/niri/exact_config.d/10-input-and-cursor.kdl b/dot_config/niri/exact_config.d/10-input-and-cursor.kdl new file mode 100644 index 0000000..d7cb00f --- /dev/null +++ b/dot_config/niri/exact_config.d/10-input-and-cursor.kdl @@ -0,0 +1,44 @@ +// Outputs (example - disabled by default) +// Run `niri msg outputs` inside a niri session to see connector names and modes. +// Then edit and uncomment this block to pin a specific monitor layout. + +// ============================================================================ +// INPUT +// ============================================================================ + +input { + keyboard { + xkb { + layout "us" + } + repeat-delay 400 + repeat-rate 50 + } + touchpad { + natural-scroll + tap + tap-button-map "left-right-middle" + accel-speed 1.0 + } + + tablet { + map-to-output "eDP-1" + } + + touch { + map-to-output "eDP-1" + } + + mod-key "Super" + mod-key-nested "Alt" +} + +gestures { + +} + +cursor { + xcursor-theme "capitaine-cursors-light" + xcursor-size 24 + hide-when-typing +} diff --git a/dot_config/niri/exact_config.d/20-layout-and-overview.kdl b/dot_config/niri/exact_config.d/20-layout-and-overview.kdl new file mode 100644 index 0000000..a19ca5f --- /dev/null +++ b/dot_config/niri/exact_config.d/20-layout-and-overview.kdl @@ -0,0 +1,57 @@ +layout { + center-focused-column "never" + background-color "transparent" + default-column-width { proportion 0.5; } + + preset-column-widths { + proportion 0.33333 + proportion 0.5 + proportion 0.66667 + } + + focus-ring { + width 1.5 + active-color "#7fc8ff" + inactive-color "transparent" + } + + border { + off + width 1.5 + active-color "#ffc87f" + inactive-color "transparent" + urgent-color "#9b0000" + } + + shadow { + off + softness 30 + spread 5 + offset x=0 y=5 + color "#0007" + } + + tab-indicator { + place-within-column + hide-when-single-tab + position "left" // Can be "left", "right", "top", or "bottom" + } + + +} + +gestures { + hot-corners { + } +} + +cursor { + xcursor-theme "capitaine-cursors-light" + xcursor-size 24 + hide-when-typing +} + +overview { + zoom 0.4 + workspace-shadow { off; } +} diff --git a/dot_config/niri/exact_config.d/30-window-rules.kdl b/dot_config/niri/exact_config.d/30-window-rules.kdl new file mode 100644 index 0000000..beef1cb --- /dev/null +++ b/dot_config/niri/exact_config.d/30-window-rules.kdl @@ -0,0 +1,135 @@ +// ============================================================================ +// WINDOW RULES +// ============================================================================ + +window-rule { + geometry-corner-radius 10 + clip-to-geometry true +} + +window-rule { + background-effect { + blur true + xray false + } +} + +// Noctalia v5: floating settings window. +window-rule { + match app-id="dev.noctalia.Noctalia" + open-floating true + default-column-width { fixed 1080; } + default-window-height { fixed 920; } +} + +blur { + passes 4 + offset 5.0 + noise 0.02 + saturation 2.0 +} + +window-rule { + match app-id="Folo" + match app-id="Spotify" + match app-id="zen" + match app-id="brave-origin-nightly" + match app-id="gemini-desktop" + match app-id="claude-desktop" + opacity 0.9 + open-floating false + draw-border-with-background false + background-effect { + blur true + xray false + } + open-focused true +} + +window-rule { + match app-id="kitty" + match app-id="zed" + match app-id="obsidian" + match app-id="Beeper" + match app-id="chromium" + match app-id="com.mitchellh.ghostty" + opacity 0.9 + open-floating false + draw-border-with-background false + open-focused true + background-effect { + blur true + xray false + } +} + +window-rule { + match app-id="org.gnome.Nautilus" + match app-id="com.gabm.satty" + open-floating true + open-focused true + draw-border-with-background false + default-column-width { proportion 0.5; } +} + +window-rule { + match app-id="kitty-dropdown" + open-floating true + opacity 1.0 + default-floating-position x=32 y=32 relative-to="top" +} + +window-rule { + match title="ostt" + open-floating true + open-focused true + default-column-width { proportion 0.1; } + default-window-height { proportion 0.15; } + opacity 0.8 + + draw-border-with-background false + default-floating-position x=64 y=64 relative-to="bottom-right" +} + + +window-rule { + match title="Picture-in-Picture" app-id="zen" + match title="Picture in picture" + open-floating true + open-focused false + opacity 1.0 + + // default-floating-position x=28 y=28 relative-to="top-right" + default-floating-position x=28 y=28 relative-to="bottom-left" + // open-on-output "eDP-1" + open-on-output "HDMI-A-1" + // open-on-output "Apple Computer Inc StudioDisplay 0x984262A7" +} + +window-rule { + // open-on-output "HDMI-A-1" +} + +window-rule { + match app-id="sticky-notest-canvas" + match title="Sticky Notes" + match app-id="vacuumtube" + match app-id="Fladder" + match app-id="gemini-desktop" + match app-id="com-fastmail-fastmail" + match app-id="Beeper" + match app-id="todoist" + match app-id="com.anthropic.Claude" + match app-id="Hermes" + + + open-on-output "eDP-1" +} + +window-rule { + match app-id="kitty" + match app-id="zed" + match app-id="obsidian" + + open-on-output "Apple Computer Inc StudioDisplay 0x984262A7" +} diff --git a/dot_config/niri/exact_config.d/40-environment.kdl b/dot_config/niri/exact_config.d/40-environment.kdl new file mode 100644 index 0000000..1ffe0bc --- /dev/null +++ b/dot_config/niri/exact_config.d/40-environment.kdl @@ -0,0 +1,22 @@ +// ============================================================================ +// ENVIRONMENT +// ============================================================================ + +environment { + XDG_CURRENT_DESKTOP "niri" + XDG_MENU_PREFIX "plasma-" // Required for Dolphin/KDE app file associations + QT_QPA_PLATFORM "wayland" + ELECTRON_OZONE_PLATFORM_HINT "auto" + QT_LOGGING_RULES "quickshell.dbus.properties=false" + + // Qt theming: kde platform reads colors from kdeglobals (requires plasma-integration pkg) + // The installer falls back to qt6ct only if plasma-integration is not installed + QT_QPA_PLATFORMTHEME "kde" + QT_STYLE_OVERRIDE "Darkly" + + // Quickshell Python virtual environment + INIR_VENV "$HOME/.local/state/quickshell/.venv" + ILLOGICAL_IMPULSE_VIRTUAL_ENV "$HOME/.local/state/quickshell/.venv" +} + + diff --git a/dot_config/niri/exact_config.d/50-startup.kdl b/dot_config/niri/exact_config.d/50-startup.kdl new file mode 100644 index 0000000..7154a9c --- /dev/null +++ b/dot_config/niri/exact_config.d/50-startup.kdl @@ -0,0 +1,11 @@ +// ============================================================================ +// STARTUP +// ============================================================================ + +// Import XDG_MENU_PREFIX to systemd for Dolphin/KDE app file associations +spawn-at-startup "bash" "-c" "systemctl --user import-environment XDG_MENU_PREFIX && kbuildsycoca6" +spawn-at-startup "/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1" +spawn-at-startup "noctalia" +spawn-at-startup "niri-dynamic-workspaces" "daemon" +spawn-at-startup "vicinae" "server" +spawn-at-startup "bash" "-c" "wl-paste --watch cliphist store &" diff --git a/dot_config/niri/exact_config.d/60-animations.kdl b/dot_config/niri/exact_config.d/60-animations.kdl new file mode 100644 index 0000000..ed2a530 --- /dev/null +++ b/dot_config/niri/exact_config.d/60-animations.kdl @@ -0,0 +1,32 @@ +// ============================================================================ +// ANIMATIONS +// ============================================================================ +// Tuned to complement quickshell's expressive Material motion curves +// QS uses ~500ms for main movements, ~400ms enter, ~200ms exit + +animations { + workspace-switch { +spring damping-ratio=1.0 stiffness=4000 epsilon=0.0001 + } + window-open { + spring damping-ratio=1.0 stiffness=5000 epsilon=0.0001 + } + window-close { + spring damping-ratio=1.0 stiffness=6000 epsilon=0.0001 + } + horizontal-view-movement { + spring damping-ratio=1.0 stiffness=4500 epsilon=0.0001 + } + window-movement { + spring damping-ratio=1.0 stiffness=5000 epsilon=0.0001 + } + window-resize { + spring damping-ratio=1.0 stiffness=5500 epsilon=0.0001 + } + config-notification-open-close { + spring damping-ratio=1.0 stiffness=5000 epsilon=0.0001 + } + screenshot-ui-open { + spring damping-ratio=1.0 stiffness=5000 epsilon=0.0001 + } +} diff --git a/dot_config/niri/exact_config.d/70-binds.kdl b/dot_config/niri/exact_config.d/70-binds.kdl new file mode 100644 index 0000000..ffe7fd8 --- /dev/null +++ b/dot_config/niri/exact_config.d/70-binds.kdl @@ -0,0 +1,154 @@ +// ============================================================================ +// KEYBINDINGS +// ============================================================================ + + +binds { + // System + Mod+Tab repeat=false { toggle-overview; } + Mod+Shift+E { quit; } + Mod+Escape allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; } + + // ii Overview (daemon) + Mod+Space repeat=false { spawn "vicinae" "toggle"; } + Mod+Shift+Space repeat=false { spawn "vicinae" "vicinae://launch/core/search-emojis"; } + Mod+Shift+Return repeat=false { spawn "vicinae" "vicinae://launch/wm/switch-windows"; } + Mod+BackSpace { focus-window-previous; } + + // ii Clipboard + Mod+P { spawn "vicinae" "vicinae://launch/clipboard/history"; } + Mod+Ctrl+R { spawn "noctalia" "msg" "plugin" "prdlk/ostt:recorder" "focused" "toggle"; } + + // ii Region tools + Mod+Shift+G { spawn "kitty" "--title=goliath" "ssh" "-t" "goliath" "tmux" "new-session" "-A" "-s" "main"; } + Mod+S { spawn "dot-screenshot" "region"; } + Mod+Shift+S { spawn "dot-screenshot" "window"; } + Mod+Ctrl+S { spawn "dot-screenshot" "monitor-focused"; } + Mod+Ctrl+Shift+S { spawn "dot-screenshot" "monitor-all"; } + // v4: Mod+Period { spawn-sh "qs -c noctalia-shell ipc call controlCenter toggle"; } + // v4: Mod+Comma { spawn-sh "qs -c noctalia-shell ipc call settings toggle"; } + Mod+Period { spawn-sh "noctalia msg panel-toggle control-center"; } + Mod+Comma { spawn-sh "noctalia msg settings-toggle"; } + + Super+Ctrl+A { spawn "vicinae" "vicinae://launch/applications/com.anthropic.Claude"; } + Super+Ctrl+G { spawn "vicinae" "vicinae://launch/applications/gemini-desktop"; } + Super+Alt+Ctrl+H { spawn "hermes" "desktop"; } + + Super+Alt+Ctrl+J { spawn "niri-launch" "kitty"; } + Super+Alt+Ctrl+K { spawn "niri-launch" "brave-origin-nightly"; } + Super+Alt+Ctrl+O { spawn "niri-launch" "obsidian"; } + Super+Alt+Ctrl+E { spawn "vicinae" "vicinae://launch/applications/com.fastmail.Fastmail"; } + Super+Alt+Ctrl+B { spawn "vicinae" "vicinae://launch/applications/beeper"; } + Super+Alt+Ctrl+L { spawn "vicinae" "vicinae://launch/applications/WebApp-Linear3312"; } + Super+Alt+Ctrl+M { spawn "vicinae" "vicinae://launch/applications/beeper"; } + Super+Alt+Ctrl+T { spawn "vicinae" "vicinae://launch/applications/todoist"; } + Super+Alt+Ctrl+N { spawn "noctalia" "msg" "panel-open" "noctalia/notes:panel"; } + Super+Alt+Ctrl+F { spawn "vicinae" "vicinae://launch/applications/org.gnome.Nautilus"; } + Super+Alt+Ctrl+Space { spawn "vicinae" "vicinae://launch/applications/io.github.faridjaff.StickyNotesCanvas"; } + Super+Alt+Ctrl+Return { spawn "vicinae" "vicinae://launch/wm/switch-windows"; } + + Super+Shift+Alt+Ctrl+W { spawn "niri-dynamic-workspaces" "switch" "w"; } + Super+Shift+Alt+Ctrl+H { spawn "niri-dynamic-workspaces" "switch" "h"; } + Super+Alt+Ctrl+Y { spawn "vicinae" "vicinae://launch/applications/rocks.shy.VacuumTube"; } + Super+Alt+Ctrl+X { spawn "niri-dynamic-workspaces" "switch" "x"; } + + // ─── Monitors ─── (Vertical) + Mod+Left { focus-monitor-left; } + Mod+Up { focus-monitor-up; } + Mod+Right { focus-monitor-right; } + Mod+Shift+Down { move-column-to-monitor-right; } + Mod+Shift+Up { move-column-to-monitor-left; } + + // ─── Layout ─── + Mod+R { switch-preset-column-width; } + Mod+Shift+R { switch-preset-window-height; } + Mod+Shift+F { maximize-column; } + Mod+F { expand-column-to-available-width; } + Super+C { center-column; } + Mod+Ctrl+C { center-visible-columns; } + Mod+Ctrl+F { fullscreen-window; } + Mod+Ctrl+O { toggle-window-floating; } + + // ─── Window Sizing: hjkl ─── + Alt+Shift+H { set-column-width "-10%"; } + Alt+Shift+J { set-window-height "-10%"; } + Alt+Shift+K { set-window-height "+10%"; } + Alt+Shift+L { set-column-width "+10%"; } + + + + // Window management + Mod+Q repeat=false { spawn "/home/prad/.local/bin/niri-smart-close"; } + + // Focus + Mod+H { focus-column-left-or-last; } + Mod+L { focus-column-right-or-first; } + Mod+J { focus-window-or-workspace-down; } + Mod+K { focus-window-or-workspace-up; } + + // Workspaces + Mod+Shift+J { move-column-to-workspace-down; } + Mod+Shift+K { move-column-to-workspace-up; } + + // Monitors + Super+O { focus-monitor-next; } + Super+Ctrl+J { focus-monitor-next; } + Super+Ctrl+K { focus-monitor-previous; } + Super+Shift+O { move-column-to-monitor-next; } + Mod+Ctrl+Shift+J { move-column-to-monitor-next; } + Mod+Ctrl+Shift+K { move-column-to-monitor-previous; } + + // Columns + Super+Ctrl+H { focus-column-first; } + Super+Ctrl+L { focus-column-last; } + Super+Ctrl+Shift+H { move-column-to-first; } + Super+Ctrl+Shift+L { move-column-to-last; } + + // Tabs + Mod+W { toggle-column-tabbed-display; } + Mod+Shift+H { spawn "/home/prad/.local/bin/niri-smart-move" "left"; } + Mod+Shift+L { spawn "/home/prad/.local/bin/niri-smart-move" "right"; } + + // Screenshots (native) + Print { screenshot; } + Ctrl+Print { screenshot-screen; } + Alt+Print { screenshot-window; } + + // ======================================================================== + // HARDWARE KEYS - Audio, Brightness, Media + // ======================================================================== + // These use noctalia IPC so the OSD (On Screen Display) shows feedback + + Mod+F24 { spawn "voxtype" "record" "toggle" "--profile" "hermes"; } + + // ─── Media Controls ─── + // v4: XF86AudioRaiseVolume allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call volume increase"; } + // v4: XF86AudioLowerVolume allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call volume decrease"; } + // v4: XF86AudioMute allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call volume muteOutput"; } + // v4: XF86AudioMicMute allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call volume muteInput"; } + // v4: XF86AudioNext allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call media next"; } + // v4: XF86AudioPrev allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call media previous"; } + // v4: XF86AudioPlay allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call media playPause"; } + // v4: XF86AudioPause allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call media playPause"; } + XF86AudioRaiseVolume allow-when-locked=true { spawn-sh "noctalia msg volume-up"; } + XF86AudioLowerVolume allow-when-locked=true { spawn-sh "noctalia msg volume-down"; } + XF86AudioMute allow-when-locked=true { spawn-sh "noctalia msg volume-mute"; } + XF86AudioMicMute allow-when-locked=true { spawn-sh "noctalia msg mic-mute"; } + XF86AudioNext allow-when-locked=true { spawn-sh "noctalia msg media next"; } + XF86AudioPrev allow-when-locked=true { spawn-sh "noctalia msg media previous"; } + XF86AudioPlay allow-when-locked=true { spawn-sh "noctalia msg media toggle"; } + XF86AudioPause allow-when-locked=true { spawn-sh "noctalia msg media toggle"; } + + // ─── Brightness Controls ─── + // v4: XF86MonBrightnessUp allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call brightness increase"; } + // v4: XF86MonBrightnessDown allow-when-locked=true { spawn-sh "qs -c noctalia-shell ipc call brightness decrease"; } + XF86MonBrightnessUp allow-when-locked=true { spawn-sh "noctalia msg brightness-up"; } + XF86MonBrightnessDown allow-when-locked=true { spawn-sh "noctalia msg brightness-down"; } + + // Power / Session + // v4: Mod+Shift+Q { spawn-sh "qs -c noctalia-shell ipc call sessionMenu toggle"; } + Mod+Shift+Q hotkey-overlay-title="Session Menu: noctalia session" { spawn-sh "noctalia msg panel-toggle session"; } + +} + + diff --git a/dot_config/niri/exact_config.d/80-layer-rules.kdl b/dot_config/niri/exact_config.d/80-layer-rules.kdl new file mode 100644 index 0000000..fee5ce8 --- /dev/null +++ b/dot_config/niri/exact_config.d/80-layer-rules.kdl @@ -0,0 +1,34 @@ + + + +/* + Noctalia v5: disable xray on all our surfaces so blur looks more realistic. + Noctalia publishes blur regions automatically when ext-background-effects is available. +*/ +layer-rule { + match namespace="^noctalia-(bar-[^\"]+|notification|dock|panel|attached-panel|osd)$" + background-effect { + xray false + //blur false + } +} + +// Option 2 (Stationary Wallpaper): place the regular wallpaper on the backdrop. +layer-rule { + match namespace="^noctalia-wallpaper" + place-within-backdrop true +} + +// Set transparent workspace background color so you see the backdrop at all times. +layout { + background-color "transparent" +} + +// Optionally, disable the workspace shadows in the overview. +overview { + workspace-shadow { + off + } +} + + diff --git a/dot_config/niri/exact_config.d/90-outputs.kdl b/dot_config/niri/exact_config.d/90-outputs.kdl new file mode 100644 index 0000000..c5bf0c2 --- /dev/null +++ b/dot_config/niri/exact_config.d/90-outputs.kdl @@ -0,0 +1,47 @@ +// ============================================================================ +// OUTPUTS +// ============================================================================ +// +// // Apple Display +// output "Apple Computer Inc StudioDisplay 0x984262A7" { +// position x=0 y=0 +// scale 1.5 +// layout { +// center-focused-column "never" +// always-center-single-column true +// gaps 8 +// default-column-width { +// proportion 0.75 +// } +// preset-column-widths { +// proportion 0.25 +// proportion 0.5 +// proportion 0.75 +// } +// } +// } +// +// +// +// output "DP-5" { +// off +// } +// +// +output "DP-4" { + off +} +// ============================================================================ +// OUTPUTS +// ============================================================================ +// The Studio Display exposes a phantom second connector (DP-4/5/6, varies per +// boot) whose only mode is 640x480. Connector name and EDID both shift, so it +// can't be matched in config — this script finds it by mode signature instead. +// spawn-at-startup "/home/prad/.config/niri/scripts/kill-phantom-display.fish" + + +include "91-internal-display.kdl" +// include "92-ultrawide.kdl" +include "93-apple-display.kdl" +include "94-portable-hdmi.kdl" +// include "95-portable-usbc.kdl" diff --git a/dot_config/niri/exact_config.d/91-internal-display.kdl b/dot_config/niri/exact_config.d/91-internal-display.kdl new file mode 100644 index 0000000..43d7a37 --- /dev/null +++ b/dot_config/niri/exact_config.d/91-internal-display.kdl @@ -0,0 +1,32 @@ + +// Internal Display +output "Tianma Microelectronics Ltd. TL134ADXP03 Unknown" { + position x=1920 y=0 + scale 1.5 + variable-refresh-rate on-demand=true + layout { + always-center-single-column true + center-focused-column "never" + gaps 8 + default-column-width { proportion 0.9; } + preset-column-widths { + proportion 0.5 + proportion 1.0 + } + } +} + +workspace "1" { + open-on-output "Tianma Microelectronics Ltd. TL134ADXP03 Unknown" +} + +window-rule { + match app-id="org.gnome.Calendar" + match app-id="discord" + match app-id="slack" + draw-border-with-background false + + open-focused true + open-maximized true + open-on-workspace "1" +} diff --git a/dot_config/niri/exact_config.d/92-ultrawide.kdl b/dot_config/niri/exact_config.d/92-ultrawide.kdl new file mode 100644 index 0000000..777249d --- /dev/null +++ b/dot_config/niri/exact_config.d/92-ultrawide.kdl @@ -0,0 +1,24 @@ +// ============================================================================ +// OUTPUTS +// ============================================================================ + +output "Samsung Electric Company S34CG50 HNTY501103" { + position x=0 y=0 + mode "3440x1440@100.00" + scale 1 + variable-refresh-rate on-demand=true + layout { + center-focused-column "never" + always-center-single-column true + gaps 16 + default-column-width { + proportion 0.3333 + } + preset-column-widths { + proportion 0.3333 + proportion 0.5 + proportion 0.6667 + } + } +} + diff --git a/dot_config/niri/exact_config.d/93-apple-display.kdl b/dot_config/niri/exact_config.d/93-apple-display.kdl new file mode 100644 index 0000000..8a77ebe --- /dev/null +++ b/dot_config/niri/exact_config.d/93-apple-display.kdl @@ -0,0 +1,24 @@ +// ============================================================================ +// OUTPUTS +// ============================================================================ + +// Apple Display +output "Apple Computer Inc StudioDisplay 0x984262A7" { + position x=0 y=0 + scale 1.5 + layout { + center-focused-column "never" + always-center-single-column true + gaps 8 + default-column-width { + proportion 0.5 + } + preset-column-widths { + proportion 0.25 + proportion 0.3333 + proportion 0.5 + proportion 0.6667 + } + } +} + diff --git a/dot_config/niri/exact_config.d/94-portable-hdmi.kdl b/dot_config/niri/exact_config.d/94-portable-hdmi.kdl new file mode 100644 index 0000000..321c925 --- /dev/null +++ b/dot_config/niri/exact_config.d/94-portable-hdmi.kdl @@ -0,0 +1,22 @@ +// ============================================================================ +// OUTPUTS +// ============================================================================ + +// Portable Display #1 +output "PNP(AOP) 16PM1QB 14490001D3X00" { + transform "90" + layout { + always-center-single-column true + center-focused-column "never" + gaps 2 + default-column-width { + proportion 1.0 + } + preset-column-widths { + proportion 0.5 + proportion 1.0 + } + } +} + + diff --git a/dot_config/niri/exact_config.d/95-portable-usbc.kdl b/dot_config/niri/exact_config.d/95-portable-usbc.kdl new file mode 100644 index 0000000..2c1c831 --- /dev/null +++ b/dot_config/niri/exact_config.d/95-portable-usbc.kdl @@ -0,0 +1,20 @@ +// ============================================================================ +// OUTPUTS +// ============================================================================ + +output "ASUSTek COMPUTER INC ASUS MB16AC M8LMTF195749" { + position x=0 y=0 + layout { + always-center-single-column true + center-focused-column "never" + gaps 2 + default-column-width { + proportion 1.0 + } + preset-column-widths { + proportion 0.5 + proportion 1.0 + } + } +} + diff --git a/dot_config/niri/noctalia.kdl b/dot_config/niri/noctalia.kdl new file mode 100644 index 0000000..28d5427 --- /dev/null +++ b/dot_config/niri/noctalia.kdl @@ -0,0 +1,35 @@ +layout { + + focus-ring { + active-color "#a398b3" + inactive-color "#1e1c21" + urgent-color "#fd4663" + } + + border { + active-color "#a398b3" + inactive-color "#1e1c21" + urgent-color "#fd4663" + } + + shadow { + color "#1e1c2170" + } + + tab-indicator { + active-color "#a398b3" + inactive-color "#4a4158" + urgent-color "#fd4663" + } + + insert-hint { + color "#a398b380" + } +} + +recent-windows { + highlight { + active-color "#a398b3" + urgent-color "#fd4663" + } +} diff --git a/dot_config/niri/scripts/executable_kill-phantom-display.fish b/dot_config/niri/scripts/executable_kill-phantom-display.fish new file mode 100755 index 0000000..aecb043 --- /dev/null +++ b/dot_config/niri/scripts/executable_kill-phantom-display.fish @@ -0,0 +1,20 @@ +#!/usr/bin/env fish +# Turn off the phantom Studio Display leg (DP-4/5/6, varies per boot). +# Its signature is a single 640x480 mode — connector name and EDID are unreliable. +# ponytail: one-shot with retry at startup; doesn't handle mid-session hotplug — +# switch to a `niri msg event-stream` watcher if that starts biting. +for i in (seq 10) + set -l phantoms (niri msg -j outputs 2>/dev/null | jq -r ' + to_entries[] + | select((.value.modes | length) == 1 + and .value.modes[0].width == 640 + and .value.modes[0].height == 480) + | .key') + if test -n "$phantoms" + for out in $phantoms + niri msg output $out off + end + exit 0 + end + sleep 1 +end diff --git a/dot_config/niri/scripts/executable_ndw-route-workspace.sh b/dot_config/niri/scripts/executable_ndw-route-workspace.sh new file mode 100755 index 0000000..0e76e78 --- /dev/null +++ b/dot_config/niri/scripts/executable_ndw-route-workspace.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# ndw-route-workspace.sh +# Routes a niri-dynamic-workspaces workspace to the correct monitor by +# resolving the Apple Studio Display's connector at runtime. +# +# Inputs: NDW_WORKSPACE_KEY env var (set by ndw on_create), or $1. +# Exits silently on unknown keys so it's safe to call for all workspaces. + +set -euo pipefail + +KEY="${NDW_WORKSPACE_KEY:-${1:-}}" +[ -z "$KEY" ] && exit 0 + +INTERNAL="HDMI-A-1" + +# Resolve the external Apple Studio Display connector. +# Match by make+model; fall back to eDP-1 if not currently connected. +resolve_external() { + niri msg --json outputs | jq -r ' + to_entries + | map(select( + .value.make == "Apple Computer Inc" + and .value.model == "StudioDisplay" + )) + | .[0].key // empty + ' +} + +case "$KEY" in + y|g|m|x|z|p|l|a) + target="$INTERNAL" + ;; + b|f|s|w|c|d|o) + target="$(resolve_external)" + [ -z "$target" ] && target="$INTERNAL" # external not connected + ;; + *) + exit 0 + ;; +esac + +exec niri msg action move-workspace-to-monitor "$target" diff --git a/dot_config/niri/scripts/executable_niri-floating-sidebar.sh b/dot_config/niri/scripts/executable_niri-floating-sidebar.sh new file mode 100755 index 0000000..c4900be --- /dev/null +++ b/dot_config/niri/scripts/executable_niri-floating-sidebar.sh @@ -0,0 +1,367 @@ +#!/usr/bin/env bash +set -euo pipefail + +#============================================================================= +# Niri Sidebar Manager +#============================================================================= +# This script manages floating windows in the Niri window manager, +# organizing them into a toggleable sidebar. +#============================================================================= + +### --- DIMENSION SETTINGS --- ### +readonly WIN_W=550 # Floating window width +readonly BASE_SLOTS=4 # Default number of slots in the sidebar +readonly GAP_BETWEEN=15 # Gap between windows +readonly BOTTOM_MARGIN=50 # Bottom screen margin +readonly TOP_MARGIN=30 # Top screen margin +readonly SIDE_MARGIN=20 # Side screen margin +readonly VISIBLE_SLIVER=70 # Pixels visible when sidebar is hidden + +### --- STATE FILES --- ### +# Get current workspace ID +WORKSPACE_ID=$(niri msg --json workspaces | jq -r '.[] | select(.is_focused).id') + +# File paths for state tracking +readonly FLAG_FILE="/tmp/niri.toggle.${WORKSPACE_ID}.floating" +readonly STATE_FILE="/tmp/niri.toggle.${WORKSPACE_ID}.state" +readonly ORDER_STATE_FILE="/tmp/niri.toggle.${WORKSPACE_ID}.order" +readonly HIDE_STATE_FILE="/tmp/niri.toggle.${WORKSPACE_ID}.hide_state" + +### --- SCREEN INFO --- ### +readonly SCREEN_W=$(niri msg --json outputs | jq -r 'to_entries[0].value.logical.width') +readonly SCREEN_H=$(niri msg --json outputs | jq -r 'to_entries[0].value.logical.height') + +#============================================================================= +# FUNCTION: get_focused_window +# Description: Returns JSON info of the currently focused window +#============================================================================= +get_focused_window() { + niri msg --json windows | jq -r '.[] | select(.is_focused)' +} + +#============================================================================= +# FUNCTION: ensure_files_exist +# Description: Creates necessary state files if they don't exist +#============================================================================= +ensure_files_exist() { + touch "$FLAG_FILE" "$STATE_FILE" "$HIDE_STATE_FILE" "$ORDER_STATE_FILE" + + if [ ! -s "$HIDE_STATE_FILE" ]; then + echo "visible" >"$HIDE_STATE_FILE" + fi + + if [ ! -s "$ORDER_STATE_FILE" ]; then + echo "bottom-up" >"$ORDER_STATE_FILE" + fi +} + +#============================================================================= +# FUNCTION: get_floating_windows +# Description: Gets a list of floating window IDs in the current workspace +#============================================================================= +get_floating_windows() { + niri msg --json windows | + jq -r ".[] | select(.is_floating==true and .workspace_id==$WORKSPACE_ID) | .id" +} + +#============================================================================= +# FUNCTION: cleanup_state_file +# Description: Removes closed windows from the state file +# Parameters: +# $1 - List of currently active floating windows +#============================================================================= +cleanup_state_file() { + local actual_floating="$1" + + if [ ! -s "$STATE_FILE" ]; then + return + fi + + local tmp_state + tmp_state=$(mktemp) + + while IFS= read -r line; do + local id_in_file + id_in_file=$(echo "$line" | cut -d: -f1) + + if echo "$actual_floating" | grep -q "^${id_in_file}$"; then + echo "$line" >>"$tmp_state" + fi + done <"$STATE_FILE" + + mv "$tmp_state" "$STATE_FILE" +} + +#============================================================================= +# FUNCTION: calculate_window_dimensions +# Description: Calculates dynamic window height and X position +# Parameters: +# $1 - Window count +# Returns: Sets WIN_H and X global variables +#============================================================================= +calculate_window_dimensions() { + local count="$1" + local slots="$BASE_SLOTS" + + # Increase slots if window count exceeds default + if [ "$count" -gt "$BASE_SLOTS" ]; then + slots="$count" + fi + + # Calculate available vertical space + local total_gaps_space=$(((slots - 1) * GAP_BETWEEN)) + local available_h=$((SCREEN_H - TOP_MARGIN - BOTTOM_MARGIN - total_gaps_space)) + + # Export calculated dimensions + WIN_H=$((available_h / slots)) + X=$((SCREEN_W - WIN_W - SIDE_MARGIN)) +} + +#============================================================================= +# FUNCTION: position_window +# Description: Moves and resizes a specific window +# Parameters: +# $1 - Window ID +# $2 - X position +# $3 - Y position +#============================================================================= +position_window() { + local id="$1" + local x="$2" + local y="$3" + + niri msg action set-window-width "$WIN_W" --id "$id" 2>/dev/null || true + niri msg action set-window-height "$WIN_H" --id "$id" 2>/dev/null || true + niri msg action move-floating-window --id "$id" --x "$x" --y "$y" 2>/dev/null || true +} + +#============================================================================= +# FUNCTION: reorder_sidebar +# Description: Syncs state and updates all window positions on screen +#============================================================================= +reorder_sidebar() { + local actual_floating + actual_floating=$(get_floating_windows) + + cleanup_state_file "$actual_floating" + + local sorted_ids + sorted_ids=$(grep -Ff <(echo "$actual_floating") "$STATE_FILE" 2>/dev/null | cut -d: -f1 || true) + + local count + count=$(echo "$sorted_ids" | grep -c . || echo 0) + + if [ "$count" -eq 0 ]; then + >"$FLAG_FILE" + echo "visible" >"$HIDE_STATE_FILE" + return + fi + + calculate_window_dimensions "$count" + + local order + order=$(cat "$ORDER_STATE_FILE" 2>/dev/null || echo "bottom-up") + + >"$FLAG_FILE" + local index=0 + + while IFS= read -r id; do + [ -z "$id" ] && continue + + local pos_y + if [ "$order" = "top-down" ]; then + pos_y=$((TOP_MARGIN + index * (WIN_H + GAP_BETWEEN))) + else + pos_y=$((SCREEN_H - BOTTOM_MARGIN - WIN_H - index * (WIN_H + GAP_BETWEEN))) + fi + + position_window "$id" "$X" "$pos_y" + echo "${id}:${X}:${pos_y}" >>"$FLAG_FILE" + + index=$((index + 1)) + done <<<"$sorted_ids" + + echo "visible" >"$HIDE_STATE_FILE" +} + +#============================================================================= +# FUNCTION: toggle_float +# Description: Toggles focused window between sidebar and tiling mode +#============================================================================= +toggle_float() { + local focused_json + focused_json=$(get_focused_window) + + local focused_id + focused_id=$(echo "$focused_json" | jq -r '.id') + + if [ -z "$focused_id" ] || [ "$focused_id" = "null" ]; then + echo "Error: No focused window" + return 1 + fi + + if grep -q "^$focused_id:" "$STATE_FILE" 2>/dev/null; then + # Restore to tiling mode + local old_dim + old_dim=$(grep "^$focused_id:" "$STATE_FILE") + + local old_w old_h + old_w=$(echo "$old_dim" | cut -d: -f2) + old_h=$(echo "$old_dim" | cut -d: -f3) + + # Remove from state + sed -i "/^$focused_id:/d" "$STATE_FILE" + + # Action: Move to tiling + niri msg action move-window-to-tiling + + # Restore original dimensions + [ "$old_w" != "null" ] && niri msg action set-column-width "$old_w" 2>/dev/null || true + [ "$old_h" != "null" ] && niri msg action set-window-height "$old_h" 2>/dev/null || true + + reorder_sidebar + echo "✓ Window removed from sidebar" + else + # Add to sidebar + local orig_w orig_h + orig_w=$(echo "$focused_json" | jq -r '.layout.window_size[0] // 800') + orig_h=$(echo "$focused_json" | jq -r '.layout.window_size[1] // 600') + + # Save original size + echo "$focused_id:$orig_w:$orig_h" >>"$STATE_FILE" + + # Action: Move to floating + niri msg action move-window-to-floating + + # Refresh sidebar + reorder_sidebar + + # Keep focus on the window + niri msg action focus-window --id "$focused_id" 2>/dev/null || true + + echo "✓ Window added to sidebar" + fi +} + +#============================================================================= +# FUNCTION: toggle_hide +# Description: Hides/Shows the entire sidebar by pushing windows off-screen +#============================================================================= +toggle_hide() { + + # Save current hide state + local previous_state + previous_state=$(cat "$HIDE_STATE_FILE" 2>/dev/null || echo "visible") + + # Reorder sidebar to fix any desync without breaking hide/show state + local actual_floating + actual_floating=$(get_floating_windows) + + if [ -n "$actual_floating" ]; then + reorder_sidebar + # reorder_sidebar forces visible, restore previous state + echo "$previous_state" >"$HIDE_STATE_FILE" + fi + + if [ ! -s "$FLAG_FILE" ]; then + echo "No floating windows detected" + return 0 + fi + + local current_state + current_state=$(cat "$HIDE_STATE_FILE") + + if [ "$current_state" = "visible" ]; then + # Hide: push windows off-screen + while IFS=: read -r id x y; do + [ -z "$id" ] && continue + local new_x=$((SCREEN_W - VISIBLE_SLIVER)) + niri msg action move-floating-window --id "$id" --x "$new_x" --y "$y" 2>/dev/null || true + done <"$FLAG_FILE" + + echo "hidden" >"$HIDE_STATE_FILE" + echo "✓ Sidebar hidden" + else + # Show: restore original positions + while IFS=: read -r id x y; do + [ -z "$id" ] && continue + niri msg action move-floating-window --id "$id" --x "$x" --y "$y" 2>/dev/null || true + done <"$FLAG_FILE" + + echo "visible" >"$HIDE_STATE_FILE" + echo "✓ Sidebar visible" + fi +} + +#============================================================================= +# FUNCTION: flip_sidebar_order +# Description: Flip the order of the sidebar +#============================================================================= + +flip_sidebar_order() { + local current + current=$(cat "$ORDER_STATE_FILE" 2>/dev/null || echo "bottom-up") + + if [ "$current" = "bottom-up" ]; then + echo "top-down" >"$ORDER_STATE_FILE" + else + echo "bottom-up" >"$ORDER_STATE_FILE" + fi + + reorder_sidebar + echo "✓ Sidebar order flipped" +} + +#============================================================================= +# FUNCTION: show_usage +# Description: Displays help information +#============================================================================= +show_usage() { + cat </dev/null 2>&1 || true +[ "$(win)" != "$w0" ] && exit 0 + +# 2) occupied workspace in that direction (skip the empty trailing one) +wss=$(niri msg --json workspaces) +wins=$(niri msg --json windows) +cwsid=$(jq -r 'map(select(.is_focused)) | .[0].id' <<<"$wss") +real_neighbor=$(jq -n --argjson wss "$wss" --argjson wins "$wins" \ + --argjson cwsid "$cwsid" --arg dir "$dir" ' + ($wss[] | select(.id==$cwsid)) as $c + | [ $wss[] + | select(.output==$c.output) + | select(if $dir=="down" then .idx>$c.idx else .idx<$c.idx end) + | .id as $wid + | select([$wins[] | select(.workspace_id==$wid)] | length > 0) ] + | length > 0') + +if [ "$real_neighbor" = "true" ]; then + niri msg action "focus-workspace-$dir" >/dev/null 2>&1 || true + exit 0 +fi + +# 3) adjacent monitor… or wrap to the far-end monitor +o0=$(out); niri msg action "focus-monitor-$dir" >/dev/null 2>&1 || true +[ "$(out)" != "$o0" ] && exit 0 +while :; do + prev=$(out) + niri msg action "focus-monitor-$opp" >/dev/null 2>&1 || true + [ "$(out)" = "$prev" ] && break +done diff --git a/dot_config/niri/scripts/executable_niri-move.sh b/dot_config/niri/scripts/executable_niri-move.sh new file mode 100755 index 0000000..e279201 --- /dev/null +++ b/dot_config/niri/scripts/executable_niri-move.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# Cascade move: column → workspace (incl. empty trailing) → monitor (cycles) +# usage: niri-move.sh up|down +set -euo pipefail +dir="${1:?usage: niri-move.sh up|down}" +opp=$([ "$dir" = down ] && echo up || echo down) + +cur=$(niri msg --json focused-window) +[ "$cur" = "null" ] && exit 0 + +out() { niri msg --json focused-output | jq -r '.name // "none"'; } +sig() { niri msg --json focused-window | jq -rc '[.workspace_id, (.layout.pos_in_scrolling_layout // null)]'; } + +# 1) reorder within the column +s0=$(sig); niri msg action "move-window-$dir" >/dev/null 2>&1 || true +[ "$(sig)" != "$s0" ] && exit 0 + +# 2) workspace in that direction (including the empty trailing one) +s0=$(sig); niri msg action "move-window-to-workspace-$dir" >/dev/null 2>&1 || true +[ "$(sig)" != "$s0" ] && exit 0 + +# 3) adjacent monitor… or wrap to the far-end monitor +o0=$(out); niri msg action "move-window-to-monitor-$dir" >/dev/null 2>&1 || true +[ "$(out)" != "$o0" ] && exit 0 +while :; do + prev=$(out) + niri msg action "move-window-to-monitor-$opp" >/dev/null 2>&1 || true + [ "$(out)" = "$prev" ] && break +done diff --git a/dot_config/noctalia/colors.json b/dot_config/noctalia/colors.json new file mode 100644 index 0000000..285aa4b --- /dev/null +++ b/dot_config/noctalia/colors.json @@ -0,0 +1,25 @@ +{ + "mPrimary": "#a398b3", + "mOnPrimary": "#100f13", + + "mSecondary": "#9c8da5", + "mOnSecondary": "#1e1c22", + + "mTertiary": "#a18fa3", + "mOnTertiary": "#1e1c22", + + "mError": "#fd4663", + "mOnError": "#1e1c22", + + "mSurface": "#1e1c21", + "mOnSurface": "#f2f2f3", + + "mSurfaceVariant": "#322f37", + "mOnSurfaceVariant": "#b2b0b5", + + "mOutline": "#6a6670", + "mShadow": "#1e1c21", + + "mHover": "#a18fa3", + "mOnHover": "#1e1c22" +} \ No newline at end of file diff --git a/dot_config/noctalia/colorschemes/Monochrome/Monochrome.json b/dot_config/noctalia/colorschemes/Monochrome/Monochrome.json new file mode 100644 index 0000000..ed065e2 --- /dev/null +++ b/dot_config/noctalia/colorschemes/Monochrome/Monochrome.json @@ -0,0 +1,94 @@ +{ + "dark": { + "mPrimary": "#aaaaaa", + "mOnPrimary": "#111111", + "mSecondary": "#a7a7a7", + "mOnSecondary": "#111111", + "mTertiary": "#cccccc", + "mOnTertiary": "#111111", + "mError": "#dddddd", + "mOnError": "#111111", + "mSurface": "#111111", + "mOnSurface": "#828282", + "mSurfaceVariant": "#191919", + "mOnSurfaceVariant": "#5d5d5d", + "mOutline": "#3c3c3c", + "mShadow": "#000000", + "mHover": "#cccccc", + "mOnHover": "#111111", + "terminal": { + "foreground": "#828282", + "background": "#111111", + "selectionFg": "#111111", + "selectionBg": "#828282", + "cursorText": "#111111", + "cursor": "#aaaaaa", + "normal": { + "black": "#191919", + "red": "#dddddd", + "green": "#cccccc", + "yellow": "#aaaaaa", + "blue": "#a7a7a7", + "magenta": "#dddddd", + "cyan": "#cccccc", + "white": "#828282" + }, + "bright": { + "black": "#3c3c3c", + "red": "#dddddd", + "green": "#cccccc", + "yellow": "#aaaaaa", + "blue": "#a7a7a7", + "magenta": "#dddddd", + "cyan": "#cccccc", + "white": "#ffffff" + } + } + }, + "light": { + "mPrimary": "#555555", + "mOnPrimary": "#eeeeee", + "mSecondary": "#505058", + "mOnSecondary": "#eeeeee", + "mTertiary": "#333333", + "mOnTertiary": "#eeeeee", + "mError": "#222222", + "mOnError": "#efefef", + "mSurface": "#d4d4d4", + "mOnSurface": "#696969", + "mSurfaceVariant": "#e8e8e8", + "mOnSurfaceVariant": "#9e9e9e", + "mOutline": "#c3c3c3", + "mShadow": "#fafafa", + "mHover": "#333333", + "mOnHover": "#eeeeee", + "terminal": { + "foreground": "#696969", + "background": "#d4d4d4", + "selectionFg": "#d4d4d4", + "selectionBg": "#696969", + "cursorText": "#d4d4d4", + "cursor": "#555555", + "normal": { + "black": "#e8e8e8", + "red": "#222222", + "green": "#333333", + "yellow": "#555555", + "blue": "#505058", + "magenta": "#222222", + "cyan": "#333333", + "white": "#696969" + }, + "bright": { + "black": "#c3c3c3", + "red": "#222222", + "green": "#333333", + "yellow": "#555555", + "blue": "#505058", + "magenta": "#222222", + "cyan": "#333333", + "white": "#000000" + } + } + } +} diff --git a/dot_config/noctalia/palettes/wallhaven-k81776-vib.json b/dot_config/noctalia/palettes/wallhaven-k81776-vib.json new file mode 100644 index 0000000..1bb3a44 --- /dev/null +++ b/dot_config/noctalia/palettes/wallhaven-k81776-vib.json @@ -0,0 +1,94 @@ +{ + "dark": { + "mPrimary": "#ef5ce9", + "mOnPrimary": "#0c070b", + "mSecondary": "#ed4592", + "mOnSecondary": "#251824", + "mTertiary": "#ed4c45", + "mOnTertiary": "#251824", + "mError": "#fd4663", + "mOnError": "#251824", + "mSurface": "#291428", + "mOnSurface": "#f3f2f3", + "mSurfaceVariant": "#452143", + "mOnSurfaceVariant": "#b6afb6", + "mOutline": "#756073", + "mShadow": "#291428", + "mHover": "#ed4c45", + "mOnHover": "#251824", + "terminal": { + "normal": { + "black": "#371b36", + "red": "#fd4663", + "green": "#ef5ce9", + "yellow": "#ed4592", + "blue": "#ed4c45", + "magenta": "#f48bef", + "cyan": "#f48bbb", + "white": "#f3f2f3" + }, + "bright": { + "black": "#756073", + "red": "#fd4663", + "green": "#ef5ce9", + "yellow": "#ed4592", + "blue": "#ed4c45", + "magenta": "#f48bef", + "cyan": "#f48bbb", + "white": "#f3f2f3" + }, + "foreground": "#f3f2f3", + "background": "#291428", + "cursor": "#f3f2f3", + "cursorText": "#291428", + "selectionFg": "#b6afb6", + "selectionBg": "#371b36" + } + }, + "light": { + "mPrimary": "#d114c9", + "mOnPrimary": "#faf9fa", + "mSecondary": "#ba125f", + "mOnSecondary": "#faf9fa", + "mTertiary": "#a31610", + "mOnTertiary": "#faf9fa", + "mError": "#fd4663", + "mOnError": "#faf9fa", + "mSurface": "#fbd0f9", + "mOnSurface": "#1b181b", + "mSurfaceVariant": "#f8bff5", + "mOnSurfaceVariant": "#50484f", + "mOutline": "#a569a3", + "mShadow": "#d9bfd8", + "mHover": "#a31610", + "mOnHover": "#faf9fa", + "terminal": { + "normal": { + "black": "#f49af0", + "red": "#fd4663", + "green": "#d114c9", + "yellow": "#ba125f", + "blue": "#a31610", + "magenta": "#8c0d86", + "cyan": "#8c0d47", + "white": "#1b181b" + }, + "bright": { + "black": "#b061ad", + "red": "#fd4663", + "green": "#d114c9", + "yellow": "#ba125f", + "blue": "#a31610", + "magenta": "#8c0d86", + "cyan": "#8c0d47", + "white": "#1b181b" + }, + "foreground": "#1b181b", + "background": "#fbd0f9", + "cursor": "#1b181b", + "cursorText": "#fbd0f9", + "selectionFg": "#50484f", + "selectionBg": "#f49af0" + } + } +} \ No newline at end of file diff --git a/dot_config/noctalia/plugins.json b/dot_config/noctalia/plugins.json new file mode 100644 index 0000000..5d49da2 --- /dev/null +++ b/dot_config/noctalia/plugins.json @@ -0,0 +1,32 @@ +{ + "sources": [ + { + "enabled": true, + "name": "Noctalia Plugins", + "url": "https://github.com/noctalia-dev/noctalia-plugins" + } + ], + "states": { + "github-feed": { + "enabled": true, + "sourceUrl": "https://github.com/noctalia-dev/noctalia-plugins" + }, + "habitica": { + "enabled": true, + "sourceUrl": "https://github.com/noctalia-dev/noctalia-plugins" + }, + "kde-connect": { + "enabled": true, + "sourceUrl": "https://github.com/noctalia-dev/noctalia-plugins" + }, + "khal-agenda-widget": { + "enabled": true, + "sourceUrl": "https://github.com/noctalia-dev/noctalia-plugins" + }, + "weather-indicator": { + "enabled": true, + "sourceUrl": "https://github.com/noctalia-dev/noctalia-plugins" + } + }, + "version": 2 +} diff --git a/dot_config/noctalia/settings.json b/dot_config/noctalia/settings.json new file mode 100644 index 0000000..ba49f0e --- /dev/null +++ b/dot_config/noctalia/settings.json @@ -0,0 +1,904 @@ +{ + "appLauncher": { + "autoPasteClipboard": false, + "clipboardWatchImageCommand": "wl-paste --type image --watch cliphist store", + "clipboardWatchTextCommand": "wl-paste --type text --watch cliphist store", + "clipboardWrapText": true, + "customLaunchPrefix": "", + "customLaunchPrefixEnabled": false, + "density": "default", + "enableClipPreview": true, + "enableClipboardChips": true, + "enableClipboardHistory": false, + "enableClipboardSmartIcons": true, + "enableSessionSearch": true, + "enableSettingsSearch": true, + "enableWindowsSearch": true, + "iconMode": "tabler", + "ignoreMouseInput": false, + "overviewLayer": true, + "pinnedApps": [ + ], + "position": "center", + "screenshotAnnotationTool": "", + "showCategories": true, + "showIconBackground": false, + "sortByMostUsed": true, + "terminalCommand": "alacritty -e", + "viewMode": "list" + }, + "audio": { + "mprisBlacklist": [ + ], + "preferredPlayer": "", + "spectrumFrameRate": 30, + "spectrumMirrored": true, + "visualizerType": "linear", + "volumeFeedback": false, + "volumeFeedbackSoundFile": "", + "volumeOverdrive": false, + "volumeStep": 5 + }, + "bar": { + "autoHideDelay": 500, + "autoShowDelay": 150, + "backgroundOpacity": 0.71, + "barType": "simple", + "capsuleColorKey": "none", + "capsuleOpacity": 1, + "contentPadding": 2, + "density": "default", + "displayMode": "always_visible", + "enableExclusionZoneInset": true, + "fontScale": 1, + "frameRadius": 8, + "frameThickness": 8, + "hideOnOverview": true, + "marginHorizontal": 4, + "marginVertical": 4, + "middleClickAction": "settings", + "middleClickCommand": "", + "middleClickFollowMouse": false, + "monitors": [ + "DP-5", + "DP-4", + "DP-1", + "eDP-1" + ], + "mouseWheelAction": "volume", + "mouseWheelWrap": true, + "outerCorners": false, + "position": "top", + "reverseScroll": false, + "rightClickAction": "controlCenter", + "rightClickCommand": "", + "rightClickFollowMouse": true, + "screenOverrides": [ + { + "enabled": false, + "name": "DP-4" + }, + { + "density": "mini", + "displayMode": "auto_hide", + "enabled": true, + "name": "eDP-1", + "position": "top" + }, + { + "density": "mini", + "enabled": true, + "name": "HDMI-A-1", + "position": "right", + "widgets": { + "center": [ + { + "compactMode": false, + "diskPath": "/", + "iconColor": "none", + "id": "SystemMonitor", + "showCpuCores": true, + "showCpuFreq": false, + "showCpuTemp": false, + "showCpuUsage": true, + "showDiskAvailable": false, + "showDiskUsage": true, + "showDiskUsageAsPercent": true, + "showGpuTemp": false, + "showLoadAverage": false, + "showMemoryAsPercent": true, + "showMemoryUsage": true, + "showNetworkStats": false, + "showSwapUsage": false, + "textColor": "none", + "useMonospaceFont": true, + "usePadding": false + } + ], + "left": [ + { + "clockColor": "none", + "customFont": "", + "formatHorizontal": "HH:mm ddd, MMM dd", + "formatVertical": "HH mm - dd MM", + "id": "Clock", + "tooltipFormat": "HH:mm ddd, MMM dd", + "useCustomFont": false + } + ], + "right": [ + { + "characterCount": 2, + "colorizeIcons": true, + "emptyColor": "secondary", + "enableScrollWheel": true, + "focusedColor": "primary", + "followFocusedScreen": false, + "fontWeight": "semibold", + "groupedBorderOpacity": 1, + "hideUnoccupied": true, + "iconScale": 0.8, + "id": "Workspace", + "labelMode": "none", + "occupiedColor": "secondary", + "pillSize": 0.6, + "showApplications": true, + "showApplicationsHover": false, + "showBadge": true, + "showLabelsOnlyWhenOccupied": true, + "unfocusedIconsOpacity": 1 + }, + { + "id": "plugin:habitica" + }, + { + "id": "plugin:github-feed" + }, + { + "id": "plugin:kde-connect" + } + ] + } + } + ], + "showCapsule": false, + "showOnWorkspaceSwitch": true, + "showOutline": false, + "useSeparateOpacity": false, + "widgetSpacing": 6, + "widgets": { + "center": [ + { + "defaultSettings": { + "customColor": "none", + "showConditionIcon": true, + "showTempUnit": true, + "showTempValue": true, + "tooltipOption": "everything" + }, + "id": "plugin:weather-indicator" + }, + { + "characterCount": 2, + "colorizeIcons": true, + "emptyColor": "secondary", + "enableScrollWheel": true, + "focusedColor": "primary", + "followFocusedScreen": false, + "fontWeight": "bold", + "groupedBorderOpacity": 1, + "hideUnoccupied": true, + "iconScale": 0.8, + "id": "Workspace", + "labelMode": "none", + "occupiedColor": "secondary", + "pillSize": 0.6, + "showApplications": true, + "showApplicationsHover": true, + "showBadge": true, + "showLabelsOnlyWhenOccupied": true, + "unfocusedIconsOpacity": 1 + }, + { + "compactMode": true, + "hideMode": "hidden", + "hideWhenIdle": false, + "id": "MediaMini", + "maxWidth": 145, + "panelShowAlbumArt": true, + "scrollingMode": "hover", + "showAlbumArt": true, + "showArtistFirst": false, + "showProgressRing": true, + "showVisualizer": true, + "textColor": "none", + "useFixedWidth": true, + "visualizerType": "linear" + } + ], + "left": [ + { + "colorizeIcons": true, + "hideMode": "hidden", + "id": "ActiveWindow", + "maxWidth": 500, + "scrollingMode": "hover", + "showIcon": true, + "showText": true, + "textColor": "none", + "useFixedWidth": true + } + ], + "right": [ + { + "defaultSettings": { + }, + "id": "plugin:kde-connect" + }, + { + "defaultSettings": { + "colorizationBadge": "Primary", + "colorizationBadgeText": "Primary", + "colorizationEnabled": false, + "colorizationIcon": "Primary", + "defaultTab": 0, + "enableSystemNotifications": false, + "githubUrl": "", + "maxEvents": 50, + "notifyForks": true, + "notifyGitHubNotifications": true, + "notifyMyRepoForks": true, + "notifyMyRepoStars": true, + "notifyPRs": true, + "notifyRepoCreations": true, + "notifyStars": true, + "openInBrowser": true, + "refreshInterval": 1800, + "showForks": true, + "showMyRepoForks": true, + "showMyRepoStars": true, + "showNotificationBadge": true, + "showPRs": true, + "showRepoCreations": true, + "showStars": true, + "token": "", + "username": "" + }, + "id": "plugin:github-feed" + }, + { + "hideWhenZero": false, + "hideWhenZeroUnread": false, + "iconColor": "none", + "id": "NotificationHistory", + "showUnreadBadge": true, + "unreadBadgeColor": "primary" + }, + { + "displayMode": "onhover", + "iconColor": "none", + "id": "Volume", + "middleClickCommand": "pwvucontrol || pavucontrol", + "textColor": "none" + }, + { + "colorizeDistroLogo": false, + "colorizeSystemIcon": "none", + "colorizeSystemText": "none", + "customIconPath": "", + "enableColorization": false, + "icon": "settings-2", + "id": "ControlCenter", + "useDistroLogo": false + }, + { + "clockColor": "none", + "customFont": "", + "formatHorizontal": "ddd MMM d h:mmAP", + "formatVertical": "HH mm - dd MM", + "id": "Clock", + "tooltipFormat": "MM/dd/yyyy HH:mm:ss", + "useCustomFont": false + } + ] + } + }, + "brightness": { + "backlightDeviceMappings": [ + ], + "brightnessStep": 5, + "enableDdcSupport": true, + "enforceMinimum": true + }, + "calendar": { + "cards": [ + { + "enabled": true, + "id": "calendar-header-card" + }, + { + "enabled": false, + "id": "calendar-month-card" + }, + { + "enabled": true, + "id": "weather-card" + } + ] + }, + "colorSchemes": { + "darkMode": true, + "generationMethod": "muted", + "manualSunrise": "06:30", + "manualSunset": "18:30", + "monitorForColors": "", + "predefinedScheme": "Monochrome", + "schedulingMode": "off", + "syncGsettings": true, + "useWallpaperColors": true + }, + "controlCenter": { + "cards": [ + { + "enabled": true, + "id": "profile-card" + }, + { + "enabled": true, + "id": "shortcuts-card" + }, + { + "enabled": true, + "id": "audio-card" + }, + { + "enabled": false, + "id": "brightness-card" + }, + { + "enabled": true, + "id": "weather-card" + }, + { + "enabled": true, + "id": "media-sysmon-card" + } + ], + "diskPath": "/", + "position": "close_to_bar_button", + "shortcuts": { + "left": [ + { + "id": "Network" + }, + { + "id": "Bluetooth" + }, + { + "id": "WallpaperSelector" + }, + { + "id": "NoctaliaPerformance" + } + ], + "right": [ + { + "id": "Notifications" + }, + { + "id": "PowerProfile" + }, + { + "id": "KeepAwake" + }, + { + "id": "NightLight" + } + ] + } + }, + "desktopWidgets": { + "enabled": false, + "gridSnap": true, + "gridSnapScale": true, + "monitorWidgets": [ + { + "name": "eDP-1", + "widgets": [ + { + "clockColor": "none", + "clockStyle": "digital", + "customFont": "", + "format": "HH:mm\\nd MMMM yyyy", + "id": "Clock", + "roundedCorners": true, + "showBackground": true, + "useCustomFont": false, + "x": 1440, + "y": 960 + }, + { + "id": "Weather", + "roundedCorners": true, + "showBackground": true, + "x": 1630, + "y": 1084 + }, + { + "diskPath": "/", + "id": "SystemStat", + "layout": "bottom", + "roundedCorners": true, + "scale": 1.085295715771401, + "showBackground": true, + "statType": "CPU", + "x": 1620, + "y": 920 + } + ] + } + ], + "overviewEnabled": true + }, + "dock": { + "animationSpeed": 1, + "backgroundOpacity": 0.92, + "colorizeIcons": false, + "deadOpacity": 0.6, + "displayMode": "auto_hide", + "dockType": "floating", + "enabled": false, + "floatingRatio": 1, + "groupApps": false, + "groupClickAction": "cycle", + "groupContextMenuMode": "extended", + "groupIndicatorStyle": "dots", + "inactiveIndicators": false, + "indicatorColor": "primary", + "indicatorOpacity": 0.6, + "indicatorThickness": 3, + "launcherIcon": "", + "launcherIconColor": "none", + "launcherPosition": "end", + "launcherUseDistroLogo": false, + "monitors": [ + ], + "onlySameOutput": true, + "pinnedApps": [ + ], + "pinnedStatic": false, + "position": "bottom", + "showDockIndicator": false, + "showLauncherIcon": false, + "sitOnFrame": false, + "size": 1 + }, + "general": { + "allowPanelsOnScreenWithoutBar": true, + "allowPasswordWithFprintd": false, + "animationDisabled": false, + "animationSpeed": 1, + "autoStartAuth": false, + "avatarImage": "/home/prad/Pictures/Prad/prad2.jpg", + "boxRadiusRatio": 1, + "clockFormat": "hh\\nmm", + "clockStyle": "custom", + "compactLockScreen": false, + "dimmerOpacity": 0.2, + "enableBlurBehind": true, + "enableLockScreenCountdown": true, + "enableLockScreenMediaControls": false, + "enableShadows": false, + "forceBlackScreenCorners": false, + "iRadiusRatio": 1, + "keybinds": { + "keyDown": [ + "Down" + ], + "keyEnter": [ + "Return", + "Enter" + ], + "keyEscape": [ + "Esc" + ], + "keyLeft": [ + "Left" + ], + "keyRemove": [ + "Del" + ], + "keyRight": [ + "Right" + ], + "keyUp": [ + "Up" + ] + }, + "language": "", + "lockOnSuspend": true, + "lockScreenAnimations": false, + "lockScreenBlur": 0, + "lockScreenCountdownDuration": 10000, + "lockScreenMonitors": [ + ], + "lockScreenTint": 0, + "passwordChars": false, + "radiusRatio": 1, + "reverseScroll": true, + "scaleRatio": 0.9500000000000001, + "screenRadiusRatio": 1, + "shadowDirection": "bottom_right", + "shadowOffsetX": 2, + "shadowOffsetY": 3, + "showChangelogOnStartup": true, + "showHibernateOnLockScreen": false, + "showScreenCorners": false, + "showSessionButtonsOnLockScreen": true, + "smoothScrollEnabled": true, + "telemetryEnabled": false + }, + "hooks": { + "colorGeneration": "", + "darkModeChange": "", + "enabled": false, + "performanceModeDisabled": "", + "performanceModeEnabled": "", + "screenLock": "", + "screenUnlock": "", + "session": "", + "startup": "", + "wallpaperChange": "" + }, + "idle": { + "customCommands": "[]", + "enabled": false, + "fadeDuration": 5, + "lockCommand": "", + "lockTimeout": 660, + "resumeLockCommand": "", + "resumeScreenOffCommand": "", + "resumeSuspendCommand": "", + "screenOffCommand": "", + "screenOffTimeout": 600, + "suspendCommand": "", + "suspendTimeout": 1800 + }, + "location": { + "analogClockInCalendar": false, + "autoLocate": true, + "firstDayOfWeek": -1, + "hideWeatherCityName": false, + "hideWeatherTimezone": false, + "name": "Ashburn", + "showCalendarEvents": true, + "showCalendarWeather": true, + "showWeekNumberInCalendar": true, + "use12hourFormat": true, + "useFahrenheit": true, + "weatherEnabled": true, + "weatherShowEffects": true, + "weatherTaliaMascotAlways": false + }, + "network": { + "bluetoothAutoConnect": true, + "bluetoothDetailsViewMode": "grid", + "bluetoothHideUnnamedDevices": false, + "bluetoothRssiPollIntervalMs": 60000, + "bluetoothRssiPollingEnabled": false, + "disableDiscoverability": false, + "networkPanelView": "wifi", + "wifiDetailsViewMode": "grid" + }, + "nightLight": { + "autoSchedule": true, + "dayTemp": "6500", + "enabled": true, + "forced": false, + "manualSunrise": "06:30", + "manualSunset": "18:30", + "nightTemp": "2813" + }, + "noctaliaPerformance": { + "disableDesktopWidgets": true, + "disableWallpaper": true + }, + "notifications": { + "backgroundOpacity": 0.75, + "clearDismissed": true, + "criticalUrgencyDuration": 15, + "density": "default", + "enableBatteryToast": true, + "enableKeyboardLayoutToast": true, + "enableMarkdown": false, + "enableMediaToast": false, + "enabled": true, + "location": "top_right", + "lowUrgencyDuration": 3, + "monitors": [ + "HDMI-A-1", + "DP-2", + "eDP-1" + ], + "normalUrgencyDuration": 8, + "overlayLayer": true, + "respectExpireTimeout": false, + "saveToHistory": { + "critical": true, + "low": true, + "normal": true + }, + "sounds": { + "criticalSoundFile": "", + "enabled": false, + "excludedApps": "discord,firefox,chrome,chromium,edge", + "lowSoundFile": "", + "normalSoundFile": "", + "separateSounds": false, + "volume": 0.5 + } + }, + "osd": { + "autoHideMs": 2000, + "backgroundOpacity": 1, + "enabled": true, + "enabledTypes": [ + 0, + 1, + 2 + ], + "location": "top_right", + "monitors": [ + ], + "overlayLayer": true + }, + "plugins": { + "autoUpdate": true, + "notifyUpdates": true + }, + "sessionMenu": { + "countdownDuration": 10000, + "enableCountdown": true, + "largeButtonsLayout": "single-row", + "largeButtonsStyle": true, + "position": "center", + "powerOptions": [ + { + "action": "lock", + "command": "", + "countdownEnabled": true, + "enabled": true, + "keybind": "1" + }, + { + "action": "suspend", + "command": "", + "countdownEnabled": true, + "enabled": true, + "keybind": "2" + }, + { + "action": "hibernate", + "command": "", + "countdownEnabled": true, + "enabled": true, + "keybind": "3" + }, + { + "action": "reboot", + "command": "", + "countdownEnabled": true, + "enabled": true, + "keybind": "4" + }, + { + "action": "logout", + "command": "", + "countdownEnabled": true, + "enabled": true, + "keybind": "5" + }, + { + "action": "shutdown", + "command": "", + "countdownEnabled": true, + "enabled": true, + "keybind": "6" + }, + { + "action": "rebootToUefi", + "command": "", + "countdownEnabled": true, + "enabled": true, + "keybind": "7" + }, + { + "action": "userspaceReboot", + "command": "", + "countdownEnabled": true, + "enabled": false, + "keybind": "" + } + ], + "showHeader": true, + "showKeybinds": true + }, + "settingsVersion": 59, + "systemMonitor": { + "batteryCriticalThreshold": 5, + "batteryWarningThreshold": 20, + "cpuCriticalThreshold": 90, + "cpuWarningThreshold": 80, + "criticalColor": "#ffb4ab", + "diskAvailCriticalThreshold": 10, + "diskAvailWarningThreshold": 20, + "diskCriticalThreshold": 90, + "diskWarningThreshold": 80, + "enableDgpuMonitoring": false, + "externalMonitor": "resources || missioncenter || jdsystemmonitor || corestats || system-monitoring-center || gnome-system-monitor || plasma-systemmonitor || mate-system-monitor || ukui-system-monitor || deepin-system-monitor || pantheon-system-monitor", + "gpuCriticalThreshold": 90, + "gpuWarningThreshold": 80, + "memCriticalThreshold": 90, + "memWarningThreshold": 80, + "swapCriticalThreshold": 90, + "swapWarningThreshold": 80, + "tempCriticalThreshold": 90, + "tempWarningThreshold": 80, + "useCustomColors": false, + "warningColor": "#f0b8c6" + }, + "templates": { + "activeTemplates": [ + { + "enabled": true, + "id": "niri" + }, + { + "enabled": true, + "id": "kitty" + }, + { + "enabled": true, + "id": "gtk" + }, + { + "enabled": true, + "id": "btop" + }, + { + "enabled": true, + "id": "yazi" + }, + { + "enabled": true, + "id": "zed" + }, + { + "enabled": true, + "id": "vicinae" + }, + { + "enabled": true, + "id": "alacritty" + }, + { + "enabled": true, + "id": "ghostty" + }, + { + "enabled": true, + "id": "starship" + }, + { + "enabled": true, + "id": "telegram" + }, + { + "enabled": true, + "id": "qt" + }, + { + "enabled": true, + "id": "kcolorscheme" + }, + { + "enabled": true, + "id": "zenBrowser" + }, + { + "enabled": true, + "id": "mango" + }, + { + "enabled": true, + "id": "cava" + }, + { + "enabled": true, + "id": "fuzzel" + }, + { + "enabled": true, + "id": "helix" + } + ], + "enableUserTheming": false + }, + "ui": { + "boxBorderEnabled": false, + "fontDefault": "VictorMono NFP", + "fontDefaultScale": 0.9, + "fontFixed": "VictorMono NF", + "fontFixedScale": 0.95, + "panelBackgroundOpacity": 0.6, + "panelsAttachedToBar": true, + "scrollbarAlwaysVisible": false, + "settingsPanelMode": "attached", + "settingsPanelSideBarCardStyle": true, + "tooltipsEnabled": true, + "translucentWidgets": true + }, + "wallpaper": { + "automationEnabled": false, + "directory": "/home/prad/Pictures/Wallpapers", + "enableMultiMonitorDirectories": false, + "enabled": true, + "favorites": [ + { + "appearance": "dark", + "colorScheme": "Monochrome", + "darkMode": true, + "generationMethod": "muted", + "paletteColors": [ + "#a398b3", + "#9c8da5", + "#a18fa3", + "#fd4663" + ], + "path": "/home/prad/Pictures/Wallpapers/wallhaven-k81776.jpg", + "useWallpaperColors": true + } + ], + "fillColor": "#000000", + "fillMode": "crop", + "hideWallpaperFilenames": false, + "linkLightAndDarkWallpapers": true, + "monitorDirectories": [ + ], + "overviewBlur": 0.4, + "overviewEnabled": true, + "overviewTint": 0.6, + "panelPosition": "follow_bar", + "randomIntervalSec": 300, + "setWallpaperOnAllMonitors": true, + "showHiddenFiles": false, + "skipStartupTransition": true, + "solidColor": "#1a1a2e", + "sortOrder": "name", + "transitionDuration": 1500, + "transitionEdgeSmoothness": 0.05, + "transitionType": [ + "fade", + "disc", + "stripes", + "wipe", + "pixelate", + "honeycomb" + ], + "useOriginalImages": false, + "useSolidColor": false, + "useWallhaven": false, + "viewMode": "browse", + "wallhavenApiKey": "", + "wallhavenCategories": "111", + "wallhavenOrder": "desc", + "wallhavenPurity": "100", + "wallhavenQuery": "new york", + "wallhavenRatios": "", + "wallhavenResolutionHeight": "", + "wallhavenResolutionMode": "atleast", + "wallhavenResolutionWidth": "", + "wallhavenSorting": "relevance", + "wallpaperChangeMode": "random" + } +} diff --git a/dot_config/systemd/user/brain-lens@.service b/dot_config/systemd/user/brain-lens@.service new file mode 100644 index 0000000..57a809e --- /dev/null +++ b/dot_config/systemd/user/brain-lens@.service @@ -0,0 +1,6 @@ +[Unit] +Description=Second-brain lens %i + +[Service] +Type=oneshot +ExecStart=%h/Documents/Obsidian/Brain/_System/Brain/run-lens.sh %i diff --git a/dot_config/systemd/user/brain-lens@build-next.timer b/dot_config/systemd/user/brain-lens@build-next.timer new file mode 100644 index 0000000..be7a9ff --- /dev/null +++ b/dot_config/systemd/user/brain-lens@build-next.timer @@ -0,0 +1,9 @@ +[Unit] +Description=Second-brain lens build-next schedule + +[Timer] +OnCalendar=*-*-* 01,07,13,19:37:00 +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/dot_config/systemd/user/brain-lens@coach.timer b/dot_config/systemd/user/brain-lens@coach.timer new file mode 100644 index 0000000..9b245db --- /dev/null +++ b/dot_config/systemd/user/brain-lens@coach.timer @@ -0,0 +1,9 @@ +[Unit] +Description=Second-brain lens coach schedule + +[Timer] +OnCalendar=*-*-* 03,09,15,21:07:00 +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/dot_config/systemd/user/brain-lens@digest.timer b/dot_config/systemd/user/brain-lens@digest.timer new file mode 100644 index 0000000..43f087e --- /dev/null +++ b/dot_config/systemd/user/brain-lens@digest.timer @@ -0,0 +1,9 @@ +[Unit] +Description=Second-brain lens digest schedule + +[Timer] +OnCalendar=*-*-* 08:03:00 +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/dot_config/systemd/user/brain-lens@what-worked.timer b/dot_config/systemd/user/brain-lens@what-worked.timer new file mode 100644 index 0000000..acaae49 --- /dev/null +++ b/dot_config/systemd/user/brain-lens@what-worked.timer @@ -0,0 +1,9 @@ +[Unit] +Description=Second-brain lens what-worked schedule + +[Timer] +OnCalendar=*-*-* 00,06,12,18:07:00 +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/dot_config/systemd/user/brain-lens@write-next.timer b/dot_config/systemd/user/brain-lens@write-next.timer new file mode 100644 index 0000000..e6300b4 --- /dev/null +++ b/dot_config/systemd/user/brain-lens@write-next.timer @@ -0,0 +1,9 @@ +[Unit] +Description=Second-brain lens write-next schedule + +[Timer] +OnCalendar=*-*-* 04,10,16,22:37:00 +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/dot_config/systemd/user/hermes-gateway.service b/dot_config/systemd/user/hermes-gateway.service new file mode 100644 index 0000000..58ea3b3 --- /dev/null +++ b/dot_config/systemd/user/hermes-gateway.service @@ -0,0 +1,27 @@ +[Unit] +Description=Hermes Agent Gateway - Messaging Platform Integration +After=network-online.target +Wants=network-online.target +StartLimitIntervalSec=0 + +[Service] +Type=simple +ExecStart=/home/prad/.hermes/hermes-agent/venv/bin/python -m hermes_cli.main gateway run +WorkingDirectory=/home/prad/.hermes +Environment="PATH=/home/prad/.hermes/hermes-agent/venv/bin:/home/prad/.hermes/hermes-agent/node_modules/.bin:/home/prad/.local/share/mise/installs/node/latest/bin:/home/prad/.local/bin:/home/prad/.cargo/bin:/home/prad/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" +Environment="VIRTUAL_ENV=/home/prad/.hermes/hermes-agent/venv" +Environment="HERMES_HOME=/home/prad/.hermes" +Restart=always +RestartSec=5 +RestartForceExitStatus=75 +RestartPreventExitStatus=78 +KillMode=mixed +KillSignal=SIGTERM +ExecReload=/bin/kill -USR1 $MAINPID +ExecStopPost=-/home/prad/.hermes/hermes-agent/venv/bin/python -m gateway.cgroup_cleanup +TimeoutStopSec=210 +StandardOutput=journal +StandardError=journal + +[Install] +WantedBy=default.target diff --git a/dot_config/systemd/user/nirinit.service b/dot_config/systemd/user/nirinit.service new file mode 100644 index 0000000..40e3a55 --- /dev/null +++ b/dot_config/systemd/user/nirinit.service @@ -0,0 +1,14 @@ +[Unit] +Description=nirinit - Niri session save/restore +PartOf=graphical-session.target +After=graphical-session.target +Requisite=graphical-session.target + +[Service] +Type=simple +ExecStart=%h/.cargo/bin/nirinit --save-interval 300 +Restart=on-failure +RestartSec=2 + +[Install] +WantedBy=graphical-session.target diff --git a/dot_config/systemd/user/omp-loop@.service b/dot_config/systemd/user/omp-loop@.service new file mode 100644 index 0000000..cd3e4f1 --- /dev/null +++ b/dot_config/systemd/user/omp-loop@.service @@ -0,0 +1,10 @@ +[Unit] +Description=omp agent loop: %i + +[Service] +Type=oneshot +ExecStart=%h/.omp/loops/bin/run-loop.sh %i +# Loops are green (read-only + own state file) but belt-and-braces: +# no interactive session, hard runtime ceiling above the script's own caps. +TimeoutStartSec=45min +Nice=10 diff --git a/dot_config/systemd/user/omp-loop@answer-gap.timer b/dot_config/systemd/user/omp-loop@answer-gap.timer new file mode 100644 index 0000000..6c8ffa2 --- /dev/null +++ b/dot_config/systemd/user/omp-loop@answer-gap.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Timer for omp loop: answer-gap + +[Timer] +OnCalendar=Thu 07:00 +Persistent=true +RandomizedDelaySec=10min + +[Install] +WantedBy=timers.target diff --git a/dot_config/systemd/user/omp-loop@brand-radar.timer b/dot_config/systemd/user/omp-loop@brand-radar.timer new file mode 100644 index 0000000..708d910 --- /dev/null +++ b/dot_config/systemd/user/omp-loop@brand-radar.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Timer for omp loop: brand-radar + +[Timer] +OnCalendar=Wed 07:00 +Persistent=true +RandomizedDelaySec=10min + +[Install] +WantedBy=timers.target diff --git a/dot_config/systemd/user/omp-loop@competitor-watch.timer b/dot_config/systemd/user/omp-loop@competitor-watch.timer new file mode 100644 index 0000000..d2a1596 --- /dev/null +++ b/dot_config/systemd/user/omp-loop@competitor-watch.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Timer for omp loop: competitor-watch + +[Timer] +OnCalendar=Fri 07:00 +Persistent=true +RandomizedDelaySec=10min + +[Install] +WantedBy=timers.target diff --git a/dot_config/systemd/user/omp-loop@intel-refresh.timer b/dot_config/systemd/user/omp-loop@intel-refresh.timer new file mode 100644 index 0000000..1a0fefb --- /dev/null +++ b/dot_config/systemd/user/omp-loop@intel-refresh.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Timer for omp loop: intel-refresh + +[Timer] +OnCalendar=Mon 06:00 +Persistent=true +RandomizedDelaySec=10min + +[Install] +WantedBy=timers.target diff --git a/dot_config/systemd/user/omp-loop@regulatory-digest.timer b/dot_config/systemd/user/omp-loop@regulatory-digest.timer new file mode 100644 index 0000000..71f57d6 --- /dev/null +++ b/dot_config/systemd/user/omp-loop@regulatory-digest.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Timer for omp loop: regulatory-digest + +[Timer] +OnCalendar=Tue 07:00 +Persistent=true +RandomizedDelaySec=10min + +[Install] +WantedBy=timers.target diff --git a/dot_config/systemd/user/omp-loop@repeat-offender.timer b/dot_config/systemd/user/omp-loop@repeat-offender.timer new file mode 100644 index 0000000..ac93091 --- /dev/null +++ b/dot_config/systemd/user/omp-loop@repeat-offender.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Timer for omp loop: repeat-offender + +[Timer] +OnCalendar=Sun 18:00 +Persistent=true +RandomizedDelaySec=10min + +[Install] +WantedBy=timers.target diff --git a/dot_config/systemd/user/omp-loop@share-of-model.timer b/dot_config/systemd/user/omp-loop@share-of-model.timer new file mode 100644 index 0000000..0b14ba5 --- /dev/null +++ b/dot_config/systemd/user/omp-loop@share-of-model.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Timer for omp loop: share-of-model + +[Timer] +OnCalendar=Mon 07:00 +Persistent=true +RandomizedDelaySec=10min + +[Install] +WantedBy=timers.target diff --git a/dot_config/systemd/user/openwebui-hermes.service b/dot_config/systemd/user/openwebui-hermes.service new file mode 100644 index 0000000..935b0f8 --- /dev/null +++ b/dot_config/systemd/user/openwebui-hermes.service @@ -0,0 +1,15 @@ +[Unit] +Description=Open WebUI connected to Hermes Agent +After=default.target + +[Service] +Type=simple +ExecStart=/bin/bash %h/.local/bin/start-open-webui-hermes.sh +Restart=always +RestartSec=3 +WorkingDirectory=%h +StandardOutput=append:%h/.hermes/logs/openwebui.log +StandardError=append:%h/.hermes/logs/openwebui.error.log + +[Install] +WantedBy=default.target diff --git a/dot_config/systemd/user/rclone-gdrive-hyperauth.service b/dot_config/systemd/user/rclone-gdrive-hyperauth.service new file mode 100644 index 0000000..850c6cb --- /dev/null +++ b/dot_config/systemd/user/rclone-gdrive-hyperauth.service @@ -0,0 +1,7 @@ +[Unit] +Description=Rclone SFTP Service for gdrive-hyperauth +Requires=rclone-gdrive-hyperauth.socket + +[Service] +Type=simple +ExecStart=/usr/bin/rclone serve sftp gdrive-hyperauth: --vfs-cache-mode full --vfs-fast-fingerprint --user yazi --pass yazi diff --git a/dot_config/systemd/user/rclone-gdrive-hyperauth.socket b/dot_config/systemd/user/rclone-gdrive-hyperauth.socket new file mode 100644 index 0000000..ea0dad5 --- /dev/null +++ b/dot_config/systemd/user/rclone-gdrive-hyperauth.socket @@ -0,0 +1,8 @@ +[Unit] +Description=Rclone SFTP Socket for gdrive-hyperauth + +[Socket] +ListenStream=127.0.0.1:2223 + +[Install] +WantedBy=sockets.target diff --git a/dot_config/systemd/user/rclone-gdrive-personal.service b/dot_config/systemd/user/rclone-gdrive-personal.service new file mode 100644 index 0000000..f67ef17 --- /dev/null +++ b/dot_config/systemd/user/rclone-gdrive-personal.service @@ -0,0 +1,7 @@ +[Unit] +Description=Rclone SFTP Service for gdrive-personal +Requires=rclone-gdrive-personal.socket + +[Service] +Type=simple +ExecStart=/usr/bin/rclone serve sftp gdrive-personal: --vfs-cache-mode full --vfs-fast-fingerprint --user yazi --pass yazi diff --git a/dot_config/systemd/user/rclone-gdrive-personal.socket b/dot_config/systemd/user/rclone-gdrive-personal.socket new file mode 100644 index 0000000..76819f1 --- /dev/null +++ b/dot_config/systemd/user/rclone-gdrive-personal.socket @@ -0,0 +1,8 @@ +[Unit] +Description=Rclone SFTP Socket for gdrive-personal + +[Socket] +ListenStream=127.0.0.1:2221 + +[Install] +WantedBy=sockets.target diff --git a/dot_config/systemd/user/rclone-gdrive-sonr.service b/dot_config/systemd/user/rclone-gdrive-sonr.service new file mode 100644 index 0000000..2264f7a --- /dev/null +++ b/dot_config/systemd/user/rclone-gdrive-sonr.service @@ -0,0 +1,7 @@ +[Unit] +Description=Rclone SFTP Service for gdrive-sonr +Requires=rclone-gdrive-sonr.socket + +[Service] +Type=simple +ExecStart=/usr/bin/rclone serve sftp gdrive-sonr: --vfs-cache-mode full --vfs-fast-fingerprint --user yazi --pass yazi diff --git a/dot_config/systemd/user/rclone-gdrive-sonr.socket b/dot_config/systemd/user/rclone-gdrive-sonr.socket new file mode 100644 index 0000000..c790ba4 --- /dev/null +++ b/dot_config/systemd/user/rclone-gdrive-sonr.socket @@ -0,0 +1,8 @@ +[Unit] +Description=Rclone SFTP Socket for gdrive-sonr + +[Socket] +ListenStream=127.0.0.1:2222 + +[Install] +WantedBy=sockets.target diff --git a/dot_config/systemd/user/shelly-notifications.service b/dot_config/systemd/user/shelly-notifications.service new file mode 100644 index 0000000..b86e5ad --- /dev/null +++ b/dot_config/systemd/user/shelly-notifications.service @@ -0,0 +1,12 @@ +[Unit] +Description=Shelly Notifications tray service +After=graphical-session.target + +[Service] +Type=simple +ExecStart=/usr/bin/shelly-notifications +Restart=on-failure +RestartSec=5s + +[Install] +WantedBy=graphical-session.target \ No newline at end of file diff --git a/dot_config/systemd/user/voxtype.service b/dot_config/systemd/user/voxtype.service new file mode 100644 index 0000000..0e22007 --- /dev/null +++ b/dot_config/systemd/user/voxtype.service @@ -0,0 +1,17 @@ +[Unit] +Description=Voxtype push-to-talk voice-to-text daemon +Documentation=https://voxtype.io +PartOf=graphical-session.target +After=graphical-session.target + +[Service] +Type=simple +ExecStart=/usr/bin/voxtype daemon +Restart=on-failure +RestartSec=5 + +# Ensure we have access to the display +Environment=XDG_RUNTIME_DIR=%t + +[Install] +WantedBy=graphical-session.target diff --git a/dot_local/bin/executable_niri-launch b/dot_local/bin/executable_niri-launch new file mode 100755 index 0000000..a80f214 --- /dev/null +++ b/dot_local/bin/executable_niri-launch @@ -0,0 +1,88 @@ +#!/bin/bash +APP=$1 +declare -a INSTANCES + +# Per-class launch commands for kitty-* (class -> command run via `kitty -e`). +# Unmapped classes just open a plain kitty with that class. +declare -A KITTY_CMDS=( + # [kitty-lazygit]="lazygit" + # [kitty-btop]="btop" +) + +# Handle webapp cycling and launching +if [[ "$APP" == "webapp" ]]; then + # Cycle through all WebApps + INSTANCES=($(niri msg -j windows | jq -r '.[] | select(.app_id | startswith("WebApp-")) | .id')) +elif [[ "$APP" == webapp-* ]]; then + # Extract the webapp name (e.g., "webapp-claude" -> "Claude") + WEBAPP_NAME=$(echo "$APP" | sed 's/webapp-//' | sed 's/.*/\u&/') + # Find matching WebApp by prefix (case-insensitive match) + APP_ID=$(niri msg -j windows | jq -r ".[] | select(.app_id | test(\"WebApp-${WEBAPP_NAME}\"; \"i\")) | .app_id" | head -1) + + if [ -z "$APP_ID" ]; then + # No instance running, launch via gtk-launch + DESKTOP_FILE=$(find ~/.local/share/applications -name "WebApp-${WEBAPP_NAME}*.desktop" -print -quit 2>/dev/null) + if [ -n "$DESKTOP_FILE" ]; then + gtk-launch "$(basename "$DESKTOP_FILE")" + else + echo "No desktop file found for WebApp-${WEBAPP_NAME}" + fi + exit 0 + fi + + INSTANCES=($(niri msg -j windows | jq -r ".[] | select(.app_id | test(\"WebApp-${WEBAPP_NAME}\"; \"i\")) | .id")) +elif [[ "$APP" == "kitty" ]]; then + # Cycle through ALL kitty windows (any class: kitty, kitty-nvim, ...) + INSTANCES=($(niri msg -j windows | jq -r '.[] | select((.app_id // "") | ascii_downcase | startswith("kitty")) | .id')) +elif [[ "$APP" == kitty-* ]]; then + # Specific kitty class, e.g. kitty-nvim -> app_id "kitty-nvim" + INSTANCES=($(niri msg -j windows | jq -r --arg cls "$APP" \ + '.[] | select((.app_id // "") | ascii_downcase == ($cls | ascii_downcase)) | .id')) + + if [ ${#INSTANCES[@]} -eq 0 ]; then + cmd="${KITTY_CMDS[$APP]:-}" + if [ -n "$cmd" ]; then + niri msg action spawn -- kitty --class "$APP" -e $cmd + else + niri msg action spawn -- kitty --class "$APP" + fi + exit 0 + fi +elif [[ "$APP" == "ghostty" ]]; then + # Cycle through Ghostty terminals (case-insensitive app_id match) + INSTANCES=($(niri msg -j windows | jq -r '.[] | select(.app_id | test("ghostty"; "i")) | .id')) +else + INSTANCES=($(niri msg -j windows | jq -r ".[] | select(.app_id==\"${APP}\") | .id")) +fi + +# Launch if no instances +if [ ${#INSTANCES[@]} -eq 0 ]; then + # Removed "kitty" from this block so it falls through to the spawn command + if [[ "$APP" == "webapp" || "$APP" == "ghostty" ]]; then + echo "No ${APP} windows running" + exit 0 + fi + niri msg action spawn -- $APP + exit 0 +fi + +# Focus logic +if [ ${#INSTANCES[@]} -eq 1 ]; then + niri msg action focus-window --id ${INSTANCES[0]} +else + ISORTED=($(printf "%s\n" "${INSTANCES[@]}" | sort -n)) + FOCUSED=$(niri msg -j focused-window | jq '.id') + + if [[ ! " ${ISORTED[@]} " =~ ${FOCUSED} ]]; then + niri msg action focus-window --id ${ISORTED[0]} + else + new_index=0 + for i in "${!ISORTED[@]}"; do + if [ "${ISORTED[$i]}" -eq "${FOCUSED}" ]; then + new_index=$(( (i + 1) % ${#ISORTED[@]} )) + break + fi + done + niri msg action focus-window --id ${ISORTED[$new_index]} + fi +fi