From 8c5f34e85a4996cccc2084d525c0a8d0ccc57431 Mon Sep 17 00:00:00 2001 From: marcusquinn <6428977+marcusquinn@users.noreply.github.com> Date: Mon, 9 Mar 2026 03:46:27 +0000 Subject: [PATCH 1/2] feat: auto-create profile README for new users on setup - Add 'init' command to profile-readme-helper.sh that creates the username/username GitHub repo, seeds a starter README with stat markers, and registers it in repos.json with priority: 'profile' - Wire init into setup.sh so it runs automatically during install/update when no profile repo exists and gh CLI is authenticated - Add footnote explaining why model savings are modest (cache reads dominate token volume, cache prices are similar across models) - Fix hardcoded marcusquinn/aidevops link in UPDATED timestamp to use generic aidevops.sh URL --- .agents/scripts/profile-readme-helper.sh | 157 ++++++++++++++++++++++- setup.sh | 31 ++++- 2 files changed, 180 insertions(+), 8 deletions(-) diff --git a/.agents/scripts/profile-readme-helper.sh b/.agents/scripts/profile-readme-helper.sh index 502c8a800..238e9c19a 100755 --- a/.agents/scripts/profile-readme-helper.sh +++ b/.agents/scripts/profile-readme-helper.sh @@ -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 # @@ -573,7 +574,8 @@ EOF | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ${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) @@ -616,6 +618,151 @@ EOF 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) || { + 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) + if [[ -n "$existing_profile" && "$existing_profile" != "null" ]]; then + if [[ -d "$existing_profile" ]]; then + 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 "$gh_user" --public --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 || + 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 '' "$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") + + cat >"$readme_path" < Shipping with AI agents around the clock -- human hours for thinking, machine hours for doing. +> Stats auto-updated by [aidevops](https://aidevops.sh). + + + + + + + +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 + git -C "$repo_dir" push origin main 2>/dev/null || git -C "$repo_dir" push origin master 2>/dev/null || { + 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) + + 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 @@ -698,7 +845,7 @@ cmd_update() { } // { 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 "" next } @@ -747,15 +894,17 @@ cmd_update() { # --- 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" diff --git a/setup.sh b/setup.sh index d06c90613..ae8de9dd2 100755 --- a/setup.sh +++ b/setup.sh @@ -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 2>&1; 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" From bc99c1b04832a0960b44141ad2f1dccffa9017cc Mon Sep 17 00:00:00 2001 From: marcusquinn <6428977+marcusquinn@users.noreply.github.com> Date: Mon, 9 Mar 2026 03:54:53 +0000 Subject: [PATCH 2/2] fix: use repo_slug in gh repo create, add --add-readme, fix redundant redirect Addresses CodeRabbit review: use consistent repo_slug variable in gh repo create to match gh repo view check, add --add-readme flag to initialize README.md on creation, remove redundant 2>&1 after &>. --- .agents/scripts/profile-readme-helper.sh | 2 +- setup.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.agents/scripts/profile-readme-helper.sh b/.agents/scripts/profile-readme-helper.sh index 238e9c19a..651a2438c 100755 --- a/.agents/scripts/profile-readme-helper.sh +++ b/.agents/scripts/profile-readme-helper.sh @@ -660,7 +660,7 @@ cmd_init() { # 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 "$gh_user" --public --description "GitHub profile README" || { + gh repo create "$repo_slug" --public --add-readme --description "GitHub profile README" || { echo "Error: failed to create repo $repo_slug" >&2 return 1 } diff --git a/setup.sh b/setup.sh index ae8de9dd2..3088252c7 100755 --- a/setup.sh +++ b/setup.sh @@ -1275,7 +1275,7 @@ ST_PLIST local pr_label="sh.aidevops.profile-readme-update" local repos_json="$HOME/.config/aidevops/repos.json" local has_profile_repo="false" - if [[ -x "$pr_script" ]] && command -v gh &>/dev/null && gh auth status &>/dev/null 2>&1; 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