From effa01310bfe91ef7a39a035f021a0dc4e345e58 Mon Sep 17 00:00:00 2001 From: "RingOfStorms (Joshua Bell)" Date: Sun, 4 Jan 2026 22:36:24 -0600 Subject: [PATCH] add gcpropose helper command --- flakes/common/hm_modules/ssh.nix | 4 +- flakes/common/nix_modules/git/default.nix | 2 + .../common/nix_modules/git/gcpropose.func.sh | 177 ++++++++++++++++++ hosts/oren/flake.lock | 58 +++--- hosts/oren/flake.nix | 4 +- 5 files changed, 210 insertions(+), 35 deletions(-) create mode 100644 flakes/common/nix_modules/git/gcpropose.func.sh diff --git a/flakes/common/hm_modules/ssh.nix b/flakes/common/hm_modules/ssh.nix index db4685a8..59f208a2 100644 --- a/flakes/common/hm_modules/ssh.nix +++ b/flakes/common/hm_modules/ssh.nix @@ -33,7 +33,9 @@ in controlMaster = "no"; controlPath = "~/.ssh/master-%r@%n:%p"; controlPersist = "no"; - StrictHostKeyChecking = "accept-new"; + extraOptions = { + StrictHostKeyChecking = "accept-new"; + }; }; # EXTERNAL diff --git a/flakes/common/nix_modules/git/default.nix b/flakes/common/nix_modules/git/default.nix index 3a4c5bc8..b90012a1 100644 --- a/flakes/common/nix_modules/git/default.nix +++ b/flakes/common/nix_modules/git/default.nix @@ -22,6 +22,7 @@ with lib; bx = "branchdel"; b = "branch"; bs = "branching_setup"; + gcp = "gcpropose"; }; environment.shellInit = lib.concatStringsSep "\n\n" [ @@ -30,5 +31,6 @@ with lib; (builtins.readFile ./branchd.func.sh) (builtins.readFile ./link_ignored.func.sh) (builtins.readFile ./branching_setup.func.sh) + (builtins.readFile ./gcpropose.func.sh) ]; } diff --git a/flakes/common/nix_modules/git/gcpropose.func.sh b/flakes/common/nix_modules/git/gcpropose.func.sh new file mode 100644 index 00000000..b236bf38 --- /dev/null +++ b/flakes/common/nix_modules/git/gcpropose.func.sh @@ -0,0 +1,177 @@ +gcpropose() { + local LITELLM_BASE_URL="http://h001.net.joshuabell.xyz:8094" + local LITELLM_MODEL="azure-gpt-5-mini-2025-08-07" + + local mode="staged" + while [ $# -gt 0 ]; do + case "$1" in + -a) mode="all"; shift ;; + -h|--help) + cat <&2 + return 2 + ;; + esac + done + + if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then + echo "Not inside a git repository." >&2 + return 1 + fi + + if ! command -v curl >/dev/null 2>&1; then + echo "Missing dependency: curl" >&2 + return 1 + fi + if ! command -v jq >/dev/null 2>&1; then + echo "Missing dependency: jq" >&2 + return 1 + fi + + local diff + if [ "$mode" = "all" ]; then + diff=$(git diff HEAD) + else + diff=$(git diff --staged) + fi + + if [ -z "$diff" ]; then + if [ "$mode" = "all" ]; then + echo "No changes vs HEAD." >&2 + else + echo "No staged changes." >&2 + fi + return 1 + fi + + local git_status + git_status=$(git status --porcelain=v1 2>/dev/null || true) + + local max_chars=10000 + diff=$(printf "%s" "$diff" | head -c "$max_chars") + + local name_status + if [ "$mode" = "all" ]; then + name_status=$(git diff --name-status HEAD 2>/dev/null || true) + else + name_status=$(git diff --name-status --staged 2>/dev/null || true) + fi + + local prompt + prompt=$(cat <&2 + printf "%s\n" "$body" >&2 + return 1 + fi + + local message + message=$(printf "%s" "$body" | jq -r ' + .choices[0].message.content + | if type == "string" then . + elif type == "array" then (map(select(.type=="text") | .text) | join("")) + else "" + end + ' 2>/dev/null || true) + message=$(printf "%s" "$message" | sed -n '1p' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') + + if [ -n "$message" ] && [ "$message" != "null" ]; then + printf "%s\n" "$message" + return 0 + fi + + local payload_responses + payload_responses=$(jq -n \ + --arg model "$LITELLM_MODEL" \ + --arg input "$prompt" \ + '{ + model: $model, + input: $input, + max_output_tokens: 64 + }') + + curl_out=$(curl -sS -w "\n%{http_code}" \ + -X POST "${LITELLM_BASE_URL}/v1/responses" \ + -H "Content-Type: application/json" \ + ${LITELLM_API_KEY:+-H "Authorization: Bearer ${LITELLM_API_KEY}"} \ + -d "$payload_responses") || return 1 + + http_code=$(printf "%s" "$curl_out" | tail -n 1) + body=$(printf "%s" "$curl_out" | sed '$d') + + if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then + echo "LiteLLM request failed (HTTP $http_code)." >&2 + printf "%s\n" "$body" >&2 + return 1 + fi + + message=$(printf "%s" "$body" | jq -r '(.output_text // empty)' 2>/dev/null || true) + message=$(printf "%s" "$message" | sed -n '1p' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') + + if [ -z "$message" ] || [ "$message" = "null" ]; then + echo "Failed to parse model response." >&2 + printf "%s\n" "$body" >&2 + return 1 + fi + + printf "%s\n" "$message" +} diff --git a/hosts/oren/flake.lock b/hosts/oren/flake.lock index 7d550e14..46a5e666 100644 --- a/hosts/oren/flake.lock +++ b/hosts/oren/flake.lock @@ -31,11 +31,11 @@ }, "locked": { "dir": "flakes/beszel", - "lastModified": 1767572382, - "narHash": "sha256-oDoVrmMpww4uY3Ez1XzrHsxJTZmBMiOO/mNrU2njiWQ=", + "lastModified": 1767575724, + "narHash": "sha256-L+3hoO4t3RCXkp9RXyXpJlCkzj6AdTOsstUv7RphEBM=", "ref": "refs/heads/master", - "rev": "165f87ebc19a48b56008738d01c5e2e5bebbbdfd", - "revCount": 1038, + "rev": "f86b8085c2ad39986c194b28d51260f8f402572a", + "revCount": 1041, "type": "git", "url": "https://git.joshuabell.xyz/ringofstorms/dotfiles" }, @@ -63,20 +63,14 @@ }, "common": { "locked": { - "dir": "flakes/common", - "lastModified": 1767572382, - "narHash": "sha256-oDoVrmMpww4uY3Ez1XzrHsxJTZmBMiOO/mNrU2njiWQ=", - "ref": "refs/heads/master", - "rev": "165f87ebc19a48b56008738d01c5e2e5bebbbdfd", - "revCount": 1038, - "type": "git", - "url": "https://git.joshuabell.xyz/ringofstorms/dotfiles" + "path": "../../flakes/common", + "type": "path" }, "original": { - "dir": "flakes/common", - "type": "git", - "url": "https://git.joshuabell.xyz/ringofstorms/dotfiles" - } + "path": "../../flakes/common", + "type": "path" + }, + "parent": [] }, "crane": { "locked": { @@ -123,11 +117,11 @@ }, "locked": { "dir": "flakes/de_plasma", - "lastModified": 1767572382, - "narHash": "sha256-oDoVrmMpww4uY3Ez1XzrHsxJTZmBMiOO/mNrU2njiWQ=", + "lastModified": 1767575724, + "narHash": "sha256-L+3hoO4t3RCXkp9RXyXpJlCkzj6AdTOsstUv7RphEBM=", "ref": "refs/heads/master", - "rev": "165f87ebc19a48b56008738d01c5e2e5bebbbdfd", - "revCount": 1038, + "rev": "f86b8085c2ad39986c194b28d51260f8f402572a", + "revCount": 1041, "type": "git", "url": "https://git.joshuabell.xyz/ringofstorms/dotfiles" }, @@ -161,11 +155,11 @@ }, "locked": { "dir": "flakes/flatpaks", - "lastModified": 1767572382, - "narHash": "sha256-oDoVrmMpww4uY3Ez1XzrHsxJTZmBMiOO/mNrU2njiWQ=", + "lastModified": 1767575724, + "narHash": "sha256-L+3hoO4t3RCXkp9RXyXpJlCkzj6AdTOsstUv7RphEBM=", "ref": "refs/heads/master", - "rev": "165f87ebc19a48b56008738d01c5e2e5bebbbdfd", - "revCount": 1038, + "rev": "f86b8085c2ad39986c194b28d51260f8f402572a", + "revCount": 1041, "type": "git", "url": "https://git.joshuabell.xyz/ringofstorms/dotfiles" }, @@ -1237,11 +1231,11 @@ }, "locked": { "dir": "flakes/opencode", - "lastModified": 1767572382, - "narHash": "sha256-oDoVrmMpww4uY3Ez1XzrHsxJTZmBMiOO/mNrU2njiWQ=", + "lastModified": 1767575724, + "narHash": "sha256-L+3hoO4t3RCXkp9RXyXpJlCkzj6AdTOsstUv7RphEBM=", "ref": "refs/heads/master", - "rev": "165f87ebc19a48b56008738d01c5e2e5bebbbdfd", - "revCount": 1038, + "rev": "f86b8085c2ad39986c194b28d51260f8f402572a", + "revCount": 1041, "type": "git", "url": "https://git.joshuabell.xyz/ringofstorms/dotfiles" }, @@ -1446,11 +1440,11 @@ }, "locked": { "dir": "flakes/secrets", - "lastModified": 1767572382, - "narHash": "sha256-oDoVrmMpww4uY3Ez1XzrHsxJTZmBMiOO/mNrU2njiWQ=", + "lastModified": 1767575724, + "narHash": "sha256-L+3hoO4t3RCXkp9RXyXpJlCkzj6AdTOsstUv7RphEBM=", "ref": "refs/heads/master", - "rev": "165f87ebc19a48b56008738d01c5e2e5bebbbdfd", - "revCount": 1038, + "rev": "f86b8085c2ad39986c194b28d51260f8f402572a", + "revCount": 1041, "type": "git", "url": "https://git.joshuabell.xyz/ringofstorms/dotfiles" }, diff --git a/hosts/oren/flake.nix b/hosts/oren/flake.nix index 8bcc0f1c..ffda7202 100644 --- a/hosts/oren/flake.nix +++ b/hosts/oren/flake.nix @@ -6,8 +6,8 @@ nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable"; # Use relative to get current version for testin - # common.url = "path:../../flakes/common"; - common.url = "git+https://git.joshuabell.xyz/ringofstorms/dotfiles?dir=flakes/common"; + common.url = "path:../../flakes/common"; + # common.url = "git+https://git.joshuabell.xyz/ringofstorms/dotfiles?dir=flakes/common"; # secrets.url = "path:../../flakes/secrets"; secrets.url = "git+https://git.joshuabell.xyz/ringofstorms/dotfiles?dir=flakes/secrets"; # flatpaks.url = "path:../../flakes/flatpaks";