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.
Files changed (329) hide show
  1. package/.agent/AGENTS.md +614 -0
  2. package/.agent/accounts.md +65 -0
  3. package/.agent/aidevops/add-new-mcp-to-aidevops.md +456 -0
  4. package/.agent/aidevops/api-integrations.md +335 -0
  5. package/.agent/aidevops/architecture.md +510 -0
  6. package/.agent/aidevops/configs.md +274 -0
  7. package/.agent/aidevops/docs.md +244 -0
  8. package/.agent/aidevops/extension.md +311 -0
  9. package/.agent/aidevops/mcp-integrations.md +340 -0
  10. package/.agent/aidevops/mcp-troubleshooting.md +162 -0
  11. package/.agent/aidevops/memory-patterns.md +172 -0
  12. package/.agent/aidevops/providers.md +217 -0
  13. package/.agent/aidevops/recommendations.md +321 -0
  14. package/.agent/aidevops/requirements.md +301 -0
  15. package/.agent/aidevops/resources.md +214 -0
  16. package/.agent/aidevops/security-requirements.md +174 -0
  17. package/.agent/aidevops/security.md +350 -0
  18. package/.agent/aidevops/service-links.md +400 -0
  19. package/.agent/aidevops/services.md +357 -0
  20. package/.agent/aidevops/setup.md +153 -0
  21. package/.agent/aidevops/troubleshooting.md +389 -0
  22. package/.agent/aidevops.md +124 -0
  23. package/.agent/build-plus.md +244 -0
  24. package/.agent/content/guidelines.md +109 -0
  25. package/.agent/content.md +87 -0
  26. package/.agent/health.md +59 -0
  27. package/.agent/legal.md +59 -0
  28. package/.agent/loop-state/full-loop.local.md +16 -0
  29. package/.agent/loop-state/ralph-loop.local.md +10 -0
  30. package/.agent/marketing.md +440 -0
  31. package/.agent/memory/README.md +260 -0
  32. package/.agent/onboarding.md +796 -0
  33. package/.agent/plan-plus.md +245 -0
  34. package/.agent/research.md +100 -0
  35. package/.agent/sales.md +333 -0
  36. package/.agent/scripts/101domains-helper.sh +701 -0
  37. package/.agent/scripts/add-missing-returns.sh +140 -0
  38. package/.agent/scripts/agent-browser-helper.sh +311 -0
  39. package/.agent/scripts/agno-setup.sh +712 -0
  40. package/.agent/scripts/ahrefs-mcp-wrapper.js +168 -0
  41. package/.agent/scripts/aidevops-update-check.sh +71 -0
  42. package/.agent/scripts/ampcode-cli.sh +522 -0
  43. package/.agent/scripts/auto-version-bump.sh +156 -0
  44. package/.agent/scripts/autogen-helper.sh +512 -0
  45. package/.agent/scripts/beads-sync-helper.sh +596 -0
  46. package/.agent/scripts/closte-helper.sh +5 -0
  47. package/.agent/scripts/cloudron-helper.sh +321 -0
  48. package/.agent/scripts/codacy-cli-chunked.sh +581 -0
  49. package/.agent/scripts/codacy-cli.sh +442 -0
  50. package/.agent/scripts/code-audit-helper.sh +5 -0
  51. package/.agent/scripts/coderabbit-cli.sh +417 -0
  52. package/.agent/scripts/coderabbit-pro-analysis.sh +238 -0
  53. package/.agent/scripts/commands/code-simplifier.md +86 -0
  54. package/.agent/scripts/commands/full-loop.md +246 -0
  55. package/.agent/scripts/commands/postflight-loop.md +103 -0
  56. package/.agent/scripts/commands/recall.md +182 -0
  57. package/.agent/scripts/commands/remember.md +132 -0
  58. package/.agent/scripts/commands/save-todo.md +175 -0
  59. package/.agent/scripts/commands/session-review.md +154 -0
  60. package/.agent/scripts/comprehensive-quality-fix.sh +106 -0
  61. package/.agent/scripts/context-builder-helper.sh +522 -0
  62. package/.agent/scripts/coolify-cli-helper.sh +674 -0
  63. package/.agent/scripts/coolify-helper.sh +380 -0
  64. package/.agent/scripts/crawl4ai-examples.sh +401 -0
  65. package/.agent/scripts/crawl4ai-helper.sh +1078 -0
  66. package/.agent/scripts/crewai-helper.sh +681 -0
  67. package/.agent/scripts/dev-browser-helper.sh +513 -0
  68. package/.agent/scripts/dns-helper.sh +396 -0
  69. package/.agent/scripts/domain-research-helper.sh +917 -0
  70. package/.agent/scripts/dspy-helper.sh +285 -0
  71. package/.agent/scripts/dspyground-helper.sh +291 -0
  72. package/.agent/scripts/eeat-score-helper.sh +1242 -0
  73. package/.agent/scripts/efficient-return-fix.sh +92 -0
  74. package/.agent/scripts/extract-opencode-prompts.sh +128 -0
  75. package/.agent/scripts/find-missing-returns.sh +113 -0
  76. package/.agent/scripts/fix-auth-headers.sh +104 -0
  77. package/.agent/scripts/fix-common-strings.sh +254 -0
  78. package/.agent/scripts/fix-content-type.sh +100 -0
  79. package/.agent/scripts/fix-error-messages.sh +130 -0
  80. package/.agent/scripts/fix-misplaced-returns.sh +74 -0
  81. package/.agent/scripts/fix-remaining-literals.sh +152 -0
  82. package/.agent/scripts/fix-return-statements.sh +41 -0
  83. package/.agent/scripts/fix-s131-default-cases.sh +249 -0
  84. package/.agent/scripts/fix-sc2155-simple.sh +102 -0
  85. package/.agent/scripts/fix-shellcheck-critical.sh +187 -0
  86. package/.agent/scripts/fix-string-literals.sh +273 -0
  87. package/.agent/scripts/full-loop-helper.sh +773 -0
  88. package/.agent/scripts/generate-opencode-agents.sh +497 -0
  89. package/.agent/scripts/generate-opencode-commands.sh +1629 -0
  90. package/.agent/scripts/generate-skills.sh +366 -0
  91. package/.agent/scripts/git-platforms-helper.sh +640 -0
  92. package/.agent/scripts/gitea-cli-helper.sh +743 -0
  93. package/.agent/scripts/github-cli-helper.sh +702 -0
  94. package/.agent/scripts/gitlab-cli-helper.sh +682 -0
  95. package/.agent/scripts/gsc-add-user-helper.sh +325 -0
  96. package/.agent/scripts/gsc-sitemap-helper.sh +678 -0
  97. package/.agent/scripts/hetzner-helper.sh +485 -0
  98. package/.agent/scripts/hostinger-helper.sh +229 -0
  99. package/.agent/scripts/keyword-research-helper.sh +1815 -0
  100. package/.agent/scripts/langflow-helper.sh +544 -0
  101. package/.agent/scripts/linkedin-automation.py +241 -0
  102. package/.agent/scripts/linter-manager.sh +599 -0
  103. package/.agent/scripts/linters-local.sh +434 -0
  104. package/.agent/scripts/list-keys-helper.sh +488 -0
  105. package/.agent/scripts/local-browser-automation.py +339 -0
  106. package/.agent/scripts/localhost-helper.sh +744 -0
  107. package/.agent/scripts/loop-common.sh +806 -0
  108. package/.agent/scripts/mainwp-helper.sh +728 -0
  109. package/.agent/scripts/markdown-formatter.sh +338 -0
  110. package/.agent/scripts/markdown-lint-fix.sh +311 -0
  111. package/.agent/scripts/mass-fix-returns.sh +58 -0
  112. package/.agent/scripts/mcp-diagnose.sh +167 -0
  113. package/.agent/scripts/mcp-inspector-helper.sh +449 -0
  114. package/.agent/scripts/memory-helper.sh +650 -0
  115. package/.agent/scripts/monitor-code-review.sh +255 -0
  116. package/.agent/scripts/onboarding-helper.sh +706 -0
  117. package/.agent/scripts/opencode-github-setup-helper.sh +797 -0
  118. package/.agent/scripts/opencode-test-helper.sh +213 -0
  119. package/.agent/scripts/pagespeed-helper.sh +464 -0
  120. package/.agent/scripts/pandoc-helper.sh +362 -0
  121. package/.agent/scripts/postflight-check.sh +555 -0
  122. package/.agent/scripts/pre-commit-hook.sh +259 -0
  123. package/.agent/scripts/pre-edit-check.sh +169 -0
  124. package/.agent/scripts/qlty-cli.sh +356 -0
  125. package/.agent/scripts/quality-cli-manager.sh +525 -0
  126. package/.agent/scripts/quality-feedback-helper.sh +462 -0
  127. package/.agent/scripts/quality-fix.sh +263 -0
  128. package/.agent/scripts/quality-loop-helper.sh +1108 -0
  129. package/.agent/scripts/ralph-loop-helper.sh +836 -0
  130. package/.agent/scripts/ralph-upstream-check.sh +341 -0
  131. package/.agent/scripts/secretlint-helper.sh +847 -0
  132. package/.agent/scripts/servers-helper.sh +241 -0
  133. package/.agent/scripts/ses-helper.sh +619 -0
  134. package/.agent/scripts/session-review-helper.sh +404 -0
  135. package/.agent/scripts/setup-linters-wizard.sh +379 -0
  136. package/.agent/scripts/setup-local-api-keys.sh +330 -0
  137. package/.agent/scripts/setup-mcp-integrations.sh +472 -0
  138. package/.agent/scripts/shared-constants.sh +246 -0
  139. package/.agent/scripts/site-crawler-helper.sh +1487 -0
  140. package/.agent/scripts/snyk-helper.sh +940 -0
  141. package/.agent/scripts/sonarcloud-autofix.sh +193 -0
  142. package/.agent/scripts/sonarcloud-cli.sh +191 -0
  143. package/.agent/scripts/sonarscanner-cli.sh +455 -0
  144. package/.agent/scripts/spaceship-helper.sh +747 -0
  145. package/.agent/scripts/stagehand-helper.sh +321 -0
  146. package/.agent/scripts/stagehand-python-helper.sh +321 -0
  147. package/.agent/scripts/stagehand-python-setup.sh +441 -0
  148. package/.agent/scripts/stagehand-setup.sh +439 -0
  149. package/.agent/scripts/system-cleanup.sh +340 -0
  150. package/.agent/scripts/terminal-title-helper.sh +388 -0
  151. package/.agent/scripts/terminal-title-setup.sh +549 -0
  152. package/.agent/scripts/test-stagehand-both-integration.sh +317 -0
  153. package/.agent/scripts/test-stagehand-integration.sh +309 -0
  154. package/.agent/scripts/test-stagehand-python-integration.sh +341 -0
  155. package/.agent/scripts/todo-ready.sh +263 -0
  156. package/.agent/scripts/tool-version-check.sh +362 -0
  157. package/.agent/scripts/toon-helper.sh +469 -0
  158. package/.agent/scripts/twilio-helper.sh +917 -0
  159. package/.agent/scripts/updown-helper.sh +279 -0
  160. package/.agent/scripts/validate-mcp-integrations.sh +250 -0
  161. package/.agent/scripts/validate-version-consistency.sh +131 -0
  162. package/.agent/scripts/vaultwarden-helper.sh +597 -0
  163. package/.agent/scripts/vercel-cli-helper.sh +816 -0
  164. package/.agent/scripts/verify-mirrors.sh +169 -0
  165. package/.agent/scripts/version-manager.sh +831 -0
  166. package/.agent/scripts/webhosting-helper.sh +471 -0
  167. package/.agent/scripts/webhosting-verify.sh +238 -0
  168. package/.agent/scripts/wordpress-mcp-helper.sh +508 -0
  169. package/.agent/scripts/worktree-helper.sh +595 -0
  170. package/.agent/scripts/worktree-sessions.sh +577 -0
  171. package/.agent/seo/dataforseo.md +215 -0
  172. package/.agent/seo/domain-research.md +532 -0
  173. package/.agent/seo/eeat-score.md +659 -0
  174. package/.agent/seo/google-search-console.md +366 -0
  175. package/.agent/seo/gsc-sitemaps.md +282 -0
  176. package/.agent/seo/keyword-research.md +521 -0
  177. package/.agent/seo/serper.md +278 -0
  178. package/.agent/seo/site-crawler.md +387 -0
  179. package/.agent/seo.md +236 -0
  180. package/.agent/services/accounting/quickfile.md +159 -0
  181. package/.agent/services/communications/telfon.md +470 -0
  182. package/.agent/services/communications/twilio.md +569 -0
  183. package/.agent/services/crm/fluentcrm.md +449 -0
  184. package/.agent/services/email/ses.md +399 -0
  185. package/.agent/services/hosting/101domains.md +378 -0
  186. package/.agent/services/hosting/closte.md +177 -0
  187. package/.agent/services/hosting/cloudflare.md +251 -0
  188. package/.agent/services/hosting/cloudron.md +478 -0
  189. package/.agent/services/hosting/dns-providers.md +335 -0
  190. package/.agent/services/hosting/domain-purchasing.md +344 -0
  191. package/.agent/services/hosting/hetzner.md +327 -0
  192. package/.agent/services/hosting/hostinger.md +287 -0
  193. package/.agent/services/hosting/localhost.md +419 -0
  194. package/.agent/services/hosting/spaceship.md +353 -0
  195. package/.agent/services/hosting/webhosting.md +330 -0
  196. package/.agent/social-media.md +69 -0
  197. package/.agent/templates/plans-template.md +114 -0
  198. package/.agent/templates/prd-template.md +129 -0
  199. package/.agent/templates/tasks-template.md +108 -0
  200. package/.agent/templates/todo-template.md +89 -0
  201. package/.agent/tools/ai-assistants/agno.md +471 -0
  202. package/.agent/tools/ai-assistants/capsolver.md +326 -0
  203. package/.agent/tools/ai-assistants/configuration.md +221 -0
  204. package/.agent/tools/ai-assistants/overview.md +209 -0
  205. package/.agent/tools/ai-assistants/status.md +171 -0
  206. package/.agent/tools/ai-assistants/windsurf.md +193 -0
  207. package/.agent/tools/ai-orchestration/autogen.md +406 -0
  208. package/.agent/tools/ai-orchestration/crewai.md +445 -0
  209. package/.agent/tools/ai-orchestration/langflow.md +405 -0
  210. package/.agent/tools/ai-orchestration/openprose.md +487 -0
  211. package/.agent/tools/ai-orchestration/overview.md +362 -0
  212. package/.agent/tools/ai-orchestration/packaging.md +647 -0
  213. package/.agent/tools/browser/agent-browser.md +464 -0
  214. package/.agent/tools/browser/browser-automation.md +400 -0
  215. package/.agent/tools/browser/chrome-devtools.md +282 -0
  216. package/.agent/tools/browser/crawl4ai-integration.md +422 -0
  217. package/.agent/tools/browser/crawl4ai-resources.md +277 -0
  218. package/.agent/tools/browser/crawl4ai-usage.md +416 -0
  219. package/.agent/tools/browser/crawl4ai.md +585 -0
  220. package/.agent/tools/browser/dev-browser.md +341 -0
  221. package/.agent/tools/browser/pagespeed.md +260 -0
  222. package/.agent/tools/browser/playwright.md +266 -0
  223. package/.agent/tools/browser/playwriter.md +310 -0
  224. package/.agent/tools/browser/stagehand-examples.md +456 -0
  225. package/.agent/tools/browser/stagehand-python.md +483 -0
  226. package/.agent/tools/browser/stagehand.md +421 -0
  227. package/.agent/tools/build-agent/agent-review.md +224 -0
  228. package/.agent/tools/build-agent/build-agent.md +784 -0
  229. package/.agent/tools/build-mcp/aidevops-plugin.md +476 -0
  230. package/.agent/tools/build-mcp/api-wrapper.md +445 -0
  231. package/.agent/tools/build-mcp/build-mcp.md +240 -0
  232. package/.agent/tools/build-mcp/deployment.md +401 -0
  233. package/.agent/tools/build-mcp/server-patterns.md +632 -0
  234. package/.agent/tools/build-mcp/transports.md +366 -0
  235. package/.agent/tools/code-review/auditing.md +383 -0
  236. package/.agent/tools/code-review/automation.md +219 -0
  237. package/.agent/tools/code-review/best-practices.md +203 -0
  238. package/.agent/tools/code-review/codacy.md +151 -0
  239. package/.agent/tools/code-review/code-simplifier.md +174 -0
  240. package/.agent/tools/code-review/code-standards.md +309 -0
  241. package/.agent/tools/code-review/coderabbit.md +101 -0
  242. package/.agent/tools/code-review/management.md +155 -0
  243. package/.agent/tools/code-review/qlty.md +248 -0
  244. package/.agent/tools/code-review/secretlint.md +565 -0
  245. package/.agent/tools/code-review/setup.md +250 -0
  246. package/.agent/tools/code-review/snyk.md +563 -0
  247. package/.agent/tools/code-review/tools.md +230 -0
  248. package/.agent/tools/content/summarize.md +353 -0
  249. package/.agent/tools/context/augment-context-engine.md +468 -0
  250. package/.agent/tools/context/context-builder-agent.md +76 -0
  251. package/.agent/tools/context/context-builder.md +375 -0
  252. package/.agent/tools/context/context7.md +371 -0
  253. package/.agent/tools/context/dspy.md +302 -0
  254. package/.agent/tools/context/dspyground.md +374 -0
  255. package/.agent/tools/context/llm-tldr.md +219 -0
  256. package/.agent/tools/context/osgrep.md +488 -0
  257. package/.agent/tools/context/prompt-optimization.md +338 -0
  258. package/.agent/tools/context/toon.md +292 -0
  259. package/.agent/tools/conversion/pandoc.md +304 -0
  260. package/.agent/tools/credentials/api-key-management.md +154 -0
  261. package/.agent/tools/credentials/api-key-setup.md +224 -0
  262. package/.agent/tools/credentials/environment-variables.md +180 -0
  263. package/.agent/tools/credentials/vaultwarden.md +382 -0
  264. package/.agent/tools/data-extraction/outscraper.md +974 -0
  265. package/.agent/tools/deployment/coolify-cli.md +388 -0
  266. package/.agent/tools/deployment/coolify-setup.md +353 -0
  267. package/.agent/tools/deployment/coolify.md +345 -0
  268. package/.agent/tools/deployment/vercel.md +390 -0
  269. package/.agent/tools/git/authentication.md +132 -0
  270. package/.agent/tools/git/gitea-cli.md +193 -0
  271. package/.agent/tools/git/github-actions.md +207 -0
  272. package/.agent/tools/git/github-cli.md +223 -0
  273. package/.agent/tools/git/gitlab-cli.md +190 -0
  274. package/.agent/tools/git/opencode-github-security.md +350 -0
  275. package/.agent/tools/git/opencode-github.md +328 -0
  276. package/.agent/tools/git/opencode-gitlab.md +252 -0
  277. package/.agent/tools/git/security.md +196 -0
  278. package/.agent/tools/git.md +207 -0
  279. package/.agent/tools/opencode/oh-my-opencode.md +375 -0
  280. package/.agent/tools/opencode/opencode-anthropic-auth.md +446 -0
  281. package/.agent/tools/opencode/opencode.md +651 -0
  282. package/.agent/tools/social-media/bird.md +437 -0
  283. package/.agent/tools/task-management/beads.md +336 -0
  284. package/.agent/tools/terminal/terminal-title.md +251 -0
  285. package/.agent/tools/ui/shadcn.md +196 -0
  286. package/.agent/tools/ui/ui-skills.md +115 -0
  287. package/.agent/tools/wordpress/localwp.md +311 -0
  288. package/.agent/tools/wordpress/mainwp.md +391 -0
  289. package/.agent/tools/wordpress/scf.md +527 -0
  290. package/.agent/tools/wordpress/wp-admin.md +729 -0
  291. package/.agent/tools/wordpress/wp-dev.md +940 -0
  292. package/.agent/tools/wordpress/wp-preferred.md +398 -0
  293. package/.agent/tools/wordpress.md +95 -0
  294. package/.agent/workflows/branch/bugfix.md +63 -0
  295. package/.agent/workflows/branch/chore.md +95 -0
  296. package/.agent/workflows/branch/experiment.md +115 -0
  297. package/.agent/workflows/branch/feature.md +59 -0
  298. package/.agent/workflows/branch/hotfix.md +98 -0
  299. package/.agent/workflows/branch/refactor.md +92 -0
  300. package/.agent/workflows/branch/release.md +96 -0
  301. package/.agent/workflows/branch.md +347 -0
  302. package/.agent/workflows/bug-fixing.md +267 -0
  303. package/.agent/workflows/changelog.md +129 -0
  304. package/.agent/workflows/code-audit-remote.md +279 -0
  305. package/.agent/workflows/conversation-starter.md +69 -0
  306. package/.agent/workflows/error-feedback.md +578 -0
  307. package/.agent/workflows/feature-development.md +355 -0
  308. package/.agent/workflows/git-workflow.md +702 -0
  309. package/.agent/workflows/multi-repo-workspace.md +268 -0
  310. package/.agent/workflows/plans.md +709 -0
  311. package/.agent/workflows/postflight.md +604 -0
  312. package/.agent/workflows/pr.md +571 -0
  313. package/.agent/workflows/preflight.md +278 -0
  314. package/.agent/workflows/ralph-loop.md +773 -0
  315. package/.agent/workflows/release.md +498 -0
  316. package/.agent/workflows/session-manager.md +254 -0
  317. package/.agent/workflows/session-review.md +311 -0
  318. package/.agent/workflows/sql-migrations.md +631 -0
  319. package/.agent/workflows/version-bump.md +283 -0
  320. package/.agent/workflows/wiki-update.md +333 -0
  321. package/.agent/workflows/worktree.md +477 -0
  322. package/LICENSE +21 -0
  323. package/README.md +1446 -0
  324. package/VERSION +1 -0
  325. package/aidevops.sh +1746 -0
  326. package/bin/aidevops +21 -0
  327. package/package.json +75 -0
  328. package/scripts/npm-postinstall.js +60 -0
  329. 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 "$@"