Skip to content

Cleanup#53

Merged
hinriksnaer merged 55 commits into
mainfrom
unstable
Mar 15, 2026
Merged

Cleanup#53
hinriksnaer merged 55 commits into
mainfrom
unstable

Conversation

@hinriksnaer

Copy link
Copy Markdown
Owner

No description provided.

hinriksnaer and others added 30 commits January 2, 2026 08:15
…ands (#47)

* feat(modules): store external modules in ~/.config/fedpunk/modules/

- Change external module storage from cache to user config directory
- Makes modules easily editable without cache invalidation issues
- Add priority-based resolution: profile -> external -> system
- Update documentation to reflect new storage location

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(module): add installed, available, and update commands

- `fedpunk module installed` - Lists deployed modules by type (native/external/profile)
- `fedpunk module available` - Lists modules available to install
- `fedpunk module update <name|all>` - Pulls git updates and redeploys if changed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: add install-from-source.sh for local RPM builds

Clean script for building and installing Fedpunk from a git checkout:
- Validates git state and warns about uncommitted changes
- Checks for build dependencies
- Creates proper source tarball from HEAD
- Builds RPM with patched spec file
- Installs with dnf

Usage:
  ./install-from-source.sh           # Build and install
  ./install-from-source.sh --build   # Build only
  ./install-from-source.sh --clean   # Clean artifacts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(install): clean old RPMs and use reinstall for updates

- Remove old fedpunk RPMs before building to avoid stale files
- Find most recently built RPM by modification time
- Use dnf reinstall to force update when version matches

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(module): fix installed command display issues

- Use separate arrays for module names and git status to avoid \t escaping issues
- Deduplicate modules by name (git URL and name can resolve to same module)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(module): show profile modules in installed command

The installed command now shows all deployed modules:
- Modules from fedpunk.yaml (explicitly deployed)
- Modules from active profile's mode.yaml

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* removed external module

* fix(spec): dynamically install all modules instead of hardcoding names

Changed from hardcoded module list to dynamic discovery:
- Installs all modules found in modules/ directory
- No need to update spec when modules are added/removed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(deployer): normalize git URLs to module names in config

When deploying a git URL, store only the module name in config:
- git@gitlab.com:org/thinkpad-fans.git -> thinkpad-fans

This prevents duplicate entries when deploying the same module
by URL and by name, and makes `fedpunk module update` work with
simple names.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(sources): add multi-module source repository support

Add sources concept for managing collections of external modules:
- Create sources.fish library for clone/update/discover operations
- Add fedpunk source CLI (add, list, sync, modules, remove)
- Update module resolver with priority: profile → sources → external → native
- Sync sources automatically before deployment
- Update module installed/available to show source modules

Sources are multi-module git repos stored in ~/.config/fedpunk/sources/
Direct git URLs are stored in ~/.config/fedpunk/modules/

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(sources): add registry format support for source repos

Sources can now be registry repos with modules.yaml that map
module names to their git URLs. This allows a single source
to reference modules in separate git repositories.

Registry format:
```yaml
modules:
  module-name:
    repo: git@gitlab.com:org/module.git
    description: Module description
```

When deploying from a registry, modules are cloned to
~/.config/fedpunk/modules/ like direct git URLs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(cli): move source commands under fedpunk module source

Consolidate source management as a subcommand of module:
- fedpunk module source add <url>
- fedpunk module source list
- fedpunk module source sync
- fedpunk module source modules
- fedpunk module source remove <url>

This makes the CLI hierarchy more intuitive since sources
are module repositories.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(cli): rename source to sources to avoid Fish builtin conflict

The 'source' function name conflicts with Fish's builtin source
command used to load files. Renamed to 'sources' (plural).

Commands are now:
- fedpunk module sources add <url>
- fedpunk module sources list
- fedpunk module sources sync
- fedpunk module sources modules
- fedpunk module sources remove <url>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(cli): show help when running fedpunk module sources without args

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(cli): support nested command directories for subcommands

The dispatcher now supports three-level commands via nested directories.
For example, cli/module/sources/ creates `fedpunk module sources <cmd>`.

Moved sources subcommands to cli/module/sources/sources.fish:
- fedpunk module sources add
- fedpunk module sources list
- fedpunk module sources sync
- fedpunk module sources modules
- fedpunk module sources remove

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(cli): include subdirectories in discovered subcommands

Updates _discover_functions to list subdirectories as nested command
groups. This allows nested command structures like cli/module/sources/
to appear in the subcommand help output.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(cli): show descriptions for nested command subdirectories

Updates _get_description to check nested subdirectories for group
function descriptions. For example, sources in cli/module/sources/
now shows its description "Manage module sources" in parent help.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(cli): move installed/available under 'module list' subgroup

Creates nested command structure:
  fedpunk module list installed
  fedpunk module list available

This provides cleaner CLI organization and maintains backwards
compatibility with the 'module list' concept from the test.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Update npm package handling to match cargo pattern:
- Check PATH for npm
- Check fnm and nvm fallback locations
- Error if not found, requiring nodejs module as dependency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
npm is needed for module package installation and comes bundled
with the nodejs package.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Check cargo packages upfront instead of per-package
- Return 1 instead of continue to fail deployment
- Check /root/.cargo/bin as fallback for root users

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Needed for modules that install packages via cargo (like yazi).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Checks for ~/.ssh/agent.sock (stable symlink from systemd ssh-agent)
before spawning a new agent. This enables reliable SSH agent forwarding
to containers that mount the stable socket path.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
ssh-add -l returns:
- 0: keys listed (connected)
- 1: no identities (connected but empty)
- 2: cannot connect to agent

Previously checked for exit 0, which failed when agent was running
but had no keys loaded. Now correctly checks for exit != 2.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sets SSH_AUTH_SOCK to ~/.ssh/agent.sock on shell startup if the stable
socket exists. This ensures containers can reliably mount the socket
and SSH agent forwarding works consistently.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove ssh-clusters references (module was deleted)
- Update module count from 3 to 2 built-in modules
- Add module sources management commands to README
- Document SSH agent stable socket feature
- Update CHANGELOG with new features for this release

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When fedpunk ssh load starts a new agent, create a symlink at
~/.ssh/agent.sock pointing to the actual socket. This ensures
all shells can find the agent via the stable socket path.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The fish config now checks if the stable socket actually works
(agent responds) before setting SSH_AUTH_SOCK, instead of just
checking if the socket file exists.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The %post script was creating ~/.config/fedpunk with mkdir -p, which
also created the parent .config directory as root. The chown only fixed
the fedpunk subdirectory, leaving .config owned by root.

Now tracks if .config was created and fixes its ownership too.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ig (#49)

* feat(profile): preserve git URLs in fedpunk.yaml for declarative config

Enable users to declaratively reference git profiles in fedpunk.yaml
by URL, similar to how sources work. The system automatically clones
and updates profiles from git URLs.

Changes:
- Remove line that overwrote profile_to_save with extracted repo name
- Add logic to save basename only for path-based profiles
- Git URLs are now preserved in config instead of being extracted to name
- Add comprehensive test script for git profile URL functionality

Example usage:
```yaml
# Git URL (auto-clones/updates on apply)
profile: git@github.com:user/hyprpunk.git
mode: laptop

# Name (resolves from profile directories)
profile: default
mode: desktop
```

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat(module): add declarative environment variable support

Modules can now declare environment variables in module.yaml under an
`environment:` section. Users can also declare global environment
variables in fedpunk.yaml.

Features:
- New env-injector.fish generates ~/.config/fish/conf.d/fedpunk-module-env.fish
- Supports $FEDPUNK_PARAM_* interpolation for dynamic values
- User-defined env vars in fedpunk.yaml override module defaults
- Env config is sourced immediately after deployment

Example module.yaml:
  environment:
    CLAUDE_CODE_USE_VERTEX: "1"
    CLOUD_ML_REGION: "$FEDPUNK_PARAM_CLAUDE_REGION"

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Fedora container images have kiwi_* environment variables that echo
to stdout during shell initialization, polluting yq output.

Added _yq_safe wrapper that runs yq with 'env -i' to avoid picking
up garbage from the shell environment.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
The previous fix in config.fish only addressed yq calls in that file.
This comprehensive fix:

- Creates shared lib/fish/yq-utils.fish with _yq_safe and _yq_safe_eval
- Updates all files that use yq to source the shared utilities
- Replaces all yq read operations with _yq_safe/_yq_safe_eval
- Prevents kiwi_* environment variable pollution in Fedora containers

Files updated:
- config.fish: Sources shared yq-utils.fish
- deployer.fish: Uses _yq_safe for module list
- env-injector.fish: Uses _yq_safe for environment reading
- module-ref-parser.fish: Uses _yq_safe_eval for parsing
- param-injector.fish: Uses _yq_safe_eval for parameter extraction
- param-prompter.fish: Uses _yq_safe_eval for config reading
- sources.fish: Uses _yq_safe for registry operations
- yaml-parser.fish: Uses _yq_safe/_yq_safe_eval for parsing

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Generate /etc/fish/conf.d/fedpunk-env.fish and /etc/profile.d/fedpunk-env.sh
Previously env-injector wrote to /etc/fish/conf.d/ and /etc/profile.d/
which required root access and failed silently without sudo.

Now writes to user-level config:
- Fish: ~/.config/fish/conf.d/fedpunk-module-env.fish (auto-sourced)
- Bash: ~/.config/fedpunk/profile.d/fedpunk-env.sh (source from .bashrc)

This matches how param-injector works and fixes the file path expected
by fedpunk-module.fish line 464.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, env-generate-fish-config was called BEFORE modules were
deployed, causing module environment variables to not be included
if the modules weren't yet in place (e.g., first-time deployment).

Now env and param config generation happens AFTER all modules are
deployed, ensuring all module.yaml files are available for parsing.

This fixes the issue where environment variables from user modules
(like CLAUDE_CODE_USE_VERTEX) weren't being generated during
fedpunk apply.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use fedpunk-config-list-enabled-modules for the duplicate check,
which properly extracts module names from both simple string and
object formats (module: name with params).

Previously the check used raw YAML which didn't match object entries.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The module resolver uses FEDPUNK_USER to find profile modules and
FEDPUNK_SYSTEM to find system modules, but these environment
variables weren't guaranteed to be set when the library was sourced
directly (e.g., during env-generate-fish-config).

This caused profile modules like 'claude' to not be found during
environment variable generation, even though they exist in the
profile's modules directory.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extend duplicate detection in fedpunk-config-add-module to also check
the active profile's mode.yaml modules list. Previously, running
`fedpunk module deploy <name>` would add a module to modules.enabled
even if it was already part of the deployed profile.

Changes:
- Add fedpunk-config-list-profile-modules helper function
- Check profile modules before adding to modules.enabled
- Add null check and -- flag to contains for robustness

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Resolve conflict in lib/fish/config.fish by keeping the improved
duplicate detection logic that also checks profile's mode.yaml.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Rewrote "What is Fedpunk?" to highlight full orchestration capabilities:
  dotfiles, packages, env variables, custom CLI, lifecycle scripts, deps
- Moved Architecture section lower (after Profiles)
- Added module resolution priority
- Removed "What is/is not" sections in favor of clearer feature list
- Fixed profile structure: plugins/ → modules/
- Updated nav links

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document the main config file structure and ~/.config/fedpunk directory
layout before diving into the module system.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Params are stored within each module entry, not at root level.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Theme CLI is external (provided by profiles like hyprpunk).
The symlink pointed to a local user path that wouldn't work on other systems.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- test/ci/ - CI test scripts (automated)
- test/unit/ - unit tests
- test/container.sh - interactive container testing
- Remove .devcontainer/ (not useful for this project)
- Remove tests/ (merged into test/unit/)
- Move test-local.sh to test/container.sh
- Update CI workflows and docs for new paths

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Profile config is now an object with three fields:
- name: profile name for local lookup
- source: git URL for fetching/updates (null for local profiles)
- mode: active mode (moved from top-level)

This enables:
- Reproducible configs (source URL preserved)
- Local profile support (source can be null)
- Cleaner organization (mode belongs to profile)

New functions:
- fedpunk-config-set-profile <name> [source] [mode]
- fedpunk-config-set-profile-mode <mode>
- fedpunk-config-get-profile-name
- fedpunk-config-get-profile-source
- fedpunk-config-get-profile-mode

Also:
- Delete obsolete docs/ directory
- Add dev user to test container
- Update tests for new config structure

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
hinriksnaer and others added 25 commits March 13, 2026 17:07
Allows testing uncommitted changes in the container.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Variables declared with 'set -l' inside if blocks are scoped to that
block and not visible outside. Fixed by declaring variables before the
if block.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
fedpunk-config-init now checks if config file exists before writing,
preventing accidental loss of user configuration. Also consolidates
param-prompter to use canonical config initialization.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Verifies that environment: section in module.yaml and fedpunk.yaml
correctly generates Fish and Bash config files with proper precedence.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added documentation for:
- environment: section in module.yaml schema
- environment: section in fedpunk.yaml (user overrides)
- env-injector.fish in core libraries list
- Environment injection step in deployment flow

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
SSH module is no longer a core built-in module. Fedpunk now ships
with only the fish module as its single built-in module.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add profile management commands (list, current, deploy, apply)
- Document mode.yaml structure with examples
- Explain git URL deployment workflow
- Expand directory structure with detailed tree showing profiles,
  sources, modules, and generated configs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Verifies that parameters: section in module.yaml and params: in
fedpunk.yaml correctly generate FEDPUNK_PARAM_<MODULE>_<KEY>
environment variables.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
SSH module does exist in fedpunk, restoring documentation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Document how modules can provide custom CLI commands via cli/ directory
- Show example CLI file structure with subcommands
- Add TUI section explaining gum-based UI elements
- List available ui-* functions for module developers

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, only user-provided params were injected. Now the system:
1. Reads parameters: section from module.yaml for defaults
2. Merges with user-provided params (user takes precedence)
3. Generates env vars for all params including defaults

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace inline module creation guide with link to
fedpunk-module-template repo which has full documentation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add fedpunk-module-template as git submodule at examples/module-template
- Update README to reference local examples/ path
- Update spec file to install examples directory in RPM

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Run `git submodule update --remote examples/module-template` to pull latest.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove dead neovim submodule from .gitmodules
- Update CLAUDE.md: profiles are external only (not 3 built-in)
- Update CLAUDE.md: themes are external only (hyprpunk provides them)
- Update module-template submodule with architecture fixes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add 5 new test files covering:
- Config preservation (init doesn't overwrite existing config)
- Disabled modules (disabled list prevents deployment)
- External modules (git URL cloning to ~/.config/fedpunk/modules/)
- Sources management (add/list/sync/modules commands)
- Lifecycle hooks (before/after hook execution)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New tests (all run in <2s each):
- test-dependency-resolution: Linear/diamond deps, cycle detection
- test-module-resolver: System/profile/external/source resolution
- test-module-ref-parser: URL/path detection, param extraction
- test-stow-conflicts: Skip/overwrite modes, state tracking
- test-module-unstow: Symlink removal, state cleanup
- test-profile-deploy: Git URL profiles, mode selection
- test-template-module: Uses examples/module-template submodule
- test-yaml-reproducibility: Config determinism
- test-cli-integration: All CLI commands, error handling

CI workflow runs tests in parallel matrix for fast feedback.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Avoids sudo/package install step that fails in CI containers.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fixed FEDPUNK_ROOT path (was going to test/ instead of project root)
- Use deployer-deploy-profile instead of deployer-deploy-from-config for initial deploy
- Added test to CI workflow

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enhanced test-module-environment.sh to verify that Bash, Fish, and Zsh
shells actually load environment variables when sourcing generated config
files, not just that the files are generated correctly.

This catches the bug where fedpunk-env.sh is generated but not
automatically sourced by Bash/Zsh (unlike Fish which auto-loads from
conf.d/).

New tests:
- Test 6: Bash shell environment loading
- Test 7: Fish shell environment loading
- Test 8: Zsh shell environment loading (skips if zsh not installed)

Each test spawns a fresh shell, sources the config file, and verifies
all environment variables are correctly set.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@hinriksnaer hinriksnaer merged commit 273da57 into main Mar 15, 2026
34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant