ai-global 1.0.0 → 1.1.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 +66 -64
- package/ai-global +307 -238
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,49 +6,55 @@ Unified configuration manager for AI coding assistants. Edit one file, sync to a
|
|
|
6
6
|
|
|
7
7
|
## Supported Tools
|
|
8
8
|
|
|
9
|
-
| Tool
|
|
10
|
-
|
|
11
|
-
| Claude Code
|
|
12
|
-
| Cursor
|
|
13
|
-
| GitHub Copilot
|
|
14
|
-
| Factory Droid
|
|
15
|
-
| Gemini CLI
|
|
16
|
-
| Windsurf
|
|
17
|
-
| Kiro
|
|
18
|
-
| Qodo
|
|
19
|
-
| Antigravity
|
|
20
|
-
| Continue
|
|
21
|
-
| Cline
|
|
22
|
-
| Roo Code
|
|
23
|
-
| Sourcegraph Cody
|
|
24
|
-
| CodeGPT
|
|
25
|
-
| GPT Engineer
|
|
26
|
-
| Smol Developer
|
|
27
|
-
| Amp
|
|
28
|
-
| Trae
|
|
29
|
-
| OpenCode
|
|
30
|
-
| OpenAI Codex
|
|
31
|
-
| Aider
|
|
32
|
-
| Codeium
|
|
33
|
-
| TabNine
|
|
34
|
-
| Zed
|
|
35
|
-
| Aide
|
|
36
|
-
| PearAI
|
|
37
|
-
| Supermaven
|
|
38
|
-
| CodeStory
|
|
39
|
-
| Double
|
|
40
|
-
| Blackbox AI
|
|
41
|
-
| Amazon Q
|
|
42
|
-
| Copilot Workspace |
|
|
43
|
-
| Goose AI
|
|
44
|
-
| Mentat
|
|
45
|
-
| Melty
|
|
46
|
-
| Void
|
|
47
|
-
| Qoder
|
|
9
|
+
| Tool | Instructions | Skills | Agents | Rules | Commands | Prompts |
|
|
10
|
+
| ----------------- | :----------: | :----: | :----: | :---: | :------: | :-----: |
|
|
11
|
+
| Claude Code | ✓ | ✓ | | | ✓ | |
|
|
12
|
+
| Cursor | ✓ | ✓ | | | | ✓ |
|
|
13
|
+
| GitHub Copilot | ✓ | | | | | |
|
|
14
|
+
| Factory Droid | ✓ | | | | | |
|
|
15
|
+
| Gemini CLI | ✓ | ✓ | | | ✓ | |
|
|
16
|
+
| Windsurf | ✓ | ✓ | ✓ | ✓ | | |
|
|
17
|
+
| Kiro | ✓ | | ✓ | | | |
|
|
18
|
+
| Qodo | ✓ | | ✓ | | | |
|
|
19
|
+
| Antigravity | ✓ | ✓ | | | ✓ | |
|
|
20
|
+
| Continue | ✓ | | | ✓ | | ✓ |
|
|
21
|
+
| Cline | ✓ | | | ✓ | | ✓ |
|
|
22
|
+
| Roo Code | ✓ | | | ✓ | | |
|
|
23
|
+
| Sourcegraph Cody | ✓ | | | | ✓ | |
|
|
24
|
+
| CodeGPT | ✓ | | | | | ✓ |
|
|
25
|
+
| GPT Engineer | ✓ | | | | | ✓ |
|
|
26
|
+
| Smol Developer | ✓ | | | | | ✓ |
|
|
27
|
+
| Amp | ✓ | | | | | |
|
|
28
|
+
| Trae | ✓ | | | | | |
|
|
29
|
+
| OpenCode | ✓ | | | | | |
|
|
30
|
+
| OpenAI Codex | ✓ | | | | | |
|
|
31
|
+
| Aider | ✓ | | | | | |
|
|
32
|
+
| Codeium | ✓ | | | | | |
|
|
33
|
+
| TabNine | ✓ | | | | | |
|
|
34
|
+
| Zed | ✓ | | | | | |
|
|
35
|
+
| Aide | ✓ | | | | | |
|
|
36
|
+
| PearAI | ✓ | | | | | |
|
|
37
|
+
| Supermaven | ✓ | | | | | |
|
|
38
|
+
| CodeStory | ✓ | | | | | |
|
|
39
|
+
| Double | ✓ | | | | | |
|
|
40
|
+
| Blackbox AI | ✓ | | | | | |
|
|
41
|
+
| Amazon Q | ✓ | | | | | |
|
|
42
|
+
| Copilot Workspace | ✓ | | | | | |
|
|
43
|
+
| Goose AI | ✓ | | | | | |
|
|
44
|
+
| Mentat | ✓ | | | | | |
|
|
45
|
+
| Melty | ✓ | | | | | |
|
|
46
|
+
| Void | ✓ | | | | | |
|
|
47
|
+
| Qoder | ✓ | | | | | |
|
|
48
48
|
|
|
49
49
|
## Installation
|
|
50
50
|
|
|
51
|
-
###
|
|
51
|
+
### curl
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
curl -fsSL https://raw.githubusercontent.com/nanxiaobei/ai-global/main/install.sh | bash
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### npm
|
|
52
58
|
|
|
53
59
|
```bash
|
|
54
60
|
npm install -g ai-global
|
|
@@ -60,12 +66,6 @@ yarn global add ai-global
|
|
|
60
66
|
bun add -g ai-global
|
|
61
67
|
```
|
|
62
68
|
|
|
63
|
-
### curl
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
curl -fsSL https://raw.githubusercontent.com/nanxiaobei/ai-global/main/install.sh | bash
|
|
67
|
-
```
|
|
68
|
-
|
|
69
69
|
## Usage
|
|
70
70
|
|
|
71
71
|
### First run
|
|
@@ -75,6 +75,7 @@ ai-global
|
|
|
75
75
|
```
|
|
76
76
|
|
|
77
77
|
This will:
|
|
78
|
+
|
|
78
79
|
1. Scan your system for installed AI tools
|
|
79
80
|
2. Backup original configs to `~/.ai-global/backups/`
|
|
80
81
|
3. Merge instructions/skills/agents/rules/commands/prompts from all tools
|
|
@@ -90,23 +91,23 @@ Changes take effect immediately - all tools read the same file via symlinks.
|
|
|
90
91
|
|
|
91
92
|
### Commands
|
|
92
93
|
|
|
93
|
-
| Command
|
|
94
|
-
|
|
95
|
-
| `ai-global`
|
|
96
|
-
| `ai-global status`
|
|
97
|
-
| `ai-global list`
|
|
98
|
-
| `ai-global backups`
|
|
99
|
-
| `ai-global
|
|
100
|
-
| `ai-global
|
|
101
|
-
| `ai-global skill <source>`
|
|
102
|
-
| `ai-global agent <source>`
|
|
103
|
-
| `ai-global rule <source>`
|
|
104
|
-
| `ai-global command <source>` | Add a command
|
|
105
|
-
| `ai-global prompt <source>`
|
|
106
|
-
| `ai-global upgrade`
|
|
107
|
-
| `ai-global uninstall`
|
|
108
|
-
| `ai-global version`
|
|
109
|
-
| `ai-global help`
|
|
94
|
+
| Command | Description |
|
|
95
|
+
| ---------------------------- | ----------------------------------------- |
|
|
96
|
+
| `ai-global` | Scan, merge and update symlinks (default) |
|
|
97
|
+
| `ai-global status` | Show symlink status |
|
|
98
|
+
| `ai-global list` | List supported tools |
|
|
99
|
+
| `ai-global backups` | List available backups |
|
|
100
|
+
| `ai-global unlink <tool>` | Unlink a tool's original config |
|
|
101
|
+
| `ai-global unlink all` | Unlink all tools |
|
|
102
|
+
| `ai-global skill <source>` | Add a skill (file or GitHub repo) |
|
|
103
|
+
| `ai-global agent <source>` | Add an agent |
|
|
104
|
+
| `ai-global rule <source>` | Add a rule |
|
|
105
|
+
| `ai-global command <source>` | Add a command |
|
|
106
|
+
| `ai-global prompt <source>` | Add a prompt |
|
|
107
|
+
| `ai-global upgrade` | Upgrade to latest version |
|
|
108
|
+
| `ai-global uninstall` | Completely remove ai-global |
|
|
109
|
+
| `ai-global version` | Show version |
|
|
110
|
+
| `ai-global help` | Show help |
|
|
110
111
|
|
|
111
112
|
### Add skill/agent/rule/command/prompt
|
|
112
113
|
|
|
@@ -170,7 +171,8 @@ ai-global uninstall
|
|
|
170
171
|
```
|
|
171
172
|
|
|
172
173
|
This will:
|
|
173
|
-
|
|
174
|
+
|
|
175
|
+
1. Unlink all tools to original configuration
|
|
174
176
|
2. Remove `~/.ai-global` directory
|
|
175
177
|
3. Remove `ai-global` command
|
|
176
178
|
|
package/ai-global
CHANGED
|
@@ -6,9 +6,8 @@
|
|
|
6
6
|
set -e
|
|
7
7
|
|
|
8
8
|
CONFIG_DIR="$HOME/.ai-global"
|
|
9
|
-
KNOWN_TOOLS_FILE="$CONFIG_DIR/.known-tools"
|
|
10
9
|
BACKUP_DIR="$CONFIG_DIR/backups"
|
|
11
|
-
|
|
10
|
+
GLOBAL_MD="$CONFIG_DIR/global.md"
|
|
12
11
|
SKILLS_DIR="$CONFIG_DIR/skills"
|
|
13
12
|
AGENTS_DIR="$CONFIG_DIR/agents"
|
|
14
13
|
RULES_DIR="$CONFIG_DIR/rules"
|
|
@@ -39,8 +38,50 @@ GREEN='\033[0;32m'
|
|
|
39
38
|
YELLOW='\033[0;33m'
|
|
40
39
|
BLUE='\033[0;34m'
|
|
41
40
|
CYAN='\033[0;36m'
|
|
41
|
+
MAGENTA='\033[0;35m'
|
|
42
|
+
BRIGHT_RED='\033[1;31m'
|
|
43
|
+
BRIGHT_GREEN='\033[1;32m'
|
|
44
|
+
BRIGHT_YELLOW='\033[1;33m'
|
|
45
|
+
BRIGHT_BLUE='\033[1;34m'
|
|
46
|
+
BRIGHT_MAGENTA='\033[1;35m'
|
|
47
|
+
BRIGHT_CYAN='\033[1;36m'
|
|
42
48
|
NC='\033[0m'
|
|
43
49
|
|
|
50
|
+
# Tool color palette (using xterm-256 colors for more variety)
|
|
51
|
+
# We pick a spread of colors from the 256-color palette (avoiding too dark/grayscale)
|
|
52
|
+
TOOL_COLORS=(
|
|
53
|
+
"\033[38;5;39m" "\033[38;5;214m" "\033[38;5;118m" "\033[38;5;171m" "\033[38;5;208m"
|
|
54
|
+
"\033[38;5;45m" "\033[38;5;190m" "\033[38;5;161m" "\033[38;5;111m" "\033[38;5;220m"
|
|
55
|
+
"\033[38;5;75m" "\033[38;5;202m" "\033[38;5;112m" "\033[38;5;141m" "\033[38;5;210m"
|
|
56
|
+
"\033[38;5;47m" "\033[38;5;226m" "\033[38;5;201m" "\033[38;5;81m" "\033[38;5;215m"
|
|
57
|
+
"\033[38;5;51m" "\033[38;5;184m" "\033[38;5;197m" "\033[38;5;105m" "\033[38;5;209m"
|
|
58
|
+
"\033[38;5;121m" "\033[38;5;227m" "\033[38;5;165m" "\033[38;5;33m" "\033[38;5;216m"
|
|
59
|
+
"\033[38;5;159m" "\033[38;5;178m" "\033[38;5;162m" "\033[38;5;117m" "\033[38;5;221m"
|
|
60
|
+
"\033[38;5;78m" "\033[38;5;203m" "\033[38;5;113m" "\033[38;5;142m" "\033[38;5;211m"
|
|
61
|
+
"\033[38;5;159m" "\033[38;5;178m" "\033[38;5;162m" "\033[38;5;117m" "\033[38;5;221m"
|
|
62
|
+
"\033[38;5;78m" "\033[38;5;203m" "\033[38;5;113m" "\033[38;5;142m" "\033[38;5;211m"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
beautify_path() {
|
|
66
|
+
local path="$1"
|
|
67
|
+
if [[ "$path" == "$HOME"* ]]; then
|
|
68
|
+
local beautified="~${path#$HOME}"
|
|
69
|
+
echo "${beautified//\/\///}"
|
|
70
|
+
else
|
|
71
|
+
echo "$path"
|
|
72
|
+
fi
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
get_tool_color() {
|
|
76
|
+
local name="$1"
|
|
77
|
+
local sum=0
|
|
78
|
+
# Simple hash to pick a stable color index
|
|
79
|
+
for (( i=0; i<${#name}; i++ )); do
|
|
80
|
+
sum=$((sum + $(printf '%d' "'${name:$i:1}")))
|
|
81
|
+
done
|
|
82
|
+
echo -e "${TOOL_COLORS[$((sum % ${#TOOL_COLORS[@]}))]}"
|
|
83
|
+
}
|
|
84
|
+
|
|
44
85
|
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
45
86
|
log_ok() { echo -e "${GREEN}[OK]${NC} $1"; }
|
|
46
87
|
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
|
@@ -81,11 +122,11 @@ declare -a KNOWN_PATTERNS=(
|
|
|
81
122
|
".blackbox|Blackbox AI|config.json|.|.|.|.|."
|
|
82
123
|
".amazonq|Amazon Q|instructions.md|.|.|.|.|."
|
|
83
124
|
".copilot-workspace|Copilot Workspace|instructions.md|.|.|.|.|."
|
|
84
|
-
".codex|OpenAI Codex|instructions.md
|
|
85
|
-
".goose|Goose AI|instructions.md
|
|
86
|
-
".mentat|Mentat|instructions.md
|
|
87
|
-
".gpt-engineer|GPT Engineer|instructions.md
|
|
88
|
-
".smol|Smol Developer|instructions.md
|
|
125
|
+
".codex|OpenAI Codex|instructions.md|skills|agents|rules|.|."
|
|
126
|
+
".goose|Goose AI|instructions.md|skills|agents|rules|.|."
|
|
127
|
+
".mentat|Mentat|instructions.md|skills|agents|rules|.|."
|
|
128
|
+
".gpt-engineer|GPT Engineer|instructions.md|skills|agents|rules|.|prompts"
|
|
129
|
+
".smol|Smol Developer|instructions.md|skills|agents|rules|.|prompts"
|
|
89
130
|
".config/opencode|OpenCode Config|instructions.md|.|.|.|.|."
|
|
90
131
|
)
|
|
91
132
|
|
|
@@ -118,6 +159,7 @@ merge_items() {
|
|
|
118
159
|
local source_dir="$1"
|
|
119
160
|
local target_dir="$2"
|
|
120
161
|
local type="$3"
|
|
162
|
+
local tool_name="$4"
|
|
121
163
|
|
|
122
164
|
[[ ! -d "$source_dir" ]] && return
|
|
123
165
|
[[ -L "$source_dir" ]] && return
|
|
@@ -140,7 +182,18 @@ merge_items() {
|
|
|
140
182
|
done
|
|
141
183
|
|
|
142
184
|
if [[ $merged_count -gt 0 ]]; then
|
|
143
|
-
|
|
185
|
+
local tool_color=$(get_tool_color "$tool_name")
|
|
186
|
+
log_ok "Merged $merged_count $type from ${tool_color}${tool_name}${NC}"
|
|
187
|
+
fi
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
# Count items in directory (dirs and files)
|
|
191
|
+
count_items() {
|
|
192
|
+
local dir="$1"
|
|
193
|
+
if [[ -d "$dir" ]]; then
|
|
194
|
+
ls -1 "$dir" 2>/dev/null | wc -l | tr -d ' '
|
|
195
|
+
else
|
|
196
|
+
echo "0"
|
|
144
197
|
fi
|
|
145
198
|
}
|
|
146
199
|
|
|
@@ -154,118 +207,126 @@ create_symlink() {
|
|
|
154
207
|
local target_dir=$(dirname "$target")
|
|
155
208
|
mkdir -p "$target_dir"
|
|
156
209
|
|
|
210
|
+
# If target exists and is a real file/dir, it should have been backed up by backup_item already.
|
|
211
|
+
# We remove it to make room for the symlink, avoiding in-place backups.
|
|
157
212
|
if [[ -e "$target" ]] && [[ ! -L "$target" ]]; then
|
|
158
|
-
|
|
159
|
-
mv "$target" "$backup"
|
|
160
|
-
log_warn "Backed up: $target"
|
|
213
|
+
rm -rf "$target"
|
|
161
214
|
fi
|
|
162
215
|
|
|
163
216
|
[[ -L "$target" ]] && rm "$target"
|
|
164
217
|
ln -s "$source" "$target"
|
|
165
218
|
}
|
|
166
219
|
|
|
167
|
-
# Count files in directory
|
|
168
|
-
count_files() {
|
|
169
|
-
local dir="$1"
|
|
170
|
-
if [[ -d "$dir" ]]; then
|
|
171
|
-
find "$dir" -maxdepth 1 -type f 2>/dev/null | wc -l | tr -d ' '
|
|
172
|
-
else
|
|
173
|
-
echo "0"
|
|
174
|
-
fi
|
|
175
|
-
}
|
|
176
|
-
|
|
177
220
|
# Show symlink status
|
|
178
221
|
show_status() {
|
|
179
222
|
log_info "Symlink status:"
|
|
180
223
|
echo ""
|
|
181
224
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
225
|
+
local total_links=0
|
|
226
|
+
|
|
227
|
+
# Instructions
|
|
228
|
+
local instr_output=""
|
|
229
|
+
for pattern in "${KNOWN_PATTERNS[@]}"; do
|
|
230
|
+
local p_dir p_name p_instr p_skills p_agents p_rules p_cmds p_prompts
|
|
231
|
+
IFS='|' read -r p_dir p_name p_instr p_skills p_agents p_rules p_cmds p_prompts <<< "$pattern"
|
|
232
|
+
|
|
233
|
+
if [[ "$p_instr" != "." ]] && [[ "$p_instr" != *.json ]] && [[ "$p_instr" != *.yml ]]; then
|
|
234
|
+
local target="$HOME/$p_dir/$p_instr"
|
|
235
|
+
if [[ -L "$target" ]]; then
|
|
236
|
+
local link_target=$(readlink "$target" 2>/dev/null || true)
|
|
237
|
+
if [[ "$link_target" == *".ai-global"* ]]; then
|
|
238
|
+
local tool_color=$(get_tool_color "$p_name")
|
|
239
|
+
instr_output+=" ${tool_color}✓ $(beautify_path "$target")${NC}\n"
|
|
240
|
+
((total_links++))
|
|
241
|
+
fi
|
|
242
|
+
fi
|
|
243
|
+
fi
|
|
244
|
+
done
|
|
245
|
+
|
|
246
|
+
if [[ -n "$instr_output" ]]; then
|
|
247
|
+
echo -e "${BLUE}[global.md]${NC}"
|
|
248
|
+
echo -e -n "$instr_output"
|
|
185
249
|
fi
|
|
186
250
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
[[ -z "$dir_name" ]] && continue
|
|
251
|
+
for type_name in skills agents rules commands prompts; do
|
|
252
|
+
local type_output=""
|
|
190
253
|
for pattern in "${KNOWN_PATTERNS[@]}"; do
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
254
|
+
local p_dir p_name p_instr p_skills p_agents p_rules p_cmds p_prompts
|
|
255
|
+
IFS='|' read -r p_dir p_name p_instr p_skills p_agents p_rules p_cmds p_prompts <<< "$pattern"
|
|
256
|
+
|
|
257
|
+
local type_dir=""
|
|
258
|
+
case "$type_name" in
|
|
259
|
+
skills) type_dir="$p_skills" ;;
|
|
260
|
+
agents) type_dir="$p_agents" ;;
|
|
261
|
+
rules) type_dir="$p_rules" ;;
|
|
262
|
+
commands) type_dir="$p_cmds" ;;
|
|
263
|
+
prompts) type_dir="$p_prompts" ;;
|
|
264
|
+
esac
|
|
265
|
+
|
|
266
|
+
if [[ "$type_dir" != "." ]]; then
|
|
267
|
+
local target="$HOME/$p_dir/$type_dir"
|
|
268
|
+
if [[ -L "$target" ]]; then
|
|
269
|
+
local link_target=$(readlink "$target" 2>/dev/null || true)
|
|
270
|
+
if [[ "$link_target" == *".ai-global"* ]]; then
|
|
271
|
+
local tool_color=$(get_tool_color "$p_name")
|
|
272
|
+
type_output+=" ${tool_color}✓ $(beautify_path "$target")${NC}\n"
|
|
273
|
+
((total_links++))
|
|
201
274
|
fi
|
|
202
275
|
fi
|
|
203
|
-
break
|
|
204
276
|
fi
|
|
205
277
|
done
|
|
206
|
-
done < "$KNOWN_TOOLS_FILE"
|
|
207
278
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
for pattern in "${KNOWN_PATTERNS[@]}"; do
|
|
213
|
-
IFS='|' read -r known_dir tool_name instr_file skills agents rules commands prompts <<< "$pattern"
|
|
214
|
-
if [[ "$dir_name" == "$known_dir" ]]; then
|
|
215
|
-
local type_dir=""
|
|
216
|
-
case "$type_name" in
|
|
217
|
-
skills) type_dir="$skills" ;;
|
|
218
|
-
agents) type_dir="$agents" ;;
|
|
219
|
-
rules) type_dir="$rules" ;;
|
|
220
|
-
commands) type_dir="$commands" ;;
|
|
221
|
-
prompts) type_dir="$prompts" ;;
|
|
222
|
-
esac
|
|
223
|
-
if [[ "$type_dir" != "." ]]; then
|
|
224
|
-
local target="$HOME/$dir_name/$type_dir"
|
|
225
|
-
if [[ -L "$target" ]]; then
|
|
226
|
-
echo -e " ${GREEN}✓${NC} $target"
|
|
227
|
-
elif [[ -e "$target" ]]; then
|
|
228
|
-
echo -e " ${YELLOW}!${NC} $target (not a symlink)"
|
|
229
|
-
else
|
|
230
|
-
echo -e " ${RED}✗${NC} $target (missing)"
|
|
231
|
-
fi
|
|
232
|
-
fi
|
|
233
|
-
break
|
|
234
|
-
fi
|
|
235
|
-
done
|
|
236
|
-
done < "$KNOWN_TOOLS_FILE"
|
|
279
|
+
if [[ -n "$type_output" ]]; then
|
|
280
|
+
echo -e "\n${BLUE}[$type_name]${NC}"
|
|
281
|
+
echo -e -n "$type_output"
|
|
282
|
+
fi
|
|
237
283
|
done
|
|
238
284
|
|
|
285
|
+
if [[ $total_links -eq 0 ]]; then
|
|
286
|
+
echo " No active symlinks found."
|
|
287
|
+
fi
|
|
288
|
+
|
|
239
289
|
echo ""
|
|
240
|
-
log_info "Shared: skills=$(
|
|
290
|
+
log_info "Shared items: skills=$(count_items "$SKILLS_DIR"), agents=$(count_items "$AGENTS_DIR"), rules=$(count_items "$RULES_DIR"), commands=$(count_items "$COMMANDS_DIR"), prompts=$(count_items "$PROMPTS_DIR")"
|
|
241
291
|
}
|
|
242
292
|
|
|
243
293
|
# List supported tools
|
|
244
294
|
list_supported() {
|
|
245
295
|
log_info "Supported AI tools:"
|
|
246
296
|
echo ""
|
|
247
|
-
printf " ${BLUE}%-22s
|
|
248
|
-
echo "
|
|
297
|
+
printf " ${BLUE}%-22s %-20s %-10s %-10s %-10s %-10s %-10s %s${NC}\n" "Directory" "Tool" "Skills" "Agents" "Rules" "Cmds" "Prompts" "Status"
|
|
298
|
+
echo " --------------------------------------------------------------------------------------------------------------------------------"
|
|
249
299
|
|
|
250
300
|
for pattern in "${KNOWN_PATTERNS[@]}"; do
|
|
251
|
-
|
|
252
|
-
|
|
301
|
+
local p_dir p_name p_instr p_skills p_agents p_rules p_cmds p_prompts
|
|
302
|
+
IFS='|' read -r p_dir p_name p_instr p_skills p_agents p_rules p_cmds p_prompts <<< "$pattern"
|
|
303
|
+
local full_path="$HOME/$p_dir"
|
|
253
304
|
|
|
254
|
-
local
|
|
255
|
-
[[ "$
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
305
|
+
local s_str="." a_str="." r_str="." c_str="." p_str="."
|
|
306
|
+
if [[ -d "$full_path" ]]; then
|
|
307
|
+
[[ "$p_skills" != "." && -d "$full_path/$p_skills" ]] && s_str="✓"
|
|
308
|
+
[[ "$p_agents" != "." && -d "$full_path/$p_agents" ]] && a_str="✓"
|
|
309
|
+
[[ "$p_rules" != "." && -d "$full_path/$p_rules" ]] && r_str="✓"
|
|
310
|
+
[[ "$p_cmds" != "." && -d "$full_path/$p_cmds" ]] && c_str="✓"
|
|
311
|
+
# Prompts can be a file or dir
|
|
312
|
+
[[ "$p_prompts" != "." && -e "$full_path/$p_prompts" ]] && p_str="✓"
|
|
313
|
+
fi
|
|
260
314
|
|
|
261
315
|
local status=""
|
|
316
|
+
local tool_color=""
|
|
262
317
|
if [[ -d "$full_path" ]]; then
|
|
263
318
|
status="${GREEN}Installed${NC}"
|
|
319
|
+
tool_color=$(get_tool_color "$p_name")
|
|
264
320
|
else
|
|
265
321
|
status="${YELLOW}Not found${NC}"
|
|
322
|
+
tool_color="${NC}"
|
|
266
323
|
fi
|
|
267
324
|
|
|
268
|
-
|
|
325
|
+
# Use manual padding because printf handles multibyte characters (✓) by byte count in Bash 3.2.
|
|
326
|
+
# Each category block matches the header's "%-10s " (11 characters total).
|
|
327
|
+
# We use indicator + 10 spaces = 11 characters.
|
|
328
|
+
printf " %b%-22s %-20s%b %s %s %s %s %s %b\n" \
|
|
329
|
+
"$tool_color" "$p_dir" "$p_name" "$NC" "$s_str" "$a_str" "$r_str" "$c_str" "$p_str" "$status"
|
|
269
330
|
done
|
|
270
331
|
echo ""
|
|
271
332
|
}
|
|
@@ -275,22 +336,25 @@ list_backups() {
|
|
|
275
336
|
log_info "Available backups:"
|
|
276
337
|
echo ""
|
|
277
338
|
|
|
278
|
-
|
|
339
|
+
# Use ls -A to catch hidden files/dirs (starting with .)
|
|
340
|
+
local backups_list=$(ls -A "$BACKUP_DIR" 2>/dev/null || true)
|
|
341
|
+
|
|
342
|
+
if [[ -z "$backups_list" ]]; then
|
|
279
343
|
echo " No backups found"
|
|
280
344
|
echo ""
|
|
281
345
|
return
|
|
282
346
|
fi
|
|
283
347
|
|
|
284
|
-
printf " ${BLUE}%-25s
|
|
285
|
-
echo "
|
|
348
|
+
printf " ${BLUE}%-25s %-12s %s${NC}\n" "Tool" "Type" "Backup File"
|
|
349
|
+
echo " --------------------------------------------------------------------"
|
|
286
350
|
|
|
287
|
-
|
|
288
|
-
[[
|
|
289
|
-
local filename=$(basename "$backup")
|
|
351
|
+
while read -r filename; do
|
|
352
|
+
[[ -z "$filename" ]] && continue
|
|
290
353
|
local tool_name=""
|
|
291
354
|
local type=""
|
|
292
355
|
|
|
293
|
-
|
|
356
|
+
# Improved regex to handle various path characters
|
|
357
|
+
if [[ "$filename" =~ ^(.+)\.([^\.]+)\.([0-9]+)$ ]]; then
|
|
294
358
|
tool_name="${BASH_REMATCH[1]}"
|
|
295
359
|
type="${BASH_REMATCH[2]}"
|
|
296
360
|
else
|
|
@@ -298,8 +362,9 @@ list_backups() {
|
|
|
298
362
|
type="unknown"
|
|
299
363
|
fi
|
|
300
364
|
|
|
301
|
-
|
|
302
|
-
|
|
365
|
+
local tool_color=$(get_tool_color "${tool_name//_/ }")
|
|
366
|
+
printf " %s%-25s %-12s %s%b\n" "$tool_color" "$tool_name" "$type" "$filename" "$NC"
|
|
367
|
+
done <<< "$backups_list"
|
|
303
368
|
echo ""
|
|
304
369
|
}
|
|
305
370
|
|
|
@@ -329,15 +394,15 @@ collect_instructions() {
|
|
|
329
394
|
done
|
|
330
395
|
|
|
331
396
|
if [[ $found_count -gt 0 ]]; then
|
|
332
|
-
echo -e "$merged_content" > "$
|
|
397
|
+
echo -e "$merged_content" > "$GLOBAL_MD"
|
|
333
398
|
log_ok "Merged instructions from $found_count tool(s)"
|
|
334
399
|
else
|
|
335
|
-
cat > "$
|
|
400
|
+
cat > "$GLOBAL_MD" << 'EOF'
|
|
336
401
|
# AI Assistant Instructions
|
|
337
402
|
|
|
338
403
|
<!-- Add your instructions here. They will sync to all AI tools. -->
|
|
339
404
|
EOF
|
|
340
|
-
log_ok "Created: $
|
|
405
|
+
log_ok "Created: $GLOBAL_MD"
|
|
341
406
|
fi
|
|
342
407
|
}
|
|
343
408
|
|
|
@@ -348,11 +413,7 @@ update_tools() {
|
|
|
348
413
|
|
|
349
414
|
mkdir -p "$SKILLS_DIR" "$AGENTS_DIR" "$RULES_DIR" "$COMMANDS_DIR" "$PROMPTS_DIR" "$BACKUP_DIR"
|
|
350
415
|
|
|
351
|
-
|
|
352
|
-
collect_instructions
|
|
353
|
-
fi
|
|
354
|
-
|
|
355
|
-
> "$KNOWN_TOOLS_FILE"
|
|
416
|
+
collect_instructions
|
|
356
417
|
|
|
357
418
|
local tool_count=0
|
|
358
419
|
|
|
@@ -361,7 +422,8 @@ update_tools() {
|
|
|
361
422
|
local full_path="$HOME/$dir_name"
|
|
362
423
|
|
|
363
424
|
if [[ -d "$full_path" ]]; then
|
|
364
|
-
|
|
425
|
+
local color=$(get_tool_color "$tool_name")
|
|
426
|
+
echo -e "${GREEN}[OK]${NC} ${color}Found: $tool_name${NC}"
|
|
365
427
|
((tool_count++))
|
|
366
428
|
|
|
367
429
|
if [[ "$instr_file" != "." ]] && [[ "$instr_file" != *.json ]] && [[ "$instr_file" != *.yml ]]; then
|
|
@@ -389,11 +451,9 @@ update_tools() {
|
|
|
389
451
|
commands) target_dir="$COMMANDS_DIR" ;;
|
|
390
452
|
prompts) target_dir="$PROMPTS_DIR" ;;
|
|
391
453
|
esac
|
|
392
|
-
merge_items "$path" "$target_dir" "$type_name"
|
|
454
|
+
merge_items "$path" "$target_dir" "$type_name" "$tool_name"
|
|
393
455
|
fi
|
|
394
456
|
done
|
|
395
|
-
|
|
396
|
-
echo "$dir_name" >> "$KNOWN_TOOLS_FILE"
|
|
397
457
|
fi
|
|
398
458
|
done
|
|
399
459
|
|
|
@@ -405,47 +465,43 @@ update_tools() {
|
|
|
405
465
|
echo ""
|
|
406
466
|
log_info "Creating symlinks..."
|
|
407
467
|
|
|
408
|
-
|
|
409
|
-
|
|
468
|
+
for pattern in "${KNOWN_PATTERNS[@]}"; do
|
|
469
|
+
IFS='|' read -r dir_name tool_name instr_file skills agents rules commands prompts <<< "$pattern"
|
|
470
|
+
local full_path="$HOME/$dir_name"
|
|
410
471
|
|
|
411
|
-
|
|
412
|
-
|
|
472
|
+
if [[ -d "$full_path" ]]; then
|
|
473
|
+
local tool_color=$(get_tool_color "$tool_name")
|
|
474
|
+
if [[ "$instr_file" != "." ]] && [[ "$instr_file" != *.json ]] && [[ "$instr_file" != *.yml ]]; then
|
|
475
|
+
local target="$HOME/$dir_name/$instr_file"
|
|
476
|
+
create_symlink "$GLOBAL_MD" "$target"
|
|
477
|
+
printf " ${tool_color}✓ %-40s -> %s${NC}\n" "$(beautify_path "$target")" "$(beautify_path "$GLOBAL_MD")"
|
|
478
|
+
fi
|
|
413
479
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
480
|
+
for type_name in skills agents rules commands prompts; do
|
|
481
|
+
local type_dir=""
|
|
482
|
+
local source_dir=""
|
|
483
|
+
case "$type_name" in
|
|
484
|
+
skills) type_dir="$skills"; source_dir="$SKILLS_DIR" ;;
|
|
485
|
+
agents) type_dir="$agents"; source_dir="$AGENTS_DIR" ;;
|
|
486
|
+
rules) type_dir="$rules"; source_dir="$RULES_DIR" ;;
|
|
487
|
+
commands) type_dir="$commands"; source_dir="$COMMANDS_DIR" ;;
|
|
488
|
+
prompts) type_dir="$prompts"; source_dir="$PROMPTS_DIR" ;;
|
|
489
|
+
esac
|
|
490
|
+
if [[ "$type_dir" != "." ]]; then
|
|
491
|
+
local target="$HOME/$dir_name/$type_dir"
|
|
492
|
+
create_symlink "$source_dir" "$target"
|
|
493
|
+
printf " ${tool_color}✓ %-40s -> %s${NC}\n" "$(beautify_path "$target")" "$(beautify_path "$source_dir")/"
|
|
419
494
|
fi
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
local source_dir=""
|
|
424
|
-
case "$type_name" in
|
|
425
|
-
skills) type_dir="$skills"; source_dir="$SKILLS_DIR" ;;
|
|
426
|
-
agents) type_dir="$agents"; source_dir="$AGENTS_DIR" ;;
|
|
427
|
-
rules) type_dir="$rules"; source_dir="$RULES_DIR" ;;
|
|
428
|
-
commands) type_dir="$commands"; source_dir="$COMMANDS_DIR" ;;
|
|
429
|
-
prompts) type_dir="$prompts"; source_dir="$PROMPTS_DIR" ;;
|
|
430
|
-
esac
|
|
431
|
-
if [[ "$type_dir" != "." ]]; then
|
|
432
|
-
local target="$HOME/$dir_name/$type_dir"
|
|
433
|
-
create_symlink "$source_dir" "$target"
|
|
434
|
-
log_ok "$target -> $type_name/"
|
|
435
|
-
fi
|
|
436
|
-
done
|
|
437
|
-
|
|
438
|
-
break
|
|
439
|
-
fi
|
|
440
|
-
done
|
|
441
|
-
done < "$KNOWN_TOOLS_FILE"
|
|
495
|
+
done
|
|
496
|
+
fi
|
|
497
|
+
done
|
|
442
498
|
|
|
443
499
|
echo ""
|
|
444
|
-
log_info "Done! Shared: skills=$(
|
|
500
|
+
log_info "Done! Shared: skills=$(count_items "$SKILLS_DIR"), agents=$(count_items "$AGENTS_DIR"), rules=$(count_items "$RULES_DIR"), commands=$(count_items "$COMMANDS_DIR"), prompts=$(count_items "$PROMPTS_DIR")"
|
|
445
501
|
}
|
|
446
502
|
|
|
447
|
-
#
|
|
448
|
-
|
|
503
|
+
# Unlink a single tool
|
|
504
|
+
unlink_single_tool() {
|
|
449
505
|
local tool_name="$1"
|
|
450
506
|
local dir_name="$2"
|
|
451
507
|
local instr_file="$3"
|
|
@@ -454,19 +510,26 @@ restore_single_tool() {
|
|
|
454
510
|
local rules="$6"
|
|
455
511
|
local commands="$7"
|
|
456
512
|
local prompts="$8"
|
|
513
|
+
local silent="${9:-false}"
|
|
457
514
|
|
|
458
|
-
log_ok "Restoring: $tool_name"
|
|
459
515
|
local backup_name=$(echo "$dir_name" | tr '/' '_')
|
|
516
|
+
local worked=false
|
|
460
517
|
|
|
518
|
+
# Check for instructions link
|
|
461
519
|
if [[ "$instr_file" != "." ]]; then
|
|
462
520
|
local target="$HOME/$dir_name/$instr_file"
|
|
463
521
|
if [[ -L "$target" ]]; then
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
522
|
+
local link_target=$(readlink "$target" 2>/dev/null || true)
|
|
523
|
+
if [[ "$link_target" == *".ai-global"* ]]; then
|
|
524
|
+
rm "$target"
|
|
525
|
+
local backup_file=$(ls -t "$BACKUP_DIR"/${backup_name}.instructions.* 2>/dev/null | head -1)
|
|
526
|
+
[[ -f "$backup_file" ]] && cp "$backup_file" "$target"
|
|
527
|
+
worked=true
|
|
528
|
+
fi
|
|
467
529
|
fi
|
|
468
530
|
fi
|
|
469
531
|
|
|
532
|
+
# Check for components links
|
|
470
533
|
for type_name in skills agents rules commands prompts; do
|
|
471
534
|
local type_dir=""
|
|
472
535
|
case "$type_name" in
|
|
@@ -479,63 +542,85 @@ restore_single_tool() {
|
|
|
479
542
|
if [[ "$type_dir" != "." ]]; then
|
|
480
543
|
local target="$HOME/$dir_name/$type_dir"
|
|
481
544
|
if [[ -L "$target" ]]; then
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
545
|
+
local link_target=$(readlink "$target" 2>/dev/null || true)
|
|
546
|
+
if [[ "$link_target" == *".ai-global"* ]]; then
|
|
547
|
+
rm "$target"
|
|
548
|
+
local backup_file=$(ls -td "$BACKUP_DIR"/${backup_name}.${type_name}.* 2>/dev/null | head -1)
|
|
549
|
+
if [[ -d "$backup_file" ]]; then
|
|
550
|
+
cp -r "$backup_file" "$target"
|
|
551
|
+
fi
|
|
552
|
+
worked=true
|
|
488
553
|
fi
|
|
489
554
|
fi
|
|
490
555
|
fi
|
|
491
556
|
done
|
|
492
|
-
}
|
|
493
557
|
|
|
494
|
-
#
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
558
|
+
# Check for backups persistence
|
|
559
|
+
local has_backups=false
|
|
560
|
+
if [[ -n "$(ls "$BACKUP_DIR"/${backup_name}.* 2>/dev/null)" ]]; then
|
|
561
|
+
has_backups=true
|
|
562
|
+
rm -rf "$BACKUP_DIR"/${backup_name}.* 2>/dev/null || true
|
|
563
|
+
fi
|
|
498
564
|
|
|
499
|
-
if [[
|
|
500
|
-
|
|
501
|
-
|
|
565
|
+
if [[ "$worked" == true ]] || [[ "$has_backups" == true ]]; then
|
|
566
|
+
if [[ "$silent" != "true" ]]; then
|
|
567
|
+
local color=$(get_tool_color "$tool_name")
|
|
568
|
+
echo -e "${GREEN}[OK]${NC} ${color}Unlinked: $tool_name${NC}"
|
|
569
|
+
fi
|
|
570
|
+
return 0
|
|
502
571
|
fi
|
|
503
572
|
|
|
504
|
-
|
|
573
|
+
return 1
|
|
574
|
+
}
|
|
505
575
|
|
|
506
|
-
|
|
507
|
-
|
|
576
|
+
# Unlink all tools
|
|
577
|
+
unlink_all_tools() {
|
|
578
|
+
log_info "Unlinking tools..."
|
|
579
|
+
echo ""
|
|
508
580
|
|
|
509
|
-
|
|
510
|
-
|
|
581
|
+
local unlinked_count=0
|
|
582
|
+
# Scan all known patterns to find and remove any symlinks
|
|
583
|
+
for pattern in "${KNOWN_PATTERNS[@]}"; do
|
|
584
|
+
IFS='|' read -r dir_name tool_name instr_file skills agents rules commands prompts <<< "$pattern"
|
|
585
|
+
if unlink_single_tool "$tool_name" "$dir_name" "$instr_file" "$skills" "$agents" "$rules" "$commands" "$prompts"; then
|
|
586
|
+
((unlinked_count++))
|
|
587
|
+
fi
|
|
588
|
+
done
|
|
511
589
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
590
|
+
# Final sweep for any remaining symlinks pointing to .ai-global
|
|
591
|
+
find "$HOME" -maxdepth 3 -type l 2>/dev/null | while read -r link; do
|
|
592
|
+
local target=$(readlink "$link" 2>/dev/null || true)
|
|
593
|
+
if [[ "$target" == *".ai-global"* ]]; then
|
|
594
|
+
rm "$link"
|
|
595
|
+
log_ok "Removed unknown symlink: $(beautify_path "$link")"
|
|
596
|
+
((unlinked_count++))
|
|
597
|
+
fi
|
|
598
|
+
done
|
|
519
599
|
|
|
520
|
-
|
|
600
|
+
# Clear all backups as requested
|
|
601
|
+
rm -rf "$BACKUP_DIR"/* 2>/dev/null || true
|
|
521
602
|
|
|
522
603
|
echo ""
|
|
523
|
-
|
|
604
|
+
if [[ $unlinked_count -gt 0 ]]; then
|
|
605
|
+
log_info "Unlinked $unlinked_count item(s) and cleared backups. Shared data preserved."
|
|
606
|
+
else
|
|
607
|
+
log_info "No active symlinks found. Backups cleared."
|
|
608
|
+
fi
|
|
524
609
|
}
|
|
525
610
|
|
|
526
|
-
#
|
|
527
|
-
|
|
611
|
+
# Unlink a specific tool
|
|
612
|
+
unlink_tool() {
|
|
528
613
|
local tool_query="$1"
|
|
529
614
|
|
|
530
615
|
if [[ -z "$tool_query" ]]; then
|
|
531
|
-
log_error "Usage: ai-global
|
|
616
|
+
log_error "Usage: ai-global unlink <tool> or ai-global unlink all"
|
|
532
617
|
echo ""
|
|
533
618
|
list_backups
|
|
534
619
|
return 1
|
|
535
620
|
fi
|
|
536
621
|
|
|
537
622
|
if [[ "$tool_query" == "all" ]]; then
|
|
538
|
-
|
|
623
|
+
unlink_all_tools
|
|
539
624
|
return
|
|
540
625
|
fi
|
|
541
626
|
|
|
@@ -547,15 +632,9 @@ restore_tool() {
|
|
|
547
632
|
local query_lower=$(echo "$tool_query" | tr '[:upper:]' '[:lower:]')
|
|
548
633
|
|
|
549
634
|
if [[ "$tool_lower" == *"$query_lower"* ]] || [[ "$dir_name" == *"$query_lower"* ]]; then
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
if [[ -f "$KNOWN_TOOLS_FILE" ]]; then
|
|
554
|
-
grep -v "^$dir_name$" "$KNOWN_TOOLS_FILE" > "$KNOWN_TOOLS_FILE.tmp" 2>/dev/null || true
|
|
555
|
-
mv "$KNOWN_TOOLS_FILE.tmp" "$KNOWN_TOOLS_FILE"
|
|
635
|
+
if ! unlink_single_tool "$tool_name" "$dir_name" "$instr_file" "$skills" "$agents" "$rules" "$commands" "$prompts"; then
|
|
636
|
+
log_info "$tool_name is not currently linked."
|
|
556
637
|
fi
|
|
557
|
-
|
|
558
|
-
log_info "$tool_name restored"
|
|
559
638
|
found=true
|
|
560
639
|
break
|
|
561
640
|
fi
|
|
@@ -769,7 +848,7 @@ add_item() {
|
|
|
769
848
|
# Uninstall
|
|
770
849
|
uninstall() {
|
|
771
850
|
log_warn "This will:"
|
|
772
|
-
echo " 1.
|
|
851
|
+
echo " 1. Unlink all tools to original configuration"
|
|
773
852
|
echo " 2. Remove ~/.ai-global directory"
|
|
774
853
|
echo " 3. Remove ai-global from PATH"
|
|
775
854
|
echo ""
|
|
@@ -781,9 +860,7 @@ uninstall() {
|
|
|
781
860
|
return
|
|
782
861
|
fi
|
|
783
862
|
|
|
784
|
-
|
|
785
|
-
restore_all_tools
|
|
786
|
-
fi
|
|
863
|
+
unlink_all_tools
|
|
787
864
|
|
|
788
865
|
[[ -L /usr/local/bin/ai-global ]] && rm -f /usr/local/bin/ai-global
|
|
789
866
|
[[ -L "$HOME/.local/bin/ai-global" ]] && rm -f "$HOME/.local/bin/ai-global"
|
|
@@ -817,10 +894,16 @@ upgrade() {
|
|
|
817
894
|
|
|
818
895
|
log_info "Upgrading: $VERSION -> $remote_version"
|
|
819
896
|
|
|
897
|
+
local current_script="$0"
|
|
898
|
+
# If running via symlink, update the target
|
|
899
|
+
if [[ -L "$current_script" ]]; then
|
|
900
|
+
current_script=$(readlink "$current_script")
|
|
901
|
+
fi
|
|
902
|
+
|
|
820
903
|
local tmp_file=$(mktemp)
|
|
821
904
|
if curl -fsSL "https://raw.githubusercontent.com/nanxiaobei/ai-global/main/ai-global" -o "$tmp_file" 2>/dev/null; then
|
|
822
905
|
chmod +x "$tmp_file"
|
|
823
|
-
mv "$tmp_file" "$
|
|
906
|
+
mv "$tmp_file" "$current_script"
|
|
824
907
|
log_ok "Upgraded to v$remote_version"
|
|
825
908
|
else
|
|
826
909
|
rm -f "$tmp_file"
|
|
@@ -831,47 +914,32 @@ upgrade() {
|
|
|
831
914
|
|
|
832
915
|
# Show help
|
|
833
916
|
show_help() {
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
(default)
|
|
841
|
-
status
|
|
842
|
-
list
|
|
843
|
-
backups
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
~/.ai-global/rules/ Code rules
|
|
861
|
-
~/.ai-global/commands/ Slash commands
|
|
862
|
-
~/.ai-global/prompts/ Prompt templates
|
|
863
|
-
|
|
864
|
-
Examples:
|
|
865
|
-
ai-global # Scan, merge and update symlinks
|
|
866
|
-
ai-global skill react.md # Add a local skill file
|
|
867
|
-
ai-global skill user/repo # Add skills from GitHub repo (auto-detects skills/ dir)
|
|
868
|
-
ai-global agent coder.md # Add an agent
|
|
869
|
-
ai-global restore claude # Restore Claude's config
|
|
870
|
-
|
|
871
|
-
Note: When adding from GitHub, it auto-detects type subdirectories
|
|
872
|
-
(e.g., skills/, agents/, rules/) if they exist.
|
|
873
|
-
|
|
874
|
-
EOF
|
|
917
|
+
echo -e "${BLUE}AI-Global: Unified AI Tools Configuration Manager${NC} v$VERSION"
|
|
918
|
+
echo ""
|
|
919
|
+
echo -e "${BLUE}USAGE:${NC}"
|
|
920
|
+
echo -e " ai-global [command]"
|
|
921
|
+
echo ""
|
|
922
|
+
echo -e "${BLUE}CORE COMMANDS:${NC}"
|
|
923
|
+
echo -e " ${GREEN}(default)${NC} Scan, merge and update symlinks"
|
|
924
|
+
echo -e " ${GREEN}status${NC} Show symlink status"
|
|
925
|
+
echo -e " ${GREEN}list${NC} List all supported AI tools"
|
|
926
|
+
echo -e " ${GREEN}backups${NC} List available backups"
|
|
927
|
+
echo -e " ${GREEN}unlink <tool>${NC} Unlink a tool's original config"
|
|
928
|
+
echo -e " ${GREEN}unlink all${NC} Unlink all tools"
|
|
929
|
+
echo ""
|
|
930
|
+
echo -e "${BLUE}RESOURCE MANAGEMENT:${NC}"
|
|
931
|
+
echo -e " ${GREEN}skill <source>${NC} Add a skill (file, GitHub repo, or new)"
|
|
932
|
+
echo -e " ${GREEN}agent <source>${NC} Add an agent"
|
|
933
|
+
echo -e " ${GREEN}rule <source>${NC} Add a rule"
|
|
934
|
+
echo -e " ${GREEN}command <source>${NC} Add a command"
|
|
935
|
+
echo -e " ${GREEN}prompt <source>${NC} Add a prompt"
|
|
936
|
+
echo ""
|
|
937
|
+
echo -e "${BLUE}SYSTEM COMMANDS:${NC}"
|
|
938
|
+
echo -e " ${GREEN}upgrade${NC} Upgrade ai-global to latest version"
|
|
939
|
+
echo -e " ${GREEN}uninstall${NC} Completely remove ai-global"
|
|
940
|
+
echo -e " ${GREEN}version${NC} Show version"
|
|
941
|
+
echo -e " ${GREEN}help${NC} Show this help"
|
|
942
|
+
echo ""
|
|
875
943
|
}
|
|
876
944
|
|
|
877
945
|
# Main
|
|
@@ -883,26 +951,27 @@ main() {
|
|
|
883
951
|
exit 0
|
|
884
952
|
fi
|
|
885
953
|
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
log_info "No
|
|
954
|
+
case "$cmd" in
|
|
955
|
+
help|--help|-h) show_help; exit 0 ;;
|
|
956
|
+
list) list_supported; exit 0 ;;
|
|
957
|
+
version|-v|--version) show_version; exit 0 ;;
|
|
958
|
+
skill|agent|rule|command|prompt|unlink|status|backups|upgrade|uninstall)
|
|
959
|
+
if [[ ! -d "$CONFIG_DIR" ]]; then
|
|
960
|
+
log_info "No configuration found. Running initial scan..."
|
|
893
961
|
update_tools
|
|
894
|
-
[[ "$cmd" == "skill" || "$cmd" == "agent" || "$cmd" == "rule" || "$cmd" == "command" || "$cmd" == "prompt" ]] || exit 0
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
962
|
+
[[ "$cmd" == "skill" || "$cmd" == "agent" || "$cmd" == "rule" || "$cmd" == "command" || "$cmd" == "prompt" || "$cmd" == "status" ]] || exit 0
|
|
963
|
+
fi
|
|
964
|
+
;;
|
|
965
|
+
version|-v|--version|help|--help|-h) ;;
|
|
966
|
+
*) cmd="update" ;;
|
|
967
|
+
esac
|
|
899
968
|
|
|
900
969
|
case "$cmd" in
|
|
901
970
|
update) update_tools ;;
|
|
902
971
|
status) show_status ;;
|
|
903
972
|
list) list_supported ;;
|
|
904
973
|
backups) list_backups ;;
|
|
905
|
-
|
|
974
|
+
unlink) unlink_tool "$2" ;;
|
|
906
975
|
skill) add_item "skill" "$2" ;;
|
|
907
976
|
agent) add_item "agent" "$2" ;;
|
|
908
977
|
rule) add_item "rule" "$2" ;;
|