Skip to content

feat: unify update/upgrade CLI, add repo tracking, npm/homebrew packaging#73

Merged
marcusquinn merged 6 commits intomainfrom
feature/cli-update-upgrade-unify
Jan 13, 2026
Merged

feat: unify update/upgrade CLI, add repo tracking, npm/homebrew packaging#73
marcusquinn merged 6 commits intomainfrom
feature/cli-update-upgrade-unify

Conversation

@marcusquinn
Copy link
Owner

@marcusquinn marcusquinn commented Jan 13, 2026

Summary

  • Unify update/upgrade commands (both do the same thing)
  • Add repos.json tracking for initialized projects
  • Auto-detect cloned repos with .aidevops.json
  • Add npm and Homebrew distribution

New CLI Commands

Command Purpose
aidevops repos List registered projects
aidevops repos add Register current project
aidevops repos remove Remove from registry
aidevops repos clean Remove stale entries
aidevops detect Find unregistered projects

Installation Methods

# npm (new)
npm install -g aidevops

# Homebrew (new)
brew install marcusquinn/tap/aidevops

# curl (existing)
bash <(curl -fsSL https://aidevops.sh)

Changes

  • aidevops.sh - Added repo tracking functions, repos/detect commands
  • package.json - Added bin entry for npm global install
  • bin/aidevops - Wrapper script for npm
  • scripts/npm-postinstall.js - Runs setup after npm install
  • homebrew/aidevops.rb - Homebrew formula
  • .github/workflows/publish-packages.yml - Auto-publish on release
  • .agent/AGENTS.md - Updated documentation
  • .agent/scripts/version-manager.sh - Updated release notes

Next Steps After Merge

  1. Publish to npm to claim aidevops name
  2. Create marcusquinn/homebrew-tap repo with Formula/ directory
  3. Add HOMEBREW_TAP_TOKEN secret for tap updates

Summary by CodeRabbit

  • New Features

    • Multiple install paths (npm, Homebrew, curl) and packaged CLI entrypoint.
    • Persistent repository registry, repo management (list/add/remove/clean), auto-upgrade checks, and a detect command for unregistered projects.
    • Homebrew support and install postinstall handling for npm installs.
  • Documentation

    • Expanded Getting Started, richer CLI command reference, project-tracking, auto-detection guidance, and Progressive Disclosure strategy.
  • Chores

    • CI workflow to publish packages and update Homebrew formula; package metadata updates.

✏️ Tip: You can customize this high-level summary in your review settings.

…ging

- Unify update/upgrade commands (both do the same thing)
- Add repos.json tracking for initialized projects (~/.config/aidevops/repos.json)
- Auto-detect cloned repos with .aidevops.json and offer to register
- Add 'aidevops repos' command to list/add/remove/clean registered projects
- Add 'aidevops detect' command to scan for unregistered projects
- Update aidevops update to check registered projects for version updates
- Create bin/aidevops wrapper for npm global install
- Create package.json with bin entry and postinstall script
- Create homebrew/aidevops.rb formula for Homebrew tap
- Add .github/workflows/publish-packages.yml for npm/homebrew releases
- Update version-manager.sh release notes for new install methods
- Update AGENTS.md documentation with new CLI commands
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 13, 2026

Walkthrough

This PR adds multi-channel distribution (npm/Homebrew), a bin wrapper and npm postinstall, automated publish workflow, a persistent repos registry with detect/register/upgrade commands, Homebrew formula, docs updates, and minor agent script compatibility and release-note formatting changes.

Changes

Cohort / File(s) Summary
Distribution & Packaging
package.json, bin/aidevops, scripts/npm-postinstall.js
Add bin entry and wrapper, postinstall hook that runs setup.sh non-interactively, update package metadata (homepage, author, engines, files, keywords, os).
Release Automation
.github/workflows/publish-packages.yml, homebrew/aidevops.rb
New GitHub Actions workflow to publish npm and update Homebrew formula (compute tarball SHA256, push tap); add Homebrew formula with install/post_install/caveats/test.
Repository Registry & CLI
aidevops.sh
Add persistent repos.json (CONFIG_DIR/REPOS_FILE), functions init_repos_file, register_repo, get_registered_repos, check_repo_needs_upgrade, detect_unregistered_repo; add repos and detect commands and integrate upgrade/registration flows.
Documentation & Release Notes
.agent/AGENTS.md, .agent/scripts/version-manager.sh
Rewrite agent installation/onboarding docs (multi-path install, project tracking, auto-detect, progressive disclosure) and reformat release-note generation output.
Agent Scripts / State
.agent/scripts/full-loop-helper.sh
Add LEGACY_STATE_FILE constant for backward-compatible legacy loop-state path.
Packaging Metadata / CI config
.codacy.yml, package.json (also listed above)
Enable semgrep engine; exclude scripts/** for linters; update package.json fields and files manifest.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI as aidevops CLI
    participant FS as Filesystem
    participant RepoDB as repos.json

    User->>CLI: run command (init/status/other)
    CLI->>FS: detect .aidevops.json in cwd
    alt .aidevops.json present and not registered
        CLI->>User: prompt to register project
        User->>CLI: confirm registration
        CLI->>RepoDB: register_repo(path, version, features)
        RepoDB->>FS: write/update repos.json
    else registered
        CLI->>RepoDB: check_repo_needs_upgrade(path)
        alt upgrade needed
            CLI->>User: suggest upgrade/propagate version
        end
    end
Loading
sequenceDiagram
    participant Dev
    participant GHA as GitHub Actions
    participant npm as npm Registry
    participant GHRel as GitHub Release
    participant BrewTap as Homebrew Tap Repo

    Dev->>GHA: trigger publish-packages workflow
    GHA->>GHA: resolve version (input or VERSION)
    GHA->>npm: npm publish (with token)
    GHA->>GHRel: fetch release tarball
    GHRel->>GHA: provide tarball
    GHA->>GHA: compute sha256
    GHA->>BrewTap: update formula (version, sha256) and push
    GHA->>GHA: emit summary with install instructions
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🛠️ A CLI, a tap, a registry spun,
wrappers that call and workflows that run,
Repos now tracked, versions aligned,
Releases auto-published, docs refined —
🎉 Cheers to automation, one deploy at a time.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main objectives: unifying update/upgrade CLI, adding repository tracking, and implementing npm/Homebrew packaging—all core changes present throughout the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 82.35% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

🧹 Recent nitpick comments
aidevops.sh (3)

149-153: Semver comparison limitation - consider documenting edge case.

The simple string comparison [[ "$repo_version" != "$current_version" ]] works for exact version matching but may behave unexpectedly for version ordering (e.g., "2.9.0" sorts after "2.10.0" lexicographically). Since this only triggers upgrade prompts (not automatic changes), the impact is low.

💡 Optional: Use sort -V for proper version comparison
-    # Compare versions (simple string comparison works for semver)
-    if [[ "$repo_version" != "$current_version" ]]; then
-        return 0  # needs upgrade
-    fi
-    return 1  # up to date
+    # Compare versions - check if repo version is older than current
+    if [[ "$repo_version" == "$current_version" ]]; then
+        return 1  # up to date
+    fi
+    # Use sort -V for proper semver ordering
+    local older
+    older=$(printf '%s\n%s' "$repo_version" "$current_version" | sort -V | head -n1)
+    if [[ "$older" == "$repo_version" ]]; then
+        return 0  # repo version is older, needs upgrade
+    fi
+    return 1  # repo version is newer or equal

526-579: Repo upgrade checking is well-implemented.

The logic for scanning registered repos and offering updates is solid. The use of jq with --arg for variable interpolation is safe. One minor note: as per coding guidelines, consider adding an explicit return 0 at the end of cmd_update() (currently relies on implicit return).

💡 Optional: Add explicit return
             fi
         fi
     fi
+    return 0
 }

1397-1549: Comprehensive repos management command.

The cmd_repos function handles list, add, remove, and clean operations correctly. The use of $((removed + 1)) for safe arithmetic is good. Per coding guidelines, consider adding explicit returns at the end of each case branch for consistency.

💡 Optional: Add explicit returns to case branches
             echo "Legend: ✓ up-to-date  ↑ update available  ✗ not found"
+            return 0
             ;;
         
         add)
             # ... existing code ...
             print_success "Registered $(basename "$project_root")"
+            return 0
             ;;
         
         remove|rm)
             # ... existing code ...
             print_success "Removed $repo_path from registry"
+            return 0
             ;;
         
         clean)
             # ... existing code ...
             else
                 print_success "Removed $removed stale entries"
             fi
+            return 0
             ;;
📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0a59352 and c62eae0.

📒 Files selected for processing (4)
  • .agent/AGENTS.md
  • .codacy.yml
  • aidevops.sh
  • package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json
🧰 Additional context used
📓 Path-based instructions (1)
**/*.sh

📄 CodeRabbit inference engine (AGENTS.md)

**/*.sh: Use local var="$1" pattern for shell variable assignments
Use explicit returns in shell scripts
Run ShellCheck on all scripts with zero violations required

Files:

  • aidevops.sh
🧠 Learnings (16)
📚 Learning: 2025-11-29T04:34:27.158Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-29T04:34:27.158Z
Learning: All instructions, documentation, and operational guidance should be maintained in AGENTS.md as the single source of truth

Applied to files:

  • .agent/AGENTS.md
📚 Learning: 2025-11-29T04:34:42.033Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: AGENT.md:0-0
Timestamp: 2025-11-29T04:34:42.033Z
Learning: Reference AGENTS.md (authoritative) instead of AGENT.md for AI assistant guidance

Applied to files:

  • .agent/AGENTS.md
📚 Learning: 2025-11-29T04:34:30.742Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-11-29T04:34:30.742Z
Learning: Maintain all instructions, documentation, and operational guidance in AGENTS.md as the single source of truth

Applied to files:

  • .agent/AGENTS.md
📚 Learning: 2026-01-06T15:57:56.027Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-06T15:57:56.027Z
Learning: Applies to **/AGENTS.md : Limit root AGENTS.md to ~50-100 max instructions with universal applicability to >80% of tasks

Applied to files:

  • .agent/AGENTS.md
📚 Learning: 2026-01-06T15:57:56.027Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-06T15:57:56.027Z
Learning: Applies to **/AGENTS.md : Use progressive disclosure in AGENTS.md with pointers to subagents rather than inline content

Applied to files:

  • .agent/AGENTS.md
📚 Learning: 2025-11-29T04:34:42.033Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: AGENT.md:0-0
Timestamp: 2025-11-29T04:34:42.033Z
Learning: Maintain all AI assistant instructions, documentation, and operational guidance in AGENTS.md as the single source of truth

Applied to files:

  • .agent/AGENTS.md
📚 Learning: 2025-11-29T04:34:30.742Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-11-29T04:34:30.742Z
Learning: Reference AGENTS.md for authoritative AI assistant guidance instead of GEMINI.md

Applied to files:

  • .agent/AGENTS.md
📚 Learning: 2025-12-22T01:24:53.937Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/AGENTS.md:0-0
Timestamp: 2025-12-22T01:24:53.937Z
Learning: Follow all security protocols and working directory specifications defined in ~/Git/aidevops/AGENTS.md

Applied to files:

  • .agent/AGENTS.md
  • aidevops.sh
📚 Learning: 2025-12-22T01:24:53.937Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/AGENTS.md:0-0
Timestamp: 2025-12-22T01:24:53.937Z
Learning: Reference the authoritative repository at ~/Git/aidevops/ for all detailed AI assistant instructions and configurations

Applied to files:

  • .agent/AGENTS.md
  • aidevops.sh
📚 Learning: 2026-01-06T15:57:56.027Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-06T15:57:56.027Z
Learning: Applies to **/setup.sh : Deploy agents locally using ./setup.sh script

Applied to files:

  • .agent/AGENTS.md
  • aidevops.sh
📚 Learning: 2025-12-22T01:24:53.937Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/AGENTS.md:0-0
Timestamp: 2025-12-22T01:24:53.937Z
Learning: Use the helper script at ~/Git/aidevops/.agent/scripts/setup-local-api-keys.sh to manage secure storage of API keys rather than manual configuration

Applied to files:

  • .agent/AGENTS.md
  • aidevops.sh
📚 Learning: 2025-12-22T01:24:53.937Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/AGENTS.md:0-0
Timestamp: 2025-12-22T01:24:53.937Z
Learning: Use only the specified working directories: ~/.aidevops/.agent-workspace/work/[project]/ for work files, ~/.aidevops/.agent-workspace/tmp/ for temporary files, and ~/.aidevops/.agent-workspace/memory/ for persistent memory

Applied to files:

  • .agent/AGENTS.md
  • aidevops.sh
📚 Learning: 2025-12-22T01:24:53.937Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/AGENTS.md:0-0
Timestamp: 2025-12-22T01:24:53.937Z
Learning: Never store credentials in working directories (~/.aidevops/.agent-workspace/), Git repositories, home directory root, or hardcoded in code and scripts

Applied to files:

  • aidevops.sh
📚 Learning: 2025-12-22T01:25:03.138Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/git/AGENTS.md:0-0
Timestamp: 2025-12-22T01:25:03.138Z
Learning: Store Service Configurations in ~/Git/aidevops/configs/[service]-config.json with file permissions set to 600

Applied to files:

  • aidevops.sh
📚 Learning: 2025-12-22T01:25:03.138Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/git/AGENTS.md:0-0
Timestamp: 2025-12-22T01:25:03.138Z
Learning: Use standardized patterns as defined in the authoritative DevOps repository at ~/Git/aidevops/

Applied to files:

  • aidevops.sh
📚 Learning: 2025-12-22T01:25:03.138Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/git/AGENTS.md:0-0
Timestamp: 2025-12-22T01:25:03.138Z
Learning: NEVER store credentials or API keys in ~/.aidevops/.agent-workspace/ directories - working files are not secure

Applied to files:

  • aidevops.sh
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (11)
.codacy.yml (2)

13-18: LGTM! Semgrep exclusion is well-documented.

The exclusion for scripts/** is appropriate given the npm postinstall context. The inline comment explains the rationale clearly, which is good practice for configuration-as-code.


37-37: ESLint exclusion aligns with CommonJS requirements.

Excluding scripts/** from ESLint is consistent with the semgrep exclusion and the documented need for Node.js/CommonJS compatibility in the npm postinstall script.

.agent/AGENTS.md (2)

410-423: Installation documentation is clear and comprehensive.

The three installation methods (npm, Homebrew, curl) are well-presented with appropriate code blocks. The outcome message accurately describes what gets deployed.


443-454: CLI commands table and tracking sections are accurate.

The new commands (repos, detect, update-tools) align with the implementation in aidevops.sh. The project tracking and auto-detection explanations provide good context for users. Based on learnings, this maintains AGENTS.md as the single source of truth for AI assistant guidance.

aidevops.sh (7)

73-80: LGTM! Clean initialization function.

The init_repos_file() function properly uses mkdir -p for idempotent directory creation and includes an explicit return 0 as per coding guidelines.


82-117: Solid repo registration with safe jq interpolation.

The function correctly uses local var="$1" pattern for parameters and --arg for safe jq variable interpolation, preventing shell injection. The temp file pattern with atomic mv ensures data integrity.


119-130: LGTM! Simple and defensive.

The function handles the jq-unavailable case gracefully and includes explicit returns.


156-186: LGTM! Well-structured detection logic.

The function has clear guard clauses with explicit returns at each exit point. The git and jq checks provide appropriate fallbacks.


1551-1632: LGTM! Robust detection with safe path handling.

The cmd_detect function properly uses find -print0 with read -d '' for safe handling of paths containing spaces. Safe arithmetic and explicit return are present. This maintains the zero technical debt standard.


1694-1703: Nice UX touch with auto-detect tip.

The silent check for unregistered repos on command entry provides helpful guidance without being intrusive. The exclusion of detect and repos commands prevents redundant messaging.


1000-1011: LGTM! Clean feature list building and registration.

The features string building with trailing comma removal is straightforward and correct. The integration with register_repo completes the init workflow properly.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link

Summary of Changes

Hello @marcusquinn, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the aidevops CLI by improving its distribution, command structure, and project management capabilities. The core purpose is to make the tool easier to install and maintain across various development environments, while also providing better oversight and update mechanisms for projects utilizing the framework. These changes aim to reduce manual intervention for users and ensure consistency across their aidevops-enabled repositories.

Highlights

  • Unified CLI Commands: The update and upgrade commands have been unified to perform the same function, streamlining the CLI experience.
  • Project Repository Tracking: Introduced a new system to track initialized projects using a repos.json file, allowing the CLI to manage and update multiple projects more effectively.
  • New CLI Commands for Repo Management: Added several new commands under aidevops repos (list, add, remove, clean) and aidevops detect to manage and discover aidevops-enabled projects.
  • Expanded Distribution Channels: The aidevops CLI can now be installed globally via npm and Homebrew, in addition to the existing curl-based installation method.
  • Automated Project Updates: The aidevops update command now checks all registered projects and offers to update their .aidevops.json configuration to the latest framework version.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/publish-packages.yml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions
Copy link

🔍 Code Quality Report

�[0;35m[MONITOR]�[0m Code Review Monitoring Report

�[0;34m[INFO]�[0m Latest Quality Status:
SonarCloud: 0 bugs, 0 vulnerabilities, 256 code smells

�[0;34m[INFO]�[0m Recent monitoring activity:
Tue Jan 13 22:37:34 UTC 2026: Code review monitoring started
Tue Jan 13 22:37:34 UTC 2026: SonarCloud - Bugs: 0, Vulnerabilities: 0, Code Smells: 256
Tue Jan 13 22:37:34 UTC 2026: Qlty - 0 issues found, auto-formatting applied
Tue Jan 13 22:37:36 UTC 2026: Codacy analysis completed with auto-fixes

📈 Current Quality Metrics

  • BUGS: 0
  • CODE SMELLS: 256
  • VULNERABILITIES: 0

Generated on: Tue Jan 13 22:38:14 UTC 2026


Generated by AI DevOps Framework Code Review Monitoring

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces significant new features, including repository tracking, auto-detection of projects, and packaging for npm and Homebrew. The changes are extensive and well-structured. I've identified a critical issue in the Homebrew formula that would prevent it from working, along with some high-severity issues related to efficiency and error handling in the main shell script. I've also found a minor issue in the new npm post-install script. My review provides suggestions to address these points to improve the robustness and correctness of the new features.

Comment on lines +18 to +19
# Install the CLI script
bin.install "aidevops.sh" => "aidevops"

Choose a reason for hiding this comment

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

critical

The install method in the Homebrew formula has a bug. It installs aidevops.sh to bin/aidevops, but then the wrapper script created later tries to execute aidevops.sh from libexec, where it was never installed. This will cause the aidevops command to fail after installation.

The aidevops.sh script should be installed to libexec instead of bin. The initial bin.install is incorrect and should be changed.

    # Install the CLI script to libexec
    libexec.install "aidevops.sh"

aidevops.sh Outdated
init_repos_file

# Normalize path (resolve symlinks, remove trailing slash)
repo_path=$(cd "$repo_path" 2>/dev/null && pwd -P)

Choose a reason for hiding this comment

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

high

The path normalization repo_path=$(cd "$repo_path" 2>/dev/null && pwd -P) can result in an empty repo_path if the original path is invalid or doesn't exist. This empty path is then used in subsequent jq commands, which could lead to unexpected behavior like modifying an entry with an empty path or creating a new one. The function should handle this error case explicitly by checking if the path normalization was successful and returning an error if it failed.

Suggested change
repo_path=$(cd "$repo_path" 2>/dev/null && pwd -P)
local normalized_path
normalized_path=$(cd "$repo_path" 2>/dev/null && pwd -P)
if [[ -z "$normalized_path" ]]; then
print_error "Invalid repository path provided: $1"
return 1
fi
repo_path="$normalized_path"

Comment on lines 1511 to 1531
local removed=0
local temp_file="${REPOS_FILE}.tmp"

# Filter out repos that don't exist
jq '[.initialized_repos[] | select(.path as $p | ($p | type == "string") and ([$p] | .[0] | test("^/")))]' "$REPOS_FILE" > /dev/null 2>&1

while IFS= read -r repo_path; do
[[ -z "$repo_path" ]] && continue
if [[ ! -d "$repo_path" ]]; then
jq --arg path "$repo_path" '.initialized_repos |= map(select(.path != $path))' "$REPOS_FILE" > "$temp_file" && \
mv "$temp_file" "$REPOS_FILE"
print_info "Removed: $repo_path"
((removed++))
fi
done < <(get_registered_repos)

if [[ $removed -eq 0 ]]; then
print_success "No stale entries found"
else
print_success "Removed $removed stale entries"
fi

Choose a reason for hiding this comment

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

high

The current implementation of cmd_repos clean iterates through registered repos and calls jq to remove each stale entry one by one. This is inefficient as it reads and writes the entire repos.json file inside the loop for every non-existent repository. This can be slow if there are many stale entries and is not an atomic operation.

A better approach is to read the file once, determine which repositories to keep, and then write the new list back to the file in a single operation. This is more efficient and safer.

            local removed=0
            local temp_file="${REPOS_FILE}.tmp"

            # Create a temporary file with only the repos that still exist
            jq -c '.initialized_repos[]' "$REPOS_FILE" 2>/dev/null | while IFS= read -r repo_json; do
                local repo_path
                repo_path=$(echo "$repo_json" | jq -r '.path')
                if [[ -d "$repo_path" ]]; then
                    echo "$repo_json"
                else
                    print_info "Removed: $repo_path"
                    ((removed++))
                fi
            done | jq -s '{"initialized_repos": .}' > "$temp_file"

            # Replace the original file
            mv "$temp_file" "$REPOS_FILE"

            if [[ $removed -eq 0 ]]; then
                print_success "No stale entries found"
            else
                print_success "Removed $removed stale entries"
            fi

* Runs setup.sh to deploy agents after npm install -g
*/

const { execSync, spawn } = require('child_process');

Choose a reason for hiding this comment

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

medium

The spawn function is imported from child_process but it is not used anywhere in the script. This is considered dead code and should be removed to improve maintainability.

Suggested change
const { execSync, spawn } = require('child_process');
const { execSync } = require('child_process');

@augmentcode
Copy link

augmentcode bot commented Jan 13, 2026

🤖 Augment PR Summary

Summary: This PR enhances the aidevops CLI distribution and project management features.

Changes:

  • Unifies update/upgrade behavior and expands update to also check initialized projects.
  • Adds per-user project registry at ~/.config/aidevops/repos.json, populated during aidevops init.
  • Introduces new CLI commands: repos (list/add/remove/clean) and detect (scan for unregistered projects).
  • Adds auto-tip to suggest registering repos that contain .aidevops.json but aren’t tracked yet.
  • Adds npm packaging (bin wrapper + postinstall setup) to support npm install -g aidevops.
  • Adds a Homebrew formula and a release workflow to publish to npm and update a tap repo on release.
  • Updates agent docs and release notes templates to reflect new installation methods and commands.

Technical Notes: The CLI now depends more heavily on jq for repo tracking/management and uses a release workflow to keep the Homebrew formula version/SHA in sync.

🤖 Was this summary useful? React with 👍 or 👎

Copy link

@augmentcode augmentcode bot left a comment

Choose a reason for hiding this comment

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

Review completed. 2 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.


const { execSync, spawn } = require('child_process');
const path = require('path');
const fs = require('fs');
Copy link

Choose a reason for hiding this comment

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

Because package.json sets "type": "module", Node will treat this .js file as ESM and require() will throw during npm install -g postinstall. Consider renaming to .cjs or rewriting with ESM import so global installs don’t break.

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎

(bin/"aidevops").write <<~EOS
#!/usr/bin/env bash
export AIDEVOPS_SHARE="#{share}/aidevops"
exec "#{libexec}/aidevops.sh" "$@"
Copy link

Choose a reason for hiding this comment

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

This wrapper exec "#{libexec}/aidevops.sh" points to a file that isn’t installed into libexec (and bin.install "aidevops.sh" => "aidevops" is then overwritten by (bin/"aidevops").write). As written, the brewed aidevops command will likely fail at runtime.

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🤖 Fix all issues with AI agents
In @.github/workflows/publish-packages.yml:
- Around line 30-37: The "Get version" step (id: version) directly interpolates
github.event.inputs.version into a run script which can enable script injection;
instead pass the workflow_dispatch input through an environment variable and
reference that env var inside the run block. Update the step to set an env entry
(e.g. VERSION: ${{ github.event.inputs.version }}) and then in the run script
check that env var (falling back to reading the VERSION file) and write to
GITHUB_OUTPUT; keep the existing output key name ("version") and preserve the
same logic but replace all occurrences of `${{ github.event.inputs.version }}`
with the shell-safe environment variable (e.g. $VERSION).
- Around line 79-83: The tarball download may return a 404 and produce an
invalid SHA; make the curl call that populates SHA256 fail on HTTP errors and
abort the step if the download fails. Change the download invocation that
references TARBALL_URL to use curl with the fail-on-error flag (e.g., -f) and
ensure you check the curl exit status before computing/exporting SHA256 (only
write to GITHUB_OUTPUT if curl succeeded), so that a failed download causes the
job to fail instead of writing an invalid SHA.
- Around line 70-83: The step that reads github.event.inputs.version uses direct
workflow interpolation; change it to accept the input via an environment
variable (e.g., INPUT_VERSION) and reference that shell variable inside the
release step and the Homebrew job to avoid injection issues: set env:
INPUT_VERSION: ${{ github.event.inputs.version }} for the step (or job), then in
the script use if [ -n "$INPUT_VERSION" ]; then VERSION="$INPUT_VERSION"; else
VERSION=$(cat VERSION); fi and build TARBALL_URL using "$VERSION" and write
outputs to $GITHUB_OUTPUT as before; apply this same pattern to the Homebrew
job's Get version and SHA step so both use INPUT_VERSION (or similarly named env
var) instead of direct ${{ github.event.inputs.version }} interpolation.
- Around line 91-102: The workflow uses the third-party action reference
dmnemec/copy_file_to_another_repo_action@main which is unpinned; replace the
@main ref with the action's specific commit SHA (e.g.,
dmnemec/copy_file_to_another_repo_action@<commit-sha>) to pin the dependency,
updating the with block only to change the ref and committing that exact SHA so
the Push to homebrew-tap step always uses the immutable, audited version of the
action.

In @aidevops.sh:
- Around line 1474-1500: The remove|rm handler's path normalization fallback
erroneously assigns repo_path from the positional $2; remove the "||
repo_path=\"$2\"" fallback and let repo_path remain as-is if cd/pwd fails (i.e.,
keep the existing repo_path local variable), so the jq removal will use the
originally supplied path variable (repo_path) rather than the wrong positional
parameter.

In @package.json:
- Around line 55-66: Remove the ".agent/" entry from the package.json "files"
array (the files manifest) so the published npm package no longer includes the
4MB developer-only directory; if any specific artifacts from .agent are actually
required at runtime, add only those specific file paths to the "files" array
instead of the whole directory, and ensure "scripts/npm-postinstall.js", "bin/",
"aidevops.sh", "setup.sh", and "VERSION" remain listed.

In @scripts/npm-postinstall.js:
- Around line 55-59: The catch block in scripts/npm-postinstall.js prints an
incorrect manual path (~/.aidevops/setup.sh); update the error output in that
catch to point to the actual package-installed setup script (resolve the package
directory at runtime, e.g. using __dirname or a computed packageDir and
reference packageDir + '/setup.sh') or, as an alternative/fallback, include the
curl installer command suggestion in the message so users have a reliable manual
option; keep the non-failing exit behavior (process.exit(0)) but ensure the log
clearly shows the real install path or the curl fallback.
🧹 Nitpick comments (6)
scripts/npm-postinstall.js (1)

7-7: Remove unused spawn import.

The spawn function is imported but never used in this script. Only execSync is utilized.

🧹 Proposed fix
-const { execSync, spawn } = require('child_process');
+const { execSync } = require('child_process');
homebrew/aidevops.rb (1)

36-39: Add non-interactive mode to post_install for consistency.

The npm postinstall script uses AIDEVOPS_NONINTERACTIVE=1 to prevent interactive prompts during automated installation. The Homebrew post_install should follow the same pattern to ensure reliable automated installation.

♻️ Proposed fix
   def post_install
     # Run setup to deploy agents
-    system "bash", "#{libexec}/setup.sh"
+    ENV["AIDEVOPS_NONINTERACTIVE"] = "1"
+    system "bash", "#{libexec}/setup.sh"
   end
aidevops.sh (4)

83-112: Add explicit return and handle path normalization failure.

Per coding guidelines, shell functions should use explicit returns. Also, the path normalization on line 91 could silently fail if the directory doesn't exist.

♻️ Suggested improvements
 register_repo() {
     local repo_path="$1"
     local version="$2"
     local features="$3"
     
     init_repos_file
     
     # Normalize path (resolve symlinks, remove trailing slash)
-    repo_path=$(cd "$repo_path" 2>/dev/null && pwd -P)
+    repo_path=$(cd "$repo_path" 2>/dev/null && pwd -P) || {
+        print_warning "Cannot access path: $repo_path"
+        return 1
+    }
     
     if ! command -v jq &>/dev/null; then
         print_warning "jq not installed - repo tracking disabled"
         return 0
     fi

And add explicit return at end:

         jq --arg path "$repo_path" --arg version "$version" --arg features "$features" \
             '.initialized_repos += [{path: $path, version: $version, features: ($features | split(",")), initialized: (now | strftime("%Y-%m-%dT%H:%M:%SZ"))}]' \
             "$REPOS_FILE" > "$temp_file" && mv "$temp_file" "$REPOS_FILE"
     fi
+    return 0
 }

114-124: Add explicit return for consistency.

The function handles the jq dependency gracefully but lacks an explicit return statement at the end.

♻️ Minor fix
     jq -r '.initialized_repos[] | .path' "$REPOS_FILE" 2>/dev/null || echo ""
+    return 0
 }

126-148: Clarify version comparison semantics.

The comment on line 143 states "simple string comparison works for semver" but string comparison doesn't handle semver correctly (e.g., "2.9.0" > "2.10.0" lexicographically). However, since the function checks for any version difference rather than "older", this is functionally acceptable for triggering update prompts.

Consider updating the comment to be more accurate:

♻️ Clarify comment
-    # Compare versions (simple string comparison works for semver)
+    # Compare versions (checks for any difference, not semantic ordering)
     if [[ "$repo_version" != "$current_version" ]]; then

1514-1516: Remove unused jq validation line.

Line 1515 executes a complex jq command but redirects output to /dev/null, making it effectively dead code. This appears to be a leftover from debugging or an incomplete validation check.

♻️ Remove dead code
             local removed=0
             local temp_file="${REPOS_FILE}.tmp"
             
-            # Filter out repos that don't exist
-            jq '[.initialized_repos[] | select(.path as $p | ($p | type == "string") and ([$p] | .[0] | test("^/")))]' "$REPOS_FILE" > /dev/null 2>&1
-            
             while IFS= read -r repo_path; do
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3dce529 and 4034bf6.

📒 Files selected for processing (9)
  • .agent/AGENTS.md
  • .agent/scripts/full-loop-helper.sh
  • .agent/scripts/version-manager.sh
  • .github/workflows/publish-packages.yml
  • aidevops.sh
  • bin/aidevops
  • homebrew/aidevops.rb
  • package.json
  • scripts/npm-postinstall.js
🧰 Additional context used
📓 Path-based instructions (3)
.agent/scripts/*.sh

⚙️ CodeRabbit configuration file

.agent/scripts/*.sh: Automation scripts - focus on:

  • Reliability and robustness
  • Clear logging and feedback
  • Proper exit codes
  • Error recovery mechanisms

Files:

  • .agent/scripts/full-loop-helper.sh
  • .agent/scripts/version-manager.sh
**/*.sh

📄 CodeRabbit inference engine (AGENTS.md)

**/*.sh: Use local var="$1" pattern for shell variable assignments
Use explicit returns in shell scripts
Run ShellCheck on all scripts with zero violations required

Files:

  • aidevops.sh
**/.agent/scripts/version-manager.sh

📄 CodeRabbit inference engine (AGENTS.md)

Use .agent/scripts/version-manager.sh release [major|minor|patch] for releases

Files:

  • .agent/scripts/version-manager.sh
🧠 Learnings (17)
📚 Learning: 2025-12-22T01:24:53.937Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/AGENTS.md:0-0
Timestamp: 2025-12-22T01:24:53.937Z
Learning: Follow all security protocols and working directory specifications defined in ~/Git/aidevops/AGENTS.md

Applied to files:

  • bin/aidevops
  • .agent/AGENTS.md
  • aidevops.sh
  • scripts/npm-postinstall.js
  • homebrew/aidevops.rb
📚 Learning: 2025-12-22T01:24:53.937Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/AGENTS.md:0-0
Timestamp: 2025-12-22T01:24:53.937Z
Learning: Reference the authoritative repository at ~/Git/aidevops/ for all detailed AI assistant instructions and configurations

Applied to files:

  • bin/aidevops
  • .agent/AGENTS.md
  • aidevops.sh
  • homebrew/aidevops.rb
  • package.json
📚 Learning: 2025-12-22T01:25:03.138Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/git/AGENTS.md:0-0
Timestamp: 2025-12-22T01:25:03.138Z
Learning: Use standardized patterns as defined in the authoritative DevOps repository at ~/Git/aidevops/

Applied to files:

  • bin/aidevops
  • aidevops.sh
📚 Learning: 2025-12-22T01:24:53.937Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/AGENTS.md:0-0
Timestamp: 2025-12-22T01:24:53.937Z
Learning: Use the helper script at ~/Git/aidevops/.agent/scripts/setup-local-api-keys.sh to manage secure storage of API keys rather than manual configuration

Applied to files:

  • bin/aidevops
  • .agent/AGENTS.md
  • aidevops.sh
📚 Learning: 2025-11-29T04:34:42.033Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: AGENT.md:0-0
Timestamp: 2025-11-29T04:34:42.033Z
Learning: Reference AGENTS.md (authoritative) instead of AGENT.md for AI assistant guidance

Applied to files:

  • .agent/AGENTS.md
📚 Learning: 2025-11-29T04:34:27.158Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-29T04:34:27.158Z
Learning: All instructions, documentation, and operational guidance should be maintained in AGENTS.md as the single source of truth

Applied to files:

  • .agent/AGENTS.md
📚 Learning: 2025-11-29T04:34:30.742Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-11-29T04:34:30.742Z
Learning: Maintain all instructions, documentation, and operational guidance in AGENTS.md as the single source of truth

Applied to files:

  • .agent/AGENTS.md
📚 Learning: 2025-11-29T04:34:42.033Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: AGENT.md:0-0
Timestamp: 2025-11-29T04:34:42.033Z
Learning: Maintain all AI assistant instructions, documentation, and operational guidance in AGENTS.md as the single source of truth

Applied to files:

  • .agent/AGENTS.md
📚 Learning: 2025-11-29T04:34:30.742Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-11-29T04:34:30.742Z
Learning: Reference AGENTS.md for authoritative AI assistant guidance instead of GEMINI.md

Applied to files:

  • .agent/AGENTS.md
📚 Learning: 2026-01-06T15:57:56.027Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-06T15:57:56.027Z
Learning: Applies to **/AGENTS.md : Limit root AGENTS.md to ~50-100 max instructions with universal applicability to >80% of tasks

Applied to files:

  • .agent/AGENTS.md
📚 Learning: 2026-01-06T15:57:56.027Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-06T15:57:56.027Z
Learning: Applies to **/AGENTS.md : Use progressive disclosure in AGENTS.md with pointers to subagents rather than inline content

Applied to files:

  • .agent/AGENTS.md
📚 Learning: 2026-01-06T15:57:56.027Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-06T15:57:56.027Z
Learning: Applies to **/setup.sh : Deploy agents locally using ./setup.sh script

Applied to files:

  • .agent/AGENTS.md
  • aidevops.sh
  • scripts/npm-postinstall.js
📚 Learning: 2025-12-22T01:24:53.937Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/AGENTS.md:0-0
Timestamp: 2025-12-22T01:24:53.937Z
Learning: Use only the specified working directories: ~/.aidevops/.agent-workspace/work/[project]/ for work files, ~/.aidevops/.agent-workspace/tmp/ for temporary files, and ~/.aidevops/.agent-workspace/memory/ for persistent memory

Applied to files:

  • .agent/AGENTS.md
  • aidevops.sh
📚 Learning: 2025-12-22T01:24:53.937Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/AGENTS.md:0-0
Timestamp: 2025-12-22T01:24:53.937Z
Learning: Never store credentials in working directories (~/.aidevops/.agent-workspace/), Git repositories, home directory root, or hardcoded in code and scripts

Applied to files:

  • aidevops.sh
📚 Learning: 2025-12-22T01:25:03.138Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/git/AGENTS.md:0-0
Timestamp: 2025-12-22T01:25:03.138Z
Learning: Store Service Configurations in ~/Git/aidevops/configs/[service]-config.json with file permissions set to 600

Applied to files:

  • aidevops.sh
📚 Learning: 2025-12-22T01:25:03.138Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/git/AGENTS.md:0-0
Timestamp: 2025-12-22T01:25:03.138Z
Learning: NEVER store credentials or API keys in ~/.aidevops/.agent-workspace/ directories - working files are not secure

Applied to files:

  • aidevops.sh
📚 Learning: 2026-01-06T15:57:56.027Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-06T15:57:56.027Z
Learning: Applies to **/.agent/scripts/version-manager.sh : Use .agent/scripts/version-manager.sh release [major|minor|patch] for releases

Applied to files:

  • .agent/scripts/version-manager.sh
🪛 GitHub Check: Codacy Static Code Analysis
.github/workflows/publish-packages.yml

[failure] 32-32: .github/workflows/publish-packages.yml#L32
Using variable interpolation ${{...}} with github context data in a run: step could allow an attacker to inject their own code into the runner.


[warning] 92-92: .github/workflows/publish-packages.yml#L92
An action sourced from a third-party repository on GitHub is not pinned to a full length commit SHA. Pinning an action to a full length commit SHA is currently the only way to use an action as an immutable release.

scripts/npm-postinstall.js

[warning] 1-1: scripts/npm-postinstall.js#L1
ES2023 Hashbang comments are forbidden.


[warning] 1-1: scripts/npm-postinstall.js#L1
This file needs no shebang.


[warning] 1-1: scripts/npm-postinstall.js#L1
This file needs no shebang.


[notice] 1-1: scripts/npm-postinstall.js#L1
You have a misspelled word: usr on Comment


[warning] 7-7: scripts/npm-postinstall.js#L7
'spawn' is assigned a value but never used.


[warning] 7-7: scripts/npm-postinstall.js#L7
'spawn' is assigned a value but never used.


[warning] 7-7: scripts/npm-postinstall.js#L7
'spawn' is assigned a value but never used.


[warning] 7-7: scripts/npm-postinstall.js#L7
A require() style import is forbidden.


[warning] 7-7: scripts/npm-postinstall.js#L7
ES2015 block-scoped variables are forbidden.


[warning] 7-7: scripts/npm-postinstall.js#L7
ES2015 destructuring is forbidden.


[notice] 7-7: scripts/npm-postinstall.js#L7
Filename npm-postinstall.js does not match the file name pattern ^([a-z][a-z0-9])(-[a-z0-9]+)(.spec|.test)?.ts$


[warning] 7-7: scripts/npm-postinstall.js#L7
Require statement not part of import statement.


[warning] 8-8: scripts/npm-postinstall.js#L8
A require() style import is forbidden.


[warning] 8-8: scripts/npm-postinstall.js#L8
ES2015 block-scoped variables are forbidden.


[warning] 8-8: scripts/npm-postinstall.js#L8
Require statement not part of import statement.


[warning] 9-9: scripts/npm-postinstall.js#L9
A require() style import is forbidden.


[warning] 9-9: scripts/npm-postinstall.js#L9
ES2015 block-scoped variables are forbidden.


[warning] 9-9: scripts/npm-postinstall.js#L9
Require statement not part of import statement.


[notice] 9-9: scripts/npm-postinstall.js#L9
You have a misspelled word: fs on Identifier


[warning] 11-11: scripts/npm-postinstall.js#L11
ES2015 block-scoped variables are forbidden.


[warning] 12-12: scripts/npm-postinstall.js#L12
ES2015 block-scoped variables are forbidden.


[warning] 13-13: scripts/npm-postinstall.js#L13
A require() style import is forbidden.


[warning] 13-13: scripts/npm-postinstall.js#L13
ES2015 block-scoped variables are forbidden.


[warning] 13-13: scripts/npm-postinstall.js#L13
Require statement not part of import statement.


[notice] 13-13: scripts/npm-postinstall.js#L13
You have a misspelled word: os on String


[warning] 16-16: scripts/npm-postinstall.js#L16
ES2015 block-scoped variables are forbidden.


[warning] 16-16: scripts/npm-postinstall.js#L16
npm_config_global is not listed as a dependency in turbo.json


[warning] 17-17: scripts/npm-postinstall.js#L17
Prefer '_.includes' over the native function.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (16)
.agent/scripts/full-loop-helper.sh (1)

49-50: LGTM!

Clean addition that completes the legacy path constants symmetrically. The shellcheck disable annotation is appropriate since this constant serves documentation and future compatibility purposes, mirroring the existing LEGACY_STATE_DIR pattern on lines 47-48.

scripts/npm-postinstall.js (1)

15-24: Global detection relies primarily on npm_config_global (correct).

The process.argv checks on lines 17-18 are ineffective during postinstall execution since npm doesn't forward the -g/--global flags to hook scripts. However, this is harmless since the npm_config_global environment variable on line 16 is the canonical detection method and will work correctly.

The overall skip logic is sound for preventing redundant setup in development environments.

.agent/scripts/version-manager.sh (1)

598-648: LGTM! Release notes template updated for multi-channel distribution.

The updated generate_release_notes() template now accurately reflects the new installation methods introduced in this PR:

  • npm global install
  • Homebrew tap
  • curl installer

The structure follows good release note practices with clear sections for installation, quick start, documentation, and links. This aligns well with the PR's goal of establishing npm and Homebrew as distribution channels.

bin/aidevops (1)

1-21: LGTM! Clean and minimal wrapper with proper error handling.

The wrapper script follows best practices:

  • Strict mode (set -euo pipefail) catches errors early
  • Uses exec to efficiently replace the wrapper process
  • Provides helpful error messages with installation guidance

The hardcoded fallback path $HOME/Git/aidevops/aidevops.sh on line 14-16 is a reasonable developer convenience, though users with non-standard layouts would need to use npm/brew installs. This tradeoff is acceptable for maintaining simplicity.

homebrew/aidevops.rb (1)

8-9: SHA256 placeholder is correctly handled by CI workflow.

The publish-packages workflow's update-homebrew-tap job dynamically computes the SHA256 hash directly from the release tarball using curl and sha256sum, then substitutes it into the formula via sed before pushing to the homebrew-tap repository. The PLACEHOLDER_SHA256 will be properly replaced during release publication.

.agent/AGENTS.md (2)

410-423: LGTM! Clear multi-channel installation documentation.

The installation section now properly documents npm, Homebrew, and curl methods. This aligns well with the new distribution infrastructure added in this PR.


443-454: Well-documented CLI surface expansion.

The new commands (update, upgrade, repos, repos add, detect, update-tools) are clearly documented with their purposes. The project tracking and auto-detection sections provide useful context for users discovering these features.

aidevops.sh (6)

73-79: LGTM! Clean initialization function.

The init_repos_file function follows good practices with directory creation before file write. The JSON structure is properly initialized.


150-180: LGTM! Well-structured detection function.

The function properly handles edge cases (not in git repo, no .aidevops.json, already registered) with appropriate return codes. Good use of explicit returns.


520-573: LGTM! Solid repo upgrade flow.

The implementation properly:

  • Iterates registered repos with process substitution
  • Checks directory existence before processing
  • Uses atomic temp file writes for JSON updates
  • Provides clear user feedback

Good integration of the repo tracking feature into the update workflow.


994-1006: LGTM! Clean feature list construction and registration.

The features_list is properly built with comma separation and trailing comma removal. Registration happens at the appropriate point after all initialization completes.


1546-1626: LGTM! Safe and thorough project detection.

The implementation properly uses find -print0 with read -d '' for safe filename handling. The two-phase approach (current directory first, then ~/Git scan) provides good UX. User prompts are clear with sensible defaults.


1691-1697: LGTM! Helpful auto-detection hook.

The auto-detection tip is a nice UX touch, properly excluding the detect and repos commands to avoid redundant messaging. Good use of stderr redirect to suppress noise.

package.json (2)

7-9: LGTM! Proper bin entry for CLI exposure.

The bin entry correctly maps the aidevops command to the wrapper script at ./bin/aidevops.


21-22: LGTM! Resilient postinstall hook.

The || true ensures npm install doesn't fail if the postinstall script encounters issues, which is appropriate for optional setup steps.

.github/workflows/publish-packages.yml (1)

1-58: LGTM! Well-structured npm publish job.

The npm publishing job follows best practices:

  • Uses provenance for supply chain transparency
  • Handles both release triggers and manual dispatch
  • Updates package.json version before publish
  • Provides clear step summary

Comment on lines +17 to +34
def install
# Install the CLI script
bin.install "aidevops.sh" => "aidevops"

# Install setup script for manual setup
libexec.install "setup.sh"

# Install agent files
(share/"aidevops").install ".agent"
(share/"aidevops").install "VERSION"

# Create wrapper that sets up paths
(bin/"aidevops").write <<~EOS
#!/usr/bin/env bash
export AIDEVOPS_SHARE="#{share}/aidevops"
exec "#{libexec}/aidevops.sh" "$@"
EOS
end
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Path mismatch: wrapper references wrong script name.

Line 19 installs aidevops.sh as aidevops in the bin directory, but line 32 in the wrapper tries to execute #{libexec}/aidevops.sh. Since the setup script is installed to libexec (line 22), not the main script, and the main script is renamed in bin, this wrapper will fail to find the script.

Additionally, the wrapper overwrites the binary just installed on line 19, which seems intentional but the exec path is incorrect.

🐛 Proposed fix - align paths correctly
   def install
     # Install the CLI script
-    bin.install "aidevops.sh" => "aidevops"
+    libexec.install "aidevops.sh"
     
     # Install setup script for manual setup
     libexec.install "setup.sh"
     
     # Install agent files
     (share/"aidevops").install ".agent"
     (share/"aidevops").install "VERSION"
     
     # Create wrapper that sets up paths
     (bin/"aidevops").write <<~EOS
       #!/usr/bin/env bash
       export AIDEVOPS_SHARE="#{share}/aidevops"
       exec "#{libexec}/aidevops.sh" "$@"
     EOS
   end
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def install
# Install the CLI script
bin.install "aidevops.sh" => "aidevops"
# Install setup script for manual setup
libexec.install "setup.sh"
# Install agent files
(share/"aidevops").install ".agent"
(share/"aidevops").install "VERSION"
# Create wrapper that sets up paths
(bin/"aidevops").write <<~EOS
#!/usr/bin/env bash
export AIDEVOPS_SHARE="#{share}/aidevops"
exec "#{libexec}/aidevops.sh" "$@"
EOS
end
def install
# Install the CLI script
libexec.install "aidevops.sh"
# Install setup script for manual setup
libexec.install "setup.sh"
# Install agent files
(share/"aidevops").install ".agent"
(share/"aidevops").install "VERSION"
# Create wrapper that sets up paths
(bin/"aidevops").write <<~EOS
#!/usr/bin/env bash
export AIDEVOPS_SHARE="#{share}/aidevops"
exec "#{libexec}/aidevops.sh" "$@"
EOS
end

- Security: Use env vars instead of direct interpolation in workflow
- Security: Pin third-party action to commit SHA
- Security: Add fail-on-error to tarball download
- Fix: Correct path fallback in remove|rm handler
- Fix: Remove unused spawn import in postinstall.js
- Fix: Correct error message path in postinstall.js
- Fix: Add explicit returns to shell functions
- Fix: Remove dead jq validation code
- Optimize: Remove .agent/ from npm package (setup.sh downloads it)
- Improve: Add non-interactive mode to Homebrew post_install
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @aidevops.sh:
- Around line 155-185: In detect_unregistered_repo(), the git rev-parse
--is-inside-work-tree call uses redundant redirection (&>/dev/null 2>&1); remove
the duplicate so the command redirects both stdout and stderr only once (e.g.,
use &>/dev/null or >/dev/null 2>&1) to avoid the double-stderr redirection and
keep behavior unchanged.
- Around line 1518-1536: The arithmetic increment using "((removed++))" can
return a non-zero exit status under set -e when removed is 0; replace that
increment with a safe form such as "((removed+=1))" or "removed=$((removed+1))"
in the block that initializes "local removed=0" and increments inside the loop
that reads from get_registered_repos so the script won't abort unexpectedly.

In @package.json:
- Around line 59-65: The package.json "files" array is missing the templates
directory required by npm-postinstall.js and setup.sh; update the "files" array
entry used in package.json to include "templates/" so that setup.sh (which calls
templates/deploy-templates.sh at line 1091) and npm-postinstall.js can find and
execute deploy-templates.sh and other template scripts during global installs.
🧹 Nitpick comments (2)
aidevops.sh (2)

73-79: Add explicit return for consistency.

Per coding guidelines, shell functions should have explicit returns.

♻️ Suggested fix
 init_repos_file() {
     if [[ ! -f "$REPOS_FILE" ]]; then
         mkdir -p "$CONFIG_DIR"
         echo '{"initialized_repos": []}' > "$REPOS_FILE"
     fi
+    return 0
 }

1583-1600: Consider adding explicit return at end of cmd_detect.

For consistency with coding guidelines requiring explicit returns in shell functions.

♻️ Suggested addition at end of cmd_detect
         done
     fi
+    return 0
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4034bf6 and 0a59352.

📒 Files selected for processing (5)
  • .github/workflows/publish-packages.yml
  • aidevops.sh
  • homebrew/aidevops.rb
  • package.json
  • scripts/npm-postinstall.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • homebrew/aidevops.rb
  • .github/workflows/publish-packages.yml
🧰 Additional context used
📓 Path-based instructions (1)
**/*.sh

📄 CodeRabbit inference engine (AGENTS.md)

**/*.sh: Use local var="$1" pattern for shell variable assignments
Use explicit returns in shell scripts
Run ShellCheck on all scripts with zero violations required

Files:

  • aidevops.sh
🧠 Learnings (10)
📚 Learning: 2025-12-22T01:24:53.937Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/AGENTS.md:0-0
Timestamp: 2025-12-22T01:24:53.937Z
Learning: Follow all security protocols and working directory specifications defined in ~/Git/aidevops/AGENTS.md

Applied to files:

  • aidevops.sh
  • package.json
  • scripts/npm-postinstall.js
📚 Learning: 2025-12-22T01:24:53.937Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/AGENTS.md:0-0
Timestamp: 2025-12-22T01:24:53.937Z
Learning: Use only the specified working directories: ~/.aidevops/.agent-workspace/work/[project]/ for work files, ~/.aidevops/.agent-workspace/tmp/ for temporary files, and ~/.aidevops/.agent-workspace/memory/ for persistent memory

Applied to files:

  • aidevops.sh
📚 Learning: 2025-12-22T01:24:53.937Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/AGENTS.md:0-0
Timestamp: 2025-12-22T01:24:53.937Z
Learning: Never store credentials in working directories (~/.aidevops/.agent-workspace/), Git repositories, home directory root, or hardcoded in code and scripts

Applied to files:

  • aidevops.sh
📚 Learning: 2025-12-22T01:24:53.937Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/AGENTS.md:0-0
Timestamp: 2025-12-22T01:24:53.937Z
Learning: Reference the authoritative repository at ~/Git/aidevops/ for all detailed AI assistant instructions and configurations

Applied to files:

  • aidevops.sh
  • package.json
📚 Learning: 2025-12-22T01:25:03.138Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/git/AGENTS.md:0-0
Timestamp: 2025-12-22T01:25:03.138Z
Learning: Store Service Configurations in ~/Git/aidevops/configs/[service]-config.json with file permissions set to 600

Applied to files:

  • aidevops.sh
📚 Learning: 2025-12-22T01:25:03.138Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/git/AGENTS.md:0-0
Timestamp: 2025-12-22T01:25:03.138Z
Learning: Use standardized patterns as defined in the authoritative DevOps repository at ~/Git/aidevops/

Applied to files:

  • aidevops.sh
📚 Learning: 2025-12-22T01:24:53.937Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/AGENTS.md:0-0
Timestamp: 2025-12-22T01:24:53.937Z
Learning: Use the helper script at ~/Git/aidevops/.agent/scripts/setup-local-api-keys.sh to manage secure storage of API keys rather than manual configuration

Applied to files:

  • aidevops.sh
📚 Learning: 2026-01-06T15:57:56.027Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-06T15:57:56.027Z
Learning: Applies to **/setup.sh : Deploy agents locally using ./setup.sh script

Applied to files:

  • aidevops.sh
  • scripts/npm-postinstall.js
📚 Learning: 2025-12-22T01:25:03.138Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: templates/home/git/AGENTS.md:0-0
Timestamp: 2025-12-22T01:25:03.138Z
Learning: NEVER store credentials or API keys in ~/.aidevops/.agent-workspace/ directories - working files are not secure

Applied to files:

  • aidevops.sh
📚 Learning: 2026-01-06T15:57:56.027Z
Learnt from: CR
Repo: marcusquinn/aidevops PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-06T15:57:56.027Z
Learning: Applies to **/AGENTS.md : Limit root AGENTS.md to ~50-100 max instructions with universal applicability to >80% of tasks

Applied to files:

  • package.json
🪛 GitHub Check: Codacy Static Code Analysis
scripts/npm-postinstall.js

[warning] 6-6: scripts/npm-postinstall.js#L6
A require() style import is forbidden.


[warning] 6-6: scripts/npm-postinstall.js#L6
ES2015 block-scoped variables are forbidden.


[warning] 6-6: scripts/npm-postinstall.js#L6
ES2015 destructuring is forbidden.


[notice] 6-6: scripts/npm-postinstall.js#L6
Filename npm-postinstall.js does not match the file name pattern ^([a-z][a-z0-9])(-[a-z0-9]+)(.spec|.test)?.ts$


[warning] 6-6: scripts/npm-postinstall.js#L6
Require statement not part of import statement.


[warning] 7-7: scripts/npm-postinstall.js#L7
A require() style import is forbidden.


[warning] 7-7: scripts/npm-postinstall.js#L7
ES2015 block-scoped variables are forbidden.


[warning] 7-7: scripts/npm-postinstall.js#L7
Require statement not part of import statement.


[warning] 8-8: scripts/npm-postinstall.js#L8
A require() style import is forbidden.


[warning] 8-8: scripts/npm-postinstall.js#L8
ES2015 block-scoped variables are forbidden.


[warning] 8-8: scripts/npm-postinstall.js#L8
Require statement not part of import statement.


[notice] 8-8: scripts/npm-postinstall.js#L8
You have a misspelled word: fs on Identifier


[warning] 9-9: scripts/npm-postinstall.js#L9
A require() style import is forbidden.


[warning] 9-9: scripts/npm-postinstall.js#L9
ES2015 block-scoped variables are forbidden.


[warning] 9-9: scripts/npm-postinstall.js#L9
Require statement not part of import statement.


[notice] 9-9: scripts/npm-postinstall.js#L9
You have a misspelled word: os on Identifier


[warning] 11-11: scripts/npm-postinstall.js#L11
ES2015 block-scoped variables are forbidden.


[warning] 12-12: scripts/npm-postinstall.js#L12
ES2015 block-scoped variables are forbidden.


[warning] 13-13: scripts/npm-postinstall.js#L13
ES2015 block-scoped variables are forbidden.


[notice] 13-13: scripts/npm-postinstall.js#L13
You have a misspelled word: os on Identifier


[warning] 16-16: scripts/npm-postinstall.js#L16
ES2015 block-scoped variables are forbidden.


[warning] 16-16: scripts/npm-postinstall.js#L16
npm_config_global is not listed as a dependency in turbo.json


[warning] 19-19: scripts/npm-postinstall.js#L19
Found existsSync from package "fs" with non literal argument at index 0


[failure] 19-19: scripts/npm-postinstall.js#L19
The application dynamically constructs file or path information.


[notice] 19-19: scripts/npm-postinstall.js#L19
You have a misspelled word: fs on Identifier


[notice] 20-20: scripts/npm-postinstall.js#L20
You have a misspelled word: aidevops on String


[failure] 25-25: scripts/npm-postinstall.js#L25
The application dynamically constructs file or path information.


[notice] 25-25: scripts/npm-postinstall.js#L25
You have a misspelled word: fs on Identifier


[notice] 30-30: scripts/npm-postinstall.js#L30
You have a misspelled word: aidevops on String


[warning] 35-35: scripts/npm-postinstall.js#L35
ES2015 template literals are forbidden.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (12)
scripts/npm-postinstall.js (3)

1-13: LGTM! Clean setup for the postinstall script.

The CommonJS imports and path construction are appropriate for a Node.js postinstall script. The static analysis warnings about ES2015 features and require() are false positives—this is intentionally a CommonJS script for broad Node.js compatibility.


15-22: Verify the skip condition logic.

The condition !isGlobalInstall && fs.existsSync(agentsDir) skips setup only when it's a local install AND agents already exist. This means:

  • Local install without agents → runs setup (may be unintended)
  • Global install → always runs setup

If the intent is to skip all local installs regardless of agent state, consider:

-if (!isGlobalInstall && fs.existsSync(agentsDir)) {
+if (!isGlobalInstall) {

Otherwise, if the current behavior is intentional (run setup on fresh local installs), a clarifying comment would help.


33-58: Solid error handling with user-friendly fallback guidance.

The non-fatal exit (code 0) ensures npm install doesn't fail if setup encounters issues, and the console output provides clear manual recovery steps. The stdio: 'inherit' correctly streams setup output to the user.

package.json (3)

7-9: LGTM! Clean bin entry for CLI exposure.

The bin entry correctly points to the wrapper script, enabling aidevops command after global npm install.


21-22: Appropriate postinstall configuration.

The || true suffix ensures npm install succeeds even if postinstall fails, matching the non-fatal error handling in the script itself.


55-58: Verify Windows exclusion is intentional.

The os field restricts installation to darwin and linux. If Windows/WSL users attempt npm install -g aidevops, npm will refuse to install. Consider whether this is the desired behavior or if a warning in the README would be more appropriate.

aidevops.sh (6)

22-26: LGTM! Well-organized configuration constants.

The CONFIG_DIR and REPOS_FILE paths follow XDG conventions (~/.config/aidevops), and the ShellCheck disable comment is appropriate for the unused REPO_URL variable.


83-116: Clean implementation with proper local variable pattern.

The function correctly uses local var="$1" pattern, handles path normalization failures gracefully, and has explicit returns. The jq-based JSON manipulation is robust.


525-578: Solid upgrade workflow with user confirmation.

The registered repos upgrade flow is well-implemented:

  • Collects repos needing upgrade into an array
  • Displays clear summary before prompting
  • Updates both .aidevops.json and the registry atomically

Minor: The nested while-read loop with jq and temp files is correct but verbose—acceptable for maintainability.


1396-1448: Well-structured repos list command with visual status indicators.

The color-coded status display (✓ up-to-date, ↑ update available, ✗ not found) provides excellent UX. The pipe-delimited parsing from jq output is a clean approach.


1550-1630: cmd_detect implementation is thorough and user-friendly.

The function handles both current-directory detection and scanning ~/Git/ for unregistered projects. The -print0 with read -d '' is the correct approach for handling paths with spaces.


1692-1701: Auto-detect tip is a nice UX touch.

Silently checking for unregistered repos and showing a non-blocking tip improves discoverability of the registration feature without interrupting workflow.

The npm-postinstall.js uses CommonJS for Node.js compatibility.
False positives: spelling (fs, os, aidevops), ES2015 features,
TypeScript rules on JS file, path traversal (package-relative paths).
- Remove redundant redirection in detect_unregistered_repo()
- Use safe arithmetic increment (removed=$((removed+1))) to avoid set -e issues
- Add explicit returns to init_repos_file() and cmd_detect()
- Include templates/ in package.json files array for setup.sh
@marcusquinn
Copy link
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 13, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@sonarqubecloud
Copy link

@github-actions
Copy link

🔍 Code Quality Report

�[0;35m[MONITOR]�[0m Code Review Monitoring Report

�[0;34m[INFO]�[0m Latest Quality Status:
SonarCloud: 0 bugs, 0 vulnerabilities, 260 code smells

�[0;34m[INFO]�[0m Recent monitoring activity:
Tue Jan 13 23:09:49 UTC 2026: Code review monitoring started
Tue Jan 13 23:09:50 UTC 2026: SonarCloud - Bugs: 0, Vulnerabilities: 0, Code Smells: 260
Tue Jan 13 23:09:50 UTC 2026: Qlty - 0 issues found, auto-formatting applied
Tue Jan 13 23:09:52 UTC 2026: Codacy analysis completed with auto-fixes

📈 Current Quality Metrics

  • BUGS: 0
  • CODE SMELLS: 260
  • VULNERABILITIES: 0

Generated on: Tue Jan 13 23:10:31 UTC 2026


Generated by AI DevOps Framework Code Review Monitoring

@marcusquinn marcusquinn merged commit d5b4fe4 into main Jan 13, 2026
7 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant