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,373 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ # brew-analyze.sh — Analyze a source directory or GitHub URL to determine package type
5
+ # and recommend a Homebrew tap template.
6
+
7
+
8
+ usage() {
9
+ cat <<EOF
10
+ Usage: $(basename "$0") [OPTIONS]
11
+
12
+ Analyze a source directory or GitHub URL to determine the project type and
13
+ recommend a Homebrew tap template.
14
+
15
+ Options:
16
+ --dir <path> Analyze a local directory
17
+ --url <github-url> Analyze a GitHub repository (shallow clone)
18
+ --json Output as JSON (default for non-TTY)
19
+ --human Output as human-readable report (default for TTY)
20
+ --help Show this help message
21
+
22
+ Examples:
23
+ $(basename "$0") --dir ./my-project --json
24
+ $(basename "$0") --url https://github.com/user/repo
25
+ EOF
26
+ }
27
+
28
+ # --- JSON helpers ---
29
+
30
+ json_escape() {
31
+ local str="$1"
32
+ str="${str//\\/\\\\}"
33
+ str="${str//\"/\\\"}"
34
+ str="${str//$'\n'/\\n}"
35
+ str="${str//$'\r'/\\r}"
36
+ str="${str//$'\t'/\\t}"
37
+ printf '%s' "$str"
38
+ }
39
+
40
+ json_array() {
41
+ local items=("$@")
42
+ local first=true
43
+ printf '['
44
+ for item in "${items[@]}"; do
45
+ if [ "$first" = true ]; then
46
+ first=false
47
+ else
48
+ printf ','
49
+ fi
50
+ printf '"%s"' "$(json_escape "$item")"
51
+ done
52
+ printf ']'
53
+ }
54
+
55
+ # --- Analysis functions ---
56
+
57
+ analyze_dir() {
58
+ local dir="$1"
59
+ local type="unknown"
60
+ local template="02"
61
+ local template_name="root-level"
62
+ local confidence="low"
63
+ local markers=()
64
+ local details=()
65
+
66
+ # 1. Cask: *.app bundle or Info.plist
67
+ if find "$dir" -maxdepth 2 -name "*.app" -type d 2>/dev/null | grep -q .; then
68
+ type="cask"
69
+ template="07"
70
+ template_name="cask-only"
71
+ confidence="high"
72
+ markers+=("*.app bundle")
73
+ details+=("has_app_bundle" "true")
74
+ elif [ -f "$dir/Info.plist" ]; then
75
+ type="cask"
76
+ template="07"
77
+ template_name="cask-only"
78
+ confidence="high"
79
+ markers+=("Info.plist")
80
+ details+=("has_info_plist" "true")
81
+ fi
82
+
83
+ # 2. Rust: Cargo.toml
84
+ if [ "$type" = "unknown" ] && [ -f "$dir/Cargo.toml" ]; then
85
+ type="rust"
86
+ template="01"
87
+ template_name="full-ci"
88
+ confidence="high"
89
+ markers+=("Cargo.toml")
90
+ local cargo_ver=""
91
+ cargo_ver=$(grep -m1 '^version' "$dir/Cargo.toml" 2>/dev/null | sed 's/.*= *"\([^"]*\)".*/\1/' || true)
92
+ [ -n "$cargo_ver" ] && details+=("cargo_version" "$cargo_ver")
93
+ details+=("has_tests" "$([ -d "$dir/src" ] && echo "true" || echo "false")")
94
+ details+=("has_ci" "$([ -d "$dir/.github" ] && echo "true" || echo "false")")
95
+ fi
96
+
97
+ # 3. Go binary: go.mod + (main.go or cmd/)
98
+ if [ "$type" = "unknown" ] && [ -f "$dir/go.mod" ]; then
99
+ local has_main=false
100
+ local has_cmd=false
101
+ [ -f "$dir/main.go" ] && has_main=true
102
+ [ -d "$dir/cmd" ] && has_cmd=true
103
+
104
+ if [ "$has_main" = true ] || [ "$has_cmd" = true ]; then
105
+ type="go-binary"
106
+ template="08"
107
+ template_name="go-binary"
108
+ confidence="high"
109
+ markers+=("go.mod")
110
+ [ "$has_main" = true ] && markers+=("main.go")
111
+ [ "$has_cmd" = true ] && markers+=("cmd/")
112
+
113
+ local go_ver=""
114
+ go_ver=$(grep -m1 '^go ' "$dir/go.mod" 2>/dev/null | awk '{print $2}' || true)
115
+ [ -n "$go_ver" ] && details+=("go_version" "$go_ver")
116
+
117
+ local entry_points=()
118
+ [ "$has_main" = true ] && entry_points+=("main.go")
119
+ [ "$has_cmd" = true ] && entry_points+=("cmd/")
120
+
121
+ details+=("has_tests" "$(find "$dir" -name '*_test.go' -print -quit 2>/dev/null | grep -q . && echo "true" || echo "false")")
122
+ details+=("has_ci" "$([ -d "$dir/.github" ] && echo "true" || echo "false")")
123
+ details+=("entry_points" "$(printf '%s' "${entry_points[*]}")")
124
+ fi
125
+ fi
126
+
127
+ # 4. Python venv: pyproject.toml or setup.py or requirements.txt
128
+ if [ "$type" = "unknown" ]; then
129
+ local has_pyproject=false
130
+ local has_setup=false
131
+ local has_reqs=false
132
+ [ -f "$dir/pyproject.toml" ] && has_pyproject=true
133
+ [ -f "$dir/setup.py" ] && has_setup=true
134
+ [ -f "$dir/requirements.txt" ] && has_reqs=true
135
+
136
+ if [ "$has_pyproject" = true ] || [ "$has_setup" = true ] || [ "$has_reqs" = true ]; then
137
+ type="python-venv"
138
+ template="04"
139
+ template_name="python-venv"
140
+ confidence="high"
141
+ [ "$has_pyproject" = true ] && markers+=("pyproject.toml")
142
+ [ "$has_setup" = true ] && markers+=("setup.py")
143
+ [ "$has_reqs" = true ] && markers+=("requirements.txt")
144
+
145
+ local py_ver=""
146
+ if [ "$has_pyproject" = true ]; then
147
+ py_ver=$(grep -m1 '^requires-python' "$dir/pyproject.toml" 2>/dev/null | sed 's/.*= *"\([^"]*\)".*/\1/' || true)
148
+ fi
149
+ [ -n "$py_ver" ] && details+=("python_version" "$py_ver")
150
+ details+=("has_tests" "$([ -d "$dir/tests" ] || [ -d "$dir/test" ] && echo "true" || echo "false")")
151
+ details+=("has_ci" "$([ -d "$dir/.github" ] && echo "true" || echo "false")")
152
+ fi
153
+ fi
154
+
155
+ # 5. Node npm: package.json with bin field
156
+ if [ "$type" = "unknown" ] && [ -f "$dir/package.json" ]; then
157
+ local has_bin=false
158
+ if grep -q '"bin"' "$dir/package.json" 2>/dev/null; then
159
+ has_bin=true
160
+ fi
161
+
162
+ if [ "$has_bin" = true ]; then
163
+ type="node-npm"
164
+ template="05"
165
+ template_name="node-npm"
166
+ confidence="high"
167
+ markers+=("package.json")
168
+ markers+=("bin field")
169
+
170
+ local node_ver=""
171
+ node_ver=$(grep -m1 '"node"' "$dir/package.json" 2>/dev/null | sed 's/.*: *"\([^"]*\)".*/\1/' || true)
172
+ [ -n "$node_ver" ] && details+=("node_version" "$node_ver")
173
+ details+=("has_tests" "$([ -d "$dir/test" ] || [ -d "$dir/tests" ] || [ -d "$dir/__tests__" ] && echo "true" || echo "false")")
174
+ details+=("has_ci" "$([ -d "$dir/.github" ] && echo "true" || echo "false")")
175
+ fi
176
+ fi
177
+
178
+ # 6. Full CI: Makefile or configure.ac or CMakeLists.txt
179
+ if [ "$type" = "unknown" ]; then
180
+ local has_makefile=false
181
+ local has_configure=false
182
+ local has_cmake=false
183
+ [ -f "$dir/Makefile" ] || [ -f "$dir/makefile" ] || [ -f "$dir/GNUmakefile" ] && has_makefile=true
184
+ [ -f "$dir/configure.ac" ] || [ -f "$dir/configure.in" ] && has_configure=true
185
+ [ -f "$dir/CMakeLists.txt" ] && has_cmake=true
186
+
187
+ if [ "$has_makefile" = true ] || [ "$has_configure" = true ] || [ "$has_cmake" = true ]; then
188
+ type="full-ci"
189
+ template="01"
190
+ template_name="full-ci"
191
+ confidence="high"
192
+ [ "$has_makefile" = true ] && markers+=("Makefile")
193
+ [ "$has_configure" = true ] && markers+=("configure.ac")
194
+ [ "$has_cmake" = true ] && markers+=("CMakeLists.txt")
195
+ details+=("has_tests" "$([ -d "$dir/tests" ] || [ -d "$dir/test" ] && echo "true" || echo "false")")
196
+ details+=("has_ci" "$([ -d "$dir/.github" ] && echo "true" || echo "false")")
197
+ fi
198
+ fi
199
+
200
+ # 7. Simple script: single .sh or .py file at root
201
+ if [ "$type" = "unknown" ]; then
202
+ local sh_count
203
+ local py_count
204
+ sh_count=$(find "$dir" -maxdepth 1 -name "*.sh" -type f 2>/dev/null | wc -l | tr -d ' ')
205
+ py_count=$(find "$dir" -maxdepth 1 -name "*.py" -type f 2>/dev/null | wc -l | tr -d ' ')
206
+
207
+ if [ "$sh_count" -eq 1 ] && [ "$py_count" -eq 0 ]; then
208
+ type="simple-script"
209
+ template="03"
210
+ template_name="simple-script"
211
+ confidence="medium"
212
+ markers+=("single .sh file")
213
+ local script_file
214
+ script_file=$(find "$dir" -maxdepth 1 -name "*.sh" -type f | head -1)
215
+ details+=("script_file" "$(basename "$script_file")")
216
+ elif [ "$py_count" -eq 1 ] && [ "$sh_count" -eq 0 ]; then
217
+ type="simple-script"
218
+ template="03"
219
+ template_name="simple-script"
220
+ confidence="medium"
221
+ markers+=("single .py file")
222
+ local script_file
223
+ script_file=$(find "$dir" -maxdepth 1 -name "*.py" -type f | head -1)
224
+ details+=("script_file" "$(basename "$script_file")")
225
+ fi
226
+ fi
227
+
228
+ # 8. Unknown fallback
229
+ if [ "$type" = "unknown" ]; then
230
+ confidence="low"
231
+ markers=()
232
+ fi
233
+
234
+ # Output results
235
+ local output_mode="json"
236
+ if [ -t 1 ] && [ "${HUMAN_FLAG:-}" != "true" ] && [ "${JSON_FLAG:-}" != "true" ]; then
237
+ output_mode="human"
238
+ elif [ "${HUMAN_FLAG:-}" = "true" ]; then
239
+ output_mode="human"
240
+ elif [ "${JSON_FLAG:-}" = "true" ]; then
241
+ output_mode="json"
242
+ fi
243
+
244
+ if [ "$output_mode" = "json" ]; then
245
+ printf '{'
246
+ printf '"type":"%s",' "$(json_escape "$type")"
247
+ printf '"template":"%s",' "$(json_escape "$template")"
248
+ printf '"template_name":"%s",' "$(json_escape "$template_name")"
249
+ printf '"confidence":"%s",' "$(json_escape "$confidence")"
250
+ printf '"markers":'
251
+ json_array "${markers[@]}"
252
+ printf ','
253
+ printf '"details":{'
254
+ local first_detail=true
255
+ local i=0
256
+ while [ $i -lt ${#details[@]} ]; do
257
+ local key="${details[$i]}"
258
+ local val="${details[$((i+1))]}"
259
+ if [ "$first_detail" = true ]; then
260
+ first_detail=false
261
+ else
262
+ printf ','
263
+ fi
264
+ printf '"%s":"%s"' "$(json_escape "$key")" "$(json_escape "$val")"
265
+ i=$((i+2))
266
+ done
267
+ printf '}'
268
+ printf '}\n'
269
+ else
270
+ printf 'Analysis Result\n'
271
+ printf '===============\n'
272
+ printf 'Type: %s\n' "$type"
273
+ printf 'Template: %s (%s)\n' "$template" "$template_name"
274
+ printf 'Confidence: %s\n' "$confidence"
275
+ printf 'Markers: %s\n' "${markers[*]:-none}"
276
+ printf 'Details:\n'
277
+ local i=0
278
+ while [ $i -lt ${#details[@]} ]; do
279
+ local key="${details[$i]}"
280
+ local val="${details[$((i+1))]}"
281
+ printf ' %s: %s\n' "$key" "$val"
282
+ i=$((i+2))
283
+ done
284
+ fi
285
+ }
286
+
287
+ # --- Main ---
288
+
289
+ DIR=""
290
+ URL=""
291
+ JSON_FLAG="false"
292
+ HUMAN_FLAG="false"
293
+
294
+ while [ $# -gt 0 ]; do
295
+ case "$1" in
296
+ --dir)
297
+ shift
298
+ if [ $# -eq 0 ]; then
299
+ echo "Error: --dir requires an argument" >&2
300
+ usage >&2
301
+ exit 1
302
+ fi
303
+ DIR="$1"
304
+ shift
305
+ ;;
306
+ --url)
307
+ shift
308
+ if [ $# -eq 0 ]; then
309
+ echo "Error: --url requires an argument" >&2
310
+ usage >&2
311
+ exit 1
312
+ fi
313
+ URL="$1"
314
+ shift
315
+ ;;
316
+ --json)
317
+ JSON_FLAG="true"
318
+ shift
319
+ ;;
320
+ --human)
321
+ HUMAN_FLAG="true"
322
+ shift
323
+ ;;
324
+ --help|-h)
325
+ usage
326
+ exit 0
327
+ ;;
328
+ *)
329
+ echo "Error: Unknown option: $1" >&2
330
+ usage >&2
331
+ exit 1
332
+ ;;
333
+ esac
334
+ done
335
+
336
+ if [ -n "$DIR" ] && [ -n "$URL" ]; then
337
+ echo "Error: Cannot specify both --dir and --url" >&2
338
+ exit 1
339
+ fi
340
+
341
+ if [ -z "$DIR" ] && [ -z "$URL" ]; then
342
+ echo "Error: Must specify either --dir or --url" >&2
343
+ usage >&2
344
+ exit 1
345
+ fi
346
+
347
+ if [ -n "$DIR" ]; then
348
+ if [ ! -d "$DIR" ]; then
349
+ echo "Error: Directory not found: $DIR" >&2
350
+ exit 1
351
+ fi
352
+ analyze_dir "$DIR"
353
+ fi
354
+
355
+ if [ -n "$URL" ]; then
356
+ # Validate GitHub URL
357
+ if ! [[ "$URL" =~ ^https://github\.com/ ]]; then
358
+ echo "Error: URL must be a GitHub repository URL" >&2
359
+ exit 1
360
+ fi
361
+
362
+ tmpdir=$(mktemp -d -p /tmp)
363
+ # shellcheck disable=SC2064
364
+ trap "rm -rf '$tmpdir'" EXIT
365
+
366
+ echo "Cloning $URL ..." >&2
367
+ if ! git clone --depth 1 "$URL" "$tmpdir" 2>/dev/null; then
368
+ echo "Error: Failed to clone repository" >&2
369
+ exit 1
370
+ fi
371
+
372
+ analyze_dir "$tmpdir"
373
+ fi
@@ -0,0 +1,140 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_NAME="$(basename "$0")"
5
+
6
+ usage() {
7
+ cat <<EOF
8
+ Usage: ${SCRIPT_NAME} [OPTIONS] <formula>
9
+
10
+ Show dependencies and reverse dependencies for a Homebrew formula.
11
+
12
+ Options:
13
+ --tree Show dependency tree (default)
14
+ --flat Show flat dependency list
15
+ --reverse, -r Show only reverse dependencies
16
+ --json Output as JSON
17
+ --help Show this help message
18
+
19
+ Examples:
20
+ ${SCRIPT_NAME} git
21
+ ${SCRIPT_NAME} --reverse git
22
+ ${SCRIPT_NAME} --json git
23
+ ${SCRIPT_NAME} --flat git
24
+ EOF
25
+ }
26
+
27
+ main() {
28
+ local show_tree=true
29
+ local show_reverse=false
30
+ local show_flat=false
31
+ local json_output=false
32
+ local formula=""
33
+
34
+ # Parse flags
35
+ while [[ $# -gt 0 ]]; do
36
+ case "$1" in
37
+ --help)
38
+ usage
39
+ exit 0
40
+ ;;
41
+ --tree)
42
+ show_tree=true
43
+ show_flat=false
44
+ shift
45
+ ;;
46
+ --flat)
47
+ show_flat=true
48
+ show_tree=false
49
+ shift
50
+ ;;
51
+ --reverse | --rev)
52
+ show_reverse=true
53
+ shift
54
+ ;;
55
+ --json)
56
+ json_output=true
57
+ shift
58
+ ;;
59
+ -*)
60
+ echo "Error: Unknown option $1" >&2
61
+ usage >&2
62
+ exit 1
63
+ ;;
64
+ *)
65
+ if [[ -z "$formula" ]]; then
66
+ formula="$1"
67
+ else
68
+ echo "Error: Only one formula argument allowed" >&2
69
+ usage >&2
70
+ exit 1
71
+ fi
72
+ shift
73
+ ;;
74
+ esac
75
+ done
76
+
77
+ if [[ -z "$formula" ]]; then
78
+ echo "Error: No formula specified" >&2
79
+ usage >&2
80
+ exit 1
81
+ fi
82
+
83
+ # Validate formula exists
84
+ if ! brew info "$formula" >/dev/null 2>&1; then
85
+ echo "Error: Formula '${formula}' not found" >&2
86
+ exit 1
87
+ fi
88
+
89
+ if [[ "$json_output" == true ]]; then
90
+ # JSON output: capture deps and reverse deps as arrays
91
+ local deps_json revdeps_json
92
+
93
+ deps_json=$(brew deps --include-build "$formula" 2>/dev/null | jq -R . | jq -s . || echo "[]")
94
+ revdeps_json=$(brew uses --recursive --installed "$formula" 2>/dev/null | jq -R . | jq -s . || echo "[]")
95
+
96
+ cat <<EOF
97
+ {
98
+ "formula": "${formula}",
99
+ "dependencies": ${deps_json},
100
+ "reverse_dependencies": ${revdeps_json}
101
+ }
102
+ EOF
103
+ exit 0
104
+ fi
105
+
106
+ if [[ "$show_reverse" == true ]]; then
107
+ echo "=== Reverse Dependencies ==="
108
+ echo ""
109
+ if ! brew uses --recursive --installed "$formula" 2>/dev/null; then
110
+ echo " (none)"
111
+ fi
112
+ exit 0
113
+ fi
114
+
115
+ if [[ "$show_flat" == true ]]; then
116
+ echo "=== Dependencies ==="
117
+ echo ""
118
+ brew deps --include-build "$formula" 2>/dev/null || true
119
+ echo ""
120
+ echo "=== Reverse Dependencies ==="
121
+ echo ""
122
+ if ! brew uses --recursive --installed "$formula" 2>/dev/null; then
123
+ echo " (none)"
124
+ fi
125
+ exit 0
126
+ fi
127
+
128
+ # Default: tree view
129
+ echo "=== Dependencies ==="
130
+ echo ""
131
+ brew deps --tree --include-build "$formula" 2>/dev/null || true
132
+ echo ""
133
+ echo "=== Reverse Dependencies ==="
134
+ echo ""
135
+ if ! brew uses --recursive --installed "$formula" 2>/dev/null; then
136
+ echo " (none)"
137
+ fi
138
+ }
139
+
140
+ main "$@"