@kokorolx/ai-sandbox-wrapper 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.
- package/README.md +540 -0
- package/bin/ai-debug +116 -0
- package/bin/ai-network +144 -0
- package/bin/ai-run +631 -0
- package/bin/cli.js +83 -0
- package/bin/setup-ssh-config +328 -0
- package/dockerfiles/AGENTS.md +92 -0
- package/dockerfiles/aider/Dockerfile +5 -0
- package/dockerfiles/amp/Dockerfile +10 -0
- package/dockerfiles/auggie/Dockerfile +12 -0
- package/dockerfiles/base/Dockerfile +73 -0
- package/dockerfiles/claude/Dockerfile +11 -0
- package/dockerfiles/codebuddy/Dockerfile +12 -0
- package/dockerfiles/codex/Dockerfile +9 -0
- package/dockerfiles/droid/Dockerfile +8 -0
- package/dockerfiles/gemini/Dockerfile +9 -0
- package/dockerfiles/jules/Dockerfile +12 -0
- package/dockerfiles/kilo/Dockerfile +25 -0
- package/dockerfiles/opencode/Dockerfile +10 -0
- package/dockerfiles/qoder/Dockerfile +12 -0
- package/dockerfiles/qwen/Dockerfile +10 -0
- package/dockerfiles/shai/Dockerfile +9 -0
- package/lib/AGENTS.md +58 -0
- package/lib/generate-ai-run.sh +19 -0
- package/lib/install-aider.sh +30 -0
- package/lib/install-amp.sh +39 -0
- package/lib/install-auggie.sh +36 -0
- package/lib/install-base.sh +139 -0
- package/lib/install-claude.sh +42 -0
- package/lib/install-codebuddy.sh +36 -0
- package/lib/install-codeserver.sh +171 -0
- package/lib/install-codex.sh +40 -0
- package/lib/install-droid.sh +27 -0
- package/lib/install-gemini.sh +39 -0
- package/lib/install-jules.sh +36 -0
- package/lib/install-kilo.sh +57 -0
- package/lib/install-opencode.sh +39 -0
- package/lib/install-qoder.sh +37 -0
- package/lib/install-qwen.sh +40 -0
- package/lib/install-shai.sh +33 -0
- package/lib/install-tool.sh +40 -0
- package/lib/install-vscode.sh +219 -0
- package/lib/ssh-key-selector.sh +189 -0
- package/package.json +46 -0
- package/setup.sh +530 -0
package/setup.sh
ADDED
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# Interactive multi-select menu
|
|
5
|
+
# Usage: multi_select "title" "comma,separated,options" "comma,separated,descriptions"
|
|
6
|
+
# Returns: SELECTED_ITEMS as an array
|
|
7
|
+
multi_select() {
|
|
8
|
+
local title="$1"
|
|
9
|
+
IFS=',' read -ra options <<< "$2"
|
|
10
|
+
IFS=',' read -ra descriptions <<< "$3"
|
|
11
|
+
local cursor=0
|
|
12
|
+
local selected=()
|
|
13
|
+
for ((i=0; i<${#options[@]}; i++)); do selected[i]=0; done
|
|
14
|
+
|
|
15
|
+
# Use tput for better terminal control
|
|
16
|
+
tput civis # Hide cursor
|
|
17
|
+
trap 'tput cnorm; exit' INT TERM # Show cursor on exit
|
|
18
|
+
|
|
19
|
+
while true; do
|
|
20
|
+
clear
|
|
21
|
+
echo "🚀 $title"
|
|
22
|
+
echo "Use ARROWS to move, SPACE to toggle, ENTER to confirm"
|
|
23
|
+
echo ""
|
|
24
|
+
|
|
25
|
+
for i in "${!options[@]}"; do
|
|
26
|
+
if [ "$i" -eq "$cursor" ]; then
|
|
27
|
+
prefix="➔ "
|
|
28
|
+
tput setaf 6 # Cyan
|
|
29
|
+
else
|
|
30
|
+
prefix=" "
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
if [ "${selected[$i]}" -eq 1 ]; then
|
|
34
|
+
check="[x]"
|
|
35
|
+
tput setaf 2 # Green
|
|
36
|
+
else
|
|
37
|
+
check="[ ]"
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
printf "%s %s %-12s - %s\n" "$prefix" "$check" "${options[$i]}" "${descriptions[$i]}"
|
|
41
|
+
tput sgr0 # Reset colors
|
|
42
|
+
done
|
|
43
|
+
|
|
44
|
+
# Handle input
|
|
45
|
+
IFS= read -rsn1 key
|
|
46
|
+
|
|
47
|
+
# Handle escape sequences for arrows
|
|
48
|
+
if [[ "$key" == $'\x1b' ]]; then
|
|
49
|
+
# Read next two chars of the escape sequence
|
|
50
|
+
read -rsn1 -t 1 next1
|
|
51
|
+
read -rsn1 -t 1 next2
|
|
52
|
+
case "$next1$next2" in
|
|
53
|
+
'[A') ((cursor--)) ;; # Up
|
|
54
|
+
'[B') ((cursor++)) ;; # Down
|
|
55
|
+
esac
|
|
56
|
+
else
|
|
57
|
+
case "$key" in
|
|
58
|
+
k) ((cursor--)) ;; # k for Up
|
|
59
|
+
j) ((cursor++)) ;; # j for Down
|
|
60
|
+
" ") # Space (toggle)
|
|
61
|
+
if [ "${selected[$cursor]}" -eq 1 ]; then
|
|
62
|
+
selected[$cursor]=0
|
|
63
|
+
else
|
|
64
|
+
selected[$cursor]=1
|
|
65
|
+
fi
|
|
66
|
+
;;
|
|
67
|
+
"") # Enter (newline/carriage return/empty string)
|
|
68
|
+
break
|
|
69
|
+
;;
|
|
70
|
+
$'\n'|$'\r') # Extra safety for different enter signals
|
|
71
|
+
break
|
|
72
|
+
;;
|
|
73
|
+
esac
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
# Keep cursor in bounds
|
|
77
|
+
if [ "$cursor" -lt 0 ]; then cursor=$((${#options[@]} - 1)); fi
|
|
78
|
+
if [ "$cursor" -ge "${#options[@]}" ]; then cursor=0; fi
|
|
79
|
+
done
|
|
80
|
+
|
|
81
|
+
tput cnorm # Show cursor
|
|
82
|
+
|
|
83
|
+
# Prepare result
|
|
84
|
+
SELECTED_ITEMS=()
|
|
85
|
+
for i in "${!options[@]}"; do
|
|
86
|
+
if [ "${selected[$i]}" -eq 1 ]; then
|
|
87
|
+
SELECTED_ITEMS+=("${options[$i]}")
|
|
88
|
+
fi
|
|
89
|
+
done
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
# Interactive single-select menu
|
|
93
|
+
# Usage: single_select "title" "comma,separated,options" "comma,separated,descriptions"
|
|
94
|
+
# Returns: SELECTED_ITEM as a string
|
|
95
|
+
single_select() {
|
|
96
|
+
local title="$1"
|
|
97
|
+
IFS=',' read -ra options <<< "$2"
|
|
98
|
+
IFS=',' read -ra descriptions <<< "$3"
|
|
99
|
+
local cursor=0
|
|
100
|
+
|
|
101
|
+
tput civis # Hide cursor
|
|
102
|
+
trap 'tput cnorm; exit' INT TERM
|
|
103
|
+
|
|
104
|
+
while true; do
|
|
105
|
+
clear
|
|
106
|
+
echo "🚀 $title"
|
|
107
|
+
echo "Use ARROWS to move, ENTER to select"
|
|
108
|
+
echo ""
|
|
109
|
+
|
|
110
|
+
for i in "${!options[@]}"; do
|
|
111
|
+
if [ "$i" -eq "$cursor" ]; then
|
|
112
|
+
prefix="➔ "
|
|
113
|
+
tput setaf 6 # Cyan
|
|
114
|
+
else
|
|
115
|
+
prefix=" "
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
printf "%s %-12s - %s\n" "$prefix" "${options[$i]}" "${descriptions[$i]}"
|
|
119
|
+
tput sgr0
|
|
120
|
+
done
|
|
121
|
+
|
|
122
|
+
IFS= read -rsn1 key
|
|
123
|
+
if [[ "$key" == $'\x1b' ]]; then
|
|
124
|
+
read -rsn1 -t 1 next1
|
|
125
|
+
read -rsn1 -t 1 next2
|
|
126
|
+
case "$next1$next2" in
|
|
127
|
+
'[A') ((cursor--)) ;;
|
|
128
|
+
'[B') ((cursor++)) ;;
|
|
129
|
+
esac
|
|
130
|
+
else
|
|
131
|
+
case "$key" in
|
|
132
|
+
k) ((cursor--)) ;;
|
|
133
|
+
j) ((cursor++)) ;;
|
|
134
|
+
"") break ;;
|
|
135
|
+
$'\n'|$'\r') break ;;
|
|
136
|
+
esac
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
if [ "$cursor" -lt 0 ]; then cursor=$((${#options[@]} - 1)); fi
|
|
140
|
+
if [ "$cursor" -ge "${#options[@]}" ]; then cursor=0; fi
|
|
141
|
+
done
|
|
142
|
+
|
|
143
|
+
tput cnorm
|
|
144
|
+
SELECTED_ITEM="${options[$cursor]}"
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
# Check and install dependencies
|
|
148
|
+
echo "Checking and installing dependencies..."
|
|
149
|
+
|
|
150
|
+
if ! command -v git &> /dev/null; then
|
|
151
|
+
echo "Installing git..."
|
|
152
|
+
apt-get update && apt-get install -y git
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
if ! command -v python3 &> /dev/null; then
|
|
156
|
+
echo "Installing python3..."
|
|
157
|
+
apt-get install -y python3 python3-pip
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
# Check for Docker
|
|
161
|
+
if ! command -v docker &> /dev/null; then
|
|
162
|
+
echo "❌ Docker not found. Please install Docker Desktop first."
|
|
163
|
+
exit 1
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
echo "🚀 AI Sandbox Setup (Docker Desktop + Node 22 LTS)"
|
|
167
|
+
|
|
168
|
+
WORKSPACES_FILE="$HOME/.ai-workspaces"
|
|
169
|
+
|
|
170
|
+
# Handle whitelisted workspaces
|
|
171
|
+
WORKSPACES=()
|
|
172
|
+
|
|
173
|
+
if [[ -f "$WORKSPACES_FILE" ]]; then
|
|
174
|
+
echo "Existing whitelisted workspaces found:"
|
|
175
|
+
while IFS= read -r line; do
|
|
176
|
+
if [[ -n "$line" ]]; then
|
|
177
|
+
echo " - $line"
|
|
178
|
+
WORKSPACES+=("$line")
|
|
179
|
+
fi
|
|
180
|
+
done < "$WORKSPACES_FILE"
|
|
181
|
+
|
|
182
|
+
echo ""
|
|
183
|
+
single_select "Configure Workspaces" "reuse,add,replace" "Keep existing whitelisted folders,Append new folders to the list,Start fresh with new folders"
|
|
184
|
+
|
|
185
|
+
case "$SELECTED_ITEM" in
|
|
186
|
+
add)
|
|
187
|
+
echo "Enter additional workspace directories (comma-separated):"
|
|
188
|
+
read -p "Add Workspaces: " WORKSPACE_INPUT
|
|
189
|
+
;;
|
|
190
|
+
replace)
|
|
191
|
+
WORKSPACES=()
|
|
192
|
+
echo "Enter new workspace directories (comma-separated):"
|
|
193
|
+
read -p "Workspaces: " WORKSPACE_INPUT
|
|
194
|
+
;;
|
|
195
|
+
*)
|
|
196
|
+
WORKSPACE_INPUT=""
|
|
197
|
+
;;
|
|
198
|
+
esac
|
|
199
|
+
else
|
|
200
|
+
echo "Enter workspace directories to whitelist (comma-separated):"
|
|
201
|
+
echo "Example: $HOME/projects, $HOME/code, /opt/work"
|
|
202
|
+
read -p "Workspaces: " WORKSPACE_INPUT
|
|
203
|
+
fi
|
|
204
|
+
|
|
205
|
+
# Parse and validate new workspaces if provided
|
|
206
|
+
if [[ -n "$WORKSPACE_INPUT" ]]; then
|
|
207
|
+
IFS=',' read -ra WORKSPACE_ARRAY <<< "$WORKSPACE_INPUT"
|
|
208
|
+
for ws in "${WORKSPACE_ARRAY[@]}"; do
|
|
209
|
+
ws=$(echo "$ws" | xargs) # trim whitespace
|
|
210
|
+
ws="${ws/#\~/$HOME}" # expand ~ to $HOME
|
|
211
|
+
if [[ -n "$ws" ]]; then
|
|
212
|
+
mkdir -p "$ws"
|
|
213
|
+
# Avoid duplicates
|
|
214
|
+
if [[ ! " ${WORKSPACES[*]} " =~ " ${ws} " ]]; then
|
|
215
|
+
WORKSPACES+=("$ws")
|
|
216
|
+
fi
|
|
217
|
+
fi
|
|
218
|
+
done
|
|
219
|
+
fi
|
|
220
|
+
|
|
221
|
+
if [[ ${#WORKSPACES[@]} -eq 0 ]]; then
|
|
222
|
+
echo "❌ No valid workspaces provided"
|
|
223
|
+
exit 1
|
|
224
|
+
fi
|
|
225
|
+
|
|
226
|
+
# Save workspaces to config file
|
|
227
|
+
printf "%s\n" "${WORKSPACES[@]}" > "$WORKSPACES_FILE"
|
|
228
|
+
chmod 600 "$WORKSPACES_FILE"
|
|
229
|
+
echo "📁 Whitelisted workspaces saved to: $WORKSPACES_FILE"
|
|
230
|
+
|
|
231
|
+
# Use first workspace as default for backwards compatibility
|
|
232
|
+
WORKSPACE="${WORKSPACES[0]}"
|
|
233
|
+
|
|
234
|
+
# Network configuration for Docker network access
|
|
235
|
+
echo ""
|
|
236
|
+
echo "🔗 Docker Network Configuration"
|
|
237
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
238
|
+
echo "You can configure AI tools to join existing Docker networks"
|
|
239
|
+
echo "(e.g., for MetaMCP services, databases, or other containers)."
|
|
240
|
+
echo ""
|
|
241
|
+
|
|
242
|
+
# Check for existing MetaMCP network
|
|
243
|
+
if docker network inspect "metamcp_metamcp-network" >/dev/null 2>&1; then
|
|
244
|
+
echo "✅ Found existing network: metamcp_metamcp-network"
|
|
245
|
+
echo ""
|
|
246
|
+
|
|
247
|
+
# Use single_select for interactive choice
|
|
248
|
+
single_select "MetaMCP Access Method" "join,host-only" "Join network (container-to-container communication),Use host.docker.internal (host access)"
|
|
249
|
+
|
|
250
|
+
case "$SELECTED_ITEM" in
|
|
251
|
+
join)
|
|
252
|
+
NETWORK_FILE="$HOME/.ai-networks"
|
|
253
|
+
echo "metamcp_metamcp-network" >> "$NETWORK_FILE"
|
|
254
|
+
chmod 600 "$NETWORK_FILE"
|
|
255
|
+
echo ""
|
|
256
|
+
echo "✅ Network joined. Both host.docker.internal and MetaMCP network enabled."
|
|
257
|
+
;;
|
|
258
|
+
host-only|"")
|
|
259
|
+
echo ""
|
|
260
|
+
echo "ℹ️ Using host.docker.internal only. MetaMCP accessible at localhost:12008 on host."
|
|
261
|
+
;;
|
|
262
|
+
esac
|
|
263
|
+
else
|
|
264
|
+
echo "No existing MetaMCP network detected."
|
|
265
|
+
echo ""
|
|
266
|
+
echo "You have two options:"
|
|
267
|
+
echo ""
|
|
268
|
+
echo "Option 1: Use host.docker.internal (recommended for most cases)"
|
|
269
|
+
echo " MetaMCP at localhost:12008 on your host machine"
|
|
270
|
+
echo " Already enabled by default"
|
|
271
|
+
echo ""
|
|
272
|
+
echo "Option 2: Join a Docker network"
|
|
273
|
+
echo " For container-to-container communication"
|
|
274
|
+
echo ""
|
|
275
|
+
read -p "Enter a Docker network name to join (leave empty to skip): " network_name
|
|
276
|
+
|
|
277
|
+
if [[ -n "$network_name" ]]; then
|
|
278
|
+
if docker network inspect "$network_name" >/dev/null 2>&1; then
|
|
279
|
+
NETWORK_FILE="$HOME/.ai-networks"
|
|
280
|
+
echo "$network_name" >> "$NETWORK_FILE"
|
|
281
|
+
chmod 600 "$NETWORK_FILE"
|
|
282
|
+
echo "✅ Network '$network_name' saved"
|
|
283
|
+
else
|
|
284
|
+
echo "⚠️ Network '$network_name' not found. Skipping."
|
|
285
|
+
fi
|
|
286
|
+
else
|
|
287
|
+
echo "ℹ️ Skipped. host.docker.internal is enabled for host access."
|
|
288
|
+
fi
|
|
289
|
+
fi
|
|
290
|
+
|
|
291
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
292
|
+
echo ""
|
|
293
|
+
|
|
294
|
+
# Tool definitions
|
|
295
|
+
TOOL_OPTIONS="amp,opencode,droid,claude,gemini,kilo,qwen,codex,qoder,auggie,codebuddy,jules,shai,vscode,codeserver"
|
|
296
|
+
TOOL_DESCS="AI coding assistant from @sourcegraph/amp,Open-source coding tool from opencode-ai,Factory CLI from factory.ai,Claude Code CLI from Anthropic,Google Gemini CLI (free tier),AI pair programmer (Git-native),Kilo Code (500+ models),Alibaba Qwen CLI (1M context),OpenAI Codex terminal agent,Qoder AI CLI assistant,Augment Auggie CLI,Tencent CodeBuddy CLI,Google Jules CLI,OVHcloud SHAI agent,VSCode Desktop in Docker (X11),VSCode in browser (fast)"
|
|
297
|
+
|
|
298
|
+
# Interactive multi-select
|
|
299
|
+
multi_select "Select AI Tools to Install" "$TOOL_OPTIONS" "$TOOL_DESCS"
|
|
300
|
+
TOOLS=("${SELECTED_ITEMS[@]}")
|
|
301
|
+
|
|
302
|
+
if [[ ${#TOOLS[@]} -eq 0 ]]; then
|
|
303
|
+
echo "❌ No tools selected for installation"
|
|
304
|
+
exit 0
|
|
305
|
+
fi
|
|
306
|
+
|
|
307
|
+
echo "Installing tools: ${TOOLS[*]}"
|
|
308
|
+
|
|
309
|
+
CONTAINERIZED_TOOLS=()
|
|
310
|
+
for tool in "${TOOLS[@]}"; do
|
|
311
|
+
if [[ "$tool" =~ ^(amp|opencode|claude|aider|droid|gemini|kilo|qwen|codex|qoder|auggie|codebuddy|jules|shai)$ ]]; then
|
|
312
|
+
CONTAINERIZED_TOOLS+=("$tool")
|
|
313
|
+
fi
|
|
314
|
+
done
|
|
315
|
+
|
|
316
|
+
echo ""
|
|
317
|
+
if [[ ${#CONTAINERIZED_TOOLS[@]} -gt 0 ]]; then
|
|
318
|
+
ADDITIONAL_TOOL_OPTIONS="spec-kit,ux-ui-promax,openspec,playwright,ruby"
|
|
319
|
+
ADDITIONAL_TOOL_DESCS="Spec-driven development toolkit,UI/UX design intelligence tool,OpenSpec - spec-driven development,Playwright browser automation (adds ~500MB),Ruby 3.3.0 + Rails 8.0.2 (adds ~500MB)"
|
|
320
|
+
|
|
321
|
+
multi_select "Select Additional Tools (installed in containers)" "$ADDITIONAL_TOOL_OPTIONS" "$ADDITIONAL_TOOL_DESCS"
|
|
322
|
+
ADDITIONAL_TOOLS=("${SELECTED_ITEMS[@]}")
|
|
323
|
+
|
|
324
|
+
if [[ ${#ADDITIONAL_TOOLS[@]} -gt 0 ]]; then
|
|
325
|
+
echo "Additional tools selected: ${ADDITIONAL_TOOLS[*]}"
|
|
326
|
+
fi
|
|
327
|
+
else
|
|
328
|
+
ADDITIONAL_TOOLS=()
|
|
329
|
+
echo "ℹ️ No containerized AI tools selected. Skipping additional tools."
|
|
330
|
+
fi
|
|
331
|
+
|
|
332
|
+
mkdir -p "$WORKSPACE"
|
|
333
|
+
mkdir -p "$HOME/bin"
|
|
334
|
+
|
|
335
|
+
# Secrets
|
|
336
|
+
ENV_FILE="$HOME/.ai-env"
|
|
337
|
+
if [ ! -f "$ENV_FILE" ]; then
|
|
338
|
+
cat <<EOF > "$ENV_FILE"
|
|
339
|
+
OPENAI_API_KEY=[REDACTED:api-key]
|
|
340
|
+
ANTHROPIC_API_KEY=[REDACTED:api-key]
|
|
341
|
+
EOF
|
|
342
|
+
chmod 600 "$ENV_FILE"
|
|
343
|
+
echo "⚠️ Edit $ENV_FILE with your real API keys"
|
|
344
|
+
fi
|
|
345
|
+
|
|
346
|
+
# Get script directory (supports both direct execution and npx)
|
|
347
|
+
if [[ -n "$AI_SANDBOX_ROOT" ]]; then
|
|
348
|
+
SCRIPT_DIR="$AI_SANDBOX_ROOT"
|
|
349
|
+
else
|
|
350
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
351
|
+
fi
|
|
352
|
+
|
|
353
|
+
# Install base image if any containerized tools selected (vscode doesn't need it)
|
|
354
|
+
NEEDS_BASE_IMAGE=0
|
|
355
|
+
for tool in "${TOOLS[@]}"; do
|
|
356
|
+
if [[ "$tool" =~ ^(amp|opencode|claude|aider)$ ]]; then
|
|
357
|
+
NEEDS_BASE_IMAGE=1
|
|
358
|
+
break
|
|
359
|
+
fi
|
|
360
|
+
done
|
|
361
|
+
|
|
362
|
+
if [[ $NEEDS_BASE_IMAGE -eq 1 ]]; then
|
|
363
|
+
INSTALL_SPEC_KIT=0
|
|
364
|
+
INSTALL_UX_UI_PROMAX=0
|
|
365
|
+
INSTALL_OPENSPEC=0
|
|
366
|
+
INSTALL_PLAYWRIGHT=0
|
|
367
|
+
INSTALL_RUBY=0
|
|
368
|
+
|
|
369
|
+
for addon in "${ADDITIONAL_TOOLS[@]}"; do
|
|
370
|
+
case "$addon" in
|
|
371
|
+
spec-kit)
|
|
372
|
+
INSTALL_SPEC_KIT=1
|
|
373
|
+
;;
|
|
374
|
+
ux-ui-promax)
|
|
375
|
+
INSTALL_UX_UI_PROMAX=1
|
|
376
|
+
;;
|
|
377
|
+
openspec)
|
|
378
|
+
INSTALL_OPENSPEC=1
|
|
379
|
+
;;
|
|
380
|
+
playwright)
|
|
381
|
+
INSTALL_PLAYWRIGHT=1
|
|
382
|
+
;;
|
|
383
|
+
ruby)
|
|
384
|
+
INSTALL_RUBY=1
|
|
385
|
+
;;
|
|
386
|
+
esac
|
|
387
|
+
done
|
|
388
|
+
|
|
389
|
+
export INSTALL_SPEC_KIT INSTALL_UX_UI_PROMAX INSTALL_OPENSPEC INSTALL_PLAYWRIGHT INSTALL_RUBY
|
|
390
|
+
bash "$SCRIPT_DIR/lib/install-base.sh"
|
|
391
|
+
fi
|
|
392
|
+
|
|
393
|
+
# Install selected tools
|
|
394
|
+
for tool in "${TOOLS[@]}"; do
|
|
395
|
+
case $tool in
|
|
396
|
+
amp)
|
|
397
|
+
bash "$SCRIPT_DIR/lib/install-amp.sh"
|
|
398
|
+
;;
|
|
399
|
+
opencode)
|
|
400
|
+
bash "$SCRIPT_DIR/lib/install-opencode.sh"
|
|
401
|
+
;;
|
|
402
|
+
droid)
|
|
403
|
+
bash "$SCRIPT_DIR/lib/install-droid.sh"
|
|
404
|
+
;;
|
|
405
|
+
claude)
|
|
406
|
+
bash "$SCRIPT_DIR/lib/install-claude.sh"
|
|
407
|
+
;;
|
|
408
|
+
gemini)
|
|
409
|
+
bash "$SCRIPT_DIR/lib/install-gemini.sh"
|
|
410
|
+
;;
|
|
411
|
+
aider)
|
|
412
|
+
bash "$SCRIPT_DIR/lib/install-aider.sh"
|
|
413
|
+
;;
|
|
414
|
+
kilo)
|
|
415
|
+
bash "$SCRIPT_DIR/lib/install-kilo.sh"
|
|
416
|
+
;;
|
|
417
|
+
qwen)
|
|
418
|
+
bash "$SCRIPT_DIR/lib/install-qwen.sh"
|
|
419
|
+
;;
|
|
420
|
+
codex)
|
|
421
|
+
bash "$SCRIPT_DIR/lib/install-codex.sh"
|
|
422
|
+
;;
|
|
423
|
+
qoder)
|
|
424
|
+
bash "$SCRIPT_DIR/lib/install-qoder.sh"
|
|
425
|
+
;;
|
|
426
|
+
auggie)
|
|
427
|
+
bash "$SCRIPT_DIR/lib/install-auggie.sh"
|
|
428
|
+
;;
|
|
429
|
+
codebuddy)
|
|
430
|
+
bash "$SCRIPT_DIR/lib/install-codebuddy.sh"
|
|
431
|
+
;;
|
|
432
|
+
jules)
|
|
433
|
+
bash "$SCRIPT_DIR/lib/install-jules.sh"
|
|
434
|
+
;;
|
|
435
|
+
shai)
|
|
436
|
+
bash "$SCRIPT_DIR/lib/install-shai.sh"
|
|
437
|
+
;;
|
|
438
|
+
vscode)
|
|
439
|
+
bash "$SCRIPT_DIR/lib/install-vscode.sh"
|
|
440
|
+
;;
|
|
441
|
+
codeserver)
|
|
442
|
+
bash "$SCRIPT_DIR/lib/install-codeserver.sh"
|
|
443
|
+
;;
|
|
444
|
+
esac
|
|
445
|
+
done
|
|
446
|
+
|
|
447
|
+
# Additional tools are installed in base image (no host installation)
|
|
448
|
+
|
|
449
|
+
# Generate ai-run wrapper
|
|
450
|
+
bash "$SCRIPT_DIR/lib/generate-ai-run.sh"
|
|
451
|
+
|
|
452
|
+
# PATH + aliases
|
|
453
|
+
SHELL_RC="$HOME/.zshrc"
|
|
454
|
+
|
|
455
|
+
# Add PATH if not already present
|
|
456
|
+
if ! grep -q 'export PATH="\$HOME/bin:\$PATH"' "$SHELL_RC" 2>/dev/null; then
|
|
457
|
+
echo "export PATH=\"\$HOME/bin:\$PATH\"" >> "$SHELL_RC"
|
|
458
|
+
fi
|
|
459
|
+
|
|
460
|
+
# Add aliases for each tool (only if not already present)
|
|
461
|
+
for tool in "${TOOLS[@]}"; do
|
|
462
|
+
if [[ "$tool" == "vscode" ]]; then
|
|
463
|
+
if ! grep -q "alias vscode=" "$SHELL_RC" 2>/dev/null; then
|
|
464
|
+
echo "alias vscode='vscode-run'" >> "$SHELL_RC"
|
|
465
|
+
fi
|
|
466
|
+
elif [[ "$tool" == "codeserver" ]]; then
|
|
467
|
+
if ! grep -q "alias codeserver=" "$SHELL_RC" 2>/dev/null; then
|
|
468
|
+
echo "alias codeserver='codeserver-run'" >> "$SHELL_RC"
|
|
469
|
+
fi
|
|
470
|
+
else
|
|
471
|
+
if ! grep -q "alias $tool=" "$SHELL_RC" 2>/dev/null; then
|
|
472
|
+
echo "alias $tool=\"ai-run $tool\"" >> "$SHELL_RC"
|
|
473
|
+
fi
|
|
474
|
+
fi
|
|
475
|
+
done
|
|
476
|
+
|
|
477
|
+
# Additional tools don't need host aliases (only in containers)
|
|
478
|
+
|
|
479
|
+
echo ""
|
|
480
|
+
echo "✅ Setup complete!"
|
|
481
|
+
echo ""
|
|
482
|
+
echo "🛠️ Installed AI tools:"
|
|
483
|
+
for tool in "${TOOLS[@]}"; do
|
|
484
|
+
if [[ "$tool" == "vscode" ]]; then
|
|
485
|
+
echo " vscode-run (or: vscode) - Desktop VSCode via X11"
|
|
486
|
+
elif [[ "$tool" == "codeserver" ]]; then
|
|
487
|
+
echo " codeserver-run (or: codeserver) - Browser VSCode at localhost:8080"
|
|
488
|
+
else
|
|
489
|
+
echo " ai-run $tool (or: $tool)"
|
|
490
|
+
fi
|
|
491
|
+
done
|
|
492
|
+
|
|
493
|
+
if [[ ${#ADDITIONAL_TOOLS[@]} -gt 0 ]]; then
|
|
494
|
+
echo ""
|
|
495
|
+
echo "🔧 Additional tools (available inside all containerized AI tools):"
|
|
496
|
+
for addon in "${ADDITIONAL_TOOLS[@]}"; do
|
|
497
|
+
case $addon in
|
|
498
|
+
spec-kit)
|
|
499
|
+
echo " specify - Spec-driven development toolkit"
|
|
500
|
+
;;
|
|
501
|
+
ux-ui-promax)
|
|
502
|
+
echo " uipro - UI/UX design intelligence tool"
|
|
503
|
+
;;
|
|
504
|
+
openspec)
|
|
505
|
+
echo " openspec - OpenSpec CLI for spec-driven development"
|
|
506
|
+
;;
|
|
507
|
+
esac
|
|
508
|
+
done
|
|
509
|
+
fi
|
|
510
|
+
echo ""
|
|
511
|
+
echo "➡ Restart terminal or run: source ~/.zshrc"
|
|
512
|
+
echo "➡ Add API keys to: $ENV_FILE"
|
|
513
|
+
echo ""
|
|
514
|
+
echo "📁 Whitelisted workspaces:"
|
|
515
|
+
for ws in "${WORKSPACES[@]}"; do
|
|
516
|
+
echo " $ws"
|
|
517
|
+
done
|
|
518
|
+
echo ""
|
|
519
|
+
echo "💡 Manage workspaces in: $WORKSPACES_FILE"
|
|
520
|
+
echo " Add folder: echo '/path/to/folder' >> $WORKSPACES_FILE"
|
|
521
|
+
echo " Remove folder: Edit $WORKSPACES_FILE and delete the line"
|
|
522
|
+
echo " List folders: cat $WORKSPACES_FILE"
|
|
523
|
+
echo ""
|
|
524
|
+
echo "📁 Per-project configs supported:"
|
|
525
|
+
for tool in "${TOOLS[@]}"; do
|
|
526
|
+
if [[ "$tool" =~ ^(vscode|codeserver)$ ]]; then
|
|
527
|
+
continue
|
|
528
|
+
fi
|
|
529
|
+
echo " .$tool.json (overrides global config in $HOME/.config/$tool or $HOME/.$tool)"
|
|
530
|
+
done
|