super-opencode 1.1.2 → 1.2.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.
- package/.opencode/agents/architect.md +54 -31
- package/.opencode/agents/backend.md +61 -34
- package/.opencode/agents/data-agent.md +422 -0
- package/.opencode/agents/devops-agent.md +331 -0
- package/.opencode/agents/frontend.md +63 -36
- package/.opencode/agents/mobile-agent.md +636 -0
- package/.opencode/agents/optimizer.md +25 -18
- package/.opencode/agents/pm-agent.md +114 -50
- package/.opencode/agents/quality.md +36 -29
- package/.opencode/agents/researcher.md +30 -21
- package/.opencode/agents/reviewer.md +39 -32
- package/.opencode/agents/security.md +42 -34
- package/.opencode/agents/writer.md +42 -31
- package/.opencode/commands/soc-analyze.md +55 -31
- package/.opencode/commands/soc-brainstorm.md +48 -26
- package/.opencode/commands/soc-cleanup.md +47 -25
- package/.opencode/commands/soc-deploy.md +271 -0
- package/.opencode/commands/soc-design.md +51 -26
- package/.opencode/commands/soc-explain.md +46 -23
- package/.opencode/commands/soc-git.md +47 -25
- package/.opencode/commands/soc-help.md +35 -14
- package/.opencode/commands/soc-implement.md +59 -29
- package/.opencode/commands/soc-improve.md +42 -20
- package/.opencode/commands/soc-onboard.md +329 -0
- package/.opencode/commands/soc-plan.md +215 -0
- package/.opencode/commands/soc-pm.md +40 -18
- package/.opencode/commands/soc-research.md +43 -20
- package/.opencode/commands/soc-review.md +39 -18
- package/.opencode/commands/soc-test.md +43 -21
- package/.opencode/commands/soc-validate.md +221 -0
- package/.opencode/commands/soc-workflow.md +38 -17
- package/.opencode/skills/confidence-check/SKILL.md +26 -19
- package/.opencode/skills/debug-protocol/SKILL.md +27 -17
- package/.opencode/skills/decision-log/SKILL.md +236 -0
- package/.opencode/skills/doc-sync/SKILL.md +345 -0
- package/.opencode/skills/package-manager/SKILL.md +502 -0
- package/.opencode/skills/package-manager/scripts/README.md +106 -0
- package/.opencode/skills/package-manager/scripts/detect-package-manager.sh +796 -0
- package/.opencode/skills/reflexion/SKILL.md +18 -11
- package/.opencode/skills/security-audit/SKILL.md +19 -14
- package/.opencode/skills/self-check/SKILL.md +30 -14
- package/.opencode/skills/simplification/SKILL.md +19 -5
- package/.opencode/skills/tech-debt/SKILL.md +245 -0
- package/LICENSE +1 -1
- package/README.md +126 -9
- package/dist/cli.js +143 -41
- package/package.json +27 -12
- package/.opencode/settings.json +0 -3
|
@@ -0,0 +1,796 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# Multi-Language Package Manager Detection Script (Bash 3.2 Compatible)
|
|
4
|
+
# Detects package managers for JavaScript, Python, Go, Rust, Java, Ruby, PHP, .NET, and more
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# ./detect-package-manager.sh [options] [language]
|
|
8
|
+
#
|
|
9
|
+
# Options:
|
|
10
|
+
# --json Output results as JSON
|
|
11
|
+
# --quiet Only output errors
|
|
12
|
+
# --recommend Show recommendation only
|
|
13
|
+
# --all Detect for all languages found
|
|
14
|
+
# --help Show this help message
|
|
15
|
+
#
|
|
16
|
+
# Language (optional, auto-detected if not specified):
|
|
17
|
+
# javascript, python, go, rust, java, ruby, php, dotnet, elixir, haskell, etc.
|
|
18
|
+
#
|
|
19
|
+
# Exit codes:
|
|
20
|
+
# 0 - Success
|
|
21
|
+
# 1 - No package manager detected
|
|
22
|
+
# 2 - Error reading project files
|
|
23
|
+
#
|
|
24
|
+
|
|
25
|
+
# Colors for output (only in non-JSON mode)
|
|
26
|
+
RED='\033[0;31m'
|
|
27
|
+
GREEN='\033[0;32m'
|
|
28
|
+
YELLOW='\033[1;33m'
|
|
29
|
+
BLUE='\033[0;34m'
|
|
30
|
+
CYAN='\033[0;36m'
|
|
31
|
+
NC='\033[0m' # No Color
|
|
32
|
+
|
|
33
|
+
# Parse arguments
|
|
34
|
+
JSON_OUTPUT=false
|
|
35
|
+
QUIET=false
|
|
36
|
+
RECOMMEND_ONLY=false
|
|
37
|
+
DETECT_ALL=false
|
|
38
|
+
SPECIFIED_LANGUAGE=""
|
|
39
|
+
|
|
40
|
+
while [[ $# -gt 0 ]]; do
|
|
41
|
+
case $1 in
|
|
42
|
+
--json)
|
|
43
|
+
JSON_OUTPUT=true
|
|
44
|
+
shift
|
|
45
|
+
;;
|
|
46
|
+
--quiet)
|
|
47
|
+
QUIET=true
|
|
48
|
+
shift
|
|
49
|
+
;;
|
|
50
|
+
--recommend)
|
|
51
|
+
RECOMMEND_ONLY=true
|
|
52
|
+
shift
|
|
53
|
+
;;
|
|
54
|
+
--all)
|
|
55
|
+
DETECT_ALL=true
|
|
56
|
+
shift
|
|
57
|
+
;;
|
|
58
|
+
--help)
|
|
59
|
+
echo "Multi-Language Package Manager Detection Script"
|
|
60
|
+
echo ""
|
|
61
|
+
echo "Usage: $0 [options] [language]"
|
|
62
|
+
echo ""
|
|
63
|
+
echo "Options:"
|
|
64
|
+
echo " --json Output results as JSON"
|
|
65
|
+
echo " --quiet Only output errors"
|
|
66
|
+
echo " --recommend Show recommendation only"
|
|
67
|
+
echo " --all Detect for all languages found"
|
|
68
|
+
echo " --help Show this help message"
|
|
69
|
+
echo ""
|
|
70
|
+
echo "Languages (auto-detected if not specified):"
|
|
71
|
+
echo " javascript - npm, yarn, pnpm, bun"
|
|
72
|
+
echo " python - pip, poetry, uv, conda, pipenv"
|
|
73
|
+
echo " go - go modules"
|
|
74
|
+
echo " rust - cargo"
|
|
75
|
+
echo " java - maven, gradle"
|
|
76
|
+
echo " ruby - bundler"
|
|
77
|
+
echo " php - composer"
|
|
78
|
+
echo " dotnet - nuget"
|
|
79
|
+
echo " elixir - mix"
|
|
80
|
+
echo " haskell - cabal, stack"
|
|
81
|
+
echo " c/cpp - cmake, conan, vcpkg"
|
|
82
|
+
echo " swift - swift package manager"
|
|
83
|
+
echo " kotlin - gradle"
|
|
84
|
+
echo " scala - sbt"
|
|
85
|
+
echo " clojure - leiningen, deps.edn"
|
|
86
|
+
echo " julia - pkg"
|
|
87
|
+
echo " r - renv, packrat"
|
|
88
|
+
echo ""
|
|
89
|
+
echo "Examples:"
|
|
90
|
+
echo " $0 # Auto-detect language and PM"
|
|
91
|
+
echo " $0 --json # JSON output"
|
|
92
|
+
echo " $0 python # Detect Python PM only"
|
|
93
|
+
echo " $0 --all --json # Detect all languages in project"
|
|
94
|
+
exit 0
|
|
95
|
+
;;
|
|
96
|
+
--*)
|
|
97
|
+
echo "Unknown option: $1"
|
|
98
|
+
echo "Use --help for usage information"
|
|
99
|
+
exit 1
|
|
100
|
+
;;
|
|
101
|
+
*)
|
|
102
|
+
# Assume it's a language specification
|
|
103
|
+
SPECIFIED_LANGUAGE="$1"
|
|
104
|
+
shift
|
|
105
|
+
;;
|
|
106
|
+
esac
|
|
107
|
+
done
|
|
108
|
+
|
|
109
|
+
# Logging function
|
|
110
|
+
log() {
|
|
111
|
+
if [[ "$QUIET" == false && "$JSON_OUTPUT" == false && "$RECOMMEND_ONLY" == false ]]; then
|
|
112
|
+
echo -e "$1"
|
|
113
|
+
fi
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
# Error function
|
|
117
|
+
error() {
|
|
118
|
+
if [[ "$JSON_OUTPUT" == false ]]; then
|
|
119
|
+
echo -e "${RED}Error: $1${NC}" >&2
|
|
120
|
+
else
|
|
121
|
+
echo "{\"error\": \"$1\"}" >&2
|
|
122
|
+
fi
|
|
123
|
+
exit 2
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
# Get project root
|
|
127
|
+
PROJECT_ROOT="${PWD}"
|
|
128
|
+
|
|
129
|
+
# Initialize results list
|
|
130
|
+
DETECTED_LANGS=""
|
|
131
|
+
|
|
132
|
+
# ============================================
|
|
133
|
+
# LANGUAGE DETECTION FUNCTIONS
|
|
134
|
+
# Each function outputs: pm|version|method|lockfile|confidence|config|field
|
|
135
|
+
# ============================================
|
|
136
|
+
|
|
137
|
+
# JavaScript/TypeScript
|
|
138
|
+
detect_javascript() {
|
|
139
|
+
local pm=""
|
|
140
|
+
local ver=""
|
|
141
|
+
local meth=""
|
|
142
|
+
local lock=""
|
|
143
|
+
local conf=0
|
|
144
|
+
local cfg=""
|
|
145
|
+
local field=""
|
|
146
|
+
|
|
147
|
+
# Check lockfiles
|
|
148
|
+
if [[ -f "${PROJECT_ROOT}/pnpm-lock.yaml" ]]; then
|
|
149
|
+
pm="pnpm"; lock="pnpm-lock.yaml"; meth="lockfile"; conf=95
|
|
150
|
+
elif [[ -f "${PROJECT_ROOT}/yarn.lock" ]]; then
|
|
151
|
+
pm="yarn"; lock="yarn.lock"; meth="lockfile"; conf=90
|
|
152
|
+
elif [[ -f "${PROJECT_ROOT}/package-lock.json" ]]; then
|
|
153
|
+
pm="npm"; lock="package-lock.json"; meth="lockfile"; conf=90
|
|
154
|
+
elif [[ -f "${PROJECT_ROOT}/bun.lockb" ]]; then
|
|
155
|
+
pm="bun"; lock="bun.lockb"; meth="lockfile"; conf=95
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# Check package.json for packageManager field
|
|
159
|
+
if [[ -f "${PROJECT_ROOT}/package.json" ]]; then
|
|
160
|
+
field=$(cat "${PROJECT_ROOT}/package.json" 2>/dev/null | grep -o '"packageManager"[^,]*' | head -1 || true)
|
|
161
|
+
if [[ -n "$field" ]]; then
|
|
162
|
+
local pm_from=$(echo "$field" | grep -o 'npm\|yarn\|pnpm\|bun' | head -1 || true)
|
|
163
|
+
local ver_from=$(echo "$field" | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -1 || true)
|
|
164
|
+
if [[ -n "$pm_from" ]]; then
|
|
165
|
+
pm="$pm_from"; ver="$ver_from"; meth="package.json"; conf=100
|
|
166
|
+
fi
|
|
167
|
+
fi
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
# Check for monorepo
|
|
171
|
+
if [[ -z "$pm" ]]; then
|
|
172
|
+
if [[ -f "${PROJECT_ROOT}/pnpm-workspace.yaml" || -d "${PROJECT_ROOT}/packages" ]]; then
|
|
173
|
+
pm="pnpm"; meth="monorepo"; conf=80
|
|
174
|
+
elif [[ -f "${PROJECT_ROOT}/package.json" ]]; then
|
|
175
|
+
pm="npm"; meth="default"; conf=60
|
|
176
|
+
fi
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
# Get installed version
|
|
180
|
+
if [[ -z "$ver" ]]; then
|
|
181
|
+
case "$pm" in
|
|
182
|
+
npm) ver=$(npm --version 2>/dev/null || echo "") ;;
|
|
183
|
+
yarn) ver=$(yarn --version 2>/dev/null || echo "") ;;
|
|
184
|
+
pnpm) ver=$(pnpm --version 2>/dev/null || echo "") ;;
|
|
185
|
+
bun) ver=$(bun --version 2>/dev/null || echo "") ;;
|
|
186
|
+
esac
|
|
187
|
+
fi
|
|
188
|
+
|
|
189
|
+
if [[ -n "$pm" ]]; then
|
|
190
|
+
echo "javascript|$pm|$ver|$meth|$lock|$conf|$cfg|$field"
|
|
191
|
+
return 0
|
|
192
|
+
fi
|
|
193
|
+
return 1
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
# Python
|
|
197
|
+
detect_python() {
|
|
198
|
+
local pm=""
|
|
199
|
+
local ver=""
|
|
200
|
+
local meth=""
|
|
201
|
+
local lock=""
|
|
202
|
+
local conf=0
|
|
203
|
+
local cfg=""
|
|
204
|
+
|
|
205
|
+
if [[ -f "${PROJECT_ROOT}/uv.lock" ]]; then
|
|
206
|
+
pm="uv"; lock="uv.lock"; meth="lockfile"; conf=95
|
|
207
|
+
elif [[ -f "${PROJECT_ROOT}/poetry.lock" ]]; then
|
|
208
|
+
pm="poetry"; lock="poetry.lock"; meth="lockfile"; conf=95
|
|
209
|
+
elif [[ -f "${PROJECT_ROOT}/Pipfile.lock" ]]; then
|
|
210
|
+
pm="pipenv"; lock="Pipfile.lock"; meth="lockfile"; conf=95
|
|
211
|
+
elif [[ -f "${PROJECT_ROOT}/conda-lock.yml" || -f "${PROJECT_ROOT}/environment.yml" ]]; then
|
|
212
|
+
pm="conda"; cfg="environment.yml"; meth="environment file"; conf=90
|
|
213
|
+
elif [[ -f "${PROJECT_ROOT}/requirements.txt" ]]; then
|
|
214
|
+
pm="pip"; lock="requirements.txt"; meth="requirements file"; conf=85
|
|
215
|
+
elif [[ -f "${PROJECT_ROOT}/pyproject.toml" ]]; then
|
|
216
|
+
if grep -q "\[tool.poetry\]" "${PROJECT_ROOT}/pyproject.toml" 2>/dev/null; then
|
|
217
|
+
pm="poetry"; meth="pyproject.toml"; conf=90
|
|
218
|
+
elif grep -q "\[tool.uv\]" "${PROJECT_ROOT}/pyproject.toml" 2>/dev/null; then
|
|
219
|
+
pm="uv"; meth="pyproject.toml"; conf=90
|
|
220
|
+
elif grep -q "\[build-system\]" "${PROJECT_ROOT}/pyproject.toml" 2>/dev/null; then
|
|
221
|
+
pm="pip"; meth="pyproject.toml"; conf=70
|
|
222
|
+
fi
|
|
223
|
+
elif [[ -f "${PROJECT_ROOT}/setup.py" || -f "${PROJECT_ROOT}/setup.cfg" ]]; then
|
|
224
|
+
pm="pip"; meth="legacy setup"; conf=70
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
if [[ -z "$ver" ]]; then
|
|
228
|
+
case "$pm" in
|
|
229
|
+
pip) ver=$(pip --version 2>/dev/null | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -1 || echo "") ;;
|
|
230
|
+
poetry) ver=$(poetry --version 2>/dev/null | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -1 || echo "") ;;
|
|
231
|
+
uv) ver=$(uv --version 2>/dev/null | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -1 || echo "") ;;
|
|
232
|
+
conda) ver=$(conda --version 2>/dev/null | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -1 || echo "") ;;
|
|
233
|
+
pipenv) ver=$(pipenv --version 2>/dev/null | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -1 || echo "") ;;
|
|
234
|
+
esac
|
|
235
|
+
fi
|
|
236
|
+
|
|
237
|
+
if [[ -n "$pm" ]]; then
|
|
238
|
+
echo "python|$pm|$ver|$meth|$lock|$conf|$cfg|"
|
|
239
|
+
return 0
|
|
240
|
+
fi
|
|
241
|
+
return 1
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
# Go
|
|
245
|
+
detect_go() {
|
|
246
|
+
if [[ -f "${PROJECT_ROOT}/go.mod" || -f "${PROJECT_ROOT}/go.sum" ]]; then
|
|
247
|
+
local ver=$(go version 2>/dev/null | grep -o 'go[0-9]\+\.[0-9]\+' || echo "")
|
|
248
|
+
echo "go|go modules|$ver|go.mod|go.sum|95||"
|
|
249
|
+
return 0
|
|
250
|
+
fi
|
|
251
|
+
return 1
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
# Rust
|
|
255
|
+
detect_rust() {
|
|
256
|
+
if [[ -f "${PROJECT_ROOT}/Cargo.toml" || -f "${PROJECT_ROOT}/Cargo.lock" ]]; then
|
|
257
|
+
local ver=$(cargo --version 2>/dev/null | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' || echo "")
|
|
258
|
+
echo "rust|cargo|$ver|Cargo.toml|Cargo.lock|95||"
|
|
259
|
+
return 0
|
|
260
|
+
fi
|
|
261
|
+
return 1
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
# Java
|
|
265
|
+
detect_java() {
|
|
266
|
+
local pm=""
|
|
267
|
+
local lock=""
|
|
268
|
+
local conf=0
|
|
269
|
+
|
|
270
|
+
if [[ -f "${PROJECT_ROOT}/pom.xml" ]]; then
|
|
271
|
+
pm="maven"; conf=95
|
|
272
|
+
elif [[ -f "${PROJECT_ROOT}/build.gradle" || -f "${PROJECT_ROOT}/build.gradle.kts" ]]; then
|
|
273
|
+
pm="gradle"; conf=95
|
|
274
|
+
elif [[ -f "${PROJECT_ROOT}/gradle.lockfile" ]]; then
|
|
275
|
+
pm="gradle"; lock="gradle.lockfile"; conf=95
|
|
276
|
+
fi
|
|
277
|
+
|
|
278
|
+
if [[ -n "$pm" ]]; then
|
|
279
|
+
local ver=""
|
|
280
|
+
if [[ "$pm" == "maven" ]]; then
|
|
281
|
+
ver=$(mvn --version 2>/dev/null | head -1 | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -1 || echo "")
|
|
282
|
+
else
|
|
283
|
+
ver=$(gradle --version 2>/dev/null | grep "Gradle" | grep -o '[0-9]\+\.[0-9]\+' | head -1 || echo "")
|
|
284
|
+
fi
|
|
285
|
+
echo "java|$pm|$ver|build file|$lock|$conf||"
|
|
286
|
+
return 0
|
|
287
|
+
fi
|
|
288
|
+
return 1
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
# Ruby
|
|
292
|
+
detect_ruby() {
|
|
293
|
+
if [[ -f "${PROJECT_ROOT}/Gemfile" || -f "${PROJECT_ROOT}/Gemfile.lock" ]]; then
|
|
294
|
+
local ver=$(bundle --version 2>/dev/null | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' || echo "")
|
|
295
|
+
echo "ruby|bundler|$ver|Gemfile|Gemfile.lock|95||"
|
|
296
|
+
return 0
|
|
297
|
+
fi
|
|
298
|
+
return 1
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
# PHP
|
|
302
|
+
detect_php() {
|
|
303
|
+
if [[ -f "${PROJECT_ROOT}/composer.json" || -f "${PROJECT_ROOT}/composer.lock" ]]; then
|
|
304
|
+
local ver=$(composer --version 2>/dev/null | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -1 || echo "")
|
|
305
|
+
echo "php|composer|$ver|composer.json|composer.lock|95||"
|
|
306
|
+
return 0
|
|
307
|
+
fi
|
|
308
|
+
return 1
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
# .NET
|
|
312
|
+
detect_dotnet() {
|
|
313
|
+
local found=false
|
|
314
|
+
for f in "${PROJECT_ROOT}"/*.csproj "${PROJECT_ROOT}"/*.fsproj "${PROJECT_ROOT}"/*.vbproj; do
|
|
315
|
+
[[ -f "$f" ]] && found=true && break
|
|
316
|
+
done
|
|
317
|
+
|
|
318
|
+
if [[ "$found" == true || -n "$(ls "${PROJECT_ROOT}"/*.sln 2>/dev/null)" || -f "${PROJECT_ROOT}/packages.config" ]]; then
|
|
319
|
+
local ver=$(dotnet --version 2>/dev/null || echo "")
|
|
320
|
+
echo "dotnet|nuget|$ver|project file|packages.lock.json|90||"
|
|
321
|
+
return 0
|
|
322
|
+
fi
|
|
323
|
+
return 1
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
# Elixir
|
|
327
|
+
detect_elixir() {
|
|
328
|
+
if [[ -f "${PROJECT_ROOT}/mix.exs" || -f "${PROJECT_ROOT}/mix.lock" ]]; then
|
|
329
|
+
local ver=$(mix --version 2>/dev/null | head -1 | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' || echo "")
|
|
330
|
+
echo "elixir|mix|$ver|mix.exs|mix.lock|95||"
|
|
331
|
+
return 0
|
|
332
|
+
fi
|
|
333
|
+
return 1
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
# Haskell
|
|
337
|
+
detect_haskell() {
|
|
338
|
+
local pm=""
|
|
339
|
+
local lock=""
|
|
340
|
+
|
|
341
|
+
if [[ -f "${PROJECT_ROOT}/stack.yaml" || -f "${PROJECT_ROOT}/stack.yaml.lock" ]]; then
|
|
342
|
+
pm="stack"; lock="stack.yaml.lock"
|
|
343
|
+
else
|
|
344
|
+
for f in "${PROJECT_ROOT}"/*.cabal; do
|
|
345
|
+
[[ -f "$f" ]] && pm="cabal" && lock="cabal.project.freeze" && break
|
|
346
|
+
done
|
|
347
|
+
fi
|
|
348
|
+
|
|
349
|
+
if [[ -n "$pm" ]]; then
|
|
350
|
+
local ver=""
|
|
351
|
+
if [[ "$pm" == "stack" ]]; then
|
|
352
|
+
ver=$(stack --version 2>/dev/null | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -1 || echo "")
|
|
353
|
+
else
|
|
354
|
+
ver=$(cabal --version 2>/dev/null | head -1 | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' || echo "")
|
|
355
|
+
fi
|
|
356
|
+
echo "haskell|$pm|$ver|config file|$lock|90||"
|
|
357
|
+
return 0
|
|
358
|
+
fi
|
|
359
|
+
return 1
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
# C/C++
|
|
363
|
+
detect_cpp() {
|
|
364
|
+
local pm=""
|
|
365
|
+
|
|
366
|
+
if [[ -f "${PROJECT_ROOT}/conanfile.txt" || -f "${PROJECT_ROOT}/conanfile.py" ]]; then
|
|
367
|
+
pm="conan"
|
|
368
|
+
elif [[ -f "${PROJECT_ROOT}/vcpkg.json" ]]; then
|
|
369
|
+
pm="vcpkg"
|
|
370
|
+
fi
|
|
371
|
+
|
|
372
|
+
if [[ -n "$pm" ]]; then
|
|
373
|
+
echo "cpp|$pm||config file||85||"
|
|
374
|
+
return 0
|
|
375
|
+
fi
|
|
376
|
+
return 1
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
# Swift
|
|
380
|
+
detect_swift() {
|
|
381
|
+
if [[ -f "${PROJECT_ROOT}/Package.swift" || -f "${PROJECT_ROOT}/Package.resolved" ]]; then
|
|
382
|
+
local ver=$(swift --version 2>/dev/null | head -1 | grep -o '[0-9]\+\.[0-9]\+' | head -1 || echo "")
|
|
383
|
+
echo "swift|swift package manager|$ver|Package.swift|Package.resolved|95||"
|
|
384
|
+
return 0
|
|
385
|
+
fi
|
|
386
|
+
return 1
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
# Scala
|
|
390
|
+
detect_scala() {
|
|
391
|
+
if [[ -f "${PROJECT_ROOT}/build.sbt" ]]; then
|
|
392
|
+
local ver=""
|
|
393
|
+
if command -v sbt &> /dev/null; then
|
|
394
|
+
ver=$(sbt sbtVersion 2>/dev/null | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' | head -1 || echo "")
|
|
395
|
+
fi
|
|
396
|
+
echo "scala|sbt|$ver|build.sbt||95||"
|
|
397
|
+
return 0
|
|
398
|
+
fi
|
|
399
|
+
return 1
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
# Clojure
|
|
403
|
+
detect_clojure() {
|
|
404
|
+
local pm=""
|
|
405
|
+
|
|
406
|
+
if [[ -f "${PROJECT_ROOT}/project.clj" ]]; then
|
|
407
|
+
pm="leiningen"
|
|
408
|
+
elif [[ -f "${PROJECT_ROOT}/deps.edn" ]]; then
|
|
409
|
+
pm="tools.deps"
|
|
410
|
+
fi
|
|
411
|
+
|
|
412
|
+
if [[ -n "$pm" ]]; then
|
|
413
|
+
echo "clojure|$pm||project file||90||"
|
|
414
|
+
return 0
|
|
415
|
+
fi
|
|
416
|
+
return 1
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
# Julia
|
|
420
|
+
detect_julia() {
|
|
421
|
+
if [[ -f "${PROJECT_ROOT}/Project.toml" || -f "${PROJECT_ROOT}/Manifest.toml" || -f "${PROJECT_ROOT}/JuliaProject.toml" ]]; then
|
|
422
|
+
local ver=$(julia --version 2>/dev/null | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+' || echo "")
|
|
423
|
+
echo "julia|Pkg|$ver|Project.toml|Manifest.toml|95||"
|
|
424
|
+
return 0
|
|
425
|
+
fi
|
|
426
|
+
return 1
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
# R
|
|
430
|
+
detect_r() {
|
|
431
|
+
if [[ -f "${PROJECT_ROOT}/renv.lock" || -d "${PROJECT_ROOT}/renv" || -f "${PROJECT_ROOT}/packrat.lock" ]]; then
|
|
432
|
+
local pm="renv"
|
|
433
|
+
[[ -f "${PROJECT_ROOT}/packrat.lock" ]] && pm="packrat"
|
|
434
|
+
echo "r|$pm||lockfile|${pm}.lock|95||"
|
|
435
|
+
return 0
|
|
436
|
+
fi
|
|
437
|
+
return 1
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
# ============================================
|
|
441
|
+
# DETECT ALL LANGUAGES
|
|
442
|
+
# ============================================
|
|
443
|
+
detect_all() {
|
|
444
|
+
local result=""
|
|
445
|
+
|
|
446
|
+
if [[ -n "$SPECIFIED_LANGUAGE" ]]; then
|
|
447
|
+
# Detect specific language only
|
|
448
|
+
case "$SPECIFIED_LANGUAGE" in
|
|
449
|
+
javascript|js|node|nodejs) result=$(detect_javascript) ;;
|
|
450
|
+
python|py) result=$(detect_python) ;;
|
|
451
|
+
go|golang) result=$(detect_go) ;;
|
|
452
|
+
rust|rs) result=$(detect_rust) ;;
|
|
453
|
+
java) result=$(detect_java) ;;
|
|
454
|
+
ruby|rb) result=$(detect_ruby) ;;
|
|
455
|
+
php) result=$(detect_php) ;;
|
|
456
|
+
dotnet|csharp|cs|fsharp|fs|vb) result=$(detect_dotnet) ;;
|
|
457
|
+
elixir|ex|exs) result=$(detect_elixir) ;;
|
|
458
|
+
haskell|hs|cabal|stack) result=$(detect_haskell) ;;
|
|
459
|
+
cpp|c++|c|conan|vcpkg|cmake) result=$(detect_cpp) ;;
|
|
460
|
+
swift) result=$(detect_swift) ;;
|
|
461
|
+
scala) result=$(detect_scala) ;;
|
|
462
|
+
clojure|clj) result=$(detect_clojure) ;;
|
|
463
|
+
julia|jl) result=$(detect_julia) ;;
|
|
464
|
+
r) result=$(detect_r) ;;
|
|
465
|
+
*) error "Unknown language: $SPECIFIED_LANGUAGE" ;;
|
|
466
|
+
esac
|
|
467
|
+
[[ -n "$result" ]] && DETECTED_LANGS="$result"
|
|
468
|
+
else
|
|
469
|
+
# Auto-detect all languages
|
|
470
|
+
result=$(detect_javascript); [[ -n "$result" ]] && DETECTED_LANGS="${DETECTED_LANGS}${DETECTED_LANGS:+,}$result"
|
|
471
|
+
result=$(detect_python); [[ -n "$result" ]] && DETECTED_LANGS="${DETECTED_LANGS}${DETECTED_LANGS:+,}$result"
|
|
472
|
+
result=$(detect_go); [[ -n "$result" ]] && DETECTED_LANGS="${DETECTED_LANGS}${DETECTED_LANGS:+,}$result"
|
|
473
|
+
result=$(detect_rust); [[ -n "$result" ]] && DETECTED_LANGS="${DETECTED_LANGS}${DETECTED_LANGS:+,}$result"
|
|
474
|
+
result=$(detect_java); [[ -n "$result" ]] && DETECTED_LANGS="${DETECTED_LANGS}${DETECTED_LANGS:+,}$result"
|
|
475
|
+
result=$(detect_ruby); [[ -n "$result" ]] && DETECTED_LANGS="${DETECTED_LANGS}${DETECTED_LANGS:+,}$result"
|
|
476
|
+
result=$(detect_php); [[ -n "$result" ]] && DETECTED_LANGS="${DETECTED_LANGS}${DETECTED_LANGS:+,}$result"
|
|
477
|
+
result=$(detect_dotnet); [[ -n "$result" ]] && DETECTED_LANGS="${DETECTED_LANGS}${DETECTED_LANGS:+,}$result"
|
|
478
|
+
result=$(detect_elixir); [[ -n "$result" ]] && DETECTED_LANGS="${DETECTED_LANGS}${DETECTED_LANGS:+,}$result"
|
|
479
|
+
result=$(detect_haskell); [[ -n "$result" ]] && DETECTED_LANGS="${DETECTED_LANGS}${DETECTED_LANGS:+,}$result"
|
|
480
|
+
result=$(detect_cpp); [[ -n "$result" ]] && DETECTED_LANGS="${DETECTED_LANGS}${DETECTED_LANGS:+,}$result"
|
|
481
|
+
result=$(detect_swift); [[ -n "$result" ]] && DETECTED_LANGS="${DETECTED_LANGS}${DETECTED_LANGS:+,}$result"
|
|
482
|
+
result=$(detect_scala); [[ -n "$result" ]] && DETECTED_LANGS="${DETECTED_LANGS}${DETECTED_LANGS:+,}$result"
|
|
483
|
+
result=$(detect_clojure); [[ -n "$result" ]] && DETECTED_LANGS="${DETECTED_LANGS}${DETECTED_LANGS:+,}$result"
|
|
484
|
+
result=$(detect_julia); [[ -n "$result" ]] && DETECTED_LANGS="${DETECTED_LANGS}${DETECTED_LANGS:+,}$result"
|
|
485
|
+
result=$(detect_r); [[ -n "$result" ]] && DETECTED_LANGS="${DETECTED_LANGS}${DETECTED_LANGS:+,}$result"
|
|
486
|
+
fi
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
# ============================================
|
|
490
|
+
# OUTPUT FORMATTING
|
|
491
|
+
# ============================================
|
|
492
|
+
get_lang_display() {
|
|
493
|
+
case "$1" in
|
|
494
|
+
javascript) echo "JavaScript/TypeScript" ;;
|
|
495
|
+
python) echo "Python" ;;
|
|
496
|
+
go) echo "Go" ;;
|
|
497
|
+
rust) echo "Rust" ;;
|
|
498
|
+
java) echo "Java" ;;
|
|
499
|
+
ruby) echo "Ruby" ;;
|
|
500
|
+
php) echo "PHP" ;;
|
|
501
|
+
dotnet) echo ".NET" ;;
|
|
502
|
+
elixir) echo "Elixir" ;;
|
|
503
|
+
haskell) echo "Haskell" ;;
|
|
504
|
+
cpp) echo "C/C++" ;;
|
|
505
|
+
swift) echo "Swift" ;;
|
|
506
|
+
scala) echo "Scala" ;;
|
|
507
|
+
clojure) echo "Clojure" ;;
|
|
508
|
+
julia) echo "Julia" ;;
|
|
509
|
+
r) echo "R" ;;
|
|
510
|
+
esac
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
get_recommendation() {
|
|
514
|
+
local lang=$1 pm=$2
|
|
515
|
+
case "$lang" in
|
|
516
|
+
javascript)
|
|
517
|
+
case "$pm" in
|
|
518
|
+
npm) echo "npm is a safe, universal choice. Consider migrating to pnpm for better performance." ;;
|
|
519
|
+
yarn) echo "yarn is reliable. For new projects, consider pnpm for disk efficiency." ;;
|
|
520
|
+
pnpm) echo "pnpm is excellent—fast, disk-efficient, and strict. Perfect choice." ;;
|
|
521
|
+
bun) echo "bun is very fast but newer. Ensure your team is comfortable with it." ;;
|
|
522
|
+
esac
|
|
523
|
+
;;
|
|
524
|
+
python)
|
|
525
|
+
case "$pm" in
|
|
526
|
+
pip) echo "pip is the standard. Consider poetry or uv for modern Python projects." ;;
|
|
527
|
+
poetry) echo "poetry provides excellent dependency resolution and packaging." ;;
|
|
528
|
+
uv) echo "uv is extremely fast and modern. Great for performance-critical projects." ;;
|
|
529
|
+
conda) echo "conda is ideal for data science and scientific computing." ;;
|
|
530
|
+
pipenv) echo "pipenv combines pip and virtualenv. Consider poetry for new projects." ;;
|
|
531
|
+
esac
|
|
532
|
+
;;
|
|
533
|
+
go) echo "Go modules is the standard. Ensure you have go.mod committed." ;;
|
|
534
|
+
rust) echo "Cargo is Rust's excellent package manager. Crates.io has great ecosystem coverage." ;;
|
|
535
|
+
java)
|
|
536
|
+
case "$pm" in
|
|
537
|
+
maven) echo "Maven is stable and widely used. Great for enterprise projects." ;;
|
|
538
|
+
gradle) echo "Gradle offers flexibility and performance. Popular for Android and modern Java." ;;
|
|
539
|
+
esac
|
|
540
|
+
;;
|
|
541
|
+
ruby) echo "Bundler is the standard. Ensure Gemfile.lock is committed for reproducibility." ;;
|
|
542
|
+
php) echo "Composer is excellent. Packagist has great package coverage." ;;
|
|
543
|
+
dotnet) echo "NuGet is the standard for .NET. Ensure packages.lock.json for reproducibility." ;;
|
|
544
|
+
elixir) echo "Mix is powerful. Hex.pm has excellent Elixir package ecosystem." ;;
|
|
545
|
+
haskell)
|
|
546
|
+
case "$pm" in
|
|
547
|
+
stack) echo "Stack is recommended for reproducible builds and LTS snapshots." ;;
|
|
548
|
+
cabal) echo "Cabal is the traditional choice. Consider stack for easier setup." ;;
|
|
549
|
+
esac
|
|
550
|
+
;;
|
|
551
|
+
cpp)
|
|
552
|
+
case "$pm" in
|
|
553
|
+
conan) echo "Conan is modern and cross-platform. Great for C++ dependency management." ;;
|
|
554
|
+
vcpkg) echo "vcpkg has excellent Microsoft ecosystem integration." ;;
|
|
555
|
+
esac
|
|
556
|
+
;;
|
|
557
|
+
swift) echo "Swift Package Manager is modern and well-integrated with Xcode." ;;
|
|
558
|
+
scala) echo "sbt is the standard. Maven Central has good Scala coverage." ;;
|
|
559
|
+
clojure)
|
|
560
|
+
case "$pm" in
|
|
561
|
+
leiningen) echo "Leiningen is mature and widely used in Clojure community." ;;
|
|
562
|
+
tools.deps) echo "tools.deps is modern and simpler. Consider for new projects." ;;
|
|
563
|
+
esac
|
|
564
|
+
;;
|
|
565
|
+
julia) echo "Julia's Pkg is excellent. General registry has good coverage." ;;
|
|
566
|
+
r)
|
|
567
|
+
case "$pm" in
|
|
568
|
+
renv) echo "renv is the modern standard for R reproducibility." ;;
|
|
569
|
+
packrat) echo "packrat is older. Consider migrating to renv." ;;
|
|
570
|
+
esac
|
|
571
|
+
;;
|
|
572
|
+
esac
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
get_commands() {
|
|
576
|
+
local lang=$1 pm=$2
|
|
577
|
+
case "$lang" in
|
|
578
|
+
javascript)
|
|
579
|
+
case "$pm" in
|
|
580
|
+
npm) echo "install:npm ci|add:npm install|add_dev:npm install --save-dev|run:npm run|exec:npx" ;;
|
|
581
|
+
yarn) echo "install:yarn install --frozen-lockfile|add:yarn add|add_dev:yarn add --dev|run:yarn|exec:yarn dlx" ;;
|
|
582
|
+
pnpm) echo "install:pnpm install --frozen-lockfile|add:pnpm add|add_dev:pnpm add -D|run:pnpm|exec:pnpm dlx" ;;
|
|
583
|
+
bun) echo "install:bun install|add:bun add|add_dev:bun add -d|run:bun run|exec:bunx" ;;
|
|
584
|
+
esac
|
|
585
|
+
;;
|
|
586
|
+
python)
|
|
587
|
+
case "$pm" in
|
|
588
|
+
pip) echo "install:pip install -r requirements.txt|add:pip install|add_dev:pip install|run:python|exec:python" ;;
|
|
589
|
+
poetry) echo "install:poetry install|add:poetry add|add_dev:poetry add --group dev|run:poetry run|exec:poetry run" ;;
|
|
590
|
+
uv) echo "install:uv sync|add:uv add|add_dev:uv add --dev|run:uv run|exec:uv run" ;;
|
|
591
|
+
conda) echo "install:conda env create -f environment.yml|add:conda install|add_dev:conda install|run:conda run|exec:conda run" ;;
|
|
592
|
+
pipenv) echo "install:pipenv install|add:pipenv install|add_dev:pipenv install --dev|run:pipenv run|exec:pipenv run" ;;
|
|
593
|
+
esac
|
|
594
|
+
;;
|
|
595
|
+
go) echo "install:go mod download|add:go get|add_dev:go get|run:go run|exec:go run" ;;
|
|
596
|
+
rust) echo "install:cargo fetch|add:cargo add|add_dev:cargo add --dev|run:cargo run|exec:cargo run" ;;
|
|
597
|
+
java)
|
|
598
|
+
case "$pm" in
|
|
599
|
+
maven) echo "install:mvn dependency:resolve|add:pom.xml edit|add_dev:pom.xml edit|run:mvn exec:java|exec:mvn exec:java" ;;
|
|
600
|
+
gradle) echo "install:gradle dependencies|add:build.gradle edit|add_dev:build.gradle edit|run:gradle run|exec:gradle run" ;;
|
|
601
|
+
esac
|
|
602
|
+
;;
|
|
603
|
+
ruby) echo "install:bundle install|add:bundle add|add_dev:bundle add --group development|run:bundle exec|exec:bundle exec" ;;
|
|
604
|
+
php) echo "install:composer install|add:composer require|add_dev:composer require --dev|run:php|exec:php" ;;
|
|
605
|
+
dotnet) echo "install:dotnet restore|add:dotnet add package|add_dev:dotnet add package|run:dotnet run|exec:dotnet run" ;;
|
|
606
|
+
elixir) echo "install:mix deps.get|add:mix deps.add|add_dev:mix deps.add|run:mix run|exec:mix run" ;;
|
|
607
|
+
haskell)
|
|
608
|
+
case "$pm" in
|
|
609
|
+
stack) echo "install:stack build|add:stack add|add_dev:stack add|run:stack run|exec:stack exec" ;;
|
|
610
|
+
cabal) echo "install:cabal build|add:cabal add|add_dev:cabal add|run:cabal run|exec:cabal exec" ;;
|
|
611
|
+
esac
|
|
612
|
+
;;
|
|
613
|
+
cpp)
|
|
614
|
+
case "$pm" in
|
|
615
|
+
conan) echo "install:conan install|add:conanfile.txt edit|add_dev:conanfile.txt edit|run:cmake|exec:cmake" ;;
|
|
616
|
+
vcpkg) echo "install:vcpkg install|add:vcpkg add|add_dev:vcpkg add|run:cmake|exec:cmake" ;;
|
|
617
|
+
esac
|
|
618
|
+
;;
|
|
619
|
+
swift) echo "install:swift package resolve|add:Package.swift edit|add_dev:Package.swift edit|run:swift run|exec:swift run" ;;
|
|
620
|
+
scala) echo "install:sbt update|add:build.sbt edit|add_dev:build.sbt edit|run:sbt run|exec:sbt run" ;;
|
|
621
|
+
clojure)
|
|
622
|
+
case "$pm" in
|
|
623
|
+
leiningen) echo "install:lein deps|add:project.clj edit|add_dev:project.clj edit|run:lein run|exec:lein exec" ;;
|
|
624
|
+
tools.deps) echo "install:clj -P|add:deps.edn edit|add_dev:deps.edn edit|run:clj -M|exec:clj -X" ;;
|
|
625
|
+
esac
|
|
626
|
+
;;
|
|
627
|
+
julia) echo "install:julia -e 'using Pkg; Pkg.instantiate()'|add:julia -e 'using Pkg; Pkg.add()'|add_dev:julia -e 'using Pkg; Pkg.add()'|run:julia|exec:julia" ;;
|
|
628
|
+
r)
|
|
629
|
+
case "$pm" in
|
|
630
|
+
renv) echo "install:renv::restore()|add:renv::install()|add_dev:renv::install()|run:Rscript|exec:Rscript" ;;
|
|
631
|
+
packrat) echo "install:packrat::restore()|add:packrat::install()|add_dev:packrat::install()|run:Rscript|exec:Rscript" ;;
|
|
632
|
+
esac
|
|
633
|
+
;;
|
|
634
|
+
esac
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
# Output JSON format
|
|
638
|
+
output_json() {
|
|
639
|
+
local first=true
|
|
640
|
+
echo "{"
|
|
641
|
+
echo " \"project_root\": \"${PROJECT_ROOT}\","
|
|
642
|
+
echo " \"languages\": ["
|
|
643
|
+
|
|
644
|
+
# Parse each detected language
|
|
645
|
+
local IFS=','
|
|
646
|
+
for entry in $DETECTED_LANGS; do
|
|
647
|
+
[[ -z "$entry" ]] && continue
|
|
648
|
+
|
|
649
|
+
if [[ "$first" == false ]]; then
|
|
650
|
+
echo ","
|
|
651
|
+
fi
|
|
652
|
+
first=false
|
|
653
|
+
|
|
654
|
+
# Parse pipe-delimited fields
|
|
655
|
+
local IFS='|'
|
|
656
|
+
local fields=($entry)
|
|
657
|
+
local lang="${fields[0]}"
|
|
658
|
+
local pm="${fields[1]}"
|
|
659
|
+
local ver="${fields[2]}"
|
|
660
|
+
local meth="${fields[3]}"
|
|
661
|
+
local lock="${fields[4]}"
|
|
662
|
+
local conf="${fields[5]}"
|
|
663
|
+
local cfg="${fields[6]}"
|
|
664
|
+
local field="${fields[7]}"
|
|
665
|
+
|
|
666
|
+
local rec=$(get_recommendation "$lang" "$pm" | sed 's/"/\\"/g')
|
|
667
|
+
local cmds=$(get_commands "$lang" "$pm")
|
|
668
|
+
|
|
669
|
+
echo " {"
|
|
670
|
+
echo " \"language\": \"$lang\","
|
|
671
|
+
echo " \"package_manager\": \"$pm\","
|
|
672
|
+
echo " \"version\": \"${ver:-}\","
|
|
673
|
+
echo " \"detection_method\": \"$meth\","
|
|
674
|
+
echo " \"confidence\": ${conf:-0},"
|
|
675
|
+
echo " \"lockfile\": \"${lock:-}\","
|
|
676
|
+
echo " \"config_file\": \"${cfg:-}\","
|
|
677
|
+
echo " \"package_manager_field\": \"${field:-}\","
|
|
678
|
+
echo " \"recommendation\": \"$rec\","
|
|
679
|
+
echo -n " \"commands\": {"
|
|
680
|
+
|
|
681
|
+
# Parse commands
|
|
682
|
+
local IFS='|'
|
|
683
|
+
local cmd_array=($cmds)
|
|
684
|
+
local first_cmd=true
|
|
685
|
+
for cmd in "${cmd_array[@]}"; do
|
|
686
|
+
local key=$(echo "$cmd" | cut -d':' -f1)
|
|
687
|
+
local val=$(echo "$cmd" | cut -d':' -f2)
|
|
688
|
+
if [[ "$first_cmd" == false ]]; then
|
|
689
|
+
echo -n ", "
|
|
690
|
+
fi
|
|
691
|
+
first_cmd=false
|
|
692
|
+
echo -n "\"$key\": \"$val\""
|
|
693
|
+
done
|
|
694
|
+
echo -n "}"
|
|
695
|
+
echo ""
|
|
696
|
+
echo -n " }"
|
|
697
|
+
done
|
|
698
|
+
|
|
699
|
+
echo ""
|
|
700
|
+
echo " ]"
|
|
701
|
+
echo "}"
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
# Output human-readable format
|
|
705
|
+
output_human() {
|
|
706
|
+
if [[ "$RECOMMEND_ONLY" == true ]]; then
|
|
707
|
+
# Get first language's package manager
|
|
708
|
+
local first_entry=$(echo "$DETECTED_LANGS" | cut -d',' -f1)
|
|
709
|
+
echo "$first_entry" | cut -d'|' -f2
|
|
710
|
+
return
|
|
711
|
+
fi
|
|
712
|
+
|
|
713
|
+
echo ""
|
|
714
|
+
echo "╔════════════════════════════════════════════════════════════╗"
|
|
715
|
+
echo "║ Multi-Language Package Manager Detection Report ║"
|
|
716
|
+
echo "╚════════════════════════════════════════════════════════════╝"
|
|
717
|
+
echo ""
|
|
718
|
+
echo "Project: ${PROJECT_ROOT}"
|
|
719
|
+
echo ""
|
|
720
|
+
|
|
721
|
+
if [[ -z "$DETECTED_LANGS" ]]; then
|
|
722
|
+
echo "${RED}No package managers detected for any language!${NC}"
|
|
723
|
+
echo ""
|
|
724
|
+
echo "This project may be new or use an unsupported build system."
|
|
725
|
+
return
|
|
726
|
+
fi
|
|
727
|
+
|
|
728
|
+
# Parse each detected language
|
|
729
|
+
local IFS=','
|
|
730
|
+
for entry in $DETECTED_LANGS; do
|
|
731
|
+
[[ -z "$entry" ]] && continue
|
|
732
|
+
|
|
733
|
+
# Parse pipe-delimited fields
|
|
734
|
+
local IFS='|'
|
|
735
|
+
local fields=($entry)
|
|
736
|
+
local lang="${fields[0]}"
|
|
737
|
+
local pm="${fields[1]}"
|
|
738
|
+
local ver="${fields[2]}"
|
|
739
|
+
local meth="${fields[3]}"
|
|
740
|
+
local lock="${fields[4]}"
|
|
741
|
+
local conf="${fields[5]}"
|
|
742
|
+
|
|
743
|
+
local display=$(get_lang_display "$lang")
|
|
744
|
+
local rec=$(get_recommendation "$lang" "$pm")
|
|
745
|
+
|
|
746
|
+
echo "${CYAN}${display}${NC}"
|
|
747
|
+
echo " ${GREEN}Recommended: ${pm}${NC}"
|
|
748
|
+
[[ -n "$ver" ]] && echo " Version: ${ver}"
|
|
749
|
+
echo " Detection: ${meth}"
|
|
750
|
+
echo " Confidence: ${conf}%"
|
|
751
|
+
[[ -n "$lock" ]] && echo " Lockfile: ${lock}"
|
|
752
|
+
echo ""
|
|
753
|
+
echo " ${BLUE}Recommendation:${NC}"
|
|
754
|
+
echo " ${rec}"
|
|
755
|
+
echo ""
|
|
756
|
+
|
|
757
|
+
# Show commands
|
|
758
|
+
local cmds=$(get_commands "$lang" "$pm")
|
|
759
|
+
echo " ${BLUE}Quick Commands:${NC}"
|
|
760
|
+
local IFS='|'
|
|
761
|
+
local cmd_array=($cmds)
|
|
762
|
+
for cmd in "${cmd_array[@]}"; do
|
|
763
|
+
local key=$(echo "$cmd" | cut -d':' -f1)
|
|
764
|
+
local val=$(echo "$cmd" | cut -d':' -f2)
|
|
765
|
+
printf " %-12s %s\n" "${key}:" "$val"
|
|
766
|
+
done
|
|
767
|
+
echo ""
|
|
768
|
+
done
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
# ============================================
|
|
772
|
+
# MAIN EXECUTION
|
|
773
|
+
# ============================================
|
|
774
|
+
main() {
|
|
775
|
+
detect_all
|
|
776
|
+
|
|
777
|
+
if [[ -z "$DETECTED_LANGS" ]]; then
|
|
778
|
+
if [[ "$JSON_OUTPUT" == true ]]; then
|
|
779
|
+
echo '{"languages": [], "error": "No package managers detected"}'
|
|
780
|
+
else
|
|
781
|
+
error "No package managers detected for any language"
|
|
782
|
+
fi
|
|
783
|
+
exit 1
|
|
784
|
+
fi
|
|
785
|
+
|
|
786
|
+
if [[ "$JSON_OUTPUT" == true ]]; then
|
|
787
|
+
output_json
|
|
788
|
+
else
|
|
789
|
+
output_human
|
|
790
|
+
fi
|
|
791
|
+
|
|
792
|
+
exit 0
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
# Run
|
|
796
|
+
main
|