opencode-homebrew-agent 1.0.0

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 (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +175 -0
  3. package/agents/brew.md +146 -0
  4. package/package.json +22 -0
  5. package/src/AGENTS.md +172 -0
  6. package/src/scripts/brew-analyze.sh +373 -0
  7. package/src/scripts/brew-deps.sh +140 -0
  8. package/src/scripts/brew-env.sh +288 -0
  9. package/src/scripts/brew-search.sh +150 -0
  10. package/src/scripts/brew-template.sh +263 -0
  11. package/src/scripts/package.json +21 -0
  12. package/src/skills/homebrew-agent/SKILL.md +203 -0
  13. package/src/skills/homebrew-tap/SKILL.md +97 -0
  14. package/src/templates/taps/01-full-ci/AGENTS.md +71 -0
  15. package/src/templates/taps/01-full-ci/tap-structure/.github/workflows/autobump.yml +24 -0
  16. package/src/templates/taps/01-full-ci/tap-structure/.github/workflows/publish.yml +33 -0
  17. package/src/templates/taps/01-full-ci/tap-structure/.github/workflows/tests.yml +33 -0
  18. package/src/templates/taps/01-full-ci/tap-structure/Formula/_formula.rb +31 -0
  19. package/src/templates/taps/01-full-ci/tap-structure/README.md +27 -0
  20. package/src/templates/taps/01-full-ci/tap-structure/cmd/.gitkeep +0 -0
  21. package/src/templates/taps/01-full-ci/tap-structure/formula_renames.json +1 -0
  22. package/src/templates/taps/01-full-ci/tap-structure/lib/.gitkeep +0 -0
  23. package/src/templates/taps/01-full-ci/tap-structure/require/.gitkeep +0 -0
  24. package/src/templates/taps/01-full-ci/tap-structure/tap_migrations.json +1 -0
  25. package/src/templates/taps/01-full-ci/template.md +45 -0
  26. package/src/templates/taps/02-root-level/AGENTS.md +72 -0
  27. package/src/templates/taps/02-root-level/tap-structure/README.md +27 -0
  28. package/src/templates/taps/02-root-level/tap-structure/_formula.rb +29 -0
  29. package/src/templates/taps/02-root-level/template.md +35 -0
  30. package/src/templates/taps/03-simple-script/AGENTS.md +71 -0
  31. package/src/templates/taps/03-simple-script/tap-structure/Formula/_formula.rb +27 -0
  32. package/src/templates/taps/03-simple-script/tap-structure/README.md +27 -0
  33. package/src/templates/taps/03-simple-script/tap-structure/scripts/release.rb +46 -0
  34. package/src/templates/taps/03-simple-script/template.md +41 -0
  35. package/src/templates/taps/04-python-venv/AGENTS.md +83 -0
  36. package/src/templates/taps/04-python-venv/tap-structure/Formula/_formula.rb +57 -0
  37. package/src/templates/taps/04-python-venv/tap-structure/README.md +27 -0
  38. package/src/templates/taps/04-python-venv/tap-structure/scripts/release.rb +44 -0
  39. package/src/templates/taps/04-python-venv/template.md +58 -0
  40. package/src/templates/taps/05-node-npm/AGENTS.md +90 -0
  41. package/src/templates/taps/05-node-npm/tap-structure/Formula/_formula.rb +46 -0
  42. package/src/templates/taps/05-node-npm/tap-structure/README.md +27 -0
  43. package/src/templates/taps/05-node-npm/tap-structure/scripts/release.rb +40 -0
  44. package/src/templates/taps/05-node-npm/template.md +74 -0
  45. package/src/templates/taps/06-keg-only/AGENTS.md +82 -0
  46. package/src/templates/taps/06-keg-only/tap-structure/Formula/_formula.rb +45 -0
  47. package/src/templates/taps/06-keg-only/tap-structure/README.md +27 -0
  48. package/src/templates/taps/06-keg-only/template.md +60 -0
  49. package/src/templates/taps/07-cask-only/AGENTS.md +97 -0
  50. package/src/templates/taps/07-cask-only/tap-structure/Casks/_app.rb +26 -0
  51. package/src/templates/taps/07-cask-only/tap-structure/README.md +27 -0
  52. package/src/templates/taps/07-cask-only/template.md +58 -0
  53. package/src/templates/taps/08-go-binary/AGENTS.md +86 -0
  54. package/src/templates/taps/08-go-binary/tap-structure/Formula/_formula.rb +40 -0
  55. package/src/templates/taps/08-go-binary/tap-structure/README.md +27 -0
  56. package/src/templates/taps/08-go-binary/tap-structure/scripts/release.rb +38 -0
  57. package/src/templates/taps/08-go-binary/template.md +60 -0
  58. package/src/workflows/analyze-source.sh +124 -0
  59. package/src/workflows/convert-npm-to-bun.sh +112 -0
  60. package/src/workflows/create-tap.sh +196 -0
@@ -0,0 +1,86 @@
1
+ ---
2
+ name: homebrew-tap-go-binary
3
+ description: Creates and maintains Homebrew taps for Go CLI tools that build from source.
4
+ ---
5
+
6
+ # homebrew-tap-go-binary
7
+
8
+ Agent for working with Go Binary tap templates.
9
+
10
+ ## Description
11
+ Helps create and maintain Homebrew taps for Go CLI tools that build from source.
12
+
13
+ ## Stacks
14
+ - homebrew
15
+ - go
16
+ - ruby
17
+
18
+ ## Requires
19
+ - basic-homebrew-knowledge
20
+
21
+ ## Key Actions
22
+
23
+ ### Go Build Pattern
24
+ ```ruby
25
+ depends_on "go" => :build
26
+
27
+ def install
28
+ system "go", "build", *std_go_args(ldflags: "-s -w -X main.version=#{version}")
29
+ end
30
+ ```
31
+
32
+ ### With Module Path
33
+ ```ruby
34
+ def install
35
+ ENV["GOPATH"] = buildpath
36
+ path = buildpath/"src/github.com/<user>/<repo>"
37
+ path.install Dir["*"]
38
+ cd path do
39
+ system "go", "build", *std_go_args(ldflags: "-s -w -X main.version=#{version}")
40
+ end
41
+ end
42
+ ```
43
+
44
+ ### Common ldflags
45
+ - `-s -w` — strip debug information (smaller binary)
46
+ - `-X main.version=#{version}` — inject version at build time
47
+ - `-X main.commit=#{Utils.git_head}` — inject commit hash
48
+
49
+ ### Permissions
50
+ - Read/write to `Formula/` and `scripts/`
51
+ - Network access for Go module downloads
52
+
53
+ ### Common Pitfalls
54
+
55
+ - `depends_on "go" => :build` is required — without `=> :build`, Go becomes a runtime dependency and users must install it to use your binary.
56
+ - `ldflags` must be a single string: `"-s -w -X main.version=#{version}"`. Multiple arguments will cause a `go build` error.
57
+ - Module-aware projects (Go 1.11+) should NOT use the GOPATH layout. Uncomment the GOPATH `def install` only for legacy projects.
58
+
59
+ ### LSP Validation
60
+
61
+ Before finishing any formula, validate with the Ruby LSP:
62
+
63
+ 1. Ensure LSP is available:
64
+ ```sh
65
+ ruby-lsp --version # Verify LSP is installed
66
+ ```
67
+ 2. Run syntax check:
68
+ ```sh
69
+ ruby -c Formula/<formula>.rb
70
+ ```
71
+ 3. Run Homebrew linting:
72
+ ```sh
73
+ brew style --tap <user>/<tapname> Formula/<formula>.rb
74
+ ```
75
+ 4. Run formula audit:
76
+ ```sh
77
+ brew audit --new-formula Formula/<formula>.rb
78
+ ```
79
+
80
+ Do NOT mark work as complete until all diagnostics pass.
81
+
82
+ ### Verification
83
+ ```sh
84
+ ruby -c Formula/<formula>.rb
85
+ brew style --tap <user>/<tapname> Formula/<formula>.rb
86
+ ```
@@ -0,0 +1,40 @@
1
+
2
+ # Go CLI tool formula — builds from source.
3
+ # Replace <formula>, <description>, <url>, <sha256> with real values.
4
+ # IMPORTANT: Rename class <Formula> to CamelCase matching the filename (e.g., MyTool for my-tool.rb).
5
+
6
+ class <Formula> < Formula
7
+ desc "<one-line description>"
8
+ homepage "https://github.com/<user>/<repo>"
9
+ url "https://github.com/<user>/<repo>/archive/refs/tags/v<version>.tar.gz"
10
+ sha256 "<sha256>"
11
+ version "<version>"
12
+ license "MIT"
13
+
14
+ depends_on "go" => :build
15
+
16
+ livecheck do
17
+ url :stable
18
+ regex(/^v?(\d+(?:\.\d+)+)$/i)
19
+ end
20
+
21
+ def install
22
+ ldflags = "-s -w -X main.version=#{version}"
23
+ system "go", "build", *std_go_args(ldflags: ldflags)
24
+ end
25
+
26
+ # Alternative: traditional GOPATH layout
27
+ # def install
28
+ # ENV["GOPATH"] = buildpath
29
+ # path = buildpath/"src/github.com/<user>/<repo>"
30
+ # path.install Dir["*"]
31
+ # cd path do
32
+ # ldflags = "-s -w -X main.version=#{version}"
33
+ # system "go", "build", *std_go_args(ldflags: ldflags)
34
+ # end
35
+ # end
36
+
37
+ test do
38
+ assert_match version.to_s, shell_output("#{bin}/<cli> --version")
39
+ end
40
+ end
@@ -0,0 +1,27 @@
1
+ # <Tap Name>
2
+
3
+ Homebrew tap for <formula>.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ brew tap <user>/<tapname>
9
+ brew install <formula>
10
+ ```
11
+
12
+ ## Upgrade
13
+
14
+ ```sh
15
+ brew upgrade <formula>
16
+ ```
17
+
18
+ ## Uninstall
19
+
20
+ ```sh
21
+ brew uninstall <formula>
22
+ brew untap <user>/<tapname>
23
+ ```
24
+
25
+ ## License
26
+
27
+ MIT
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Version bump script for Go binary formula.
5
+ # Usage: ruby scripts/update-formula.rb <version>
6
+
7
+ require "open-uri"
8
+ require "digest"
9
+
10
+ TAP_DIR = File.dirname(__dir__)
11
+ FORMULA_FILE = File.join(TAP_DIR, "Formula", "_formula.rb") # rename to your formula name
12
+
13
+ def usage
14
+ puts "Usage: ruby scripts/update-formula.rb <version>"
15
+ puts " e.g., ruby scripts/update-formula.rb 1.2.3"
16
+ exit 1
17
+ end
18
+
19
+ def fetch_sha256(url)
20
+ uri = URI.parse(url)
21
+ puts " Downloading #{url}..."
22
+ content = URI.open(uri).read
23
+ Digest::SHA256.hexdigest(content)
24
+ end
25
+
26
+ version = ARGV.first || usage()
27
+ tarball_url = "https://github.com/<user>/<repo>/archive/refs/tags/v#{version}.tar.gz"
28
+
29
+ puts "Updating Formula/<formula>.rb to version #{version}..."
30
+ sha = fetch_sha256(tarball_url)
31
+
32
+ formula_content = File.read(FORMULA_FILE)
33
+ formula_content.sub!(/version "\d+\.\d+\.\d+"/, "version \"#{version}\"")
34
+ formula_content.sub!(/sha256 "[0-9a-f]{64}"/, "sha256 \"#{sha}\"")
35
+
36
+ File.write(FORMULA_FILE, formula_content)
37
+ puts "Done. Formula updated to v#{version}."
38
+ puts "Review: git diff Formula/<formula>.rb"
@@ -0,0 +1,60 @@
1
+ # Template 08: Go Binary
2
+
3
+ ## Pattern: CLI tools written in Go
4
+
5
+ For Go CLI tools that build from source using `go build`. Common for
6
+ modern cloud/CLI tools (e.g., `gh`, `docker`, `kubectl` clone). Uses
7
+ `depends_on "go" => :build` and compiles during `brew install`.
8
+
9
+ ### Structure
10
+
11
+ ```
12
+ homebrew-<tap>/
13
+ ├── Formula/
14
+ │ └── <formula>.rb # Formula with Go build
15
+ ├── scripts/
16
+ │ └── release.rb # (optional) Version bump script
17
+ ├── .gitignore
18
+ ├── LICENSE
19
+ └── README.md
20
+ ```
21
+
22
+ ### Key Formula Pattern
23
+
24
+ ```ruby
25
+ depends_on "go" => :build
26
+
27
+ def install
28
+ system "go", "build", *std_go_args(ldflags: "-s -w -X main.version=#{version}")
29
+ end
30
+
31
+ # Alternative: traditional GOPATH layout (uncomment if needed)
32
+ # def install
33
+ # ENV["GOPATH"] = buildpath
34
+ # path = buildpath/"src/github.com/<user>/<repo>"
35
+ # path.install Dir["*"]
36
+ # cd path do
37
+ # system "go", "build", *std_go_args(ldflags: "-s -w -X main.version=#{version}")
38
+ # end
39
+ # end
40
+ ```
41
+
42
+ ### When to Use
43
+
44
+ - Your CLI tool is written in Go
45
+ - The source is available on GitHub
46
+ - You want to build from source (not download a pre-built binary)
47
+ - You want to set version via `ldflags` at build time
48
+
49
+ ### When NOT to Use
50
+
51
+ - The Go tool is distributed as a pre-built binary (use template 03 instead)
52
+ - The tool requires CGo with external C libraries (add `depends_on` as needed)
53
+
54
+ ### Reference
55
+
56
+ - `std_go_args` is a Homebrew helper that sets `-o`, `-trimpath`, etc.
57
+ - Common `ldflags`: `-s -w` (strip debug), `-X main.version=#{version}` (inject version)
58
+ - For module-based projects, `GOPROXY` may need setting via `ENV`
59
+
60
+ - Start with `brew tap-new <user>/homebrew-<tapname>` to generate the CI skeleton (optional — manual structure works too)
@@ -0,0 +1,124 @@
1
+ #!/bin/bash
2
+ # workflows/analyze-source.sh
3
+ # Rich wrapper around brew-analyze.sh with human-readable output.
4
+ set -euo pipefail
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
8
+ ANALYZE="${PROJECT_ROOT}/scripts/brew-analyze.sh"
9
+
10
+ # --- Usage ---
11
+ usage() {
12
+ cat << 'EOF'
13
+ Usage: analyze-source.sh [OPTIONS]
14
+
15
+ Analyze a source directory or GitHub URL and recommend a Homebrew template.
16
+
17
+ Options:
18
+ --dir <path> Analyze local directory
19
+ --url <github-url> Analyze GitHub URL
20
+ --json Output raw JSON
21
+ --human Output human-readable report (default)
22
+ --help Show this help message
23
+ EOF
24
+ }
25
+
26
+ # --- Parse args ---
27
+ DIR=""
28
+ URL=""
29
+ JSON_MODE=false
30
+ HUMAN_MODE=false
31
+
32
+ while [[ $# -gt 0 ]]; do
33
+ case "$1" in
34
+ --dir) DIR="$2"; shift 2 ;;
35
+ --url) URL="$2"; shift 2 ;;
36
+ --json) JSON_MODE=true; shift ;;
37
+ --human) HUMAN_MODE=true; shift ;;
38
+ --help) usage; exit 0 ;;
39
+ *) echo "error: unknown option: $1" >&2; usage >&2; exit 1 ;;
40
+ esac
41
+ done
42
+
43
+ # --- Determine mode ---
44
+ if $JSON_MODE; then
45
+ if [[ -n "$DIR" ]]; then
46
+ "$ANALYZE" --dir "$DIR" --json
47
+ elif [[ -n "$URL" ]]; then
48
+ "$ANALYZE" --url "$URL" --json
49
+ else
50
+ echo "error: --dir or --url required" >&2
51
+ usage >&2
52
+ exit 1
53
+ fi
54
+ exit 0
55
+ fi
56
+
57
+ # --- Run analysis ---
58
+ if [[ -n "$DIR" ]]; then
59
+ ANALYSIS=$("$ANALYZE" --dir "$DIR" --json 2>/dev/null)
60
+ SOURCE="$DIR"
61
+ elif [[ -n "$URL" ]]; then
62
+ ANALYSIS=$("$ANALYZE" --url "$URL" --json 2>/dev/null)
63
+ SOURCE="$URL"
64
+ else
65
+ echo "error: --dir or --url required" >&2
66
+ usage >&2
67
+ exit 1
68
+ fi
69
+
70
+ # --- Parse JSON ---
71
+ TYPE=$(echo "$ANALYSIS" | python3 -c 'import sys,json; print(json.load(sys.stdin).get("type","unknown"))')
72
+ TEMPLATE=$(echo "$ANALYSIS" | python3 -c 'import sys,json; print(json.load(sys.stdin).get("template","02"))')
73
+ TEMPLATE_NAME=$(echo "$ANALYSIS" | python3 -c 'import sys,json; print(json.load(sys.stdin).get("template_name","root-level"))')
74
+ CONFIDENCE=$(echo "$ANALYSIS" | python3 -c 'import sys,json; print(json.load(sys.stdin).get("confidence","low"))')
75
+ MARKERS=$(echo "$ANALYSIS" | python3 -c 'import sys,json; print(" ".join(json.load(sys.stdin).get("markers",[])))')
76
+
77
+ # --- Complexity estimation ---
78
+ COMPLEXITY="simple"
79
+ case "$TYPE" in
80
+ simple-script|root-level) COMPLEXITY="simple" ;;
81
+ node-npm|python-venv|go-binary) COMPLEXITY="medium" ;;
82
+ full-ci|cask|keg-only) COMPLEXITY="complex" ;;
83
+ *) COMPLEXITY="unknown" ;;
84
+ esac
85
+
86
+ # --- Print report ---
87
+ cat << EOF
88
+
89
+ Source Analysis Report
90
+ ======================
91
+ Source: $SOURCE
92
+
93
+ Detected Type
94
+ -------------
95
+ Project type: $TYPE
96
+ Template: $TEMPLATE ($TEMPLATE_NAME)
97
+ Confidence: $CONFIDENCE
98
+ Markers: $MARKERS
99
+
100
+ Complexity Estimate
101
+ -------------------
102
+ $COMPLEXITY
103
+
104
+ Next Steps
105
+ ----------
106
+ To scaffold this as a Homebrew tap, run:
107
+
108
+ bash workflows/create-tap.sh --source "$SOURCE" --name <FormulaName> --tap <user>/homebrew-<tap>
109
+
110
+ Or with all options:
111
+
112
+ bash workflows/create-tap.sh \
113
+ --source "$SOURCE" \
114
+ --name MyCli \
115
+ --tap myuser/homebrew-mycli \
116
+ --output ./mytap \
117
+ --non-interactive
118
+
119
+ EOF
120
+
121
+ if [[ "$TYPE" == "node-npm" ]]; then
122
+ echo "Note: This project uses npm. You can convert to bun with --convert-to-bun"
123
+ echo ""
124
+ fi
@@ -0,0 +1,112 @@
1
+ #!/bin/bash
2
+ # workflows/convert-npm-to-bun.sh
3
+ # Convert an npm-based Homebrew formula to use bun.
4
+ set -euo pipefail
5
+
6
+ # --- Usage ---
7
+ usage() {
8
+ cat << 'EOF'
9
+ Usage: convert-npm-to-bun.sh [OPTIONS]
10
+
11
+ Convert an npm-based Homebrew formula to use bun.
12
+
13
+ Options:
14
+ --formula <path> Path to the formula .rb file
15
+ --check Only check if conversion is possible
16
+ --dry-run Show what would change without modifying
17
+ --help Show this help message
18
+
19
+ Examples:
20
+ convert-npm-to-bun.sh --formula Formula/my-cli.rb --dry-run
21
+ convert-npm-to-bun.sh --formula Formula/my-cli.rb
22
+ EOF
23
+ }
24
+
25
+ # --- Parse args ---
26
+ FORMULA=""
27
+ CHECK=false
28
+ DRY_RUN=false
29
+
30
+ while [[ $# -gt 0 ]]; do
31
+ case "$1" in
32
+ --formula) FORMULA="$2"; shift 2 ;;
33
+ --check) CHECK=true; shift ;;
34
+ --dry-run) DRY_RUN=true; shift ;;
35
+ --help) usage; exit 0 ;;
36
+ *) echo "error: unknown option: $1" >&2; usage >&2; exit 1 ;;
37
+ esac
38
+ done
39
+
40
+ # --- Validate ---
41
+ if [[ -z "$FORMULA" ]]; then
42
+ echo "error: --formula is required" >&2
43
+ usage >&2
44
+ exit 1
45
+ fi
46
+
47
+ if [[ ! -f "$FORMULA" ]]; then
48
+ echo "error: file not found: $FORMULA" >&2
49
+ exit 1
50
+ fi
51
+
52
+ # --- Check for bun ---
53
+ if ! command -v bun >/dev/null 2>&1; then
54
+ echo "warning: bun is not installed. Install with: brew install oven-sh/bun/bun" >&2
55
+ fi
56
+
57
+ # --- Analyze formula ---
58
+ if grep -q 'depends_on.*"bun"' "$FORMULA"; then
59
+ echo "info: formula already uses bun — nothing to convert" >&2
60
+ exit 0
61
+ fi
62
+
63
+ if ! grep -q 'depends_on.*"node"' "$FORMULA"; then
64
+ echo "error: no npm/node dependency found in formula" >&2
65
+ exit 1
66
+ fi
67
+
68
+ if $CHECK; then
69
+ echo "info: conversion is possible (npm formula detected)" >&2
70
+ exit 0
71
+ fi
72
+
73
+ # --- Compute changes ---
74
+ TMP_FORMULA=$(mktemp -p /tmp)
75
+ trap 'rm -f "$TMP_FORMULA"' EXIT
76
+
77
+ cp "$FORMULA" "$TMP_FORMULA"
78
+
79
+ # Replace node dependency with bun
80
+ sed -i.bak 's/depends_on "node"/depends_on "bun"/' "$TMP_FORMULA"
81
+
82
+ # Replace npm install with bun install
83
+ sed -i.bak 's/system "npm", "install", \*std_npm_args/system "bun", "install"/' "$TMP_FORMULA"
84
+ sed -i.bak 's/system "npm", "install"/system "bun", "install"/' "$TMP_FORMULA"
85
+
86
+ # Add bun tap note comment after the bun dependency line
87
+ awk '/depends_on "bun"/ { print; print " # NOTE: bun is provided by oven-sh/bun tap: brew tap oven-sh/bun"; next } 1' "$TMP_FORMULA" > "${TMP_FORMULA}.tmp"
88
+ mv "${TMP_FORMULA}.tmp" "$TMP_FORMULA"
89
+
90
+ rm -f "$TMP_FORMULA.bak"
91
+
92
+ # --- Show diff ---
93
+ if $DRY_RUN; then
94
+ echo "=== Proposed changes ===" >&2
95
+ diff -u "$FORMULA" "$TMP_FORMULA" || true
96
+ echo "" >&2
97
+ echo "Run without --dry-run to apply changes" >&2
98
+ exit 0
99
+ fi
100
+
101
+ # --- Apply changes ---
102
+ cp "$TMP_FORMULA" "$FORMULA"
103
+
104
+ # --- Validate ---
105
+ echo "=== Validating converted formula ===" >&2
106
+ if ruby -c "$FORMULA" >&2; then
107
+ echo "Formula syntax: OK" >&2
108
+ echo "Conversion complete: $FORMULA" >&2
109
+ else
110
+ echo "error: converted formula has syntax errors" >&2
111
+ exit 1
112
+ fi
@@ -0,0 +1,196 @@
1
+ #!/bin/bash
2
+ # workflows/create-tap.sh
3
+ # End-to-end workflow: analyze source, recommend template, scaffold tap.
4
+ set -euo pipefail
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
8
+ ANALYZE="${PROJECT_ROOT}/scripts/brew-analyze.sh"
9
+ TEMPLATE="${PROJECT_ROOT}/scripts/brew-template.sh"
10
+
11
+ # --- Defaults ---
12
+ SOURCE=""
13
+ NAME=""
14
+ TAP=""
15
+ OUTPUT=""
16
+ NON_INTERACTIVE=false
17
+ CONVERT_TO_BUN=false
18
+
19
+ # --- Usage ---
20
+ usage() {
21
+ cat << 'EOF'
22
+ Usage: create-tap.sh [OPTIONS]
23
+
24
+ Create a Homebrew tap from a source directory or GitHub URL.
25
+
26
+ Options:
27
+ --source <url|path> Source to analyze (GitHub URL or local directory)
28
+ --name <formula> Formula name (CamelCase or kebab-case)
29
+ --tap <user/tap> Tap identifier (e.g., user/homebrew-mytap)
30
+ --output <path> Output directory for the tap
31
+ --non-interactive Skip all prompts
32
+ --convert-to-bun Prefer bun over npm for node projects
33
+ --help Show this help message
34
+
35
+ Examples:
36
+ create-tap.sh --source https://github.com/user/cli-tool --name mycli --tap myuser/homebrew-mycli --output ./mytap --non-interactive
37
+ create-tap.sh --source /path/to/project --non-interactive
38
+ EOF
39
+ }
40
+
41
+ # --- Parse args ---
42
+ while [[ $# -gt 0 ]]; do
43
+ case "$1" in
44
+ --source) SOURCE="$2"; shift 2 ;;
45
+ --name) NAME="$2"; shift 2 ;;
46
+ --tap) TAP="$2"; shift 2 ;;
47
+ --output) OUTPUT="$2"; shift 2 ;;
48
+ --non-interactive) NON_INTERACTIVE=true; shift ;;
49
+ --convert-to-bun) CONVERT_TO_BUN=true; shift ;;
50
+ --help) usage; exit 0 ;;
51
+ *) echo "error: unknown option: $1" >&2; usage >&2; exit 1 ;;
52
+ esac
53
+ done
54
+
55
+ # --- Validate ---
56
+ if [[ -z "$SOURCE" ]]; then
57
+ echo "error: --source is required" >&2
58
+ usage >&2
59
+ exit 1
60
+ fi
61
+
62
+ # --- Interactive prompts ---
63
+ prompt() {
64
+ local var_name="$1"
65
+ local question="$2"
66
+ local default="${3:-}"
67
+ if $NON_INTERACTIVE; then
68
+ echo "error: $var_name is required in non-interactive mode" >&2
69
+ exit 1
70
+ fi
71
+ if [[ -n "$default" ]]; then
72
+ read -rp "$question [$default]: " val
73
+ val="${val:-$default}"
74
+ else
75
+ read -rp "$question: " val
76
+ fi
77
+ if [[ -z "$val" ]]; then
78
+ echo "error: $var_name cannot be empty" >&2
79
+ exit 1
80
+ fi
81
+ printf -v "$var_name" '%s' "$val"
82
+ }
83
+
84
+ # --- Analyze source ---
85
+ echo "=== Analyzing source: $SOURCE ===" >&2
86
+
87
+ if [[ -d "$SOURCE" ]]; then
88
+ ANALYSIS=$("$ANALYZE" --dir "$SOURCE" --json 2>/dev/null)
89
+ else
90
+ ANALYSIS=$("$ANALYZE" --url "$SOURCE" --json 2>/dev/null)
91
+ fi
92
+
93
+ TYPE=$(echo "$ANALYSIS" | python3 -c 'import sys,json; print(json.load(sys.stdin).get("type","unknown"))')
94
+ TEMPLATE_NUM=$(echo "$ANALYSIS" | python3 -c 'import sys,json; print(json.load(sys.stdin).get("template","02"))')
95
+ CONFIDENCE=$(echo "$ANALYSIS" | python3 -c 'import sys,json; print(json.load(sys.stdin).get("confidence","low"))')
96
+
97
+ echo "Detected type: $TYPE (template $TEMPLATE_NUM, confidence: $CONFIDENCE)" >&2
98
+
99
+ # --- Gather metadata ---
100
+ if [[ -z "$NAME" ]]; then
101
+ prompt NAME "Formula name (e.g., MyCli)"
102
+ fi
103
+
104
+ if [[ -z "$TAP" ]]; then
105
+ if [[ "$SOURCE" =~ github\.com/([^/]+)/([^/]+) ]]; then
106
+ DEFAULT_TAP="${BASH_REMATCH[1]}/homebrew-${BASH_REMATCH[2]}"
107
+ else
108
+ DEFAULT_TAP=""
109
+ fi
110
+ prompt TAP "Tap identifier (e.g., user/homebrew-mytap)" "$DEFAULT_TAP"
111
+ fi
112
+
113
+ # --- Auto-generate output directory ---
114
+ # Smart fallback:
115
+ # GitHub URL: github.com/owner/repo-name → ./repo-name
116
+ # Local path: /path/to/my-project → ./my-project
117
+ # Prepend "homebrew-" if not present
118
+ if [[ -z "$OUTPUT" ]]; then
119
+ if [[ "$SOURCE" =~ github\.com/([^/]+)/([^/]+)(\.git)?$ ]]; then
120
+ # GitHub URL: use repo name
121
+ repo_name="${BASH_REMATCH[2]}"
122
+ # Strip .git suffix if present
123
+ repo_name="${repo_name%.git}"
124
+ raw_name="$repo_name"
125
+ else
126
+ # Local path: use basename
127
+ raw_name=$(basename "$SOURCE")
128
+ fi
129
+
130
+ # Sanitize: lowercase, replace spaces with hyphens
131
+ raw_name=$(echo "$raw_name" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
132
+
133
+ # Prepend "homebrew-" if not already present
134
+ if [[ "$raw_name" == homebrew-* ]]; then
135
+ DEFAULT_OUTPUT="./${raw_name}"
136
+ else
137
+ DEFAULT_OUTPUT="./homebrew-${raw_name}"
138
+ fi
139
+
140
+ if $NON_INTERACTIVE; then
141
+ OUTPUT="$DEFAULT_OUTPUT"
142
+ echo "Auto-generated output directory: $OUTPUT" >&2
143
+ else
144
+ prompt OUTPUT "Output directory" "$DEFAULT_OUTPUT"
145
+ fi
146
+ fi
147
+
148
+ # --- Apply template ---
149
+ echo "=== Generating tap structure ===" >&2
150
+
151
+ TEMPLATE_ARGS=(
152
+ "$TYPE"
153
+ --name "$NAME"
154
+ --output "$OUTPUT"
155
+ )
156
+
157
+ if $CONVERT_TO_BUN; then
158
+ TEMPLATE_ARGS+=(--convert-to-bun)
159
+ fi
160
+
161
+ "$TEMPLATE" "${TEMPLATE_ARGS[@]}"
162
+
163
+ # --- Validate ---
164
+ FORMULA_FILE=""
165
+ for f in "$OUTPUT"/Formula/*.rb; do
166
+ if [[ -f "$f" ]]; then
167
+ FORMULA_FILE="$f"
168
+ break
169
+ fi
170
+ done
171
+
172
+ if [[ -n "$FORMULA_FILE" ]]; then
173
+ echo "=== Validating formula ===" >&2
174
+ if ruby -c "$FORMULA_FILE" >&2; then
175
+ echo "Formula syntax: OK" >&2
176
+ else
177
+ echo "Warning: formula has syntax errors" >&2
178
+ fi
179
+ fi
180
+
181
+ # --- Summary ---
182
+ echo "" >&2
183
+ echo "=== Tap Created ===" >&2
184
+ echo "Location: $(cd "$OUTPUT" && pwd)" >&2
185
+ echo "Tap: $TAP" >&2
186
+ echo "Formula: $NAME" >&2
187
+ echo "Template: $TEMPLATE_NUM ($TYPE)" >&2
188
+ echo "" >&2
189
+ echo "Next steps:" >&2
190
+ echo " 1. cd $(cd "$OUTPUT" && pwd)" >&2
191
+ echo " 2. Edit the formula in Formula/" >&2
192
+ echo " 3. Run: brew style --tap $TAP Formula/$NAME.rb" >&2
193
+ echo " 4. Run: brew audit --new-formula Formula/$NAME.rb" >&2
194
+ echo " 5. git init && git add . && git commit -m 'Initial commit'" >&2
195
+ echo " 6. git remote add origin https://github.com/$TAP.git" >&2
196
+ echo " 7. git push -u origin main" >&2