Kieran's opinionated (and probably slightly dumb) nix config

feat: add pbnj

dunkirk.sh 27d4c9fd 0738d054

verified
+731
+4
machines/atalanta/default.nix
··· 113 113 file = ../../secrets/bore/auth-token.age; 114 114 owner = "kierank"; 115 115 }; 116 + pbnj = { 117 + file = ../../secrets/pbnj.age; 118 + owner = "kierank"; 119 + }; 116 120 }; 117 121 118 122 environment.variables = {
+5
machines/atalanta/home/default.nix
··· 40 40 enable = true; 41 41 authTokenFile = osConfig.age.secrets."bore/auth-token".path; 42 42 }; 43 + pbnj = { 44 + enable = true; 45 + host = "https://pbnj.dunkirk.sh"; 46 + authKeyFile = osConfig.age.secrets.pbnj.path; 47 + }; 43 48 ssh = { 44 49 enable = true; 45 50
+4
machines/ember/default.nix
··· 32 32 apps = { 33 33 helix.enable = true; 34 34 }; 35 + pbnj = { 36 + enable = true; 37 + host = "https://pbnj.dunkirk.sh"; 38 + }; 35 39 ssh = { 36 40 enable = true; 37 41 zmx.enable = true;
+39
modules/home/apps/pbnj/completions/pbnj.bash
··· 1 + _pbnj() { 2 + local cur prev words cword 3 + _init_completion || return 4 + 5 + local commands="init config list delete delete-all" 6 + 7 + case $prev in 8 + -L|--language) 9 + COMPREPLY=($(compgen -W "go python javascript typescript rust ruby java c cpp csharp php bash html css json yaml xml sql markdown swift kotlin scala nix lua vim toml" -- "$cur")) 10 + return 11 + ;; 12 + -f|--filename|-u|--update|-k|--key) 13 + return 14 + ;; 15 + delete|-d) 16 + return 17 + ;; 18 + list) 19 + return 20 + ;; 21 + esac 22 + 23 + case $cur in 24 + -*) 25 + COMPREPLY=($(compgen -W "-L --language -f --filename -p --private -k --key -u --update -n --no-copy -l --list -h --help" -- "$cur")) 26 + return 27 + ;; 28 + esac 29 + 30 + if [[ $cword -eq 1 ]]; then 31 + COMPREPLY=($(compgen -W "$commands" -- "$cur")) 32 + COMPREPLY+=($(compgen -f -- "$cur")) 33 + return 34 + fi 35 + 36 + _filedir 37 + } 38 + 39 + complete -F _pbnj pbnj
+26
modules/home/apps/pbnj/completions/pbnj.fish
··· 1 + # pbnj completions for fish 2 + 3 + set -l commands init config list delete delete-all 4 + set -l languages go python javascript typescript rust ruby java c cpp csharp php bash html css json yaml xml sql markdown swift kotlin scala nix lua vim toml 5 + 6 + complete -c pbnj -f 7 + 8 + # Commands 9 + complete -c pbnj -n "not __fish_seen_subcommand_from $commands" -a init -d "Configure pbnj instance" 10 + complete -c pbnj -n "not __fish_seen_subcommand_from $commands" -a config -d "Show current configuration" 11 + complete -c pbnj -n "not __fish_seen_subcommand_from $commands" -a list -d "List recent pastes" 12 + complete -c pbnj -n "not __fish_seen_subcommand_from $commands" -a delete -d "Delete a paste" 13 + complete -c pbnj -n "not __fish_seen_subcommand_from $commands" -a delete-all -d "Delete all pastes" 14 + 15 + # File completion for default 16 + complete -c pbnj -n "not __fish_seen_subcommand_from $commands" -F 17 + 18 + # Options 19 + complete -c pbnj -s L -l language -d "Override language" -xa "$languages" 20 + complete -c pbnj -s f -l filename -d "Set filename" -r 21 + complete -c pbnj -s p -l private -d "Create private paste" 22 + complete -c pbnj -s k -l key -d "Add secret key" -r 23 + complete -c pbnj -s u -l update -d "Update existing paste" -r 24 + complete -c pbnj -s n -l no-copy -d "Don't copy URL" 25 + complete -c pbnj -s l -l list -d "List pastes" 26 + complete -c pbnj -s h -l help -d "Show help"
+57
modules/home/apps/pbnj/completions/pbnj.zsh
··· 1 + #compdef pbnj 2 + 3 + _pbnj() { 4 + local -a commands 5 + commands=( 6 + 'init:Configure pbnj instance' 7 + 'config:Show current configuration' 8 + 'list:List recent pastes' 9 + 'delete:Delete a paste' 10 + 'delete-all:Delete all pastes' 11 + ) 12 + 13 + local -a languages 14 + languages=(go python javascript typescript rust ruby java c cpp csharp php bash html css json yaml xml sql markdown swift kotlin scala nix lua vim toml) 15 + 16 + _arguments -C \ 17 + '1: :->cmd' \ 18 + '*: :->args' \ 19 + '-L+[Override language]:language:($languages)' \ 20 + '--language+[Override language]:language:($languages)' \ 21 + '-f+[Set filename]:filename:_files' \ 22 + '--filename+[Set filename]:filename:_files' \ 23 + '-p[Create private paste]' \ 24 + '--private[Create private paste]' \ 25 + '-k+[Add secret key]:key:' \ 26 + '--key+[Add secret key]:key:' \ 27 + '-u+[Update existing paste]:id:' \ 28 + '--update+[Update existing paste]:id:' \ 29 + '-n[Do not copy URL]' \ 30 + '--no-copy[Do not copy URL]' \ 31 + '-l+[List pastes]:limit:' \ 32 + '--list+[List pastes]:limit:' \ 33 + '-h[Show help]' \ 34 + '--help[Show help]' 35 + 36 + case $state in 37 + cmd) 38 + _describe -t commands 'command' commands 39 + _files 40 + ;; 41 + args) 42 + case $words[2] in 43 + list) 44 + _message 'limit (number)' 45 + ;; 46 + delete) 47 + _message 'paste id' 48 + ;; 49 + *) 50 + _files 51 + ;; 52 + esac 53 + ;; 54 + esac 55 + } 56 + 57 + _pbnj "$@"
+477
modules/home/apps/pbnj/default.nix
··· 1 + { 2 + config, 3 + lib, 4 + pkgs, 5 + ... 6 + }: 7 + let 8 + cfg = config.atelier.pbnj; 9 + 10 + hostArg = if cfg.host != null then ''"${cfg.host}"'' else "\"\""; 11 + authKeyFileArg = if cfg.authKeyFile != null then ''"${cfg.authKeyFile}"'' else "\"\""; 12 + 13 + # Platform-specific clipboard commands 14 + clipboardCopy = if pkgs.stdenv.isDarwin then 15 + "printf '%s' \"$url\" | pbcopy 2>/dev/null" 16 + else 17 + "echo \"$url\" | ${pkgs.wl-clipboard}/bin/wl-copy 2>/dev/null || echo \"$url\" | ${pkgs.xclip}/bin/xclip -selection clipboard 2>/dev/null"; 18 + 19 + pbnjScript = pkgs.writeShellScript "pbnj" '' 20 + set -e 21 + set -o pipefail 22 + 23 + CONFIG_FILE="''${PBNJ_CONFIG:-$HOME/.pbnj.json}" 24 + CONFIGURED_HOST=${hostArg} 25 + CONFIGURED_AUTH_KEY_FILE=${authKeyFileArg} 26 + 27 + # Load config 28 + load_config() { 29 + # Priority: env var > nix config > config file 30 + if [ -n "$PBNJ_HOST" ]; then 31 + HOST="$PBNJ_HOST" 32 + elif [ -n "$CONFIGURED_HOST" ]; then 33 + HOST="$CONFIGURED_HOST" 34 + elif [ -f "$CONFIG_FILE" ]; then 35 + HOST=$(${pkgs.jq}/bin/jq -r '.host // empty' "$CONFIG_FILE" 2>/dev/null) 36 + fi 37 + 38 + if [ -n "$PBNJ_AUTH_KEY" ]; then 39 + AUTH_KEY="$PBNJ_AUTH_KEY" 40 + elif [ -n "$CONFIGURED_AUTH_KEY_FILE" ] && [ -f "$CONFIGURED_AUTH_KEY_FILE" ]; then 41 + AUTH_KEY=$(${pkgs.coreutils}/bin/cat "$CONFIGURED_AUTH_KEY_FILE") 42 + elif [ -f "$CONFIG_FILE" ]; then 43 + AUTH_KEY=$(${pkgs.jq}/bin/jq -r '.auth_key // empty' "$CONFIG_FILE" 2>/dev/null) 44 + fi 45 + } 46 + 47 + check_config() { 48 + if [ -z "$HOST" ] || [ -z "$AUTH_KEY" ]; then 49 + ${pkgs.gum}/bin/gum style --foreground 196 "Not configured. Run 'pbnj init' first." 50 + exit 1 51 + fi 52 + } 53 + 54 + # Detect language from filename 55 + detect_language() { 56 + local filename="$1" 57 + local ext="''${filename##*.}" 58 + case "$ext" in 59 + go) echo "go" ;; 60 + py) echo "python" ;; 61 + js) echo "javascript" ;; 62 + ts) echo "typescript" ;; 63 + rs) echo "rust" ;; 64 + rb) echo "ruby" ;; 65 + java) echo "java" ;; 66 + c|h) echo "c" ;; 67 + cpp|hpp|cc) echo "cpp" ;; 68 + cs) echo "csharp" ;; 69 + php) echo "php" ;; 70 + sh|bash|zsh) echo "bash" ;; 71 + html) echo "html" ;; 72 + css) echo "css" ;; 73 + json) echo "json" ;; 74 + yaml|yml) echo "yaml" ;; 75 + xml) echo "xml" ;; 76 + sql) echo "sql" ;; 77 + md) echo "markdown" ;; 78 + swift) echo "swift" ;; 79 + kt) echo "kotlin" ;; 80 + scala) echo "scala" ;; 81 + nix) echo "nix" ;; 82 + lua) echo "lua" ;; 83 + vim) echo "vim" ;; 84 + toml) echo "toml" ;; 85 + *) echo "" ;; 86 + esac 87 + } 88 + 89 + # Format age 90 + format_age() { 91 + local created="$1" 92 + local now=$(${pkgs.coreutils}/bin/date +%s) 93 + local then=$(${pkgs.coreutils}/bin/date -d "$created" +%s 2>/dev/null || echo "$now") 94 + local diff=$((now - then)) 95 + 96 + if [ $diff -lt 60 ]; then 97 + echo "just now" 98 + elif [ $diff -lt 3600 ]; then 99 + echo "$((diff / 60))m ago" 100 + elif [ $diff -lt 86400 ]; then 101 + echo "$((diff / 3600))h ago" 102 + elif [ $diff -lt 604800 ]; then 103 + echo "$((diff / 86400))d ago" 104 + else 105 + echo "$((diff / 604800))w ago" 106 + fi 107 + } 108 + 109 + # Commands 110 + cmd_init() { 111 + ${pkgs.gum}/bin/gum style --bold --foreground 212 "Configure pbnj" 112 + echo 113 + 114 + host=$(${pkgs.gum}/bin/gum input --placeholder "https://paste.example.com" --prompt "Host URL: ") 115 + if [ -z "$host" ]; then 116 + ${pkgs.gum}/bin/gum style --foreground 196 "No host provided" 117 + exit 1 118 + fi 119 + 120 + auth_key=$(${pkgs.gum}/bin/gum input --placeholder "your-auth-key" --prompt "Auth Key: " --password) 121 + if [ -z "$auth_key" ]; then 122 + ${pkgs.gum}/bin/gum style --foreground 196 "No auth key provided" 123 + exit 1 124 + fi 125 + 126 + # Remove trailing slash 127 + host="''${host%/}" 128 + 129 + echo "{\"host\": \"$host\", \"auth_key\": \"$auth_key\"}" > "$CONFIG_FILE" 130 + chmod 600 "$CONFIG_FILE" 131 + 132 + ${pkgs.gum}/bin/gum style --foreground 35 "✓ Configuration saved to $CONFIG_FILE" 133 + } 134 + 135 + cmd_config() { 136 + load_config 137 + 138 + if [ -z "$HOST" ] || [ -z "$AUTH_KEY" ]; then 139 + ${pkgs.gum}/bin/gum style --foreground 117 "Not configured. Run 'pbnj init' first." 140 + exit 0 141 + fi 142 + 143 + ${pkgs.gum}/bin/gum style --bold --foreground 212 "pbnj config" 144 + echo 145 + echo " Host: $HOST" 146 + # Mask auth key 147 + masked="''${AUTH_KEY:0:4}...''${AUTH_KEY: -4}" 148 + echo " Auth: $masked" 149 + } 150 + 151 + cmd_list() { 152 + load_config 153 + check_config 154 + 155 + local limit="''${1:-10}" 156 + 157 + response=$(${pkgs.curl}/bin/curl -s -f -X GET \ 158 + -H "Authorization: Bearer $AUTH_KEY" \ 159 + "$HOST/api?limit=$limit" 2>&1) || { 160 + ${pkgs.gum}/bin/gum style --foreground 196 "Failed to fetch pastes" 161 + exit 1 162 + } 163 + 164 + count=$(echo "$response" | ${pkgs.jq}/bin/jq -r '.pastes | length') 165 + 166 + if [ "$count" = "0" ] || [ -z "$count" ]; then 167 + ${pkgs.gum}/bin/gum style --foreground 117 "No pastes found." 168 + exit 0 169 + fi 170 + 171 + ${pkgs.gum}/bin/gum style --bold --foreground 212 "Recent pastes" 172 + echo 173 + 174 + echo "$response" | ${pkgs.jq}/bin/jq -r '.pastes[] | "\(.id)|\(.language // "-")|\(.created_at // "-")|\(.filename // "-")"' | while IFS='|' read -r id lang created filename; do 175 + age=$(format_age "$created") 176 + printf " %-24s %-10s %-10s %s\n" "$id" "$lang" "$age" "$filename" 177 + done 178 + 179 + echo 180 + ${pkgs.gum}/bin/gum style --foreground 117 "Select paste to copy URL:" 181 + 182 + selected=$(echo "$response" | ${pkgs.jq}/bin/jq -r '.pastes[].id' | ${pkgs.gum}/bin/gum choose --no-limit=false) 183 + 184 + if [ -n "$selected" ]; then 185 + url="$HOST/$selected" 186 + ${clipboardCopy} || true 187 + ${pkgs.gum}/bin/gum style --foreground 35 "✓ Copied: $url" 188 + fi 189 + } 190 + 191 + cmd_delete() { 192 + load_config 193 + check_config 194 + 195 + local id="$1" 196 + 197 + if [ -z "$id" ]; then 198 + ${pkgs.gum}/bin/gum style --foreground 196 "Usage: pbnj delete <id>" 199 + exit 1 200 + fi 201 + 202 + if ! ${pkgs.gum}/bin/gum confirm "Delete paste $id?"; then 203 + ${pkgs.gum}/bin/gum style --foreground 117 "Cancelled." 204 + exit 0 205 + fi 206 + 207 + ${pkgs.curl}/bin/curl -s -f -X DELETE \ 208 + -H "Authorization: Bearer $AUTH_KEY" \ 209 + "$HOST/api/$id" >/dev/null || { 210 + ${pkgs.gum}/bin/gum style --foreground 196 "Failed to delete paste" 211 + exit 1 212 + } 213 + 214 + ${pkgs.gum}/bin/gum style --foreground 35 "✓ Deleted" 215 + } 216 + 217 + cmd_delete_all() { 218 + load_config 219 + check_config 220 + 221 + if ! ${pkgs.gum}/bin/gum confirm "Delete ALL pastes? This cannot be undone."; then 222 + ${pkgs.gum}/bin/gum style --foreground 117 "Cancelled." 223 + exit 0 224 + fi 225 + 226 + ${pkgs.curl}/bin/curl -s -f -X DELETE \ 227 + -H "Authorization: Bearer $AUTH_KEY" \ 228 + "$HOST/api" >/dev/null || { 229 + ${pkgs.gum}/bin/gum style --foreground 196 "Failed to delete pastes" 230 + exit 1 231 + } 232 + 233 + ${pkgs.gum}/bin/gum style --foreground 35 "✓ All pastes deleted" 234 + } 235 + 236 + cmd_upload() { 237 + load_config 238 + check_config 239 + 240 + local content="" 241 + local filename="" 242 + local language="" 243 + local private="false" 244 + local key="" 245 + local update_id="" 246 + local no_copy="false" 247 + 248 + # Parse arguments 249 + while [ $# -gt 0 ]; do 250 + case "$1" in 251 + -L|--language) 252 + language="$2" 253 + shift 2 254 + ;; 255 + -f|--filename) 256 + filename="$2" 257 + shift 2 258 + ;; 259 + -p|--private) 260 + private="true" 261 + shift 262 + ;; 263 + -k|--key) 264 + key="$2" 265 + shift 2 266 + ;; 267 + -u|--update) 268 + update_id="$2" 269 + shift 2 270 + ;; 271 + -n|--no-copy) 272 + no_copy="true" 273 + shift 274 + ;; 275 + -|/dev/stdin) 276 + shift 277 + ;; 278 + *) 279 + # Assume it's a file 280 + if [ -f "$1" ]; then 281 + content=$(${pkgs.coreutils}/bin/cat "$1") 282 + if [ -z "$filename" ]; then 283 + filename=$(${pkgs.coreutils}/bin/basename "$1") 284 + fi 285 + else 286 + ${pkgs.gum}/bin/gum style --foreground 196 "File not found: $1" 287 + exit 1 288 + fi 289 + shift 290 + ;; 291 + esac 292 + done 293 + 294 + # Read from stdin if no file provided 295 + if [ -z "$content" ]; then 296 + if [ -t 0 ]; then 297 + ${pkgs.gum}/bin/gum style --foreground 196 "No input provided (pipe content or specify a file)" 298 + exit 1 299 + fi 300 + content=$(${pkgs.coreutils}/bin/cat) 301 + fi 302 + 303 + # Detect language if not specified 304 + if [ -z "$language" ] && [ -n "$filename" ]; then 305 + language=$(detect_language "$filename") 306 + fi 307 + 308 + # Build JSON payload 309 + payload=$(${pkgs.jq}/bin/jq -n \ 310 + --arg content "$content" \ 311 + --arg filename "$filename" \ 312 + --arg language "$language" \ 313 + --argjson private "$private" \ 314 + --arg key "$key" \ 315 + '{code: $content} + 316 + (if $filename != "" then {filename: $filename} else {} end) + 317 + (if $language != "" then {language: $language} else {} end) + 318 + (if $private then {private: true} else {} end) + 319 + (if $key != "" then {key: $key} else {} end)') 320 + 321 + # Make request 322 + local method="POST" 323 + local url="$HOST/api" 324 + 325 + if [ -n "$update_id" ]; then 326 + method="PUT" 327 + url="$HOST/api/$update_id" 328 + fi 329 + 330 + response=$(echo "$payload" | ${pkgs.curl}/bin/curl -s -f -X "$method" \ 331 + -H "Content-Type: application/json" \ 332 + -H "Authorization: Bearer $AUTH_KEY" \ 333 + -d @- \ 334 + "$url" 2>&1) || { 335 + ${pkgs.gum}/bin/gum style --foreground 196 "Failed to upload paste" 336 + echo "$response" >&2 337 + exit 1 338 + } 339 + 340 + paste_id=$(echo "$response" | ${pkgs.jq}/bin/jq -r '.id // empty') 341 + paste_url=$(echo "$response" | ${pkgs.jq}/bin/jq -r '.url // empty') 342 + 343 + if [ -z "$paste_url" ] && [ -n "$paste_id" ]; then 344 + paste_url="$HOST/$paste_id" 345 + fi 346 + 347 + # Copy to clipboard 348 + if [ "$no_copy" != "true" ]; then 349 + url="$paste_url" 350 + if ${clipboardCopy}; then 351 + ${pkgs.gum}/bin/gum style --foreground 35 "✓ Copied to clipboard" 352 + fi 353 + fi 354 + 355 + ${pkgs.gum}/bin/gum style --foreground 35 "$paste_url" 356 + } 357 + 358 + # Main 359 + case "''${1:-}" in 360 + init|--init) 361 + cmd_init 362 + ;; 363 + config|--show-config) 364 + cmd_config 365 + ;; 366 + list) 367 + shift 368 + cmd_list "$@" 369 + ;; 370 + -l|--list) 371 + shift 372 + cmd_list "$@" 373 + ;; 374 + delete|-d) 375 + shift 376 + cmd_delete "$@" 377 + ;; 378 + delete-all|-D) 379 + cmd_delete_all 380 + ;; 381 + -h|--help) 382 + ${pkgs.gum}/bin/gum style --bold --foreground 212 "pbnj - pastebin CLI" 383 + echo 384 + echo "Usage: pbnj [options] [file]" 385 + echo " cat file | pbnj" 386 + echo 387 + echo "Commands:" 388 + echo " init Configure pbnj instance" 389 + echo " config Show current configuration" 390 + echo " list [n] List recent pastes (default: 10)" 391 + echo " delete <id> Delete a paste" 392 + echo " delete-all Delete all pastes" 393 + echo 394 + echo "Options:" 395 + echo " -L, --language <lang> Override language detection" 396 + echo " -f, --filename <name> Set custom filename" 397 + echo " -p, --private Create private paste" 398 + echo " -k, --key <key> Add secret key" 399 + echo " -u, --update <id> Update existing paste" 400 + echo " -n, --no-copy Don't copy URL to clipboard" 401 + echo " -l, --list [n] List recent pastes" 402 + echo " -h, --help Show this help" 403 + ;; 404 + -*) 405 + # Flags for upload 406 + cmd_upload "$@" 407 + ;; 408 + "") 409 + # No args, try stdin 410 + cmd_upload "$@" 411 + ;; 412 + *) 413 + # File argument 414 + cmd_upload "$@" 415 + ;; 416 + esac 417 + ''; 418 + 419 + pbnj = pkgs.stdenv.mkDerivation { 420 + pname = "pbnj"; 421 + version = "1.0"; 422 + 423 + dontUnpack = true; 424 + 425 + nativeBuildInputs = with pkgs; [ pandoc installShellFiles ]; 426 + 427 + manPageSrc = ./pbnj.1.md; 428 + bashCompletionSrc = ./completions/pbnj.bash; 429 + zshCompletionSrc = ./completions/pbnj.zsh; 430 + fishCompletionSrc = ./completions/pbnj.fish; 431 + 432 + buildPhase = '' 433 + ${pkgs.pandoc}/bin/pandoc -s -t man $manPageSrc -o pbnj.1 434 + ''; 435 + 436 + installPhase = '' 437 + mkdir -p $out/bin 438 + 439 + cp ${pbnjScript} $out/bin/pbnj 440 + chmod +x $out/bin/pbnj 441 + 442 + installManPage pbnj.1 443 + 444 + installShellCompletion --bash --name pbnj $bashCompletionSrc 445 + installShellCompletion --zsh --name _pbnj $zshCompletionSrc 446 + installShellCompletion --fish --name pbnj.fish $fishCompletionSrc 447 + ''; 448 + 449 + meta = with lib; { 450 + description = "Pastebin CLI with charm"; 451 + homepage = "https://github.com/bhavnicksm/pbnj"; 452 + license = licenses.mit; 453 + maintainers = [ ]; 454 + }; 455 + }; 456 + in 457 + { 458 + options.atelier.pbnj = { 459 + enable = lib.mkEnableOption "pbnj pastebin CLI"; 460 + 461 + host = lib.mkOption { 462 + type = lib.types.nullOr lib.types.str; 463 + default = null; 464 + description = "pbnj instance URL"; 465 + }; 466 + 467 + authKeyFile = lib.mkOption { 468 + type = lib.types.nullOr lib.types.path; 469 + default = null; 470 + description = "Path to file containing auth key (e.g. agenix secret)"; 471 + }; 472 + }; 473 + 474 + config = lib.mkIf cfg.enable { 475 + home.packages = [ pbnj ]; 476 + }; 477 + }
+103
modules/home/apps/pbnj/pbnj.1.md
··· 1 + % PBNJ(1) pbnj 1.0 2 + % 3 + % January 2026 4 + 5 + # NAME 6 + 7 + pbnj - pastebin CLI 8 + 9 + # SYNOPSIS 10 + 11 + **pbnj** [*OPTIONS*] [*FILE*] 12 + 13 + **cat** *file* | **pbnj** 14 + 15 + # DESCRIPTION 16 + 17 + **pbnj** is a command-line interface for uploading and managing code snippets on a pbnj pastebin instance. 18 + 19 + # COMMANDS 20 + 21 + **init** 22 + : Configure pbnj instance (host URL and auth key). 23 + 24 + **config** 25 + : Show current configuration. 26 + 27 + **list** [*n*] 28 + : List recent pastes (default: 10). Interactive selection to copy URL. 29 + 30 + **delete** *id* 31 + : Delete a specific paste. 32 + 33 + **delete-all** 34 + : Delete all pastes (with confirmation). 35 + 36 + # OPTIONS 37 + 38 + **-L**, **--language** *lang* 39 + : Override automatic language detection. 40 + 41 + **-f**, **--filename** *name* 42 + : Set custom filename for the paste. 43 + 44 + **-p**, **--private** 45 + : Create private/unlisted paste. 46 + 47 + **-k**, **--key** *key* 48 + : Add secret key to paste. 49 + 50 + **-u**, **--update** *id* 51 + : Update an existing paste by ID. 52 + 53 + **-n**, **--no-copy** 54 + : Don't automatically copy URL to clipboard. 55 + 56 + **-l**, **--list** [*n*] 57 + : List recent pastes. 58 + 59 + **-h**, **--help** 60 + : Show help message. 61 + 62 + # EXAMPLES 63 + 64 + Upload a file: 65 + 66 + pbnj script.py 67 + 68 + Pipe content: 69 + 70 + cat file.txt | pbnj 71 + 72 + Upload with custom language: 73 + 74 + pbnj -L rust main.rs 75 + 76 + Create private paste: 77 + 78 + pbnj -p secret.txt 79 + 80 + Update existing paste: 81 + 82 + pbnj -u crunchy-peanut updated.py 83 + 84 + List recent pastes: 85 + 86 + pbnj list 20 87 + 88 + # CONFIGURATION 89 + 90 + Configuration is stored in **~/.pbnj.json** or can be set via environment variables: 91 + 92 + **PBNJ_HOST** 93 + : The pbnj instance URL. 94 + 95 + **PBNJ_AUTH_KEY** 96 + : Authentication key. 97 + 98 + **PBNJ_CONFIG** 99 + : Override config file path. 100 + 101 + # SEE ALSO 102 + 103 + **curl**(1), **jq**(1)
+13
secrets/pbnj.age
··· 1 + age-encryption.org/v1 2 + -> ssh-rsa DqcG0Q 3 + MGtlHPaqmXCFdy9L0hWX8+jFYnr4OoDJMkWCyKWD6ZROVqQpmZSA5rSR6K10pQfl 4 + KcHhlfWDApzQdpI70IGFglvH27coIQQ718kP/HnlLyAW0zCLxTxt1tz6uOHmKepO 5 + DlSj8zGzED324pu7wmTz7Ji5VS3UdiKCcYx8UNg/AepCeFJSKQiouiBCUGFh4h6v 6 + V3jI/LT/RifEwIoJAmj/w7ba3RWdaQm0+0t+TRu81ZZNzk2d8rDoVPsG6QybE44p 7 + XOHhsOgcvDmhqFXw6UyWQWI0zKJ1dB71rRU7kjUeMvs+QvMEQ/Poi4h3QyblWpEZ 8 + q5wa7v9QEEMd1aXw3KMsDY1GWzprsejU3mdHAcp+xQgOe6kh3upsdPQ8vkPXaq4f 9 + 6b2BvI1+MErzMKGuXgHWyGTyhcZEaVhPR13LIKjkuzUhTGwfHA/4k6yt1UQdpD8D 10 + AAQgWWTHfGbSSktaXtp/QSwl/E17PrPlFObIX0Yb22r8+krhJI+xPPGUvza5fjal 11 + 12 + --- 9NHTxSngPXZ/0VOvf0oP2ONipWdbrfjVmaOWEAw4baU 13 + ��+I�@�k3��5)Kai �`=��K�='�}��Z}^��O8݁�D^��"�����D4�����\U鹺�
+3
secrets/secrets.nix
··· 74 74 "zai.age".publicKeys = [ 75 75 kierank 76 76 ]; 77 + "pbnj.age".publicKeys = [ 78 + kierank 79 + ]; 77 80 }