Compare commits
224 Commits
intel-graphics
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 474bd840d2 | |||
| a2b4d0f479 | |||
| 4eeef628b0 | |||
| 559edbe89a | |||
| 753426fd91 | |||
| 8a7439fe1d | |||
| bb42e115d5 | |||
| 0f1c9235e9 | |||
| 09b1b838b0 | |||
| 4aa2e67794 | |||
| efe63cb0a9 | |||
| 181ee03cc2 | |||
| 3d881785d5 | |||
| d48267c8ad | |||
| 94e1d17ad7 | |||
| 92291d7a12 | |||
| 50f25bc6a4 | |||
| ee01610675 | |||
| 261b5dd0b2 | |||
| 7c41597269 | |||
| 02a7d44b57 | |||
| 6f67e5f451 | |||
| 6c397bc61a | |||
| be52931cbe | |||
| 9af55f9e16 | |||
| beb62ba7e0 | |||
| a8e27ee9d3 | |||
| c9f554e276 | |||
| 6385102d3d | |||
| 1e1238a6c1 | |||
| 6584bf521f | |||
| f4005787ba | |||
| 5939224604 | |||
| bd80c370bf | |||
| a5089b77e9 | |||
| abdf71f7dc | |||
| 1219e2e69f | |||
| 94666c75a0 | |||
| b6efd4d27b | |||
| 0993a23874 | |||
| ae1ac19436 | |||
| 6caa433b50 | |||
| e8086e8528 | |||
| 48225afa6d | |||
| c9ca5b2952 | |||
| e38135a054 | |||
| d673653afb | |||
| 7e3cae0f4f | |||
| b100de6f87 | |||
| 7f3daae4fe | |||
| 685f414839 | |||
| 69007bcf02 | |||
| 682bb61037 | |||
| 3ba8564194 | |||
| 0ed0b1e6c5 | |||
| bf3e86e56a | |||
| afb7ef8c68 | |||
| 616a3929cd | |||
| f9dfa0404e | |||
| c763eed5b6 | |||
| b7fae3aa17 | |||
| 68faf941b7 | |||
| b9e8198607 | |||
| e78891a63e | |||
| 900a963c79 | |||
| 746487377e | |||
| 0eda413f66 | |||
| 9d5cffee14 | |||
| 669e590c60 | |||
| f2177c0c68 | |||
| 8b23df9fed | |||
| 57e1e116c2 | |||
| 38dff7bfeb | |||
| 8e1025a3c1 | |||
| 346d407744 | |||
| 265d97cecc | |||
| 5098792587 | |||
| f4df2ab6eb | |||
| b46e05fd71 | |||
| a593e0696e | |||
| fa97d8857d | |||
| 1bd6c0e599 | |||
| e72616534e | |||
| 5e2701d93f | |||
| 8e83f70d27 | |||
| 46d60f132e | |||
| 488721bc7c | |||
| 5070f11eed | |||
| d1a39f7d19 | |||
| b21ad24226 | |||
| fd495e35f8 | |||
| 4793175aa4 | |||
| c9a4f52c31 | |||
| e17d9b8278 | |||
| 82477f5be9 | |||
| cea4993cad | |||
| a8725139d0 | |||
| edad4122b0 | |||
| b431113faf | |||
| ebfba09c8d | |||
| d36188ec6c | |||
| b23d228e35 | |||
| d4659b1b04 | |||
| 0dff3c1585 | |||
| d026c0c4fa | |||
| a0052892c8 | |||
| d140e4fe20 | |||
| 80530a876e | |||
| a255a6969e | |||
| 9231cc6703 | |||
| 6b1feea23c | |||
| 8b08019611 | |||
| 8515801e0d | |||
| 210816b5f1 | |||
| 1f1cfd1528 | |||
| 4e93ef4719 | |||
| c3bf9e2817 | |||
| c86ebb5d5a | |||
| 22c193ddc2 | |||
| d00a6b0462 | |||
| 8cb30ac572 | |||
| a581b4eb07 | |||
| f0d3a146a0 | |||
| 016fbd726b | |||
| 92eb194682 | |||
| 90706618e7 | |||
| c681394ff7 | |||
| 6e23c3b7f7 | |||
| aab35e484c | |||
| 9f7157771c | |||
| 65dd668e9e | |||
| df363e4836 | |||
| c99ef360a9 | |||
| 02354206d3 | |||
| fee579a16d | |||
| 558b0b0964 | |||
| 9ff2c240a9 | |||
| 4ea74bd1ab | |||
| d3d019c0c6 | |||
| bdb880e6bc | |||
| 3f78498f09 | |||
| bfaf0d46d9 | |||
| e08defd4f4 | |||
| 3e3ad71e27 | |||
| e58144016f | |||
| 2f3eb7a426 | |||
| 0ba95c35e5 | |||
| c41f1c5c70 | |||
| ffcc7b397f | |||
| 29821d2531 | |||
| d45f9f1869 | |||
| 9100ab46ac | |||
| 3257d435d1 | |||
| dcbd73a9cf | |||
| d497c84643 | |||
| b25f09af9c | |||
| 7f6cd33011 | |||
| bf1acd55b7 | |||
| 7de527822c | |||
| e10d94b329 | |||
| 2d1bd96434 | |||
| 0f2a209c52 | |||
| 855b54e0c2 | |||
| 0137e92e0d | |||
| b5733171e3 | |||
| 94a877d5cb | |||
| 97c9400530 | |||
| d01952ae2b | |||
| 22c887abc4 | |||
| 3c3f66ee6d | |||
| a849ff0c7b | |||
| 1aea9ec423 | |||
| bc8a219f16 | |||
| e14bb4de17 | |||
| 587114e642 | |||
| 8f374aaa95 | |||
| 622484eb93 | |||
| 7d0acb6165 | |||
| e42a7e30a0 | |||
| c2afc748c6 | |||
| 908dffd29a | |||
| fbae48a832 | |||
| 73ac1b10c1 | |||
| dbbb887a82 | |||
| cbab3c5cb1 | |||
| c0751a61cf | |||
| 15c15b1bf8 | |||
| 54a47415aa | |||
| 9cd16e4991 | |||
| 002765d5a6 | |||
| 2a6f4ae648 | |||
| 3bf1766695 | |||
| 63dba816c2 | |||
| 629840f7e6 | |||
| 3dd30db025 | |||
| e6f66b97eb | |||
| 4e6c560c89 | |||
| cf11bdb40d | |||
| 434b07dd4d | |||
| ed539c6764 | |||
| b691497600 | |||
| f1f01e917a | |||
| ee45f05948 | |||
| 3579707156 | |||
| 61a357409b | |||
| 49a137bc86 | |||
| 96725612b9 | |||
| af46e1dd87 | |||
| 793be6d767 | |||
| af99c3be6f | |||
| ad13045c12 | |||
| 149079e822 | |||
| 17ab594730 | |||
| c529670dec | |||
| cb34bbf467 | |||
| f6c5af6238 | |||
| db327aa6d7 | |||
| c1419de69c | |||
| 00f1eb1912 | |||
| 80846e8671 | |||
| fb2ec0f227 | |||
| af98eb69fb | |||
| ae9aa49576 | |||
| 31f6d2417b |
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"WebSearch",
|
||||
"WebFetch(domain:wiki.hypr.land)",
|
||||
"WebFetch(domain:gist.github.com)",
|
||||
"WebFetch(domain:github.com)",
|
||||
"Bash(GH_PAGER=cat gh api:*)",
|
||||
"Bash(kitten @ launch:*)",
|
||||
"Bash(for name in designer-bold designer analyze-branch oracle librarian git-master planning-with-files react-patterns vercel-react-best-practices smart-debug tdd-cycle security-scan issue remove-deadcode worktree-compare worktree-list)",
|
||||
"Bash(do mv \"commands/$name.md\" \"skills/$name/SKILL.md\")",
|
||||
"Bash(done)",
|
||||
"Bash(TUICR_TERMINAL=kitty /home/naps62/.claude/skills/tuicr/tuicr-wrapper.sh:*)",
|
||||
"Bash(nix search:*)",
|
||||
"WebFetch(domain:raw.githubusercontent.com)",
|
||||
"WebFetch(domain:api.github.com)",
|
||||
"WebFetch(domain:docs.tempo.xyz)",
|
||||
"Bash(nix-prefetch-url:*)",
|
||||
"WebFetch(domain:release-assets.githubusercontent.com)",
|
||||
"Bash(nix build:*)",
|
||||
"Bash(nix-build:*)",
|
||||
"Bash(direnv version:*)",
|
||||
"Bash(nix:*)",
|
||||
"WebFetch(domain:devenv.sh)",
|
||||
"WebFetch(domain:discourse.nixos.org)",
|
||||
"Bash(curl:*)",
|
||||
"WebFetch(domain:quickshell.org)",
|
||||
"WebFetch(domain:www.tonybtw.com)",
|
||||
"Bash(systemctl:*)",
|
||||
"Bash(darkman get:*)",
|
||||
"Bash(dconf read:*)",
|
||||
"Bash(journalctl:*)",
|
||||
"Bash(hyprctl:*)",
|
||||
"WebFetch(domain:docs.noctalia.dev)",
|
||||
"WebFetch(domain:gerg-l.github.io)",
|
||||
"Bash(pw-cli info:*)",
|
||||
"WebFetch(domain:jgrulich.cz)",
|
||||
"WebFetch(domain:fedoraproject.org)",
|
||||
"WebFetch(domain:docs.pipewire.org)",
|
||||
"Bash(wpctl status:*)",
|
||||
"WebFetch(domain:bugs.chromium.org)",
|
||||
"WebFetch(domain:gitlab.freedesktop.org)",
|
||||
"Bash(python3 -c ' *)"
|
||||
]
|
||||
},
|
||||
"sandbox": {
|
||||
"enabled": true,
|
||||
"autoAllowBashIfSandboxed": false
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
nix build .#nixosConfigurations.live.config.system.build.isoImage
|
||||
Generated
+675
-533
File diff suppressed because it is too large
Load Diff
@@ -15,9 +15,6 @@
|
||||
url = "github:nix-community/home-manager";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
nix-colors.url = "github:misterio77/nix-colors";
|
||||
nixvim.url = "github:nix-community/nixvim";
|
||||
neovim-nightly-overlay.url = "github:nix-community/neovim-nightly-overlay";
|
||||
nvchad4nix = {
|
||||
url = "github:nix-community/nix4nvchad";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
@@ -30,12 +27,23 @@
|
||||
foundry = {
|
||||
url = "github:shazow/foundry.nix";
|
||||
};
|
||||
utils.url = "github:numtide/flake-utils";
|
||||
hardware.url = "github:NixOS/nixos-hardware/master";
|
||||
firefox-addons.url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons";
|
||||
rose-pine-hyprcursor.url = "github:ndom91/rose-pine-hyprcursor";
|
||||
hyprpanel = {
|
||||
url = "github:Jas-SinghFSU/HyprPanel";
|
||||
zen-browser.url = "github:0xc000022070/zen-browser-flake";
|
||||
ethui.url = "github:ethui/ethui/nix";
|
||||
hyprland = {
|
||||
type = "git";
|
||||
url = "https://github.com/hyprwm/Hyprland";
|
||||
submodules = true;
|
||||
};
|
||||
noctalia = {
|
||||
url = "github:noctalia-dev/noctalia-shell";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
spicetify-nix.url = "github:Gerg-L/spicetify-nix";
|
||||
claude-code.url = "github:sadjow/claude-code-nix";
|
||||
nix-index-database = {
|
||||
url = "github:nix-community/nix-index-database";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
@@ -46,7 +54,6 @@
|
||||
systems,
|
||||
nixpkgs,
|
||||
home-manager,
|
||||
utils,
|
||||
...
|
||||
}@inputs:
|
||||
let
|
||||
@@ -56,15 +63,14 @@
|
||||
import nixpkgs {
|
||||
inherit system;
|
||||
config.allowUnfree = true;
|
||||
config.android_sdk.accept_license = true;
|
||||
overlays = [
|
||||
inputs.foundry.overlay
|
||||
inputs.hyprpanel.overlay
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
x86 = pkgsFor.x86_64-linux;
|
||||
aarch64 = pkgsFor.aarch64-linux;
|
||||
|
||||
mkNixOS =
|
||||
name:
|
||||
@@ -81,26 +87,25 @@
|
||||
name: pkgs:
|
||||
home-manager.lib.homeManagerConfiguration {
|
||||
inherit pkgs;
|
||||
modules = [ ./home/${name} ];
|
||||
modules = [
|
||||
./home/${name}
|
||||
];
|
||||
extraSpecialArgs = {
|
||||
inherit inputs outputs;
|
||||
inherit inputs outputs self;
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
nixosConfigurations = {
|
||||
arrakis = mkNixOS "arrakis";
|
||||
trantor = mkNixOS "trantor";
|
||||
desktop = mkNixOS "desktop";
|
||||
pi = mkNixOS "pi";
|
||||
live = mkNixOS "live";
|
||||
konishi = mkNixOS "konishi";
|
||||
};
|
||||
|
||||
# Named "<user>@<host>" so `nh home switch` auto-detects them
|
||||
# (nh home tries "$USER@$(hostname)", not the bare hostname).
|
||||
homeConfigurations = {
|
||||
arrakis = mkHome "arrakis" x86;
|
||||
trantor = mkHome "trantor" x86;
|
||||
desktop = mkHome "desktop" x86;
|
||||
pi = mkHome "pi" aarch64;
|
||||
"naps62@arrakis" = mkHome "arrakis" x86;
|
||||
"naps62@konishi" = mkHome "konishi" x86;
|
||||
};
|
||||
|
||||
devShells =
|
||||
@@ -114,4 +119,3 @@
|
||||
forEachPkg (pkgs: import ./shell.nix { inherit pkgs; });
|
||||
};
|
||||
}
|
||||
# Note: Can also be referenced withou
|
||||
|
||||
+23
-26
@@ -1,47 +1,44 @@
|
||||
{
|
||||
inputs,
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
outputs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
imports = [
|
||||
inputs.nix-colors.homeManagerModule
|
||||
inputs.nixvim.homeManagerModules.nixvim
|
||||
../common/programs/default.nix
|
||||
../common/programs/desktop
|
||||
../common/programs/zen-browser.nix
|
||||
../common/programs/hyprland
|
||||
../common/programs/ghostty.nix
|
||||
../common/programs/syncthing.nix
|
||||
../common/programs/kitty
|
||||
../common/programs/unity.nix
|
||||
../common/programs/ethui.nix
|
||||
../common/programs/gpg.nix
|
||||
../common/features/xdg.nix
|
||||
../common/features/bluetooth.nix
|
||||
../common/features/downloads-cleanup.nix
|
||||
../common/programs/3d.nix
|
||||
../common/programs/godot.nix
|
||||
./monitors.nix
|
||||
];
|
||||
|
||||
home.sessionVariables = {
|
||||
LIBVA_DRIVER_NAME = "nvidia";
|
||||
XDG_SESSION_TYPE = "wayland";
|
||||
GDM_BACKEND = "nvidia-drm";
|
||||
__GLX_VENDOR_LIBRARY_NAME = "nvidia";
|
||||
};
|
||||
custom.hyprland.cursorSize = 32;
|
||||
|
||||
wayland.windowManager.hyprland.settings = {
|
||||
windowrulev2 = [
|
||||
"float, class:thunar"
|
||||
"move cursor -50% -50%, class:thunar"
|
||||
"size 800 600, class:thunar"
|
||||
exec-once = [
|
||||
];
|
||||
|
||||
env = [
|
||||
"GDK_SCALE, 1.5"
|
||||
workspace = [
|
||||
"1, monitor:DP-3"
|
||||
"2, monitor:eDP-1"
|
||||
"3, monitor:eDP-1"
|
||||
"4, monitor:eDP-1"
|
||||
];
|
||||
|
||||
windowrule = [
|
||||
"no_initial_focus on, match:class bevy-.*"
|
||||
"float on, match:class bevy-.*"
|
||||
"size 800 600, match:class bevy-.*"
|
||||
"move 100%-800 100%-600, match:class bevy-.*"
|
||||
];
|
||||
};
|
||||
|
||||
home = {
|
||||
username = lib.mkDefault "naps62";
|
||||
stateVersion = lib.mkDefault "24.05";
|
||||
};
|
||||
# v4 `bar.density` has no v5 equivalent; spacing is tuned via
|
||||
# bar.main.padding / widget_spacing / thickness if needed.
|
||||
}
|
||||
|
||||
@@ -1,24 +1,12 @@
|
||||
{
|
||||
inputs,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
wallpaper1 = pkgs.fetchurl {
|
||||
url = "https://4kwallpapers.com/images/wallpapers/abstract-design-3840x2160-17068.jpg";
|
||||
hash = "sha256-F/XE/ETwzYwtbQWXY78c2AJc8xe2mRunB8Q9/c2F7kY=";
|
||||
};
|
||||
in
|
||||
_:
|
||||
{
|
||||
wayland.windowManager.hyprland.settings = {
|
||||
monitor = [
|
||||
"eDP-1, preferred, 0x0, 1, bitdepth, 8"
|
||||
"DP-1, preferred, auto-up, 1"
|
||||
"DP-2, preferred, auto-up, 1"
|
||||
"DP-3, preferred, auto-up, 1"
|
||||
"DP-4, preferred, auto-up, 1"
|
||||
];
|
||||
};
|
||||
|
||||
services.hyprpaper.settings.preload = [ (builtins.toString wallpaper1) ];
|
||||
services.hyprpaper.settings.wallpaper = [
|
||||
"eDP-1,${builtins.toString wallpaper1}"
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
# services.blueman-applet.enable = true;
|
||||
|
||||
# systemd.user.services.mpris-proxy = {
|
||||
# description = "Mpris proxy";
|
||||
# after = [
|
||||
# "network.target"
|
||||
# "sound.target"
|
||||
# ];
|
||||
# wantedBy = [ "default.target" ];
|
||||
# serviceConfig.ExecStart = "${pkgs.bluez}/bin/mpris-proxy";
|
||||
# };
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
{ pkgs, config, ... }:
|
||||
|
||||
let
|
||||
downloadsDir = "${config.home.homeDirectory}/downloads";
|
||||
# Age in days after which files should be deleted
|
||||
maxAge = 30;
|
||||
in
|
||||
{
|
||||
systemd.user.services.downloads-cleanup = {
|
||||
Unit = {
|
||||
Description = "Clean old files from downloads subdirectories";
|
||||
};
|
||||
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${pkgs.writeShellScript "downloads-cleanup" ''
|
||||
set -euo pipefail
|
||||
|
||||
echo "Starting downloads cleanup..."
|
||||
echo "Cleaning files older than ${toString maxAge} days from ${downloadsDir}/*/ (including hidden files)"
|
||||
|
||||
# Find and delete files older than maxAge days in subdirectories of downloads
|
||||
# -mindepth 2 ensures we only look inside subdirectories, not in downloads/ itself
|
||||
# -type f ensures we only delete files, not directories
|
||||
# This includes hidden files and directories
|
||||
if [ -d "${downloadsDir}" ]; then
|
||||
${pkgs.findutils}/bin/find "${downloadsDir}" \
|
||||
-mindepth 2 \
|
||||
-type f \
|
||||
-mtime +${toString maxAge} \
|
||||
-print \
|
||||
-delete 2>/dev/null || true
|
||||
|
||||
# Also remove empty directories (including hidden ones)
|
||||
${pkgs.findutils}/bin/find "${downloadsDir}" \
|
||||
-mindepth 2 \
|
||||
-type d \
|
||||
-empty \
|
||||
-print \
|
||||
-delete 2>/dev/null || true
|
||||
|
||||
echo "Cleanup completed successfully"
|
||||
else
|
||||
echo "Downloads directory does not exist, skipping cleanup"
|
||||
fi
|
||||
''}";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.user.timers.downloads-cleanup = {
|
||||
Unit = {
|
||||
Description = "Timer for downloads cleanup";
|
||||
};
|
||||
|
||||
Timer = {
|
||||
OnCalendar = "daily";
|
||||
Persistent = true;
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "timers.target" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
ledger-live-desktop
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
self,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.home.mutableFiles;
|
||||
repoPath = config.home.mutableFilesRepoPath;
|
||||
flakePrefix = self.outPath;
|
||||
|
||||
fileEntries = lib.attrsToList cfg;
|
||||
|
||||
toRepoPath = storePath: repoPath + lib.removePrefix flakePrefix (toString storePath);
|
||||
|
||||
checkScript = lib.concatMapStringsSep "\n" (
|
||||
{ name, value }:
|
||||
let
|
||||
target = "${config.home.homeDirectory}/${name}";
|
||||
storePath = value.source;
|
||||
originalPath = toRepoPath value.source;
|
||||
in
|
||||
''
|
||||
if [ -f "${target}" ] && ! ${lib.getExe' pkgs.diffutils "diff"} -q "${storePath}" "${target}" > /dev/null 2>&1; then
|
||||
echo ""
|
||||
echo "!! mutable file changed: ${name}"
|
||||
echo " To bring changes upstream:"
|
||||
echo " cp ${target} ${originalPath}"
|
||||
echo ""
|
||||
${lib.getExe' pkgs.diffutils "diff"} -u "${storePath}" "${target}" || true
|
||||
_mutable_changed=1
|
||||
fi
|
||||
''
|
||||
) fileEntries;
|
||||
|
||||
copyScript = lib.concatMapStringsSep "\n" (
|
||||
{ name, value }:
|
||||
let
|
||||
target = "${config.home.homeDirectory}/${name}";
|
||||
inherit (value) source;
|
||||
dirName = builtins.dirOf target;
|
||||
in
|
||||
''
|
||||
mkdir -p "${dirName}"
|
||||
cp -f "${source}" "${target}"
|
||||
chmod ${if value.executable then "755" else "644"} "${target}"
|
||||
''
|
||||
) fileEntries;
|
||||
in
|
||||
{
|
||||
options.home.mutableFilesRepoPath = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "Absolute path to the nixos-config repo on disk.";
|
||||
};
|
||||
|
||||
options.home.mutableFiles = lib.mkOption {
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule {
|
||||
options = {
|
||||
source = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
description = "Path to the source file.";
|
||||
};
|
||||
executable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Whether the file should be executable.";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
default = { };
|
||||
description = "Files to copy (not symlink) into the home directory, with change detection.";
|
||||
};
|
||||
|
||||
config = lib.mkIf (cfg != { }) {
|
||||
home.activation.mutableFiles = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||
_mutable_changed=0
|
||||
${checkScript}
|
||||
if [ "$_mutable_changed" -eq 1 ]; then
|
||||
echo ""
|
||||
echo "!! Aborting: mutable files have been modified outside of nix."
|
||||
echo " Bring the changes upstream first, then re-run."
|
||||
exit 1
|
||||
fi
|
||||
${copyScript}
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
{ ... }:
|
||||
_:
|
||||
{
|
||||
xdg = {
|
||||
userDirs = {
|
||||
enable = true;
|
||||
createDirectories = true;
|
||||
createDirectories = false;
|
||||
# Keep exporting XDG_*_DIR as session variables (new default is false).
|
||||
setSessionVariables = true;
|
||||
desktop = null;
|
||||
documents = null;
|
||||
download = "downloads";
|
||||
@@ -18,11 +20,11 @@
|
||||
enable = true;
|
||||
defaultApplications = {
|
||||
# web
|
||||
"text/html" = "firefox.desktop";
|
||||
"x-scheme-handler/http" = "firefox.desktop";
|
||||
"x-scheme-handler/https" = "firefox.desktop";
|
||||
"x-scheme-handler/avbout" = "firefox.desktop";
|
||||
"x-scheme-handler/unknown" = "firefox.desktop";
|
||||
"text/html" = "google-chrome.desktop";
|
||||
"x-scheme-handler/http" = "zen-twilight.desktop";
|
||||
"x-scheme-handler/https" = "zen-twilight.desktop";
|
||||
"x-scheme-handler/avbout" = "zen-twilight.desktop";
|
||||
"x-scheme-handler/unknown" = "zen-twilight.desktop";
|
||||
|
||||
# video
|
||||
"video/mp4" = "mpv.desktop";
|
||||
@@ -36,14 +38,20 @@
|
||||
"image/png" = "imv.desktop";
|
||||
|
||||
# pdfs
|
||||
"application/pdf" = "zathura.pdf";
|
||||
"application/fdf" = "zathura.pdf";
|
||||
"application/pdx" = "zathura.pdf";
|
||||
"application/x-pdf" = "zathura.pdf";
|
||||
"application/xfdf" = "zathura.pdf";
|
||||
"application/pdf" = "org.pwmt.zathura.desktop";
|
||||
"application/fdf" = "org.pwmt.zathura.desktop";
|
||||
"application/pdx" = "org.pwmt.zathura.desktop";
|
||||
"application/x-pdf" = "org.pwmt.zathura.desktop";
|
||||
"application/xfdf" = "org.pwmt.zathura.desktop";
|
||||
|
||||
# files
|
||||
"inode/directory" = "thunar.desktop";
|
||||
|
||||
# 3d printing
|
||||
"model/3mf" = "PrusaSlicer.desktop";
|
||||
"application/x-3mf" = "PrusaSlicer.desktop";
|
||||
"model/stl" = "PrusaSlicer.desktop";
|
||||
"application/sla" = "PrusaSlicer.desktop";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
blender
|
||||
prusa-slicer
|
||||
google-fonts
|
||||
];
|
||||
|
||||
fonts.fontconfig.enable = true;
|
||||
|
||||
xdg.desktopEntries.prusaslicer-url-handler = {
|
||||
name = "PrusaSlicer Protocol Handler";
|
||||
exec = "prusa-slicer %u";
|
||||
type = "Application";
|
||||
noDisplay = true;
|
||||
mimeType = [ "x-scheme-handler/prusaslicer" ];
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Screenshots: stored in ~/downloads/screenshots, with date time in the filename
|
||||
@@ -0,0 +1,20 @@
|
||||
Download a music playlist for "aulas de música" (kids music classes).
|
||||
|
||||
The user will paste the content of a monthly playlist from the teacher. Extract all URLs (SoundCloud and YouTube links, which may be split across multiple lines) and download them as MP3 files.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Parse the pasted content to extract all URLs. Links are often split across lines — reconstruct them by joining consecutive lines that form a single URL.
|
||||
2. Determine the month name from the content (e.g., "Creche - março" → "marco").
|
||||
3. Create the folder `aulas-musica-{month}` in the current directory.
|
||||
4. Download all tracks as MP3 using yt-dlp via nix-shell:
|
||||
```
|
||||
TMPDIR=/tmp nix-shell -p yt-dlp ffmpeg --run 'cd <folder> && yt-dlp -x --audio-format mp3 -o "%(title)s.%(ext)s" <urls>'
|
||||
```
|
||||
5. List the downloaded files to confirm everything worked.
|
||||
|
||||
## Important
|
||||
|
||||
- Always use `TMPDIR=/tmp` before `nix-shell` (NixOS sandbox compatibility).
|
||||
- Always use `dangerouslyDisableSandbox: true` for the download command.
|
||||
- Reconstruct URLs carefully — SoundCloud short links and YouTube links are often broken across 2 lines in the pasted content.
|
||||
@@ -0,0 +1,20 @@
|
||||
Merge a branch from the worktree.
|
||||
If you're currently working on a worktree, assume that's the one I'm referring to.
|
||||
|
||||
Start by committing any staged and unstaged changes. I may have made changes to the worktree manually.
|
||||
Then merge back the new main branch, since I may have made changes to it.
|
||||
|
||||
# Language specific:
|
||||
|
||||
## Rust
|
||||
|
||||
Ensure cargo check is happy.
|
||||
Ensure clippy is happy. clean up any new warnings.
|
||||
|
||||
## Typescript
|
||||
|
||||
Ensure tsc is happy.
|
||||
|
||||
# Finally
|
||||
|
||||
Squash the commits into a single one, merge into the base branch, and delete the worktree.
|
||||
@@ -0,0 +1,6 @@
|
||||
This command should only work while in a secondary branch (not main or master).
|
||||
|
||||
Commit any unstaged changes
|
||||
Fetch updates from the origin repo
|
||||
If there are new commits on the parent branch (typically origin/main), then merge them back into the current branch
|
||||
Solve any conflicts, and analyze the incoming changes to see if additional changes are required to the branch's code (e.g.: if something was renamed in the meantime in main, our new code may need to be adjusted)
|
||||
@@ -0,0 +1,64 @@
|
||||
{ pkgs, inputs, ... }:
|
||||
{
|
||||
home.file.".default-npm-packages".text = ''
|
||||
@anthropic-ai/sandbox-runtime
|
||||
@beads/bd
|
||||
'';
|
||||
|
||||
home.packages = with pkgs; [
|
||||
inputs.claude-code.packages.${pkgs.stdenv.hostPlatform.system}.default
|
||||
|
||||
# sandbox
|
||||
bubblewrap
|
||||
socat
|
||||
libseccomp
|
||||
|
||||
# voice
|
||||
sox
|
||||
|
||||
# beads
|
||||
dolt
|
||||
];
|
||||
|
||||
# Commands
|
||||
home.file.".claude/commands/merge.md".source = ./commands/merge.md;
|
||||
home.file.".claude/commands/update.md".source = ./commands/update.md;
|
||||
home.file.".claude/commands/download-playlist.md".source = ./commands/download-playlist.md;
|
||||
|
||||
# Skills: agents
|
||||
home.file.".claude/skills/designer-bold/SKILL.md".source = ./skills/designer-bold/SKILL.md;
|
||||
home.file.".claude/skills/designer/SKILL.md".source = ./skills/designer/SKILL.md;
|
||||
home.file.".claude/skills/frontend-design/SKILL.md".source = ./skills/frontend-design/SKILL.md;
|
||||
home.file.".claude/skills/analyze-branch/SKILL.md".source = ./skills/analyze-branch/SKILL.md;
|
||||
home.file.".claude/skills/oracle/SKILL.md".source = ./skills/oracle/SKILL.md;
|
||||
home.file.".claude/skills/librarian/SKILL.md".source = ./skills/librarian/SKILL.md;
|
||||
|
||||
# Skills: knowledge
|
||||
home.file.".claude/skills/git-master/SKILL.md".source = ./skills/git-master/SKILL.md;
|
||||
home.file.".claude/skills/planning-with-files/SKILL.md".source =
|
||||
./skills/planning-with-files/SKILL.md;
|
||||
home.file.".claude/skills/react-patterns/SKILL.md".source = ./skills/react-patterns/SKILL.md;
|
||||
home.file.".claude/skills/vercel-react-best-practices/SKILL.md".source =
|
||||
./skills/vercel-react-best-practices/SKILL.md;
|
||||
|
||||
# Skills: workflows
|
||||
home.file.".claude/skills/smart-debug/SKILL.md".source = ./skills/smart-debug/SKILL.md;
|
||||
home.file.".claude/skills/tdd-cycle/SKILL.md".source = ./skills/tdd-cycle/SKILL.md;
|
||||
home.file.".claude/skills/security-scan/SKILL.md".source = ./skills/security-scan/SKILL.md;
|
||||
home.file.".claude/skills/issue/SKILL.md".source = ./skills/issue/SKILL.md;
|
||||
home.file.".claude/skills/remove-deadcode/SKILL.md".source = ./skills/remove-deadcode/SKILL.md;
|
||||
home.file.".claude/skills/worktree-compare/SKILL.md".source = ./skills/worktree-compare/SKILL.md;
|
||||
home.file.".claude/skills/worktree-list/SKILL.md".source = ./skills/worktree-list/SKILL.md;
|
||||
|
||||
# Skills: linear workflow
|
||||
home.file.".claude/skills/linear-common/COMMON.md".source = ./skills/linear-common/COMMON.md;
|
||||
home.file.".claude/skills/work/SKILL.md".source = ./skills/work/SKILL.md;
|
||||
home.file.".claude/skills/yolo/SKILL.md".source = ./skills/yolo/SKILL.md;
|
||||
|
||||
home.file.".claude/statusline.sh" = {
|
||||
source = ./statusline.sh;
|
||||
executable = true;
|
||||
};
|
||||
home.mutableFiles.".claude/settings.json".source = ./settings.json;
|
||||
home.file.".claude/CLAUDE.md".source = ./CLAUDE.md;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/claude-code-settings.json",
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Edit",
|
||||
"Write",
|
||||
"Bash(ls:*)",
|
||||
"Bash(tree:*)",
|
||||
"Bash(cat:*)",
|
||||
"Bash(head:*)",
|
||||
"Bash(tail:*)",
|
||||
"Bash(find:*)",
|
||||
"Bash(fd:*)",
|
||||
"Bash(grep:*)",
|
||||
"Bash(rg:*)",
|
||||
"Bash(wc:*)",
|
||||
"Bash(sort:*)",
|
||||
"Bash(uniq:*)",
|
||||
"Bash(diff:*)",
|
||||
"Bash(pwd:*)",
|
||||
"Bash(which:*)",
|
||||
"Bash(jq:*)",
|
||||
"Bash(git:*)",
|
||||
"Bash(gh:*)",
|
||||
"Bash(sed:*)",
|
||||
"Bash(cp:*)",
|
||||
"Bash(chmod:*)",
|
||||
"Bash(mkdir:*)",
|
||||
"Bash(kitty @ set-tab-title:*)"
|
||||
],
|
||||
"additionalDirectories": [
|
||||
"/home/naps62/projects",
|
||||
"/home/naps62/ethui",
|
||||
"/home/naps62/labs",
|
||||
"/home/naps62/subvisual"
|
||||
]
|
||||
},
|
||||
"statusLine": {
|
||||
"type": "command",
|
||||
"command": "~/.claude/statusline.sh"
|
||||
},
|
||||
"extraKnownMarketplaces": {
|
||||
"impeccable": {
|
||||
"source": {
|
||||
"source": "github",
|
||||
"repo": "pbakaus/impeccable"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sandbox": {
|
||||
"enabled": true,
|
||||
"autoAllowBashIfSandboxed": false,
|
||||
"allowedNetworkHosts": [
|
||||
"github.com",
|
||||
"api.github.com",
|
||||
"raw.githubusercontent.com",
|
||||
"gist.github.com",
|
||||
"release-assets.githubusercontent.com"
|
||||
]
|
||||
},
|
||||
"voiceEnabled": true,
|
||||
"defaultMode": "acceptEdits",
|
||||
"feedbackSurveyState": {
|
||||
"lastShownTime": 1754052643456
|
||||
},
|
||||
"mcpServers": {
|
||||
"herd-mcp": {
|
||||
"type": "http",
|
||||
"url": "https://mcp.herd.eco/v1"
|
||||
},
|
||||
"linear": {
|
||||
"type": "http",
|
||||
"url": "https://mcp.linear.app/mcp"
|
||||
},
|
||||
"home-assistant": {
|
||||
"type": "http",
|
||||
"url": "https://ha-mcp.n62.casa/mcp"
|
||||
}
|
||||
},
|
||||
"enabledPlugins": {
|
||||
"typescript-lsp@claude-plugins-official": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
description: Fast branch analysis - review changes for bugs, performance, security, and architecture issues
|
||||
---
|
||||
|
||||
# Analyze Branch
|
||||
|
||||
Analyze the current branch relative to the base branch and generate a detailed report in `reports/` focusing on:
|
||||
- Critical bugs (null safety, SQL injection, type errors)
|
||||
- N+1 queries and performance issues
|
||||
- Security vulnerabilities
|
||||
- Breaking changes (caller analysis)
|
||||
- Database migration risks
|
||||
- Architecture (SOLID/DRY)
|
||||
|
||||
Create the `reports/` directory if missing. Create/overwrite ONE report file in that directory.
|
||||
|
||||
## Constraints (CRITICAL)
|
||||
|
||||
- DO NOT execute commands that modify the repository or history.
|
||||
- DO NOT execute commands that modify dependencies or runtime state.
|
||||
- The only allowed write operation is the report file in `reports/`.
|
||||
|
||||
## Input
|
||||
|
||||
You may receive a branch/ref as an argument. If absent or empty, use the **current branch**.
|
||||
|
||||
## Procedure
|
||||
|
||||
### Step 1: Git Context
|
||||
|
||||
```bash
|
||||
CURRENT=$(git branch --show-current)
|
||||
BASE=$(git merge-base HEAD main 2>/dev/null || git merge-base HEAD master 2>/dev/null)
|
||||
git diff --name-only $BASE..HEAD
|
||||
git diff --stat $BASE..HEAD
|
||||
```
|
||||
|
||||
### Step 2: Analyze Changed Files
|
||||
|
||||
For each changed file:
|
||||
1. Read the full diff: `git diff $BASE..HEAD -- <file>`
|
||||
2. Read surrounding context in the file
|
||||
3. Check for issues listed above
|
||||
|
||||
### Step 3: Cross-Reference
|
||||
|
||||
- Check callers of modified functions (grep for function names across codebase)
|
||||
- Check if modified database queries have proper indexes
|
||||
- Check if new endpoints have authentication/authorization
|
||||
- Check if error handling covers new failure modes
|
||||
|
||||
### Step 4: Generate Report
|
||||
|
||||
Write report to `reports/branch-analysis-<branch-name>.md`:
|
||||
|
||||
```markdown
|
||||
# Branch Analysis: <branch-name>
|
||||
|
||||
**Date**: <date>
|
||||
**Base**: <base-branch>
|
||||
**Files Changed**: <count>
|
||||
**Risk Score**: <LOW|MEDIUM|HIGH|CRITICAL>
|
||||
|
||||
## Summary
|
||||
<1-3 sentence overview>
|
||||
|
||||
## Critical Findings
|
||||
### <Finding Title>
|
||||
- **Severity**: CRITICAL|HIGH|MEDIUM|LOW
|
||||
- **File**: path/to/file:line
|
||||
- **Issue**: Description
|
||||
- **Suggestion**: How to fix
|
||||
|
||||
## Performance
|
||||
<N+1 queries, missing indexes, expensive operations>
|
||||
|
||||
## Security
|
||||
<Auth gaps, injection risks, data exposure>
|
||||
|
||||
## Breaking Changes
|
||||
<API changes, schema changes, removed exports>
|
||||
|
||||
## Architecture
|
||||
<SOLID violations, DRY issues, complexity>
|
||||
```
|
||||
|
||||
### Step 5: Summary
|
||||
|
||||
Print the risk score and top 3 findings to stdout after writing the report.
|
||||
|
||||
$ARGUMENTS
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
description: Opinionated UI/UX specialist for distinctive, visually striking interfaces. Anti-generic-AI aesthetics. Bold typography, asymmetric layouts, intentional color.
|
||||
---
|
||||
|
||||
You are Designer Bold - a frontend UI/UX specialist who creates intentional, polished, DISTINCTIVE experiences.
|
||||
|
||||
**Role**: Craft cohesive UI/UX that balances visual impact with usability. Every interface should be memorable and deliberately designed for its context.
|
||||
|
||||
## Design Principles
|
||||
|
||||
**Typography**
|
||||
- Choose distinctive, characterful fonts that elevate aesthetics
|
||||
- Avoid generic defaults (Arial, Inter, Roboto, system fonts) -- opt for unexpected, beautiful choices
|
||||
- Pair a display font with a refined body font for hierarchy
|
||||
- Never converge on common AI choices (Space Grotesk) across designs
|
||||
|
||||
**Color & Theme**
|
||||
- Commit to a cohesive aesthetic with clear color variables
|
||||
- Dominant colors with sharp accents > timid, evenly-distributed palettes
|
||||
- Create atmosphere through intentional color relationships
|
||||
- Vary between light and dark themes -- no design should look the same
|
||||
|
||||
**Motion & Interaction**
|
||||
- Leverage framework animation utilities when available (Tailwind's transition/animation classes)
|
||||
- Focus on high-impact moments: orchestrated page loads with staggered reveals
|
||||
- Use scroll-triggers and hover states that surprise and delight
|
||||
- One well-timed animation > scattered micro-interactions
|
||||
- Drop to custom CSS/JS only when utilities can't achieve the vision
|
||||
|
||||
**Spatial Composition**
|
||||
- Break conventions: asymmetry, overlap, diagonal flow, grid-breaking
|
||||
- Generous negative space OR controlled density -- commit to the choice
|
||||
- Unexpected layouts that guide the eye
|
||||
|
||||
**Visual Depth**
|
||||
- Create atmosphere beyond solid colors: gradient meshes, noise textures, geometric patterns
|
||||
- Layer transparencies, dramatic shadows, decorative borders
|
||||
- Contextual effects that match the aesthetic (grain overlays, custom cursors)
|
||||
|
||||
**Styling Approach**
|
||||
- Default to Tailwind CSS utility classes when available -- fast, maintainable, consistent
|
||||
- Use custom CSS when the vision requires it: complex animations, unique effects, advanced compositions
|
||||
- Balance utility-first speed with creative freedom where it matters
|
||||
|
||||
**Match Vision to Execution**
|
||||
- Maximalist designs -> elaborate implementation, extensive animations, rich effects
|
||||
- Minimalist designs -> restraint, precision, careful spacing and typography
|
||||
- Elegance comes from executing the chosen vision fully, not halfway
|
||||
|
||||
## Design Thinking
|
||||
|
||||
Before coding, understand the context and commit to a BOLD aesthetic direction:
|
||||
- **Purpose**: What problem does this interface solve? Who uses it?
|
||||
- **Tone**: Pick an extreme: brutally minimal, maximalist chaos, retro-futuristic, organic/natural, luxury/refined, playful/toy-like, editorial/magazine, brutalist/raw, art deco/geometric, soft/pastel, industrial/utilitarian
|
||||
- **Constraints**: Technical requirements (framework, performance, accessibility)
|
||||
- **Differentiation**: What makes this UNFORGETTABLE? What's the one thing someone will remember?
|
||||
|
||||
## Constraints
|
||||
- Respect existing design systems when present
|
||||
- Leverage component libraries where available
|
||||
- Prioritize visual excellence -- code perfection comes second
|
||||
|
||||
## Skills
|
||||
- When implementing React components, use `/react-patterns` for code examples of composition, compound components, hooks, and accessibility patterns.
|
||||
- When optimizing performance, use `/vercel-react-best-practices` for Vercel's 45 prioritized performance rules.
|
||||
|
||||
You are capable of extraordinary creative work. Commit fully to distinctive visions and show what's possible when breaking conventions thoughtfully.
|
||||
|
||||
$ARGUMENTS
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
description: Conventional frontend specialist. React 18+, Tailwind CSS, TypeScript, accessibility (WCAG 2.1 AA), responsive design, performance optimization.
|
||||
---
|
||||
|
||||
You are Designer - a frontend specialist focused on building production-grade, accessible, performant interfaces.
|
||||
|
||||
## Core Stack
|
||||
|
||||
- **React 18+**: Server Components, Suspense, useTransition, useDeferredValue
|
||||
- **TypeScript**: Strict mode, no implicit any, explicit return types on exports
|
||||
- **Tailwind CSS**: Utility-first, design tokens via CSS variables, responsive with mobile-first breakpoints
|
||||
- **Accessibility**: WCAG 2.1 AA compliance from the start, not bolted on after
|
||||
|
||||
## Component Architecture
|
||||
|
||||
- **Composition over inheritance**: Build from small, focused components
|
||||
- **Compound components**: Use Context for implicit state sharing (Tabs, Accordion, Menu)
|
||||
- **Error boundaries**: Wrap critical UI sections with fallback UIs
|
||||
- **Single responsibility**: Each component does one thing well
|
||||
- **Props**: Use TypeScript interfaces, prefer explicit props over spreading
|
||||
|
||||
## Accessibility
|
||||
|
||||
- Semantic HTML first (button, nav, main, article, aside, header, footer)
|
||||
- Keyboard navigation for all interactive elements
|
||||
- Focus management for modals, dialogs, and dynamic content
|
||||
- ARIA attributes only when semantic HTML is insufficient
|
||||
- Color contrast: minimum 4.5:1 for normal text, 3:1 for large text
|
||||
- Touch targets: minimum 44x44px on mobile
|
||||
- Screen reader testing considerations in component design
|
||||
|
||||
## Performance Targets
|
||||
|
||||
- Largest Contentful Paint (LCP): < 2.5s
|
||||
- First Input Delay (FID): < 100ms
|
||||
- Cumulative Layout Shift (CLS): < 0.1
|
||||
- Bundle size awareness: code split at route boundaries, lazy load below-the-fold
|
||||
|
||||
## Performance Patterns
|
||||
|
||||
- `React.memo` for expensive pure components
|
||||
- `useMemo` for expensive calculations, `useCallback` for stable references passed to children
|
||||
- Code splitting with `React.lazy` and `Suspense` at route and feature boundaries
|
||||
- Virtualization for long lists (@tanstack/react-virtual)
|
||||
- Image optimization: lazy loading, proper dimensions, modern formats (WebP/AVIF)
|
||||
- Eliminate render waterfalls: parallel data fetching, avoid sequential awaits
|
||||
|
||||
## Styling Approach
|
||||
|
||||
- Tailwind utility classes as default
|
||||
- CSS variables for theme tokens (colors, spacing, typography scale)
|
||||
- Responsive: mobile-first with sm/md/lg/xl breakpoints
|
||||
- Dark mode via Tailwind's `dark:` variant with system preference detection
|
||||
- Animation: CSS transitions for simple effects, Framer Motion for complex orchestration
|
||||
- Consistent spacing scale, consistent border-radius, consistent shadow levels
|
||||
|
||||
## State Management
|
||||
|
||||
- Local state (`useState`) for component-scoped state
|
||||
- Context + `useReducer` for shared state within a feature
|
||||
- URL state for anything that should be shareable/bookmarkable
|
||||
- Server state via React Query / SWR / Server Components
|
||||
- Avoid prop drilling beyond 2 levels -- lift to Context or compose differently
|
||||
|
||||
## TypeScript Conventions
|
||||
|
||||
- PascalCase for components, interfaces, types
|
||||
- camelCase for functions, variables, hooks
|
||||
- Props interfaces named `ComponentNameProps`
|
||||
- Prefer `interface` for component props, `type` for unions/intersections
|
||||
- No `any` -- use `unknown` and narrow with type guards
|
||||
|
||||
## Testing Considerations
|
||||
|
||||
- Components should be testable with React Testing Library
|
||||
- Test behavior, not implementation details
|
||||
- Accessible queries first: getByRole, getByLabelText, getByText
|
||||
|
||||
## Skills
|
||||
|
||||
- When implementing React components, use `/react-patterns` for code examples of composition, compound components, hooks, and accessibility patterns.
|
||||
- When optimizing performance, use `/vercel-react-best-practices` for Vercel's 45 prioritized performance rules across 8 categories.
|
||||
|
||||
$ARGUMENTS
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
name: frontend-design
|
||||
description: Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML/CSS layouts, or when styling/beautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.
|
||||
license: Complete terms in LICENSE.txt
|
||||
---
|
||||
|
||||
This skill guides creation of distinctive, production-grade frontend interfaces that avoid generic "AI slop" aesthetics. Implement real working code with exceptional attention to aesthetic details and creative choices.
|
||||
|
||||
The user provides frontend requirements: a component, page, application, or interface to build. They may include context about the purpose, audience, or technical constraints.
|
||||
|
||||
## Design Thinking
|
||||
|
||||
Before coding, understand the context and commit to a BOLD aesthetic direction:
|
||||
- **Purpose**: What problem does this interface solve? Who uses it?
|
||||
- **Tone**: Pick an extreme: brutally minimal, maximalist chaos, retro-futuristic, organic/natural, luxury/refined, playful/toy-like, editorial/magazine, brutalist/raw, art deco/geometric, soft/pastel, industrial/utilitarian, etc. There are so many flavors to choose from. Use these for inspiration but design one that is true to the aesthetic direction.
|
||||
- **Constraints**: Technical requirements (framework, performance, accessibility).
|
||||
- **Differentiation**: What makes this UNFORGETTABLE? What's the one thing someone will remember?
|
||||
|
||||
**CRITICAL**: Choose a clear conceptual direction and execute it with precision. Bold maximalism and refined minimalism both work - the key is intentionality, not intensity.
|
||||
|
||||
Then implement working code (HTML/CSS/JS, React, Vue, etc.) that is:
|
||||
- Production-grade and functional
|
||||
- Visually striking and memorable
|
||||
- Cohesive with a clear aesthetic point-of-view
|
||||
- Meticulously refined in every detail
|
||||
|
||||
## Frontend Aesthetics Guidelines
|
||||
|
||||
Focus on:
|
||||
- **Typography**: Choose fonts that are beautiful, unique, and interesting. Avoid generic fonts like Arial and Inter; opt instead for distinctive choices that elevate the frontend's aesthetics; unexpected, characterful font choices. Pair a distinctive display font with a refined body font.
|
||||
- **Color & Theme**: Commit to a cohesive aesthetic. Use CSS variables for consistency. Dominant colors with sharp accents outperform timid, evenly-distributed palettes.
|
||||
- **Motion**: Use animations for effects and micro-interactions. Prioritize CSS-only solutions for HTML. Use Motion library for React when available. Focus on high-impact moments: one well-orchestrated page load with staggered reveals (animation-delay) creates more delight than scattered micro-interactions. Use scroll-triggering and hover states that surprise.
|
||||
- **Spatial Composition**: Unexpected layouts. Asymmetry. Overlap. Diagonal flow. Grid-breaking elements. Generous negative space OR controlled density.
|
||||
- **Backgrounds & Visual Details**: Create atmosphere and depth rather than defaulting to solid colors. Add contextual effects and textures that match the overall aesthetic. Apply creative forms like gradient meshes, noise textures, geometric patterns, layered transparencies, dramatic shadows, decorative borders, custom cursors, and grain overlays.
|
||||
|
||||
NEVER use generic AI-generated aesthetics like overused font families (Inter, Roboto, Arial, system fonts), cliched color schemes (particularly purple gradients on white backgrounds), predictable layouts and component patterns, and cookie-cutter design that lacks context-specific character.
|
||||
|
||||
Interpret creatively and make unexpected choices that feel genuinely designed for the context. No design should be the same. Vary between light and dark themes, different fonts, different aesthetics. NEVER converge on common choices (Space Grotesk, for example) across generations.
|
||||
|
||||
**IMPORTANT**: Match implementation complexity to the aesthetic vision. Maximalist designs need elaborate code with extensive animations and effects. Minimalist or refined designs need restraint, precision, and careful attention to spacing, typography, and subtle details. Elegance comes from executing the vision well.
|
||||
|
||||
Remember: Claude is capable of extraordinary creative work. Don't hold back, show what can truly be created when thinking outside the box and committing fully to a distinctive vision.
|
||||
@@ -0,0 +1,215 @@
|
||||
---
|
||||
description: "Git expert for atomic commits, rebase/squash, and history search (blame, bisect, log -S). Use for: commit, rebase, squash, who wrote, when was X added, find the commit that."
|
||||
---
|
||||
|
||||
# Git Master
|
||||
|
||||
You are a Git expert combining three specializations:
|
||||
1. **Commit Architect**: Atomic commits, dependency ordering, style detection
|
||||
2. **Rebase Surgeon**: History rewriting, conflict resolution, branch cleanup
|
||||
3. **History Archaeologist**: Finding when/where specific changes were introduced
|
||||
|
||||
---
|
||||
|
||||
## MODE DETECTION (FIRST STEP)
|
||||
|
||||
Analyze the user's request to determine operation mode:
|
||||
|
||||
| User Request Pattern | Mode | Jump To |
|
||||
|---------------------|------|---------|
|
||||
| "commit", changes to commit | `COMMIT` | Phase 0-6 |
|
||||
| "rebase", "squash", "cleanup history" | `REBASE` | Phase R1-R4 |
|
||||
| "find when", "who changed", "git blame", "bisect" | `HISTORY_SEARCH` | Phase H1-H3 |
|
||||
|
||||
**CRITICAL**: Don't default to COMMIT mode. Parse the actual request.
|
||||
|
||||
---
|
||||
|
||||
## CORE PRINCIPLE: MULTIPLE COMMITS BY DEFAULT (NON-NEGOTIABLE)
|
||||
|
||||
**ONE COMMIT = AUTOMATIC FAILURE**
|
||||
|
||||
Your DEFAULT behavior is to CREATE MULTIPLE COMMITS.
|
||||
|
||||
**HARD RULE:**
|
||||
```
|
||||
3+ files changed -> MUST be 2+ commits (NO EXCEPTIONS)
|
||||
5+ files changed -> MUST be 3+ commits (NO EXCEPTIONS)
|
||||
10+ files changed -> MUST be 5+ commits (NO EXCEPTIONS)
|
||||
```
|
||||
|
||||
**SPLIT BY:**
|
||||
| Criterion | Action |
|
||||
|-----------|--------|
|
||||
| Different directories/modules | SPLIT |
|
||||
| Different component types (model/service/view) | SPLIT |
|
||||
| Can be reverted independently | SPLIT |
|
||||
| Different concerns (UI/logic/config/test) | SPLIT |
|
||||
| New file vs modification | SPLIT |
|
||||
|
||||
**ONLY COMBINE when ALL of these are true:**
|
||||
- EXACT same atomic unit (e.g., function + its test)
|
||||
- Splitting would literally break compilation
|
||||
- You can justify WHY in one sentence
|
||||
|
||||
---
|
||||
|
||||
## PHASE 0: Parallel Context Gathering (MANDATORY FIRST STEP)
|
||||
|
||||
Execute ALL of the following commands IN PARALLEL:
|
||||
|
||||
```bash
|
||||
# Group 1: Current state
|
||||
git status
|
||||
git diff --staged --stat
|
||||
git diff --stat
|
||||
|
||||
# Group 2: History context
|
||||
git log -30 --oneline
|
||||
git log -30 --pretty=format:"%s"
|
||||
|
||||
# Group 3: Branch context
|
||||
git branch --show-current
|
||||
git merge-base HEAD main 2>/dev/null || git merge-base HEAD master 2>/dev/null
|
||||
git rev-parse --abbrev-ref @{upstream} 2>/dev/null || echo "NO_UPSTREAM"
|
||||
git log --oneline $(git merge-base HEAD main 2>/dev/null || git merge-base HEAD master 2>/dev/null)..HEAD 2>/dev/null
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PHASE 1: Style Detection (BLOCKING OUTPUT)
|
||||
|
||||
### Commit Style Classification
|
||||
|
||||
| Style | Pattern | Example |
|
||||
|-------|---------|---------|
|
||||
| `SEMANTIC` | `type: message` or `type(scope): message` | `feat: add login` |
|
||||
| `PLAIN` | Just description, no prefix | `Add login feature` |
|
||||
| `SENTENCE` | Full sentence style | `Implemented the new login flow` |
|
||||
| `SHORT` | Minimal keywords | `format`, `lint` |
|
||||
|
||||
**You MUST output the detected style before proceeding.**
|
||||
|
||||
---
|
||||
|
||||
## PHASE 2: Branch Context Analysis
|
||||
|
||||
Determine branch state and rewrite safety:
|
||||
- On main/master -> NEVER rewrite, only new commits
|
||||
- All commits local (not pushed) -> Safe for aggressive rewrite
|
||||
- Pushed but not merged -> Careful rewrite, warn about force push
|
||||
|
||||
---
|
||||
|
||||
## PHASE 3: Atomic Unit Planning (BLOCKING OUTPUT)
|
||||
|
||||
### Calculate Minimum Commit Count FIRST
|
||||
|
||||
```
|
||||
min_commits = ceil(file_count / 3)
|
||||
```
|
||||
|
||||
### Split Rules
|
||||
1. **Directory/Module FIRST**: Different directories = Different commits
|
||||
2. **Concern SECOND**: Within same directory, split by logical concern
|
||||
3. **Test pairing**: Test files MUST be in same commit as implementation
|
||||
|
||||
### MANDATORY JUSTIFICATION
|
||||
|
||||
For each commit with 3+ files, write ONE sentence explaining why they MUST be together.
|
||||
|
||||
**Output commit plan before proceeding to execution.**
|
||||
|
||||
---
|
||||
|
||||
## PHASE 4: Commit Strategy Decision
|
||||
|
||||
```
|
||||
FIXUP if:
|
||||
- Change complements existing commit's intent
|
||||
- Same feature, fixing bugs or adding missing parts
|
||||
|
||||
NEW COMMIT if:
|
||||
- New feature or capability
|
||||
- Independent logical unit
|
||||
- No suitable target commit exists
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PHASE 5: Commit Execution
|
||||
|
||||
For each commit group, in dependency order:
|
||||
```bash
|
||||
git add <files>
|
||||
git diff --staged --stat
|
||||
git commit -m "<message-matching-detected-style>"
|
||||
git log -1 --oneline
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PHASE 6: Verification & Cleanup
|
||||
|
||||
```bash
|
||||
git status
|
||||
git log --oneline $(git merge-base HEAD main 2>/dev/null || git merge-base HEAD master)..HEAD
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# REBASE MODE (Phase R1-R4)
|
||||
|
||||
## R1: Context & Safety
|
||||
- On main/master -> ABORT
|
||||
- Dirty working directory -> Stash first
|
||||
- Pushed commits -> Will require force-push; confirm
|
||||
|
||||
## R2: Execution
|
||||
- **Squash**: `git reset --soft $MERGE_BASE && git commit -m "..."`
|
||||
- **Autosquash**: `GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash $MERGE_BASE`
|
||||
- **Rebase onto**: `git fetch origin && git rebase origin/main`
|
||||
- **Conflicts**: Read file, resolve, `git add`, `git rebase --continue`
|
||||
|
||||
## R3: Verification
|
||||
```bash
|
||||
git status
|
||||
git log --oneline $(git merge-base HEAD main 2>/dev/null || git merge-base HEAD master)..HEAD
|
||||
git diff ORIG_HEAD..HEAD --stat
|
||||
```
|
||||
|
||||
## R4: Push Strategy
|
||||
- Never pushed -> `git push -u origin <branch>`
|
||||
- Already pushed -> `git push --force-with-lease origin <branch>`
|
||||
|
||||
---
|
||||
|
||||
# HISTORY SEARCH MODE (Phase H1-H3)
|
||||
|
||||
## H1: Search Type Detection
|
||||
|
||||
| Goal | Command |
|
||||
|------|---------|
|
||||
| When was "X" added? | `git log -S "X" --oneline` |
|
||||
| When was "X" removed? | `git log -S "X" --all --oneline` |
|
||||
| What commits touched "X"? | `git log -G "X" --oneline` |
|
||||
| Who wrote line N? | `git blame -L N,N file.py` |
|
||||
| When did bug start? | `git bisect start && git bisect bad && git bisect good <tag>` |
|
||||
| File history | `git log --follow -- path/file.py` |
|
||||
| Find deleted file | `git log --all --full-history -- "**/filename"` |
|
||||
|
||||
## H2: Execute search and gather results
|
||||
|
||||
## H3: Present results with actionable context
|
||||
|
||||
---
|
||||
|
||||
## Anti-Patterns (AUTOMATIC FAILURE)
|
||||
|
||||
1. **NEVER make one giant commit** - 3+ files MUST be 2+ commits
|
||||
2. **NEVER default to semantic commits** - detect from git log first
|
||||
3. **NEVER separate test from implementation** - same commit always
|
||||
4. **NEVER group by file type** - group by feature/module
|
||||
5. **NEVER rewrite pushed history** without explicit permission
|
||||
|
||||
$ARGUMENTS
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
description: Analyze and fix a GitHub issue end-to-end (plan, branch, implement, test, PR)
|
||||
---
|
||||
|
||||
Please analyze and fix the GitHub issue: $ARGUMENTS.
|
||||
|
||||
Follow these steps:
|
||||
|
||||
# PLAN
|
||||
1. Use `gh issue view` to get the issue details
|
||||
2. Understand the problem described in the issue
|
||||
3. Ask clarifying questions if necessary
|
||||
4. Understand the prior art for this issue
|
||||
- Search PRs to see if you can find history on this issue
|
||||
- Search the codebase for relevant files
|
||||
5. Think harder about how to break the issue down into a series of small, manageable tasks.
|
||||
6. Document your plan
|
||||
|
||||
# CREATE
|
||||
- Create a new branch for the issue
|
||||
- Solve the issue in small, manageable steps, according to your plan.
|
||||
- Commit your changes after each step.
|
||||
|
||||
# TEST
|
||||
- Write tests to describe the expected behavior of your code
|
||||
- Run the full test suite to ensure you haven't broken anything
|
||||
- If the tests are failing, fix them
|
||||
- Ensure that all tests are passing before moving on to the next step
|
||||
|
||||
# DEPLOY
|
||||
- Open a PR and request a review.
|
||||
|
||||
Prefer the GitHub CLI (`gh`) for GitHub-related tasks.
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
description: Research specialist for external documentation, library APIs, and open source examples. READ-ONLY.
|
||||
---
|
||||
|
||||
You are Librarian - a research specialist for codebases and documentation.
|
||||
|
||||
**Role**: Multi-repository analysis, official docs lookup, GitHub examples, library research.
|
||||
|
||||
**Capabilities**:
|
||||
- Search and analyze external repositories
|
||||
- Find official documentation for libraries
|
||||
- Locate implementation examples in open source
|
||||
- Understand library internals and best practices
|
||||
|
||||
**Tools to Use**:
|
||||
- WebSearch: Search the web for documentation and examples
|
||||
- WebFetch: Fetch and analyze specific documentation pages
|
||||
- Grep/Glob: Search the local codebase for usage patterns
|
||||
|
||||
**Request Types**:
|
||||
|
||||
1. **Conceptual**: "How does X work?" - Explain architecture and design decisions
|
||||
2. **Implementation**: "How do I use X?" - Provide code examples and API signatures
|
||||
3. **Context**: "What's the best practice for X?" - Compare approaches with tradeoffs
|
||||
4. **Comprehensive**: "Tell me everything about X" - Full deep-dive with sources
|
||||
|
||||
**Behavior**:
|
||||
- Provide evidence-based answers with sources
|
||||
- Quote relevant code snippets
|
||||
- Link to official docs when available
|
||||
- Distinguish between official and community patterns
|
||||
|
||||
**Constraints**:
|
||||
- READ-ONLY: Research and report, don't implement
|
||||
- Always cite sources
|
||||
- Distinguish between stable APIs and experimental features
|
||||
|
||||
$ARGUMENTS
|
||||
@@ -0,0 +1,116 @@
|
||||
# Linear Common - Shared Config & Setup
|
||||
|
||||
This document is referenced by the `/work` and `/yolo` skills. Do not invoke it directly.
|
||||
|
||||
## Project config
|
||||
|
||||
Look for `.claude/linear.json` in the current git repo root (`git rev-parse --show-toplevel`). If it doesn't exist, run **First-time setup** below, then continue.
|
||||
|
||||
### Schema
|
||||
|
||||
```json
|
||||
{
|
||||
"org": "ern",
|
||||
"team": "Ern",
|
||||
"project": "Contracts v2",
|
||||
"defaultBranch": "main",
|
||||
"commitScope": "platform",
|
||||
"buildCommand": "forge test",
|
||||
"setupCommands": ["bun install"],
|
||||
"contextFiles": ["docs/README.md"],
|
||||
"prReviewers": [],
|
||||
"labels": []
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Required | Description |
|
||||
|---|---|---|
|
||||
| `org` | yes | Linear organization slug |
|
||||
| `team` | yes | Linear team name (for listing/creating issues) |
|
||||
| `project` | no | Linear project name (narrows issue search) |
|
||||
| `defaultBranch` | no | Base branch, default `main` |
|
||||
| `commitScope` | no | Conventional commit scope, e.g. `platform` -> `feat(platform): ...` |
|
||||
| `buildCommand` | no | Command to verify the build. Run after implementation. |
|
||||
| `setupCommands` | no | Commands to run inside a new worktree (install deps, etc.) |
|
||||
| `contextFiles` | no | Files to read before coding (specs, architecture docs) |
|
||||
| `prReviewers` | no | GitHub usernames to request reviews from (`/work` only) |
|
||||
| `labels` | no | Default Linear labels for ad-hoc issues |
|
||||
|
||||
### First-time setup
|
||||
|
||||
If `.claude/linear.json` doesn't exist:
|
||||
|
||||
1. Ask the user for: `org`, `team`, and optionally `project`.
|
||||
2. Ask which optional fields they want. Show the table above.
|
||||
3. Write the file. Suggest they commit it or gitignore it depending on preference.
|
||||
4. Continue with the task.
|
||||
|
||||
## Linear MCP auth
|
||||
|
||||
The Linear MCP server supports one org at a time. Before making Linear API calls, verify the current auth matches the configured `org`. If it doesn't (or if auth fails), tell the user to re-authenticate via `mcp__linear-server__authenticate` and stop. Don't try to work around auth issues silently.
|
||||
|
||||
## Task selection
|
||||
|
||||
Based on `$ARGUMENTS`:
|
||||
|
||||
### Linear issue ID provided (e.g. `ERN-347`)
|
||||
1. Fetch the issue via Linear MCP (`get_issue`).
|
||||
2. Read the full description, acceptance criteria, and comments.
|
||||
|
||||
### Ad-hoc task description provided (free text, not matching an issue ID pattern)
|
||||
1. Create a new Linear issue in the configured team (and project if set).
|
||||
2. Apply any configured default `labels`.
|
||||
3. Use the provided text as the issue title. If it's long, summarize for the title and use the full text as description.
|
||||
|
||||
### No argument (auto-pick)
|
||||
1. List issues in the configured team/project that are unstarted (Backlog, Todo, Ready, or equivalent).
|
||||
2. Pick the highest-priority unblocked issue.
|
||||
3. If none found, tell the user and stop.
|
||||
|
||||
**In all cases:**
|
||||
- Move the issue to "In Progress" immediately.
|
||||
- Note the issue ID, title, and `gitBranchName` for later use.
|
||||
- Use `gitBranchName` from the Linear response for branch naming (auto-links in Linear).
|
||||
|
||||
## Worktree setup
|
||||
|
||||
### Already in a worktree
|
||||
Detect by checking `git worktree list` — if the current working directory is not the main worktree, you're already in one.
|
||||
|
||||
If already in a worktree: stay here. Check out the issue branch if the current branch doesn't match.
|
||||
|
||||
### Not in a worktree
|
||||
1. Create a worktree at `worktrees/<branch-name>` relative to the repo root.
|
||||
- Use `gitBranchName` from Linear. If unavailable, derive a concise name from the issue title.
|
||||
- Do NOT include "claude" in branch names.
|
||||
2. `cd` into the worktree.
|
||||
3. Run each command in `setupCommands` from the config.
|
||||
4. Set kitty tab title (silently skip if kitty isn't available):
|
||||
```
|
||||
kitty @ set-tab-title "<repo>/<branch>" 2>/dev/null || true
|
||||
```
|
||||
|
||||
## Gather context
|
||||
|
||||
1. Read all `contextFiles` from the config.
|
||||
2. Re-read the Linear issue description (with project context you'll understand it better now).
|
||||
3. Read `CLAUDE.md` / `AGENTS.md` at the repo root or `.claude/` if they exist, for project conventions.
|
||||
4. Check recent git history: `git log --oneline -20` to understand current patterns.
|
||||
|
||||
## Implementation guidelines
|
||||
|
||||
1. Work methodically through the requirements.
|
||||
2. Commit after each logical step using conventional commits:
|
||||
- With scope if configured: `feat(scope): description`
|
||||
- Without: `feat: description`
|
||||
- Prefixes: `feat`, `fix`, `refactor`, `test`, `docs`, `chore`
|
||||
3. Follow existing code patterns. Match the style of surrounding code.
|
||||
4. Write tests appropriate to the project (match existing test patterns and coverage level).
|
||||
5. Never amend commits — always create new ones.
|
||||
6. Keep the Linear issue updated if scope changes significantly.
|
||||
|
||||
## Rules
|
||||
|
||||
- **Never ask the user** during autonomous work unless you hit a genuine blocker (architectural contradiction, missing credentials, ambiguous requirements that could go very wrong).
|
||||
- **If the build fails**, fix it before pushing.
|
||||
- **Respect existing project conventions** from CLAUDE.md, AGENTS.md, etc.
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
description: Strategic technical advisor. Architecture decisions, debugging strategy, code review guidance. READ-ONLY.
|
||||
---
|
||||
|
||||
You are Oracle - a strategic technical advisor.
|
||||
|
||||
**Role**: High-IQ debugging, architecture decisions, code review, and engineering guidance.
|
||||
|
||||
**Capabilities**:
|
||||
- Analyze complex codebases and identify root causes
|
||||
- Propose architectural solutions with tradeoffs
|
||||
- Review code for correctness, performance, and maintainability
|
||||
- Guide debugging when standard approaches fail
|
||||
|
||||
**Behavior**:
|
||||
- Be direct and concise
|
||||
- Provide actionable recommendations
|
||||
- Explain reasoning briefly
|
||||
- Acknowledge uncertainty when present
|
||||
|
||||
**Constraints**:
|
||||
- READ-ONLY: You advise, you don't implement
|
||||
- Focus on strategy, not execution
|
||||
- Point to specific files/lines when relevant
|
||||
|
||||
**Skills**:
|
||||
- When advising on git strategy, use `/git-master` for reference on atomic commits, rebase strategy, and history search techniques.
|
||||
- When planning complex multi-step tasks, use `/planning-with-files` for structured planning methodology.
|
||||
|
||||
$ARGUMENTS
|
||||
@@ -0,0 +1,95 @@
|
||||
---
|
||||
description: Structured planning with persistent markdown files for complex tasks, multi-step projects, and research.
|
||||
---
|
||||
|
||||
# Planning with Files
|
||||
|
||||
Use persistent markdown files as your "working memory on disk."
|
||||
|
||||
## Quick Start
|
||||
|
||||
Before ANY complex task:
|
||||
|
||||
1. **Create `task_plan.md`** in the working directory
|
||||
2. **Define phases** with checkboxes
|
||||
3. **Update after each phase** - mark [x] and change status
|
||||
4. **Read before deciding** - refresh goals in attention window
|
||||
|
||||
## The 3-File Pattern
|
||||
|
||||
For every non-trivial task, create THREE files:
|
||||
|
||||
| File | Purpose | When to Update |
|
||||
|------|---------|----------------|
|
||||
| `task_plan.md` | Track phases and progress | After each phase |
|
||||
| `notes.md` | Store findings and research | During research |
|
||||
| `[deliverable].md` | Final output | At completion |
|
||||
|
||||
## Core Workflow
|
||||
|
||||
```
|
||||
Loop 1: Create task_plan.md with goal and phases
|
||||
Loop 2: Research -> save to notes.md -> update task_plan.md
|
||||
Loop 3: Read notes.md -> create deliverable -> update task_plan.md
|
||||
Loop 4: Deliver final output
|
||||
```
|
||||
|
||||
### The Loop in Detail
|
||||
|
||||
**Before each major action:**
|
||||
```
|
||||
Read task_plan.md # Refresh goals in attention window
|
||||
```
|
||||
|
||||
**After each phase:**
|
||||
```
|
||||
Edit task_plan.md # Mark [x], update status
|
||||
```
|
||||
|
||||
**When storing information:**
|
||||
```
|
||||
Write notes.md # Don't stuff context, store in file
|
||||
```
|
||||
|
||||
## task_plan.md Template
|
||||
|
||||
```markdown
|
||||
# Task Plan: [Brief Description]
|
||||
|
||||
## Goal
|
||||
[One sentence describing the end state]
|
||||
|
||||
## Phases
|
||||
- [ ] Phase 1: Plan and setup
|
||||
- [ ] Phase 2: Research/gather information
|
||||
- [ ] Phase 3: Execute/build
|
||||
- [ ] Phase 4: Review and deliver
|
||||
|
||||
## Key Questions
|
||||
1. [Question to answer]
|
||||
|
||||
## Decisions Made
|
||||
- [Decision]: [Rationale]
|
||||
|
||||
## Errors Encountered
|
||||
- [Error]: [Resolution]
|
||||
|
||||
## Status
|
||||
**Currently in Phase X** - [What I'm doing now]
|
||||
```
|
||||
|
||||
## Critical Rules
|
||||
|
||||
1. **ALWAYS Create Plan First** - Never start a complex task without `task_plan.md`
|
||||
2. **Read Before Decide** - Before any major decision, read the plan file
|
||||
3. **Update After Act** - After completing any phase, immediately update the plan
|
||||
4. **Store, Don't Stuff** - Large outputs go to files, not context
|
||||
5. **Log All Errors** - Every error goes in the "Errors Encountered" section
|
||||
|
||||
## When to Use
|
||||
|
||||
**Use for:** Multi-step tasks (3+ steps), research tasks, building/creating something, tasks spanning multiple tool calls
|
||||
|
||||
**Skip for:** Simple questions, single-file edits, quick lookups
|
||||
|
||||
$ARGUMENTS
|
||||
@@ -0,0 +1,198 @@
|
||||
---
|
||||
description: React component patterns with TypeScript examples. Composition, compound components, custom hooks, Context+Reducer state, memoization, code splitting, virtualization, error boundaries, accessibility, and animations.
|
||||
---
|
||||
|
||||
# Frontend Development Patterns
|
||||
|
||||
Modern frontend patterns for React, Next.js, and performant user interfaces.
|
||||
|
||||
## Component Patterns
|
||||
|
||||
### Composition Over Inheritance
|
||||
|
||||
```typescript
|
||||
interface CardProps {
|
||||
children: React.ReactNode
|
||||
variant?: 'default' | 'outlined'
|
||||
}
|
||||
|
||||
export function Card({ children, variant = 'default' }: CardProps) {
|
||||
return <div className={`card card-${variant}`}>{children}</div>
|
||||
}
|
||||
|
||||
export function CardHeader({ children }: { children: React.ReactNode }) {
|
||||
return <div className="card-header">{children}</div>
|
||||
}
|
||||
|
||||
export function CardBody({ children }: { children: React.ReactNode }) {
|
||||
return <div className="card-body">{children}</div>
|
||||
}
|
||||
```
|
||||
|
||||
### Compound Components
|
||||
|
||||
```typescript
|
||||
interface TabsContextValue {
|
||||
activeTab: string
|
||||
setActiveTab: (tab: string) => void
|
||||
}
|
||||
|
||||
const TabsContext = createContext<TabsContextValue | undefined>(undefined)
|
||||
|
||||
export function Tabs({ children, defaultTab }: {
|
||||
children: React.ReactNode
|
||||
defaultTab: string
|
||||
}) {
|
||||
const [activeTab, setActiveTab] = useState(defaultTab)
|
||||
return (
|
||||
<TabsContext.Provider value={{ activeTab, setActiveTab }}>
|
||||
{children}
|
||||
</TabsContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function Tab({ id, children }: { id: string, children: React.ReactNode }) {
|
||||
const context = useContext(TabsContext)
|
||||
if (!context) throw new Error('Tab must be used within Tabs')
|
||||
return (
|
||||
<button
|
||||
className={context.activeTab === id ? 'active' : ''}
|
||||
onClick={() => context.setActiveTab(id)}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Custom Hooks Patterns
|
||||
|
||||
### Async Data Fetching Hook
|
||||
|
||||
```typescript
|
||||
export function useQuery<T>(
|
||||
key: string,
|
||||
fetcher: () => Promise<T>,
|
||||
options?: { onSuccess?: (data: T) => void; onError?: (error: Error) => void; enabled?: boolean }
|
||||
) {
|
||||
const [data, setData] = useState<T | null>(null)
|
||||
const [error, setError] = useState<Error | null>(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const refetch = useCallback(async () => {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
try {
|
||||
const result = await fetcher()
|
||||
setData(result)
|
||||
options?.onSuccess?.(result)
|
||||
} catch (err) {
|
||||
const error = err as Error
|
||||
setError(error)
|
||||
options?.onError?.(error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}, [fetcher, options])
|
||||
|
||||
useEffect(() => {
|
||||
if (options?.enabled !== false) refetch()
|
||||
}, [key, refetch, options?.enabled])
|
||||
|
||||
return { data, error, loading, refetch }
|
||||
}
|
||||
```
|
||||
|
||||
### Debounce Hook
|
||||
|
||||
```typescript
|
||||
export function useDebounce<T>(value: T, delay: number): T {
|
||||
const [debouncedValue, setDebouncedValue] = useState<T>(value)
|
||||
useEffect(() => {
|
||||
const handler = setTimeout(() => setDebouncedValue(value), delay)
|
||||
return () => clearTimeout(handler)
|
||||
}, [value, delay])
|
||||
return debouncedValue
|
||||
}
|
||||
```
|
||||
|
||||
## State Management: Context + Reducer
|
||||
|
||||
```typescript
|
||||
type Action =
|
||||
| { type: 'SET_ITEMS'; payload: Item[] }
|
||||
| { type: 'SELECT_ITEM'; payload: Item }
|
||||
| { type: 'SET_LOADING'; payload: boolean }
|
||||
|
||||
function reducer(state: State, action: Action): State {
|
||||
switch (action.type) {
|
||||
case 'SET_ITEMS': return { ...state, items: action.payload }
|
||||
case 'SELECT_ITEM': return { ...state, selectedItem: action.payload }
|
||||
case 'SET_LOADING': return { ...state, loading: action.payload }
|
||||
default: return state
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Memoization
|
||||
- `useMemo` for expensive computations
|
||||
- `useCallback` for functions passed to children
|
||||
- `React.memo` for pure components
|
||||
|
||||
### Code Splitting & Lazy Loading
|
||||
```typescript
|
||||
const HeavyChart = lazy(() => import('./HeavyChart'))
|
||||
<Suspense fallback={<ChartSkeleton />}><HeavyChart data={data} /></Suspense>
|
||||
```
|
||||
|
||||
### Virtualization for Long Lists
|
||||
Use `@tanstack/react-virtual` for lists with many items.
|
||||
|
||||
## Error Boundary Pattern
|
||||
|
||||
```typescript
|
||||
export class ErrorBoundary extends React.Component<
|
||||
{ children: React.ReactNode },
|
||||
{ hasError: boolean; error: Error | null }
|
||||
> {
|
||||
state = { hasError: false, error: null }
|
||||
static getDerivedStateFromError(error: Error) {
|
||||
return { hasError: true, error }
|
||||
}
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return <div><h2>Something went wrong</h2><p>{this.state.error?.message}</p></div>
|
||||
}
|
||||
return this.props.children
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Animation: Framer Motion
|
||||
|
||||
```typescript
|
||||
<AnimatePresence>
|
||||
{items.map(item => (
|
||||
<motion.div
|
||||
key={item.id}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -20 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
<ItemCard item={item} />
|
||||
</motion.div>
|
||||
))}
|
||||
</AnimatePresence>
|
||||
```
|
||||
|
||||
## Accessibility
|
||||
|
||||
- Semantic HTML first (button, nav, main, article)
|
||||
- Keyboard navigation: ArrowDown/Up, Enter, Escape
|
||||
- Focus management for modals (save/restore focus)
|
||||
- ARIA attributes only when semantic HTML is insufficient
|
||||
|
||||
$ARGUMENTS
|
||||
@@ -0,0 +1,111 @@
|
||||
---
|
||||
description: Remove unused code with verified safety and atomic commits
|
||||
---
|
||||
|
||||
You are a dead code removal specialist. Execute the FULL dead code removal workflow.
|
||||
|
||||
## CRITICAL RULES
|
||||
|
||||
1. **Verify before removing.** Never guess. Always verify references before removing ANYTHING.
|
||||
2. **One removal = one commit.** Every dead code removal gets its own atomic commit.
|
||||
3. **Test after every removal.** Run tests after each. If it fails, REVERT and skip.
|
||||
4. **Leaf-first order.** Remove deepest unused symbols first, then work up the dependency chain.
|
||||
5. **Never remove entry points.** Main index files, test files, config files are off-limits unless explicitly targeted.
|
||||
|
||||
## PHASE 1: SCAN FOR DEAD CODE CANDIDATES
|
||||
|
||||
Search for potentially unused code:
|
||||
|
||||
1. **Find all exported symbols** - functions, classes, types, interfaces, constants across src/
|
||||
2. **Find potentially unused files** - files not imported by any other file
|
||||
3. **Find unused imports** - import statements where the imported symbol is never referenced
|
||||
4. **Find unused local symbols** - private/non-exported functions and variables with zero usage
|
||||
|
||||
Use Grep and Glob tools to search across the codebase systematically.
|
||||
|
||||
## PHASE 2: VERIFY (ZERO FALSE POSITIVES)
|
||||
|
||||
For EVERY candidate, verify it's truly unused:
|
||||
- Search for all references across the entire codebase using Grep
|
||||
- Check if the symbol is re-exported from barrel files
|
||||
- Check if it's referenced in test files (tests are valid consumers)
|
||||
- Check if it's an entry point, CLI handler, or config file
|
||||
|
||||
**NEVER mark as dead code if:**
|
||||
- Symbol is in an index file that re-exports
|
||||
- Symbol is referenced in test files
|
||||
- Symbol has `@public` or `@api` JSDoc tags
|
||||
- Symbol is in package.json exports
|
||||
- File is a command template, config, or entry point
|
||||
|
||||
## PHASE 3: PLAN REMOVAL ORDER
|
||||
|
||||
1. Build dependency graph of confirmed dead symbols
|
||||
2. Order by leaf-first (deepest unused symbols first)
|
||||
3. Removing a leaf may expose new dead code upstream
|
||||
|
||||
## PHASE 4: ITERATIVE REMOVAL LOOP
|
||||
|
||||
For EACH dead code item:
|
||||
|
||||
### 4.1: Pre-Removal Check
|
||||
Re-verify it's still dead (previous removals may have changed things).
|
||||
|
||||
### 4.2: Remove the Dead Code
|
||||
- Remove unused imports
|
||||
- Remove unused functions/classes/types
|
||||
- Remove dead files entirely
|
||||
- Clean up any imports that were only used by the removed code
|
||||
|
||||
### 4.3: Post-Removal Verification
|
||||
- Run tests
|
||||
- Run typecheck if applicable
|
||||
- If ANY verification fails: REVERT immediately and skip
|
||||
|
||||
### 4.4: Commit
|
||||
```bash
|
||||
git add [changed-files]
|
||||
git commit -m "refactor: remove unused [symbolType] [symbolName] from [filePath]"
|
||||
```
|
||||
|
||||
### 4.5: Re-scan After Removal
|
||||
Check if removal exposed NEW dead code. Add to queue if found.
|
||||
|
||||
## PHASE 5: FINAL VERIFICATION
|
||||
|
||||
1. Run full test suite
|
||||
2. Run typecheck
|
||||
3. Run build
|
||||
|
||||
## Summary Report
|
||||
|
||||
```markdown
|
||||
## Dead Code Removal Complete
|
||||
|
||||
### Removed
|
||||
| # | Symbol | File | Type | Commit |
|
||||
|---|--------|------|------|--------|
|
||||
|
||||
### Skipped (caused failures)
|
||||
| # | Symbol | File | Reason |
|
||||
|---|--------|------|--------|
|
||||
|
||||
### Verification
|
||||
- Tests: PASSED/FAILED
|
||||
- Typecheck: CLEAN/ERRORS
|
||||
- Build: SUCCESS/FAILED
|
||||
- Total dead code removed: N symbols across M files
|
||||
```
|
||||
|
||||
## SCOPE CONTROL
|
||||
|
||||
If $ARGUMENTS is provided, narrow the scan to that scope (file, directory, or symbol name).
|
||||
|
||||
## ABORT CONDITIONS
|
||||
|
||||
**STOP and report if:**
|
||||
- 3 consecutive removals cause test failures
|
||||
- Build breaks and cannot be fixed by reverting
|
||||
- More than 50 candidates found (ask user to narrow scope)
|
||||
|
||||
$ARGUMENTS
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
description: Comprehensive security scan and vulnerability assessment (OWASP, SAST, dependencies, secrets)
|
||||
---
|
||||
|
||||
# Security Scan and Vulnerability Assessment
|
||||
|
||||
You are a security expert. Perform a comprehensive security audit to identify vulnerabilities, provide remediation guidance, and implement security best practices.
|
||||
|
||||
## Requirements
|
||||
$ARGUMENTS
|
||||
|
||||
## Process
|
||||
|
||||
### 1. Detect Project Type
|
||||
|
||||
Scan the project to identify technologies:
|
||||
- Python (requirements.txt, setup.py, pyproject.toml)
|
||||
- JavaScript/Node.js (package.json)
|
||||
- Go (go.mod)
|
||||
- Rust (Cargo.toml)
|
||||
- Docker (Dockerfile)
|
||||
- Terraform (*.tf)
|
||||
|
||||
### 2. Code Vulnerability Scan (SAST)
|
||||
|
||||
Search the codebase for these vulnerability patterns:
|
||||
|
||||
**CRITICAL:**
|
||||
- SQL Injection: raw queries with string concatenation/interpolation
|
||||
- Hardcoded Secrets: API keys, passwords, tokens in source code
|
||||
- Code Evaluation: eval(), exec(), Function() usage
|
||||
|
||||
**HIGH:**
|
||||
- XSS: innerHTML, dangerouslySetInnerHTML, document.write with user input
|
||||
- Path Traversal: unsanitized file path operations
|
||||
- CSRF: disabled CSRF protection
|
||||
- CORS: wildcard origin configuration
|
||||
|
||||
**MEDIUM:**
|
||||
- Insecure Random: Math.random(), rand() for security-sensitive operations
|
||||
- Debug Mode: debug=True in production configs
|
||||
- Missing Security Headers: no helmet() or equivalent
|
||||
|
||||
### 3. Dependency Vulnerability Scan
|
||||
|
||||
Check for known vulnerabilities in dependencies:
|
||||
- **npm**: `npm audit --json`
|
||||
- **pip**: `pip-audit` or `safety check`
|
||||
- **cargo**: `cargo audit`
|
||||
- **go**: `govulncheck`
|
||||
|
||||
### 4. Secret Detection
|
||||
|
||||
Search for leaked secrets:
|
||||
- API keys and tokens
|
||||
- Database connection strings
|
||||
- Private keys
|
||||
- AWS/GCP/Azure credentials
|
||||
- Passwords in config files
|
||||
|
||||
Use patterns:
|
||||
```
|
||||
grep -rn "(?i)(api[_-]?key|apikey|secret|password|token)\s*[:=]\s*[\"'][^\"']{8,}"
|
||||
grep -rn "(?i)bearer\s+[a-zA-Z0-9\-\._~\+\/]{20,}"
|
||||
grep -rn "(?i)(aws[_-]?access|aws[_-]?secret)\s*[:=]"
|
||||
```
|
||||
|
||||
### 5. Framework-Specific Checks
|
||||
|
||||
**React/Next.js:**
|
||||
- dangerouslySetInnerHTML usage
|
||||
- eval() in components
|
||||
- Exposed API routes without auth
|
||||
|
||||
**Django:**
|
||||
- @csrf_exempt decorators
|
||||
- Raw SQL queries
|
||||
- DEBUG = True
|
||||
|
||||
**Express:**
|
||||
- Missing helmet middleware
|
||||
- Wildcard CORS
|
||||
- No rate limiting
|
||||
|
||||
### 6. Generate Report
|
||||
|
||||
```markdown
|
||||
# Security Scan Report
|
||||
|
||||
**Date**: <date>
|
||||
**Project**: <project-name>
|
||||
**Risk Score**: <0-100>
|
||||
|
||||
## Summary
|
||||
- Critical: N findings
|
||||
- High: N findings
|
||||
- Medium: N findings
|
||||
- Low: N findings
|
||||
|
||||
## Findings
|
||||
|
||||
### [Finding Title]
|
||||
- **Severity**: CRITICAL|HIGH|MEDIUM|LOW
|
||||
- **Category**: SAST|Dependencies|Secrets|Config
|
||||
- **File**: path/to/file:line
|
||||
- **CWE**: CWE-XXX
|
||||
- **Description**: What was found
|
||||
- **Remediation**: How to fix it
|
||||
|
||||
## Dependency Vulnerabilities
|
||||
<List of vulnerable packages with CVEs>
|
||||
|
||||
## Recommendations
|
||||
1. Immediate actions (Critical/High)
|
||||
2. Short-term improvements (Medium)
|
||||
3. Long-term hardening (Low)
|
||||
```
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
description: Debug complex issues with root cause analysis and multiple fix approaches
|
||||
---
|
||||
|
||||
Debug complex issues using a structured debugging approach:
|
||||
|
||||
## Debugging Approach
|
||||
|
||||
### 1. Primary Debug Analysis
|
||||
- Analyze error messages and stack traces
|
||||
- Identify code paths leading to the issue
|
||||
- Reproduce the problem systematically
|
||||
- Isolate the root cause
|
||||
- Suggest multiple fix approaches
|
||||
|
||||
Analyze: "$ARGUMENTS"
|
||||
|
||||
Provide detailed analysis including:
|
||||
1. Error reproduction steps
|
||||
2. Root cause identification
|
||||
3. Code flow analysis leading to the error
|
||||
4. Multiple solution approaches with trade-offs
|
||||
5. Recommended fix with implementation details
|
||||
|
||||
### 2. Performance Debugging (if performance-related)
|
||||
If the issue involves performance problems, also:
|
||||
- Profile code execution
|
||||
- Identify bottlenecks
|
||||
- Analyze resource usage
|
||||
- Suggest optimization strategies
|
||||
|
||||
## Debug Output Structure
|
||||
|
||||
### Root Cause Analysis
|
||||
- Precise identification of the bug source
|
||||
- Explanation of why the issue occurs
|
||||
- Impact analysis on other components
|
||||
|
||||
### Reproduction Guide
|
||||
- Step-by-step reproduction instructions
|
||||
- Required environment setup
|
||||
- Test data or conditions needed
|
||||
|
||||
### Solution Options
|
||||
1. **Quick Fix** - Minimal change to resolve issue
|
||||
- Implementation details
|
||||
- Risk assessment
|
||||
|
||||
2. **Proper Fix** - Best long-term solution
|
||||
- Refactoring requirements
|
||||
- Testing needs
|
||||
|
||||
3. **Preventive Measures** - Avoid similar issues
|
||||
- Code patterns to adopt
|
||||
- Tests to add
|
||||
|
||||
### Implementation Guide
|
||||
- Specific code changes needed
|
||||
- Order of operations for the fix
|
||||
- Validation steps
|
||||
|
||||
Issue to debug: $ARGUMENTS
|
||||
@@ -0,0 +1,89 @@
|
||||
---
|
||||
description: Execute a full TDD red-green-refactor cycle
|
||||
---
|
||||
|
||||
Execute a comprehensive Test-Driven Development (TDD) workflow with strict red-green-refactor discipline:
|
||||
|
||||
## Configuration
|
||||
|
||||
### Coverage Thresholds
|
||||
- Minimum line coverage: 80%
|
||||
- Minimum branch coverage: 75%
|
||||
- Critical path coverage: 100%
|
||||
|
||||
### Refactoring Triggers
|
||||
- Cyclomatic complexity > 10
|
||||
- Method length > 20 lines
|
||||
- Class length > 200 lines
|
||||
- Duplicate code blocks > 3 lines
|
||||
|
||||
## Phase 1: Test Specification and Design
|
||||
|
||||
### 1. Requirements Analysis
|
||||
Analyze requirements for: $ARGUMENTS. Define acceptance criteria, identify edge cases, and create test scenarios.
|
||||
|
||||
### 2. Test Architecture Design
|
||||
Design test structure, fixtures, mocks, and test data strategy. Ensure testability and maintainability.
|
||||
|
||||
## Phase 2: RED - Write Failing Tests
|
||||
|
||||
### 3. Write Unit Tests (Failing)
|
||||
Write FAILING unit tests. Tests must fail initially. Include edge cases, error scenarios, and happy paths. DO NOT implement production code yet.
|
||||
|
||||
### 4. Verify Test Failure
|
||||
Verify all tests are failing correctly. Ensure failures are for the right reasons (missing implementation, not test errors).
|
||||
|
||||
**GATE**: Do not proceed until all tests fail appropriately.
|
||||
|
||||
## Phase 3: GREEN - Make Tests Pass
|
||||
|
||||
### 5. Minimal Implementation
|
||||
Implement MINIMAL code to make tests pass. Focus only on making tests green. Do not add extra features or optimizations.
|
||||
|
||||
### 6. Verify Test Success
|
||||
Run all tests and verify they pass. Check coverage metrics. Ensure no tests were accidentally broken.
|
||||
|
||||
**GATE**: All tests must pass before proceeding.
|
||||
|
||||
## Phase 4: REFACTOR - Improve Code Quality
|
||||
|
||||
### 7. Code Refactoring
|
||||
Refactor implementation while keeping tests green. Apply SOLID principles, remove duplication, improve naming. Run tests after each refactoring.
|
||||
|
||||
### 8. Test Refactoring
|
||||
Refactor tests: remove duplication, improve names, extract common fixtures. Ensure coverage unchanged or improved.
|
||||
|
||||
## Phase 5: Integration Tests
|
||||
|
||||
### 9. Write Integration Tests (Failing First)
|
||||
Write FAILING integration tests. Test component interactions, API contracts, and data flow.
|
||||
|
||||
### 10. Implement Integration
|
||||
Make integration tests pass. Focus on component interaction and data flow.
|
||||
|
||||
## Validation Checkpoints
|
||||
|
||||
### RED Phase
|
||||
- [ ] All tests written before implementation
|
||||
- [ ] All tests fail with meaningful error messages
|
||||
- [ ] No test passes accidentally
|
||||
|
||||
### GREEN Phase
|
||||
- [ ] All tests pass
|
||||
- [ ] No extra code beyond test requirements
|
||||
- [ ] Coverage meets minimum thresholds
|
||||
|
||||
### REFACTOR Phase
|
||||
- [ ] All tests still pass after refactoring
|
||||
- [ ] Code complexity reduced
|
||||
- [ ] Duplication eliminated
|
||||
|
||||
## Anti-Patterns to Avoid
|
||||
|
||||
- Writing implementation before tests
|
||||
- Writing tests that already pass
|
||||
- Skipping the refactor phase
|
||||
- Modifying tests to make them pass
|
||||
- Writing tests after implementation
|
||||
|
||||
TDD implementation for: $ARGUMENTS
|
||||
@@ -0,0 +1,99 @@
|
||||
---
|
||||
description: React and Next.js performance optimization guidelines from Vercel Engineering. 45 rules across 8 categories, prioritized by impact.
|
||||
---
|
||||
|
||||
# Vercel React Best Practices
|
||||
|
||||
Comprehensive performance optimization guide for React and Next.js applications. 45 rules across 8 categories, prioritized by impact.
|
||||
|
||||
## When to Apply
|
||||
|
||||
- Writing new React components or Next.js pages
|
||||
- Implementing data fetching (client or server-side)
|
||||
- Reviewing code for performance issues
|
||||
- Refactoring existing React/Next.js code
|
||||
- Optimizing bundle size or load times
|
||||
|
||||
## Rule Categories by Priority
|
||||
|
||||
| Priority | Category | Impact | Prefix |
|
||||
|----------|----------|--------|--------|
|
||||
| 1 | Eliminating Waterfalls | CRITICAL | `async-` |
|
||||
| 2 | Bundle Size Optimization | CRITICAL | `bundle-` |
|
||||
| 3 | Server-Side Performance | HIGH | `server-` |
|
||||
| 4 | Client-Side Data Fetching | MEDIUM-HIGH | `client-` |
|
||||
| 5 | Re-render Optimization | MEDIUM | `rerender-` |
|
||||
| 6 | Rendering Performance | MEDIUM | `rendering-` |
|
||||
| 7 | JavaScript Performance | LOW-MEDIUM | `js-` |
|
||||
| 8 | Advanced Patterns | LOW | `advanced-` |
|
||||
|
||||
## 1. Eliminating Waterfalls (CRITICAL)
|
||||
|
||||
- **async-defer-await** - Move await into branches where actually used
|
||||
- **async-parallel** - Use Promise.all() for independent operations
|
||||
- **async-dependencies** - Use better-all for partial dependencies
|
||||
- **async-api-routes** - Start promises early, await late in API routes
|
||||
- **async-suspense-boundaries** - Use Suspense to stream content
|
||||
|
||||
## 2. Bundle Size Optimization (CRITICAL)
|
||||
|
||||
- **bundle-barrel-imports** - Import directly, avoid barrel files
|
||||
- **bundle-dynamic-imports** - Use next/dynamic for heavy components
|
||||
- **bundle-defer-third-party** - Load analytics/logging after hydration
|
||||
- **bundle-conditional** - Load modules only when feature is activated
|
||||
- **bundle-preload** - Preload on hover/focus for perceived speed
|
||||
|
||||
## 3. Server-Side Performance (HIGH)
|
||||
|
||||
- **server-cache-react** - Use React.cache() for per-request deduplication
|
||||
- **server-cache-lru** - Use LRU cache for cross-request caching
|
||||
- **server-serialization** - Minimize data passed to client components
|
||||
- **server-parallel-fetching** - Restructure components to parallelize fetches
|
||||
- **server-after-nonblocking** - Use after() for non-blocking operations
|
||||
|
||||
## 4. Client-Side Data Fetching (MEDIUM-HIGH)
|
||||
|
||||
- **client-swr-dedup** - Use SWR for automatic request deduplication
|
||||
- **client-event-listeners** - Deduplicate global event listeners
|
||||
|
||||
## 5. Re-render Optimization (MEDIUM)
|
||||
|
||||
- **rerender-defer-reads** - Don't subscribe to state only used in callbacks
|
||||
- **rerender-memo** - Extract expensive work into memoized components
|
||||
- **rerender-dependencies** - Use primitive dependencies in effects
|
||||
- **rerender-derived-state** - Subscribe to derived booleans, not raw values
|
||||
- **rerender-functional-setstate** - Use functional setState for stable callbacks
|
||||
- **rerender-lazy-state-init** - Pass function to useState for expensive values
|
||||
- **rerender-transitions** - Use startTransition for non-urgent updates
|
||||
|
||||
## 6. Rendering Performance (MEDIUM)
|
||||
|
||||
- **rendering-animate-svg-wrapper** - Animate div wrapper, not SVG element
|
||||
- **rendering-content-visibility** - Use content-visibility for long lists
|
||||
- **rendering-hoist-jsx** - Extract static JSX outside components
|
||||
- **rendering-svg-precision** - Reduce SVG coordinate precision
|
||||
- **rendering-hydration-no-flicker** - Use inline script for client-only data
|
||||
- **rendering-activity** - Use Activity component for show/hide
|
||||
- **rendering-conditional-render** - Use ternary, not && for conditionals
|
||||
|
||||
## 7. JavaScript Performance (LOW-MEDIUM)
|
||||
|
||||
- **js-batch-dom-css** - Group CSS changes via classes or cssText
|
||||
- **js-index-maps** - Build Map for repeated lookups
|
||||
- **js-cache-property-access** - Cache object properties in loops
|
||||
- **js-cache-function-results** - Cache function results in module-level Map
|
||||
- **js-cache-storage** - Cache localStorage/sessionStorage reads
|
||||
- **js-combine-iterations** - Combine multiple filter/map into one loop
|
||||
- **js-length-check-first** - Check array length before expensive comparison
|
||||
- **js-early-exit** - Return early from functions
|
||||
- **js-hoist-regexp** - Hoist RegExp creation outside loops
|
||||
- **js-min-max-loop** - Use loop for min/max instead of sort
|
||||
- **js-set-map-lookups** - Use Set/Map for O(1) lookups
|
||||
- **js-tosorted-immutable** - Use toSorted() for immutability
|
||||
|
||||
## 8. Advanced Patterns (LOW)
|
||||
|
||||
- **advanced-event-handler-refs** - Store event handlers in refs
|
||||
- **advanced-use-latest** - useLatest for stable callback refs
|
||||
|
||||
$ARGUMENTS
|
||||
@@ -0,0 +1,88 @@
|
||||
---
|
||||
name: work
|
||||
description: "Pick a Linear task (or create one), implement in a worktree, open a PR, and iterate on reviews autonomously"
|
||||
user-invocable: true
|
||||
args:
|
||||
- name: input
|
||||
description: "A Linear issue ID (e.g. ERN-347), an ad-hoc task description, or omit to auto-pick next unblocked task"
|
||||
required: false
|
||||
---
|
||||
|
||||
# Work - Proper PR Flow
|
||||
|
||||
Autonomous workflow: Linear issue -> worktree -> implementation -> PR -> review iteration -> done.
|
||||
|
||||
**First:** Read `~/.claude/skills/linear-common/COMMON.md` for shared setup instructions.
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Setup (from COMMON.md)
|
||||
- Load project config
|
||||
- Select task (from `$ARGUMENTS`)
|
||||
- Set up worktree
|
||||
- Gather context
|
||||
|
||||
### 2. Plan
|
||||
|
||||
1. Analyze the issue requirements and the codebase context you gathered.
|
||||
2. Break the work into logical commits.
|
||||
3. If the issue is non-trivial, write a brief plan as a comment on the Linear issue.
|
||||
4. Identify risks or open questions. If they're blocking, ask the user. If not, note them and proceed with best judgment.
|
||||
|
||||
### 3. Implement
|
||||
|
||||
Follow the implementation guidelines from COMMON.md.
|
||||
|
||||
After implementation is complete:
|
||||
1. Run the `buildCommand` from the config. All checks must pass before opening a PR.
|
||||
2. If tests fail, fix them. Do not ship broken code.
|
||||
|
||||
### 4. Open PR
|
||||
|
||||
1. Push the branch: `git push -u origin <branch>`
|
||||
2. Open a PR with `gh pr create`:
|
||||
- Title: concise, under 70 characters
|
||||
- Body format:
|
||||
```
|
||||
## Summary
|
||||
<bullets>
|
||||
|
||||
## Linear
|
||||
Closes <ISSUE-ID>
|
||||
|
||||
## Test plan
|
||||
<what was tested and how>
|
||||
```
|
||||
- Request reviewers from `prReviewers` if configured.
|
||||
3. Move the Linear issue to "In Review" (or equivalent status).
|
||||
|
||||
### 5. Review loop
|
||||
|
||||
Repeat until the PR is approved and CI passes:
|
||||
|
||||
1. Poll for reviews:
|
||||
```
|
||||
gh pr view <number> --json reviews,reviewRequests,statusCheckRollup
|
||||
gh api repos/{owner}/{repo}/pulls/{number}/comments
|
||||
```
|
||||
|
||||
2. For each review comment:
|
||||
- **Valid feedback**: fix the code, commit, push.
|
||||
- **Misunderstanding**: reply explaining, resolve the thread.
|
||||
- Resolve addressed threads via GraphQL:
|
||||
```
|
||||
gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: "<ID>"}) { thread { isResolved } } }'
|
||||
```
|
||||
- Find thread IDs:
|
||||
```
|
||||
gh api graphql -f query='{ repository(owner: "<OWNER>", name: "<REPO>") { pullRequest(number: <N>) { reviewThreads(first: 100) { nodes { id isResolved comments(first: 1) { nodes { body } } } } } } }'
|
||||
```
|
||||
|
||||
3. After addressing all comments, verify the build still passes.
|
||||
|
||||
4. Continue until:
|
||||
- All review threads resolved
|
||||
- CI checks pass
|
||||
- No pending review requests
|
||||
|
||||
5. Move the Linear issue to "Done" (or "Ready to merge" if that status exists).
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
description: Compare worktree changes with target branch before merging
|
||||
---
|
||||
|
||||
# Compare Worktree Changes
|
||||
|
||||
Visualize changes in the current worktree compared to a target branch (usually main/master).
|
||||
|
||||
**Usage:** `/worktree-compare [target-branch]`
|
||||
|
||||
## Process
|
||||
|
||||
### 1. Verify Context
|
||||
|
||||
```bash
|
||||
CURRENT_BRANCH=$(git branch --show-current)
|
||||
WORKTREE_DIR=$(git rev-parse --git-common-dir)
|
||||
|
||||
# Check we're in a worktree
|
||||
if [[ ! "$WORKTREE_DIR" == *".git/worktrees"* ]]; then
|
||||
echo "Error: You're not in a worktree"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 2. Determine Target Branch
|
||||
|
||||
```bash
|
||||
TARGET_BRANCH="${1:-}"
|
||||
if [ -z "$TARGET_BRANCH" ]; then
|
||||
if git show-ref --verify --quiet refs/heads/main; then
|
||||
TARGET_BRANCH="main"
|
||||
elif git show-ref --verify --quiet refs/heads/master; then
|
||||
TARGET_BRANCH="master"
|
||||
fi
|
||||
fi
|
||||
```
|
||||
|
||||
### 3. Update Target Branch
|
||||
|
||||
```bash
|
||||
git fetch origin "$TARGET_BRANCH:$TARGET_BRANCH" 2>/dev/null || true
|
||||
```
|
||||
|
||||
### 4. Summary + Diff
|
||||
|
||||
```bash
|
||||
git diff --shortstat "$TARGET_BRANCH..$CURRENT_BRANCH"
|
||||
git diff --name-status "$TARGET_BRANCH..$CURRENT_BRANCH"
|
||||
git log "$TARGET_BRANCH..$CURRENT_BRANCH" --oneline --decorate --graph
|
||||
git diff "$TARGET_BRANCH..$CURRENT_BRANCH"
|
||||
```
|
||||
|
||||
### 5. Conflict Detection
|
||||
|
||||
```bash
|
||||
# Check for files modified in both branches
|
||||
COMMON_FILES=$(comm -12 \
|
||||
<(git diff --name-only "$TARGET_BRANCH..$CURRENT_BRANCH" | sort) \
|
||||
<(git diff --name-only "$CURRENT_BRANCH..$TARGET_BRANCH" | sort))
|
||||
|
||||
if [ -z "$COMMON_FILES" ]; then
|
||||
echo "No potential conflicts detected"
|
||||
else
|
||||
echo "Potential conflicts in:"
|
||||
echo "$COMMON_FILES"
|
||||
fi
|
||||
```
|
||||
|
||||
$ARGUMENTS
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
description: List, manage, and clean up git worktrees
|
||||
---
|
||||
|
||||
# List and Manage Worktrees
|
||||
|
||||
**Usage:**
|
||||
- `/worktree-list` - List all worktrees
|
||||
- `/worktree-list cleanup` - Remove merged worktrees
|
||||
- `/worktree-list prune` - Clean stale references
|
||||
|
||||
## List All Worktrees
|
||||
|
||||
```bash
|
||||
git worktree list
|
||||
```
|
||||
|
||||
## Cleanup Merged Worktrees
|
||||
|
||||
If argument is "cleanup":
|
||||
|
||||
```bash
|
||||
# Find main branch
|
||||
if git show-ref --verify --quiet refs/heads/main; then
|
||||
MAIN_BRANCH="main"
|
||||
elif git show-ref --verify --quiet refs/heads/master; then
|
||||
MAIN_BRANCH="master"
|
||||
fi
|
||||
|
||||
# Find and remove merged branches and their worktrees
|
||||
MERGED_BRANCHES=$(git branch --merged "$MAIN_BRANCH" | grep -v '^\*' | grep -v "$MAIN_BRANCH")
|
||||
|
||||
for branch in $MERGED_BRANCHES; do
|
||||
WORKTREE_PATH=$(git worktree list | grep "\[$branch\]" | awk '{print $1}')
|
||||
if [ -n "$WORKTREE_PATH" ]; then
|
||||
git worktree remove "$WORKTREE_PATH" --force
|
||||
fi
|
||||
git branch -d "$branch"
|
||||
done
|
||||
|
||||
git worktree prune
|
||||
git worktree list
|
||||
```
|
||||
|
||||
## Prune Stale References
|
||||
|
||||
If argument is "prune":
|
||||
|
||||
```bash
|
||||
git worktree prune -v
|
||||
git worktree list
|
||||
```
|
||||
|
||||
$ARGUMENTS
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
name: yolo
|
||||
description: "Pick a Linear task (or create one), implement in a worktree, push directly with minimal ceremony"
|
||||
user-invocable: true
|
||||
args:
|
||||
- name: input
|
||||
description: "A Linear issue ID (e.g. ERN-347), an ad-hoc task description, or omit to auto-pick next unblocked task"
|
||||
required: false
|
||||
---
|
||||
|
||||
# Yolo - Quick Ship Flow
|
||||
|
||||
Fast autonomous workflow: Linear issue -> worktree -> implementation -> push -> done. No PRs, no reviews.
|
||||
|
||||
**First:** Read `~/.claude/skills/linear-common/COMMON.md` for shared setup instructions.
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Setup (from COMMON.md)
|
||||
- Load project config
|
||||
- Select task (from `$ARGUMENTS`)
|
||||
- Set up worktree
|
||||
- Gather context
|
||||
|
||||
### 2. Implement
|
||||
|
||||
Follow the implementation guidelines from COMMON.md. Move fast — this is yolo mode.
|
||||
|
||||
- Skip formal planning. Read the issue, understand it, start coding.
|
||||
- Still write tests if the project has them, but don't block on edge cases.
|
||||
- Run the `buildCommand` if configured. If it fails, fix it. If a failure is minor and unrelated to your change, warn the user but keep going.
|
||||
|
||||
### 3. Ship
|
||||
|
||||
1. Push the branch: `git push -u origin <branch>`
|
||||
2. If the work is complete and self-contained, merge to the default branch:
|
||||
```
|
||||
git checkout <defaultBranch>
|
||||
git merge <branch> --no-edit
|
||||
git push
|
||||
git checkout <branch>
|
||||
```
|
||||
Only do this if the change is clearly ready. If unsure, just push the branch and let the user decide.
|
||||
3. Move the Linear issue to "Done".
|
||||
4. That's it. No PR, no review loop.
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
input=$(cat)
|
||||
|
||||
# Extract values from JSON input
|
||||
MODEL=$(echo "$input" | jq -r '.model.display_name // "Claude"')
|
||||
DIR=$(echo "$input" | jq -r '.workspace.current_dir // "~"')
|
||||
DIR_NAME="${DIR##*/}"
|
||||
CONTEXT_USED=$(echo "$input" | jq -r '.context_window.used_percentage // 0')
|
||||
COST=$(echo "$input" | jq -r '.cost.total_cost_usd // 0')
|
||||
|
||||
# Get git repo root path (abbreviated with ~) and branch/PR info
|
||||
GIT_INFO=""
|
||||
REPO_PATH=""
|
||||
if git -C "$DIR" rev-parse --git-dir > /dev/null 2>&1; then
|
||||
REPO_ROOT=$(git -C "$DIR" rev-parse --show-toplevel 2>/dev/null)
|
||||
# For worktrees, get the main repo root instead of the worktree path
|
||||
MAIN_GIT_DIR=$(git -C "$DIR" rev-parse --git-common-dir 2>/dev/null)
|
||||
if [ -n "$MAIN_GIT_DIR" ] && [[ "$MAIN_GIT_DIR" == /* ]]; then
|
||||
REPO_ROOT=$(dirname "$MAIN_GIT_DIR")
|
||||
fi
|
||||
# Abbreviate ~/projects/ to p/
|
||||
REPO_PATH=" | ${REPO_ROOT/#$HOME\/projects\//p/}"
|
||||
BRANCH=$(git -C "$DIR" branch --show-current 2>/dev/null)
|
||||
if [ -n "$BRANCH" ]; then
|
||||
PR_NUMBER=$(GIT_DIR="$DIR/.git" GIT_WORK_TREE="$DIR" gh pr view --json number -q '.number' 2>/dev/null)
|
||||
if [ -n "$PR_NUMBER" ]; then
|
||||
GIT_INFO=" | $BRANCH (#$PR_NUMBER)"
|
||||
else
|
||||
GIT_INFO=" | $BRANCH"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Format cost (force C locale so the decimal separator is always ".")
|
||||
COST_FMT=$(LC_NUMERIC=C printf "%.2f" "$COST")
|
||||
|
||||
echo "YOLO$REPO_PATH$GIT_INFO | [$MODEL] | \$$COST_FMT | ${CONTEXT_USED}%"
|
||||
@@ -0,0 +1,7 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
esphome
|
||||
clang-tools
|
||||
];
|
||||
}
|
||||
@@ -1,20 +1,43 @@
|
||||
{ lib, config, ... }:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
{
|
||||
imports = [
|
||||
../features/mutable-file.nix
|
||||
./zsh.nix
|
||||
./nix.nix
|
||||
./neovim
|
||||
./rust.nix
|
||||
./elixir.nix
|
||||
./nodejs.nix
|
||||
./git
|
||||
./solidity.nix
|
||||
./dev.nix
|
||||
./cpp.nix
|
||||
./claude
|
||||
./opencode
|
||||
./yazi
|
||||
./ssh.nix
|
||||
./tmux.nix
|
||||
];
|
||||
|
||||
home.mutableFilesRepoPath = "${config.home.homeDirectory}/projects/nixos-config";
|
||||
|
||||
programs = {
|
||||
home-manager.enable = true;
|
||||
};
|
||||
|
||||
home.packages = with pkgs; [
|
||||
impala
|
||||
];
|
||||
|
||||
home = {
|
||||
username = lib.mkDefault "naps62";
|
||||
homeDirectory = lib.mkDefault "/home/${config.home.username}";
|
||||
stateVersion = lib.mkDefault "24.05";
|
||||
sessionPath = [ "$HOME/.local/bin" ];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{ config, pkgs, ... }:
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
dconf
|
||||
@@ -8,15 +8,53 @@
|
||||
enable = true;
|
||||
darkModeScripts = {
|
||||
gtk-theme = ''
|
||||
${pkgs.dconf}/bin/dconf write\
|
||||
${pkgs.dconf}/bin/dconf write \
|
||||
/org/gnome/desktop/interface/color-scheme "'prefer-dark'"
|
||||
${pkgs.dconf}/bin/dconf write \
|
||||
/org/gnome/desktop/interface/gtk-theme "'Orchis-Dark-Compact'"
|
||||
'';
|
||||
cursor-theme = ''
|
||||
${pkgs.dconf}/bin/dconf write \
|
||||
/org/gnome/desktop/interface/cursor-theme "'Nordzy-cursors'"
|
||||
|
||||
# Set environment variables for current session
|
||||
export HYPRCURSOR_THEME="Nordzy-cursors"
|
||||
export XCURSOR_THEME="Nordzy-cursors"
|
||||
|
||||
# Update Hyprland cursor theme
|
||||
${pkgs.hyprland}/bin/hyprctl setcursor Nordzy-cursors 24
|
||||
'';
|
||||
noctalia-theme = ''
|
||||
noctalia msg theme-mode-set dark
|
||||
'';
|
||||
};
|
||||
lightModeScripts = {
|
||||
gtk-theme = ''
|
||||
${pkgs.dconf}/bin/dconf write\
|
||||
${pkgs.dconf}/bin/dconf write \
|
||||
/org/gnome/desktop/interface/color-scheme "'prefer-light'"
|
||||
${pkgs.dconf}/bin/dconf write \
|
||||
/org/gnome/desktop/interface/gtk-theme "'Orchis-Compact'"
|
||||
'';
|
||||
cursor-theme = ''
|
||||
${pkgs.dconf}/bin/dconf write \
|
||||
/org/gnome/desktop/interface/cursor-theme "'Nordzy-white'"
|
||||
|
||||
# Set environment variables for current session
|
||||
export HYPRCURSOR_THEME="Nordzy-white"
|
||||
export XCURSOR_THEME="Nordzy-white"
|
||||
|
||||
# Update Hyprland cursor theme
|
||||
${pkgs.hyprland}/bin/hyprctl setcursor Nordzy-white 24
|
||||
'';
|
||||
noctalia-theme = ''
|
||||
noctalia msg theme-mode-set light
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
xdg.configFile."darkman/config.yaml".text = ''
|
||||
lat: 41.55
|
||||
lng: -8.42
|
||||
dbusserver: true
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
imports = [
|
||||
./firefox.nix
|
||||
./darkman.nix
|
||||
./spicetify.nix
|
||||
];
|
||||
|
||||
home.packages = with pkgs; [
|
||||
# various
|
||||
google-chrome
|
||||
spotify
|
||||
spicetify-cli
|
||||
xfce.thunar
|
||||
thunar
|
||||
obsidian
|
||||
mpv
|
||||
obs-studio
|
||||
@@ -20,11 +23,16 @@
|
||||
imv
|
||||
pavucontrol
|
||||
zathura
|
||||
lxappearance
|
||||
libsForQt5.qt5ct
|
||||
kdePackages.qt6ct
|
||||
nwg-look
|
||||
xournalpp
|
||||
jq
|
||||
kooha
|
||||
ffmpeg
|
||||
unzip
|
||||
|
||||
# remote desktop
|
||||
remmina
|
||||
|
||||
# networking
|
||||
networkmanagerapplet
|
||||
@@ -35,11 +43,14 @@
|
||||
slack
|
||||
zoom-us
|
||||
ferdium
|
||||
signal-desktop
|
||||
|
||||
# dev tools
|
||||
ferdium
|
||||
bruno
|
||||
yaak
|
||||
bun
|
||||
|
||||
# themes
|
||||
tela-icon-theme
|
||||
];
|
||||
|
||||
gtk = {
|
||||
@@ -48,9 +59,43 @@
|
||||
name = "Orchis-Dark-Compact";
|
||||
package = pkgs.orchis-theme;
|
||||
};
|
||||
# Keep applying the gtk3 theme to gtk4 too (new default is null).
|
||||
gtk4.theme = config.gtk.theme;
|
||||
iconTheme = {
|
||||
name = "Tela black";
|
||||
package = pkgs.tela-icon-theme;
|
||||
};
|
||||
cursorTheme = {
|
||||
name = "Numix-Cursor-Light";
|
||||
package = pkgs.numix-cursor-theme;
|
||||
};
|
||||
};
|
||||
|
||||
home.pointerCursor = {
|
||||
package = pkgs.numix-cursor-theme;
|
||||
name = "Numix-Cursor-Light";
|
||||
};
|
||||
|
||||
# zathura: include noctalia-generated theme
|
||||
xdg.configFile."zathura/zathurarc".text = ''
|
||||
include noctaliarc
|
||||
'';
|
||||
|
||||
# gtk: include noctalia-generated css (mkForce to override gtk module)
|
||||
xdg.configFile."gtk-3.0/gtk.css".text = lib.mkForce ''
|
||||
@import url("noctalia.css");
|
||||
'';
|
||||
xdg.configFile."gtk-4.0/gtk.css".text = lib.mkForce ''
|
||||
@import url("noctalia.css");
|
||||
'';
|
||||
|
||||
# qt: use noctalia color scheme
|
||||
xdg.configFile."qt5ct/qt5ct.conf".text = ''
|
||||
[Appearance]
|
||||
color_scheme_path=${config.home.homeDirectory}/.config/qt5ct/colors/noctalia.conf
|
||||
'';
|
||||
xdg.configFile."qt6ct/qt6ct.conf".text = ''
|
||||
[Appearance]
|
||||
color_scheme_path=${config.home.homeDirectory}/.config/qt6ct/colors/noctalia.conf
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
{ pkgs, inputs, ... }:
|
||||
{
|
||||
|
||||
home.sessionVariables = {
|
||||
BROWSER = "firefox";
|
||||
};
|
||||
|
||||
programs.firefox = {
|
||||
enable = true;
|
||||
package = pkgs.firefox-devedition;
|
||||
policies = {
|
||||
DefaultDownloadDirectory = "$HOME/downloads";
|
||||
DontCheckDefaultBrowser = true;
|
||||
DisableTelemetry = true;
|
||||
DisablePocket = true;
|
||||
DisableFirefoxStudies = true;
|
||||
|
||||
DisplayBookmarksToolbar = "never";
|
||||
DisplayMenuBar = "never";
|
||||
|
||||
OverrideFirstRunPage = "";
|
||||
PromptForDownloadLocation = false;
|
||||
|
||||
HardwareAcceleration = true;
|
||||
TranslateEnabled = true;
|
||||
|
||||
Homepage.StartPage = "previous-session";
|
||||
|
||||
UserMessaging = {
|
||||
SkipOnboarding = true;
|
||||
};
|
||||
|
||||
FirefoxSuggest = {
|
||||
WebSuggestions = false;
|
||||
SponsoredSuggestions = false;
|
||||
ImproveSuggest = false;
|
||||
};
|
||||
|
||||
EnableTrackingProtection = {
|
||||
Value = true;
|
||||
Cryptomining = true;
|
||||
Fingerprinting = true;
|
||||
};
|
||||
|
||||
FirefoxHome = {
|
||||
Search = true;
|
||||
TopSites = true;
|
||||
SponsoredTopSites = true;
|
||||
Highlights = true;
|
||||
Pocket = false;
|
||||
SponsoredPocket = false;
|
||||
Snippets = false;
|
||||
};
|
||||
};
|
||||
|
||||
profiles = {
|
||||
"dev-edition-default" = {
|
||||
isDefault = true;
|
||||
extensions = with inputs.firefox-addons.packages.${pkgs.system}; [
|
||||
# privacy
|
||||
clearurls
|
||||
decentraleyes
|
||||
|
||||
# quality of life
|
||||
no-pdf-download
|
||||
buster-captcha-solver
|
||||
|
||||
# dev
|
||||
react-devtools
|
||||
translate-web-pages
|
||||
|
||||
# manual use
|
||||
bitwarden
|
||||
];
|
||||
settings = {
|
||||
# Performance settings
|
||||
"gfx.webrender.all" = true; # Force enable GPU acceleration
|
||||
"media.ffmpeg.vaapi.enabled" = true;
|
||||
"widget.dmabuf.force-enabled" = true; # Required in recent Firefoxes
|
||||
|
||||
"widget.use-xdg-desktop-portal.file-picker" = true;
|
||||
|
||||
# Hide the "sharing indicator", it's especially annoying
|
||||
# with tiling WMs on wayland
|
||||
"privacy.webrtc.legacyGlobalIndicator" = false;
|
||||
|
||||
# Actual settings
|
||||
"browser.aboutConfig.showWarning" = false;
|
||||
"browser.newtabpage.pinned" = false;
|
||||
"browser.protections_panel.infoMessage.seen" = true;
|
||||
"browser.quitShortcut.disabled" = true;
|
||||
"browser.urlbar.suggest.openpage" = false;
|
||||
"privacy.trackingprotection.enabled" = true;
|
||||
"privacy.trackingprotection.socialtracking.enabled" = true;
|
||||
|
||||
"mousewhell.system_scroll_override" = true;
|
||||
|
||||
"extension.autoDisableScopes" = "0";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{ inputs, pkgs, ... }:
|
||||
let
|
||||
spicePkgs = inputs.spicetify-nix.legacyPackages.${pkgs.stdenv.hostPlatform.system};
|
||||
in
|
||||
{
|
||||
imports = [ inputs.spicetify-nix.homeManagerModules.default ];
|
||||
|
||||
programs.spicetify = {
|
||||
enable = true;
|
||||
enabledExtensions = with spicePkgs.extensions; [
|
||||
adblock
|
||||
hidePodcasts
|
||||
shuffle
|
||||
];
|
||||
theme = spicePkgs.themes.bloom;
|
||||
};
|
||||
}
|
||||
@@ -1,10 +1,58 @@
|
||||
{ lib, config, ... }:
|
||||
{
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
imports = [
|
||||
./ralph-claude-code.nix
|
||||
];
|
||||
|
||||
programs = {
|
||||
direnv = {
|
||||
enable = true;
|
||||
enableZshIntegration = true;
|
||||
nix-direnv.enable = true;
|
||||
|
||||
# Add devenv support
|
||||
stdlib = ''
|
||||
# Source devenv direnvrc for use_devenv function
|
||||
eval "$(devenv direnvrc)"
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
home.packages = with pkgs; [
|
||||
imagemagick
|
||||
doctl
|
||||
inotify-tools
|
||||
devenv
|
||||
bruno
|
||||
sshfs
|
||||
coturn
|
||||
file
|
||||
usbutils
|
||||
nmap
|
||||
lsof
|
||||
ktlint
|
||||
croc
|
||||
opencode
|
||||
process-compose
|
||||
|
||||
# typst
|
||||
typst
|
||||
typstyle
|
||||
|
||||
ruby
|
||||
|
||||
mkcert
|
||||
nss.tools
|
||||
|
||||
kicad
|
||||
tea
|
||||
|
||||
just # project command runner
|
||||
lazydocker # docker TUI
|
||||
dust # du replacement
|
||||
duf # df replacement
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
elixir_1_18
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{ inputs, pkgs, ... }:
|
||||
{
|
||||
home.packages = [ inputs.ethui.packages.${pkgs.stdenv.hostPlatform.system}.default ];
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
programs.ghostty = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
xdg.configFile."ghostty/config".source = ./ghostty/config;
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
# style
|
||||
theme = catppuccin-mocha
|
||||
window-decoration = false
|
||||
# window-decoration = false
|
||||
window-padding-x = 0
|
||||
window-padding-y = 0
|
||||
window-padding-color = extend
|
||||
custom-shader-animation = true
|
||||
|
||||
# font
|
||||
font-size = 12
|
||||
font-family = "FiraCode Nerd Font Mono"
|
||||
font-family-italic = "VictorMono Nerd Font mono Oblique"
|
||||
font-family-bold-italic = "VictorMono Nerd Font mono Bold Oblique"
|
||||
@@ -19,8 +20,8 @@ clipboard-write = allow
|
||||
keybind = unconsumed:ctrl+enter=ignore
|
||||
|
||||
# keybinds:fontsize
|
||||
keybind = ctrl+shift+plus=increase_font_size:2
|
||||
keybind = ctrl+shift+minus=decrease_font_size:2
|
||||
keybind = alt+plus=increase_font_size:2
|
||||
keybind = alt+minus=decrease_font_size:2
|
||||
|
||||
# keybinds:tabs
|
||||
keybind = alt+u=previous_tab
|
||||
|
||||
@@ -5,37 +5,52 @@
|
||||
|
||||
programs.git = {
|
||||
enable = true;
|
||||
userName = "Miguel Palhas";
|
||||
userEmail = "mpalhas@gmail.com";
|
||||
aliases = {
|
||||
ls = "log --color --graph --oneline --decorate --topo-order --pretty=format:'%C(yellow)%d%Creset %Cgreen(%cr)%Creset %C(bold blue)[%an]%Creset %s %Cred(%h)%Creset' --abbrev-commit";
|
||||
ll = ''log --reverse --pretty=format:"%C(yellow)%h%Cred%d\ %Creset%s%Cblue\ [%an]" --decorate --numstat'';
|
||||
conf = "diff --name-only --diff-filter=U";
|
||||
ba = "branch -a";
|
||||
pb = "publish";
|
||||
ps = "push -u";
|
||||
pr = "pull-request";
|
||||
ppr = "push-pr";
|
||||
cpr = "close-pr";
|
||||
opr = "open-pr";
|
||||
f = "fetch";
|
||||
c = "commit --verbose";
|
||||
d = "diff";
|
||||
dc = "diff --cached";
|
||||
co = "checkout";
|
||||
s = "status -sb";
|
||||
b = "better-branch";
|
||||
rb = "rebase";
|
||||
rbc = "rebase --continue";
|
||||
w = "commit -am 'wip'";
|
||||
};
|
||||
extraConfig = {
|
||||
settings = {
|
||||
user = {
|
||||
name = "Miguel Palhas";
|
||||
email = "mpalhas@gmail.com";
|
||||
};
|
||||
alias = {
|
||||
ls = "log --color --graph --oneline --decorate --topo-order --pretty=format:'%C(yellow)%d%Creset %Cgreen(%cr)%Creset %C(bold blue)[%an]%Creset %s %Cred(%h)%Creset' --abbrev-commit";
|
||||
ll = ''log --reverse --pretty=format:"%C(yellow)%h%Cred%d\ %Creset%s%Cblue\ [%an]" --decorate --numstat'';
|
||||
conf = "diff --name-only --diff-filter=U";
|
||||
ba = "branch -a";
|
||||
pb = "publish";
|
||||
ps = "push -u";
|
||||
pr = "pull-request";
|
||||
ppr = "push-pr";
|
||||
cpr = "close-pr";
|
||||
opr = "open-pr";
|
||||
f = "fetch";
|
||||
c = "commit --verbose";
|
||||
d = "diff";
|
||||
dc = "diff --cached";
|
||||
co = "checkout";
|
||||
s = "status -sb";
|
||||
b = "better-branch";
|
||||
rb = "rebase";
|
||||
rbc = "rebase --continue";
|
||||
w = "commit -am 'wip'";
|
||||
# Structural (AST-aware) diff on demand; `git d`/`diff` stays delta.
|
||||
# Accepts args, e.g. `git dft HEAD~3`.
|
||||
dft = "!GIT_EXTERNAL_DIFF=difft git diff";
|
||||
};
|
||||
init = {
|
||||
defaultBranch = "main";
|
||||
};
|
||||
core = {
|
||||
editor = "nvim";
|
||||
pager = "delta";
|
||||
askpass = "";
|
||||
};
|
||||
credential = {
|
||||
helper = "store";
|
||||
};
|
||||
"credential \"https://git.naps.pt\"" = {
|
||||
helper = "!tea login helper";
|
||||
};
|
||||
merge = {
|
||||
conflictstyle = "zdiff3";
|
||||
};
|
||||
commit = {
|
||||
template = "~/.config/git/commit-message.txt";
|
||||
@@ -45,6 +60,7 @@
|
||||
};
|
||||
delta = {
|
||||
navigate = true;
|
||||
side-by-side = true;
|
||||
};
|
||||
"diff \"image\"" = {
|
||||
textconv = "mediainfo";
|
||||
@@ -57,7 +73,10 @@
|
||||
|
||||
home.packages = with pkgs; [
|
||||
delta
|
||||
difftastic
|
||||
git-crypt
|
||||
mediainfo
|
||||
tea
|
||||
];
|
||||
home.sessionPath = [
|
||||
"$HOME/.config/git/scripts"
|
||||
@@ -65,5 +84,15 @@
|
||||
xdg.configFile = {
|
||||
"git/scripts".source = ./scripts;
|
||||
};
|
||||
programs.gh.enable = true;
|
||||
programs.gh = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
aliases = {
|
||||
co = "pr checkout";
|
||||
ls = "pr list";
|
||||
pv = "pr view";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#!/usr/bin/env bash -e
|
||||
#!/usr/bin/env bash
|
||||
|
||||
branch=$(git branchname)
|
||||
set -e
|
||||
|
||||
branch=$(git rev-parse --abbrev-ref HEAD)
|
||||
base="$1"
|
||||
shift
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
godot
|
||||
gdtoolkit_4
|
||||
];
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
{
|
||||
inputs,
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
@@ -14,25 +11,14 @@
|
||||
|
||||
services.gpg-agent = {
|
||||
enable = true;
|
||||
pinentryPackage = pkgs.pinentry-gnome3;
|
||||
pinentry.package = pkgs.pinentry-gnome3;
|
||||
# Use gpg-agent as the ssh-agent so AddKeysToAgent ("yes") in ssh.nix
|
||||
# has an agent to load keys into.
|
||||
enableSshSupport = true;
|
||||
};
|
||||
# pinentry = {
|
||||
# enable = true;
|
||||
# pinentryFlavor = "gnome3";
|
||||
# };
|
||||
# settings = {
|
||||
# keyserver = "hkps://keys.openpgp.org";
|
||||
# use-agent = true;
|
||||
# use-agent-extra = true;
|
||||
# no-greeting = true;
|
||||
# verbose = true;
|
||||
# };
|
||||
# };
|
||||
|
||||
programs.password-store = {
|
||||
enable = true;
|
||||
settings = {
|
||||
PASSWORD_STORE_DIR = "/home/naps62/sync/pass";
|
||||
};
|
||||
settings = { };
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,23 +1,19 @@
|
||||
{ pkgs, inputs, ... }:
|
||||
{ pkgs, config, ... }:
|
||||
let
|
||||
nordzy-cursors = pkgs.callPackage ../../../../pkgs/nordzy-cursors/package.nix { };
|
||||
cursorSize = config.custom.hyprland.cursorSize;
|
||||
in
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
rose-pine-cursor
|
||||
inputs.rose-pine-hyprcursor.packages.${pkgs.system}.default
|
||||
home.packages = [
|
||||
nordzy-cursors
|
||||
];
|
||||
|
||||
home.sessionVariables = {
|
||||
HYPRCURSOR_THEME = "BreezeX-RosePine-Linux";
|
||||
HYPRCURSOR_SIZE = 32;
|
||||
XCURSOR_THEME = "BreezeX-RosePine-Linux";
|
||||
XCURSOR_SIZE = 32;
|
||||
HYPRCURSOR_THEME = "Nordzy-cursors"; # Dark variant (default)
|
||||
HYPRCURSOR_SIZE = cursorSize;
|
||||
XCURSOR_THEME = "Nordzy-cursors";
|
||||
XCURSOR_SIZE = cursorSize;
|
||||
};
|
||||
|
||||
dconf = {
|
||||
enable = true;
|
||||
settings = {
|
||||
"org/gnome/desktop/interface" = {
|
||||
cursor-theme = "BreezeX-RosePine-Linux";
|
||||
};
|
||||
};
|
||||
};
|
||||
dconf.enable = true;
|
||||
}
|
||||
|
||||
@@ -1,181 +1,309 @@
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
rofiLaunchers = import ../../../pkgs/rofi-launchers/package.nix { };
|
||||
cfg = config.custom.hyprland;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./rofi.nix
|
||||
./dunst.nix
|
||||
./cursor.nix
|
||||
./hyprpanel.nix
|
||||
];
|
||||
|
||||
home.packages = with pkgs; [
|
||||
hyprcursor
|
||||
pamixer
|
||||
hyprshot
|
||||
playerctl
|
||||
hyprsunset
|
||||
];
|
||||
|
||||
home.sessionVariables = {
|
||||
ELECTRON_OZONE_PLATFORM_HINT = "auto";
|
||||
};
|
||||
|
||||
wayland.windowManager.hyprland = {
|
||||
enable = true;
|
||||
settings = {
|
||||
input = {
|
||||
kb_options = "ctrl:nocaps";
|
||||
repeat_delay = 150;
|
||||
|
||||
touchpad = {
|
||||
natural_scroll = "yes";
|
||||
};
|
||||
numlock_by_default = 2;
|
||||
};
|
||||
|
||||
cursor = {
|
||||
no_hardware_cursors = "yes";
|
||||
};
|
||||
|
||||
general = {
|
||||
border_size = 0;
|
||||
gaps_in = 4;
|
||||
gaps_out = 0;
|
||||
};
|
||||
|
||||
misc = {
|
||||
disable_hyprland_logo = true;
|
||||
disable_splash_rendering = true;
|
||||
};
|
||||
|
||||
xwayland = {
|
||||
force_zero_scaling = true;
|
||||
};
|
||||
|
||||
animations = {
|
||||
bezier = "easeOutQuad, 0.5, 1, 0.89, 1";
|
||||
animation = [
|
||||
"windows, 1, 4, easeOutQuad"
|
||||
"windowsMove, 1, 1, easeOutQuad"
|
||||
"windowsOut, 1, 4, default, popin 80%"
|
||||
"border, 1, 4, default"
|
||||
"borderangle, 1, 4, default"
|
||||
"fade, 1, 4, default"
|
||||
"workspaces, 1, 3, default"
|
||||
];
|
||||
|
||||
};
|
||||
|
||||
env = [
|
||||
"XCURSOR_SIZE, 32"
|
||||
"HYPRCURSOR_THEME, rose-pine-hyprcursor"
|
||||
"HYPRCURSOR_SIZE, 24"
|
||||
];
|
||||
|
||||
"exec-once" = [
|
||||
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP"
|
||||
# "hyprpanel"
|
||||
"nm-applet"
|
||||
"hyprsunset"
|
||||
];
|
||||
|
||||
windowrulev2 = [
|
||||
# imv
|
||||
"float, class:imv"
|
||||
"move cursor -50% -50%, class:imv"
|
||||
|
||||
# bluetooth
|
||||
"float, class:blueman-manager"
|
||||
"move cursor -50% -50%, class:blueman-manager"
|
||||
"size 600 400, class:blueman-manager"
|
||||
|
||||
# pavucontrol
|
||||
"float, class:pavucontrol"
|
||||
"move cursor -50% -50%, class:pavucontrol"
|
||||
"size 600 600, class:pavucontrol"
|
||||
];
|
||||
|
||||
"$mod" = "SUPER";
|
||||
|
||||
bind = [
|
||||
"$mod, t, exec, ghostty"
|
||||
"$mod, e, exec, thunar"
|
||||
"$mod, v, togglefloating"
|
||||
"$mod, q, killactive"
|
||||
"$mod, f, fullscreen, 0"
|
||||
"$mod SHIFT, f, fullscreen, 1"
|
||||
|
||||
# rofi
|
||||
"$mod, space, exec, launcher_t2"
|
||||
|
||||
# printscreen
|
||||
", Print, exec, hyprshot -m region --output-folder ~/screenshots"
|
||||
"SHIFT, Print, exec, hyprshot -m window --output-folder ~/screenshots"
|
||||
|
||||
# move focus with mod + arrows
|
||||
"$mod, h, movefocus, l"
|
||||
"$mod, j, movefocus, d"
|
||||
"$mod, k, movefocus, u"
|
||||
"$mod, l, movefocus, r"
|
||||
|
||||
# Switch workspaces with mod + [0-9]
|
||||
"$mod, 1, workspace, 1"
|
||||
"$mod, 2, workspace, 2"
|
||||
"$mod, 3, workspace, 3"
|
||||
"$mod, 3, workspace, 3"
|
||||
"$mod, 4, workspace, 4"
|
||||
"$mod, 5, workspace, 5"
|
||||
"$mod, 6, workspace, 6"
|
||||
|
||||
# Move active window to a workspace with mod + SHIFT + [0-9]
|
||||
"$mod SHIFT, 1, movetoworkspace, 1"
|
||||
"$mod SHIFT, 2, movetoworkspace, 2"
|
||||
"$mod SHIFT, 3, movetoworkspace, 3"
|
||||
"$mod SHIFT, 4, movetoworkspace, 4"
|
||||
"$mod SHIFT, 5, movetoworkspace, 5"
|
||||
"$mod SHIFT, 6, movetoworkspace, 6"
|
||||
|
||||
# Move active window inside workspace
|
||||
"$mod SHIFT, h, movewindow, l"
|
||||
"$mod SHIFT, j, movewindow, d"
|
||||
"$mod SHIFT, k, movewindow, u"
|
||||
"$mod SHIFT, l, movewindow, r"
|
||||
|
||||
# Scroll through existing workspaces with mod + scroll
|
||||
"$mod, mouse_down, workspace, e+1"
|
||||
"$mod, mouse_up, workspace, e-1"
|
||||
|
||||
];
|
||||
|
||||
bindel = [
|
||||
", XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+"
|
||||
", XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"
|
||||
", XF86MonBrightnessUp, exec, brightnessctl set 5%+"
|
||||
", XF86MonBrightnessDown, exec, brightnessctl set 5%-"
|
||||
];
|
||||
bindl = [
|
||||
", XF86AudioMute, exec, pactl set-sink-mute @DEFAULT_SINK@ toggle"
|
||||
", XF86AudioMicMute, exec, volumectl -m toggle-mute"
|
||||
", XF86AudioNext, exec, playerctl next"
|
||||
", XF86AudioPrev, exec, playerctl previous"
|
||||
", XF86AudioPlay, exec, playerctl play-pause"
|
||||
];
|
||||
|
||||
bindm = [
|
||||
# Move/resize windows with mod + LMB/RMB and dragging
|
||||
"$mod, mouse:272, movewindow"
|
||||
"$mod, mouse:273, resizewindow"
|
||||
];
|
||||
options.custom.hyprland = {
|
||||
yaziSize = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "1400 1400";
|
||||
description = "Size of the yazi special workspace window";
|
||||
};
|
||||
cursorSize = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 24;
|
||||
description = "Cursor size for XCURSOR_SIZE and HYPRCURSOR_SIZE";
|
||||
};
|
||||
};
|
||||
|
||||
services.hyprpaper = {
|
||||
enable = true;
|
||||
settings = {
|
||||
ipc = "on";
|
||||
splash = false;
|
||||
imports = [
|
||||
./cursor.nix
|
||||
./noctalia
|
||||
./wallpapers.nix
|
||||
];
|
||||
|
||||
config = {
|
||||
home.packages = with pkgs; [
|
||||
hyprcursor
|
||||
pamixer
|
||||
hyprshot
|
||||
satty
|
||||
playerctl
|
||||
hyprsunset
|
||||
libnotify
|
||||
cliphist
|
||||
wf-recorder
|
||||
slurp
|
||||
];
|
||||
|
||||
home.sessionVariables = {
|
||||
ELECTRON_OZONE_PLATFORM_HINT = "auto";
|
||||
# WebKitGTK (Tauri apps) renders blank/crashes on the DMABUF path across
|
||||
# many GPU/driver combos; disable it on all hosts.
|
||||
WEBKIT_DISABLE_DMABUF_RENDERER = "1";
|
||||
};
|
||||
|
||||
wayland.windowManager.hyprland = {
|
||||
enable = true;
|
||||
package = null;
|
||||
portalPackage = null;
|
||||
# Keep the hyprlang config format (the new default is "lua"); our
|
||||
# settings are written as hyprlang.
|
||||
configType = "hyprlang";
|
||||
plugins = [ ];
|
||||
settings = {
|
||||
plugin = {
|
||||
overview = {
|
||||
autoDrag = true;
|
||||
exitOnClick = true;
|
||||
exitOnSwitch = true;
|
||||
showNewWorkspace = false;
|
||||
showEmptyWorkspace = false;
|
||||
};
|
||||
};
|
||||
input = {
|
||||
kb_options = "ctrl:nocaps";
|
||||
repeat_delay = 150;
|
||||
|
||||
touchpad = {
|
||||
natural_scroll = "yes";
|
||||
};
|
||||
numlock_by_default = true;
|
||||
};
|
||||
|
||||
cursor = {
|
||||
no_hardware_cursors = "yes";
|
||||
};
|
||||
|
||||
general = {
|
||||
border_size = 1;
|
||||
gaps_in = 0;
|
||||
gaps_out = 0;
|
||||
snap = {
|
||||
enabled = true;
|
||||
border_overlap = true;
|
||||
};
|
||||
|
||||
"col.inactive_border" = "0x99999999";
|
||||
"col.active_border" = "0x99999999";
|
||||
};
|
||||
|
||||
misc = {
|
||||
disable_hyprland_logo = true;
|
||||
disable_splash_rendering = true;
|
||||
on_focus_under_fullscreen = 2;
|
||||
};
|
||||
|
||||
ecosystem = {
|
||||
no_update_news = true;
|
||||
};
|
||||
|
||||
xwayland = {
|
||||
force_zero_scaling = true;
|
||||
};
|
||||
|
||||
decoration = {
|
||||
blur = {
|
||||
enabled = true;
|
||||
popups = false;
|
||||
};
|
||||
shadow = {
|
||||
enabled = false;
|
||||
};
|
||||
};
|
||||
|
||||
# keep default animations, but speed them all up
|
||||
animations = {
|
||||
animation = [
|
||||
"global, 1, 2, default"
|
||||
];
|
||||
};
|
||||
|
||||
env = [
|
||||
"GDK_SCALE, 2.0"
|
||||
"XCURSOR_SIZE, ${toString cfg.cursorSize}"
|
||||
"HYPRCURSOR_THEME, rose-pine-hyprcursor"
|
||||
"HYPRCURSOR_SIZE, ${toString cfg.cursorSize}"
|
||||
];
|
||||
|
||||
"exec-once" = [
|
||||
"dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP"
|
||||
"hyprctl setcursor Nordzy-cursors ${toString cfg.cursorSize}"
|
||||
"hyprsunset"
|
||||
"nerd-dictation begin --simulate-input-tool WTYPE --suspend-on-start && touch ~/.cache/nerd-dictation-suspended"
|
||||
"noctalia"
|
||||
];
|
||||
|
||||
layerrule = [
|
||||
"blur 1, match:namespace noctalia-wallpaper"
|
||||
"ignore_alpha 0.5, match:namespace noctalia-wallpaper"
|
||||
];
|
||||
workspace = [
|
||||
# no gaps when only window
|
||||
"w[t1], gapsout:0, gapsin:0"
|
||||
"w[tg1], gapsout:0, gapsin:0"
|
||||
"f[1], gapsout:0, gapsin:0"
|
||||
|
||||
"special:terminal, on-created-empty:[float; size 1400 1000; center 1] kitty, persistent:false"
|
||||
"special:yazi, on-created-empty:[float; size ${cfg.yaziSize}; center 1] kitty --session sessions/yazi, persistent:false"
|
||||
];
|
||||
|
||||
windowrule = [
|
||||
# satty
|
||||
"float on, match:class com.gabm.satty"
|
||||
|
||||
# imv
|
||||
"float on, match:class imv"
|
||||
"size 1920 1080, match:class imv"
|
||||
"move (cursor_x-(window_w*0.5)) (cursor_y-(window_h*0.5)), match:class imv"
|
||||
|
||||
# mpv
|
||||
"float on, match:class mpv"
|
||||
"size 1920 1080, match:class mpv"
|
||||
"move (cursor_x-(window_w*0.5)) (cursor_y-(window_h*0.5)), match:class mpv"
|
||||
|
||||
|
||||
# thunar
|
||||
"float on, match:class thunar"
|
||||
"size 1800 1200, match:class thunar"
|
||||
"move (cursor_x-(window_w*0.5)) (cursor_y-(window_h*0.5)), match:class thunar"
|
||||
|
||||
# bluetooth
|
||||
"float on, match:class \\.blueman-manager-wrapped"
|
||||
"size 1200 800, match:class \\.blueman-manager-wrapped"
|
||||
"move (cursor_x-(window_w*0.5)) (cursor_y-(window_h*0.5)), match:class \\.blueman-manager-wrapped"
|
||||
|
||||
# pavucontrol
|
||||
"float on, match:class org\\.pulseaudio\\.pavucontrol"
|
||||
"size 1200 1200, match:class org\\.pulseaudio\\.pavucontrol"
|
||||
"move (cursor_x-(window_w*0.5)) (cursor_y-(window_h*0.5)), match:class org\\.pulseaudio\\.pavucontrol"
|
||||
|
||||
# metamask
|
||||
"float on, match:class chrome-nkbihfbeogaeaoehlefnkodbefgpgknn-.*"
|
||||
|
||||
# bitwarden, chrome
|
||||
"float on, match:class chrome-nngceckbapebfimnlniiiahkandclblb-.*"
|
||||
|
||||
# claude for chrome
|
||||
"float on, match:class chrome-fcoeoabgfenejglbffodgkkbkcdhcgfn-.*"
|
||||
"move (cursor_x-(window_w*0.5)) (cursor_y-(window_h*0.5)), match:class chrome-fcoeoabgfenejglbffodgkkbkcdhcgfn-.*"
|
||||
|
||||
# no gaps when only window
|
||||
"border_size 0, match:float 0, match:workspace w[t1]"
|
||||
"rounding 0, match:float 0, match:workspace w[t1]"
|
||||
"border_size 0, match:float 0, match:workspace w[tg1]"
|
||||
"rounding 0, match:float 0, match:workspace w[tg1]"
|
||||
"border_size 0, match:float 0, match:workspace f[1]"
|
||||
"rounding 0, match:float 0, match:workspace f[1]"
|
||||
|
||||
"center 1, match:workspace special:terminal"
|
||||
"center 1, match:workspace special:yazi"
|
||||
];
|
||||
|
||||
"$mod" = "SUPER";
|
||||
|
||||
bind = [
|
||||
"$mod, n, exec, noctalia msg panel-toggle control-center"
|
||||
"$mod, t, exec, kitty"
|
||||
"$mod, v, togglefloating"
|
||||
"$mod, q, killactive"
|
||||
"$mod, f, fullscreen, 0"
|
||||
"$mod SHIFT, f, fullscreen, 1"
|
||||
|
||||
"$mod, space, exec, noctalia msg panel-toggle launcher"
|
||||
|
||||
# printscreen
|
||||
", Print, exec, hyprshot -m region --raw | satty --filename - --output-filename ~/downloads/screenshots/$(date +%Y-%m-%d_%H-%M-%S).png"
|
||||
"SHIFT, Print, exec, hyprshot -m window --raw | satty --filename - --output-filename ~/downloads/screenshots/$(date +%Y-%m-%d_%H-%M-%S).png"
|
||||
|
||||
# move focus with mod + arrows
|
||||
"$mod, h, movefocus, l"
|
||||
"$mod, j, movefocus, d"
|
||||
"$mod, k, movefocus, u"
|
||||
"$mod, l, movefocus, r"
|
||||
|
||||
# Switch workspaces with mod + [0-9]
|
||||
"$mod, 1, workspace, 1"
|
||||
"$mod, 2, workspace, 2"
|
||||
"$mod, 3, workspace, 3"
|
||||
"$mod, 4, workspace, 4"
|
||||
"$mod, 5, workspace, 5"
|
||||
"$mod, 6, workspace, 6"
|
||||
|
||||
# Move active window to a workspace with mod + SHIFT + [0-9]
|
||||
"$mod SHIFT, 1, movetoworkspace, 1"
|
||||
"$mod SHIFT, 2, movetoworkspace, 2"
|
||||
"$mod SHIFT, 3, movetoworkspace, 3"
|
||||
"$mod SHIFT, 4, movetoworkspace, 4"
|
||||
"$mod SHIFT, 5, movetoworkspace, 5"
|
||||
"$mod SHIFT, 6, movetoworkspace, 6"
|
||||
|
||||
# Move active window inside workspace
|
||||
"$mod SHIFT, h, movewindow, l"
|
||||
"$mod SHIFT, j, movewindow, d"
|
||||
"$mod SHIFT, k, movewindow, u"
|
||||
"$mod SHIFT, l, movewindow, r"
|
||||
|
||||
# Scroll through existing workspaces with mod + scroll
|
||||
"$mod, mouse_down, workspace, e+1"
|
||||
"$mod, mouse_up, workspace, e-1"
|
||||
|
||||
# special workspaces
|
||||
"$mod, x, togglespecialworkspace, terminal"
|
||||
"$mod, x, centerwindow"
|
||||
"$mod, e, togglespecialworkspace, yazi"
|
||||
"$mod, e, centerwindow"
|
||||
];
|
||||
|
||||
bindel = [
|
||||
", XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+"
|
||||
", XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"
|
||||
", XF86MonBrightnessUp, exec, brightnessctl set 5%+"
|
||||
", XF86MonBrightnessDown, exec, brightnessctl set 5%-"
|
||||
];
|
||||
bindl = [
|
||||
", XF86AudioMute, exec, pactl set-sink-mute @DEFAULT_SINK@ toggle"
|
||||
", XF86AudioMicMute, exec, volumectl -m toggle-mute"
|
||||
", XF86AudioNext, exec, playerctl next"
|
||||
", XF86AudioPrev, exec, playerctl previous"
|
||||
", XF86AudioPlay, exec, playerctl play-pause"
|
||||
];
|
||||
|
||||
bindm = [
|
||||
# Move/resize windows with mod + LMB/RMB and dragging
|
||||
"$mod, mouse:272, movewindow"
|
||||
"$mod, mouse:273, resizewindow"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
services.hyprpaper.enable = false;
|
||||
|
||||
services.hypridle = {
|
||||
enable = true;
|
||||
settings = {
|
||||
general = {
|
||||
after_sleep_cmd = "hyprctl dispatch dpms on";
|
||||
ignore_dbus_inhibit = false;
|
||||
lock_cmd = "noctalia msg session lock";
|
||||
};
|
||||
listener = [
|
||||
{
|
||||
timeout = 900;
|
||||
on-timeout = "noctalia msg session lock";
|
||||
}
|
||||
{
|
||||
timeout = 1200;
|
||||
on-timeout = "hyprctl dispatch dpms off";
|
||||
on-resume = "hyprctl dispatch dpms on";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
home.packages = with pkgs; [ libnotify ];
|
||||
|
||||
services.dunst = {
|
||||
enable = true;
|
||||
};
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
{
|
||||
inputs,
|
||||
...
|
||||
}:
|
||||
|
||||
{
|
||||
imports = [ inputs.hyprpanel.homeManagerModules.hyprpanel ];
|
||||
|
||||
programs.hyprpanel = {
|
||||
enable = true;
|
||||
overlay.enable = true;
|
||||
systemd.enable = true;
|
||||
overwrite.enable = true;
|
||||
|
||||
layout = {
|
||||
bar = {
|
||||
layouts = {
|
||||
"1" = {
|
||||
"left" = [
|
||||
"dashboard"
|
||||
"workspaces"
|
||||
"windowtitle"
|
||||
];
|
||||
"middle" = [ "media" ];
|
||||
"right" = [
|
||||
"volume"
|
||||
"network"
|
||||
"bluetooth"
|
||||
"systray"
|
||||
"clock"
|
||||
"notifications"
|
||||
];
|
||||
};
|
||||
"0" = {
|
||||
"left" = [ ];
|
||||
"middle" = [ ];
|
||||
"right" = [ ];
|
||||
};
|
||||
"2" = {
|
||||
"left" = [ ];
|
||||
"middle" = [ ];
|
||||
"right" = [ ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
settings = {
|
||||
theme.bar.transparent = true;
|
||||
theme.font = {
|
||||
name = "Fira Code Nerd Font";
|
||||
size = "14px";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
inputs,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
avatar = pkgs.fetchurl {
|
||||
url = "https://github.com/naps62.png";
|
||||
sha256 = "1ck11xg4rwcvn8dcc06ax7i9yfzy21v1n6h5mcjrkrici5sznlsv";
|
||||
};
|
||||
in
|
||||
{
|
||||
imports = [ inputs.noctalia.homeModules.default ];
|
||||
|
||||
# Noctalia v5 rewrote the config schema (TOML, snake_case, flat sections).
|
||||
# The v4 settings (appLauncher.*, bar.widgets.*, controlCenter.shortcuts.*, etc.)
|
||||
# have no v5 equivalents — most must now be tweaked through the in-shell
|
||||
# Settings UI. See docs.noctalia.dev/v5 and example.toml in the upstream repo.
|
||||
programs.noctalia = {
|
||||
enable = true;
|
||||
settings = {
|
||||
shell = {
|
||||
font_family = "Sans Serif";
|
||||
avatar_path = "${config.home.homeDirectory}/.face";
|
||||
telemetry_enabled = false;
|
||||
polkit_agent = true;
|
||||
};
|
||||
|
||||
wallpaper = {
|
||||
enabled = true;
|
||||
fill_mode = "crop";
|
||||
directory = "${config.home.homeDirectory}/.cache/wallpapers/3840x2160";
|
||||
transition = [ "fade" ];
|
||||
transition_duration = 1500;
|
||||
automation = {
|
||||
enabled = true;
|
||||
interval_minutes = 360;
|
||||
order = "random";
|
||||
recursive = true;
|
||||
};
|
||||
};
|
||||
|
||||
theme = {
|
||||
mode = "dark";
|
||||
source = "builtin";
|
||||
builtin = "Nord";
|
||||
templates = {
|
||||
enable_builtin_templates = true;
|
||||
builtin_ids = [
|
||||
"btop"
|
||||
"gtk3"
|
||||
"gtk4"
|
||||
"hyprland"
|
||||
"qt"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
notification.enable_daemon = true;
|
||||
|
||||
weather = {
|
||||
enabled = true;
|
||||
unit = "celsius";
|
||||
};
|
||||
|
||||
location = {
|
||||
auto_locate = false;
|
||||
address = "Braga, Portugal";
|
||||
};
|
||||
|
||||
nightlight = {
|
||||
enabled = true;
|
||||
temperature_day = 6500;
|
||||
temperature_night = 4000;
|
||||
};
|
||||
|
||||
bar.main = {
|
||||
position = "top";
|
||||
background_opacity = 0.93;
|
||||
radius = 12;
|
||||
start = [ "launcher" "wallpaper" "workspaces" ];
|
||||
center = [ "media" "clock" ];
|
||||
end = [ "tray" "notifications" "network" "bluetooth" "volume" "brightness" "battery" "control-center" "session" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
home.file.".face".source = avatar;
|
||||
|
||||
# force overwrite files that noctalia may have turned into regular files
|
||||
xdg.configFile."hypr/hyprland.conf".force = true;
|
||||
xdg.configFile."gtk-3.0/gtk.css".force = true;
|
||||
|
||||
# source noctalia-generated color theme in hyprland (v5 path).
|
||||
# Hyprland globs every source path, so a missing file errors as
|
||||
# "globbing error: found no match" — pre-create an empty placeholder
|
||||
# so the first boot doesn't fail before noctalia has run.
|
||||
home.activation.ensureNoctaliaHyprConf = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||
run mkdir -p "$HOME/.config/hypr"
|
||||
run touch "$HOME/.config/hypr/noctalia.conf"
|
||||
'';
|
||||
|
||||
wayland.windowManager.hyprland.settings.source = [
|
||||
"~/.config/hypr/noctalia.conf"
|
||||
];
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
rofi-wayland
|
||||
(callPackage ../../../../pkgs/rofi-launchers/package.nix { })
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
# Horizontal wallpapers (3840x2160) for HDMI-A-1 and DP-1
|
||||
# Just add any image URL you want here
|
||||
horizontal = [
|
||||
"https://images.hdqwalls.com/download/black-red-square-rectangle-rq-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/metals-shapes-abstract-8k-8c-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/vertical-lines-colorful-abstract-5k-hu-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/cyberpunk-drive-neon-metropolis-if-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/horizon-zero-dawn-abstract-m2-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/pcb-circuit-board-abstract-x3-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/upcoming-stars-6h-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/abstract-colors-glitter-4k-8m-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/rainbow-spectrum-4k-h2-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/time-lapse-photography-tf-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/women-bokeh-rain-7q-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/fire-bokeh-5k-vm-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/train-track-ocean-beach-mountain-photography-5k-mh-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/bullet-train-motion-view-from-inside-ld-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/long-exposure-photo-of-a-highway-gf-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/hohenschwangau-castle-in-germany-5k-tb-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/girl-watching-glowing-metropolis-tg-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/cosmic-storm-over-alien-metropolis-dl-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/win-11-abstract-5k-7o-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/windows-11-5k-zz-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/localhost-lab-where-ideas-take-shape-ij-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/ipad-os18-purple-dark-jf-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/linux-nixos-7q-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/macbook-pro-m2-js-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/0101-dw-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/apple-studio-display-wwdc-qg-3840x2160.jpg"
|
||||
"https://images.hdqwalls.com/download/starfield-i-mac-ie-3840x2160.jpg"
|
||||
];
|
||||
|
||||
# Vertical wallpapers (2160x3840) for DP-2
|
||||
# Same images in vertical resolution
|
||||
vertical = [
|
||||
"https://images.hdqwalls.com/download/black-red-square-rectangle-rq-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/metals-shapes-abstract-8k-8c-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/vertical-lines-colorful-abstract-5k-hu-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/cyberpunk-drive-neon-metropolis-if-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/horizon-zero-dawn-abstract-m2-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/pcb-circuit-board-abstract-x3-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/upcoming-stars-6h-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/abstract-colors-glitter-4k-8m-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/rainbow-spectrum-4k-h2-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/time-lapse-photography-tf-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/women-bokeh-rain-7q-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/fire-bokeh-5k-vm-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/train-track-ocean-beach-mountain-photography-5k-mh-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/bullet-train-motion-view-from-inside-ld-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/long-exposure-photo-of-a-highway-gf-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/hohenschwangau-castle-in-germany-5k-tb-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/girl-watching-glowing-metropolis-tg-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/cosmic-storm-over-alien-metropolis-dl-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/win-11-abstract-5k-7o-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/windows-11-5k-zz-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/localhost-lab-where-ideas-take-shape-ij-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/ipad-os18-purple-dark-jf-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/linux-nixos-7q-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/macbook-pro-m2-js-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/0101-dw-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/apple-studio-display-wwdc-qg-2160x3840.jpg"
|
||||
"https://images.hdqwalls.com/download/starfield-i-mac-ie-2160x3840.jpg"
|
||||
];
|
||||
|
||||
# Wallpaper fetch script - downloads wallpapers to cache
|
||||
fetchScript = pkgs.writeShellScript "wallpaper-fetch" ''
|
||||
set -euo pipefail
|
||||
|
||||
HORIZONTAL_DIR="$HOME/.cache/wallpapers/3840x2160"
|
||||
VERTICAL_DIR="$HOME/.cache/wallpapers/2160x3840"
|
||||
mkdir -p "$HORIZONTAL_DIR" "$VERTICAL_DIR"
|
||||
|
||||
HORIZONTAL=(${builtins.concatStringsSep " " (map (url: ''"${url}"'') horizontal)})
|
||||
VERTICAL=(${builtins.concatStringsSep " " (map (url: ''"${url}"'') vertical)})
|
||||
|
||||
download() {
|
||||
local url="$1"
|
||||
local dir="$2"
|
||||
local filename=$(basename "$url")
|
||||
local filepath="$dir/$filename"
|
||||
|
||||
if [ ! -f "$filepath" ]; then
|
||||
echo "Downloading $filename..." >&2
|
||||
${pkgs.curl}/bin/curl -sSL -o "$filepath" "$url" || {
|
||||
echo "Failed to download $url" >&2
|
||||
return 1
|
||||
}
|
||||
fi
|
||||
}
|
||||
|
||||
echo "Fetching horizontal wallpapers..."
|
||||
for url in "''${HORIZONTAL[@]}"; do
|
||||
download "$url" "$HORIZONTAL_DIR"
|
||||
done
|
||||
|
||||
echo "Fetching vertical wallpapers..."
|
||||
for url in "''${VERTICAL[@]}"; do
|
||||
download "$url" "$VERTICAL_DIR"
|
||||
done
|
||||
|
||||
echo "Done. Wallpapers cached in:"
|
||||
echo " Horizontal: $HORIZONTAL_DIR"
|
||||
echo " Vertical: $VERTICAL_DIR"
|
||||
'';
|
||||
in
|
||||
{
|
||||
home.file.".local/bin/wallpaper-fetch".source = fetchScript;
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
programs.kitty = {
|
||||
enable = true;
|
||||
settings = {
|
||||
confirm_os_window_close = 0;
|
||||
enable_audio_bell = false;
|
||||
cursor_trail = 1;
|
||||
|
||||
enabled_layouts = "tall, grid, fat, splits";
|
||||
|
||||
# font
|
||||
font_family = "FiraCode Nerd Font Mono";
|
||||
bold_font = "FiraCode Nerd Font Mono Bold";
|
||||
italic_font = "VictorMono Nerd Font Mono Oblique";
|
||||
bold_italic_font = "VictorMono Nerd Font Mono Bold Oblique";
|
||||
disable_ligatures = "cursor";
|
||||
|
||||
# tab-style
|
||||
tab_bar_edge = "bottom";
|
||||
tab_bar_style = "powerline";
|
||||
tab_powerline_style = "slanted";
|
||||
tab_title_template = "{title}{' :{}'.format(num_windows) if num_windows > 1 else ''}";
|
||||
|
||||
# keys
|
||||
kitty_mod = "alt";
|
||||
};
|
||||
|
||||
keybindings = {
|
||||
"kitty_mod+t" = "new_tab_with_cwd";
|
||||
"kitty_mod+enter" = "new_window_with_cwd";
|
||||
"kitty_mod+r" = "set_tab_title";
|
||||
|
||||
"kitty_mod+u" = "previous_tab";
|
||||
"kitty_mod+i" = "next_tab";
|
||||
|
||||
"ctrl+shift+l" = "next_layout";
|
||||
"ctrl+shift+left" = "resize_window narrower";
|
||||
"ctrl+shift+right" = "resize_window right";
|
||||
|
||||
"ctrl+shift+0x27" = "change_font_size all +2.0";
|
||||
"ctrl+shift+minus" = "change_font_size all -2.0";
|
||||
"ctrl+shift+backspace" = "change_font_size all 0";
|
||||
|
||||
"kitty_mod+h" = "neighboring_window left";
|
||||
"kitty_mod+j" = "neighboring_window down";
|
||||
"kitty_mod+k" = "neighboring_window up";
|
||||
"kitty_mod+l" = "neighboring_window right";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
clip2path = pkgs.writeShellScript "clip2path" ''
|
||||
set -e
|
||||
|
||||
if [ -n "$WAYLAND_DISPLAY" ]; then
|
||||
types=$(wl-paste --list-types)
|
||||
if grep -q '^image/' <<<"$types"; then
|
||||
ext=$(grep -m1 '^image/' <<<"$types" | cut -d/ -f2 | cut -d';' -f1)
|
||||
file="/tmp/clip_$(date +%s).''${ext}"
|
||||
wl-paste --type "image/''${ext}" > "$file"
|
||||
printf '%q' "$file" | kitty @ send-text --stdin
|
||||
else
|
||||
wl-paste --no-newline | kitty @ send-text --stdin
|
||||
fi
|
||||
elif [ -n "$DISPLAY" ]; then
|
||||
types=$(xclip -selection clipboard -t TARGETS -o)
|
||||
if grep -q '^image/' <<<"$types"; then
|
||||
ext=$(grep -m1 '^image/' <<<"$types" | cut -d/ -f2 | cut -d';' -f1)
|
||||
file="/tmp/clip_$(date +%s).''${ext}"
|
||||
xclip -selection clipboard -t "image/''${ext}" -o > "$file"
|
||||
printf '%q' "$file" | kitty @ send-text --stdin
|
||||
else
|
||||
xclip -selection clipboard -o | kitty @ send-text --stdin
|
||||
fi
|
||||
fi
|
||||
'';
|
||||
|
||||
scrollbackPager = pkgs.writeShellScript "kitty-scrollback" ''
|
||||
f=$(mktemp)
|
||||
cat | perl -0777 -pe 's/\x1b(?:\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]|\][^\x07\x1b]*(?:\x07|\x1b\\)|.)//g; s/\s+\z/\n/' > "$f"
|
||||
nvim + -c "set ft=sh noma" "$f"
|
||||
rm "$f"
|
||||
'';
|
||||
in
|
||||
{
|
||||
programs.kitty = {
|
||||
enable = true;
|
||||
# Fixed theme — noctalia no longer toggles kitty with dark/light mode.
|
||||
themeFile = "Catppuccin-Mocha";
|
||||
settings = {
|
||||
confirm_os_window_close = 0;
|
||||
cursor_trail = 1;
|
||||
copy_on_select = true;
|
||||
|
||||
enabled_layouts = "tall, grid, fat, splits, stack";
|
||||
|
||||
# font
|
||||
font_family = "FiraCode Nerd Font Mono";
|
||||
bold_font = "FiraCode Nerd Font Mono Bold";
|
||||
italic_font = "VictorMono Nerd Font Mono Oblique";
|
||||
bold_italic_font = "VictorMono Nerd Font Mono Bold Oblique";
|
||||
disable_ligatures = "cursor";
|
||||
|
||||
# tab-style
|
||||
tab_bar_edge = "bottom";
|
||||
tab_bar_style = "powerline";
|
||||
tab_powerline_style = "slanted";
|
||||
tab_bar_filter = "session:~ or session:^$";
|
||||
|
||||
# keys
|
||||
kitty_mod = "alt";
|
||||
|
||||
# remove control
|
||||
allow_remote_control = true;
|
||||
listen_on = "unix:/tmp/kitty.sock";
|
||||
|
||||
scrollback_pager = "${scrollbackPager}";
|
||||
|
||||
enable_audio_bell = false;
|
||||
bell_on_tab = true;
|
||||
};
|
||||
|
||||
keybindings = {
|
||||
"kitty_mod+t" = "new_tab_with_cwd";
|
||||
"kitty_mod+enter" = "new_window_with_cwd";
|
||||
"kitty_mod+v" = "combine : goto_layout splits : launch --cwd=current --location=vsplit";
|
||||
"kitty_mod+s" = "combine : goto_layout splits : launch --cwd=current --location=hsplit";
|
||||
"kitty_mod+r" = "set_tab_title";
|
||||
|
||||
"kitty_mod+u" = "previous_tab";
|
||||
"kitty_mod+i" = "next_tab";
|
||||
|
||||
"ctrl+shift+c" = "copy_to_clipboard";
|
||||
"ctrl+shift+v" = "launch --type=background --allow-remote-control --keep-focus ${clip2path}";
|
||||
|
||||
"ctrl+shift+l" = "next_layout";
|
||||
"ctrl+shift+left" = "resize_window narrower";
|
||||
"ctrl+shift+right" = "resize_window right";
|
||||
"kitty_mod+space" = "toggle_layout stack";
|
||||
|
||||
"ctrl+shift+0x27" = "change_font_size all +2.0";
|
||||
"ctrl+shift+minus" = "change_font_size all -2.0";
|
||||
"ctrl+shift+backspace" = "change_font_size all 0";
|
||||
|
||||
"kitty_mod+h" = "neighboring_window left";
|
||||
"kitty_mod+shift+h" = "show_scrollback";
|
||||
"kitty_mod+j" = "neighboring_window down";
|
||||
"kitty_mod+k" = "neighboring_window up";
|
||||
"kitty_mod+l" = "neighboring_window right";
|
||||
|
||||
"f7>/" = "goto_session";
|
||||
};
|
||||
|
||||
extraConfig = ''
|
||||
cursor_shape block
|
||||
'';
|
||||
};
|
||||
|
||||
xdg.configFile."kitty/sessions".source = ./sessions;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
launch yazi
|
||||
@@ -5,10 +5,9 @@
|
||||
EDITOR = "nvim";
|
||||
};
|
||||
home.packages = with pkgs; [
|
||||
nixfmt-rfc-style
|
||||
nixfmt
|
||||
biome
|
||||
stylua
|
||||
neovide
|
||||
];
|
||||
|
||||
programs.nvchad = {
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
{
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
venvDir = "$HOME/.local/share/nerd-dictation/venv";
|
||||
|
||||
# Create an FHS environment where vosk can be pip-installed
|
||||
nerd-dictation-env = pkgs.buildFHSEnv {
|
||||
name = "nerd-dictation-fhs";
|
||||
targetPkgs = pkgs: with pkgs; [
|
||||
# Python and pip for vosk
|
||||
python3
|
||||
python3Packages.pip
|
||||
python3Packages.virtualenv
|
||||
|
||||
# Audio recording (pipewire)
|
||||
pipewire
|
||||
pulseaudio # for parec
|
||||
|
||||
# Input simulation (wayland-compatible)
|
||||
ydotool
|
||||
wtype
|
||||
xdotool
|
||||
|
||||
# Manylinux compatibility
|
||||
pythonManylinuxPackages.manylinux2014Package
|
||||
];
|
||||
runScript = "bash";
|
||||
};
|
||||
|
||||
# Fetch nerd-dictation from GitHub
|
||||
nerd-dictation-src = pkgs.fetchFromGitHub {
|
||||
owner = "ideasman42";
|
||||
repo = "nerd-dictation";
|
||||
rev = "main";
|
||||
hash = "sha256-xjaHrlJvk8bNvWp1VE4EAHi2VJlAutBxUgWB++3Qo+s=";
|
||||
};
|
||||
|
||||
modelUrl = "https://alphacephei.com/vosk/models/vosk-model-en-us-0.22-lgraph.zip";
|
||||
modelName = "vosk-model-en-us-0.22-lgraph";
|
||||
modelDir = "$HOME/.config/nerd-dictation";
|
||||
|
||||
# Wrapper script that handles setup and runs nerd-dictation
|
||||
nerd-dictation = pkgs.writeShellScriptBin "nerd-dictation" ''
|
||||
set -e
|
||||
VENV="${venvDir}"
|
||||
MODEL_DIR="${modelDir}"
|
||||
|
||||
# Setup venv if needed
|
||||
if [ ! -d "$VENV" ]; then
|
||||
echo "[nerd-dictation] Setting up Python venv and installing vosk..."
|
||||
${nerd-dictation-env}/bin/nerd-dictation-fhs -c "
|
||||
set -e
|
||||
mkdir -p \$(dirname ${venvDir})
|
||||
python3 -m venv ${venvDir}
|
||||
source ${venvDir}/bin/activate
|
||||
pip install --upgrade pip -q
|
||||
pip install vosk -q
|
||||
"
|
||||
echo "[nerd-dictation] Venv ready."
|
||||
fi
|
||||
|
||||
# Download model if needed
|
||||
if [ ! -d "$MODEL_DIR/model" ]; then
|
||||
echo "[nerd-dictation] Downloading VOSK model (${modelName})..."
|
||||
mkdir -p "$MODEL_DIR"
|
||||
cd "$MODEL_DIR"
|
||||
${pkgs.curl}/bin/curl -L --progress-bar -o "${modelName}.zip" "${modelUrl}"
|
||||
echo "[nerd-dictation] Extracting model..."
|
||||
${pkgs.unzip}/bin/unzip -q "${modelName}.zip"
|
||||
mv "${modelName}" model
|
||||
rm "${modelName}.zip"
|
||||
echo "[nerd-dictation] Model ready."
|
||||
fi
|
||||
|
||||
exec ${nerd-dictation-env}/bin/nerd-dictation-fhs -c "source $VENV/bin/activate && python3 ${nerd-dictation-src}/nerd-dictation $*"
|
||||
'';
|
||||
|
||||
# Toggle script for hyprland keybind
|
||||
nerd-dictation-toggle = pkgs.writeShellScriptBin "nerd-dictation-toggle" ''
|
||||
hyprctl() {
|
||||
env -u LD_LIBRARY_PATH ${pkgs.hyprland}/bin/hyprctl "$@"
|
||||
}
|
||||
|
||||
set_border() {
|
||||
local size=$1
|
||||
local color=$2
|
||||
# Unset existing rules for single-window workspaces
|
||||
hyprctl keyword windowrule "unset, match:float 0, match:workspace w[t1]"
|
||||
hyprctl keyword windowrule "unset, match:float 0, match:workspace w[tg1]"
|
||||
hyprctl keyword windowrule "unset, match:float 0, match:workspace f[1]"
|
||||
hyprctl keyword windowrule "unset, match:fullscreen 1"
|
||||
# Re-add with specified border size
|
||||
hyprctl keyword windowrule "border_size $size, match:float 0, match:workspace w[t1]"
|
||||
hyprctl keyword windowrule "rounding 0, match:float 0, match:workspace w[t1]"
|
||||
hyprctl keyword windowrule "border_size $size, match:float 0, match:workspace w[tg1]"
|
||||
hyprctl keyword windowrule "rounding 0, match:float 0, match:workspace w[tg1]"
|
||||
hyprctl keyword windowrule "border_size $size, match:float 0, match:workspace f[1]"
|
||||
hyprctl keyword windowrule "rounding 0, match:float 0, match:workspace f[1]"
|
||||
hyprctl keyword windowrule "border_size $size, match:fullscreen 1"
|
||||
# Set border color
|
||||
hyprctl keyword general:col.active_border "$color"
|
||||
}
|
||||
|
||||
# Check if currently suspended (file exists when suspended)
|
||||
if [ -f "$HOME/.cache/nerd-dictation-suspended" ]; then
|
||||
nerd-dictation resume
|
||||
rm -f "$HOME/.cache/nerd-dictation-suspended"
|
||||
set_border 5 "rgb(ff0000)"
|
||||
else
|
||||
nerd-dictation suspend
|
||||
touch "$HOME/.cache/nerd-dictation-suspended"
|
||||
set_border 0 "0x99999999"
|
||||
fi
|
||||
'';
|
||||
in
|
||||
{
|
||||
home.packages = [
|
||||
nerd-dictation
|
||||
nerd-dictation-toggle
|
||||
pkgs.ydotool
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{ pkgs, inputs, ... }:
|
||||
{
|
||||
imports = [
|
||||
# Prebuilt, weekly-updated nix-index database (backs `comma`).
|
||||
inputs.nix-index-database.homeModules.nix-index
|
||||
];
|
||||
|
||||
# `comma` (`,`) — run any nixpkgs program once without installing it.
|
||||
programs.nix-index.enable = true;
|
||||
programs.nix-index-database.comma.enable = true;
|
||||
|
||||
home.packages = with pkgs; [
|
||||
nvd # version diff between generations (used by nh)
|
||||
nix-output-monitor # readable build output (nom; used by nh)
|
||||
statix # nix linter / antipattern finder
|
||||
deadnix # finds unused nix bindings
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
typescript-language-server
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Screenshots: stored in ~/downloads/screenshots, with date time in the filename
|
||||
@@ -0,0 +1,127 @@
|
||||
---
|
||||
description: Fast branch analysis (optimized single agent)
|
||||
model: anthropic/claude-sonnet-4-5
|
||||
mode: subagent
|
||||
temperature: 0.1
|
||||
tools:
|
||||
bash: true
|
||||
task: false
|
||||
edit: false
|
||||
write: true
|
||||
webfetch: false
|
||||
permission:
|
||||
edit: allow
|
||||
webfetch: deny
|
||||
bash:
|
||||
"git add*": deny
|
||||
"git commit*": deny
|
||||
"git push*": deny
|
||||
"git checkout*": deny
|
||||
"git reset*": deny
|
||||
"git rebase*": deny
|
||||
"git merge*": deny
|
||||
"*": allow
|
||||
---
|
||||
|
||||
# Optimized Analyze-Branch Agent
|
||||
|
||||
You are the **fast and comprehensive** branch analysis agent. Perform all analyses inline (no sub-agents) with visual progress tracking.
|
||||
|
||||
## Objective
|
||||
|
||||
Analyze a branch relative to the base branch and generate a detailed report in `reports/` focusing on:
|
||||
- Critical bugs (null safety, SQL injection, type errors)
|
||||
- N+1 queries and performance issues
|
||||
- Security vulnerabilities
|
||||
- Breaking changes (caller analysis)
|
||||
- Database migration risks
|
||||
- Architecture (SOLID/DRY)
|
||||
|
||||
This invocation serves as explicit approval to:
|
||||
- Create the `reports/` directory if missing.
|
||||
- Create/overwrite ONE report file in that directory.
|
||||
|
||||
**DO NOT ask for further confirmation.**
|
||||
|
||||
---
|
||||
|
||||
## Constraints (CRITICAL)
|
||||
|
||||
- DO NOT execute commands that modify the repository or history.
|
||||
- DO NOT execute commands that modify dependencies or runtime state.
|
||||
- The only allowed write operation is the report file in `reports/`.
|
||||
|
||||
---
|
||||
|
||||
## Input
|
||||
|
||||
You may receive a branch/ref as an argument. If absent or empty, use the **current branch**.
|
||||
|
||||
---
|
||||
|
||||
## Procedure
|
||||
|
||||
### Step 1: Git Context
|
||||
|
||||
```bash
|
||||
# Get branch info
|
||||
CURRENT=$(git branch --show-current)
|
||||
BASE=$(git merge-base HEAD main 2>/dev/null || git merge-base HEAD master 2>/dev/null)
|
||||
|
||||
# Get changed files
|
||||
git diff --name-only $BASE..HEAD
|
||||
git diff --stat $BASE..HEAD
|
||||
```
|
||||
|
||||
### Step 2: Analyze Changed Files
|
||||
|
||||
For each changed file:
|
||||
1. Read the full diff: `git diff $BASE..HEAD -- <file>`
|
||||
2. Read surrounding context in the file
|
||||
3. Check for issues listed in the objective
|
||||
|
||||
### Step 3: Cross-Reference
|
||||
|
||||
- Check callers of modified functions (grep for function names across codebase)
|
||||
- Check if modified database queries have proper indexes
|
||||
- Check if new endpoints have authentication/authorization
|
||||
- Check if error handling covers new failure modes
|
||||
|
||||
### Step 4: Generate Report
|
||||
|
||||
Write report to `reports/branch-analysis-<branch-name>.md`:
|
||||
|
||||
```markdown
|
||||
# Branch Analysis: <branch-name>
|
||||
|
||||
**Date**: <date>
|
||||
**Base**: <base-branch>
|
||||
**Files Changed**: <count>
|
||||
**Risk Score**: <LOW|MEDIUM|HIGH|CRITICAL>
|
||||
|
||||
## Summary
|
||||
<1-3 sentence overview>
|
||||
|
||||
## Critical Findings
|
||||
### <Finding Title>
|
||||
- **Severity**: CRITICAL|HIGH|MEDIUM|LOW
|
||||
- **File**: path/to/file:line
|
||||
- **Issue**: Description
|
||||
- **Suggestion**: How to fix
|
||||
|
||||
## Performance
|
||||
<N+1 queries, missing indexes, expensive operations>
|
||||
|
||||
## Security
|
||||
<Auth gaps, injection risks, data exposure>
|
||||
|
||||
## Breaking Changes
|
||||
<API changes, schema changes, removed exports>
|
||||
|
||||
## Architecture
|
||||
<SOLID violations, DRY issues, complexity>
|
||||
```
|
||||
|
||||
### Step 5: Summary
|
||||
|
||||
Print the risk score and top 3 findings to stdout after writing the report.
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
description: Opinionated UI/UX specialist for distinctive, visually striking interfaces. Anti-generic-AI aesthetics. Bold typography, asymmetric layouts, intentional color.
|
||||
model: anthropic/claude-opus-4-6
|
||||
mode: all
|
||||
temperature: 0.7
|
||||
---
|
||||
|
||||
You are Designer Bold - a frontend UI/UX specialist who creates intentional, polished, DISTINCTIVE experiences.
|
||||
|
||||
**Role**: Craft cohesive UI/UX that balances visual impact with usability. Every interface should be memorable and deliberately designed for its context.
|
||||
|
||||
## Design Principles
|
||||
|
||||
**Typography**
|
||||
- Choose distinctive, characterful fonts that elevate aesthetics
|
||||
- Avoid generic defaults (Arial, Inter, Roboto, system fonts) -- opt for unexpected, beautiful choices
|
||||
- Pair a display font with a refined body font for hierarchy
|
||||
- Never converge on common AI choices (Space Grotesk) across designs
|
||||
|
||||
**Color & Theme**
|
||||
- Commit to a cohesive aesthetic with clear color variables
|
||||
- Dominant colors with sharp accents > timid, evenly-distributed palettes
|
||||
- Create atmosphere through intentional color relationships
|
||||
- Vary between light and dark themes -- no design should look the same
|
||||
|
||||
**Motion & Interaction**
|
||||
- Leverage framework animation utilities when available (Tailwind's transition/animation classes)
|
||||
- Focus on high-impact moments: orchestrated page loads with staggered reveals
|
||||
- Use scroll-triggers and hover states that surprise and delight
|
||||
- One well-timed animation > scattered micro-interactions
|
||||
- Drop to custom CSS/JS only when utilities can't achieve the vision
|
||||
|
||||
**Spatial Composition**
|
||||
- Break conventions: asymmetry, overlap, diagonal flow, grid-breaking
|
||||
- Generous negative space OR controlled density -- commit to the choice
|
||||
- Unexpected layouts that guide the eye
|
||||
|
||||
**Visual Depth**
|
||||
- Create atmosphere beyond solid colors: gradient meshes, noise textures, geometric patterns
|
||||
- Layer transparencies, dramatic shadows, decorative borders
|
||||
- Contextual effects that match the aesthetic (grain overlays, custom cursors)
|
||||
|
||||
**Styling Approach**
|
||||
- Default to Tailwind CSS utility classes when available -- fast, maintainable, consistent
|
||||
- Use custom CSS when the vision requires it: complex animations, unique effects, advanced compositions
|
||||
- Balance utility-first speed with creative freedom where it matters
|
||||
|
||||
**Match Vision to Execution**
|
||||
- Maximalist designs -> elaborate implementation, extensive animations, rich effects
|
||||
- Minimalist designs -> restraint, precision, careful spacing and typography
|
||||
- Elegance comes from executing the chosen vision fully, not halfway
|
||||
|
||||
## Design Thinking
|
||||
|
||||
Before coding, understand the context and commit to a BOLD aesthetic direction:
|
||||
- **Purpose**: What problem does this interface solve? Who uses it?
|
||||
- **Tone**: Pick an extreme: brutally minimal, maximalist chaos, retro-futuristic, organic/natural, luxury/refined, playful/toy-like, editorial/magazine, brutalist/raw, art deco/geometric, soft/pastel, industrial/utilitarian
|
||||
- **Constraints**: Technical requirements (framework, performance, accessibility)
|
||||
- **Differentiation**: What makes this UNFORGETTABLE? What's the one thing someone will remember?
|
||||
|
||||
## Constraints
|
||||
- Respect existing design systems when present
|
||||
- Leverage component libraries where available
|
||||
- Prioritize visual excellence -- code perfection comes second
|
||||
|
||||
## Skills
|
||||
- When implementing React components, invoke the `react-patterns` skill for code examples of composition, compound components, hooks, and accessibility patterns.
|
||||
- When optimizing performance, invoke the `vercel-react-best-practices` skill for Vercel's 45 prioritized performance rules.
|
||||
|
||||
You are capable of extraordinary creative work. Commit fully to distinctive visions and show what's possible when breaking conventions thoughtfully.
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
description: Conventional frontend specialist. React 18+, Tailwind CSS, TypeScript, accessibility (WCAG 2.1 AA), responsive design, performance optimization.
|
||||
model: anthropic/claude-sonnet-4-5
|
||||
mode: all
|
||||
temperature: 0.2
|
||||
---
|
||||
|
||||
You are Designer - a frontend specialist focused on building production-grade, accessible, performant interfaces.
|
||||
|
||||
## Core Stack
|
||||
|
||||
- **React 18+**: Server Components, Suspense, useTransition, useDeferredValue
|
||||
- **TypeScript**: Strict mode, no implicit any, explicit return types on exports
|
||||
- **Tailwind CSS**: Utility-first, design tokens via CSS variables, responsive with mobile-first breakpoints
|
||||
- **Accessibility**: WCAG 2.1 AA compliance from the start, not bolted on after
|
||||
|
||||
## Component Architecture
|
||||
|
||||
- **Composition over inheritance**: Build from small, focused components
|
||||
- **Compound components**: Use Context for implicit state sharing (Tabs, Accordion, Menu)
|
||||
- **Error boundaries**: Wrap critical UI sections with fallback UIs
|
||||
- **Single responsibility**: Each component does one thing well
|
||||
- **Props**: Use TypeScript interfaces, prefer explicit props over spreading
|
||||
|
||||
## Accessibility
|
||||
|
||||
- Semantic HTML first (button, nav, main, article, aside, header, footer)
|
||||
- Keyboard navigation for all interactive elements
|
||||
- Focus management for modals, dialogs, and dynamic content
|
||||
- ARIA attributes only when semantic HTML is insufficient
|
||||
- Color contrast: minimum 4.5:1 for normal text, 3:1 for large text
|
||||
- Touch targets: minimum 44x44px on mobile
|
||||
- Screen reader testing considerations in component design
|
||||
|
||||
## Performance Targets
|
||||
|
||||
- Largest Contentful Paint (LCP): < 2.5s
|
||||
- First Input Delay (FID): < 100ms
|
||||
- Cumulative Layout Shift (CLS): < 0.1
|
||||
- Bundle size awareness: code split at route boundaries, lazy load below-the-fold
|
||||
|
||||
## Performance Patterns
|
||||
|
||||
- `React.memo` for expensive pure components
|
||||
- `useMemo` for expensive calculations, `useCallback` for stable references passed to children
|
||||
- Code splitting with `React.lazy` and `Suspense` at route and feature boundaries
|
||||
- Virtualization for long lists (@tanstack/react-virtual)
|
||||
- Image optimization: lazy loading, proper dimensions, modern formats (WebP/AVIF)
|
||||
- Eliminate render waterfalls: parallel data fetching, avoid sequential awaits
|
||||
|
||||
## Styling Approach
|
||||
|
||||
- Tailwind utility classes as default
|
||||
- CSS variables for theme tokens (colors, spacing, typography scale)
|
||||
- Responsive: mobile-first with sm/md/lg/xl breakpoints
|
||||
- Dark mode via Tailwind's `dark:` variant with system preference detection
|
||||
- Animation: CSS transitions for simple effects, Framer Motion for complex orchestration
|
||||
- Consistent spacing scale, consistent border-radius, consistent shadow levels
|
||||
|
||||
## State Management
|
||||
|
||||
- Local state (`useState`) for component-scoped state
|
||||
- Context + `useReducer` for shared state within a feature
|
||||
- URL state for anything that should be shareable/bookmarkable
|
||||
- Server state via React Query / SWR / Server Components
|
||||
- Avoid prop drilling beyond 2 levels -- lift to Context or compose differently
|
||||
|
||||
## TypeScript Conventions
|
||||
|
||||
- PascalCase for components, interfaces, types
|
||||
- camelCase for functions, variables, hooks
|
||||
- Props interfaces named `ComponentNameProps`
|
||||
- Prefer `interface` for component props, `type` for unions/intersections
|
||||
- No `any` -- use `unknown` and narrow with type guards
|
||||
|
||||
## Testing Considerations
|
||||
|
||||
- Components should be testable with React Testing Library
|
||||
- Test behavior, not implementation details
|
||||
- Accessible queries first: getByRole, getByLabelText, getByText
|
||||
|
||||
## Skills
|
||||
|
||||
- When implementing React components, invoke the `react-patterns` skill for code examples of composition, compound components, hooks, and accessibility patterns.
|
||||
- When optimizing performance, invoke the `vercel-react-best-practices` skill for Vercel's 45 prioritized performance rules across 8 categories.
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
description: Fast codebase navigation specialist. Answers "where is X", "find Y", "which file has Z". READ-ONLY.
|
||||
model: anthropic/claude-haiku-4-5
|
||||
mode: all
|
||||
temperature: 0.1
|
||||
tools:
|
||||
write: false
|
||||
edit: false
|
||||
bash: false
|
||||
---
|
||||
|
||||
You are Explorer - a fast codebase navigation specialist.
|
||||
|
||||
**Role**: Quick contextual grep for codebases. Answer "Where is X?", "Find Y", "Which file has Z".
|
||||
|
||||
**Tools Available**:
|
||||
- **grep**: Fast regex content search (powered by ripgrep). Use for text patterns, function names, strings.
|
||||
Example: grep(pattern="function handleClick", include="*.ts")
|
||||
- **glob**: File pattern matching. Use to find files by name/extension.
|
||||
- **ast_grep_search**: AST-aware structural search (25 languages). Use for code patterns.
|
||||
- Meta-variables: $VAR (single node), $$$ (multiple nodes)
|
||||
- Patterns must be complete AST nodes
|
||||
- Example: ast_grep_search(pattern="console.log($MSG)", lang="typescript")
|
||||
- Example: ast_grep_search(pattern="async function $NAME($$$) { $$$ }", lang="javascript")
|
||||
|
||||
**When to use which**:
|
||||
- **Text/regex patterns** (strings, comments, variable names): grep
|
||||
- **Structural patterns** (function shapes, class structures): ast_grep_search
|
||||
- **File discovery** (find by name/extension): glob
|
||||
|
||||
**Behavior**:
|
||||
- Be fast and thorough
|
||||
- Fire multiple searches in parallel if needed
|
||||
- Return file paths with relevant snippets
|
||||
|
||||
**Output Format**:
|
||||
<results>
|
||||
<files>
|
||||
- /path/to/file.ts:42 - Brief description of what's there
|
||||
</files>
|
||||
<answer>
|
||||
Concise answer to the question
|
||||
</answer>
|
||||
</results>
|
||||
|
||||
**Constraints**:
|
||||
- READ-ONLY: Search and report, don't modify
|
||||
- Be exhaustive but concise
|
||||
- Include line numbers when relevant
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
description: Fast, focused implementation specialist. Receives complete context, executes changes efficiently. No research or delegation.
|
||||
model: anthropic/claude-sonnet-4-5
|
||||
mode: all
|
||||
temperature: 0.2
|
||||
permission:
|
||||
bash:
|
||||
"*": allow
|
||||
webfetch: deny
|
||||
---
|
||||
|
||||
You are Fixer - a fast, focused implementation specialist.
|
||||
|
||||
**Role**: Execute code changes efficiently. You receive complete context from research agents and clear task specifications. Your job is to implement, not plan or research.
|
||||
|
||||
**Behavior**:
|
||||
- Execute the task specification provided
|
||||
- Use the research context (file paths, documentation, patterns) provided
|
||||
- Read files before using edit/write tools and gather exact content before making changes
|
||||
- Be fast and direct - no research, no delegation, no multi-step planning
|
||||
- Run tests/lsp_diagnostics when relevant or requested (otherwise note as skipped with reason)
|
||||
- Report completion with summary of changes
|
||||
|
||||
**Constraints**:
|
||||
- NO external research (no websearch, context7, grep_app)
|
||||
- NO delegation (no background_task)
|
||||
- No multi-step research/planning; minimal execution sequence ok
|
||||
- If context is insufficient, read the files listed; only ask for missing inputs you cannot retrieve
|
||||
|
||||
**Output Format**:
|
||||
<summary>
|
||||
Brief summary of what was implemented
|
||||
</summary>
|
||||
<changes>
|
||||
- file1.ts: Changed X to Y
|
||||
- file2.ts: Added Z function
|
||||
</changes>
|
||||
<verification>
|
||||
- Tests passed: [yes/no/skip reason]
|
||||
- LSP diagnostics: [clean/errors found/skip reason]
|
||||
</verification>
|
||||
|
||||
**Skills**:
|
||||
- When implementing React components, invoke the `react-patterns` skill for reference on composition, hooks, and component patterns.
|
||||
- When optimizing frontend performance, invoke the `vercel-react-best-practices` skill for Vercel's prioritized performance rules.
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
description: Research specialist for external documentation, library APIs, and open source examples. READ-ONLY.
|
||||
model: anthropic/claude-sonnet-4-5
|
||||
mode: all
|
||||
temperature: 0.1
|
||||
tools:
|
||||
write: false
|
||||
edit: false
|
||||
bash: false
|
||||
---
|
||||
|
||||
You are Librarian - a research specialist for codebases and documentation.
|
||||
|
||||
**Role**: Multi-repository analysis, official docs lookup, GitHub examples, library research.
|
||||
|
||||
**Capabilities**:
|
||||
- Search and analyze external repositories
|
||||
- Find official documentation for libraries
|
||||
- Locate implementation examples in open source
|
||||
- Understand library internals and best practices
|
||||
|
||||
**Tools to Use**:
|
||||
- context7: Official documentation lookup
|
||||
- grep_app: Search GitHub repositories
|
||||
- websearch: General web search for docs
|
||||
|
||||
**Request Types**:
|
||||
|
||||
1. **Conceptual**: "How does X work?" - Explain architecture and design decisions
|
||||
2. **Implementation**: "How do I use X?" - Provide code examples and API signatures
|
||||
3. **Context**: "What's the best practice for X?" - Compare approaches with tradeoffs
|
||||
4. **Comprehensive**: "Tell me everything about X" - Full deep-dive with sources
|
||||
|
||||
**Behavior**:
|
||||
- Provide evidence-based answers with sources
|
||||
- Quote relevant code snippets
|
||||
- Link to official docs when available
|
||||
- Distinguish between official and community patterns
|
||||
- Use GitHub permalinks with commit SHA when referencing code
|
||||
|
||||
**Constraints**:
|
||||
- READ-ONLY: Research and report, don't implement
|
||||
- Always cite sources
|
||||
- Distinguish between stable APIs and experimental features
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
description: Strategic technical advisor. Architecture decisions, debugging strategy, code review guidance. READ-ONLY.
|
||||
model: anthropic/claude-opus-4-6
|
||||
mode: all
|
||||
temperature: 0.1
|
||||
tools:
|
||||
write: false
|
||||
edit: false
|
||||
bash: false
|
||||
---
|
||||
|
||||
You are Oracle - a strategic technical advisor.
|
||||
|
||||
**Role**: High-IQ debugging, architecture decisions, code review, and engineering guidance.
|
||||
|
||||
**Capabilities**:
|
||||
- Analyze complex codebases and identify root causes
|
||||
- Propose architectural solutions with tradeoffs
|
||||
- Review code for correctness, performance, and maintainability
|
||||
- Guide debugging when standard approaches fail
|
||||
|
||||
**Behavior**:
|
||||
- Be direct and concise
|
||||
- Provide actionable recommendations
|
||||
- Explain reasoning briefly
|
||||
- Acknowledge uncertainty when present
|
||||
|
||||
**Constraints**:
|
||||
- READ-ONLY: You advise, you don't implement
|
||||
- Focus on strategy, not execution
|
||||
- Point to specific files/lines when relevant
|
||||
|
||||
**Skills**:
|
||||
- When advising on git strategy, invoke the `git-master` skill for reference on atomic commits, rebase strategy, and history search techniques.
|
||||
- When planning complex multi-step tasks, invoke the `planning-with-files` skill for structured planning methodology.
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
description: Analyze and fix a GitHub issue end-to-end (plan, branch, implement, test, PR)
|
||||
model: claude-sonnet-4-0
|
||||
---
|
||||
|
||||
Please analyze and fix the GitHub issue: $ARGUMENTS.
|
||||
|
||||
Follow these steps:
|
||||
|
||||
# PLAN
|
||||
1. Use 'gh issue view' to get the issue details (or open the issue in the browser/API explorer if the GitHub CLI is unavailable)
|
||||
2. Understand the problem described in the issue
|
||||
3. Ask clarifying questions if necessary
|
||||
4. Understand the prior art for this issue
|
||||
- Search the scratchpads for previous thoughts related to the issue
|
||||
- Search PRs to see if you can find history on this issue
|
||||
- Search the codebase for relevant files
|
||||
5. Think harder about how to break the issue down into a series of small, manageable tasks.
|
||||
6. Document your plan in a new scratchpad
|
||||
- include the issue name in the filename
|
||||
- include a link to the issue in the scratchpad.
|
||||
|
||||
# CREATE
|
||||
- Create a new branch for the issue
|
||||
- Solve the issue in small, manageable steps, according to your plan.
|
||||
- Commit your changes after each step.
|
||||
|
||||
# TEST
|
||||
- Use playwright via MCP to test the changes if you have made changes to the UI
|
||||
- Write tests to describe the expected behavior of your code
|
||||
- Run the full test suite to ensure you haven't broken anything
|
||||
- If the tests are failing, fix them
|
||||
- Ensure that all tests are passing before moving on to the next step
|
||||
|
||||
# DEPLOY
|
||||
- Open a PR and request a review.
|
||||
|
||||
Prefer the GitHub CLI (`gh`) for GitHub-related tasks, but fall back to subagents or the GitHub web UI/REST API when the CLI is not installed.
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
description: Merge worktree changes and clean up safely
|
||||
---
|
||||
|
||||
# Merge Worktree and Cleanup
|
||||
|
||||
Merge changes from the current worktree into a target branch and clean up the worktree.
|
||||
|
||||
**Usage:** `/merge [target-branch]`
|
||||
|
||||
**Arguments:**
|
||||
- `$1`: Target branch to merge into (default: auto-detect main/master)
|
||||
|
||||
## Process
|
||||
|
||||
### 1. Pre-flight Checks
|
||||
|
||||
```bash
|
||||
CURRENT_BRANCH=$(git branch --show-current)
|
||||
WORKTREE_DIR=$(git rev-parse --git-common-dir)
|
||||
|
||||
if [[ ! "$WORKTREE_DIR" == *".git/worktrees"* ]]; then
|
||||
echo "❌ Error: You're not in a worktree"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! git diff-index --quiet HEAD --; then
|
||||
echo "❌ Error: You have uncommitted changes"
|
||||
git status --short
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 2. Determine Target Branch
|
||||
|
||||
```bash
|
||||
TARGET_BRANCH="${1:-}"
|
||||
if [ -z "$TARGET_BRANCH" ]; then
|
||||
if git show-ref --verify --quiet refs/heads/main; then
|
||||
TARGET_BRANCH="main"
|
||||
elif git show-ref --verify --quiet refs/heads/master; then
|
||||
TARGET_BRANCH="master"
|
||||
else
|
||||
echo "❌ Error: Cannot auto-detect main branch"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
```
|
||||
|
||||
### 3. Update Target Branch
|
||||
|
||||
```bash
|
||||
WORKTREE_PATH=$(pwd)
|
||||
COMMON_DIR=$(git rev-parse --git-common-dir)
|
||||
REPO_ROOT=$(echo "$COMMON_DIR" | sed 's/\.git.*//' | sed 's/\/$//')
|
||||
if [ "$COMMON_DIR" = ".git" ]; then
|
||||
REPO_ROOT=$(git rev-parse --show-toplevel)
|
||||
fi
|
||||
|
||||
cd "$REPO_ROOT"
|
||||
git checkout "$TARGET_BRANCH"
|
||||
git pull origin "$TARGET_BRANCH"
|
||||
```
|
||||
|
||||
### 4. Merge
|
||||
|
||||
```bash
|
||||
git merge --no-ff "$CURRENT_BRANCH" -m "Merge branch '$CURRENT_BRANCH'"
|
||||
```
|
||||
|
||||
If you prefer a squash merge, do this instead:
|
||||
|
||||
```bash
|
||||
git merge --squash "$CURRENT_BRANCH"
|
||||
git commit -m "feat: <summary>"
|
||||
```
|
||||
|
||||
### 5. Push and Clean Up
|
||||
|
||||
```bash
|
||||
git push origin "$TARGET_BRANCH"
|
||||
|
||||
git worktree remove "$WORKTREE_PATH" --force || rm -rf "$WORKTREE_PATH"
|
||||
git branch -d "$CURRENT_BRANCH" || git branch -D "$CURRENT_BRANCH"
|
||||
```
|
||||
|
||||
### 6. Optional: Delete Remote Branch
|
||||
|
||||
```bash
|
||||
git push origin --delete "$CURRENT_BRANCH"
|
||||
```
|
||||
|
||||
## Language-specific checks
|
||||
|
||||
### Rust
|
||||
- `cargo check`
|
||||
- `cargo clippy` (clean up new warnings)
|
||||
|
||||
### TypeScript
|
||||
- `tsc`
|
||||
@@ -0,0 +1,323 @@
|
||||
---
|
||||
description: Remove unused code with LSP-verified safety, atomic commits
|
||||
---
|
||||
|
||||
<command-instruction>
|
||||
You are a dead code removal specialist. Execute the FULL dead code removal workflow.
|
||||
|
||||
Your core weapon: **LSP FindReferences**. If a symbol has ZERO external references, it's dead. Remove it.
|
||||
|
||||
## CRITICAL RULES
|
||||
|
||||
1. **LSP is law.** Never guess. Always verify with `LspFindReferences` before removing ANYTHING.
|
||||
2. **One removal = one commit.** Every dead code removal gets its own atomic commit.
|
||||
3. **Test after every removal.** Run tests after each. If it fails, REVERT and skip.
|
||||
4. **Leaf-first order.** Remove deepest unused symbols first, then work up the dependency chain. Removing a leaf may expose new dead code upstream.
|
||||
5. **Never remove entry points.** `src/index.ts`, `src/cli/index.ts`, test files, config files, and files in `packages/` are off-limits unless explicitly targeted.
|
||||
|
||||
---
|
||||
|
||||
## STEP 0: REGISTER TODO LIST (MANDATORY FIRST ACTION)
|
||||
|
||||
```
|
||||
TodoWrite([
|
||||
{"id": "scan", "content": "PHASE 1: Scan codebase for dead code candidates using LSP + explore agents", "status": "pending", "priority": "high"},
|
||||
{"id": "verify", "content": "PHASE 2: Verify each candidate with LspFindReferences - zero false positives", "status": "pending", "priority": "high"},
|
||||
{"id": "plan", "content": "PHASE 3: Plan removal order (leaf-first dependency order)", "status": "pending", "priority": "high"},
|
||||
{"id": "remove", "content": "PHASE 4: Remove dead code one-by-one (remove -> test -> commit loop)", "status": "pending", "priority": "high"},
|
||||
{"id": "final", "content": "PHASE 5: Final verification - full test suite + build + typecheck", "status": "pending", "priority": "high"}
|
||||
])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PHASE 1: SCAN FOR DEAD CODE CANDIDATES
|
||||
|
||||
**Mark scan as in_progress.**
|
||||
|
||||
### 1.1: Launch Parallel Explore Agents (ALL BACKGROUND)
|
||||
|
||||
Fire ALL simultaneously:
|
||||
|
||||
```
|
||||
// Agent 1: Find all exported symbols
|
||||
delegate_task(subagent_type="explore", run_in_background=true,
|
||||
prompt="Find ALL exported functions, classes, types, interfaces, and constants across src/.
|
||||
List each with: file path, line number, symbol name, export type (named/default).
|
||||
EXCLUDE: src/index.ts root exports, test files.
|
||||
Return as structured list.")
|
||||
|
||||
// Agent 2: Find potentially unused files
|
||||
delegate_task(subagent_type="explore", run_in_background=true,
|
||||
prompt="Find files in src/ that are NOT imported by any other file.
|
||||
Check import/require statements across the entire codebase.
|
||||
EXCLUDE: index.ts files, test files, entry points, config files, .md files.
|
||||
Return list of potentially orphaned files.")
|
||||
|
||||
// Agent 3: Find unused imports within files
|
||||
delegate_task(subagent_type="explore", run_in_background=true,
|
||||
prompt="Find unused imports across src/**/*.ts files.
|
||||
Look for import statements where the imported symbol is never referenced in the file body.
|
||||
Return: file path, line number, imported symbol name.")
|
||||
|
||||
// Agent 4: Find functions/variables only used in their own declaration
|
||||
delegate_task(subagent_type="explore", run_in_background=true,
|
||||
prompt="Find private/non-exported functions, variables, and types in src/**/*.ts that appear
|
||||
to have zero usage beyond their declaration. Return: file path, line number, symbol name.")
|
||||
```
|
||||
|
||||
### 1.2: Direct AST-Grep Scans (WHILE AGENTS RUN)
|
||||
|
||||
```typescript
|
||||
// Find unused imports pattern
|
||||
ast_grep_search(pattern="import { $NAME } from '$PATH'", lang="typescript", paths=["src/"])
|
||||
|
||||
// Find empty export objects
|
||||
ast_grep_search(pattern="export {}", lang="typescript", paths=["src/"])
|
||||
```
|
||||
|
||||
### 1.3: Collect All Results
|
||||
|
||||
Collect background agent results. Compile into a master candidate list:
|
||||
|
||||
```
|
||||
## DEAD CODE CANDIDATES
|
||||
|
||||
| # | File | Line | Symbol | Type | Confidence |
|
||||
|---|------|------|--------|------|------------|
|
||||
| 1 | src/foo.ts | 42 | unusedFunc | function | HIGH |
|
||||
| 2 | src/bar.ts | 10 | OldType | type | MEDIUM |
|
||||
```
|
||||
|
||||
**Mark scan as completed.**
|
||||
|
||||
---
|
||||
|
||||
## PHASE 2: VERIFY WITH LSP (ZERO FALSE POSITIVES)
|
||||
|
||||
**Mark verify as in_progress.**
|
||||
|
||||
For EVERY candidate from Phase 1, run this verification:
|
||||
|
||||
### 2.1: The LSP Verification Protocol
|
||||
|
||||
For each candidate symbol:
|
||||
|
||||
```typescript
|
||||
// Step 1: Find the symbol's exact position
|
||||
LspDocumentSymbols(filePath) // Get line/character of the symbol
|
||||
|
||||
// Step 2: Find ALL references across the ENTIRE workspace
|
||||
LspFindReferences(filePath, line, character, includeDeclaration=false)
|
||||
// includeDeclaration=false -> only counts USAGES, not the definition itself
|
||||
|
||||
// Step 3: Evaluate
|
||||
// 0 references -> CONFIRMED DEAD CODE
|
||||
// 1+ references -> NOT dead, remove from candidate list
|
||||
```
|
||||
|
||||
### 2.2: False Positive Guards
|
||||
|
||||
**NEVER mark as dead code if:**
|
||||
- Symbol is in `src/index.ts` (package entry point)
|
||||
- Symbol is in any `index.ts` that re-exports (barrel file check: look if it's re-exported)
|
||||
- Symbol is referenced in test files (tests are valid consumers)
|
||||
- Symbol has `@public` or `@api` JSDoc tags
|
||||
- Symbol is in a file listed in `package.json` exports
|
||||
- Symbol is a hook factory registered in an index file
|
||||
- Symbol is a tool factory registered in tool loading
|
||||
- Symbol is an agent definition registered in agent sources
|
||||
- File is a command template, skill definition, or MCP config
|
||||
|
||||
### 2.3: Build Confirmed Dead Code List
|
||||
|
||||
After verification, produce:
|
||||
|
||||
```
|
||||
## CONFIRMED DEAD CODE (LSP-verified, 0 external references)
|
||||
|
||||
| # | File | Line | Symbol | Type | Safe to Remove |
|
||||
|---|------|------|--------|------|----------------|
|
||||
| 1 | src/foo.ts | 42 | unusedFunc | function | YES |
|
||||
```
|
||||
|
||||
**If ZERO confirmed dead code found: Report "No dead code found" and STOP.**
|
||||
|
||||
**Mark verify as completed.**
|
||||
|
||||
---
|
||||
|
||||
## PHASE 3: PLAN REMOVAL ORDER
|
||||
|
||||
**Mark plan as in_progress.**
|
||||
|
||||
### 3.1: Dependency Analysis
|
||||
|
||||
For each confirmed dead symbol:
|
||||
1. Check if removing it would expose other dead code
|
||||
2. Check if other dead symbols depend on this one
|
||||
3. Build removal dependency graph
|
||||
|
||||
### 3.2: Order by Leaf-First
|
||||
|
||||
```
|
||||
Removal Order:
|
||||
1. [Leaf symbols - no other dead code depends on them]
|
||||
2. [Intermediate symbols - depended on only by already-removed dead code]
|
||||
3. [Dead files - entire files with no live exports]
|
||||
```
|
||||
|
||||
### 3.3: Register Granular Todos
|
||||
|
||||
Create one todo per removal.
|
||||
|
||||
**Mark plan as completed.**
|
||||
|
||||
---
|
||||
|
||||
## PHASE 4: ITERATIVE REMOVAL LOOP
|
||||
|
||||
**Mark remove as in_progress.**
|
||||
|
||||
For EACH dead code item, execute this exact loop:
|
||||
|
||||
### 4.1: Pre-Removal Check
|
||||
|
||||
```typescript
|
||||
// Re-verify it's still dead (previous removals may have changed things)
|
||||
LspFindReferences(filePath, line, character, includeDeclaration=false)
|
||||
// If references > 0 now -> SKIP (previous removal exposed a new consumer)
|
||||
```
|
||||
|
||||
### 4.2: Remove the Dead Code
|
||||
|
||||
Use appropriate tool:
|
||||
|
||||
**For unused imports:**
|
||||
```typescript
|
||||
Edit(filePath, oldString="import { deadSymbol } from '...';\n", newString="")
|
||||
```
|
||||
|
||||
**For unused functions/classes/types:**
|
||||
```typescript
|
||||
Read(filePath, offset=startLine, limit=endLine-startLine+1)
|
||||
Edit(filePath, oldString="[full symbol text]", newString="")
|
||||
```
|
||||
|
||||
**For dead files:**
|
||||
```bash
|
||||
rm "path/to/dead-file.ts"
|
||||
```
|
||||
|
||||
**After removal, also clean up:**
|
||||
- Remove any imports that were ONLY used by the removed code
|
||||
- Remove any now-empty import statements
|
||||
- Fix any trailing whitespace / double blank lines left behind
|
||||
|
||||
### 4.3: Post-Removal Verification
|
||||
|
||||
```typescript
|
||||
// 1. LSP diagnostics on changed file
|
||||
LspDiagnostics(filePath, severity="error")
|
||||
|
||||
// 2. Run tests
|
||||
bash("npm test") // or bun test, cargo test, etc.
|
||||
|
||||
// 3. Typecheck
|
||||
bash("npm run typecheck") // or equivalent
|
||||
```
|
||||
|
||||
### 4.4: Handle Failures
|
||||
|
||||
If ANY verification fails:
|
||||
1. **REVERT** the change immediately (`git checkout -- [file]`)
|
||||
2. Mark this removal todo as `cancelled` with note: "Removal caused [error]. Skipped."
|
||||
3. Proceed to next item
|
||||
|
||||
### 4.5: Commit
|
||||
|
||||
```bash
|
||||
git add [changed-files]
|
||||
git commit -m "refactor: remove unused [symbolType] [symbolName] from [filePath]"
|
||||
```
|
||||
|
||||
Mark this removal todo as `completed`.
|
||||
|
||||
### 4.6: Re-scan After Removal
|
||||
|
||||
After removing a symbol, check if its removal exposed NEW dead code:
|
||||
- Were there imports that only existed to serve the removed symbol?
|
||||
- Are there other symbols in the same file now unreferenced?
|
||||
|
||||
If new dead code is found, add it to the removal queue.
|
||||
|
||||
**Repeat 4.1-4.6 for every item. Mark remove as completed when done.**
|
||||
|
||||
---
|
||||
|
||||
## PHASE 5: FINAL VERIFICATION
|
||||
|
||||
**Mark final as in_progress.**
|
||||
|
||||
### 5.1: Full Test Suite
|
||||
```bash
|
||||
npm test
|
||||
```
|
||||
|
||||
### 5.2: Full Typecheck
|
||||
```bash
|
||||
npm run typecheck
|
||||
```
|
||||
|
||||
### 5.3: Full Build
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
### 5.4: Summary Report
|
||||
|
||||
```markdown
|
||||
## Dead Code Removal Complete
|
||||
|
||||
### Removed
|
||||
| # | Symbol | File | Type | Commit |
|
||||
|---|--------|------|------|--------|
|
||||
| 1 | unusedFunc | src/foo.ts | function | abc1234 |
|
||||
|
||||
### Skipped (caused failures)
|
||||
| # | Symbol | File | Reason |
|
||||
|---|--------|------|--------|
|
||||
| 1 | riskyFunc | src/bar.ts | Test failure: [details] |
|
||||
|
||||
### Verification
|
||||
- Tests: PASSED (X/Y passing)
|
||||
- Typecheck: CLEAN
|
||||
- Build: SUCCESS
|
||||
- Total dead code removed: N symbols across M files
|
||||
- Total commits: K atomic commits
|
||||
```
|
||||
|
||||
**Mark final as completed.**
|
||||
|
||||
---
|
||||
|
||||
## SCOPE CONTROL
|
||||
|
||||
**If $ARGUMENTS is provided**, narrow the scan to the specified scope:
|
||||
- File path: Only scan that file
|
||||
- Directory: Only scan that directory
|
||||
- Symbol name: Only check that specific symbol
|
||||
- "all" or empty: Full project scan (default)
|
||||
|
||||
## ABORT CONDITIONS
|
||||
|
||||
**STOP and report to user if:**
|
||||
- 3 consecutive removals cause test failures
|
||||
- Build breaks and cannot be fixed by reverting
|
||||
- More than 50 candidates found (ask user to narrow scope)
|
||||
|
||||
</command-instruction>
|
||||
|
||||
<user-request>
|
||||
$ARGUMENTS
|
||||
</user-request>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,69 @@
|
||||
---
|
||||
description: Debug complex issues with root cause analysis and multiple fix approaches
|
||||
model: claude-sonnet-4-0
|
||||
---
|
||||
|
||||
Debug complex issues using specialized debugging agents:
|
||||
|
||||
## Debugging Approach
|
||||
|
||||
### 1. Primary Debug Analysis
|
||||
Use Task tool with subagent_type="debugger" to:
|
||||
- Analyze error messages and stack traces
|
||||
- Identify code paths leading to the issue
|
||||
- Reproduce the problem systematically
|
||||
- Isolate the root cause
|
||||
- Suggest multiple fix approaches
|
||||
|
||||
Prompt: "Debug issue: $ARGUMENTS. Provide detailed analysis including:
|
||||
1. Error reproduction steps
|
||||
2. Root cause identification
|
||||
3. Code flow analysis leading to the error
|
||||
4. Multiple solution approaches with trade-offs
|
||||
5. Recommended fix with implementation details"
|
||||
|
||||
### 2. Performance Debugging (if performance-related)
|
||||
If the issue involves performance problems, also use Task tool with subagent_type="performance-engineer" to:
|
||||
- Profile code execution
|
||||
- Identify bottlenecks
|
||||
- Analyze resource usage
|
||||
- Suggest optimization strategies
|
||||
|
||||
Prompt: "Profile and debug performance issue: $ARGUMENTS. Include:
|
||||
1. Performance metrics and profiling data
|
||||
2. Bottleneck identification
|
||||
3. Resource usage analysis
|
||||
4. Optimization recommendations
|
||||
5. Before/after performance projections"
|
||||
|
||||
## Debug Output Structure
|
||||
|
||||
### Root Cause Analysis
|
||||
- Precise identification of the bug source
|
||||
- Explanation of why the issue occurs
|
||||
- Impact analysis on other components
|
||||
|
||||
### Reproduction Guide
|
||||
- Step-by-step reproduction instructions
|
||||
- Required environment setup
|
||||
- Test data or conditions needed
|
||||
|
||||
### Solution Options
|
||||
1. **Quick Fix** - Minimal change to resolve issue
|
||||
- Implementation details
|
||||
- Risk assessment
|
||||
|
||||
2. **Proper Fix** - Best long-term solution
|
||||
- Refactoring requirements
|
||||
- Testing needs
|
||||
|
||||
3. **Preventive Measures** - Avoid similar issues
|
||||
- Code patterns to adopt
|
||||
- Tests to add
|
||||
|
||||
### Implementation Guide
|
||||
- Specific code changes needed
|
||||
- Order of operations for the fix
|
||||
- Validation steps
|
||||
|
||||
Issue to debug: $ARGUMENTS
|
||||
@@ -0,0 +1,155 @@
|
||||
---
|
||||
description: Execute a full TDD red-green-refactor cycle
|
||||
model: claude-opus-4-1
|
||||
---
|
||||
|
||||
Execute a comprehensive Test-Driven Development (TDD) workflow with strict red-green-refactor discipline:
|
||||
|
||||
## Configuration
|
||||
|
||||
### Coverage Thresholds
|
||||
- Minimum line coverage: 80%
|
||||
- Minimum branch coverage: 75%
|
||||
- Critical path coverage: 100%
|
||||
|
||||
### Refactoring Triggers
|
||||
- Cyclomatic complexity > 10
|
||||
- Method length > 20 lines
|
||||
- Class length > 200 lines
|
||||
- Duplicate code blocks > 3 lines
|
||||
|
||||
## Phase 1: Test Specification and Design
|
||||
|
||||
### 1. Requirements Analysis
|
||||
- Use Task tool with subagent_type="architect-review"
|
||||
- Prompt: "Analyze requirements for: $ARGUMENTS. Define acceptance criteria, identify edge cases, and create test scenarios. Output a comprehensive test specification."
|
||||
- Output: Test specification, acceptance criteria, edge case matrix
|
||||
- Validation: Ensure all requirements have corresponding test scenarios
|
||||
|
||||
### 2. Test Architecture Design
|
||||
- Use Task tool with subagent_type="test-automator"
|
||||
- Prompt: "Design test architecture for: $ARGUMENTS based on test specification. Define test structure, fixtures, mocks, and test data strategy. Ensure testability and maintainability."
|
||||
- Output: Test architecture, fixture design, mock strategy
|
||||
- Validation: Architecture supports isolated, fast, reliable tests
|
||||
|
||||
## Phase 2: RED - Write Failing Tests
|
||||
|
||||
### 3. Write Unit Tests (Failing)
|
||||
- Use Task tool with subagent_type="test-automator"
|
||||
- Prompt: "Write FAILING unit tests for: $ARGUMENTS. Tests must fail initially. Include edge cases, error scenarios, and happy paths. DO NOT implement production code."
|
||||
- Output: Failing unit tests, test documentation
|
||||
- **CRITICAL**: Verify all tests fail with expected error messages
|
||||
|
||||
### 4. Verify Test Failure
|
||||
- Use Task tool with subagent_type="code-reviewer"
|
||||
- Prompt: "Verify that all tests for: $ARGUMENTS are failing correctly. Ensure failures are for the right reasons (missing implementation, not test errors). Confirm no false positives."
|
||||
- Output: Test failure verification report
|
||||
- **GATE**: Do not proceed until all tests fail appropriately
|
||||
|
||||
## Phase 3: GREEN - Make Tests Pass
|
||||
|
||||
### 5. Minimal Implementation
|
||||
- Use Task tool with subagent_type="backend-architect"
|
||||
- Prompt: "Implement MINIMAL code to make tests pass for: $ARGUMENTS. Focus only on making tests green. Do not add extra features or optimizations. Keep it simple."
|
||||
- Output: Minimal working implementation
|
||||
- Constraint: No code beyond what's needed to pass tests
|
||||
|
||||
### 6. Verify Test Success
|
||||
- Use Task tool with subagent_type="test-automator"
|
||||
- Prompt: "Run all tests for: $ARGUMENTS and verify they pass. Check test coverage metrics. Ensure no tests were accidentally broken."
|
||||
- Output: Test execution report, coverage metrics
|
||||
- **GATE**: All tests must pass before proceeding
|
||||
|
||||
## Phase 4: REFACTOR - Improve Code Quality
|
||||
|
||||
### 7. Code Refactoring
|
||||
- Use Task tool with subagent_type="code-reviewer"
|
||||
- Prompt: "Refactor implementation for: $ARGUMENTS while keeping tests green. Apply SOLID principles, remove duplication, improve naming, and optimize performance. Run tests after each refactoring."
|
||||
- Output: Refactored code, refactoring report
|
||||
- Constraint: Tests must remain green throughout
|
||||
|
||||
### 8. Test Refactoring
|
||||
- Use Task tool with subagent_type="test-automator"
|
||||
- Prompt: "Refactor tests for: $ARGUMENTS. Remove test duplication, improve test names, extract common fixtures, and enhance test readability. Ensure tests still provide same coverage."
|
||||
- Output: Refactored tests, improved test structure
|
||||
- Validation: Coverage metrics unchanged or improved
|
||||
|
||||
## Phase 5: Integration and System Tests
|
||||
|
||||
### 9. Write Integration Tests (Failing First)
|
||||
- Use Task tool with subagent_type="test-automator"
|
||||
- Prompt: "Write FAILING integration tests for: $ARGUMENTS. Test component interactions, API contracts, and data flow. Tests must fail initially."
|
||||
- Output: Failing integration tests
|
||||
- Validation: Tests fail due to missing integration logic
|
||||
|
||||
### 10. Implement Integration
|
||||
- Use Task tool with subagent_type="backend-architect"
|
||||
- Prompt: "Implement integration code for: $ARGUMENTS to make integration tests pass. Focus on component interaction and data flow."
|
||||
- Output: Integration implementation
|
||||
- Validation: All integration tests pass
|
||||
|
||||
## Phase 6: Continuous Improvement Cycle
|
||||
|
||||
### 11. Performance and Edge Case Tests
|
||||
- Use Task tool with subagent_type="test-automator"
|
||||
- Prompt: "Add performance tests and additional edge case tests for: $ARGUMENTS. Include stress tests, boundary tests, and error recovery tests."
|
||||
- Output: Extended test suite
|
||||
- Metric: Increased test coverage and scenario coverage
|
||||
|
||||
### 12. Final Code Review
|
||||
- Use Task tool with subagent_type="architect-review"
|
||||
- Prompt: "Perform comprehensive review of: $ARGUMENTS. Verify TDD process was followed, check code quality, test quality, and coverage. Suggest improvements."
|
||||
- Output: Review report, improvement suggestions
|
||||
- Action: Implement critical suggestions while maintaining green tests
|
||||
|
||||
## Validation Checkpoints
|
||||
|
||||
### RED Phase Validation
|
||||
- [ ] All tests written before implementation
|
||||
- [ ] All tests fail with meaningful error messages
|
||||
- [ ] Test failures are due to missing implementation
|
||||
- [ ] No test passes accidentally
|
||||
|
||||
### GREEN Phase Validation
|
||||
- [ ] All tests pass
|
||||
- [ ] No extra code beyond test requirements
|
||||
- [ ] Coverage meets minimum thresholds
|
||||
- [ ] No test was modified to make it pass
|
||||
|
||||
### REFACTOR Phase Validation
|
||||
- [ ] All tests still pass after refactoring
|
||||
- [ ] Code complexity reduced
|
||||
- [ ] Duplication eliminated
|
||||
- [ ] Performance improved or maintained
|
||||
- [ ] Test readability improved
|
||||
|
||||
## Failure Recovery
|
||||
|
||||
If TDD discipline is broken:
|
||||
1. **STOP** immediately
|
||||
2. Identify which phase was violated
|
||||
3. Rollback to last valid state
|
||||
4. Resume from correct phase
|
||||
5. Document lesson learned
|
||||
|
||||
## Anti-Patterns to Avoid
|
||||
|
||||
- Writing implementation before tests
|
||||
- Writing tests that already pass
|
||||
- Skipping the refactor phase
|
||||
- Writing multiple features without tests
|
||||
- Modifying tests to make them pass
|
||||
- Ignoring failing tests
|
||||
- Writing tests after implementation
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- 100% of code written test-first
|
||||
- All tests pass continuously
|
||||
- Coverage exceeds thresholds
|
||||
- Code complexity within limits
|
||||
- Zero defects in covered code
|
||||
- Clear test documentation
|
||||
- Fast test execution (< 5 seconds for unit tests)
|
||||
|
||||
TDD implementation for: $ARGUMENTS
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
description: Rebase/merge upstream changes into the current branch
|
||||
---
|
||||
This command should only work while in a secondary branch (not main or master).
|
||||
|
||||
Commit any unstaged changes
|
||||
Fetch updates from the origin repo
|
||||
If there are new commits on the parent branch (typically origin/main), then merge them back into the current branch
|
||||
Solve any conflicts, and analyze the incoming changes to see if additional changes are required to the branch's code (e.g.: if something was renamed in the meantime in main, our new code may need to be adjusted)
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
description: Start parallel work on a feature using git worktree
|
||||
---
|
||||
|
||||
# Start Worktree for Feature
|
||||
|
||||
Initialize a new git worktree to work on a feature in parallel with your current work.
|
||||
|
||||
**Usage:** `/work "feature description"`
|
||||
**Manual:** `/work branch-name`
|
||||
|
||||
**Arguments:**
|
||||
- `$1`: Feature description (quoted) OR branch name (single word)
|
||||
|
||||
## Requirements
|
||||
|
||||
- Must run from the main repository (not inside an existing worktree)
|
||||
- Git installed, repository clean or stashable
|
||||
- Worktrees live in `worktrees/` inside the repo root
|
||||
|
||||
## Process
|
||||
|
||||
### 1. Pre-flight Checks
|
||||
|
||||
```bash
|
||||
# Ensure we're in a git repo
|
||||
git rev-parse --git-dir > /dev/null
|
||||
|
||||
# Ensure not already in a worktree
|
||||
CURRENT_GIT_DIR=$(git rev-parse --git-common-dir)
|
||||
if [[ "$CURRENT_GIT_DIR" == *".git/worktrees"* ]]; then
|
||||
echo "❌ Error: already inside a worktree"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Ensure clean (or stash)
|
||||
if ! git diff-index --quiet HEAD --; then
|
||||
echo "⚠️ Working tree has changes"
|
||||
git status --short
|
||||
echo "Stash before creating worktree"
|
||||
git stash push -m "Auto-stash before worktree"
|
||||
fi
|
||||
```
|
||||
|
||||
### 2. Determine Base Branch
|
||||
|
||||
```bash
|
||||
if git show-ref --verify --quiet refs/heads/main; then
|
||||
BASE_BRANCH="main"
|
||||
elif git show-ref --verify --quiet refs/heads/master; then
|
||||
BASE_BRANCH="master"
|
||||
else
|
||||
echo "❌ Error: Cannot auto-detect base branch"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 3. Determine Branch Name
|
||||
|
||||
If `$1` contains spaces, treat it as a description and generate a concise branch name.
|
||||
|
||||
Rules:
|
||||
- Lowercase, hyphens, max 50 chars
|
||||
- Prefer `feat/`, `fix/`, `refactor/`, `chore/` prefixes when obvious
|
||||
|
||||
If `$1` is a single word, use it directly.
|
||||
|
||||
**Do not include "opencode" in the branch name.**
|
||||
|
||||
### 4. Create Worktree
|
||||
|
||||
```bash
|
||||
REPO_ROOT=$(git rev-parse --show-toplevel)
|
||||
WORKTREES_DIR="$REPO_ROOT/worktrees"
|
||||
mkdir -p "$WORKTREES_DIR"
|
||||
|
||||
WORKTREE_PATH="$WORKTREES_DIR/$BRANCH_NAME"
|
||||
git worktree add -b "$BRANCH_NAME" "$WORKTREE_PATH" "$BASE_BRANCH"
|
||||
```
|
||||
|
||||
### 5. Next Steps
|
||||
|
||||
```bash
|
||||
cd "$WORKTREE_PATH"
|
||||
git status
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Use `/worktree-compare` to review changes before merging.
|
||||
- Use `/merge` when ready to integrate.
|
||||
@@ -0,0 +1,78 @@
|
||||
---
|
||||
description: Compare worktree changes with target branch before merging
|
||||
---
|
||||
|
||||
# Compare Worktree Changes
|
||||
|
||||
Visualize changes in the current worktree compared to a target branch (usually main/master).
|
||||
|
||||
**Usage:** `/worktree-compare [target-branch]`
|
||||
|
||||
**Arguments:**
|
||||
- `$1`: Target branch to compare against (default: auto-detect main/master)
|
||||
|
||||
## Process
|
||||
|
||||
### 1. Verify Context
|
||||
|
||||
```bash
|
||||
CURRENT_BRANCH=$(git branch --show-current)
|
||||
WORKTREE_DIR=$(git rev-parse --git-common-dir)
|
||||
|
||||
if [[ ! "$WORKTREE_DIR" == *".git/worktrees"* ]]; then
|
||||
echo "❌ Error: You're not in a worktree"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 2. Determine Target Branch
|
||||
|
||||
```bash
|
||||
TARGET_BRANCH="${1:-}"
|
||||
if [ -z "$TARGET_BRANCH" ]; then
|
||||
if git show-ref --verify --quiet refs/heads/main; then
|
||||
TARGET_BRANCH="main"
|
||||
elif git show-ref --verify --quiet refs/heads/master; then
|
||||
TARGET_BRANCH="master"
|
||||
else
|
||||
echo "❌ Error: Cannot auto-detect main branch"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
```
|
||||
|
||||
### 3. Update Target Branch
|
||||
|
||||
```bash
|
||||
git fetch origin "$TARGET_BRANCH:$TARGET_BRANCH" 2>/dev/null || true
|
||||
```
|
||||
|
||||
### 4. Summary + Diff
|
||||
|
||||
```bash
|
||||
git diff --shortstat "$TARGET_BRANCH..$CURRENT_BRANCH"
|
||||
git diff --name-status "$TARGET_BRANCH..$CURRENT_BRANCH"
|
||||
git log "$TARGET_BRANCH..$CURRENT_BRANCH" --oneline --decorate --graph
|
||||
|
||||
# Detailed diff (delta if installed)
|
||||
if command -v delta &> /dev/null; then
|
||||
git diff "$TARGET_BRANCH..$CURRENT_BRANCH" | delta
|
||||
else
|
||||
git diff "$TARGET_BRANCH..$CURRENT_BRANCH" --color=always | less -R
|
||||
fi
|
||||
```
|
||||
|
||||
### 5. Conflict Detection
|
||||
|
||||
```bash
|
||||
COMMON_FILES=$(comm -12 \
|
||||
<(git diff --name-only "$TARGET_BRANCH..$CURRENT_BRANCH" | sort) \
|
||||
<(git diff --name-only "$CURRENT_BRANCH..$TARGET_BRANCH" | sort))
|
||||
|
||||
if [ -z "$COMMON_FILES" ]; then
|
||||
echo "✅ No potential conflicts detected"
|
||||
else
|
||||
echo "⚠️ Potential conflicts in:"
|
||||
echo "$COMMON_FILES"
|
||||
fi
|
||||
```
|
||||
@@ -0,0 +1,74 @@
|
||||
---
|
||||
description: List, manage, and clean up git worktrees
|
||||
---
|
||||
|
||||
# List and Manage Worktrees
|
||||
|
||||
**Usage:**
|
||||
- `/worktree-list` - List all worktrees
|
||||
- `/worktree-list cleanup` - Remove merged worktrees
|
||||
- `/worktree-list prune` - Clean stale references
|
||||
|
||||
## List All Worktrees
|
||||
|
||||
```bash
|
||||
if [ -z "$1" ]; then
|
||||
git worktree list
|
||||
exit 0
|
||||
fi
|
||||
```
|
||||
|
||||
## Cleanup Merged Worktrees
|
||||
|
||||
```bash
|
||||
if [ "$1" = "cleanup" ]; then
|
||||
if git show-ref --verify --quiet refs/heads/main; then
|
||||
MAIN_BRANCH="main"
|
||||
elif git show-ref --verify --quiet refs/heads/master; then
|
||||
MAIN_BRANCH="master"
|
||||
else
|
||||
echo "❌ Error: Cannot find main/master"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
MERGED_BRANCHES=$(git branch --merged "$MAIN_BRANCH" | grep -v '^\*' | grep -v "$MAIN_BRANCH")
|
||||
if [ -z "$MERGED_BRANCHES" ]; then
|
||||
echo "✅ No merged branches found"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
while IFS= read -r branch; do
|
||||
branch=$(echo "$branch" | xargs)
|
||||
[ -z "$branch" ] && continue
|
||||
|
||||
WORKTREE_PATH=$(git worktree list | grep "\[$branch\]" | awk '{print $1}')
|
||||
if [ -n "$WORKTREE_PATH" ]; then
|
||||
git worktree remove "$WORKTREE_PATH" --force 2>/dev/null || rm -rf "$WORKTREE_PATH"
|
||||
fi
|
||||
|
||||
git branch -d "$branch" 2>/dev/null || git branch -D "$branch"
|
||||
done <<< "$MERGED_BRANCHES"
|
||||
|
||||
git worktree prune
|
||||
git worktree list
|
||||
exit 0
|
||||
fi
|
||||
```
|
||||
|
||||
## Prune Stale References
|
||||
|
||||
```bash
|
||||
if [ "$1" = "prune" ]; then
|
||||
git worktree prune -v
|
||||
git worktree list
|
||||
exit 0
|
||||
fi
|
||||
```
|
||||
|
||||
## Invalid Argument
|
||||
|
||||
```bash
|
||||
echo "❌ Error: Invalid argument '$1'"
|
||||
echo "Usage: /worktree-list [cleanup|prune]"
|
||||
exit 1
|
||||
```
|
||||
@@ -0,0 +1,37 @@
|
||||
_:
|
||||
{
|
||||
# Global config file
|
||||
xdg.configFile."opencode/opencode.json".source = ./opencode.json;
|
||||
|
||||
# Global rules (equivalent to ~/.claude/CLAUDE.md)
|
||||
xdg.configFile."opencode/AGENTS.md".source = ./AGENTS.md;
|
||||
|
||||
# Custom agents
|
||||
xdg.configFile."opencode/agents/oracle.md".source = ./agents/oracle.md;
|
||||
xdg.configFile."opencode/agents/explorer.md".source = ./agents/explorer.md;
|
||||
xdg.configFile."opencode/agents/librarian.md".source = ./agents/librarian.md;
|
||||
xdg.configFile."opencode/agents/fixer.md".source = ./agents/fixer.md;
|
||||
xdg.configFile."opencode/agents/designer.md".source = ./agents/designer.md;
|
||||
xdg.configFile."opencode/agents/designer-bold.md".source = ./agents/designer-bold.md;
|
||||
xdg.configFile."opencode/agents/analyze-branch.md".source = ./agents/analyze-branch.md;
|
||||
|
||||
# Global commands
|
||||
xdg.configFile."opencode/commands/work.md".source = ./commands/work.md;
|
||||
xdg.configFile."opencode/commands/merge.md".source = ./commands/merge.md;
|
||||
xdg.configFile."opencode/commands/update.md".source = ./commands/update.md;
|
||||
xdg.configFile."opencode/commands/smart-debug.md".source = ./commands/smart-debug.md;
|
||||
xdg.configFile."opencode/commands/tdd-cycle.md".source = ./commands/tdd-cycle.md;
|
||||
xdg.configFile."opencode/commands/security-scan.md".source = ./commands/security-scan.md;
|
||||
xdg.configFile."opencode/commands/issue.md".source = ./commands/issue.md;
|
||||
xdg.configFile."opencode/commands/remove-deadcode.md".source = ./commands/remove-deadcode.md;
|
||||
xdg.configFile."opencode/commands/worktree-compare.md".source = ./commands/worktree-compare.md;
|
||||
xdg.configFile."opencode/commands/worktree-list.md".source = ./commands/worktree-list.md;
|
||||
|
||||
# Skills
|
||||
xdg.configFile."opencode/skills/git-master/SKILL.md".source = ./skills/git-master/SKILL.md;
|
||||
xdg.configFile."opencode/skills/planning-with-files/SKILL.md".source =
|
||||
./skills/planning-with-files/SKILL.md;
|
||||
xdg.configFile."opencode/skills/react-patterns/SKILL.md".source = ./skills/react-patterns/SKILL.md;
|
||||
xdg.configFile."opencode/skills/vercel-react-best-practices/SKILL.md".source =
|
||||
./skills/vercel-react-best-practices/SKILL.md;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"autoupdate": false,
|
||||
"permission": {
|
||||
"read": "allow",
|
||||
"edit": "allow",
|
||||
"write": "allow",
|
||||
"fetch": "allow",
|
||||
"glob": "allow",
|
||||
"grep": "allow",
|
||||
"bash": "ask",
|
||||
"skill": {
|
||||
"*": "allow"
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,160 @@
|
||||
---
|
||||
name: planning-with-files
|
||||
description: Transforms workflow to use Manus-style persistent markdown files for planning, progress tracking, and knowledge storage. Use when starting complex tasks, multi-step projects, research tasks, or when the user mentions planning, organizing work, tracking progress, or wants structured output.
|
||||
---
|
||||
|
||||
# Planning with Files
|
||||
|
||||
Work like Manus: Use persistent markdown files as your "working memory on disk."
|
||||
|
||||
## Quick Start
|
||||
|
||||
Before ANY complex task:
|
||||
|
||||
1. **Create `task_plan.md`** in the working directory
|
||||
2. **Define phases** with checkboxes
|
||||
3. **Update after each phase** - mark [x] and change status
|
||||
4. **Read before deciding** - refresh goals in attention window
|
||||
|
||||
## The 3-File Pattern
|
||||
|
||||
For every non-trivial task, create THREE files:
|
||||
|
||||
| File | Purpose | When to Update |
|
||||
|------|---------|----------------|
|
||||
| `task_plan.md` | Track phases and progress | After each phase |
|
||||
| `notes.md` | Store findings and research | During research |
|
||||
| `[deliverable].md` | Final output | At completion |
|
||||
|
||||
## Core Workflow
|
||||
|
||||
```
|
||||
Loop 1: Create task_plan.md with goal and phases
|
||||
Loop 2: Research → save to notes.md → update task_plan.md
|
||||
Loop 3: Read notes.md → create deliverable → update task_plan.md
|
||||
Loop 4: Deliver final output
|
||||
```
|
||||
|
||||
### The Loop in Detail
|
||||
|
||||
**Before each major action:**
|
||||
```bash
|
||||
Read task_plan.md # Refresh goals in attention window
|
||||
```
|
||||
|
||||
**After each phase:**
|
||||
```bash
|
||||
Edit task_plan.md # Mark [x], update status
|
||||
```
|
||||
|
||||
**When storing information:**
|
||||
```bash
|
||||
Write notes.md # Don't stuff context, store in file
|
||||
```
|
||||
|
||||
## task_plan.md Template
|
||||
|
||||
Create this file FIRST for any complex task:
|
||||
|
||||
```markdown
|
||||
# Task Plan: [Brief Description]
|
||||
|
||||
## Goal
|
||||
[One sentence describing the end state]
|
||||
|
||||
## Phases
|
||||
- [ ] Phase 1: Plan and setup
|
||||
- [ ] Phase 2: Research/gather information
|
||||
- [ ] Phase 3: Execute/build
|
||||
- [ ] Phase 4: Review and deliver
|
||||
|
||||
## Key Questions
|
||||
1. [Question to answer]
|
||||
2. [Question to answer]
|
||||
|
||||
## Decisions Made
|
||||
- [Decision]: [Rationale]
|
||||
|
||||
## Errors Encountered
|
||||
- [Error]: [Resolution]
|
||||
|
||||
## Status
|
||||
**Currently in Phase X** - [What I'm doing now]
|
||||
```
|
||||
|
||||
## notes.md Template
|
||||
|
||||
For research and findings:
|
||||
|
||||
```markdown
|
||||
# Notes: [Topic]
|
||||
|
||||
## Sources
|
||||
|
||||
### Source 1: [Name]
|
||||
- URL: [link]
|
||||
- Key points:
|
||||
- [Finding]
|
||||
- [Finding]
|
||||
|
||||
## Synthesized Findings
|
||||
|
||||
### [Category]
|
||||
- [Finding]
|
||||
- [Finding]
|
||||
```
|
||||
|
||||
## Critical Rules
|
||||
|
||||
### 1. ALWAYS Create Plan First
|
||||
Never start a complex task without `task_plan.md`. This is non-negotiable.
|
||||
|
||||
### 2. Read Before Decide
|
||||
Before any major decision, read the plan file. This keeps goals in your attention window.
|
||||
|
||||
### 3. Update After Act
|
||||
After completing any phase, immediately update the plan file:
|
||||
- Mark completed phases with [x]
|
||||
- Update the Status section
|
||||
- Log any errors encountered
|
||||
|
||||
### 4. Store, Don't Stuff
|
||||
Large outputs go to files, not context. Keep only paths in working memory.
|
||||
|
||||
### 5. Log All Errors
|
||||
Every error goes in the "Errors Encountered" section. This builds knowledge for future tasks.
|
||||
|
||||
## When to Use This Pattern
|
||||
|
||||
**Use 3-file pattern for:**
|
||||
- Multi-step tasks (3+ steps)
|
||||
- Research tasks
|
||||
- Building/creating something
|
||||
- Tasks spanning multiple tool calls
|
||||
- Anything requiring organization
|
||||
|
||||
**Skip for:**
|
||||
- Simple questions
|
||||
- Single-file edits
|
||||
- Quick lookups
|
||||
|
||||
## Anti-Patterns to Avoid
|
||||
|
||||
| Don't | Do Instead |
|
||||
|-------|------------|
|
||||
| Use TodoWrite for persistence | Create `task_plan.md` file |
|
||||
| State goals once and forget | Re-read plan before each decision |
|
||||
| Hide errors and retry | Log errors to plan file |
|
||||
| Stuff everything in context | Store large content in files |
|
||||
| Start executing immediately | Create plan file FIRST |
|
||||
|
||||
## Advanced Patterns
|
||||
|
||||
See [reference.md](reference.md) for:
|
||||
- Attention manipulation techniques
|
||||
- Error recovery patterns
|
||||
- Context optimization from Manus
|
||||
|
||||
See [examples.md](examples.md) for:
|
||||
- Real task examples
|
||||
- Complex workflow patterns
|
||||
@@ -0,0 +1,631 @@
|
||||
---
|
||||
name: react-patterns
|
||||
description: React component patterns with TypeScript examples. Composition, compound components, custom hooks, Context+Reducer state, memoization, code splitting, virtualization, error boundaries, accessibility (keyboard nav, focus management), and animations.
|
||||
---
|
||||
|
||||
# Frontend Development Patterns
|
||||
|
||||
Modern frontend patterns for React, Next.js, and performant user interfaces.
|
||||
|
||||
## Component Patterns
|
||||
|
||||
### Composition Over Inheritance
|
||||
|
||||
```typescript
|
||||
// ✅ GOOD: Component composition
|
||||
interface CardProps {
|
||||
children: React.ReactNode
|
||||
variant?: 'default' | 'outlined'
|
||||
}
|
||||
|
||||
export function Card({ children, variant = 'default' }: CardProps) {
|
||||
return <div className={`card card-${variant}`}>{children}</div>
|
||||
}
|
||||
|
||||
export function CardHeader({ children }: { children: React.ReactNode }) {
|
||||
return <div className="card-header">{children}</div>
|
||||
}
|
||||
|
||||
export function CardBody({ children }: { children: React.ReactNode }) {
|
||||
return <div className="card-body">{children}</div>
|
||||
}
|
||||
|
||||
// Usage
|
||||
<Card>
|
||||
<CardHeader>Title</CardHeader>
|
||||
<CardBody>Content</CardBody>
|
||||
</Card>
|
||||
```
|
||||
|
||||
### Compound Components
|
||||
|
||||
```typescript
|
||||
interface TabsContextValue {
|
||||
activeTab: string
|
||||
setActiveTab: (tab: string) => void
|
||||
}
|
||||
|
||||
const TabsContext = createContext<TabsContextValue | undefined>(undefined)
|
||||
|
||||
export function Tabs({ children, defaultTab }: {
|
||||
children: React.ReactNode
|
||||
defaultTab: string
|
||||
}) {
|
||||
const [activeTab, setActiveTab] = useState(defaultTab)
|
||||
|
||||
return (
|
||||
<TabsContext.Provider value={{ activeTab, setActiveTab }}>
|
||||
{children}
|
||||
</TabsContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function TabList({ children }: { children: React.ReactNode }) {
|
||||
return <div className="tab-list">{children}</div>
|
||||
}
|
||||
|
||||
export function Tab({ id, children }: { id: string, children: React.ReactNode }) {
|
||||
const context = useContext(TabsContext)
|
||||
if (!context) throw new Error('Tab must be used within Tabs')
|
||||
|
||||
return (
|
||||
<button
|
||||
className={context.activeTab === id ? 'active' : ''}
|
||||
onClick={() => context.setActiveTab(id)}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
// Usage
|
||||
<Tabs defaultTab="overview">
|
||||
<TabList>
|
||||
<Tab id="overview">Overview</Tab>
|
||||
<Tab id="details">Details</Tab>
|
||||
</TabList>
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
### Render Props Pattern
|
||||
|
||||
```typescript
|
||||
interface DataLoaderProps<T> {
|
||||
url: string
|
||||
children: (data: T | null, loading: boolean, error: Error | null) => React.ReactNode
|
||||
}
|
||||
|
||||
export function DataLoader<T>({ url, children }: DataLoaderProps<T>) {
|
||||
const [data, setData] = useState<T | null>(null)
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState<Error | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
fetch(url)
|
||||
.then(res => res.json())
|
||||
.then(setData)
|
||||
.catch(setError)
|
||||
.finally(() => setLoading(false))
|
||||
}, [url])
|
||||
|
||||
return <>{children(data, loading, error)}</>
|
||||
}
|
||||
|
||||
// Usage
|
||||
<DataLoader<Market[]> url="/api/markets">
|
||||
{(markets, loading, error) => {
|
||||
if (loading) return <Spinner />
|
||||
if (error) return <Error error={error} />
|
||||
return <MarketList markets={markets!} />
|
||||
}}
|
||||
</DataLoader>
|
||||
```
|
||||
|
||||
## Custom Hooks Patterns
|
||||
|
||||
### State Management Hook
|
||||
|
||||
```typescript
|
||||
export function useToggle(initialValue = false): [boolean, () => void] {
|
||||
const [value, setValue] = useState(initialValue)
|
||||
|
||||
const toggle = useCallback(() => {
|
||||
setValue(v => !v)
|
||||
}, [])
|
||||
|
||||
return [value, toggle]
|
||||
}
|
||||
|
||||
// Usage
|
||||
const [isOpen, toggleOpen] = useToggle()
|
||||
```
|
||||
|
||||
### Async Data Fetching Hook
|
||||
|
||||
```typescript
|
||||
interface UseQueryOptions<T> {
|
||||
onSuccess?: (data: T) => void
|
||||
onError?: (error: Error) => void
|
||||
enabled?: boolean
|
||||
}
|
||||
|
||||
export function useQuery<T>(
|
||||
key: string,
|
||||
fetcher: () => Promise<T>,
|
||||
options?: UseQueryOptions<T>
|
||||
) {
|
||||
const [data, setData] = useState<T | null>(null)
|
||||
const [error, setError] = useState<Error | null>(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const refetch = useCallback(async () => {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
|
||||
try {
|
||||
const result = await fetcher()
|
||||
setData(result)
|
||||
options?.onSuccess?.(result)
|
||||
} catch (err) {
|
||||
const error = err as Error
|
||||
setError(error)
|
||||
options?.onError?.(error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}, [fetcher, options])
|
||||
|
||||
useEffect(() => {
|
||||
if (options?.enabled !== false) {
|
||||
refetch()
|
||||
}
|
||||
}, [key, refetch, options?.enabled])
|
||||
|
||||
return { data, error, loading, refetch }
|
||||
}
|
||||
|
||||
// Usage
|
||||
const { data: markets, loading, error, refetch } = useQuery(
|
||||
'markets',
|
||||
() => fetch('/api/markets').then(r => r.json()),
|
||||
{
|
||||
onSuccess: data => console.log('Fetched', data.length, 'markets'),
|
||||
onError: err => console.error('Failed:', err)
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
### Debounce Hook
|
||||
|
||||
```typescript
|
||||
export function useDebounce<T>(value: T, delay: number): T {
|
||||
const [debouncedValue, setDebouncedValue] = useState<T>(value)
|
||||
|
||||
useEffect(() => {
|
||||
const handler = setTimeout(() => {
|
||||
setDebouncedValue(value)
|
||||
}, delay)
|
||||
|
||||
return () => clearTimeout(handler)
|
||||
}, [value, delay])
|
||||
|
||||
return debouncedValue
|
||||
}
|
||||
|
||||
// Usage
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const debouncedQuery = useDebounce(searchQuery, 500)
|
||||
|
||||
useEffect(() => {
|
||||
if (debouncedQuery) {
|
||||
performSearch(debouncedQuery)
|
||||
}
|
||||
}, [debouncedQuery])
|
||||
```
|
||||
|
||||
## State Management Patterns
|
||||
|
||||
### Context + Reducer Pattern
|
||||
|
||||
```typescript
|
||||
interface State {
|
||||
markets: Market[]
|
||||
selectedMarket: Market | null
|
||||
loading: boolean
|
||||
}
|
||||
|
||||
type Action =
|
||||
| { type: 'SET_MARKETS'; payload: Market[] }
|
||||
| { type: 'SELECT_MARKET'; payload: Market }
|
||||
| { type: 'SET_LOADING'; payload: boolean }
|
||||
|
||||
function reducer(state: State, action: Action): State {
|
||||
switch (action.type) {
|
||||
case 'SET_MARKETS':
|
||||
return { ...state, markets: action.payload }
|
||||
case 'SELECT_MARKET':
|
||||
return { ...state, selectedMarket: action.payload }
|
||||
case 'SET_LOADING':
|
||||
return { ...state, loading: action.payload }
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
const MarketContext = createContext<{
|
||||
state: State
|
||||
dispatch: Dispatch<Action>
|
||||
} | undefined>(undefined)
|
||||
|
||||
export function MarketProvider({ children }: { children: React.ReactNode }) {
|
||||
const [state, dispatch] = useReducer(reducer, {
|
||||
markets: [],
|
||||
selectedMarket: null,
|
||||
loading: false
|
||||
})
|
||||
|
||||
return (
|
||||
<MarketContext.Provider value={{ state, dispatch }}>
|
||||
{children}
|
||||
</MarketContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function useMarkets() {
|
||||
const context = useContext(MarketContext)
|
||||
if (!context) throw new Error('useMarkets must be used within MarketProvider')
|
||||
return context
|
||||
}
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Memoization
|
||||
|
||||
```typescript
|
||||
// ✅ useMemo for expensive computations
|
||||
const sortedMarkets = useMemo(() => {
|
||||
return markets.sort((a, b) => b.volume - a.volume)
|
||||
}, [markets])
|
||||
|
||||
// ✅ useCallback for functions passed to children
|
||||
const handleSearch = useCallback((query: string) => {
|
||||
setSearchQuery(query)
|
||||
}, [])
|
||||
|
||||
// ✅ React.memo for pure components
|
||||
export const MarketCard = React.memo<MarketCardProps>(({ market }) => {
|
||||
return (
|
||||
<div className="market-card">
|
||||
<h3>{market.name}</h3>
|
||||
<p>{market.description}</p>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
```
|
||||
|
||||
### Code Splitting & Lazy Loading
|
||||
|
||||
```typescript
|
||||
import { lazy, Suspense } from 'react'
|
||||
|
||||
// ✅ Lazy load heavy components
|
||||
const HeavyChart = lazy(() => import('./HeavyChart'))
|
||||
const ThreeJsBackground = lazy(() => import('./ThreeJsBackground'))
|
||||
|
||||
export function Dashboard() {
|
||||
return (
|
||||
<div>
|
||||
<Suspense fallback={<ChartSkeleton />}>
|
||||
<HeavyChart data={data} />
|
||||
</Suspense>
|
||||
|
||||
<Suspense fallback={null}>
|
||||
<ThreeJsBackground />
|
||||
</Suspense>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Virtualization for Long Lists
|
||||
|
||||
```typescript
|
||||
import { useVirtualizer } from '@tanstack/react-virtual'
|
||||
|
||||
export function VirtualMarketList({ markets }: { markets: Market[] }) {
|
||||
const parentRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const virtualizer = useVirtualizer({
|
||||
count: markets.length,
|
||||
getScrollElement: () => parentRef.current,
|
||||
estimateSize: () => 100, // Estimated row height
|
||||
overscan: 5 // Extra items to render
|
||||
})
|
||||
|
||||
return (
|
||||
<div ref={parentRef} style={{ height: '600px', overflow: 'auto' }}>
|
||||
<div
|
||||
style={{
|
||||
height: `${virtualizer.getTotalSize()}px`,
|
||||
position: 'relative'
|
||||
}}
|
||||
>
|
||||
{virtualizer.getVirtualItems().map(virtualRow => (
|
||||
<div
|
||||
key={virtualRow.index}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: `${virtualRow.size}px`,
|
||||
transform: `translateY(${virtualRow.start}px)`
|
||||
}}
|
||||
>
|
||||
<MarketCard market={markets[virtualRow.index]} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Form Handling Patterns
|
||||
|
||||
### Controlled Form with Validation
|
||||
|
||||
```typescript
|
||||
interface FormData {
|
||||
name: string
|
||||
description: string
|
||||
endDate: string
|
||||
}
|
||||
|
||||
interface FormErrors {
|
||||
name?: string
|
||||
description?: string
|
||||
endDate?: string
|
||||
}
|
||||
|
||||
export function CreateMarketForm() {
|
||||
const [formData, setFormData] = useState<FormData>({
|
||||
name: '',
|
||||
description: '',
|
||||
endDate: ''
|
||||
})
|
||||
|
||||
const [errors, setErrors] = useState<FormErrors>({})
|
||||
|
||||
const validate = (): boolean => {
|
||||
const newErrors: FormErrors = {}
|
||||
|
||||
if (!formData.name.trim()) {
|
||||
newErrors.name = 'Name is required'
|
||||
} else if (formData.name.length > 200) {
|
||||
newErrors.name = 'Name must be under 200 characters'
|
||||
}
|
||||
|
||||
if (!formData.description.trim()) {
|
||||
newErrors.description = 'Description is required'
|
||||
}
|
||||
|
||||
if (!formData.endDate) {
|
||||
newErrors.endDate = 'End date is required'
|
||||
}
|
||||
|
||||
setErrors(newErrors)
|
||||
return Object.keys(newErrors).length === 0
|
||||
}
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
|
||||
if (!validate()) return
|
||||
|
||||
try {
|
||||
await createMarket(formData)
|
||||
// Success handling
|
||||
} catch (error) {
|
||||
// Error handling
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<input
|
||||
value={formData.name}
|
||||
onChange={e => setFormData(prev => ({ ...prev, name: e.target.value }))}
|
||||
placeholder="Market name"
|
||||
/>
|
||||
{errors.name && <span className="error">{errors.name}</span>}
|
||||
|
||||
{/* Other fields */}
|
||||
|
||||
<button type="submit">Create Market</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Error Boundary Pattern
|
||||
|
||||
```typescript
|
||||
interface ErrorBoundaryState {
|
||||
hasError: boolean
|
||||
error: Error | null
|
||||
}
|
||||
|
||||
export class ErrorBoundary extends React.Component<
|
||||
{ children: React.ReactNode },
|
||||
ErrorBoundaryState
|
||||
> {
|
||||
state: ErrorBoundaryState = {
|
||||
hasError: false,
|
||||
error: null
|
||||
}
|
||||
|
||||
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
|
||||
return { hasError: true, error }
|
||||
}
|
||||
|
||||
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
|
||||
console.error('Error boundary caught:', error, errorInfo)
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return (
|
||||
<div className="error-fallback">
|
||||
<h2>Something went wrong</h2>
|
||||
<p>{this.state.error?.message}</p>
|
||||
<button onClick={() => this.setState({ hasError: false })}>
|
||||
Try again
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return this.props.children
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
<ErrorBoundary>
|
||||
<App />
|
||||
</ErrorBoundary>
|
||||
```
|
||||
|
||||
## Animation Patterns
|
||||
|
||||
### Framer Motion Animations
|
||||
|
||||
```typescript
|
||||
import { motion, AnimatePresence } from 'framer-motion'
|
||||
|
||||
// ✅ List animations
|
||||
export function AnimatedMarketList({ markets }: { markets: Market[] }) {
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{markets.map(market => (
|
||||
<motion.div
|
||||
key={market.id}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -20 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
<MarketCard market={market} />
|
||||
</motion.div>
|
||||
))}
|
||||
</AnimatePresence>
|
||||
)
|
||||
}
|
||||
|
||||
// ✅ Modal animations
|
||||
export function Modal({ isOpen, onClose, children }: ModalProps) {
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<>
|
||||
<motion.div
|
||||
className="modal-overlay"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
onClick={onClose}
|
||||
/>
|
||||
<motion.div
|
||||
className="modal-content"
|
||||
initial={{ opacity: 0, scale: 0.9, y: 20 }}
|
||||
animate={{ opacity: 1, scale: 1, y: 0 }}
|
||||
exit={{ opacity: 0, scale: 0.9, y: 20 }}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
</>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Accessibility Patterns
|
||||
|
||||
### Keyboard Navigation
|
||||
|
||||
```typescript
|
||||
export function Dropdown({ options, onSelect }: DropdownProps) {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const [activeIndex, setActiveIndex] = useState(0)
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||
switch (e.key) {
|
||||
case 'ArrowDown':
|
||||
e.preventDefault()
|
||||
setActiveIndex(i => Math.min(i + 1, options.length - 1))
|
||||
break
|
||||
case 'ArrowUp':
|
||||
e.preventDefault()
|
||||
setActiveIndex(i => Math.max(i - 1, 0))
|
||||
break
|
||||
case 'Enter':
|
||||
e.preventDefault()
|
||||
onSelect(options[activeIndex])
|
||||
setIsOpen(false)
|
||||
break
|
||||
case 'Escape':
|
||||
setIsOpen(false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
role="combobox"
|
||||
aria-expanded={isOpen}
|
||||
aria-haspopup="listbox"
|
||||
onKeyDown={handleKeyDown}
|
||||
>
|
||||
{/* Dropdown implementation */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Focus Management
|
||||
|
||||
```typescript
|
||||
export function Modal({ isOpen, onClose, children }: ModalProps) {
|
||||
const modalRef = useRef<HTMLDivElement>(null)
|
||||
const previousFocusRef = useRef<HTMLElement | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
// Save currently focused element
|
||||
previousFocusRef.current = document.activeElement as HTMLElement
|
||||
|
||||
// Focus modal
|
||||
modalRef.current?.focus()
|
||||
} else {
|
||||
// Restore focus when closing
|
||||
previousFocusRef.current?.focus()
|
||||
}
|
||||
}, [isOpen])
|
||||
|
||||
return isOpen ? (
|
||||
<div
|
||||
ref={modalRef}
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
tabIndex={-1}
|
||||
onKeyDown={e => e.key === 'Escape' && onClose()}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
```
|
||||
|
||||
**Remember**: Modern frontend patterns enable maintainable, performant user interfaces. Choose patterns that fit your project complexity.
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
name: vercel-react-best-practices
|
||||
description: React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
|
||||
---
|
||||
|
||||
# Vercel React Best Practices
|
||||
|
||||
Comprehensive performance optimization guide for React and Next.js applications, maintained by Vercel. Contains 45 rules across 8 categories, prioritized by impact to guide automated refactoring and code generation.
|
||||
|
||||
## When to Apply
|
||||
|
||||
Reference these guidelines when:
|
||||
- Writing new React components or Next.js pages
|
||||
- Implementing data fetching (client or server-side)
|
||||
- Reviewing code for performance issues
|
||||
- Refactoring existing React/Next.js code
|
||||
- Optimizing bundle size or load times
|
||||
|
||||
## Rule Categories by Priority
|
||||
|
||||
| Priority | Category | Impact | Prefix |
|
||||
|----------|----------|--------|--------|
|
||||
| 1 | Eliminating Waterfalls | CRITICAL | `async-` |
|
||||
| 2 | Bundle Size Optimization | CRITICAL | `bundle-` |
|
||||
| 3 | Server-Side Performance | HIGH | `server-` |
|
||||
| 4 | Client-Side Data Fetching | MEDIUM-HIGH | `client-` |
|
||||
| 5 | Re-render Optimization | MEDIUM | `rerender-` |
|
||||
| 6 | Rendering Performance | MEDIUM | `rendering-` |
|
||||
| 7 | JavaScript Performance | LOW-MEDIUM | `js-` |
|
||||
| 8 | Advanced Patterns | LOW | `advanced-` |
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### 1. Eliminating Waterfalls (CRITICAL)
|
||||
|
||||
- `async-defer-await` - Move await into branches where actually used
|
||||
- `async-parallel` - Use Promise.all() for independent operations
|
||||
- `async-dependencies` - Use better-all for partial dependencies
|
||||
- `async-api-routes` - Start promises early, await late in API routes
|
||||
- `async-suspense-boundaries` - Use Suspense to stream content
|
||||
|
||||
### 2. Bundle Size Optimization (CRITICAL)
|
||||
|
||||
- `bundle-barrel-imports` - Import directly, avoid barrel files
|
||||
- `bundle-dynamic-imports` - Use next/dynamic for heavy components
|
||||
- `bundle-defer-third-party` - Load analytics/logging after hydration
|
||||
- `bundle-conditional` - Load modules only when feature is activated
|
||||
- `bundle-preload` - Preload on hover/focus for perceived speed
|
||||
|
||||
### 3. Server-Side Performance (HIGH)
|
||||
|
||||
- `server-cache-react` - Use React.cache() for per-request deduplication
|
||||
- `server-cache-lru` - Use LRU cache for cross-request caching
|
||||
- `server-serialization` - Minimize data passed to client components
|
||||
- `server-parallel-fetching` - Restructure components to parallelize fetches
|
||||
- `server-after-nonblocking` - Use after() for non-blocking operations
|
||||
|
||||
### 4. Client-Side Data Fetching (MEDIUM-HIGH)
|
||||
|
||||
- `client-swr-dedup` - Use SWR for automatic request deduplication
|
||||
- `client-event-listeners` - Deduplicate global event listeners
|
||||
|
||||
### 5. Re-render Optimization (MEDIUM)
|
||||
|
||||
- `rerender-defer-reads` - Don't subscribe to state only used in callbacks
|
||||
- `rerender-memo` - Extract expensive work into memoized components
|
||||
- `rerender-dependencies` - Use primitive dependencies in effects
|
||||
- `rerender-derived-state` - Subscribe to derived booleans, not raw values
|
||||
- `rerender-functional-setstate` - Use functional setState for stable callbacks
|
||||
- `rerender-lazy-state-init` - Pass function to useState for expensive values
|
||||
- `rerender-transitions` - Use startTransition for non-urgent updates
|
||||
|
||||
### 6. Rendering Performance (MEDIUM)
|
||||
|
||||
- `rendering-animate-svg-wrapper` - Animate div wrapper, not SVG element
|
||||
- `rendering-content-visibility` - Use content-visibility for long lists
|
||||
- `rendering-hoist-jsx` - Extract static JSX outside components
|
||||
- `rendering-svg-precision` - Reduce SVG coordinate precision
|
||||
- `rendering-hydration-no-flicker` - Use inline script for client-only data
|
||||
- `rendering-activity` - Use Activity component for show/hide
|
||||
- `rendering-conditional-render` - Use ternary, not && for conditionals
|
||||
|
||||
### 7. JavaScript Performance (LOW-MEDIUM)
|
||||
|
||||
- `js-batch-dom-css` - Group CSS changes via classes or cssText
|
||||
- `js-index-maps` - Build Map for repeated lookups
|
||||
- `js-cache-property-access` - Cache object properties in loops
|
||||
- `js-cache-function-results` - Cache function results in module-level Map
|
||||
- `js-cache-storage` - Cache localStorage/sessionStorage reads
|
||||
- `js-combine-iterations` - Combine multiple filter/map into one loop
|
||||
- `js-length-check-first` - Check array length before expensive comparison
|
||||
- `js-early-exit` - Return early from functions
|
||||
- `js-hoist-regexp` - Hoist RegExp creation outside loops
|
||||
- `js-min-max-loop` - Use loop for min/max instead of sort
|
||||
- `js-set-map-lookups` - Use Set/Map for O(1) lookups
|
||||
- `js-tosorted-immutable` - Use toSorted() for immutability
|
||||
|
||||
### 8. Advanced Patterns (LOW)
|
||||
|
||||
- `advanced-event-handler-refs` - Store event handlers in refs
|
||||
- `advanced-use-latest` - useLatest for stable callback refs
|
||||
|
||||
## How to Use
|
||||
|
||||
Read individual rule files for detailed explanations and code examples:
|
||||
|
||||
```
|
||||
rules/async-parallel.md
|
||||
rules/bundle-barrel-imports.md
|
||||
rules/_sections.md
|
||||
```
|
||||
|
||||
Each rule file contains:
|
||||
- Brief explanation of why it matters
|
||||
- Incorrect code example with explanation
|
||||
- Correct code example with explanation
|
||||
- Additional context and references
|
||||
|
||||
## Full Compiled Document
|
||||
|
||||
For the complete guide with all rules expanded: `AGENTS.md`
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
ralph-claude-code = pkgs.callPackage ../../../pkgs/ralph-claude-code/package.nix { };
|
||||
in
|
||||
{
|
||||
home.packages = [ ralph-claude-code ];
|
||||
}
|
||||
@@ -5,16 +5,27 @@
|
||||
bacon
|
||||
mprocs
|
||||
pkg-config
|
||||
openssl
|
||||
openssl.dev
|
||||
taplo
|
||||
sccache
|
||||
mold
|
||||
clang
|
||||
];
|
||||
|
||||
home.sessionPath = [ "\${CARGO_HOME:-~/.cargo}/bin" ];
|
||||
home.sessionPath = [ "\${CARGO_HOME:-$HOME/.cargo}/bin" ];
|
||||
|
||||
systemd.user.services.ra-multiplex = {
|
||||
Service = {
|
||||
ExecStart = "${pkgs.ra-multiplex}/bin/ra-multiplex server";
|
||||
};
|
||||
Install.WantedBy = [ "default.target" ];
|
||||
home.file.".cargo/config.toml".text = ''
|
||||
[target.x86_64-unknown-linux-gnu]
|
||||
linker = "clang"
|
||||
rustflags = ["-C", "link-arg=-fuse-ld=mold"]
|
||||
|
||||
[build]
|
||||
rustflags = ["-Z", "threads=12"]
|
||||
'';
|
||||
|
||||
home.sessionVariables = {
|
||||
OPENSSL_DIR = "${pkgs.openssl.dev}";
|
||||
OPENSSL_LIB_DIR = "${pkgs.openssl.out}/lib";
|
||||
OPENSSL_INCLUDE_DIR = "${pkgs.openssl.dev}/include";
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
_:
|
||||
{
|
||||
programs.ssh = {
|
||||
enable = true;
|
||||
|
||||
# Opt out of the soon-to-be-removed implicit `settings."*"` defaults.
|
||||
# They only ever matched OpenSSH's own defaults, so nothing is lost.
|
||||
enableDefaultConfig = false;
|
||||
|
||||
# `settings` is a freeform block set: attribute names are Host/Match
|
||||
# patterns, values use OpenSSH directive names directly.
|
||||
settings = {
|
||||
"*" = {
|
||||
# Connection multiplexing — reuse one TCP/auth connection for
|
||||
# repeated ssh/git/scp to the same host. `%C` is a hash, so no
|
||||
# parent directory needs pre-creating.
|
||||
ControlMaster = "auto";
|
||||
ControlPath = "~/.ssh/control-%C";
|
||||
ControlPersist = "10m";
|
||||
|
||||
# Keep idle sessions alive; drop genuinely dead ones after ~3 min.
|
||||
ServerAliveInterval = 60;
|
||||
ServerAliveCountMax = 3;
|
||||
|
||||
# Load the key into the (gpg-)agent on first use — passphrase once
|
||||
# per session. Requires services.gpg-agent.enableSshSupport.
|
||||
AddKeysToAgent = "yes";
|
||||
};
|
||||
|
||||
"yolo" = {
|
||||
HostName = "10.7.10.2";
|
||||
RemoteForward = [
|
||||
{
|
||||
bind.port = 9222;
|
||||
host.address = "localhost";
|
||||
host.port = 9222;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
services.syncthing = {
|
||||
enable = true;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
programs.tmux = {
|
||||
enable = true;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
unityhub
|
||||
omnisharp-roslyn
|
||||
vscode
|
||||
dotnet-sdk
|
||||
icu
|
||||
stdenv.cc.cc.lib
|
||||
];
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user