Compare commits

...

3 Commits

Author SHA1 Message Date
m3tm3re
6e6e819150 project-launcher changes 2026-01-06 05:54:39 +01:00
m3tm3re
5f8b5dbcdc bd sync: 2026-01-05 12:50:04 2026-01-05 12:50:04 +01:00
m3tm3re
586d199497 bd sync: 2026-01-05 12:46:30 2026-01-05 12:46:30 +01:00
6 changed files with 122 additions and 56 deletions

View File

@@ -1,2 +1,6 @@
{"id":"nixpkgs-hrh","title":"projectDirs on rofi-project-switcher should be exported to users home-manager environment","status":"open","priority":2,"issue_type":"feature","created_at":"2026-01-05T11:46:43.640224459+01:00","created_by":"m3tam3re","updated_at":"2026-01-05T11:48:29.222863787+01:00"}
{"id":"nixpkgs-w3u","title":"projectDirs should support args, for example --agent \u003cagentname\u003e","description":"This means project directories need to be an attribute set and we also need to change the launch command to \"opencode \u003cdirectory name\u003e \u003carguments\u003e\".\n","status":"open","priority":2,"issue_type":"feature","created_at":"2026-01-05T11:56:13.844735432+01:00","created_by":"m3tam3re","updated_at":"2026-01-05T12:03:38.74441203+01:00"}
{"id":"nixpkgs-3k8","title":"Export project config as environment variable","description":"Export project configuration as home.sessionVariables (similar to zellij-ps pattern). Use JSON format for the env var since projects now have structured data (path + args).","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-05T12:45:50.803017318+01:00","created_by":"m3tam3re","updated_at":"2026-01-05T12:48:22.968626155+01:00","closed_at":"2026-01-05T12:48:22.968626155+01:00","close_reason":"Added home.sessionVariables.ROFI_PROJECT_OPENER_CONFIG with JSON config","dependencies":[{"issue_id":"nixpkgs-3k8","depends_on_id":"nixpkgs-hrh","type":"parent-child","created_at":"2026-01-05T12:46:03.16885012+01:00","created_by":"m3tam3re"}]}
{"id":"nixpkgs-5ml","title":"Update rofi-project-opener script to pass args to opencode","description":"Modify pkgs/rofi-project-opener script to read the new config format and launch opencode with: 'opencode \u003cdirectory\u003e \u003carguments\u003e' instead of just 'opencode' in the directory.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-05T12:45:49.748958951+01:00","created_by":"m3tam3re","updated_at":"2026-01-05T12:49:40.800083615+01:00","closed_at":"2026-01-05T12:49:40.800083615+01:00","close_reason":"Script updated to read JSON config and pass args to opencode","dependencies":[{"issue_id":"nixpkgs-5ml","depends_on_id":"nixpkgs-w3u","type":"parent-child","created_at":"2026-01-05T12:46:02.338350208+01:00","created_by":"m3tam3re"},{"issue_id":"nixpkgs-5ml","depends_on_id":"nixpkgs-sys","type":"blocks","created_at":"2026-01-05T12:46:04.966269033+01:00","created_by":"m3tam3re"}]}
{"id":"nixpkgs-e2u","title":"Change projectDirs from list to attrset with path and args","description":"Change projectDirs option type from 'types.listOf types.str' to an attrset like:\n\nprojectDirs = {\n nixpkgs = { path = \"~/p/NIX/nixpkgs\"; args = \"--agent Planner-Sisyphus\"; };\n myproject = { path = \"~/dev/myproject\"; }; # args optional\n};\n\nMust maintain backward compatibility consideration.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-05T12:45:48.6992807+01:00","created_by":"m3tam3re","updated_at":"2026-01-05T12:48:12.178120719+01:00","closed_at":"2026-01-05T12:48:12.178120719+01:00","close_reason":"Changed projectDirs from listOf str to attrsOf submodule with path+args","dependencies":[{"issue_id":"nixpkgs-e2u","depends_on_id":"nixpkgs-w3u","type":"parent-child","created_at":"2026-01-05T12:46:00.515400521+01:00","created_by":"m3tam3re"}]}
{"id":"nixpkgs-hrh","title":"projectDirs on rofi-project-switcher should be exported to users home-manager environment","status":"closed","priority":2,"issue_type":"feature","created_at":"2026-01-05T11:46:43.640224459+01:00","created_by":"m3tam3re","updated_at":"2026-01-05T12:49:43.584087541+01:00","closed_at":"2026-01-05T12:49:43.584087541+01:00","close_reason":"Feature complete: config exported as ROFI_PROJECT_OPENER_CONFIG env var","dependencies":[{"issue_id":"nixpkgs-hrh","depends_on_id":"nixpkgs-w3u","type":"blocks","created_at":"2026-01-05T12:46:05.867959608+01:00","created_by":"m3tam3re"}]}
{"id":"nixpkgs-sys","title":"Update config file format to include args per project","description":"Update the config file at ~/.config/rofi-project-opener/config to support per-project args. Change from PROJECT_DIRS to a format that encodes both path and args, e.g. JSON or structured text.","status":"closed","priority":1,"issue_type":"task","created_at":"2026-01-05T12:45:51.793810575+01:00","created_by":"m3tam3re","updated_at":"2026-01-05T12:48:21.75755315+01:00","closed_at":"2026-01-05T12:48:21.75755315+01:00","close_reason":"Config file now writes JSON (projects.json) with per-project path and args","dependencies":[{"issue_id":"nixpkgs-sys","depends_on_id":"nixpkgs-w3u","type":"parent-child","created_at":"2026-01-05T12:46:01.400263722+01:00","created_by":"m3tam3re"},{"issue_id":"nixpkgs-sys","depends_on_id":"nixpkgs-e2u","type":"blocks","created_at":"2026-01-05T12:46:04.055948778+01:00","created_by":"m3tam3re"}]}
{"id":"nixpkgs-w3u","title":"projectDirs should support args, for example --agent \u003cagentname\u003e","description":"This means project directories need to be an attribute set and we also need to change the launch command to \"opencode \u003cdirectory name\u003e \u003carguments\u003e\".\n","status":"closed","priority":2,"issue_type":"feature","created_at":"2026-01-05T11:56:13.844735432+01:00","created_by":"m3tam3re","updated_at":"2026-01-05T12:49:42.34144046+01:00","closed_at":"2026-01-05T12:49:42.34144046+01:00","close_reason":"Feature complete: projectDirs now supports args per directory"}

4
.beads/metadata.json Normal file
View File

@@ -0,0 +1,4 @@
{
"database": "beads.db",
"jsonl_export": "issues.jsonl"
}

View File

@@ -46,6 +46,7 @@ nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#zellij-ps
| `mem0` | AI memory assistant with vector storage |
| `msty-studio` | Msty Studio application |
| `pomodoro-timer` | Pomodoro timer utility |
| `rofi-project-opener` | Rofi-based project launcher |
| `stt-ptt` | Push to Talk Speech to Text |
| `tuxedo-backlight` | Backlight control for Tuxedo laptops |
| `zellij-ps` | Project switcher for Zellij |

View File

@@ -34,6 +34,7 @@ Documentation for all custom packages:
- [mem0](./packages/mem0.md) - AI memory assistant with vector storage
- [msty-studio](./packages/msty-studio.md) - Msty Studio application
- [pomodoro-timer](./packages/pomodoro-timer.md) - Pomodoro timer utility
- [rofi-project-opener](./packages/rofi-project-opener.md) - Rofi-based project launcher with custom args
- [stt-ptt](./packages/stt-ptt.md) - Push to Talk Speech to Text using Whisper
- [tuxedo-backlight](./packages/tuxedo-backlight.md) - Backlight control for Tuxedo laptops
- [zellij-ps](./packages/zellij-ps.md) - Project switcher for Zellij
@@ -50,6 +51,7 @@ Configuration modules for NixOS and Home Manager:
#### Home Manager Modules
- [Overview](./modules/home-manager/overview.md) - Home Manager modules overview
- [CLI Tools](./modules/home-manager/cli/) - CLI-related modules
- [rofi-project-opener](./modules/home-manager/cli/rofi-project-opener.md) - Rofi-based project launcher
- [stt-ptt](./modules/home-manager/cli/stt-ptt.md) - Push to Talk Speech to Text
- [zellij-ps](./modules/home-manager/cli/zellij-ps.md) - Zellij project switcher
- [Coding](./modules/home-manager/coding/) - Development-related modules

View File

@@ -7,23 +7,56 @@
with lib; let
cfg = config.cli.rofi-project-opener;
# Convert list of paths to colon-separated string
projectDirsStr = concatStringsSep ":" cfg.projectDirs;
# Project directory submodule type
projectDirType = types.submodule {
options = {
path = mkOption {
type = types.str;
description = "Base directory path to scan for project subdirectories.";
example = "~/dev";
};
args = mkOption {
type = types.str;
default = "";
description = "Additional arguments to pass to opencode when launching projects from this directory.";
example = "--agent Planner-Sisyphus";
};
};
};
# Convert projectDirs attrset to JSON for config file
projectDirsJson = builtins.toJSON (
mapAttrs (name: value: {
path = value.path;
args = value.args;
}) cfg.projectDirs
);
in {
options.cli.rofi-project-opener = {
enable = mkEnableOption "Rofi-based project directory launcher";
projectDirs = mkOption {
type = types.listOf types.str;
default = ["~/dev" "~/projects"];
type = types.attrsOf projectDirType;
default = {
dev = { path = "~/dev"; };
projects = { path = "~/projects"; };
};
description = ''
List of base directories to scan for project subdirectories.
Attribute set of base directories to scan for project subdirectories.
Each directory will be scanned for immediate subdirectories (non-hidden).
Projects are displayed as "base_dir/project_name" in rofi.
Supports ~ for home directory expansion.
Each entry can specify:
- path: Base directory path (supports ~ for home directory)
- args: Optional arguments to pass to opencode for projects in this directory
'';
example = literalExpression ''
{
nixpkgs = { path = "~/p/NIX/nixpkgs"; args = "--agent Planner-Sisyphus"; };
dev = { path = "~/dev"; };
work = { path = "~/work"; args = "--agent work-agent"; };
}
'';
example = literalExpression ''["~/dev" "~/projects" "~/code"]'';
};
terminal = mkOption {
@@ -37,17 +70,21 @@ in {
type = types.str;
default = "";
description = ''
Custom command to pass to the terminal.
Custom command to run in the terminal.
Use %s as a placeholder for the project path.
If empty, defaults to opening a shell in the project directory and running opencode.
Placeholders:
- %s = project path
- %a = project args (from projectDirs.<name>.args)
If empty, defaults to: cd to project, run "opencode %a"
Examples:
- "" (empty) - Uses default: cd to project, run opencode
- "-e zsh -c 'cd %s && opencode'" - Custom shell with explicit path
- "--hold -e nvim" - Open editor directly (no %s = no cd)
- "" (empty) - Uses default: cd to project, run opencode with args
- "opencode %a" - Run opencode with project-specific args
- "nvim" - Open editor (no args)
- "myapp %s %a" - Custom app with path and args
'';
example = literalExpression ''"-e zsh -c 'cd %s && opencode'"'';
example = literalExpression ''"opencode %a"'';
};
rofiPrompt = mkOption {
@@ -77,10 +114,12 @@ in {
config = mkIf cfg.enable {
home.packages = [pkgs.rofi-project-opener];
# Write config file (shell-independent)
# Write JSON config file for project directories
xdg.configFile."rofi-project-opener/projects.json".text = projectDirsJson;
# Write shell config file for other settings
xdg.configFile."rofi-project-opener/config".text = ''
# rofi-project-opener configuration
PROJECT_DIRS="${projectDirsStr}"
TERMINAL="${if isDerivation cfg.terminal then "${cfg.terminal}/bin/${cfg.terminal.pname or (builtins.baseNameOf (toString cfg.terminal))}" else cfg.terminal}"
${optionalString (cfg.terminalCommand != "") ''TERMINAL_CMD="${cfg.terminalCommand}"''}
ROFI_PROMPT="${cfg.rofiPrompt}"

View File

@@ -1,11 +1,11 @@
{
lib,
writeShellScriptBin,
rofi,
libnotify,
coreutils,
gnugrep,
gnused,
jq,
}:
writeShellScriptBin "rofi-project-opener" ''
#!/usr/bin/env bash
@@ -24,9 +24,12 @@ writeShellScriptBin "rofi-project-opener" ''
BASENAME="${coreutils}/bin/basename"
GREP="${gnugrep}/bin/grep"
SED="${gnused}/bin/sed"
JQ="${jq}/bin/jq"
# Configuration from config file or environment variables
CONFIG_FILE="''${XDG_CONFIG_HOME:-$HOME/.config}/rofi-project-opener/config"
# Configuration files
CONFIG_DIR="''${XDG_CONFIG_HOME:-$HOME/.config}/rofi-project-opener"
CONFIG_FILE="$CONFIG_DIR/config"
PROJECTS_JSON="$CONFIG_DIR/projects.json"
if [[ -f "$CONFIG_FILE" ]]; then
# shellcheck disable=SC1090
@@ -34,12 +37,19 @@ writeShellScriptBin "rofi-project-opener" ''
fi
# Fallback to environment variables or defaults
PROJECT_DIRS="''${PROJECT_DIRS:-$HOME}"
TERMINAL="''${TERMINAL:-kitty}"
TERMINAL_CMD="''${TERMINAL_CMD:-}"
ROFI_PROMPT="''${ROFI_PROMPT:-Select project}"
ROFI_ARGS="''${ROFI_ARGS:--dmenu -i}"
# Check for projects.json
if [[ ! -f "$PROJECTS_JSON" ]]; then
echo "[rofi-project-opener] Error: No projects.json found at $PROJECTS_JSON" >&2
"$NOTIFY" -u critical -a "rofi-project-opener" "No projects.json configuration found"
exit 1
fi
PROJECTS_JSON_DATA="$(cat "$PROJECTS_JSON")"
# Temporary file for project list
PROJECTS_LIST="''${XDG_RUNTIME_DIR:-/tmp}/rofi-project-opener.$$"
@@ -59,26 +69,33 @@ writeShellScriptBin "rofi-project-opener" ''
"$NOTIFY" -u critical -a "rofi-project-opener" "$message"
}
# Build list of projects
# Build list of projects from JSON config
# Format: display_name|full_path|args
build_project_list() {
> "$PROJECTS_LIST"
# Split PROJECT_DIRS by colon and iterate
IFS=':' read -ra DIR_ARRAY <<< "$PROJECT_DIRS"
for base_dir in "''${DIR_ARRAY[@]}"; do
# Parse JSON and iterate over each base directory entry
local keys
keys=$(echo "$PROJECTS_JSON_DATA" | "$JQ" -r 'keys[]')
for key in $keys; do
local base_path base_args
base_path=$(echo "$PROJECTS_JSON_DATA" | "$JQ" -r --arg k "$key" '.[$k].path')
base_args=$(echo "$PROJECTS_JSON_DATA" | "$JQ" -r --arg k "$key" '.[$k].args // ""')
# Expand ~ to $HOME
base_dir="''${base_dir/#\~/$HOME}"
base_path="''${base_path/#\~/$HOME}"
# Expand $HOME variable (allows both ~ and $HOME in config)
base_dir="$(eval echo "$base_dir")"
base_path="$(eval echo "$base_path")"
# Skip if directory doesn't exist
if [[ ! -d "$base_dir" ]]; then
echo "[rofi-project-opener] Warning: Directory does not exist: $base_dir" >&2
if [[ ! -d "$base_path" ]]; then
echo "[rofi-project-opener] Warning: Directory does not exist: $base_path" >&2
continue
fi
# Find 1st level subdirectories (non-hidden)
for project in "$base_dir"/*/; do
for project in "$base_path"/*/; do
if [[ -d "$project" ]]; then
# Get directory name without trailing slash
project_path="''${project%/}"
@@ -89,8 +106,8 @@ writeShellScriptBin "rofi-project-opener" ''
continue
fi
base_display="$("$BASENAME" "$base_dir")"
echo "$base_display/$project_name|$project_path" >> "$PROJECTS_LIST"
# Use key as display prefix (e.g., "dev/myproject")
echo "$key/$project_name|$project_path|$base_args" >> "$PROJECTS_LIST"
fi
done
done
@@ -101,7 +118,7 @@ writeShellScriptBin "rofi-project-opener" ''
# Build project list
if ! build_project_list; then
show_error "No projects found in PROJECT_DIRS: $PROJECT_DIRS"
show_error "No projects found in configured directories"
exit 1
fi
@@ -117,8 +134,10 @@ writeShellScriptBin "rofi-project-opener" ''
exit 0
fi
# Get the full path from selection
project_path=$("$GREP" "^$selection|" "$PROJECTS_LIST" | "$CUT" -d '|' -f2)
# Get the full path and args from selection
selected_line=$("$GREP" "^$selection|" "$PROJECTS_LIST")
project_path=$(echo "$selected_line" | "$CUT" -d '|' -f2)
project_args=$(echo "$selected_line" | "$CUT" -d '|' -f3)
# Exit if path not found (shouldn't happen)
if [[ -z "$project_path" ]]; then
@@ -133,33 +152,30 @@ writeShellScriptBin "rofi-project-opener" ''
fi
# Build terminal command
# Placeholders: %s = project path, %a = project args
if [[ -n "$TERMINAL_CMD" ]]; then
# Check if %s placeholder is present
if [[ "$TERMINAL_CMD" == *"%s"* ]]; then
# Replace %s with project path and use as-is
final_cmd="''${TERMINAL_CMD//%s/$project_path}"
# shellcheck disable=SC2086
exec "$TERMINAL" $final_cmd
else
# Treat as command to run: wrap in shell with cd (--hold keeps terminal open)
# Source /etc/profile (base PATH) and HM session vars (sessionPath) for NixOS
exec "$TERMINAL" --hold -e bash --login -c "
unset __HM_SESS_VARS_SOURCED
for f in ~/.nix-profile/etc/profile.d/hm-session-vars.sh /etc/profiles/per-user/\$USER/etc/profile.d/hm-session-vars.sh; do
[ -f \"\$f\" ] && . \"\$f\"
done
cd '$project_path' && exec $TERMINAL_CMD
"
fi
else
# Default: open terminal, cd to project, run opencode
# Substitute placeholders
final_cmd="$TERMINAL_CMD"
final_cmd="''${final_cmd//%s/$project_path}"
final_cmd="''${final_cmd//%a/$project_args}"
# Source /etc/profile (base PATH) and HM session vars (sessionPath) for NixOS
exec "$TERMINAL" --hold -e bash --login -c "
unset __HM_SESS_VARS_SOURCED
for f in ~/.nix-profile/etc/profile.d/hm-session-vars.sh /etc/profiles/per-user/\$USER/etc/profile.d/hm-session-vars.sh; do
[ -f \"\$f\" ] && . \"\$f\"
done
cd '$project_path' && opencode
cd '$project_path' && exec $final_cmd
"
else
# Default: open terminal, cd to project, run opencode with args
# Source /etc/profile (base PATH) and HM session vars (sessionPath) for NixOS
exec "$TERMINAL" --hold -e bash --login -c "
unset __HM_SESS_VARS_SOURCED
for f in ~/.nix-profile/etc/profile.d/hm-session-vars.sh /etc/profiles/per-user/\$USER/etc/profile.d/hm-session-vars.sh; do
[ -f \"\$f\" ] && . \"\$f\"
done
cd '$project_path' && opencode $project_args
"
fi
''