Skip to content

Commit 88e60e8

Browse files
committed
feat: release v0.9.0 - feature complete -m
- Added symmetric GPG encryption for vault security - Implemented extension-aware logic for .txt and .gpg files - Hardened pre-flight checks to prevent accidental data leaks - Updated documentation and README to reflect feature-complete status - Finalised community-vault sync logic and fzf-widget integration
1 parent a5a1086 commit 88e60e8

4 files changed

Lines changed: 160 additions & 27 deletions

File tree

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.9.0] - 2026-04-16
9+
### Added
10+
- Vault Encryption. Symmetric GPG support for sensitive data.
11+
- New commands `xc lock` and `xc unlock` for vault security.
12+
- Security Gates. Global pre-flight checks to prevent accidental leaks of encrypted data.
13+
- Extension Awareness. The system now seamlessly handles both .txt and .gpg files.
14+
- Visual Feedback. Added warnings and status labels for locked vaults in the list view.
15+
16+
### Changed
17+
- Refined fzf-vault-widget to respect vault lock states.
18+
- Hardened placeholder logic to prevent execution on empty inputs.
19+
- Improved `xc use` logic to handle switching between mixed-format vaults.
20+
21+
---
22+
823
## [0.8.0] - 2026-04-10
924
### Added
1025
- Raw Input Mode: Implemented `xc add --raw` to allow capturing complex commands via stdin. This prevents the shell from evaluating subshells or stripping quotes during the saving process.

README.md

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

2-
## XC Manager
3-
**Version: 0.8.0**
2+
## XC - command vault manager
3+
**Version: 0.9.0**
44

55
[![Awesome Zsh Plugins](https://img.shields.io/badge/Awesome-Zsh%20Plugins-brightgreen)](https://github.com/unixorn/awesome-zsh-plugins)
66
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
@@ -9,18 +9,23 @@
99

1010
![XC-Manager TUI](https://github.com/Rakosn1cek/xc-manager/blob/main/preview-2.png)
1111

12-
**XC manager in Action:**
12+
**XC in Action:**
1313
<p align="center">
1414
<video src="https://github.com/user-attachments/assets/d67640fb-4e9e-4d36-b7a1-d588a24ab9a6" width="700" controls muted autoplay loop>
1515
Your browser does not support the video tag.
1616
</video>
1717
</p>
1818

19-
A high-performance, minimal dependency Zsh vault for managing complex commands.
19+
XC is a lightweight, Zsh-native vault manager for command execution. It’s for anyone who live in the CLI and need a fast, searchable, and now secure way to manage their most important one-liners. No bloat, no complex dependencies. Just your commands, vaulted.
2020

21-
**Recent Fixes** [0.8.0]
22-
- **Raw Input Capture**: Added `xc add --raw` to handle complex commands. This bypasses shell evaluation, allowing you to save curl, jq, and nested subshells exactly as they are written without the shell stripping quotes or expanding variables.
23-
- **Community-Vaults**: Added a few more curated community-vaults. All vaults now have at least 50 usefull commands and strings.
21+
**Status:** Feature Complete [v0.9.0]
22+
XC command vault manager has officially reached its feature-complete milestone. All planned functionality, including template engines, global search, and GPG security, is now implemented and stable.
23+
24+
**Recent Fixes & Updates** [0.9.0]
25+
- **Vault Security**: Integrated GPG symmetric encryption. Use `xc lock` and `xc unlock` to protect sensitive commands, API keys, and environment variables.
26+
- **Pre-flight Safety**: Added extension-aware logic to prevent accidental operations on encrypted vaults.
27+
- **Raw Input Capture**: Added `xc add --raw` to handle complex commands. This bypasses shell evaluation, allowing you to save `curl`, `jq`, and nested subshells exactly as they are written without the shell stripping quotes or expanding variables.
28+
- **Community Vaults**: Expanded the curated collection via `xc sync`. All community vaults now contain at least 50 useful commands and strings.
2429

2530
---
2631

@@ -57,6 +62,21 @@ zstyle ':xc:*' fzf_colors "fg:7,hl:4,fg+:15,hl+:12,info:2,prompt:5,pointer:12"
5762

5863
---
5964

65+
**Dependencies:**
66+
67+
To ensure all features work as intended, make sure the following are installed:
68+
69+
- **Zsh**: The core shell environment (version 5.8+ recommended).
70+
- **fzf**: Powering the fuzzy search and interactive selection.
71+
- **GnuPG**: Required for the `lock` and `unlock` encryption features.
72+
- **curl**: Necessary for synchronising community vaults via `xc sync`.
73+
74+
**Arch Linux:**
75+
```zsh
76+
pacman -S zsh fzf gnupg curl
77+
```
78+
---
79+
6080
**Community Sync:**
6181
Pull any curated, Arch Wiki-verified "Problem-Solution" vaults directly from the repository.
6282

@@ -92,6 +112,7 @@ Pull any curated, Arch Wiki-verified "Problem-Solution" vaults directly from the
92112
- Proactive Saving: Run `xc` to save the command you just executed.
93113
- FZF Integration: Fuzzy search with live previews.
94114
- Distro Agnostic: Works on Arch, Fedora, Debian, and macOS.
115+
- Vault Security: Symmetric GPG encryption to protect sensitive commands and API keys.
95116
- Save commands with {{variables}} to create templates. XC prompts for input during execution.
96117
- Global Swap: Using the same name (e.g. cp {{file}} {{file}}.bak) prompts once and updates all instances.
97118
- Individual Control: Use unique names (e.g. mv {{old}} {{new}}) to prompt for each value separately.
@@ -112,6 +133,12 @@ Pull any curated, Arch Wiki-verified "Problem-Solution" vaults directly from the
112133
- Capture Raw Text: Run `xc add --raw` -> paste complex command -> Press Enter -> then `Ctrl+D` to enter descriptions -> Save
113134
- Check Version: Run `xc -v`
114135

136+
**Security & Encryption**
137+
- For vaults containing sensitive environment variables, API keys, or internal IPs, XC now supports symmetric encryption via GPG.
138+
- Lock a vault: `xc lock` encrypts the active vault and removes the plain text file.
139+
- Unlock a vault: `xc unlock` restores the vault to plain text for editing/searching.
140+
- Protection: XC will automatically block search and add operations if a vault is locked, preventing binary data corruption or accidental plain text writes.
141+
115142
> *Note 1:
116143
Aliases are saved by default to ~/.zsh_aliases. If you prefer to save them directly into your main config file, add this to your .zshrc:
117144
`export XC_ALIAS_TARGET="$HOME/.zshrc"`
@@ -133,16 +160,22 @@ View Script: on GitHub [Show-Aliases Script](https://github.com/Rakosn1cek/dotfi
133160

134161
[x] Dynamic Placeholders
135162

136-
[ ] Encrypted Vaults (GPG/age support)
163+
[x] Encrypted Vaults (GPG/age support)
164+
165+
**Long-term research**
137166

138167
[ ] Cross-Shell Research (Bash/Fish wrappers)
139168

169+
> **Note:** I have reached the original goals for this project and will not be personally pursuing cross-shell support. If you are interested in implementing Bash or Fish wrappers, contributions and PRs are welcome.
170+
140171
**License**
141172
Distributed under the MIT License. See LICENSE for more information.
142173

143-
⭐ Star XC-Manager on GitHub
144-
145174
**Support & Feedback**
146175
- Bug Reports: If something isn't working, please open an [Issue](https://github.com/Rakosn1cek/XC-Manager/issues).
147176
- Feature Ideas: To discuss the roadmap or suggest a polish, head over to the[Discussions](https://github.com/Rakosn1cek/XC-Manager/discussions) tab.
148177
- Community Snippets: Have a complex one-liner you've vaulted? Share it in the "Show and Tell" discussion.
178+
179+
If XC-Manager has made your CLI life easier, consider giving it a star on GitHub! It helps other developers find the tool.
180+
181+
[⭐ Star XC on GitHub](https://github.com/Rakosn1cek/XC-Manager)

autoload/fzf-vault-widget

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
#!/usr/bin/env zsh
2+
3+
# ==============================================================================
4+
# XC-Manager: A functional vault for command execution.
5+
# Copyright (c) 2026 Lukas Grumlik - (Rakosn1cek)
6+
# License: MIT
7+
# Part of the Awesome-Zsh-Plugins collection.
28
# File: ~/arch-projects/XC-Manager/autoload/fzf-vault-widget
9+
# ==============================================================================
10+
311

412
# --- 1. User Configuration ---
513
local alias_target="${XC_ALIAS_TARGET:-$HOME/.zsh_aliases}"
614
local marker="# --- XC-Manager Aliases ---"
15+
autoload -U colors && colors
716

817
# --- 2. Helper Function: The Alias Engine ---
918
_xc_add_alias() {
@@ -39,9 +48,17 @@ local vault_dir="${XC_VAULT_DIR:-$HOME/.local/share/xc}"
3948
local state_file="$HOME/.cache/xc_active_vault"
4049
local active_name="main"
4150
[[ -f "$state_file" ]] && active_name=$(<"$state_file")
51+
52+
# Check for both extensions
4253
local vault_file="$vault_dir/${active_name}.txt"
54+
[[ -f "$vault_dir/${active_name}.gpg" ]] && vault_file="$vault_dir/${active_name}.gpg"
4355

44-
if [[ ! -f "$vault_file" ]]; then
56+
# If the file we found is a GPG file, show the locked warning
57+
if [[ "$vault_file" == *.gpg ]]; then
58+
zle -M "Vault '$active_name' is locked. Run 'xc unlock' to use it."
59+
return 1
60+
# If neither .txt nor .gpg exists
61+
elif [[ ! -f "$vault_file" ]]; then
4562
zle -M "Vault '$active_name' not found."
4663
return 1
4764
fi

autoload/xc

Lines changed: 84 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# File: ~/arch-projects/XC-Manager/autoload/xc
88
# ==============================================================================
99

10-
readonly XC_VERSION="0.8.0"
10+
readonly XC_VERSION="0.9.0"
1111
setopt EXTENDED_GLOB
1212

1313
# ==============================================================================
@@ -22,6 +22,7 @@ local active_name="main"
2222
[[ -f "$state_file" ]] && active_name=$(<"$state_file")
2323

2424
local vault_file="$vault_dir/${active_name}.txt"
25+
[[ -f "$vault_dir/${active_name}.gpg" ]] && vault_file="$vault_dir/${active_name}.gpg"
2526

2627
# --- Placeholder Processor Helper ---
2728
__xc_fill_placeholders() {
@@ -57,14 +58,17 @@ A functional vault for command execution and alias management.
5758
Usage: xc <command> [arguments]
5859
5960
Commands:
60-
add Vault a new command or one-liner.
61-
add --raw Paste raw text (use for curl, jq). Finish with Enter then Ctrl+D.
62-
list List of available vaults with current vault in use marked with *.
63-
select Open fzf to vault a command from your history.
64-
clean Interactively remove entries with a safety lock.
65-
use Switch between different vault files.
66-
sync Interactive "Package Manager" for community vaults.
67-
alias Promote a vaulted command to a permanent Zsh alias.
61+
add Vault a new command or one-liner.
62+
add --raw Paste raw text (use for curl, jq). Finish with Enter then Ctrl+D.
63+
list List of available vaults with current vault in use marked with *.
64+
select Open fzf to vault a command from your history.
65+
clean Interactively remove entries with a safety lock.
66+
use Switch between different vault files.
67+
lock Encrypt a vault currently in use with GPG (requires passphrase).
68+
lock <vault-name> Encrypt any vault specified by the user.
69+
unlock Decrypt a locked vault back to plain text.
70+
sync Interactive "Package Manager" for community vaults.
71+
alias Promote a vaulted command to a permanent Zsh alias.
6872
6973
Templating:
7074
Use {{var}} in your commands to create interactive prompts.
@@ -94,16 +98,65 @@ elif [[ "$1" == "init" ]]; then
9498
# List Available Vaults (Inventory Check)
9599
elif [[ "$1" == "list" ]]; then
96100
echo "Available Vaults in $vault_dir:"
97-
for f in "$vault_dir"/*.txt(N); do
101+
for f in "$vault_dir"/*.(txt|gpg)(N); do
98102
local v_name="${f:t:r}"
103+
local v_ext="${f:e}"
104+
local lock_label=""
105+
[[ "$v_ext" == "gpg" ]] && lock_label=" [LOCKED]"
106+
99107
if [[ "$v_name" == "$active_name" ]]; then
100-
echo " * $v_name (active)"
108+
echo " * $v_name (active)$lock_label"
101109
else
102-
echo " $v_name"
110+
echo " $v_name$lock_label"
103111
fi
104112
done
105113
return 0
106114

115+
# --- Lock Vault (Symmetric Encryption) ---
116+
elif [[ "$1" == "lock" ]]; then
117+
local target_name="${2:-$active_name}"
118+
local target_file="$vault_dir/${target_name}.txt"
119+
local encrypted_file="$vault_dir/${target_name}.gpg"
120+
121+
if [[ ! -f "$target_file" ]]; then
122+
echo "Error: Vault '$target_name' not found or already encrypted."
123+
return 1
124+
fi
125+
126+
echo "Encrypting vault: $target_name"
127+
# gpg --symmetric handles the passphrase prompt via pinentry
128+
if gpg --symmetric --output "$encrypted_file" "$target_file"; then
129+
rm "$target_file"
130+
echo "Success: Vault '$target_name' is now locked (.gpg)."
131+
echo "The original .txt file has been removed."
132+
else
133+
echo "Error: Encryption failed."
134+
return 1
135+
fi
136+
return 0
137+
138+
# --- Unlock Vault (Decryption) ---
139+
elif [[ "$1" == "unlock" ]]; then
140+
local target_name="${2:-$active_name}"
141+
local target_file="$vault_dir/${target_name}.txt"
142+
local encrypted_file="$vault_dir/${target_name}.gpg"
143+
144+
if [[ ! -f "$encrypted_file" ]]; then
145+
echo "Error: Encrypted vault '$target_name.gpg' not found."
146+
return 1
147+
fi
148+
149+
echo "Decrypting vault: $target_name"
150+
if gpg --decrypt --output "$target_file" "$encrypted_file"; then
151+
rm "$encrypted_file"
152+
echo "Success: Vault '$target_name' is now unlocked (.txt)."
153+
echo "The .gpg file has been removed."
154+
else
155+
echo "Error: Decryption failed. Incorrect passphrase or GPG error."
156+
return 1
157+
fi
158+
return 0
159+
107160
# Clean Vault
108161
elif [[ "$1" == "clean" ]]; then
109162
[[ ! -f "$vault_file" ]] && echo "Vault not found." && return 1
@@ -143,14 +196,20 @@ elif [[ "$1" == "use" ]]; then
143196
if [[ -z "$2" ]]; then
144197
echo "Active Vault: [${active_name}]"
145198
echo "Available Vaults:"
146-
for f in "$vault_dir"/*.txt(N); do
199+
for f in "$vault_dir"/*.(txt|gpg)(N); do
147200
local v_name="${f:t:r}"
148-
[[ "$v_name" == "$active_name" ]] && echo " * $v_name (active)" || echo " $v_name"
201+
local v_ext="${f:e}"
202+
local lock_label=""
203+
[[ "$v_ext" == "gpg" ]] && lock_label=" [LOCKED]"
204+
[[ "$v_name" == "$active_name" ]] && echo " * $v_name (active)$lock_label" || echo " $v_name$lock_label"
149205
done
150206
else
151207
echo "$2" > "$state_file"
152208
echo "Switched to vault: $2"
153-
[[ ! -f "$vault_dir/$2.txt" ]] && touch "$vault_dir/$2.txt"
209+
# Check if either .txt OR .gpg exists. If neither, create a new .txt.
210+
if [[ ! -f "$vault_dir/$2.txt" && ! -f "$vault_dir/$2.gpg" ]]; then
211+
touch "$vault_dir/$2.txt"
212+
fi
154213
fi
155214
return 0
156215

@@ -244,7 +303,16 @@ fi
244303
# ==============================================================================
245304
# SECTION 3: PRE-FLIGHT CHECK
246305
# ==============================================================================
247-
if [[ ! -f "$vault_file" ]]; then
306+
# 1. Check if the vault is locked (extension is .gpg)
307+
if [[ "$vault_file" == *.gpg ]]; then
308+
# If the command is empty (Ctrl+G) or not a management command, block it
309+
if [[ -z "$1" || ( "$1" != "unlock" && "$1" != "use" && "$1" != "list" && "$1" != "lock" ) ]]; then
310+
print -P "%F{yellow}Vault [${active_name}] is currently locked (.gpg).%f"
311+
print -P "Run 'xc unlock' to access or add commands to this vault."
312+
return 1
313+
fi
314+
# 2. If it's not locked, check if the file actually exists
315+
elif [[ ! -f "$vault_file" ]]; then
248316
echo "Vault not found. Please run 'xc init' first."
249317
return 1
250318
fi

0 commit comments

Comments
 (0)