aidevops 2.52.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent/AGENTS.md +614 -0
- package/.agent/accounts.md +65 -0
- package/.agent/aidevops/add-new-mcp-to-aidevops.md +456 -0
- package/.agent/aidevops/api-integrations.md +335 -0
- package/.agent/aidevops/architecture.md +510 -0
- package/.agent/aidevops/configs.md +274 -0
- package/.agent/aidevops/docs.md +244 -0
- package/.agent/aidevops/extension.md +311 -0
- package/.agent/aidevops/mcp-integrations.md +340 -0
- package/.agent/aidevops/mcp-troubleshooting.md +162 -0
- package/.agent/aidevops/memory-patterns.md +172 -0
- package/.agent/aidevops/providers.md +217 -0
- package/.agent/aidevops/recommendations.md +321 -0
- package/.agent/aidevops/requirements.md +301 -0
- package/.agent/aidevops/resources.md +214 -0
- package/.agent/aidevops/security-requirements.md +174 -0
- package/.agent/aidevops/security.md +350 -0
- package/.agent/aidevops/service-links.md +400 -0
- package/.agent/aidevops/services.md +357 -0
- package/.agent/aidevops/setup.md +153 -0
- package/.agent/aidevops/troubleshooting.md +389 -0
- package/.agent/aidevops.md +124 -0
- package/.agent/build-plus.md +244 -0
- package/.agent/content/guidelines.md +109 -0
- package/.agent/content.md +87 -0
- package/.agent/health.md +59 -0
- package/.agent/legal.md +59 -0
- package/.agent/loop-state/full-loop.local.md +16 -0
- package/.agent/loop-state/ralph-loop.local.md +10 -0
- package/.agent/marketing.md +440 -0
- package/.agent/memory/README.md +260 -0
- package/.agent/onboarding.md +796 -0
- package/.agent/plan-plus.md +245 -0
- package/.agent/research.md +100 -0
- package/.agent/sales.md +333 -0
- package/.agent/scripts/101domains-helper.sh +701 -0
- package/.agent/scripts/add-missing-returns.sh +140 -0
- package/.agent/scripts/agent-browser-helper.sh +311 -0
- package/.agent/scripts/agno-setup.sh +712 -0
- package/.agent/scripts/ahrefs-mcp-wrapper.js +168 -0
- package/.agent/scripts/aidevops-update-check.sh +71 -0
- package/.agent/scripts/ampcode-cli.sh +522 -0
- package/.agent/scripts/auto-version-bump.sh +156 -0
- package/.agent/scripts/autogen-helper.sh +512 -0
- package/.agent/scripts/beads-sync-helper.sh +596 -0
- package/.agent/scripts/closte-helper.sh +5 -0
- package/.agent/scripts/cloudron-helper.sh +321 -0
- package/.agent/scripts/codacy-cli-chunked.sh +581 -0
- package/.agent/scripts/codacy-cli.sh +442 -0
- package/.agent/scripts/code-audit-helper.sh +5 -0
- package/.agent/scripts/coderabbit-cli.sh +417 -0
- package/.agent/scripts/coderabbit-pro-analysis.sh +238 -0
- package/.agent/scripts/commands/code-simplifier.md +86 -0
- package/.agent/scripts/commands/full-loop.md +246 -0
- package/.agent/scripts/commands/postflight-loop.md +103 -0
- package/.agent/scripts/commands/recall.md +182 -0
- package/.agent/scripts/commands/remember.md +132 -0
- package/.agent/scripts/commands/save-todo.md +175 -0
- package/.agent/scripts/commands/session-review.md +154 -0
- package/.agent/scripts/comprehensive-quality-fix.sh +106 -0
- package/.agent/scripts/context-builder-helper.sh +522 -0
- package/.agent/scripts/coolify-cli-helper.sh +674 -0
- package/.agent/scripts/coolify-helper.sh +380 -0
- package/.agent/scripts/crawl4ai-examples.sh +401 -0
- package/.agent/scripts/crawl4ai-helper.sh +1078 -0
- package/.agent/scripts/crewai-helper.sh +681 -0
- package/.agent/scripts/dev-browser-helper.sh +513 -0
- package/.agent/scripts/dns-helper.sh +396 -0
- package/.agent/scripts/domain-research-helper.sh +917 -0
- package/.agent/scripts/dspy-helper.sh +285 -0
- package/.agent/scripts/dspyground-helper.sh +291 -0
- package/.agent/scripts/eeat-score-helper.sh +1242 -0
- package/.agent/scripts/efficient-return-fix.sh +92 -0
- package/.agent/scripts/extract-opencode-prompts.sh +128 -0
- package/.agent/scripts/find-missing-returns.sh +113 -0
- package/.agent/scripts/fix-auth-headers.sh +104 -0
- package/.agent/scripts/fix-common-strings.sh +254 -0
- package/.agent/scripts/fix-content-type.sh +100 -0
- package/.agent/scripts/fix-error-messages.sh +130 -0
- package/.agent/scripts/fix-misplaced-returns.sh +74 -0
- package/.agent/scripts/fix-remaining-literals.sh +152 -0
- package/.agent/scripts/fix-return-statements.sh +41 -0
- package/.agent/scripts/fix-s131-default-cases.sh +249 -0
- package/.agent/scripts/fix-sc2155-simple.sh +102 -0
- package/.agent/scripts/fix-shellcheck-critical.sh +187 -0
- package/.agent/scripts/fix-string-literals.sh +273 -0
- package/.agent/scripts/full-loop-helper.sh +773 -0
- package/.agent/scripts/generate-opencode-agents.sh +497 -0
- package/.agent/scripts/generate-opencode-commands.sh +1629 -0
- package/.agent/scripts/generate-skills.sh +366 -0
- package/.agent/scripts/git-platforms-helper.sh +640 -0
- package/.agent/scripts/gitea-cli-helper.sh +743 -0
- package/.agent/scripts/github-cli-helper.sh +702 -0
- package/.agent/scripts/gitlab-cli-helper.sh +682 -0
- package/.agent/scripts/gsc-add-user-helper.sh +325 -0
- package/.agent/scripts/gsc-sitemap-helper.sh +678 -0
- package/.agent/scripts/hetzner-helper.sh +485 -0
- package/.agent/scripts/hostinger-helper.sh +229 -0
- package/.agent/scripts/keyword-research-helper.sh +1815 -0
- package/.agent/scripts/langflow-helper.sh +544 -0
- package/.agent/scripts/linkedin-automation.py +241 -0
- package/.agent/scripts/linter-manager.sh +599 -0
- package/.agent/scripts/linters-local.sh +434 -0
- package/.agent/scripts/list-keys-helper.sh +488 -0
- package/.agent/scripts/local-browser-automation.py +339 -0
- package/.agent/scripts/localhost-helper.sh +744 -0
- package/.agent/scripts/loop-common.sh +806 -0
- package/.agent/scripts/mainwp-helper.sh +728 -0
- package/.agent/scripts/markdown-formatter.sh +338 -0
- package/.agent/scripts/markdown-lint-fix.sh +311 -0
- package/.agent/scripts/mass-fix-returns.sh +58 -0
- package/.agent/scripts/mcp-diagnose.sh +167 -0
- package/.agent/scripts/mcp-inspector-helper.sh +449 -0
- package/.agent/scripts/memory-helper.sh +650 -0
- package/.agent/scripts/monitor-code-review.sh +255 -0
- package/.agent/scripts/onboarding-helper.sh +706 -0
- package/.agent/scripts/opencode-github-setup-helper.sh +797 -0
- package/.agent/scripts/opencode-test-helper.sh +213 -0
- package/.agent/scripts/pagespeed-helper.sh +464 -0
- package/.agent/scripts/pandoc-helper.sh +362 -0
- package/.agent/scripts/postflight-check.sh +555 -0
- package/.agent/scripts/pre-commit-hook.sh +259 -0
- package/.agent/scripts/pre-edit-check.sh +169 -0
- package/.agent/scripts/qlty-cli.sh +356 -0
- package/.agent/scripts/quality-cli-manager.sh +525 -0
- package/.agent/scripts/quality-feedback-helper.sh +462 -0
- package/.agent/scripts/quality-fix.sh +263 -0
- package/.agent/scripts/quality-loop-helper.sh +1108 -0
- package/.agent/scripts/ralph-loop-helper.sh +836 -0
- package/.agent/scripts/ralph-upstream-check.sh +341 -0
- package/.agent/scripts/secretlint-helper.sh +847 -0
- package/.agent/scripts/servers-helper.sh +241 -0
- package/.agent/scripts/ses-helper.sh +619 -0
- package/.agent/scripts/session-review-helper.sh +404 -0
- package/.agent/scripts/setup-linters-wizard.sh +379 -0
- package/.agent/scripts/setup-local-api-keys.sh +330 -0
- package/.agent/scripts/setup-mcp-integrations.sh +472 -0
- package/.agent/scripts/shared-constants.sh +246 -0
- package/.agent/scripts/site-crawler-helper.sh +1487 -0
- package/.agent/scripts/snyk-helper.sh +940 -0
- package/.agent/scripts/sonarcloud-autofix.sh +193 -0
- package/.agent/scripts/sonarcloud-cli.sh +191 -0
- package/.agent/scripts/sonarscanner-cli.sh +455 -0
- package/.agent/scripts/spaceship-helper.sh +747 -0
- package/.agent/scripts/stagehand-helper.sh +321 -0
- package/.agent/scripts/stagehand-python-helper.sh +321 -0
- package/.agent/scripts/stagehand-python-setup.sh +441 -0
- package/.agent/scripts/stagehand-setup.sh +439 -0
- package/.agent/scripts/system-cleanup.sh +340 -0
- package/.agent/scripts/terminal-title-helper.sh +388 -0
- package/.agent/scripts/terminal-title-setup.sh +549 -0
- package/.agent/scripts/test-stagehand-both-integration.sh +317 -0
- package/.agent/scripts/test-stagehand-integration.sh +309 -0
- package/.agent/scripts/test-stagehand-python-integration.sh +341 -0
- package/.agent/scripts/todo-ready.sh +263 -0
- package/.agent/scripts/tool-version-check.sh +362 -0
- package/.agent/scripts/toon-helper.sh +469 -0
- package/.agent/scripts/twilio-helper.sh +917 -0
- package/.agent/scripts/updown-helper.sh +279 -0
- package/.agent/scripts/validate-mcp-integrations.sh +250 -0
- package/.agent/scripts/validate-version-consistency.sh +131 -0
- package/.agent/scripts/vaultwarden-helper.sh +597 -0
- package/.agent/scripts/vercel-cli-helper.sh +816 -0
- package/.agent/scripts/verify-mirrors.sh +169 -0
- package/.agent/scripts/version-manager.sh +831 -0
- package/.agent/scripts/webhosting-helper.sh +471 -0
- package/.agent/scripts/webhosting-verify.sh +238 -0
- package/.agent/scripts/wordpress-mcp-helper.sh +508 -0
- package/.agent/scripts/worktree-helper.sh +595 -0
- package/.agent/scripts/worktree-sessions.sh +577 -0
- package/.agent/seo/dataforseo.md +215 -0
- package/.agent/seo/domain-research.md +532 -0
- package/.agent/seo/eeat-score.md +659 -0
- package/.agent/seo/google-search-console.md +366 -0
- package/.agent/seo/gsc-sitemaps.md +282 -0
- package/.agent/seo/keyword-research.md +521 -0
- package/.agent/seo/serper.md +278 -0
- package/.agent/seo/site-crawler.md +387 -0
- package/.agent/seo.md +236 -0
- package/.agent/services/accounting/quickfile.md +159 -0
- package/.agent/services/communications/telfon.md +470 -0
- package/.agent/services/communications/twilio.md +569 -0
- package/.agent/services/crm/fluentcrm.md +449 -0
- package/.agent/services/email/ses.md +399 -0
- package/.agent/services/hosting/101domains.md +378 -0
- package/.agent/services/hosting/closte.md +177 -0
- package/.agent/services/hosting/cloudflare.md +251 -0
- package/.agent/services/hosting/cloudron.md +478 -0
- package/.agent/services/hosting/dns-providers.md +335 -0
- package/.agent/services/hosting/domain-purchasing.md +344 -0
- package/.agent/services/hosting/hetzner.md +327 -0
- package/.agent/services/hosting/hostinger.md +287 -0
- package/.agent/services/hosting/localhost.md +419 -0
- package/.agent/services/hosting/spaceship.md +353 -0
- package/.agent/services/hosting/webhosting.md +330 -0
- package/.agent/social-media.md +69 -0
- package/.agent/templates/plans-template.md +114 -0
- package/.agent/templates/prd-template.md +129 -0
- package/.agent/templates/tasks-template.md +108 -0
- package/.agent/templates/todo-template.md +89 -0
- package/.agent/tools/ai-assistants/agno.md +471 -0
- package/.agent/tools/ai-assistants/capsolver.md +326 -0
- package/.agent/tools/ai-assistants/configuration.md +221 -0
- package/.agent/tools/ai-assistants/overview.md +209 -0
- package/.agent/tools/ai-assistants/status.md +171 -0
- package/.agent/tools/ai-assistants/windsurf.md +193 -0
- package/.agent/tools/ai-orchestration/autogen.md +406 -0
- package/.agent/tools/ai-orchestration/crewai.md +445 -0
- package/.agent/tools/ai-orchestration/langflow.md +405 -0
- package/.agent/tools/ai-orchestration/openprose.md +487 -0
- package/.agent/tools/ai-orchestration/overview.md +362 -0
- package/.agent/tools/ai-orchestration/packaging.md +647 -0
- package/.agent/tools/browser/agent-browser.md +464 -0
- package/.agent/tools/browser/browser-automation.md +400 -0
- package/.agent/tools/browser/chrome-devtools.md +282 -0
- package/.agent/tools/browser/crawl4ai-integration.md +422 -0
- package/.agent/tools/browser/crawl4ai-resources.md +277 -0
- package/.agent/tools/browser/crawl4ai-usage.md +416 -0
- package/.agent/tools/browser/crawl4ai.md +585 -0
- package/.agent/tools/browser/dev-browser.md +341 -0
- package/.agent/tools/browser/pagespeed.md +260 -0
- package/.agent/tools/browser/playwright.md +266 -0
- package/.agent/tools/browser/playwriter.md +310 -0
- package/.agent/tools/browser/stagehand-examples.md +456 -0
- package/.agent/tools/browser/stagehand-python.md +483 -0
- package/.agent/tools/browser/stagehand.md +421 -0
- package/.agent/tools/build-agent/agent-review.md +224 -0
- package/.agent/tools/build-agent/build-agent.md +784 -0
- package/.agent/tools/build-mcp/aidevops-plugin.md +476 -0
- package/.agent/tools/build-mcp/api-wrapper.md +445 -0
- package/.agent/tools/build-mcp/build-mcp.md +240 -0
- package/.agent/tools/build-mcp/deployment.md +401 -0
- package/.agent/tools/build-mcp/server-patterns.md +632 -0
- package/.agent/tools/build-mcp/transports.md +366 -0
- package/.agent/tools/code-review/auditing.md +383 -0
- package/.agent/tools/code-review/automation.md +219 -0
- package/.agent/tools/code-review/best-practices.md +203 -0
- package/.agent/tools/code-review/codacy.md +151 -0
- package/.agent/tools/code-review/code-simplifier.md +174 -0
- package/.agent/tools/code-review/code-standards.md +309 -0
- package/.agent/tools/code-review/coderabbit.md +101 -0
- package/.agent/tools/code-review/management.md +155 -0
- package/.agent/tools/code-review/qlty.md +248 -0
- package/.agent/tools/code-review/secretlint.md +565 -0
- package/.agent/tools/code-review/setup.md +250 -0
- package/.agent/tools/code-review/snyk.md +563 -0
- package/.agent/tools/code-review/tools.md +230 -0
- package/.agent/tools/content/summarize.md +353 -0
- package/.agent/tools/context/augment-context-engine.md +468 -0
- package/.agent/tools/context/context-builder-agent.md +76 -0
- package/.agent/tools/context/context-builder.md +375 -0
- package/.agent/tools/context/context7.md +371 -0
- package/.agent/tools/context/dspy.md +302 -0
- package/.agent/tools/context/dspyground.md +374 -0
- package/.agent/tools/context/llm-tldr.md +219 -0
- package/.agent/tools/context/osgrep.md +488 -0
- package/.agent/tools/context/prompt-optimization.md +338 -0
- package/.agent/tools/context/toon.md +292 -0
- package/.agent/tools/conversion/pandoc.md +304 -0
- package/.agent/tools/credentials/api-key-management.md +154 -0
- package/.agent/tools/credentials/api-key-setup.md +224 -0
- package/.agent/tools/credentials/environment-variables.md +180 -0
- package/.agent/tools/credentials/vaultwarden.md +382 -0
- package/.agent/tools/data-extraction/outscraper.md +974 -0
- package/.agent/tools/deployment/coolify-cli.md +388 -0
- package/.agent/tools/deployment/coolify-setup.md +353 -0
- package/.agent/tools/deployment/coolify.md +345 -0
- package/.agent/tools/deployment/vercel.md +390 -0
- package/.agent/tools/git/authentication.md +132 -0
- package/.agent/tools/git/gitea-cli.md +193 -0
- package/.agent/tools/git/github-actions.md +207 -0
- package/.agent/tools/git/github-cli.md +223 -0
- package/.agent/tools/git/gitlab-cli.md +190 -0
- package/.agent/tools/git/opencode-github-security.md +350 -0
- package/.agent/tools/git/opencode-github.md +328 -0
- package/.agent/tools/git/opencode-gitlab.md +252 -0
- package/.agent/tools/git/security.md +196 -0
- package/.agent/tools/git.md +207 -0
- package/.agent/tools/opencode/oh-my-opencode.md +375 -0
- package/.agent/tools/opencode/opencode-anthropic-auth.md +446 -0
- package/.agent/tools/opencode/opencode.md +651 -0
- package/.agent/tools/social-media/bird.md +437 -0
- package/.agent/tools/task-management/beads.md +336 -0
- package/.agent/tools/terminal/terminal-title.md +251 -0
- package/.agent/tools/ui/shadcn.md +196 -0
- package/.agent/tools/ui/ui-skills.md +115 -0
- package/.agent/tools/wordpress/localwp.md +311 -0
- package/.agent/tools/wordpress/mainwp.md +391 -0
- package/.agent/tools/wordpress/scf.md +527 -0
- package/.agent/tools/wordpress/wp-admin.md +729 -0
- package/.agent/tools/wordpress/wp-dev.md +940 -0
- package/.agent/tools/wordpress/wp-preferred.md +398 -0
- package/.agent/tools/wordpress.md +95 -0
- package/.agent/workflows/branch/bugfix.md +63 -0
- package/.agent/workflows/branch/chore.md +95 -0
- package/.agent/workflows/branch/experiment.md +115 -0
- package/.agent/workflows/branch/feature.md +59 -0
- package/.agent/workflows/branch/hotfix.md +98 -0
- package/.agent/workflows/branch/refactor.md +92 -0
- package/.agent/workflows/branch/release.md +96 -0
- package/.agent/workflows/branch.md +347 -0
- package/.agent/workflows/bug-fixing.md +267 -0
- package/.agent/workflows/changelog.md +129 -0
- package/.agent/workflows/code-audit-remote.md +279 -0
- package/.agent/workflows/conversation-starter.md +69 -0
- package/.agent/workflows/error-feedback.md +578 -0
- package/.agent/workflows/feature-development.md +355 -0
- package/.agent/workflows/git-workflow.md +702 -0
- package/.agent/workflows/multi-repo-workspace.md +268 -0
- package/.agent/workflows/plans.md +709 -0
- package/.agent/workflows/postflight.md +604 -0
- package/.agent/workflows/pr.md +571 -0
- package/.agent/workflows/preflight.md +278 -0
- package/.agent/workflows/ralph-loop.md +773 -0
- package/.agent/workflows/release.md +498 -0
- package/.agent/workflows/session-manager.md +254 -0
- package/.agent/workflows/session-review.md +311 -0
- package/.agent/workflows/sql-migrations.md +631 -0
- package/.agent/workflows/version-bump.md +283 -0
- package/.agent/workflows/wiki-update.md +333 -0
- package/.agent/workflows/worktree.md +477 -0
- package/LICENSE +21 -0
- package/README.md +1446 -0
- package/VERSION +1 -0
- package/aidevops.sh +1746 -0
- package/bin/aidevops +21 -0
- package/package.json +75 -0
- package/scripts/npm-postinstall.js +60 -0
- package/setup.sh +2366 -0
package/aidevops.sh
ADDED
|
@@ -0,0 +1,1746 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# AI DevOps Framework CLI
|
|
4
|
+
# Usage: aidevops <command> [options]
|
|
5
|
+
#
|
|
6
|
+
# Version: 2.13.0
|
|
7
|
+
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
# Colors for output
|
|
11
|
+
GREEN='\033[0;32m'
|
|
12
|
+
BLUE='\033[0;34m'
|
|
13
|
+
YELLOW='\033[1;33m'
|
|
14
|
+
RED='\033[0;31m'
|
|
15
|
+
CYAN='\033[0;36m'
|
|
16
|
+
BOLD='\033[1m'
|
|
17
|
+
NC='\033[0m' # No Color
|
|
18
|
+
|
|
19
|
+
# Paths
|
|
20
|
+
INSTALL_DIR="$HOME/Git/aidevops"
|
|
21
|
+
AGENTS_DIR="$HOME/.aidevops/agents"
|
|
22
|
+
CONFIG_DIR="$HOME/.config/aidevops"
|
|
23
|
+
REPOS_FILE="$CONFIG_DIR/repos.json"
|
|
24
|
+
# shellcheck disable=SC2034 # Used in fresh install fallback
|
|
25
|
+
REPO_URL="https://github.com/marcusquinn/aidevops.git"
|
|
26
|
+
VERSION_FILE="$INSTALL_DIR/VERSION"
|
|
27
|
+
|
|
28
|
+
print_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
29
|
+
print_success() { echo -e "${GREEN}[OK]${NC} $1"; }
|
|
30
|
+
print_warning() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
|
31
|
+
print_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
|
32
|
+
print_header() { echo -e "${BOLD}${CYAN}$1${NC}"; }
|
|
33
|
+
|
|
34
|
+
# Get current version
|
|
35
|
+
get_version() {
|
|
36
|
+
if [[ -f "$VERSION_FILE" ]]; then
|
|
37
|
+
cat "$VERSION_FILE"
|
|
38
|
+
else
|
|
39
|
+
echo "unknown"
|
|
40
|
+
fi
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# Get remote version
|
|
44
|
+
get_remote_version() {
|
|
45
|
+
# Use GitHub API (not cached) instead of raw.githubusercontent.com (cached 5 min)
|
|
46
|
+
local version
|
|
47
|
+
if command -v jq &>/dev/null; then
|
|
48
|
+
version=$(curl -fsSL "https://api.github.com/repos/marcusquinn/aidevops/contents/VERSION" 2>/dev/null | jq -r '.content // empty' 2>/dev/null | base64 -d 2>/dev/null | tr -d '\n')
|
|
49
|
+
if [[ -n "$version" ]]; then
|
|
50
|
+
echo "$version"
|
|
51
|
+
return 0
|
|
52
|
+
fi
|
|
53
|
+
fi
|
|
54
|
+
# Fallback to raw (cached) if jq unavailable or API fails
|
|
55
|
+
curl -fsSL "https://raw.githubusercontent.com/marcusquinn/aidevops/main/VERSION" 2>/dev/null || echo "unknown"
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# Check if a command exists
|
|
59
|
+
check_cmd() {
|
|
60
|
+
command -v "$1" >/dev/null 2>&1
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# Check if a directory exists
|
|
64
|
+
check_dir() {
|
|
65
|
+
[[ -d "$1" ]]
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
# Check if a file exists
|
|
69
|
+
check_file() {
|
|
70
|
+
[[ -f "$1" ]]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# Initialize repos.json if it doesn't exist
|
|
74
|
+
init_repos_file() {
|
|
75
|
+
if [[ ! -f "$REPOS_FILE" ]]; then
|
|
76
|
+
mkdir -p "$CONFIG_DIR"
|
|
77
|
+
echo '{"initialized_repos": []}' > "$REPOS_FILE"
|
|
78
|
+
fi
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# Register a repo in repos.json
|
|
82
|
+
# Usage: register_repo <path> <version> <features>
|
|
83
|
+
register_repo() {
|
|
84
|
+
local repo_path="$1"
|
|
85
|
+
local version="$2"
|
|
86
|
+
local features="$3"
|
|
87
|
+
|
|
88
|
+
init_repos_file
|
|
89
|
+
|
|
90
|
+
# Normalize path (resolve symlinks, remove trailing slash)
|
|
91
|
+
repo_path=$(cd "$repo_path" 2>/dev/null && pwd -P)
|
|
92
|
+
|
|
93
|
+
if ! command -v jq &>/dev/null; then
|
|
94
|
+
print_warning "jq not installed - repo tracking disabled"
|
|
95
|
+
return 0
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
# Check if repo already registered
|
|
99
|
+
if jq -e --arg path "$repo_path" '.initialized_repos[] | select(.path == $path)' "$REPOS_FILE" &>/dev/null; then
|
|
100
|
+
# Update existing entry
|
|
101
|
+
local temp_file="${REPOS_FILE}.tmp"
|
|
102
|
+
jq --arg path "$repo_path" --arg version "$version" --arg features "$features" \
|
|
103
|
+
'(.initialized_repos[] | select(.path == $path)) |= {path: $path, version: $version, features: ($features | split(",")), updated: (now | strftime("%Y-%m-%dT%H:%M:%SZ"))}' \
|
|
104
|
+
"$REPOS_FILE" > "$temp_file" && mv "$temp_file" "$REPOS_FILE"
|
|
105
|
+
else
|
|
106
|
+
# Add new entry
|
|
107
|
+
local temp_file="${REPOS_FILE}.tmp"
|
|
108
|
+
jq --arg path "$repo_path" --arg version "$version" --arg features "$features" \
|
|
109
|
+
'.initialized_repos += [{path: $path, version: $version, features: ($features | split(",")), initialized: (now | strftime("%Y-%m-%dT%H:%M:%SZ"))}]' \
|
|
110
|
+
"$REPOS_FILE" > "$temp_file" && mv "$temp_file" "$REPOS_FILE"
|
|
111
|
+
fi
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# Get list of registered repos
|
|
115
|
+
get_registered_repos() {
|
|
116
|
+
init_repos_file
|
|
117
|
+
|
|
118
|
+
if ! command -v jq &>/dev/null; then
|
|
119
|
+
echo "[]"
|
|
120
|
+
return 0
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
jq -r '.initialized_repos[] | .path' "$REPOS_FILE" 2>/dev/null || echo ""
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
# Check if a repo needs upgrade (version behind current)
|
|
127
|
+
check_repo_needs_upgrade() {
|
|
128
|
+
local repo_path="$1"
|
|
129
|
+
local current_version
|
|
130
|
+
current_version=$(get_version)
|
|
131
|
+
|
|
132
|
+
if ! command -v jq &>/dev/null; then
|
|
133
|
+
return 1
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
local repo_version
|
|
137
|
+
repo_version=$(jq -r --arg path "$repo_path" '.initialized_repos[] | select(.path == $path) | .version' "$REPOS_FILE" 2>/dev/null)
|
|
138
|
+
|
|
139
|
+
if [[ -z "$repo_version" || "$repo_version" == "null" ]]; then
|
|
140
|
+
return 1
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
# Compare versions (simple string comparison works for semver)
|
|
144
|
+
if [[ "$repo_version" != "$current_version" ]]; then
|
|
145
|
+
return 0 # needs upgrade
|
|
146
|
+
fi
|
|
147
|
+
return 1 # up to date
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
# Detect if current directory has aidevops but isn't registered
|
|
151
|
+
detect_unregistered_repo() {
|
|
152
|
+
local project_root
|
|
153
|
+
|
|
154
|
+
# Check if in a git repo
|
|
155
|
+
if ! git rev-parse --is-inside-work-tree &>/dev/null 2>&1; then
|
|
156
|
+
return 1
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
project_root=$(git rev-parse --show-toplevel 2>/dev/null)
|
|
160
|
+
|
|
161
|
+
# Check for .aidevops.json
|
|
162
|
+
if [[ ! -f "$project_root/.aidevops.json" ]]; then
|
|
163
|
+
return 1
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
init_repos_file
|
|
167
|
+
|
|
168
|
+
if ! command -v jq &>/dev/null; then
|
|
169
|
+
return 1
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
# Check if already registered
|
|
173
|
+
if jq -e --arg path "$project_root" '.initialized_repos[] | select(.path == $path)' "$REPOS_FILE" &>/dev/null; then
|
|
174
|
+
return 1 # already registered
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
# Not registered - return the path
|
|
178
|
+
echo "$project_root"
|
|
179
|
+
return 0
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
# Check if on protected branch and offer worktree creation
|
|
183
|
+
# Returns 0 if safe to proceed, 1 if user cancelled
|
|
184
|
+
# Sets WORKTREE_PATH if worktree was created
|
|
185
|
+
check_protected_branch() {
|
|
186
|
+
local branch_type="${1:-chore}"
|
|
187
|
+
local branch_suffix="${2:-aidevops-setup}"
|
|
188
|
+
|
|
189
|
+
# Not in a git repo - skip check
|
|
190
|
+
if ! git rev-parse --is-inside-work-tree &>/dev/null; then
|
|
191
|
+
return 0
|
|
192
|
+
fi
|
|
193
|
+
|
|
194
|
+
local current_branch
|
|
195
|
+
current_branch=$(git branch --show-current 2>/dev/null || echo "")
|
|
196
|
+
|
|
197
|
+
# Not on a protected branch - safe to proceed
|
|
198
|
+
if [[ ! "$current_branch" =~ ^(main|master)$ ]]; then
|
|
199
|
+
return 0
|
|
200
|
+
fi
|
|
201
|
+
|
|
202
|
+
local project_root
|
|
203
|
+
project_root=$(git rev-parse --show-toplevel)
|
|
204
|
+
local repo_name
|
|
205
|
+
repo_name=$(basename "$project_root")
|
|
206
|
+
local suggested_branch="$branch_type/$branch_suffix"
|
|
207
|
+
|
|
208
|
+
echo ""
|
|
209
|
+
print_warning "On protected branch '$current_branch'"
|
|
210
|
+
echo ""
|
|
211
|
+
echo "Options:"
|
|
212
|
+
echo " 1. Create worktree: $suggested_branch (recommended)"
|
|
213
|
+
echo " 2. Continue on $current_branch (commits directly to main)"
|
|
214
|
+
echo " 3. Cancel"
|
|
215
|
+
echo ""
|
|
216
|
+
local choice
|
|
217
|
+
read -r -p "Choice [1]: " choice
|
|
218
|
+
choice="${choice:-1}"
|
|
219
|
+
|
|
220
|
+
case "$choice" in
|
|
221
|
+
1)
|
|
222
|
+
# Create worktree
|
|
223
|
+
local worktree_dir
|
|
224
|
+
worktree_dir="$(dirname "$project_root")/${repo_name}-${branch_type}-${branch_suffix}"
|
|
225
|
+
|
|
226
|
+
print_info "Creating worktree at $worktree_dir..."
|
|
227
|
+
|
|
228
|
+
if [[ -f "$AGENTS_DIR/scripts/worktree-helper.sh" ]]; then
|
|
229
|
+
if bash "$AGENTS_DIR/scripts/worktree-helper.sh" add "$suggested_branch" 2>/dev/null; then
|
|
230
|
+
export WORKTREE_PATH="$worktree_dir"
|
|
231
|
+
echo ""
|
|
232
|
+
print_success "Worktree created!"
|
|
233
|
+
print_info "Switching to: $worktree_dir"
|
|
234
|
+
echo ""
|
|
235
|
+
# Change to worktree directory
|
|
236
|
+
cd "$worktree_dir" || return 1
|
|
237
|
+
return 0
|
|
238
|
+
else
|
|
239
|
+
print_error "Failed to create worktree"
|
|
240
|
+
return 1
|
|
241
|
+
fi
|
|
242
|
+
else
|
|
243
|
+
# Fallback without helper script
|
|
244
|
+
if git worktree add -b "$suggested_branch" "$worktree_dir" 2>/dev/null; then
|
|
245
|
+
export WORKTREE_PATH="$worktree_dir"
|
|
246
|
+
echo ""
|
|
247
|
+
print_success "Worktree created!"
|
|
248
|
+
print_info "Switching to: $worktree_dir"
|
|
249
|
+
echo ""
|
|
250
|
+
cd "$worktree_dir" || return 1
|
|
251
|
+
return 0
|
|
252
|
+
else
|
|
253
|
+
print_error "Failed to create worktree"
|
|
254
|
+
return 1
|
|
255
|
+
fi
|
|
256
|
+
fi
|
|
257
|
+
;;
|
|
258
|
+
2)
|
|
259
|
+
print_warning "Continuing on $current_branch - changes will commit directly"
|
|
260
|
+
return 0
|
|
261
|
+
;;
|
|
262
|
+
3|*)
|
|
263
|
+
print_info "Cancelled"
|
|
264
|
+
return 1
|
|
265
|
+
;;
|
|
266
|
+
esac
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
# Status command - check all installations
|
|
270
|
+
cmd_status() {
|
|
271
|
+
print_header "AI DevOps Framework Status"
|
|
272
|
+
echo "=========================="
|
|
273
|
+
echo ""
|
|
274
|
+
|
|
275
|
+
local current_version
|
|
276
|
+
current_version=$(get_version)
|
|
277
|
+
local remote_version
|
|
278
|
+
remote_version=$(get_remote_version)
|
|
279
|
+
|
|
280
|
+
# Version info
|
|
281
|
+
print_header "Version"
|
|
282
|
+
echo " Installed: $current_version"
|
|
283
|
+
echo " Latest: $remote_version"
|
|
284
|
+
if [[ "$current_version" != "$remote_version" && "$remote_version" != "unknown" ]]; then
|
|
285
|
+
print_warning "Update available! Run: aidevops update"
|
|
286
|
+
elif [[ "$current_version" == "$remote_version" ]]; then
|
|
287
|
+
print_success "Up to date"
|
|
288
|
+
fi
|
|
289
|
+
echo ""
|
|
290
|
+
|
|
291
|
+
# Installation paths
|
|
292
|
+
print_header "Installation"
|
|
293
|
+
if check_dir "$INSTALL_DIR"; then
|
|
294
|
+
print_success "Repository: $INSTALL_DIR"
|
|
295
|
+
else
|
|
296
|
+
print_error "Repository: Not found at $INSTALL_DIR"
|
|
297
|
+
fi
|
|
298
|
+
|
|
299
|
+
if check_dir "$AGENTS_DIR"; then
|
|
300
|
+
local agent_count
|
|
301
|
+
agent_count=$(find "$AGENTS_DIR" -name "*.md" -type f 2>/dev/null | wc -l | tr -d ' ')
|
|
302
|
+
print_success "Agents: $AGENTS_DIR ($agent_count files)"
|
|
303
|
+
else
|
|
304
|
+
print_error "Agents: Not deployed"
|
|
305
|
+
fi
|
|
306
|
+
echo ""
|
|
307
|
+
|
|
308
|
+
# Required dependencies
|
|
309
|
+
print_header "Required Dependencies"
|
|
310
|
+
for cmd in git curl jq ssh; do
|
|
311
|
+
if check_cmd "$cmd"; then
|
|
312
|
+
print_success "$cmd"
|
|
313
|
+
else
|
|
314
|
+
print_error "$cmd - not installed"
|
|
315
|
+
fi
|
|
316
|
+
done
|
|
317
|
+
echo ""
|
|
318
|
+
|
|
319
|
+
# Optional dependencies
|
|
320
|
+
print_header "Optional Dependencies"
|
|
321
|
+
if check_cmd sshpass; then
|
|
322
|
+
print_success "sshpass"
|
|
323
|
+
else
|
|
324
|
+
print_warning "sshpass - not installed (needed for password SSH)"
|
|
325
|
+
fi
|
|
326
|
+
echo ""
|
|
327
|
+
|
|
328
|
+
# Recommended tools
|
|
329
|
+
print_header "Recommended Tools"
|
|
330
|
+
|
|
331
|
+
# Tabby
|
|
332
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
333
|
+
if check_dir "/Applications/Tabby.app"; then
|
|
334
|
+
print_success "Tabby terminal"
|
|
335
|
+
else
|
|
336
|
+
print_warning "Tabby terminal - not installed"
|
|
337
|
+
fi
|
|
338
|
+
else
|
|
339
|
+
if check_cmd tabby; then
|
|
340
|
+
print_success "Tabby terminal"
|
|
341
|
+
else
|
|
342
|
+
print_warning "Tabby terminal - not installed"
|
|
343
|
+
fi
|
|
344
|
+
fi
|
|
345
|
+
|
|
346
|
+
# Zed
|
|
347
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
348
|
+
if check_dir "/Applications/Zed.app"; then
|
|
349
|
+
print_success "Zed editor"
|
|
350
|
+
# Check OpenCode extension
|
|
351
|
+
if check_dir "$HOME/Library/Application Support/Zed/extensions/installed/opencode"; then
|
|
352
|
+
print_success " └─ OpenCode extension"
|
|
353
|
+
else
|
|
354
|
+
print_warning " └─ OpenCode extension - not installed"
|
|
355
|
+
fi
|
|
356
|
+
else
|
|
357
|
+
print_warning "Zed editor - not installed"
|
|
358
|
+
fi
|
|
359
|
+
else
|
|
360
|
+
if check_cmd zed; then
|
|
361
|
+
print_success "Zed editor"
|
|
362
|
+
if check_dir "$HOME/.local/share/zed/extensions/installed/opencode"; then
|
|
363
|
+
print_success " └─ OpenCode extension"
|
|
364
|
+
else
|
|
365
|
+
print_warning " └─ OpenCode extension - not installed"
|
|
366
|
+
fi
|
|
367
|
+
else
|
|
368
|
+
print_warning "Zed editor - not installed"
|
|
369
|
+
fi
|
|
370
|
+
fi
|
|
371
|
+
echo ""
|
|
372
|
+
|
|
373
|
+
# Git CLI tools
|
|
374
|
+
print_header "Git CLI Tools"
|
|
375
|
+
if check_cmd gh; then
|
|
376
|
+
print_success "GitHub CLI (gh)"
|
|
377
|
+
else
|
|
378
|
+
print_warning "GitHub CLI (gh) - not installed"
|
|
379
|
+
fi
|
|
380
|
+
|
|
381
|
+
if check_cmd glab; then
|
|
382
|
+
print_success "GitLab CLI (glab)"
|
|
383
|
+
else
|
|
384
|
+
print_warning "GitLab CLI (glab) - not installed"
|
|
385
|
+
fi
|
|
386
|
+
|
|
387
|
+
if check_cmd tea; then
|
|
388
|
+
print_success "Gitea CLI (tea)"
|
|
389
|
+
else
|
|
390
|
+
print_warning "Gitea CLI (tea) - not installed"
|
|
391
|
+
fi
|
|
392
|
+
echo ""
|
|
393
|
+
|
|
394
|
+
# AI Tools
|
|
395
|
+
print_header "AI Tools & MCPs"
|
|
396
|
+
|
|
397
|
+
if check_cmd opencode; then
|
|
398
|
+
print_success "OpenCode CLI"
|
|
399
|
+
else
|
|
400
|
+
print_warning "OpenCode CLI - not installed"
|
|
401
|
+
fi
|
|
402
|
+
|
|
403
|
+
if check_cmd auggie; then
|
|
404
|
+
if check_file "$HOME/.augment/session.json"; then
|
|
405
|
+
print_success "Augment Context Engine (authenticated)"
|
|
406
|
+
else
|
|
407
|
+
print_warning "Augment Context Engine (not authenticated)"
|
|
408
|
+
fi
|
|
409
|
+
else
|
|
410
|
+
print_warning "Augment Context Engine - not installed"
|
|
411
|
+
fi
|
|
412
|
+
|
|
413
|
+
if check_cmd osgrep; then
|
|
414
|
+
print_success "osgrep (local semantic search)"
|
|
415
|
+
else
|
|
416
|
+
print_warning "osgrep - not installed"
|
|
417
|
+
fi
|
|
418
|
+
|
|
419
|
+
if check_cmd bd; then
|
|
420
|
+
print_success "Beads CLI (task graph)"
|
|
421
|
+
else
|
|
422
|
+
print_warning "Beads CLI (bd) - not installed"
|
|
423
|
+
fi
|
|
424
|
+
echo ""
|
|
425
|
+
|
|
426
|
+
# Python/Node environments
|
|
427
|
+
print_header "Development Environments"
|
|
428
|
+
|
|
429
|
+
if check_dir "$INSTALL_DIR/python-env/dspy-env"; then
|
|
430
|
+
print_success "DSPy Python environment"
|
|
431
|
+
else
|
|
432
|
+
print_warning "DSPy Python environment - not created"
|
|
433
|
+
fi
|
|
434
|
+
|
|
435
|
+
if check_cmd dspyground; then
|
|
436
|
+
print_success "DSPyGround"
|
|
437
|
+
else
|
|
438
|
+
print_warning "DSPyGround - not installed"
|
|
439
|
+
fi
|
|
440
|
+
echo ""
|
|
441
|
+
|
|
442
|
+
# AI Assistant configs
|
|
443
|
+
print_header "AI Assistant Configurations"
|
|
444
|
+
|
|
445
|
+
local ai_configs=(
|
|
446
|
+
"$HOME/.config/opencode/opencode.json:OpenCode"
|
|
447
|
+
"$HOME/.cursor/rules:Cursor"
|
|
448
|
+
"$HOME/.claude/commands:Claude Code"
|
|
449
|
+
"$HOME/.continue:Continue.dev"
|
|
450
|
+
"$HOME/CLAUDE.md:Claude CLI memory"
|
|
451
|
+
"$HOME/GEMINI.md:Gemini CLI memory"
|
|
452
|
+
"$HOME/.cursorrules:Cursor rules"
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
for config in "${ai_configs[@]}"; do
|
|
456
|
+
local path="${config%%:*}"
|
|
457
|
+
local name="${config##*:}"
|
|
458
|
+
if [[ -e "$path" ]]; then
|
|
459
|
+
print_success "$name"
|
|
460
|
+
else
|
|
461
|
+
print_warning "$name - not configured"
|
|
462
|
+
fi
|
|
463
|
+
done
|
|
464
|
+
echo ""
|
|
465
|
+
|
|
466
|
+
# SSH key
|
|
467
|
+
print_header "SSH Configuration"
|
|
468
|
+
if check_file "$HOME/.ssh/id_ed25519"; then
|
|
469
|
+
print_success "Ed25519 SSH key"
|
|
470
|
+
else
|
|
471
|
+
print_warning "Ed25519 SSH key - not found"
|
|
472
|
+
fi
|
|
473
|
+
echo ""
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
# Update/upgrade command
|
|
477
|
+
cmd_update() {
|
|
478
|
+
print_header "Updating AI DevOps Framework"
|
|
479
|
+
echo ""
|
|
480
|
+
|
|
481
|
+
local current_version
|
|
482
|
+
current_version=$(get_version)
|
|
483
|
+
|
|
484
|
+
print_info "Current version: $current_version"
|
|
485
|
+
print_info "Fetching latest version..."
|
|
486
|
+
|
|
487
|
+
if check_dir "$INSTALL_DIR/.git"; then
|
|
488
|
+
cd "$INSTALL_DIR" || exit 1
|
|
489
|
+
|
|
490
|
+
# Fetch and check for updates
|
|
491
|
+
git fetch origin main --quiet
|
|
492
|
+
|
|
493
|
+
local local_hash
|
|
494
|
+
local_hash=$(git rev-parse HEAD)
|
|
495
|
+
local remote_hash
|
|
496
|
+
remote_hash=$(git rev-parse origin/main)
|
|
497
|
+
|
|
498
|
+
if [[ "$local_hash" == "$remote_hash" ]]; then
|
|
499
|
+
print_success "Framework already up to date!"
|
|
500
|
+
else
|
|
501
|
+
print_info "Pulling latest changes..."
|
|
502
|
+
if git pull --ff-only origin main; then
|
|
503
|
+
local new_version
|
|
504
|
+
new_version=$(get_version)
|
|
505
|
+
print_success "Updated to version $new_version"
|
|
506
|
+
echo ""
|
|
507
|
+
print_info "Running setup to apply changes..."
|
|
508
|
+
bash "$INSTALL_DIR/setup.sh"
|
|
509
|
+
else
|
|
510
|
+
print_error "Failed to pull updates"
|
|
511
|
+
print_info "Try: cd $INSTALL_DIR && git pull"
|
|
512
|
+
return 1
|
|
513
|
+
fi
|
|
514
|
+
fi
|
|
515
|
+
else
|
|
516
|
+
print_warning "Repository not found, performing fresh install..."
|
|
517
|
+
# shellcheck disable=SC2312 # curl|bash is intentional for install
|
|
518
|
+
bash <(curl -fsSL https://raw.githubusercontent.com/marcusquinn/aidevops/main/setup.sh)
|
|
519
|
+
fi
|
|
520
|
+
|
|
521
|
+
# Check registered repos for updates
|
|
522
|
+
echo ""
|
|
523
|
+
print_header "Checking Initialized Projects"
|
|
524
|
+
|
|
525
|
+
local repos_needing_upgrade=()
|
|
526
|
+
local current_ver
|
|
527
|
+
current_ver=$(get_version)
|
|
528
|
+
|
|
529
|
+
while IFS= read -r repo_path; do
|
|
530
|
+
[[ -z "$repo_path" ]] && continue
|
|
531
|
+
|
|
532
|
+
if [[ -d "$repo_path" ]]; then
|
|
533
|
+
if check_repo_needs_upgrade "$repo_path"; then
|
|
534
|
+
repos_needing_upgrade+=("$repo_path")
|
|
535
|
+
fi
|
|
536
|
+
fi
|
|
537
|
+
done < <(get_registered_repos)
|
|
538
|
+
|
|
539
|
+
if [[ ${#repos_needing_upgrade[@]} -eq 0 ]]; then
|
|
540
|
+
print_success "All registered projects are up to date"
|
|
541
|
+
else
|
|
542
|
+
echo ""
|
|
543
|
+
print_warning "${#repos_needing_upgrade[@]} project(s) may need updates:"
|
|
544
|
+
for repo in "${repos_needing_upgrade[@]}"; do
|
|
545
|
+
local repo_name
|
|
546
|
+
repo_name=$(basename "$repo")
|
|
547
|
+
echo " - $repo_name ($repo)"
|
|
548
|
+
done
|
|
549
|
+
echo ""
|
|
550
|
+
read -r -p "Update .aidevops.json version in these projects? [y/N] " response
|
|
551
|
+
if [[ "$response" =~ ^[Yy]$ ]]; then
|
|
552
|
+
for repo in "${repos_needing_upgrade[@]}"; do
|
|
553
|
+
if [[ -f "$repo/.aidevops.json" ]]; then
|
|
554
|
+
print_info "Updating $repo..."
|
|
555
|
+
# Update version in .aidevops.json
|
|
556
|
+
if command -v jq &>/dev/null; then
|
|
557
|
+
local temp_file="${repo}/.aidevops.json.tmp"
|
|
558
|
+
jq --arg version "$current_ver" '.version = $version' "$repo/.aidevops.json" > "$temp_file" && \
|
|
559
|
+
mv "$temp_file" "$repo/.aidevops.json"
|
|
560
|
+
|
|
561
|
+
# Update repos.json entry
|
|
562
|
+
local features
|
|
563
|
+
features=$(jq -r '[.features | to_entries[] | select(.value == true) | .key] | join(",")' "$repo/.aidevops.json" 2>/dev/null || echo "")
|
|
564
|
+
register_repo "$repo" "$current_ver" "$features"
|
|
565
|
+
|
|
566
|
+
print_success "Updated $(basename "$repo")"
|
|
567
|
+
else
|
|
568
|
+
print_warning "jq not installed - manual update needed for $repo"
|
|
569
|
+
fi
|
|
570
|
+
fi
|
|
571
|
+
done
|
|
572
|
+
fi
|
|
573
|
+
fi
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
# Uninstall command
|
|
577
|
+
cmd_uninstall() {
|
|
578
|
+
print_header "Uninstall AI DevOps Framework"
|
|
579
|
+
echo ""
|
|
580
|
+
|
|
581
|
+
print_warning "This will remove:"
|
|
582
|
+
echo " - $AGENTS_DIR (deployed agents)"
|
|
583
|
+
echo " - $INSTALL_DIR (repository)"
|
|
584
|
+
echo " - AI assistant configuration references"
|
|
585
|
+
echo " - Shell aliases (if added)"
|
|
586
|
+
echo ""
|
|
587
|
+
print_warning "This will NOT remove:"
|
|
588
|
+
echo " - Installed tools (Tabby, Zed, gh, glab, etc.)"
|
|
589
|
+
echo " - SSH keys"
|
|
590
|
+
echo " - Python/Node environments"
|
|
591
|
+
echo ""
|
|
592
|
+
|
|
593
|
+
read -r -p "Are you sure you want to uninstall? (yes/no): " confirm
|
|
594
|
+
|
|
595
|
+
if [[ "$confirm" != "yes" ]]; then
|
|
596
|
+
print_info "Uninstall cancelled"
|
|
597
|
+
return 0
|
|
598
|
+
fi
|
|
599
|
+
|
|
600
|
+
echo ""
|
|
601
|
+
|
|
602
|
+
# Remove agents directory
|
|
603
|
+
if check_dir "$AGENTS_DIR"; then
|
|
604
|
+
print_info "Removing $AGENTS_DIR..."
|
|
605
|
+
rm -rf "$AGENTS_DIR"
|
|
606
|
+
print_success "Removed agents directory"
|
|
607
|
+
fi
|
|
608
|
+
|
|
609
|
+
# Remove config backups
|
|
610
|
+
if check_dir "$HOME/.aidevops"; then
|
|
611
|
+
print_info "Removing $HOME/.aidevops..."
|
|
612
|
+
rm -rf "$HOME/.aidevops"
|
|
613
|
+
print_success "Removed aidevops config directory"
|
|
614
|
+
fi
|
|
615
|
+
|
|
616
|
+
# Remove AI assistant references
|
|
617
|
+
print_info "Removing AI assistant configuration references..."
|
|
618
|
+
|
|
619
|
+
local ai_agent_files=(
|
|
620
|
+
"$HOME/.config/opencode/agent/AGENTS.md"
|
|
621
|
+
"$HOME/.cursor/rules/AGENTS.md"
|
|
622
|
+
"$HOME/.claude/commands/AGENTS.md"
|
|
623
|
+
"$HOME/.continue/AGENTS.md"
|
|
624
|
+
"$HOME/.cody/AGENTS.md"
|
|
625
|
+
"$HOME/.opencode/AGENTS.md"
|
|
626
|
+
)
|
|
627
|
+
|
|
628
|
+
for file in "${ai_agent_files[@]}"; do
|
|
629
|
+
if check_file "$file"; then
|
|
630
|
+
# Check if it only contains our reference
|
|
631
|
+
if grep -q "Add ~/.aidevops/agents/AGENTS.md" "$file" 2>/dev/null; then
|
|
632
|
+
rm -f "$file"
|
|
633
|
+
print_success "Removed $file"
|
|
634
|
+
fi
|
|
635
|
+
fi
|
|
636
|
+
done
|
|
637
|
+
|
|
638
|
+
# Remove shell aliases
|
|
639
|
+
print_info "Removing shell aliases..."
|
|
640
|
+
for rc_file in "$HOME/.zshrc" "$HOME/.bashrc" "$HOME/.bash_profile"; do
|
|
641
|
+
if check_file "$rc_file"; then
|
|
642
|
+
if grep -q "# AI Assistant Server Access Framework" "$rc_file" 2>/dev/null; then
|
|
643
|
+
# Create backup
|
|
644
|
+
cp "$rc_file" "$rc_file.bak"
|
|
645
|
+
# Remove our alias block (from comment to empty line)
|
|
646
|
+
sed -i.tmp '/# AI Assistant Server Access Framework/,/^$/d' "$rc_file"
|
|
647
|
+
rm -f "$rc_file.tmp"
|
|
648
|
+
print_success "Removed aliases from $rc_file"
|
|
649
|
+
fi
|
|
650
|
+
fi
|
|
651
|
+
done
|
|
652
|
+
|
|
653
|
+
# Remove memory files
|
|
654
|
+
print_info "Removing AI memory files..."
|
|
655
|
+
local memory_files=(
|
|
656
|
+
"$HOME/CLAUDE.md"
|
|
657
|
+
"$HOME/GEMINI.md"
|
|
658
|
+
"$HOME/WINDSURF.md"
|
|
659
|
+
"$HOME/.qwen/QWEN.md"
|
|
660
|
+
"$HOME/.factory/DROID.md"
|
|
661
|
+
)
|
|
662
|
+
|
|
663
|
+
for file in "${memory_files[@]}"; do
|
|
664
|
+
if check_file "$file"; then
|
|
665
|
+
rm -f "$file"
|
|
666
|
+
print_success "Removed $file"
|
|
667
|
+
fi
|
|
668
|
+
done
|
|
669
|
+
|
|
670
|
+
# Remove repository (ask separately)
|
|
671
|
+
echo ""
|
|
672
|
+
read -r -p "Also remove the repository at $INSTALL_DIR? (yes/no): " remove_repo
|
|
673
|
+
|
|
674
|
+
if [[ "$remove_repo" == "yes" ]]; then
|
|
675
|
+
if check_dir "$INSTALL_DIR"; then
|
|
676
|
+
print_info "Removing $INSTALL_DIR..."
|
|
677
|
+
rm -rf "$INSTALL_DIR"
|
|
678
|
+
print_success "Removed repository"
|
|
679
|
+
fi
|
|
680
|
+
else
|
|
681
|
+
print_info "Keeping repository at $INSTALL_DIR"
|
|
682
|
+
fi
|
|
683
|
+
|
|
684
|
+
echo ""
|
|
685
|
+
print_success "Uninstall complete!"
|
|
686
|
+
print_info "To reinstall, run:"
|
|
687
|
+
echo " bash <(curl -fsSL https://raw.githubusercontent.com/marcusquinn/aidevops/main/setup.sh)"
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
# Init command - initialize aidevops in a project
|
|
691
|
+
cmd_init() {
|
|
692
|
+
local features="${1:-all}"
|
|
693
|
+
|
|
694
|
+
print_header "Initialize AI DevOps in Project"
|
|
695
|
+
echo ""
|
|
696
|
+
|
|
697
|
+
# Check if we're in a git repo
|
|
698
|
+
if ! git rev-parse --is-inside-work-tree &>/dev/null; then
|
|
699
|
+
print_error "Not in a git repository"
|
|
700
|
+
print_info "Run 'git init' first or navigate to a git repository"
|
|
701
|
+
return 1
|
|
702
|
+
fi
|
|
703
|
+
|
|
704
|
+
# Check for protected branch and offer worktree
|
|
705
|
+
if ! check_protected_branch "chore" "aidevops-init"; then
|
|
706
|
+
return 1
|
|
707
|
+
fi
|
|
708
|
+
|
|
709
|
+
local project_root
|
|
710
|
+
project_root=$(git rev-parse --show-toplevel)
|
|
711
|
+
print_info "Project root: $project_root"
|
|
712
|
+
echo ""
|
|
713
|
+
|
|
714
|
+
# Parse features
|
|
715
|
+
local enable_planning=false
|
|
716
|
+
local enable_git_workflow=false
|
|
717
|
+
local enable_code_quality=false
|
|
718
|
+
local enable_time_tracking=false
|
|
719
|
+
local enable_database=false
|
|
720
|
+
local enable_beads=false
|
|
721
|
+
|
|
722
|
+
case "$features" in
|
|
723
|
+
all)
|
|
724
|
+
enable_planning=true
|
|
725
|
+
enable_git_workflow=true
|
|
726
|
+
enable_code_quality=true
|
|
727
|
+
enable_time_tracking=true
|
|
728
|
+
enable_database=true
|
|
729
|
+
enable_beads=true
|
|
730
|
+
;;
|
|
731
|
+
planning)
|
|
732
|
+
enable_planning=true
|
|
733
|
+
;;
|
|
734
|
+
git-workflow)
|
|
735
|
+
enable_git_workflow=true
|
|
736
|
+
;;
|
|
737
|
+
code-quality)
|
|
738
|
+
enable_code_quality=true
|
|
739
|
+
;;
|
|
740
|
+
time-tracking)
|
|
741
|
+
enable_time_tracking=true
|
|
742
|
+
enable_planning=true # time-tracking requires planning
|
|
743
|
+
;;
|
|
744
|
+
database)
|
|
745
|
+
enable_database=true
|
|
746
|
+
;;
|
|
747
|
+
beads)
|
|
748
|
+
enable_beads=true
|
|
749
|
+
enable_planning=true # beads requires planning
|
|
750
|
+
;;
|
|
751
|
+
*)
|
|
752
|
+
# Comma-separated list
|
|
753
|
+
IFS=',' read -ra FEATURE_LIST <<< "$features"
|
|
754
|
+
for feature in "${FEATURE_LIST[@]}"; do
|
|
755
|
+
case "$feature" in
|
|
756
|
+
planning) enable_planning=true ;;
|
|
757
|
+
git-workflow) enable_git_workflow=true ;;
|
|
758
|
+
code-quality) enable_code_quality=true ;;
|
|
759
|
+
time-tracking)
|
|
760
|
+
enable_time_tracking=true
|
|
761
|
+
enable_planning=true
|
|
762
|
+
;;
|
|
763
|
+
database) enable_database=true ;;
|
|
764
|
+
beads)
|
|
765
|
+
enable_beads=true
|
|
766
|
+
enable_planning=true
|
|
767
|
+
;;
|
|
768
|
+
esac
|
|
769
|
+
done
|
|
770
|
+
;;
|
|
771
|
+
esac
|
|
772
|
+
|
|
773
|
+
# Create .aidevops.json config
|
|
774
|
+
local config_file="$project_root/.aidevops.json"
|
|
775
|
+
local aidevops_version
|
|
776
|
+
aidevops_version=$(get_version)
|
|
777
|
+
|
|
778
|
+
print_info "Creating .aidevops.json..."
|
|
779
|
+
cat > "$config_file" << EOF
|
|
780
|
+
{
|
|
781
|
+
"version": "$aidevops_version",
|
|
782
|
+
"initialized": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
|
783
|
+
"features": {
|
|
784
|
+
"planning": $enable_planning,
|
|
785
|
+
"git_workflow": $enable_git_workflow,
|
|
786
|
+
"code_quality": $enable_code_quality,
|
|
787
|
+
"time_tracking": $enable_time_tracking,
|
|
788
|
+
"database": $enable_database,
|
|
789
|
+
"beads": $enable_beads
|
|
790
|
+
},
|
|
791
|
+
"time_tracking": {
|
|
792
|
+
"enabled": $enable_time_tracking,
|
|
793
|
+
"prompt_on_commit": true,
|
|
794
|
+
"auto_record_branch_start": true
|
|
795
|
+
},
|
|
796
|
+
"database": {
|
|
797
|
+
"enabled": $enable_database,
|
|
798
|
+
"schema_path": "schemas",
|
|
799
|
+
"migrations_path": "migrations",
|
|
800
|
+
"seeds_path": "seeds",
|
|
801
|
+
"auto_generate_migration": true
|
|
802
|
+
},
|
|
803
|
+
"beads": {
|
|
804
|
+
"enabled": $enable_beads,
|
|
805
|
+
"sync_on_commit": false,
|
|
806
|
+
"auto_ready_check": true
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
EOF
|
|
810
|
+
print_success "Created .aidevops.json"
|
|
811
|
+
|
|
812
|
+
# Create .agent symlink
|
|
813
|
+
if [[ ! -e "$project_root/.agent" ]]; then
|
|
814
|
+
print_info "Creating .agent symlink..."
|
|
815
|
+
ln -s "$AGENTS_DIR" "$project_root/.agent"
|
|
816
|
+
print_success "Created .agent -> $AGENTS_DIR"
|
|
817
|
+
else
|
|
818
|
+
print_warning ".agent already exists, skipping symlink"
|
|
819
|
+
fi
|
|
820
|
+
|
|
821
|
+
# Create planning files if enabled
|
|
822
|
+
if [[ "$enable_planning" == "true" ]]; then
|
|
823
|
+
print_info "Setting up planning files..."
|
|
824
|
+
|
|
825
|
+
# Create TODO.md from template
|
|
826
|
+
if [[ ! -f "$project_root/TODO.md" ]]; then
|
|
827
|
+
if [[ -f "$AGENTS_DIR/templates/todo-template.md" ]]; then
|
|
828
|
+
cp "$AGENTS_DIR/templates/todo-template.md" "$project_root/TODO.md"
|
|
829
|
+
print_success "Created TODO.md"
|
|
830
|
+
else
|
|
831
|
+
# Fallback minimal template
|
|
832
|
+
cat > "$project_root/TODO.md" << 'EOF'
|
|
833
|
+
# TODO
|
|
834
|
+
|
|
835
|
+
## In Progress
|
|
836
|
+
|
|
837
|
+
<!-- Tasks currently being worked on -->
|
|
838
|
+
|
|
839
|
+
## Backlog
|
|
840
|
+
|
|
841
|
+
<!-- Prioritized list of upcoming tasks -->
|
|
842
|
+
|
|
843
|
+
---
|
|
844
|
+
|
|
845
|
+
*Format: `- [ ] Task description @owner #tag ~estimate`*
|
|
846
|
+
*Time tracking: `started:`, `completed:`, `actual:`*
|
|
847
|
+
EOF
|
|
848
|
+
print_success "Created TODO.md (minimal template)"
|
|
849
|
+
fi
|
|
850
|
+
else
|
|
851
|
+
print_warning "TODO.md already exists, skipping"
|
|
852
|
+
fi
|
|
853
|
+
|
|
854
|
+
# Create todo/ directory and PLANS.md
|
|
855
|
+
mkdir -p "$project_root/todo/tasks"
|
|
856
|
+
|
|
857
|
+
if [[ ! -f "$project_root/todo/PLANS.md" ]]; then
|
|
858
|
+
if [[ -f "$AGENTS_DIR/templates/plans-template.md" ]]; then
|
|
859
|
+
cp "$AGENTS_DIR/templates/plans-template.md" "$project_root/todo/PLANS.md"
|
|
860
|
+
print_success "Created todo/PLANS.md"
|
|
861
|
+
else
|
|
862
|
+
# Fallback minimal template
|
|
863
|
+
cat > "$project_root/todo/PLANS.md" << 'EOF'
|
|
864
|
+
# Execution Plans
|
|
865
|
+
|
|
866
|
+
Complex, multi-session work that requires detailed planning.
|
|
867
|
+
|
|
868
|
+
## Active Plans
|
|
869
|
+
|
|
870
|
+
<!-- Plans currently in progress -->
|
|
871
|
+
|
|
872
|
+
## Completed Plans
|
|
873
|
+
|
|
874
|
+
<!-- Archived completed plans -->
|
|
875
|
+
|
|
876
|
+
---
|
|
877
|
+
|
|
878
|
+
*See `.agent/workflows/plans.md` for planning workflow*
|
|
879
|
+
EOF
|
|
880
|
+
print_success "Created todo/PLANS.md (minimal template)"
|
|
881
|
+
fi
|
|
882
|
+
else
|
|
883
|
+
print_warning "todo/PLANS.md already exists, skipping"
|
|
884
|
+
fi
|
|
885
|
+
|
|
886
|
+
# Create .gitkeep in tasks
|
|
887
|
+
touch "$project_root/todo/tasks/.gitkeep"
|
|
888
|
+
fi
|
|
889
|
+
|
|
890
|
+
# Create database directories if enabled
|
|
891
|
+
if [[ "$enable_database" == "true" ]]; then
|
|
892
|
+
print_info "Setting up database schema directories..."
|
|
893
|
+
|
|
894
|
+
# Create schemas directory with AGENTS.md
|
|
895
|
+
if [[ ! -d "$project_root/schemas" ]]; then
|
|
896
|
+
mkdir -p "$project_root/schemas"
|
|
897
|
+
cat > "$project_root/schemas/AGENTS.md" << 'EOF'
|
|
898
|
+
# Database Schemas
|
|
899
|
+
|
|
900
|
+
Declarative schema files - source of truth for database structure.
|
|
901
|
+
|
|
902
|
+
See: `@sql-migrations` or `.agent/workflows/sql-migrations.md`
|
|
903
|
+
EOF
|
|
904
|
+
print_success "Created schemas/ directory"
|
|
905
|
+
else
|
|
906
|
+
print_warning "schemas/ already exists, skipping"
|
|
907
|
+
fi
|
|
908
|
+
|
|
909
|
+
# Create migrations directory with AGENTS.md
|
|
910
|
+
if [[ ! -d "$project_root/migrations" ]]; then
|
|
911
|
+
mkdir -p "$project_root/migrations"
|
|
912
|
+
cat > "$project_root/migrations/AGENTS.md" << 'EOF'
|
|
913
|
+
# Database Migrations
|
|
914
|
+
|
|
915
|
+
Auto-generated versioned migration files. Do not edit manually.
|
|
916
|
+
|
|
917
|
+
See: `@sql-migrations` or `.agent/workflows/sql-migrations.md`
|
|
918
|
+
EOF
|
|
919
|
+
print_success "Created migrations/ directory"
|
|
920
|
+
else
|
|
921
|
+
print_warning "migrations/ already exists, skipping"
|
|
922
|
+
fi
|
|
923
|
+
|
|
924
|
+
# Create seeds directory with AGENTS.md
|
|
925
|
+
if [[ ! -d "$project_root/seeds" ]]; then
|
|
926
|
+
mkdir -p "$project_root/seeds"
|
|
927
|
+
cat > "$project_root/seeds/AGENTS.md" << 'EOF'
|
|
928
|
+
# Database Seeds
|
|
929
|
+
|
|
930
|
+
Initial and reference data (roles, statuses, test accounts).
|
|
931
|
+
|
|
932
|
+
See: `@sql-migrations` or `.agent/workflows/sql-migrations.md`
|
|
933
|
+
EOF
|
|
934
|
+
print_success "Created seeds/ directory"
|
|
935
|
+
else
|
|
936
|
+
print_warning "seeds/ already exists, skipping"
|
|
937
|
+
fi
|
|
938
|
+
fi
|
|
939
|
+
|
|
940
|
+
# Initialize Beads if enabled
|
|
941
|
+
if [[ "$enable_beads" == "true" ]]; then
|
|
942
|
+
print_info "Setting up Beads task graph..."
|
|
943
|
+
|
|
944
|
+
# Check if Beads CLI is installed
|
|
945
|
+
if ! command -v bd &> /dev/null; then
|
|
946
|
+
print_warning "Beads CLI (bd) not installed"
|
|
947
|
+
echo " Install with: brew install steveyegge/beads/bd"
|
|
948
|
+
echo " Or: go install github.com/steveyegge/beads/cmd/bd@latest"
|
|
949
|
+
else
|
|
950
|
+
# Initialize Beads in the project
|
|
951
|
+
if [[ ! -d "$project_root/.beads" ]]; then
|
|
952
|
+
print_info "Initializing Beads database..."
|
|
953
|
+
if (cd "$project_root" && bd init 2>/dev/null); then
|
|
954
|
+
print_success "Beads initialized"
|
|
955
|
+
else
|
|
956
|
+
print_warning "Beads init failed - run manually: bd init"
|
|
957
|
+
fi
|
|
958
|
+
else
|
|
959
|
+
print_info "Beads already initialized"
|
|
960
|
+
fi
|
|
961
|
+
|
|
962
|
+
# Run initial sync from TODO.md/PLANS.md
|
|
963
|
+
if [[ -f "$AGENTS_DIR/scripts/beads-sync-helper.sh" ]]; then
|
|
964
|
+
print_info "Syncing tasks to Beads..."
|
|
965
|
+
if bash "$AGENTS_DIR/scripts/beads-sync-helper.sh" push "$project_root" 2>/dev/null; then
|
|
966
|
+
print_success "Tasks synced to Beads"
|
|
967
|
+
else
|
|
968
|
+
print_warning "Beads sync failed - run manually: beads-sync-helper.sh push"
|
|
969
|
+
fi
|
|
970
|
+
fi
|
|
971
|
+
fi
|
|
972
|
+
fi
|
|
973
|
+
|
|
974
|
+
# Add to .gitignore if needed
|
|
975
|
+
local gitignore="$project_root/.gitignore"
|
|
976
|
+
if [[ -f "$gitignore" ]]; then
|
|
977
|
+
if ! grep -q "^\.agent$" "$gitignore" 2>/dev/null; then
|
|
978
|
+
{
|
|
979
|
+
echo ""
|
|
980
|
+
echo "# aidevops"
|
|
981
|
+
echo ".agent"
|
|
982
|
+
} >> "$gitignore"
|
|
983
|
+
print_success "Added .agent to .gitignore"
|
|
984
|
+
fi
|
|
985
|
+
# Add .beads if beads is enabled
|
|
986
|
+
if [[ "$enable_beads" == "true" ]]; then
|
|
987
|
+
if ! grep -q "^\.beads$" "$gitignore" 2>/dev/null; then
|
|
988
|
+
echo ".beads" >> "$gitignore"
|
|
989
|
+
print_success "Added .beads to .gitignore"
|
|
990
|
+
fi
|
|
991
|
+
fi
|
|
992
|
+
fi
|
|
993
|
+
|
|
994
|
+
# Build features string for registration
|
|
995
|
+
local features_list=""
|
|
996
|
+
[[ "$enable_planning" == "true" ]] && features_list="${features_list}planning,"
|
|
997
|
+
[[ "$enable_git_workflow" == "true" ]] && features_list="${features_list}git-workflow,"
|
|
998
|
+
[[ "$enable_code_quality" == "true" ]] && features_list="${features_list}code-quality,"
|
|
999
|
+
[[ "$enable_time_tracking" == "true" ]] && features_list="${features_list}time-tracking,"
|
|
1000
|
+
[[ "$enable_database" == "true" ]] && features_list="${features_list}database,"
|
|
1001
|
+
[[ "$enable_beads" == "true" ]] && features_list="${features_list}beads,"
|
|
1002
|
+
features_list="${features_list%,}" # Remove trailing comma
|
|
1003
|
+
|
|
1004
|
+
# Register repo in repos.json
|
|
1005
|
+
register_repo "$project_root" "$aidevops_version" "$features_list"
|
|
1006
|
+
|
|
1007
|
+
echo ""
|
|
1008
|
+
print_success "AI DevOps initialized!"
|
|
1009
|
+
echo ""
|
|
1010
|
+
echo "Enabled features:"
|
|
1011
|
+
[[ "$enable_planning" == "true" ]] && echo " ✓ Planning (TODO.md, PLANS.md)"
|
|
1012
|
+
[[ "$enable_git_workflow" == "true" ]] && echo " ✓ Git workflow (branch management)"
|
|
1013
|
+
[[ "$enable_code_quality" == "true" ]] && echo " ✓ Code quality (linting, auditing)"
|
|
1014
|
+
[[ "$enable_time_tracking" == "true" ]] && echo " ✓ Time tracking (estimates, actuals)"
|
|
1015
|
+
[[ "$enable_database" == "true" ]] && echo " ✓ Database (schemas/, migrations/, seeds/)"
|
|
1016
|
+
[[ "$enable_beads" == "true" ]] && echo " ✓ Beads (task graph visualization)"
|
|
1017
|
+
echo ""
|
|
1018
|
+
echo "Next steps:"
|
|
1019
|
+
if [[ "$enable_beads" == "true" ]]; then
|
|
1020
|
+
echo " 1. Add tasks to TODO.md with dependencies (blocked-by:t001)"
|
|
1021
|
+
echo " 2. Run /ready to see unblocked tasks"
|
|
1022
|
+
echo " 3. Run /sync-beads to sync with Beads graph"
|
|
1023
|
+
echo " 4. Use 'bd' CLI for graph visualization"
|
|
1024
|
+
elif [[ "$enable_database" == "true" ]]; then
|
|
1025
|
+
echo " 1. Add schema files to schemas/"
|
|
1026
|
+
echo " 2. Run diff to generate migrations"
|
|
1027
|
+
echo " 3. See .agent/workflows/sql-migrations.md"
|
|
1028
|
+
else
|
|
1029
|
+
echo " 1. Add tasks to TODO.md"
|
|
1030
|
+
echo " 2. Use /create-prd for complex features"
|
|
1031
|
+
echo " 3. Use /feature to start development"
|
|
1032
|
+
fi
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
# Upgrade planning command - upgrade TODO.md and PLANS.md to latest templates
|
|
1036
|
+
cmd_upgrade_planning() {
|
|
1037
|
+
local force=false
|
|
1038
|
+
local backup=true
|
|
1039
|
+
local dry_run=false
|
|
1040
|
+
|
|
1041
|
+
# Parse arguments
|
|
1042
|
+
while [[ $# -gt 0 ]]; do
|
|
1043
|
+
case "$1" in
|
|
1044
|
+
--force|-f) force=true; shift ;;
|
|
1045
|
+
--no-backup) backup=false; shift ;;
|
|
1046
|
+
--dry-run|-n) dry_run=true; shift ;;
|
|
1047
|
+
*) shift ;;
|
|
1048
|
+
esac
|
|
1049
|
+
done
|
|
1050
|
+
|
|
1051
|
+
print_header "Upgrade Planning Files"
|
|
1052
|
+
echo ""
|
|
1053
|
+
|
|
1054
|
+
# Check if in a git repo
|
|
1055
|
+
if ! git rev-parse --is-inside-work-tree &>/dev/null; then
|
|
1056
|
+
print_error "Not in a git repository"
|
|
1057
|
+
return 1
|
|
1058
|
+
fi
|
|
1059
|
+
|
|
1060
|
+
# Check for protected branch and offer worktree (skip for dry-run)
|
|
1061
|
+
if [[ "$dry_run" != "true" ]]; then
|
|
1062
|
+
if ! check_protected_branch "chore" "upgrade-planning"; then
|
|
1063
|
+
return 1
|
|
1064
|
+
fi
|
|
1065
|
+
fi
|
|
1066
|
+
|
|
1067
|
+
local project_root
|
|
1068
|
+
project_root=$(git rev-parse --show-toplevel)
|
|
1069
|
+
|
|
1070
|
+
# Check if aidevops is initialized
|
|
1071
|
+
if [[ ! -f "$project_root/.aidevops.json" ]]; then
|
|
1072
|
+
print_error "aidevops not initialized in this project"
|
|
1073
|
+
print_info "Run 'aidevops init' first"
|
|
1074
|
+
return 1
|
|
1075
|
+
fi
|
|
1076
|
+
|
|
1077
|
+
# Check if planning is enabled (use jq if available, fallback to grep)
|
|
1078
|
+
if command -v jq &>/dev/null; then
|
|
1079
|
+
if ! jq -e '.features.planning == true' "$project_root/.aidevops.json" &>/dev/null; then
|
|
1080
|
+
print_error "Planning feature not enabled"
|
|
1081
|
+
print_info "Run 'aidevops init planning' to enable"
|
|
1082
|
+
return 1
|
|
1083
|
+
fi
|
|
1084
|
+
else
|
|
1085
|
+
local planning_enabled
|
|
1086
|
+
planning_enabled=$(grep -o '"planning": *true' "$project_root/.aidevops.json" 2>/dev/null || echo "")
|
|
1087
|
+
if [[ -z "$planning_enabled" ]]; then
|
|
1088
|
+
print_error "Planning feature not enabled"
|
|
1089
|
+
print_info "Run 'aidevops init planning' to enable"
|
|
1090
|
+
return 1
|
|
1091
|
+
fi
|
|
1092
|
+
fi
|
|
1093
|
+
|
|
1094
|
+
local todo_file="$project_root/TODO.md"
|
|
1095
|
+
local plans_file="$project_root/todo/PLANS.md"
|
|
1096
|
+
local todo_template="$AGENTS_DIR/templates/todo-template.md"
|
|
1097
|
+
local plans_template="$AGENTS_DIR/templates/plans-template.md"
|
|
1098
|
+
|
|
1099
|
+
# Check templates exist
|
|
1100
|
+
if [[ ! -f "$todo_template" ]]; then
|
|
1101
|
+
print_error "TODO template not found: $todo_template"
|
|
1102
|
+
return 1
|
|
1103
|
+
fi
|
|
1104
|
+
if [[ ! -f "$plans_template" ]]; then
|
|
1105
|
+
print_error "PLANS template not found: $plans_template"
|
|
1106
|
+
return 1
|
|
1107
|
+
fi
|
|
1108
|
+
|
|
1109
|
+
local needs_upgrade=false
|
|
1110
|
+
local todo_needs_upgrade=false
|
|
1111
|
+
local plans_needs_upgrade=false
|
|
1112
|
+
|
|
1113
|
+
# Check TODO.md
|
|
1114
|
+
if [[ -f "$todo_file" ]]; then
|
|
1115
|
+
# Check if it's using the minimal template (no TOON markers)
|
|
1116
|
+
if ! grep -q "TOON:meta" "$todo_file" 2>/dev/null; then
|
|
1117
|
+
todo_needs_upgrade=true
|
|
1118
|
+
needs_upgrade=true
|
|
1119
|
+
print_warning "TODO.md uses minimal template (missing TOON markers)"
|
|
1120
|
+
else
|
|
1121
|
+
print_success "TODO.md already has TOON markers"
|
|
1122
|
+
fi
|
|
1123
|
+
else
|
|
1124
|
+
print_info "TODO.md not found - will create from template"
|
|
1125
|
+
todo_needs_upgrade=true
|
|
1126
|
+
needs_upgrade=true
|
|
1127
|
+
fi
|
|
1128
|
+
|
|
1129
|
+
# Check PLANS.md
|
|
1130
|
+
if [[ -f "$plans_file" ]]; then
|
|
1131
|
+
# Check if it's using the minimal template (no TOON markers)
|
|
1132
|
+
if ! grep -q "TOON:meta" "$plans_file" 2>/dev/null; then
|
|
1133
|
+
plans_needs_upgrade=true
|
|
1134
|
+
needs_upgrade=true
|
|
1135
|
+
print_warning "todo/PLANS.md uses minimal template (missing TOON markers)"
|
|
1136
|
+
else
|
|
1137
|
+
print_success "todo/PLANS.md already has TOON markers"
|
|
1138
|
+
fi
|
|
1139
|
+
else
|
|
1140
|
+
print_info "todo/PLANS.md not found - will create from template"
|
|
1141
|
+
plans_needs_upgrade=true
|
|
1142
|
+
needs_upgrade=true
|
|
1143
|
+
fi
|
|
1144
|
+
|
|
1145
|
+
if [[ "$needs_upgrade" == "false" ]]; then
|
|
1146
|
+
echo ""
|
|
1147
|
+
print_success "Planning files are up to date!"
|
|
1148
|
+
return 0
|
|
1149
|
+
fi
|
|
1150
|
+
|
|
1151
|
+
echo ""
|
|
1152
|
+
|
|
1153
|
+
if [[ "$dry_run" == "true" ]]; then
|
|
1154
|
+
print_info "Dry run - no changes will be made"
|
|
1155
|
+
echo ""
|
|
1156
|
+
[[ "$todo_needs_upgrade" == "true" ]] && echo " Would upgrade: TODO.md"
|
|
1157
|
+
[[ "$plans_needs_upgrade" == "true" ]] && echo " Would upgrade: todo/PLANS.md"
|
|
1158
|
+
return 0
|
|
1159
|
+
fi
|
|
1160
|
+
|
|
1161
|
+
# Confirm upgrade unless forced
|
|
1162
|
+
if [[ "$force" == "false" ]]; then
|
|
1163
|
+
echo "Files to upgrade:"
|
|
1164
|
+
[[ "$todo_needs_upgrade" == "true" ]] && echo " - TODO.md"
|
|
1165
|
+
[[ "$plans_needs_upgrade" == "true" ]] && echo " - todo/PLANS.md"
|
|
1166
|
+
echo ""
|
|
1167
|
+
echo "This will:"
|
|
1168
|
+
echo " 1. Extract existing tasks from current files"
|
|
1169
|
+
echo " 2. Create backups (.bak files)"
|
|
1170
|
+
echo " 3. Apply new TOON-enhanced templates"
|
|
1171
|
+
echo " 4. Merge existing tasks into new structure"
|
|
1172
|
+
echo ""
|
|
1173
|
+
read -r -p "Continue? [y/N] " response
|
|
1174
|
+
if [[ ! "$response" =~ ^[Yy]$ ]]; then
|
|
1175
|
+
print_info "Upgrade cancelled"
|
|
1176
|
+
return 0
|
|
1177
|
+
fi
|
|
1178
|
+
fi
|
|
1179
|
+
|
|
1180
|
+
echo ""
|
|
1181
|
+
|
|
1182
|
+
# Upgrade TODO.md
|
|
1183
|
+
if [[ "$todo_needs_upgrade" == "true" ]]; then
|
|
1184
|
+
print_info "Upgrading TODO.md..."
|
|
1185
|
+
|
|
1186
|
+
# Extract existing tasks if file exists
|
|
1187
|
+
local existing_tasks=""
|
|
1188
|
+
if [[ -f "$todo_file" ]]; then
|
|
1189
|
+
# Extract task lines (lines starting with - [ ] or - [x] or - [-])
|
|
1190
|
+
existing_tasks=$(grep -E "^[[:space:]]*- \[([ x-])\]" "$todo_file" 2>/dev/null || echo "")
|
|
1191
|
+
|
|
1192
|
+
# Create backup
|
|
1193
|
+
if [[ "$backup" == "true" ]]; then
|
|
1194
|
+
cp "$todo_file" "${todo_file}.bak"
|
|
1195
|
+
print_success "Backup created: TODO.md.bak"
|
|
1196
|
+
fi
|
|
1197
|
+
fi
|
|
1198
|
+
|
|
1199
|
+
# Copy template (strip YAML frontmatter - lines between first two ---)
|
|
1200
|
+
# Use temp file to avoid race condition on failure
|
|
1201
|
+
local temp_todo="${todo_file}.new"
|
|
1202
|
+
if awk '/^---$/ && !p {c++; if(c==2) p=1; next} p' "$todo_template" > "$temp_todo" 2>/dev/null && [[ -s "$temp_todo" ]]; then
|
|
1203
|
+
mv "$temp_todo" "$todo_file"
|
|
1204
|
+
else
|
|
1205
|
+
rm -f "$temp_todo"
|
|
1206
|
+
cp "$todo_template" "$todo_file"
|
|
1207
|
+
fi
|
|
1208
|
+
|
|
1209
|
+
# Update date placeholder
|
|
1210
|
+
sed -i.tmp "s/{{DATE}}/$(date +%Y-%m-%d)/" "$todo_file" 2>/dev/null || true
|
|
1211
|
+
rm -f "${todo_file}.tmp"
|
|
1212
|
+
|
|
1213
|
+
# Merge existing tasks into Backlog section (after the TOON block closing tag)
|
|
1214
|
+
if [[ -n "$existing_tasks" ]]; then
|
|
1215
|
+
# Find the Backlog TOON block and insert tasks after its closing -->
|
|
1216
|
+
if grep -q "<!--TOON:backlog" "$todo_file"; then
|
|
1217
|
+
local temp_file="${todo_file}.merge"
|
|
1218
|
+
awk -v tasks="$existing_tasks" '
|
|
1219
|
+
/<!--TOON:backlog/ { in_backlog=1 }
|
|
1220
|
+
in_backlog && /^-->$/ { print; print ""; print tasks; in_backlog=0; next }
|
|
1221
|
+
{ print }
|
|
1222
|
+
' "$todo_file" > "$temp_file"
|
|
1223
|
+
mv "$temp_file" "$todo_file"
|
|
1224
|
+
print_success "Merged existing tasks into Backlog"
|
|
1225
|
+
fi
|
|
1226
|
+
fi
|
|
1227
|
+
|
|
1228
|
+
print_success "TODO.md upgraded to TOON-enhanced template"
|
|
1229
|
+
fi
|
|
1230
|
+
|
|
1231
|
+
# Upgrade PLANS.md
|
|
1232
|
+
if [[ "$plans_needs_upgrade" == "true" ]]; then
|
|
1233
|
+
print_info "Upgrading todo/PLANS.md..."
|
|
1234
|
+
|
|
1235
|
+
# Ensure directory exists
|
|
1236
|
+
mkdir -p "$project_root/todo/tasks"
|
|
1237
|
+
|
|
1238
|
+
# Extract existing plans if file exists
|
|
1239
|
+
local existing_plans=""
|
|
1240
|
+
if [[ -f "$plans_file" ]]; then
|
|
1241
|
+
# Extract plan sections (### headers and their content)
|
|
1242
|
+
existing_plans=$(awk '/^### /{found=1} found{print}' "$plans_file" 2>/dev/null || echo "")
|
|
1243
|
+
|
|
1244
|
+
# Create backup
|
|
1245
|
+
if [[ "$backup" == "true" ]]; then
|
|
1246
|
+
cp "$plans_file" "${plans_file}.bak"
|
|
1247
|
+
print_success "Backup created: todo/PLANS.md.bak"
|
|
1248
|
+
fi
|
|
1249
|
+
fi
|
|
1250
|
+
|
|
1251
|
+
# Copy template (strip YAML frontmatter - lines between first two ---)
|
|
1252
|
+
# Use temp file to avoid race condition on failure
|
|
1253
|
+
local temp_plans="${plans_file}.new"
|
|
1254
|
+
if awk '/^---$/ && !p {c++; if(c==2) p=1; next} p' "$plans_template" > "$temp_plans" 2>/dev/null && [[ -s "$temp_plans" ]]; then
|
|
1255
|
+
mv "$temp_plans" "$plans_file"
|
|
1256
|
+
else
|
|
1257
|
+
rm -f "$temp_plans"
|
|
1258
|
+
cp "$plans_template" "$plans_file"
|
|
1259
|
+
fi
|
|
1260
|
+
|
|
1261
|
+
# Update date placeholder
|
|
1262
|
+
sed -i.tmp "s/{{DATE}}/$(date +%Y-%m-%d)/" "$plans_file" 2>/dev/null || true
|
|
1263
|
+
rm -f "${plans_file}.tmp"
|
|
1264
|
+
|
|
1265
|
+
# Merge existing plans into Active Plans section (after the TOON block closing tag)
|
|
1266
|
+
if [[ -n "$existing_plans" ]]; then
|
|
1267
|
+
if grep -q "<!--TOON:active_plans" "$plans_file"; then
|
|
1268
|
+
local temp_file="${plans_file}.merge"
|
|
1269
|
+
awk -v plans="$existing_plans" '
|
|
1270
|
+
/<!--TOON:active_plans/ { in_active=1 }
|
|
1271
|
+
in_active && /^-->$/ { print; print ""; print plans; in_active=0; next }
|
|
1272
|
+
{ print }
|
|
1273
|
+
' "$plans_file" > "$temp_file"
|
|
1274
|
+
mv "$temp_file" "$plans_file"
|
|
1275
|
+
print_success "Merged existing plans into Active Plans"
|
|
1276
|
+
fi
|
|
1277
|
+
fi
|
|
1278
|
+
|
|
1279
|
+
print_success "todo/PLANS.md upgraded to TOON-enhanced template"
|
|
1280
|
+
fi
|
|
1281
|
+
|
|
1282
|
+
# Update .aidevops.json with template version
|
|
1283
|
+
local config_file="$project_root/.aidevops.json"
|
|
1284
|
+
local aidevops_version
|
|
1285
|
+
aidevops_version=$(get_version)
|
|
1286
|
+
|
|
1287
|
+
# Add/update templates_version in config (use jq if available)
|
|
1288
|
+
if command -v jq &>/dev/null; then
|
|
1289
|
+
local temp_json="${config_file}.tmp"
|
|
1290
|
+
jq --arg version "$aidevops_version" '.templates_version = $version' "$config_file" > "$temp_json" && \
|
|
1291
|
+
mv "$temp_json" "$config_file"
|
|
1292
|
+
else
|
|
1293
|
+
# Fallback using awk for portable newline handling (BSD sed doesn't support \n)
|
|
1294
|
+
if ! grep -q '"templates_version"' "$config_file" 2>/dev/null; then
|
|
1295
|
+
# Insert templates_version after version line
|
|
1296
|
+
local temp_json="${config_file}.tmp"
|
|
1297
|
+
awk -v ver="$aidevops_version" '
|
|
1298
|
+
/"version":/ {
|
|
1299
|
+
sub(/"version": "[^"]*"/, "\"version\": \"" ver "\",\n \"templates_version\": \"" ver "\"")
|
|
1300
|
+
}
|
|
1301
|
+
{ print }
|
|
1302
|
+
' "$config_file" > "$temp_json" && mv "$temp_json" "$config_file"
|
|
1303
|
+
else
|
|
1304
|
+
# Update existing templates_version
|
|
1305
|
+
sed -i.tmp "s/\"templates_version\": \"[^\"]*\"/\"templates_version\": \"$aidevops_version\"/" "$config_file" 2>/dev/null || true
|
|
1306
|
+
rm -f "${config_file}.tmp"
|
|
1307
|
+
fi
|
|
1308
|
+
fi
|
|
1309
|
+
|
|
1310
|
+
echo ""
|
|
1311
|
+
print_success "Planning files upgraded!"
|
|
1312
|
+
echo ""
|
|
1313
|
+
echo "Next steps:"
|
|
1314
|
+
echo " 1. Review the upgraded files"
|
|
1315
|
+
echo " 2. Verify your tasks were preserved"
|
|
1316
|
+
if [[ "$backup" == "true" ]]; then
|
|
1317
|
+
echo " 3. Remove .bak files when satisfied"
|
|
1318
|
+
echo ""
|
|
1319
|
+
echo "If issues occurred, restore from backups:"
|
|
1320
|
+
[[ "$todo_needs_upgrade" == "true" ]] && echo " mv TODO.md.bak TODO.md"
|
|
1321
|
+
[[ "$plans_needs_upgrade" == "true" ]] && echo " mv todo/PLANS.md.bak todo/PLANS.md"
|
|
1322
|
+
fi
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
# Features command - list available features
|
|
1326
|
+
cmd_features() {
|
|
1327
|
+
print_header "AI DevOps Features"
|
|
1328
|
+
echo ""
|
|
1329
|
+
|
|
1330
|
+
echo "Available features for 'aidevops init':"
|
|
1331
|
+
echo ""
|
|
1332
|
+
echo " planning TODO.md and PLANS.md task management"
|
|
1333
|
+
echo " - Quick task tracking in TODO.md"
|
|
1334
|
+
echo " - Complex execution plans in todo/PLANS.md"
|
|
1335
|
+
echo " - PRD and task file generation"
|
|
1336
|
+
echo ""
|
|
1337
|
+
echo " git-workflow Branch management and PR workflows"
|
|
1338
|
+
echo " - Automatic branch suggestions"
|
|
1339
|
+
echo " - Preflight quality checks"
|
|
1340
|
+
echo " - PR creation and review"
|
|
1341
|
+
echo ""
|
|
1342
|
+
echo " code-quality Linting and code auditing"
|
|
1343
|
+
echo " - ShellCheck, secretlint, pattern checks"
|
|
1344
|
+
echo " - Remote auditing (CodeRabbit, Codacy, SonarCloud)"
|
|
1345
|
+
echo " - Code standards compliance"
|
|
1346
|
+
echo ""
|
|
1347
|
+
echo " time-tracking Time estimation and tracking"
|
|
1348
|
+
echo " - Estimate format: ~4h (ai:2h test:1h)"
|
|
1349
|
+
echo " - Automatic started:/completed: timestamps"
|
|
1350
|
+
echo " - Release time summaries"
|
|
1351
|
+
echo ""
|
|
1352
|
+
echo " database Declarative database schema management"
|
|
1353
|
+
echo " - schemas/ for declarative SQL/TypeScript"
|
|
1354
|
+
echo " - migrations/ for versioned changes"
|
|
1355
|
+
echo " - seeds/ for initial/test data"
|
|
1356
|
+
echo " - Auto-generate migrations on schema diff"
|
|
1357
|
+
echo ""
|
|
1358
|
+
echo " beads Task graph visualization with Beads"
|
|
1359
|
+
echo " - Dependency tracking (blocked-by:, blocks:)"
|
|
1360
|
+
echo " - Graph visualization with bd CLI"
|
|
1361
|
+
echo " - Ready task detection (/ready)"
|
|
1362
|
+
echo " - Bi-directional sync with TODO.md/PLANS.md"
|
|
1363
|
+
echo ""
|
|
1364
|
+
echo "Usage:"
|
|
1365
|
+
echo " aidevops init # Enable all features"
|
|
1366
|
+
echo " aidevops init planning # Enable only planning"
|
|
1367
|
+
echo " aidevops init beads # Enable beads (includes planning)"
|
|
1368
|
+
echo " aidevops init database # Enable only database"
|
|
1369
|
+
echo " aidevops init planning,database # Enable multiple"
|
|
1370
|
+
echo ""
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
# Update tools command - check and update installed tools
|
|
1374
|
+
# Passes all arguments through to tool-version-check.sh
|
|
1375
|
+
cmd_update_tools() {
|
|
1376
|
+
print_header "Tool Version Check"
|
|
1377
|
+
echo ""
|
|
1378
|
+
|
|
1379
|
+
local tool_check_script="$AGENTS_DIR/scripts/tool-version-check.sh"
|
|
1380
|
+
|
|
1381
|
+
if [[ ! -f "$tool_check_script" ]]; then
|
|
1382
|
+
print_error "Tool version check script not found"
|
|
1383
|
+
print_info "Run 'aidevops update' first to get the latest scripts"
|
|
1384
|
+
return 1
|
|
1385
|
+
fi
|
|
1386
|
+
|
|
1387
|
+
# Pass all arguments through to the script
|
|
1388
|
+
bash "$tool_check_script" "$@"
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
# Repos command - list and manage registered repos
|
|
1392
|
+
cmd_repos() {
|
|
1393
|
+
local action="${1:-list}"
|
|
1394
|
+
|
|
1395
|
+
case "$action" in
|
|
1396
|
+
list|ls)
|
|
1397
|
+
print_header "Registered AI DevOps Projects"
|
|
1398
|
+
echo ""
|
|
1399
|
+
|
|
1400
|
+
init_repos_file
|
|
1401
|
+
|
|
1402
|
+
if ! command -v jq &>/dev/null; then
|
|
1403
|
+
print_error "jq required for repo management"
|
|
1404
|
+
return 1
|
|
1405
|
+
fi
|
|
1406
|
+
|
|
1407
|
+
local count
|
|
1408
|
+
count=$(jq '.initialized_repos | length' "$REPOS_FILE" 2>/dev/null || echo "0")
|
|
1409
|
+
|
|
1410
|
+
if [[ "$count" == "0" ]]; then
|
|
1411
|
+
print_info "No projects registered yet"
|
|
1412
|
+
echo ""
|
|
1413
|
+
echo "Initialize a project with: aidevops init"
|
|
1414
|
+
return 0
|
|
1415
|
+
fi
|
|
1416
|
+
|
|
1417
|
+
local current_ver
|
|
1418
|
+
current_ver=$(get_version)
|
|
1419
|
+
|
|
1420
|
+
jq -r '.initialized_repos[] | "\(.path)|\(.version)|\(.features | join(","))"' "$REPOS_FILE" 2>/dev/null | while IFS='|' read -r path version features; do
|
|
1421
|
+
local name
|
|
1422
|
+
name=$(basename "$path")
|
|
1423
|
+
local status="✓"
|
|
1424
|
+
local status_color="$GREEN"
|
|
1425
|
+
|
|
1426
|
+
if [[ "$version" != "$current_ver" ]]; then
|
|
1427
|
+
status="↑"
|
|
1428
|
+
status_color="$YELLOW"
|
|
1429
|
+
fi
|
|
1430
|
+
|
|
1431
|
+
if [[ ! -d "$path" ]]; then
|
|
1432
|
+
status="✗"
|
|
1433
|
+
status_color="$RED"
|
|
1434
|
+
fi
|
|
1435
|
+
|
|
1436
|
+
echo -e "${status_color}${status}${NC} ${BOLD}$name${NC}"
|
|
1437
|
+
echo " Path: $path"
|
|
1438
|
+
echo " Version: $version"
|
|
1439
|
+
echo " Features: $features"
|
|
1440
|
+
echo ""
|
|
1441
|
+
done
|
|
1442
|
+
|
|
1443
|
+
echo "Legend: ✓ up-to-date ↑ update available ✗ not found"
|
|
1444
|
+
;;
|
|
1445
|
+
|
|
1446
|
+
add)
|
|
1447
|
+
# Register current directory
|
|
1448
|
+
if ! git rev-parse --is-inside-work-tree &>/dev/null; then
|
|
1449
|
+
print_error "Not in a git repository"
|
|
1450
|
+
return 1
|
|
1451
|
+
fi
|
|
1452
|
+
|
|
1453
|
+
local project_root
|
|
1454
|
+
project_root=$(git rev-parse --show-toplevel)
|
|
1455
|
+
|
|
1456
|
+
if [[ ! -f "$project_root/.aidevops.json" ]]; then
|
|
1457
|
+
print_error "No .aidevops.json found - run 'aidevops init' first"
|
|
1458
|
+
return 1
|
|
1459
|
+
fi
|
|
1460
|
+
|
|
1461
|
+
local version features
|
|
1462
|
+
if command -v jq &>/dev/null; then
|
|
1463
|
+
version=$(jq -r '.version' "$project_root/.aidevops.json" 2>/dev/null || echo "unknown")
|
|
1464
|
+
features=$(jq -r '[.features | to_entries[] | select(.value == true) | .key] | join(",")' "$project_root/.aidevops.json" 2>/dev/null || echo "")
|
|
1465
|
+
else
|
|
1466
|
+
version="unknown"
|
|
1467
|
+
features=""
|
|
1468
|
+
fi
|
|
1469
|
+
|
|
1470
|
+
register_repo "$project_root" "$version" "$features"
|
|
1471
|
+
print_success "Registered $(basename "$project_root")"
|
|
1472
|
+
;;
|
|
1473
|
+
|
|
1474
|
+
remove|rm)
|
|
1475
|
+
local repo_path="${2:-}"
|
|
1476
|
+
|
|
1477
|
+
if [[ -z "$repo_path" ]]; then
|
|
1478
|
+
# Use current directory
|
|
1479
|
+
if git rev-parse --is-inside-work-tree &>/dev/null; then
|
|
1480
|
+
repo_path=$(git rev-parse --show-toplevel)
|
|
1481
|
+
else
|
|
1482
|
+
print_error "Specify a repo path or run from within a git repo"
|
|
1483
|
+
return 1
|
|
1484
|
+
fi
|
|
1485
|
+
fi
|
|
1486
|
+
|
|
1487
|
+
# Normalize path
|
|
1488
|
+
repo_path=$(cd "$repo_path" 2>/dev/null && pwd -P) || repo_path="$2"
|
|
1489
|
+
|
|
1490
|
+
if ! command -v jq &>/dev/null; then
|
|
1491
|
+
print_error "jq required for repo management"
|
|
1492
|
+
return 1
|
|
1493
|
+
fi
|
|
1494
|
+
|
|
1495
|
+
local temp_file="${REPOS_FILE}.tmp"
|
|
1496
|
+
jq --arg path "$repo_path" '.initialized_repos |= map(select(.path != $path))' "$REPOS_FILE" > "$temp_file" && \
|
|
1497
|
+
mv "$temp_file" "$REPOS_FILE"
|
|
1498
|
+
|
|
1499
|
+
print_success "Removed $repo_path from registry"
|
|
1500
|
+
;;
|
|
1501
|
+
|
|
1502
|
+
clean)
|
|
1503
|
+
# Remove entries for repos that no longer exist
|
|
1504
|
+
print_info "Cleaning up stale repo entries..."
|
|
1505
|
+
|
|
1506
|
+
if ! command -v jq &>/dev/null; then
|
|
1507
|
+
print_error "jq required for repo management"
|
|
1508
|
+
return 1
|
|
1509
|
+
fi
|
|
1510
|
+
|
|
1511
|
+
local removed=0
|
|
1512
|
+
local temp_file="${REPOS_FILE}.tmp"
|
|
1513
|
+
|
|
1514
|
+
# Filter out repos that don't exist
|
|
1515
|
+
jq '[.initialized_repos[] | select(.path as $p | ($p | type == "string") and ([$p] | .[0] | test("^/")))]' "$REPOS_FILE" > /dev/null 2>&1
|
|
1516
|
+
|
|
1517
|
+
while IFS= read -r repo_path; do
|
|
1518
|
+
[[ -z "$repo_path" ]] && continue
|
|
1519
|
+
if [[ ! -d "$repo_path" ]]; then
|
|
1520
|
+
jq --arg path "$repo_path" '.initialized_repos |= map(select(.path != $path))' "$REPOS_FILE" > "$temp_file" && \
|
|
1521
|
+
mv "$temp_file" "$REPOS_FILE"
|
|
1522
|
+
print_info "Removed: $repo_path"
|
|
1523
|
+
((removed++))
|
|
1524
|
+
fi
|
|
1525
|
+
done < <(get_registered_repos)
|
|
1526
|
+
|
|
1527
|
+
if [[ $removed -eq 0 ]]; then
|
|
1528
|
+
print_success "No stale entries found"
|
|
1529
|
+
else
|
|
1530
|
+
print_success "Removed $removed stale entries"
|
|
1531
|
+
fi
|
|
1532
|
+
;;
|
|
1533
|
+
|
|
1534
|
+
*)
|
|
1535
|
+
echo "Usage: aidevops repos <command>"
|
|
1536
|
+
echo ""
|
|
1537
|
+
echo "Commands:"
|
|
1538
|
+
echo " list List all registered projects (default)"
|
|
1539
|
+
echo " add Register current project"
|
|
1540
|
+
echo " remove Remove project from registry"
|
|
1541
|
+
echo " clean Remove entries for non-existent projects"
|
|
1542
|
+
;;
|
|
1543
|
+
esac
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
# Detect command - check for unregistered aidevops repos
|
|
1547
|
+
cmd_detect() {
|
|
1548
|
+
print_header "Detecting AI DevOps Projects"
|
|
1549
|
+
echo ""
|
|
1550
|
+
|
|
1551
|
+
# Check current directory first
|
|
1552
|
+
local unregistered
|
|
1553
|
+
unregistered=$(detect_unregistered_repo)
|
|
1554
|
+
|
|
1555
|
+
if [[ -n "$unregistered" ]]; then
|
|
1556
|
+
print_info "Found unregistered aidevops project:"
|
|
1557
|
+
echo " $unregistered"
|
|
1558
|
+
echo ""
|
|
1559
|
+
read -r -p "Register this project? [Y/n] " response
|
|
1560
|
+
response="${response:-y}"
|
|
1561
|
+
if [[ "$response" =~ ^[Yy]$ ]]; then
|
|
1562
|
+
local version features
|
|
1563
|
+
if command -v jq &>/dev/null; then
|
|
1564
|
+
version=$(jq -r '.version' "$unregistered/.aidevops.json" 2>/dev/null || echo "unknown")
|
|
1565
|
+
features=$(jq -r '[.features | to_entries[] | select(.value == true) | .key] | join(",")' "$unregistered/.aidevops.json" 2>/dev/null || echo "")
|
|
1566
|
+
else
|
|
1567
|
+
version="unknown"
|
|
1568
|
+
features=""
|
|
1569
|
+
fi
|
|
1570
|
+
register_repo "$unregistered" "$version" "$features"
|
|
1571
|
+
print_success "Registered $(basename "$unregistered")"
|
|
1572
|
+
fi
|
|
1573
|
+
return 0
|
|
1574
|
+
fi
|
|
1575
|
+
|
|
1576
|
+
# Scan common locations
|
|
1577
|
+
print_info "Scanning for aidevops projects in ~/Git/..."
|
|
1578
|
+
|
|
1579
|
+
local found=0
|
|
1580
|
+
local to_register=()
|
|
1581
|
+
|
|
1582
|
+
if [[ -d "$HOME/Git" ]]; then
|
|
1583
|
+
while IFS= read -r -d '' aidevops_json; do
|
|
1584
|
+
local repo_dir
|
|
1585
|
+
repo_dir=$(dirname "$aidevops_json")
|
|
1586
|
+
|
|
1587
|
+
# Check if already registered
|
|
1588
|
+
init_repos_file
|
|
1589
|
+
if command -v jq &>/dev/null; then
|
|
1590
|
+
if ! jq -e --arg path "$repo_dir" '.initialized_repos[] | select(.path == $path)' "$REPOS_FILE" &>/dev/null; then
|
|
1591
|
+
to_register+=("$repo_dir")
|
|
1592
|
+
((found++))
|
|
1593
|
+
fi
|
|
1594
|
+
fi
|
|
1595
|
+
done < <(find "$HOME/Git" -maxdepth 3 -name ".aidevops.json" -print0 2>/dev/null)
|
|
1596
|
+
fi
|
|
1597
|
+
|
|
1598
|
+
if [[ $found -eq 0 ]]; then
|
|
1599
|
+
print_success "No unregistered aidevops projects found"
|
|
1600
|
+
return 0
|
|
1601
|
+
fi
|
|
1602
|
+
|
|
1603
|
+
echo ""
|
|
1604
|
+
print_info "Found $found unregistered project(s):"
|
|
1605
|
+
for repo in "${to_register[@]}"; do
|
|
1606
|
+
echo " - $(basename "$repo") ($repo)"
|
|
1607
|
+
done
|
|
1608
|
+
|
|
1609
|
+
echo ""
|
|
1610
|
+
read -r -p "Register all? [Y/n] " response
|
|
1611
|
+
response="${response:-y}"
|
|
1612
|
+
if [[ "$response" =~ ^[Yy]$ ]]; then
|
|
1613
|
+
for repo in "${to_register[@]}"; do
|
|
1614
|
+
local version features
|
|
1615
|
+
if command -v jq &>/dev/null; then
|
|
1616
|
+
version=$(jq -r '.version' "$repo/.aidevops.json" 2>/dev/null || echo "unknown")
|
|
1617
|
+
features=$(jq -r '[.features | to_entries[] | select(.value == true) | .key] | join(",")' "$repo/.aidevops.json" 2>/dev/null || echo "")
|
|
1618
|
+
else
|
|
1619
|
+
version="unknown"
|
|
1620
|
+
features=""
|
|
1621
|
+
fi
|
|
1622
|
+
register_repo "$repo" "$version" "$features"
|
|
1623
|
+
print_success "Registered $(basename "$repo")"
|
|
1624
|
+
done
|
|
1625
|
+
fi
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
# Help command
|
|
1629
|
+
cmd_help() {
|
|
1630
|
+
local version
|
|
1631
|
+
version=$(get_version)
|
|
1632
|
+
|
|
1633
|
+
echo "AI DevOps Framework CLI v$version"
|
|
1634
|
+
echo ""
|
|
1635
|
+
echo "Usage: aidevops <command> [options]"
|
|
1636
|
+
echo ""
|
|
1637
|
+
echo "Commands:"
|
|
1638
|
+
echo " init [features] Initialize aidevops in current project"
|
|
1639
|
+
echo " upgrade-planning Upgrade TODO.md/PLANS.md to latest templates"
|
|
1640
|
+
echo " features List available features for init"
|
|
1641
|
+
echo " status Check installation status of all components"
|
|
1642
|
+
echo " update Update aidevops to the latest version (alias: upgrade)"
|
|
1643
|
+
echo " upgrade Alias for update"
|
|
1644
|
+
echo " update-tools Check for outdated tools (--update to auto-update)"
|
|
1645
|
+
echo " repos [cmd] Manage registered projects (list/add/remove/clean)"
|
|
1646
|
+
echo " detect Find and register aidevops projects"
|
|
1647
|
+
echo " uninstall Remove aidevops from your system"
|
|
1648
|
+
echo " version Show version information"
|
|
1649
|
+
echo " help Show this help message"
|
|
1650
|
+
echo ""
|
|
1651
|
+
echo "Examples:"
|
|
1652
|
+
echo " aidevops init # Initialize with all features"
|
|
1653
|
+
echo " aidevops init planning # Initialize with planning only"
|
|
1654
|
+
echo " aidevops upgrade-planning # Upgrade planning files to latest"
|
|
1655
|
+
echo " aidevops features # List available features"
|
|
1656
|
+
echo " aidevops status # Check what's installed"
|
|
1657
|
+
echo " aidevops update # Update framework + check projects"
|
|
1658
|
+
echo " aidevops repos # List registered projects"
|
|
1659
|
+
echo " aidevops repos add # Register current project"
|
|
1660
|
+
echo " aidevops detect # Find unregistered projects"
|
|
1661
|
+
echo " aidevops update-tools # Check for outdated tools"
|
|
1662
|
+
echo " aidevops update-tools -u # Update all outdated tools"
|
|
1663
|
+
echo " aidevops uninstall # Remove aidevops"
|
|
1664
|
+
echo ""
|
|
1665
|
+
echo "Installation:"
|
|
1666
|
+
echo " npm install -g aidevops # via npm"
|
|
1667
|
+
echo " brew install marcusquinn/tap/aidevops # via Homebrew"
|
|
1668
|
+
echo " bash <(curl -fsSL https://aidevops.sh) # via curl"
|
|
1669
|
+
echo ""
|
|
1670
|
+
echo "Documentation: https://github.com/marcusquinn/aidevops"
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
# Version command
|
|
1674
|
+
cmd_version() {
|
|
1675
|
+
local current_version
|
|
1676
|
+
current_version=$(get_version)
|
|
1677
|
+
local remote_version
|
|
1678
|
+
remote_version=$(get_remote_version)
|
|
1679
|
+
|
|
1680
|
+
echo "aidevops $current_version"
|
|
1681
|
+
|
|
1682
|
+
if [[ "$remote_version" != "unknown" && "$current_version" != "$remote_version" ]]; then
|
|
1683
|
+
echo "Latest: $remote_version (run 'aidevops update' to upgrade)"
|
|
1684
|
+
fi
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
# Main entry point
|
|
1688
|
+
main() {
|
|
1689
|
+
local command="${1:-help}"
|
|
1690
|
+
|
|
1691
|
+
# Auto-detect unregistered repo on any command (silent check)
|
|
1692
|
+
local unregistered
|
|
1693
|
+
unregistered=$(detect_unregistered_repo 2>/dev/null)
|
|
1694
|
+
if [[ -n "$unregistered" && "$command" != "detect" && "$command" != "repos" ]]; then
|
|
1695
|
+
echo -e "${YELLOW}[TIP]${NC} This project uses aidevops but isn't registered. Run: aidevops repos add"
|
|
1696
|
+
echo ""
|
|
1697
|
+
fi
|
|
1698
|
+
|
|
1699
|
+
case "$command" in
|
|
1700
|
+
init|i)
|
|
1701
|
+
shift
|
|
1702
|
+
cmd_init "$@"
|
|
1703
|
+
;;
|
|
1704
|
+
features|f)
|
|
1705
|
+
cmd_features
|
|
1706
|
+
;;
|
|
1707
|
+
status|s)
|
|
1708
|
+
cmd_status
|
|
1709
|
+
;;
|
|
1710
|
+
update|upgrade|u)
|
|
1711
|
+
cmd_update
|
|
1712
|
+
;;
|
|
1713
|
+
update-tools|tools)
|
|
1714
|
+
shift
|
|
1715
|
+
cmd_update_tools "$@"
|
|
1716
|
+
;;
|
|
1717
|
+
upgrade-planning|up)
|
|
1718
|
+
shift
|
|
1719
|
+
cmd_upgrade_planning "$@"
|
|
1720
|
+
;;
|
|
1721
|
+
repos|projects)
|
|
1722
|
+
shift
|
|
1723
|
+
cmd_repos "$@"
|
|
1724
|
+
;;
|
|
1725
|
+
detect|scan)
|
|
1726
|
+
cmd_detect
|
|
1727
|
+
;;
|
|
1728
|
+
uninstall|remove)
|
|
1729
|
+
cmd_uninstall
|
|
1730
|
+
;;
|
|
1731
|
+
version|v|-v|--version)
|
|
1732
|
+
cmd_version
|
|
1733
|
+
;;
|
|
1734
|
+
help|h|-h|--help)
|
|
1735
|
+
cmd_help
|
|
1736
|
+
;;
|
|
1737
|
+
*)
|
|
1738
|
+
print_error "Unknown command: $command"
|
|
1739
|
+
echo ""
|
|
1740
|
+
cmd_help
|
|
1741
|
+
exit 1
|
|
1742
|
+
;;
|
|
1743
|
+
esac
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
main "$@"
|