Compare commits
14 commits
feat/riggi
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 5902011dc6 | |||
| 3fe859e21f | |||
| d6f943ba7f | |||
| 85debcbcd4 | |||
| f49a9c8019 | |||
| 9e49bd830d | |||
| 8feb3957a2 | |||
| 447da21da4 | |||
| a627589a48 | |||
| 57c86c5083 | |||
| ceb5ee4356 | |||
| ae2ee1fb77 | |||
| 7af406f315 | |||
| c694915cd5 |
34 changed files with 549 additions and 55 deletions
|
|
@ -46,6 +46,15 @@ bosun.secrets.npmrc = { ... }; # Secret definitions
|
|||
|
||||
Profile definitions are in `modules/generic/profiles.nix`, implementations in `modules/nixos/profiles/`.
|
||||
|
||||
## Adding packages
|
||||
|
||||
Before writing a custom `packages/` derivation, always check if the package already exists in nixpkgs:
|
||||
- Stable: https://search.nixos.org/packages?channel=25.11&query=<name>
|
||||
- Unstable: https://search.nixos.org/packages?channel=unstable&query=<name>
|
||||
- Master (bleeding edge): check open PRs at https://github.com/NixOS/nixpkgs/pulls
|
||||
|
||||
If it exists in `unstable` or `master` but not stable, pull it via `overlays/unstable.nix` using `channels.unstable` or `channels.master`. Only write a custom `packages/` derivation as a last resort.
|
||||
|
||||
## Architecture patterns
|
||||
|
||||
- **import-tree** auto-discovers and imports `.nix` files in `modules/flake/`. Files prefixed with `_` are excluded from auto-import.
|
||||
|
|
|
|||
6
flake.lock
generated
6
flake.lock
generated
|
|
@ -778,11 +778,11 @@
|
|||
},
|
||||
"master": {
|
||||
"locked": {
|
||||
"lastModified": 1767143992,
|
||||
"narHash": "sha256-c3jlq36uxltxGLuQ3KPYfxZkue/LLD0Ct3NdhBUsRyo=",
|
||||
"lastModified": 1771495899,
|
||||
"narHash": "sha256-UlAN9PHsBx1Kk65gR/KvLfO74zQcOjNZ+d/0td5T8eM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5830d8dfe6ae79365987d78bda3dd4152c271d8b",
|
||||
"rev": "f4f54061a12ebbdd03d7c53eed54d1e135840624",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
|||
7
home/by-host/endurance/config/attic.nix
Normal file
7
home/by-host/endurance/config/attic.nix
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{...}: {
|
||||
# Attic binary cache client configuration
|
||||
xdg.configFile."attic/config.toml".text = ''
|
||||
[cache.toph]
|
||||
endpoint = "https://cache.toph.so"
|
||||
'';
|
||||
}
|
||||
32
home/by-host/endurance/config/aws.nix
Normal file
32
home/by-host/endurance/config/aws.nix
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{ pkgs, config, lib, ... }: {
|
||||
home.packages = [ pkgs.awscli2 ];
|
||||
|
||||
# Derive AWS credentials from the existing nix-cache S3 secret — same
|
||||
# credentials, different format. No duplication, no Nomad API access needed.
|
||||
age.generators.aws-credentials = { decrypt, deps, ... }: ''
|
||||
KEY=$(${decrypt} ${lib.escapeShellArg deps.nix-cache-s3-env.file} \
|
||||
| grep AWS_ACCESS_KEY_ID | cut -d= -f2-)
|
||||
SECRET=$(${decrypt} ${lib.escapeShellArg deps.nix-cache-s3-env.file} \
|
||||
| grep AWS_SECRET_ACCESS_KEY | cut -d= -f2-)
|
||||
printf '[t4]\naws_access_key_id = %s\naws_secret_access_key = %s\n' \
|
||||
"$KEY" "$SECRET"
|
||||
'';
|
||||
|
||||
bosun.secrets.aws-credentials = {
|
||||
rekeyFile = "aws-credentials.age";
|
||||
path = "${config.home.homeDirectory}/.aws/credentials";
|
||||
mode = "0600";
|
||||
generator = {
|
||||
script = "aws-credentials";
|
||||
dependencies = {
|
||||
inherit (config.age.secrets) nix-cache-s3-env;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
home.file.".aws/config".text = ''
|
||||
[profile t4]
|
||||
endpoint_url = https://s3.toph.so
|
||||
region = us-east-1
|
||||
'';
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
rfc # TUI-based RFC reader
|
||||
nix-init # Generate Nix packages from URLs
|
||||
install-nothing
|
||||
marimo
|
||||
|
||||
# Language Servers
|
||||
lua-language-server
|
||||
|
|
@ -23,6 +24,9 @@
|
|||
nodePackages.typescript-language-server
|
||||
nil # nix lsp
|
||||
|
||||
# Node.js for MCP servers
|
||||
nodejs_22
|
||||
|
||||
# trurl # Parsing and manipulating URLs via CLI
|
||||
pandoc # Document converter
|
||||
ripgrep # Grep file search
|
||||
|
|
@ -38,6 +42,7 @@
|
|||
gitui
|
||||
tea
|
||||
harbor.agent-deck # Terminal session manager for AI coding agents
|
||||
happy-coder # Claude Code mobile client (happy.engineering)
|
||||
harbor.oryx # TUI for sniffing network traffic using eBPF
|
||||
|
||||
# BMAD
|
||||
|
|
@ -82,33 +87,48 @@
|
|||
enable = true;
|
||||
# package = inputs.unstable.${system}.claude-code;
|
||||
|
||||
# mcpServers = {
|
||||
# fetch = {
|
||||
# args = ["-y" "@modelcontextprotocol/server-fetch"];
|
||||
# command = "npx";
|
||||
# type = "stdio";
|
||||
# };
|
||||
# playwright = {
|
||||
# args = ["-y" "@modelcontextprotocol/server-playwright"];
|
||||
# command = "npx";
|
||||
# type = "stdio";
|
||||
# };
|
||||
# stackexchange = {
|
||||
# args = ["-y" "mcp-server-stackexchange"];
|
||||
# command = "npx";
|
||||
# type = "stdio";
|
||||
# };
|
||||
# arxiv = {
|
||||
# args = ["-y" "mcp-server-arxiv"];
|
||||
# command = "npx";
|
||||
# type = "stdio";
|
||||
# };
|
||||
# claudezilla = {
|
||||
# command = "bun";
|
||||
# args = ["/home/toph/code/vendor/claudezilla/mcp/server.js"];
|
||||
# type = "stdio";
|
||||
# };
|
||||
# };
|
||||
mcpServers = {
|
||||
# Official MCP servers (require Node.js)
|
||||
fetch = {
|
||||
command = "npx";
|
||||
args = ["-y" "@modelcontextprotocol/server-fetch"];
|
||||
type = "stdio";
|
||||
};
|
||||
playwright = {
|
||||
command = "npx";
|
||||
args = ["-y" "@modelcontextprotocol/server-playwright"];
|
||||
type = "stdio";
|
||||
};
|
||||
stackexchange = {
|
||||
command = "npx";
|
||||
args = ["-y" "mcp-server-stackexchange"];
|
||||
type = "stdio";
|
||||
};
|
||||
arxiv = {
|
||||
command = "npx";
|
||||
args = ["-y" "mcp-server-arxiv"];
|
||||
type = "stdio";
|
||||
};
|
||||
|
||||
# Custom MCP servers
|
||||
claudezilla = {
|
||||
command = "bun";
|
||||
args = ["/home/toph/code/vendor/claudezilla/mcp/server.js"];
|
||||
type = "stdio";
|
||||
};
|
||||
|
||||
# Charlie MCP servers (local)
|
||||
charlie-memory = {
|
||||
command = "bun";
|
||||
args = ["/home/toph/agent/mcp/memory/index.js"];
|
||||
type = "stdio";
|
||||
};
|
||||
charlie-comunica = {
|
||||
command = "bun";
|
||||
args = ["/home/toph/agent/mcp/comunica/index.js"];
|
||||
type = "stdio";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
./wakatime.nix
|
||||
./gpg
|
||||
./niri
|
||||
./hyprland
|
||||
./stylix.nix
|
||||
./default-applications.nix
|
||||
./misc/launcher.nix
|
||||
|
|
|
|||
15
home/by-host/endurance/hyprland/default.nix
Normal file
15
home/by-host/endurance/hyprland/default.nix
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{pkgs, ...}: {
|
||||
imports = [
|
||||
./settings.nix
|
||||
./keybinds.nix
|
||||
./window-rules.nix
|
||||
];
|
||||
|
||||
wayland.windowManager.hyprland.enable = true;
|
||||
|
||||
home.packages = with pkgs; [
|
||||
wl-clipboard
|
||||
cliphist
|
||||
hyprpicker
|
||||
];
|
||||
}
|
||||
66
home/by-host/endurance/hyprland/keybinds.nix
Normal file
66
home/by-host/endurance/hyprland/keybinds.nix
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
{pkgs, ...}: {
|
||||
wayland.windowManager.hyprland.settings = {
|
||||
"$mod" = "SUPER";
|
||||
|
||||
bind = [
|
||||
# Apps
|
||||
"$mod, space, exec, fuzzel"
|
||||
"$mod, c, exec, ${pkgs.harbor.spawn-term}/bin/spawn-term"
|
||||
"$mod, e, exec, nautilus"
|
||||
"$mod, d, exec, zeal"
|
||||
"$mod, g, exec, ${pkgs.harbor.hg-picker}/bin/hg-picker"
|
||||
"$mod, v, exec, cliphist list | fuzzel --dmenu | cliphist decode | wl-copy"
|
||||
|
||||
# Window management
|
||||
"$mod, q, killactive"
|
||||
"$mod, f, fullscreen, 1"
|
||||
"$mod, t, togglefloating"
|
||||
"$mod, p, pseudo"
|
||||
"$mod SHIFT, j, togglesplit"
|
||||
|
||||
# Focus (vim-style, matching niri keybinds)
|
||||
"$mod, h, movefocus, l"
|
||||
"$mod, l, movefocus, r"
|
||||
"$mod, k, movefocus, u"
|
||||
"$mod, j, movefocus, d"
|
||||
|
||||
# Move windows
|
||||
"$mod CTRL, h, movewindow, l"
|
||||
"$mod CTRL, l, movewindow, r"
|
||||
"$mod CTRL, k, movewindow, u"
|
||||
"$mod CTRL, j, movewindow, d"
|
||||
|
||||
# Workspaces
|
||||
"$mod, 1, workspace, 1"
|
||||
"$mod, 2, workspace, 2"
|
||||
"$mod, 3, workspace, 3"
|
||||
"$mod, 4, workspace, 4"
|
||||
"$mod, 5, workspace, 5"
|
||||
"$mod, 6, workspace, 6"
|
||||
"$mod, 7, workspace, 7"
|
||||
"$mod, 8, workspace, 8"
|
||||
|
||||
# Move to workspace silently
|
||||
"$mod CTRL, 1, movetoworkspacesilent, 1"
|
||||
"$mod CTRL, 2, movetoworkspacesilent, 2"
|
||||
"$mod CTRL, 3, movetoworkspacesilent, 3"
|
||||
"$mod CTRL, 4, movetoworkspacesilent, 4"
|
||||
"$mod CTRL, 5, movetoworkspacesilent, 5"
|
||||
"$mod CTRL, 6, movetoworkspacesilent, 6"
|
||||
"$mod CTRL, 7, movetoworkspacesilent, 7"
|
||||
"$mod CTRL, 8, movetoworkspacesilent, 8"
|
||||
];
|
||||
|
||||
bindm = [
|
||||
# Mouse: move and resize windows
|
||||
"$mod, mouse:272, movewindow"
|
||||
"$mod, mouse:273, resizewindow"
|
||||
];
|
||||
|
||||
bindl = [
|
||||
# Scroll through workspaces
|
||||
"$mod, mouse_down, workspace, e+1"
|
||||
"$mod, mouse_up, workspace, e-1"
|
||||
];
|
||||
};
|
||||
}
|
||||
95
home/by-host/endurance/hyprland/settings.nix
Normal file
95
home/by-host/endurance/hyprland/settings.nix
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
{pkgs, ...}: {
|
||||
wayland.windowManager.hyprland.settings = {
|
||||
monitor = [
|
||||
# Main ultrawide (left)
|
||||
"HDMI-A-1,3840x1080,0x0,1"
|
||||
# Vertical display (right)
|
||||
"DP-3,1920x1080,3840x-430,1,transform,1"
|
||||
# Fallback for any other monitor
|
||||
",preferred,auto,1"
|
||||
];
|
||||
|
||||
exec-once = [
|
||||
# Clipboard history
|
||||
"wl-paste --type text --watch cliphist store"
|
||||
"wl-paste --type image --watch cliphist store"
|
||||
# Automount USB drives
|
||||
"udiskie"
|
||||
];
|
||||
|
||||
env = [
|
||||
"MOZ_ENABLE_WAYLAND,1"
|
||||
"QT_WAYLAND_DISABLE_WINDOWDECORATION,1"
|
||||
"ELECTRON_OZONE_PLATFORM_HINT,auto"
|
||||
"NIXOS_OZONE_WL,1"
|
||||
"XDG_SESSION_TYPE,wayland"
|
||||
"XDG_CURRENT_DESKTOP,Hyprland"
|
||||
];
|
||||
|
||||
input = {
|
||||
kb_layout = "us";
|
||||
kb_variant = "intl";
|
||||
follow_mouse = 2;
|
||||
sensitivity = 0;
|
||||
};
|
||||
|
||||
general = {
|
||||
gaps_in = 8;
|
||||
gaps_out = 15;
|
||||
border_size = 2;
|
||||
layout = "dwindle";
|
||||
};
|
||||
|
||||
decoration = {
|
||||
rounding = 8;
|
||||
blur = {
|
||||
enabled = true;
|
||||
size = 4;
|
||||
passes = 2;
|
||||
noise = 0.05;
|
||||
};
|
||||
shadow = {
|
||||
enabled = true;
|
||||
range = 4;
|
||||
render_power = 3;
|
||||
};
|
||||
};
|
||||
|
||||
animations = {
|
||||
enabled = true;
|
||||
bezier = "myBezier, 0.05, 0.9, 0.1, 1.05";
|
||||
animation = [
|
||||
"windows, 1, 7, myBezier"
|
||||
"windowsOut, 1, 7, default, popin 80%"
|
||||
"border, 1, 10, default"
|
||||
"fade, 1, 7, default"
|
||||
"workspaces, 1, 6, default"
|
||||
];
|
||||
};
|
||||
|
||||
# Single tiled window on main monitor: give it breathing room
|
||||
workspace = [
|
||||
# Pin workspaces to monitors
|
||||
"1, monitor:HDMI-A-1, default:true"
|
||||
"2, monitor:HDMI-A-1"
|
||||
"3, monitor:HDMI-A-1"
|
||||
"4, monitor:HDMI-A-1"
|
||||
"5, monitor:HDMI-A-1"
|
||||
"6, monitor:DP-3, default:true"
|
||||
"7, monitor:DP-3"
|
||||
"8, monitor:DP-3"
|
||||
# Single tiled window on main monitor: give it breathing room
|
||||
"w[t1] m[HDMI-A-1], gapsout:15 840 15 840"
|
||||
];
|
||||
|
||||
dwindle = {
|
||||
pseudotile = true;
|
||||
preserve_split = true;
|
||||
};
|
||||
|
||||
misc = {
|
||||
disable_hyprland_logo = true;
|
||||
disable_splash_rendering = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
32
home/by-host/endurance/hyprland/window-rules.nix
Normal file
32
home/by-host/endurance/hyprland/window-rules.nix
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{...}: {
|
||||
wayland.windowManager.hyprland.settings = {
|
||||
windowrulev2 = [
|
||||
# Prevent garbage frame flash before first render
|
||||
"immediate, class:.*"
|
||||
|
||||
# Privacy: block from screen capture
|
||||
"noscreenshare, class:^(1password)$"
|
||||
"noscreenshare, class:^(thunderbird)$"
|
||||
"noscreenshare, title:^(ld\\.toph\\.so)$"
|
||||
|
||||
# Floating windows
|
||||
"float, class:^(org\\.zealdocs\\.zeal)$"
|
||||
"center 1, class:^(org\\.zealdocs\\.zeal)$"
|
||||
"size 50% 80%, class:^(org\\.zealdocs\\.zeal)$"
|
||||
"minsize 1400 500, class:^(org\\.zealdocs\\.zeal)$"
|
||||
|
||||
"float, class:^(speedcrunch)$"
|
||||
"center 1, class:^(speedcrunch)$"
|
||||
"size 30% 60%, class:^(speedcrunch)$"
|
||||
|
||||
"float, title:^(DevTools)$"
|
||||
|
||||
# Kitty: slight transparency
|
||||
"opacity 0.97 0.97, class:^(kitty)$"
|
||||
|
||||
# JetBrains: suppress phantom windows (RE2 doesn't support lookaheads,
|
||||
# so we can't exclude toolbox here — apply per-IDE if needed)
|
||||
# "nofocus, class:^(jetbrains-idea|jetbrains-rider|jetbrains-clion)$, floating:1, title:^win\\d+$"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
|
@ -2,5 +2,9 @@
|
|||
programs.niri.settings.spawn-at-startup = [
|
||||
# open fastfetch by default
|
||||
{argv = ["kitty" "--title" "'fastfetch'" "sh" "-c" "'fastfetch; read'"];}
|
||||
|
||||
# Clipboard history daemons
|
||||
{argv = ["wl-paste" "--type" "text" "--watch" "cliphist" "store"];}
|
||||
{argv = ["wl-paste" "--type" "image" "--watch" "cliphist" "store"];}
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,5 +15,7 @@
|
|||
|
||||
home.packages = with pkgs; [
|
||||
fuzzel
|
||||
wl-clipboard
|
||||
cliphist
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
"Mod+d".action = spawn "zeal"; # Documentation viewer
|
||||
"Mod+c".action = spawn "${pkgs.harbor.spawn-term}/bin/spawn-term";
|
||||
"Mod+g".action = spawn "${pkgs.harbor.hg-picker}/bin/hg-picker";
|
||||
"Mod+v".action = spawn "sh" "-c" "cliphist list | fuzzel --dmenu | cliphist decode | wl-copy";
|
||||
|
||||
"Mod+q".action = close-window;
|
||||
"Mod+f".action = fullscreen-window;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,25 @@
|
|||
|
||||
#quirks = ["avahi" "docker" "nix-ld"];
|
||||
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPjqieS4GkYAa1WRYZpxjgYsj7VGZ9U+rTFCkX8M0umD";
|
||||
|
||||
secrets = {
|
||||
nix-cache-privkey = "nix-cache-privkey.age";
|
||||
nix-cache-s3-env = "nix-cache-s3.env.age";
|
||||
};
|
||||
};
|
||||
|
||||
# Sign builds and push to the S3 binary cache at s3.toph.so/nix-cache.
|
||||
nix.settings = {
|
||||
secret-key-files = [config.age.secrets.nix-cache-privkey.path];
|
||||
post-build-hook = toString (pkgs.writeScript "nix-cache-upload" ''
|
||||
#!/bin/sh
|
||||
set -uf
|
||||
. ${config.age.secrets.nix-cache-s3-env.path}
|
||||
${config.nix.package}/bin/nix copy \
|
||||
--to "s3://nix-cache?endpoint=https://s3.toph.so®ion=us-east-1" \
|
||||
$OUT_PATHS \
|
||||
>> /tmp/nix-cache-upload.log 2>&1 &
|
||||
'');
|
||||
};
|
||||
|
||||
networking = {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
inherit lib;
|
||||
pkgs = prev;
|
||||
};
|
||||
harbor = inputs.self.packages.${system} or {};
|
||||
})
|
||||
];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,5 +24,6 @@
|
|||
just
|
||||
nh
|
||||
age
|
||||
attic-client
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,14 @@
|
|||
keep-outputs = true;
|
||||
|
||||
trusted-users = ["root" "@wheel"];
|
||||
substituters = ["https://cache.nixos.org/"];
|
||||
substituters = [
|
||||
"https://cache.nixos.org/"
|
||||
"https://cache.toph.so/toph"
|
||||
];
|
||||
trusted-public-keys = [
|
||||
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
|
||||
"toph:E/oP7KyljH/yprI5LArxNPpSlQCdo29sMOkh3jm53Yg="
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -20,11 +20,13 @@ in {
|
|||
'';
|
||||
|
||||
functions = {
|
||||
nomad-ui = {
|
||||
description = "Fetches the Nomad management token from alvin and opens the authenticated UI";
|
||||
nomad-auth = {
|
||||
description = "Fetches the Nomad management token from alvin. Pass --ui to also open the authenticated UI.";
|
||||
body = ''
|
||||
set -gx NOMAD_TOKEN (ssh root@alvin cat /var/lib/nomad-acl/management.token)
|
||||
nomad ui -authenticate
|
||||
if contains -- --ui $argv
|
||||
nomad ui -authenticate
|
||||
end
|
||||
'';
|
||||
};
|
||||
agx = {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ in {
|
|||
package = pkgs.niri; # TODO: Use input niri pkgs/overlay!
|
||||
};
|
||||
|
||||
programs.hyprland.enable = true;
|
||||
|
||||
services = {
|
||||
xserver = {
|
||||
enable = true;
|
||||
|
|
@ -62,11 +64,15 @@ in {
|
|||
xdg.portal = {
|
||||
enable = true;
|
||||
# xdgOpenUsePortal = true;
|
||||
config.common.default = "gtk";
|
||||
config = {
|
||||
common.default = "gtk";
|
||||
hyprland.default = ["hyprland" "gtk"];
|
||||
};
|
||||
|
||||
extraPortals = with pkgs; [
|
||||
xdg-desktop-portal-gnome
|
||||
xdg-desktop-portal-gtk
|
||||
xdg-desktop-portal-hyprland
|
||||
];
|
||||
};
|
||||
|
||||
|
|
|
|||
BIN
new-secret-ci.key
Normal file
BIN
new-secret-ci.key
Normal file
Binary file not shown.
|
|
@ -17,5 +17,5 @@
|
|||
# open-webui
|
||||
;
|
||||
|
||||
inherit (channels.master) install-nothing;
|
||||
inherit (channels.master) install-nothing marimo happy-coder;
|
||||
}
|
||||
|
|
|
|||
116
packages/active-path/active-path
Normal file
116
packages/active-path/active-path
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#!/usr/bin/env bash
|
||||
# active-path <pid>
|
||||
#
|
||||
# Given a PID (e.g. from active-window), output the active working directory
|
||||
# or project root for that process. Handles:
|
||||
# - VSCode/Electron: parses --folder-uri from the process tree
|
||||
# - Terminals (kitty, etc.): finds the deepest meaningful cwd in the tree
|
||||
# - Fallback: own cwd
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
PID="${1:?Usage: active-path <pid>}"
|
||||
|
||||
PROJECT_MARKERS=(.git Cargo.toml package.json Gemfile pyproject.toml go.mod flake.nix)
|
||||
|
||||
# Walk up from a path looking for a project root marker.
|
||||
# Returns the marker directory, or the original path if nothing is found.
|
||||
find_project_root() {
|
||||
local dir="$1"
|
||||
local d="$dir"
|
||||
while [[ "$d" != "/" && -n "$d" ]]; do
|
||||
for marker in "${PROJECT_MARKERS[@]}"; do
|
||||
[[ -e "$d/$marker" ]] && { printf '%s\n' "$d"; return 0; }
|
||||
done
|
||||
d="$(dirname "$d")"
|
||||
done
|
||||
printf '%s\n' "$dir"
|
||||
}
|
||||
|
||||
# Decode a percent-encoded URI path component (file:/// paths are rarely
|
||||
# exotic, but spaces and non-ASCII chars do occur).
|
||||
url_decode() {
|
||||
printf '%b' "${1//%/\\x}"
|
||||
}
|
||||
|
||||
# Read null-terminated argv of a pid and look for --folder-uri.
|
||||
# Prints the decoded path and returns 0 if found, else returns 1.
|
||||
folder_uri_from_cmdline() {
|
||||
local pid="$1"
|
||||
local prev=""
|
||||
while IFS= read -r -d $'\0' arg; do
|
||||
case "$arg" in
|
||||
--folder-uri=file://*)
|
||||
url_decode "${arg#--folder-uri=file://}"
|
||||
return 0
|
||||
;;
|
||||
file://*)
|
||||
if [[ "$prev" == "--folder-uri" ]]; then
|
||||
url_decode "${arg#file://}"
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
prev="$arg"
|
||||
done < "/proc/$pid/cmdline" 2>/dev/null
|
||||
return 1
|
||||
}
|
||||
|
||||
# Collect PIDs of all processes in the subtree rooted at $1.
|
||||
all_pids() {
|
||||
local pid="$1"
|
||||
printf '%s\n' "$pid"
|
||||
for child in $(pgrep -P "$pid" 2>/dev/null); do
|
||||
all_pids "$child"
|
||||
done
|
||||
}
|
||||
|
||||
# Given a list of PIDs, return the most specific (longest) cwd that lives
|
||||
# under the user's home directory. Falls back to any non-root, non-proc cwd.
|
||||
best_cwd_from_pids() {
|
||||
local best=""
|
||||
for pid in "$@"; do
|
||||
local cwd
|
||||
cwd=$(readlink -f "/proc/$pid/cwd" 2>/dev/null) || continue
|
||||
[[ "$cwd" == "/" || "$cwd" == "/root" || "$cwd" == "${HOME}" ]] && continue
|
||||
[[ "$cwd" =~ ^/(proc|sys|run|dev) ]] && continue
|
||||
|
||||
# Prefer paths under home; among those prefer longer (more specific) ones
|
||||
if [[ "$cwd" == "${HOME}"/* ]]; then
|
||||
if [[ -z "$best" || "${#cwd}" -gt "${#best}" ]]; then
|
||||
best="$cwd"
|
||||
fi
|
||||
elif [[ -z "$best" ]]; then
|
||||
best="$cwd"
|
||||
fi
|
||||
done
|
||||
[[ -n "$best" ]] && printf '%s\n' "$best"
|
||||
}
|
||||
|
||||
# --- Main ---
|
||||
|
||||
readarray -t TREE < <(all_pids "$PID")
|
||||
|
||||
# 1. VSCode / Electron: search entire process tree for --folder-uri
|
||||
for pid in "${TREE[@]}"; do
|
||||
if path=$(folder_uri_from_cmdline "$pid" 2>/dev/null); then
|
||||
find_project_root "$path"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
|
||||
# 2. Terminal / generic: find the best cwd among all processes in the tree
|
||||
# (prefers the shell or its running child over the terminal emulator itself,
|
||||
# because terminal emulators typically sit at $HOME while the shell has moved)
|
||||
if cwd=$(best_cwd_from_pids "${TREE[@]}"); then
|
||||
find_project_root "$cwd"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 3. Absolute fallback: own cwd, even if it's /
|
||||
own=$(readlink -f "/proc/$PID/cwd" 2>/dev/null || true)
|
||||
[[ -n "$own" ]] && find_project_root "$own" && exit 0
|
||||
|
||||
exit 1
|
||||
6
packages/active-path/package.nix
Normal file
6
packages/active-path/package.nix
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{pkgs, ...}:
|
||||
pkgs.writeShellApplication {
|
||||
name = "active-path";
|
||||
runtimeInputs = [pkgs.procps];
|
||||
text = builtins.readFile ./active-path;
|
||||
}
|
||||
19
packages/active-window/package.nix
Normal file
19
packages/active-window/package.nix
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{pkgs, ...}:
|
||||
pkgs.writeShellApplication {
|
||||
name = "active-window";
|
||||
runtimeInputs = [pkgs.jq];
|
||||
text = ''
|
||||
if [[ -n "''${NIRI_SOCKET:-}" ]]; then
|
||||
FOCUSED_ID=$(niri msg --json focused-window | jq '.id')
|
||||
niri msg --json windows \
|
||||
| jq --argjson id "$FOCUSED_ID" \
|
||||
'[.[] | select(.id == $id)] | first
|
||||
| {compositor: "niri", class: .app_id, pid: .pid}'
|
||||
elif [[ -n "''${HYPRLAND_INSTANCE_SIGNATURE:-}" ]]; then
|
||||
hyprctl activewindow -j \
|
||||
| jq '{compositor: "hyprland", class: .class, pid: .pid}'
|
||||
else
|
||||
printf '{"compositor":"unknown","class":null,"pid":null}\n'
|
||||
fi
|
||||
'';
|
||||
}
|
||||
6
packages/mcp-wrapper/default.nix
Normal file
6
packages/mcp-wrapper/default.nix
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{ pkgs }:
|
||||
|
||||
pkgs.writeShellScriptBin "mcp-npx" ''
|
||||
# Wrapper that provides npx with Node.js in PATH
|
||||
exec ${pkgs.nodejs_22}/bin/npx "$@"
|
||||
''
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
{pkgs, ...}:
|
||||
pkgs.writeShellApplication {
|
||||
name = "quick-zeal";
|
||||
runtimeInputs = [pkgs.harbor.active-window pkgs.jq];
|
||||
text = builtins.readFile ./quick-zeal;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,14 @@ extract_major_version() {
|
|||
}
|
||||
|
||||
# Detects the focused window and checks if it's Kitty
|
||||
ACTIVE_WINDOW=$(hyprctl activewindow -j | jq -r '.class')
|
||||
WINDOW=$(active-window)
|
||||
ACTIVE_WINDOW=$(printf '%s' "$WINDOW" | jq -r '.class // empty')
|
||||
PID=$(printf '%s' "$WINDOW" | jq -r '.pid // empty')
|
||||
|
||||
# Check if the focused window is a Kitty terminal and if it's in a Git repository.
|
||||
# If so, determine the project type and open Zeal with the appropriate argument
|
||||
zeal_argument=""
|
||||
if [[ $ACTIVE_WINDOW == "kitty" ]]; then
|
||||
PID=$(hyprctl activewindow -j | jq -r '.pid')
|
||||
CHILD_PID=$(pgrep -P "$PID" | tail -1)
|
||||
|
||||
SHELL_CWD=$(readlink -f "/proc/${CHILD_PID}/cwd")
|
||||
|
|
|
|||
|
|
@ -1,25 +1,13 @@
|
|||
{pkgs, ...}:
|
||||
pkgs.writeNushellApplication {
|
||||
name = "spawn-term";
|
||||
runtimeInputs = with pkgs; [kdotool];
|
||||
runtimeInputs = [pkgs.harbor.active-window];
|
||||
|
||||
text = ''
|
||||
let compositor = $env.XDG_CURRENT_DESKTOP? | default ""
|
||||
|
||||
let window_info = if ($compositor | str contains "niri") {
|
||||
let focused_window = (niri msg --json focused-window | from json | get id?)
|
||||
if ($focused_window | is-empty) {
|
||||
{ is_kitty: false, pid: null }
|
||||
} else {
|
||||
let info = (niri msg --json windows | from json | where id == $focused_window | first)
|
||||
{ is_kitty: ($info.app_id? == "kitty"), pid: $info.pid? }
|
||||
}
|
||||
} else {
|
||||
let focused_window = (kdotool getactivewindow)
|
||||
{
|
||||
is_kitty: ((kdotool getwindowclassname $focused_window) == "kitty"),
|
||||
pid: (kdotool getwindowpid $focused_window | into int)
|
||||
}
|
||||
let window = (active-window | from json)
|
||||
let window_info = {
|
||||
is_kitty: ($window.class? == "kitty"),
|
||||
pid: $window.pid?
|
||||
}
|
||||
|
||||
if $window_info.is_kitty {
|
||||
|
|
|
|||
11
secrets/aws-credentials.age
Normal file
11
secrets/aws-credentials.age
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
age-encryption.org/v1
|
||||
-> X25519 j9CFK6quTBAviKfxt7nk/sdsTR/5swqEfqLgo7gjmTw
|
||||
BSrgJCxZY1nIOtjkzAdx60POzJ98IF5ryF1SLXKMgZk
|
||||
-> piv-p256 Kmn3OQ AwqKwTZh40d7YdbU3mMJFhKz75X/NKfXdBCzpKWf75uo
|
||||
FIuAwxkVMN12HoV7SN7iq1fOhqakL4Lbz5Wp/PabTO4
|
||||
-> F=1e<+J-grease pk rVDW+r/ Zme4
|
||||
y52QMNBhnOd9wwF4NauKUGkRCt99O7L+cqGD6od03cDf79bfsCxc0jyY7wW+fe9R
|
||||
TgFDwzdeRl4LQCL/3uH4bj+j
|
||||
--- zuMUxvMUyLES8iVG6tbdW/oU0bAaTDlRJwN7x+k6kTw
|
||||
Ê_Ï5ýZÄB£öÛù~Úi©Ç%<25>B¸3RÕ›ËrÜËôê˜<C3AA>W<| ASƒ•=œ×³Û*IÁ~޻ئ<C398>y$¦äY´`Óp|F¨Èz?nR ÄÂâÚ4h7y·Á#‘
/r…Vy«|Ò¢B+~òBfÁƒ;±å|áÇWu¤$Y“E=ËÇIÁU'… ¬
|
||||
¯
|
||||
BIN
secrets/nix-cache-privkey.age
Normal file
BIN
secrets/nix-cache-privkey.age
Normal file
Binary file not shown.
11
secrets/nix-cache-s3.env.age
Normal file
11
secrets/nix-cache-s3.env.age
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
age-encryption.org/v1
|
||||
-> X25519 pxQqMT3kixRevDw5AOugW61Stxpa54NPwdaMDf5ywBc
|
||||
emM75EuTf5bL1eueeWsmFfbEZDT5+27VzBOQgCfGzlw
|
||||
-> piv-p256 Kmn3OQ A92Zkli15jy0zZZiW+VYVi5apkhwXi5gZdGsfz4Nzrai
|
||||
wP2maNvDOmxxA6PMcj930SJLFnExpQHYOqWVXvh2g3o
|
||||
-> ,*$Gmjb-grease `Ob>AA UG\`RJP S @-2
|
||||
+HbUwSV+W2xrg8coxxpvSQ+VfPGWfqr0HjtDmX3wCmCO0jpjqKqRCDEAsTj5oTKL
|
||||
MUOwTg
|
||||
--- Ib2BGSJRp6WTD55zNN072D+RFxRegKZhjXa48sKg3+Q
|
||||
ìLŸôÐô~\FþQ$€´¬šáûÌFõ²
|
||||
i¯ E±EØ®ÔMi[x¿/z ÒþŠ¢·ÿÃ×s‡ÆüÆg®l8· 6tÒìi]ø’¨0Èo6—¿%’ÆúáÜÐc/ïÃ+%Ô¹Œ~ùšHˆpPŽ‘%[úuQ;шŒ_[p_§²}ªw†È
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
age-encryption.org/v1
|
||||
-> ssh-ed25519 /u/eYA jAj/U8H5mR2k4JV8FEckBb8vmpGP9LLCFCFATVZd4yA
|
||||
WyXJPAyZS2Dq93pK2GuVYNbBIxNyvEVJuVWrpZS89Zs
|
||||
-> @W-grease _
|
||||
Gd35VA
|
||||
--- 6blY/MMnEQunu/tWdJv/oGaqf1i6Pv+xdrqLV0EZNes
|
||||
«<EFBFBD>ˆëÇægŒúóþ/½çM0•2äPçÿ!°9XU–ÂxÖKï¦(ònÊ“ëçã×…/¯j„[`fÃ<66>.Nf¯f1ã ÃVíŒë€á!·rÆ}h`êûåÑeƒàsÀ/&8¾£þÅÛ¥«ûSÙ2ËÏ!o£úõ¾NjÞÕpäL?ïX]Ív<C38D>8C
|
||||
Binary file not shown.
|
|
@ -0,0 +1,8 @@
|
|||
age-encryption.org/v1
|
||||
-> ssh-ed25519 Sih9FA DiICdXQXdFzjmLaO3TbZmurGr7rRlOyeyT4B6Q2hbgw
|
||||
AMltu9LuCxoev0zm5Ihoa0aSYVvs7SAD04NIF4gyMxw
|
||||
-> K0!Lf-grease AnUy
|
||||
q4vQ1RJdAeh03A
|
||||
--- g4sTWmo/FkvfmPBcfalOQE3FUapLvqYKLEfqDUvt2Yw
|
||||
*ñUäA†±=¾w1üƒ·&º*d©UÙÎ<C399>s>a4¦s«˜hi<68>g<EFBFBD>€}K Š»}ÒïàÆ8dÄþp‰¸œˆÔVë†bB¼•†TxéÊ<C3A9>ÈŒ0sˆüdÃ÷Q¿UR+
|
||||
nF?æÈÚ ýƒÏP'i¥Xœ²)¥UsÜq¶²EŒ~Êèi¥ûÀˆ=âµ|<7C>P.¥ùÁâ2
|
||||
Loading…
Add table
Reference in a new issue