diff --git a/cstm_cmt_msg_rules.md b/cstm_cmt_msg_rules.md new file mode 100644 index 0000000..7f81def --- /dev/null +++ b/cstm_cmt_msg_rules.md @@ -0,0 +1,46 @@ +# Custom Commit Message Rules + +## Format +- Subject line: imperative verb + what changed (50 chars max) +- Body: explain WHY, not what (the diff shows what) +- Use present tense: "Add feature" not "Added feature" + +## Structure +First line: : + +Body (if needed): +- Context: Why was this change necessary? +- Impact: What does this enable or fix? +- Notes: Any caveats, side effects, or follow-up needed + +## Type Prefixes +Use one of these tags: +- feat: New feature or capability +- fix: Bug fix or correction +- refactor: Code restructuring without behavior change +- perf: Performance improvement +- docs: Documentation only +- test: Test additions or updates +- chore: Build, tooling, dependencies +- style: Formatting, whitespace, naming + +## Content Guidelines +- Be specific: "Fix null pointer in user login" not "Fix bug" +- Mention affected area: "auth:", "ui:", "api:", etc. when relevant +- Avoid obvious statements: don't say "update file X" if that's clear from diff +- Include ticket/issue reference if applicable: "Fixes #123" + +## Examples +Good: +- feat(auth): Add OAuth2 token refresh logic +- fix(api): Prevent race condition in cache writes +- refactor(db): Extract query builder to separate module + +Bad: +- Updated files +- Changes +- Fixed stuff +- WIP + +## Output Format +Plain text only. No markdown formatting (**bold**, `code`, etc.) \ No newline at end of file diff --git a/resources/diffsense.sh b/resources/diffsense.sh index ecac813..8ef57c8 100755 --- a/resources/diffsense.sh +++ b/resources/diffsense.sh @@ -149,7 +149,7 @@ set_max_chars_for_model() { DIFFSENSE_MAX_CHARS=1194000 ;; *) - DIFFSENSE_MAX_CHARS=10000 + DIFFSENSE_MAX_CHARS=8000 ;; esac } @@ -157,28 +157,32 @@ set_max_chars_for_model() { # ---------- help ---------- print_help() { cat <<'EOF' -Usage: diffsense [MESSAGE STYLE] [AI MODEL] [OPTIONS] +Usage: diffsense [--byo=] [STYLE] [MODEL] [OPTIONS] + +BYO (Bring Your Own Prompt): + --byo= Custom prompt file (max 400 chars), relative to current dir. STYLE: - default Default style. Works when nothing is specified - verbose Detailed multi-line commit message - minimal Single-line, 72-char max subject + --default Default style (if nothing specified) + --verbose Detailed multi-line commit message + --minimal Single-line, 50-char max subject MODEL: - afm On-device (LOCAL) model. [DEFAULT MODEL] - pcc Perplexity (PRIVATE) model - gpt ChatGPT / OpenAI model + --afm On-device (LOCAL) model [DEFAULT] + --pcc Perplexity (PRIVATE) model + --gpt ChatGPT / OpenAI model OPTIONS: --nopopup Disable popup editor in the Shortcut - -h, --help Show this help message and exit + -h, --help Show this help message Examples: diffsense diffsense --verbose diffsense --verbose --gpt + diffsense --byo=.diffsense-prompt --verbose --gpt + diffsense --byo=prompts/rules.txt --minimal diffsense --nopopup - diffsense --minimal --nopopup EOF } @@ -187,8 +191,15 @@ parse_args() { local message_style="default" local ai_model="afm" local nopopup_suffix="" + local byo_path="" for raw_arg in "$@"; do + # Handle --byo=path separately (before stripping --) + if [[ "$raw_arg" == --byo=* ]]; then + byo_path="${raw_arg#--byo=}" + continue + fi + local arg="${raw_arg#--}" case "$arg" in @@ -215,9 +226,11 @@ parse_args() { gpt) ai_model_internal="CHATGPT" ;; esac - echo "$ai_model_internal $message_style $nopopup_suffix" + # Use | as delimiter to handle empty fields + echo "${ai_model_internal}|${message_style}|${nopopup_suffix}|${byo_path}" } + # ---------- platform ---------- check_platform_and_arch() { local arch os_major @@ -268,7 +281,6 @@ check_git_state() { fi } -# ---------- build prompt ---------- # ---------- build prompt ---------- build_prompt() { case "$1" in @@ -317,6 +329,67 @@ Constraints: esac } +# ---------- load BYO (bring your own) prompt ---------- +load_byo_prompt() { + local path="$1" + local max_chars=400 + + # No path provided = no BYO + if [[ -z "$path" ]]; then + return 0 + fi + + # Trim whitespace/newlines + path="${path#"${path%%[![:space:]]*}"}" + path="${path%"${path##*[![:space:]]}"}" + + # Resolve path relative to current directory + local resolved_path + if [[ "$path" == /* ]]; then + resolved_path="$path" + elif [[ "$path" == ~* ]]; then + resolved_path="${path/#\~/$HOME}" + else + resolved_path="$(pwd)/$path" + fi + + # Check file exists + if [[ ! -f "$resolved_path" ]]; then + echo "⚠️ BYO file not found: $path → Falling back to base prompt." >&2 + return 0 + fi + + # Check file is readable + if [[ ! -r "$resolved_path" ]]; then + echo "⚠️ BYO file unreadable: $path → Falling back to base prompt." >&2 + return 0 + fi + + # Read content using cat + local content + content=$(cat "$resolved_path") + if [[ $? -ne 0 ]]; then + echo "⚠️ BYO file parse error: $path → Falling back to base prompt." >&2 + return 0 + fi + + # Check if empty + if [[ -z "$content" ]]; then + echo "⚠️ BYO file is empty: $path → Falling back to base prompt." >&2 + return 0 + fi + + # Check length + if (( ${#content} > max_chars )); then + echo "⚠️ BYO exceeds ${max_chars} chars (${#content}) → Falling back to base prompt." >&2 + return 0 + fi + + # Success + printf '%s' "$content" +} + + # ---------- build exclude args ---------- build_diff_excludes() { @@ -557,7 +630,6 @@ build_allocated_diff() { echo "${preamble}${files_header}${file_summary}${diff_header}${final_diff}" } - # ---------- prepare diff ---------- prepare_diff() { local header="$1" @@ -605,8 +677,8 @@ commit_changes() { # ---------- main ---------- diffsense() { - local parsed ai_model message_style nopopup_suffix - local diff header prompt payload commit_msg + local parsed ai_model message_style nopopup_suffix byo_path + local diff header prompt byo_prompt payload commit_msg if [[ "$#" -gt 0 ]]; then case "$1" in @@ -621,17 +693,28 @@ diffsense() { exit 1 fi - ai_model=$(awk '{print $1}' <<< "$parsed") - message_style=$(awk '{print $2}' <<< "$parsed") - nopopup_suffix=$(awk '{print $3}' <<< "$parsed") + # Parse with | delimiter + IFS='|' read -r ai_model message_style nopopup_suffix byo_path <<< "$parsed" + + # DEBUG set_max_chars_for_model "$ai_model" check_platform_and_arch || exit 1 check_is_git_repo check_git_state + # Build base prompt prompt=$(build_prompt "$message_style") + + # Load and append BYO prompt if provided + if [[ -n "$byo_path" ]]; then + byo_prompt=$(load_byo_prompt "$byo_path") + if [[ -n "$byo_prompt" ]]; then + prompt="${prompt}"$'\n\n'"Additional Instructions:"$'\n'"${byo_prompt}" + fi + fi + header="@@DIFFSENSE_META=${ai_model}${nopopup_suffix}" # Main diff strategy @@ -639,7 +722,7 @@ diffsense() { payload="${header}"$'\n'"${prompt}"$'\n\n'"${diff}" - # SAFETY: Final truncation to guarantee we never exceed the limit + # SAFETY: Final truncation to guarantee we never exceed the limit if (( ${#payload} > DIFFSENSE_MAX_CHARS )); then payload="${payload:0:DIFFSENSE_MAX_CHARS}" fi @@ -648,4 +731,6 @@ diffsense() { commit_changes "$commit_msg" } +diffsense "$@" + diffsense "$@" \ No newline at end of file