Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 153 additions & 4 deletions .agents/scripts/profile-readme-helper.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
# profile-readme-helper.sh — Auto-update GitHub profile README with live stats
#
# Usage:
# profile-readme-helper.sh update [--dry-run] # Update README with live data
# profile-readme-helper.sh init # Create profile repo, seed README, register
# profile-readme-helper.sh update [--dry-run] # Update README with live data
# profile-readme-helper.sh generate # Print generated stats section to stdout
# profile-readme-helper.sh help
#
Expand Down Expand Up @@ -573,7 +574,8 @@
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
${model_rows}| **Total** | **${f_total_req}** | **${f_total_in}** | **${f_total_out}** | **${f_total_cache}** | **\$${total_cost}** | **\$${f_total_csavings}** | **\$${f_total_msavings}** |

_${f_all_tokens} total tokens processed. ${cache_pct}% cache hit rate. \$${combined_savings} total saved (\$${f_total_csavings} caching + \$${f_total_msavings} model routing vs all-Opus)._
_${f_all_tokens} total tokens processed. ${cache_pct}% cache hit rate. \$${combined_savings} total saved (\$${f_total_csavings} caching + \$${f_total_msavings} model routing vs all-Opus).
Model savings are modest because ~${cache_pct}% of tokens are cache reads, where price differences between models are small._
EOF

# Build top apps table (macOS only — requires Knowledge DB)
Expand Down Expand Up @@ -616,6 +618,151 @@
return 0
}

# --- Initialize profile README repo ---
# Creates the username/username GitHub repo if it doesn't exist, clones it,
# seeds a starter README with stat markers, and registers it in repos.json.
cmd_init() {
# Require gh CLI
if ! command -v gh &>/dev/null; then
echo "Error: gh CLI required. Install from https://cli.github.com" >&2
return 1
fi

# Get GitHub username
local gh_user
gh_user=$(gh api user --jq '.login' 2>/dev/null) || {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Suppressing stderr with 2>/dev/null for the gh api call hides potentially useful error messages. If the command fails for reasons other than authentication (e.g., network issues, API changes), the || block will execute, but you lose valuable debugging information from the gh CLI itself. It's better to let gh print its own errors to stderr.

Suggested change
gh_user=$(gh api user --jq '.login' 2>/dev/null) || {
gh_user=$(gh api user --jq '.login') || {
References
  1. Avoid using '2>/dev/null' for blanket suppression of command errors in shell scripts to ensure that authentication, syntax, or system issues remain visible for debugging.

echo "Error: not authenticated with gh CLI. Run 'gh auth login' first." >&2
return 1
}

local repo_slug="${gh_user}/${gh_user}"
local repo_dir="${HOME}/Git/${gh_user}"
local repos_json="${HOME}/.config/aidevops/repos.json"

# Check if already initialized
if [[ -f "$repos_json" ]] && command -v jq &>/dev/null; then
local existing_profile
existing_profile=$(jq -r '
if .initialized_repos then
.initialized_repos[] | select(.priority == "profile") | .path
else
to_entries[] | select(.value.priority == "profile") | .value.path
end
' "$repos_json" 2>/dev/null | head -1)
Comment on lines +645 to +651

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Suppressing stderr for jq with 2>/dev/null can hide important errors. If repos.json is malformed, jq will fail silently, and the script might proceed with incorrect assumptions. Removing 2>/dev/null will make parsing errors visible, which is crucial for debugging.

Suggested change
existing_profile=$(jq -r '
if .initialized_repos then
.initialized_repos[] | select(.priority == "profile") | .path
else
to_entries[] | select(.value.priority == "profile") | .value.path
end
' "$repos_json" 2>/dev/null | head -1)
existing_profile=$(jq -r '
if .initialized_repos then
.initialized_repos[] | select(.priority == "profile") | .path
else
to_entries[] | select(.value.priority == "profile") | .value.path
end
' "$repos_json" | head -1)
References
  1. When reporting errors for failed file operations in shell scripts, such as 'jq' writes, include the file path in the error message. Avoid suppressing stderr with '2>/dev/null' to ensure that diagnostic information about malformed files or write failures is visible.

if [[ -n "$existing_profile" && "$existing_profile" != "null" ]]; then
if [[ -d "$existing_profile" ]]; then

Check warning on line 653 in .agents/scripts/profile-readme-helper.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Merge this if statement with the enclosing one.

See more on https://sonarcloud.io/project/issues?id=marcusquinn_aidevops&issues=AZzQtYv3wGcokXvEVJ96&open=AZzQtYv3wGcokXvEVJ96&pullRequest=3954
echo "Profile repo already initialized at $existing_profile"
return 0
fi
fi
fi

# Create the repo on GitHub if it doesn't exist
if ! gh repo view "$repo_slug" &>/dev/null; then
echo "Creating GitHub profile repo: $repo_slug"
gh repo create "$repo_slug" --public --add-readme --description "GitHub profile README" || {
echo "Error: failed to create repo $repo_slug" >&2
return 1
}
else
echo "GitHub repo $repo_slug already exists"
fi

# Clone if not already local
if [[ ! -d "$repo_dir" ]]; then
echo "Cloning $repo_slug to $repo_dir"
git clone "git@github.com:${repo_slug}.git" "$repo_dir" 2>/dev/null ||

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While the intention to silently fall back from SSH to HTTPS for git clone is clear, suppressing stderr with 2>/dev/null hides all errors. This includes potential configuration issues or other problems unrelated to SSH key availability, which could be valuable for debugging. It's better to allow error messages to be visible. For git clone, consider using the -q flag to suppress standard output while keeping stderr visible for debugging.

Suggested change
git clone "git@github.com:${repo_slug}.git" "$repo_dir" 2>/dev/null ||
git clone -q "git@github.com:${repo_slug}.git" "$repo_dir" ||
References
  1. When using git commands (like 'init', 'remote') in shell scripts, use the '-q' flag to suppress standard output instead of '2>/dev/null', ensuring that error messages on stderr remain visible for debugging.

git clone "https://github.com/${repo_slug}.git" "$repo_dir" || {
echo "Error: failed to clone $repo_slug" >&2
return 1
}
else
echo "Local repo already exists at $repo_dir"
fi

# Seed README.md if it doesn't have stat markers
local readme_path="${repo_dir}/README.md"
if [[ ! -f "$readme_path" ]] || ! grep -q '<!-- STATS-START -->' "$readme_path"; then
echo "Creating starter README with stat markers"

# Get display name from git config or GitHub
local display_name
display_name=$(git config --global user.name 2>/dev/null || echo "$gh_user")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Suppressing stderr for git config with 2>/dev/null can hide underlying issues with the git configuration. If the command fails for a reason other than user.name not being set, the error message would be lost, making debugging harder. It's better to let potential errors be displayed.

Suggested change
display_name=$(git config --global user.name 2>/dev/null || echo "$gh_user")
display_name=$(git config --global user.name || echo "$gh_user")
References
  1. Avoid using '2>/dev/null' for blanket suppression of command errors in shell scripts to ensure that authentication, syntax, or system issues remain visible for debugging.


cat >"$readme_path" <<README
# ${display_name}

> Shipping with AI agents around the clock -- human hours for thinking, machine hours for doing.
> Stats auto-updated by [aidevops](https://aidevops.sh).

<!-- STATS-START -->
<!-- Stats will be populated on first update -->
<!-- STATS-END -->

<!-- UPDATED-START -->
<!-- UPDATED-END -->
README

git -C "$repo_dir" add README.md
git -C "$repo_dir" commit -m "feat: initialize profile README with aidevops stat markers" --no-verify 2>/dev/null || true

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using 2>/dev/null with git commit suppresses potentially important error messages. For instance, if git is not configured with a user name/email, the commit will fail, but the reason will be hidden. The || true correctly prevents the script from exiting, but removing 2>/dev/null would improve debuggability by showing why the command failed.

Suggested change
git -C "$repo_dir" commit -m "feat: initialize profile README with aidevops stat markers" --no-verify 2>/dev/null || true
git -C "$repo_dir" commit -m "feat: initialize profile README with aidevops stat markers" --no-verify || true
References
  1. In shell scripts with 'set -e' enabled, use '|| true' to prevent the script from exiting when a command like 'jq' fails on an optional lookup. Do not suppress stderr with '2>/dev/null' so that actual syntax or system errors remain visible for debugging.

git -C "$repo_dir" push origin main 2>/dev/null || git -C "$repo_dir" push origin master 2>/dev/null || {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Suppressing stderr for git push with 2>/dev/null hides the reason for push failures. If both pushes to main and master fail, the user only gets a generic 'failed to push' warning without knowing why (e.g., authentication failure, network error, non-fast-forward updates). Removing 2>/dev/null will provide the actual error message from git, which is crucial for debugging.

Suggested change
git -C "$repo_dir" push origin main 2>/dev/null || git -C "$repo_dir" push origin master 2>/dev/null || {
git -C "$repo_dir" push origin main || git -C "$repo_dir" push origin master || {
References
  1. Avoid using '2>/dev/null' for blanket suppression of command errors in shell scripts to ensure that authentication, syntax, or system issues remain visible for debugging.

echo "Warning: failed to push initial README — push manually" >&2
}
fi

# Register in repos.json
if [[ -f "$repos_json" ]] && command -v jq &>/dev/null; then
# Check if already registered
local already_registered
already_registered=$(jq -r --arg path "$repo_dir" '
if .initialized_repos then
[.initialized_repos[] | select(.path == $path)] | length
else
[to_entries[] | select(.value.path == $path)] | length
end
' "$repos_json" 2>/dev/null)
Comment on lines +717 to +723

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Suppressing stderr for jq with 2>/dev/null can hide important errors. If repos.json is malformed, jq will fail silently, and the script might proceed with incorrect assumptions. Removing 2>/dev/null will make parsing errors visible, aiding in debugging.

Suggested change
already_registered=$(jq -r --arg path "$repo_dir" '
if .initialized_repos then
[.initialized_repos[] | select(.path == $path)] | length
else
[to_entries[] | select(.value.path == $path)] | length
end
' "$repos_json" 2>/dev/null)
already_registered=$(jq -r --arg path "$repo_dir" '
if .initialized_repos then
[.initialized_repos[] | select(.path == $path)] | length
else
[to_entries[] | select(.value.path == $path)] | length
end
' "$repos_json")
References
  1. When reporting errors for failed file operations in shell scripts, such as 'jq' writes, include the file path in the error message. Avoid suppressing stderr with '2>/dev/null' to ensure that diagnostic information about malformed files or write failures is visible.


if [[ "$already_registered" == "0" ]]; then
echo "Registering profile repo in repos.json"
local tmp_json
tmp_json=$(mktemp)
jq --arg path "$repo_dir" --arg slug "$repo_slug" '
.initialized_repos += [{
"path": $path,
"slug": $slug,
"priority": "profile",
"pulse": false,
"maintainer": ($slug | split("/")[0])
}]
' "$repos_json" >"$tmp_json" && mv "$tmp_json" "$repos_json"
else
# Ensure priority is set to "profile"
local tmp_json
tmp_json=$(mktemp)
jq --arg path "$repo_dir" '
.initialized_repos |= map(
if .path == $path then .priority = "profile" else . end
)
' "$repos_json" >"$tmp_json" && mv "$tmp_json" "$repos_json"
fi
fi

# Run first update
echo "Running first stats update..."
cmd_update

echo ""
echo "Profile README initialized at: https://github.com/${gh_user}"
echo ""
echo "IMPORTANT: To show this on your GitHub profile, visit:"
echo " https://github.com/${repo_slug}"
echo "and click the 'Show on profile' button if prompted."
echo ""
echo "Stats will auto-update daily at 06:00 (configured by setup.sh)."

return 0
}

# --- Update the profile README ---
cmd_update() {
local dry_run=false
Expand Down Expand Up @@ -698,7 +845,7 @@
}
/<!-- UPDATED-END -->/ {
skip = 0
printf "_Stats auto-updated %s by [aidevops](https://github.com/marcusquinn/aidevops) pulse._\n", ts
printf "_Stats auto-updated %s by [aidevops](https://aidevops.sh) pulse._\n", ts
print "<!-- UPDATED-END -->"
next
}
Expand Down Expand Up @@ -747,15 +894,17 @@

# --- Main dispatch ---
case "${1:-help}" in
init) cmd_init ;;
generate) cmd_generate ;;
update)
shift
cmd_update "$@"
;;
help | *)
echo "Usage: profile-readme-helper.sh {update [--dry-run]|generate|help}"
echo "Usage: profile-readme-helper.sh {init|update [--dry-run]|generate|help}"
echo ""
echo "Commands:"
echo " init Create profile repo, seed README, register in repos.json"
echo " update [--dry-run] Update profile README with live stats and push"
echo " generate Print generated stats section to stdout"
echo " help Show this help"
Expand Down
31 changes: 27 additions & 4 deletions setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1268,18 +1268,41 @@ ST_PLIST
fi
fi

# Profile README auto-update — updates GitHub profile README with contributor stats.
# Only installed if user has a profile repo (priority: "profile") in repos.json.
# macOS: launchd plist (daily at 06:00) | Linux: cron (daily at 06:00)
# Profile README auto-create repo and seed README if not already set up.
# Requires gh CLI authenticated. Creates username/username repo, seeds README
# with stat markers, registers in repos.json with priority: "profile".
local pr_script="$HOME/.aidevops/agents/scripts/profile-readme-helper.sh"
local pr_label="sh.aidevops.profile-readme-update"
local repos_json="$HOME/.config/aidevops/repos.json"
local has_profile_repo="false"
if [[ -f "$repos_json" ]] && command -v jq &>/dev/null; then
if [[ -x "$pr_script" ]] && command -v gh &>/dev/null && gh auth status &>/dev/null; then
# Initialize profile repo if not already set up
if [[ -f "$repos_json" ]] && command -v jq &>/dev/null; then
if jq -e '.initialized_repos[]? | select(.priority == "profile")' "$repos_json" >/dev/null 2>&1; then
has_profile_repo="true"
fi
fi
if [[ "$has_profile_repo" == "false" ]]; then
print_info "Setting up GitHub profile README..."
if bash "$pr_script" init; then
has_profile_repo="true"
print_info "Profile README created. Visit your profile repo and click 'Show on profile'."
else
print_warning "Profile README setup failed (non-fatal, skipping)"
fi
else
has_profile_repo="true"
fi
elif [[ -f "$repos_json" ]] && command -v jq &>/dev/null; then
# No gh CLI but check if profile repo already registered
if jq -e '.initialized_repos[]? | select(.priority == "profile")' "$repos_json" >/dev/null 2>&1; then
has_profile_repo="true"
fi
fi

# Profile README auto-update scheduled job.
# Only installed if user has a profile repo (priority: "profile") in repos.json.
# macOS: launchd plist (daily at 06:00) | Linux: cron (daily at 06:00)
if [[ -x "$pr_script" ]] && [[ "$has_profile_repo" == "true" ]]; then
mkdir -p "$HOME/.aidevops/.agent-workspace/logs"

Expand Down