@conductor-oss/conductor-skills 1.4.2
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/.claude-plugin/marketplace.json +20 -0
- package/.claude-plugin/plugin.json +13 -0
- package/LICENSE.txt +176 -0
- package/README.md +352 -0
- package/VERSION +1 -0
- package/bin/conductor-skills.js +135 -0
- package/commands/conductor-optimize.md +18 -0
- package/commands/conductor-scaffold-worker.md +19 -0
- package/commands/conductor-setup.md +15 -0
- package/commands/conductor.md +15 -0
- package/install.ps1 +677 -0
- package/install.sh +855 -0
- package/package.json +50 -0
- package/skills/conductor/SKILL.md +151 -0
- package/skills/conductor/examples/ai-agent-loop.md +119 -0
- package/skills/conductor/examples/ai-agent-mcp.md +129 -0
- package/skills/conductor/examples/create-and-run-workflow.md +50 -0
- package/skills/conductor/examples/do-while-loop.md +72 -0
- package/skills/conductor/examples/fork-join.md +52 -0
- package/skills/conductor/examples/llm-chat.md +61 -0
- package/skills/conductor/examples/llm-rag.md +115 -0
- package/skills/conductor/examples/monitor-and-retry.md +54 -0
- package/skills/conductor/examples/review-workflow.md +67 -0
- package/skills/conductor/examples/signal-wait-task.md +36 -0
- package/skills/conductor/examples/sub-workflow.md +52 -0
- package/skills/conductor/examples/workflows/ai-agent-loop.json +88 -0
- package/skills/conductor/examples/workflows/ai-agent-mcp.json +69 -0
- package/skills/conductor/examples/workflows/child-normalize.json +21 -0
- package/skills/conductor/examples/workflows/do-while-loop.json +35 -0
- package/skills/conductor/examples/workflows/fork-join.json +61 -0
- package/skills/conductor/examples/workflows/llm-chat.json +28 -0
- package/skills/conductor/examples/workflows/llm-rag.json +49 -0
- package/skills/conductor/examples/workflows/parent-pipeline.json +35 -0
- package/skills/conductor/examples/workflows/weather-notification.json +42 -0
- package/skills/conductor/references/api-reference.md +111 -0
- package/skills/conductor/references/cli-index.md +92 -0
- package/skills/conductor/references/fallback-cli.md +36 -0
- package/skills/conductor/references/optimization.md +148 -0
- package/skills/conductor/references/orkes.md +57 -0
- package/skills/conductor/references/schedules.md +81 -0
- package/skills/conductor/references/setup.md +126 -0
- package/skills/conductor/references/troubleshooting.md +35 -0
- package/skills/conductor/references/visualization.md +49 -0
- package/skills/conductor/references/workers.md +227 -0
- package/skills/conductor/references/workflow-definition.md +672 -0
- package/skills/conductor/scripts/conductor_api.py +396 -0
package/install.sh
ADDED
|
@@ -0,0 +1,855 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
# Conductor Skills Installer
|
|
6
|
+
# Installs Conductor workflow orchestration skills for your AI coding agent.
|
|
7
|
+
# https://github.com/conductor-oss/conductor-skills
|
|
8
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
VERSION="1.4.2"
|
|
11
|
+
# Per-file fetches are pinned to this version's tag so the installer and the
|
|
12
|
+
# files it pulls always come from the same release. Pages can serve a cached
|
|
13
|
+
# install.sh older than `main`; pinning prevents schema drift.
|
|
14
|
+
# `main` is only used for fetch_remote_version (the "is there a newer release?"
|
|
15
|
+
# check), never for file content.
|
|
16
|
+
REPO_BASE="https://raw.githubusercontent.com/conductor-oss/conductor-skills/v${VERSION}"
|
|
17
|
+
REPO_MAIN="https://raw.githubusercontent.com/conductor-oss/conductor-skills/main"
|
|
18
|
+
|
|
19
|
+
# When set, skip the network fetch and copy from this directory instead.
|
|
20
|
+
# The npm package sets this so the bundled files are used.
|
|
21
|
+
LOCAL_DIR="${CONDUCTOR_SKILLS_LOCAL_DIR:-}"
|
|
22
|
+
|
|
23
|
+
# Files to ship to non-Claude agents (Claude uses the marketplace flow).
|
|
24
|
+
SKILL_FILES=(
|
|
25
|
+
"skills/conductor/SKILL.md"
|
|
26
|
+
"skills/conductor/references/setup.md"
|
|
27
|
+
"skills/conductor/references/cli-index.md"
|
|
28
|
+
"skills/conductor/references/fallback-cli.md"
|
|
29
|
+
"skills/conductor/references/workflow-definition.md"
|
|
30
|
+
"skills/conductor/references/workers.md"
|
|
31
|
+
"skills/conductor/references/api-reference.md"
|
|
32
|
+
"skills/conductor/references/visualization.md"
|
|
33
|
+
"skills/conductor/references/schedules.md"
|
|
34
|
+
"skills/conductor/references/orkes.md"
|
|
35
|
+
"skills/conductor/references/optimization.md"
|
|
36
|
+
"skills/conductor/references/troubleshooting.md"
|
|
37
|
+
"skills/conductor/examples/create-and-run-workflow.md"
|
|
38
|
+
"skills/conductor/examples/monitor-and-retry.md"
|
|
39
|
+
"skills/conductor/examples/signal-wait-task.md"
|
|
40
|
+
"skills/conductor/examples/fork-join.md"
|
|
41
|
+
"skills/conductor/examples/do-while-loop.md"
|
|
42
|
+
"skills/conductor/examples/sub-workflow.md"
|
|
43
|
+
"skills/conductor/examples/review-workflow.md"
|
|
44
|
+
"skills/conductor/examples/llm-chat.md"
|
|
45
|
+
"skills/conductor/examples/ai-agent-mcp.md"
|
|
46
|
+
"skills/conductor/examples/ai-agent-loop.md"
|
|
47
|
+
"skills/conductor/examples/llm-rag.md"
|
|
48
|
+
"skills/conductor/examples/workflows/weather-notification.json"
|
|
49
|
+
"skills/conductor/examples/workflows/fork-join.json"
|
|
50
|
+
"skills/conductor/examples/workflows/do-while-loop.json"
|
|
51
|
+
"skills/conductor/examples/workflows/child-normalize.json"
|
|
52
|
+
"skills/conductor/examples/workflows/parent-pipeline.json"
|
|
53
|
+
"skills/conductor/examples/workflows/llm-chat.json"
|
|
54
|
+
"skills/conductor/examples/workflows/ai-agent-mcp.json"
|
|
55
|
+
"skills/conductor/examples/workflows/ai-agent-loop.json"
|
|
56
|
+
"skills/conductor/examples/workflows/llm-rag.json"
|
|
57
|
+
"skills/conductor/scripts/conductor_api.py"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# Colors (if terminal supports them)
|
|
61
|
+
if [ -t 1 ]; then
|
|
62
|
+
RED='\033[0;31m'
|
|
63
|
+
GREEN='\033[0;32m'
|
|
64
|
+
YELLOW='\033[1;33m'
|
|
65
|
+
BLUE='\033[0;34m'
|
|
66
|
+
BOLD='\033[1m'
|
|
67
|
+
NC='\033[0m'
|
|
68
|
+
else
|
|
69
|
+
RED='' GREEN='' YELLOW='' BLUE='' BOLD='' NC=''
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
73
|
+
# Helpers
|
|
74
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
75
|
+
|
|
76
|
+
info() { echo -e "${BLUE}[info]${NC} $*"; }
|
|
77
|
+
ok() { echo -e "${GREEN}[ok]${NC} $*"; }
|
|
78
|
+
warn() { echo -e "${YELLOW}[warn]${NC} $*"; }
|
|
79
|
+
error() { echo -e "${RED}[error]${NC} $*" >&2; }
|
|
80
|
+
|
|
81
|
+
usage() {
|
|
82
|
+
cat <<EOF
|
|
83
|
+
${BOLD}Conductor Skills Installer v${VERSION}${NC}
|
|
84
|
+
|
|
85
|
+
Usage:
|
|
86
|
+
install.sh [--agent <name> | --all] [--global] [--project-dir <path>]
|
|
87
|
+
[--upgrade] [--check] [--force] [--uninstall]
|
|
88
|
+
|
|
89
|
+
Options:
|
|
90
|
+
--agent <name> Install for a specific agent
|
|
91
|
+
--all Auto-detect all agents and install for each
|
|
92
|
+
--global Install globally (available in all projects)
|
|
93
|
+
--project-dir <path> Target project directory (default: current directory)
|
|
94
|
+
--upgrade Check for newer version and upgrade installed agents
|
|
95
|
+
--check Dry run — show what would be installed, no changes
|
|
96
|
+
--force Overwrite existing files without prompting
|
|
97
|
+
--uninstall Remove installed skill files
|
|
98
|
+
--version Print version and exit
|
|
99
|
+
--help Show this help message
|
|
100
|
+
|
|
101
|
+
Supported agents:
|
|
102
|
+
claude Claude Code (Anthropic)
|
|
103
|
+
codex Codex CLI (OpenAI)
|
|
104
|
+
gemini Gemini CLI (Google)
|
|
105
|
+
cursor Cursor
|
|
106
|
+
windsurf Windsurf (Codeium)
|
|
107
|
+
cline Cline
|
|
108
|
+
aider Aider
|
|
109
|
+
copilot GitHub Copilot
|
|
110
|
+
amazonq Amazon Q Developer
|
|
111
|
+
opencode OpenCode
|
|
112
|
+
roo Roo Code
|
|
113
|
+
amp Amp
|
|
114
|
+
|
|
115
|
+
Examples:
|
|
116
|
+
# Auto-detect and install for all agents
|
|
117
|
+
install.sh --all
|
|
118
|
+
|
|
119
|
+
# Install globally for Codex CLI
|
|
120
|
+
install.sh --agent codex --global
|
|
121
|
+
|
|
122
|
+
# Check what would be installed
|
|
123
|
+
install.sh --all --check
|
|
124
|
+
|
|
125
|
+
# Upgrade all installed agents to latest
|
|
126
|
+
install.sh --all --upgrade
|
|
127
|
+
|
|
128
|
+
# Uninstall from all agents
|
|
129
|
+
install.sh --all --uninstall
|
|
130
|
+
|
|
131
|
+
EOF
|
|
132
|
+
exit 0
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
136
|
+
# Agent detection
|
|
137
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
138
|
+
|
|
139
|
+
detect_agents() {
|
|
140
|
+
local detected=()
|
|
141
|
+
|
|
142
|
+
command -v claude &>/dev/null && detected+=(claude)
|
|
143
|
+
{ command -v codex &>/dev/null || [ -d "$HOME/.codex" ]; } && detected+=(codex)
|
|
144
|
+
{ command -v gemini &>/dev/null || [ -d "$HOME/.gemini" ]; } && detected+=(gemini)
|
|
145
|
+
[ -d "$HOME/.cursor" ] && detected+=(cursor)
|
|
146
|
+
[ -d "$HOME/.codeium" ] && detected+=(windsurf)
|
|
147
|
+
[ -d "$HOME/.cline" ] && detected+=(cline)
|
|
148
|
+
command -v aider &>/dev/null && detected+=(aider)
|
|
149
|
+
[ -d "$HOME/.config/github-copilot" ] && detected+=(copilot)
|
|
150
|
+
{ command -v q &>/dev/null || [ -d "$HOME/.amazonq" ]; } && detected+=(amazonq)
|
|
151
|
+
command -v opencode &>/dev/null && detected+=(opencode)
|
|
152
|
+
[ -d "$HOME/.roo" ] && detected+=(roo)
|
|
153
|
+
{ command -v amp &>/dev/null || [ -d "$HOME/.config/amp" ]; } && detected+=(amp)
|
|
154
|
+
|
|
155
|
+
echo "${detected[@]}"
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
159
|
+
# Manifest tracking
|
|
160
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
161
|
+
|
|
162
|
+
GLOBAL_MANIFEST="$HOME/.conductor-skills/manifest.json"
|
|
163
|
+
|
|
164
|
+
get_manifest_path() {
|
|
165
|
+
local is_global="$1"
|
|
166
|
+
local project_dir="${2:-.}"
|
|
167
|
+
if [ "$is_global" = "true" ]; then
|
|
168
|
+
echo "$GLOBAL_MANIFEST"
|
|
169
|
+
else
|
|
170
|
+
echo "$project_dir/.conductor-skills/manifest.json"
|
|
171
|
+
fi
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
ensure_manifest() {
|
|
175
|
+
local manifest="$1"
|
|
176
|
+
local dir
|
|
177
|
+
dir=$(dirname "$manifest")
|
|
178
|
+
mkdir -p "$dir"
|
|
179
|
+
if [ ! -f "$manifest" ]; then
|
|
180
|
+
echo '{"schema_version":1,"installations":{}}' > "$manifest"
|
|
181
|
+
fi
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
read_manifest_version() {
|
|
185
|
+
local manifest="$1"
|
|
186
|
+
local agent="$2"
|
|
187
|
+
|
|
188
|
+
if [ ! -f "$manifest" ]; then
|
|
189
|
+
echo ""
|
|
190
|
+
return
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
python3 -c "
|
|
194
|
+
import json, sys
|
|
195
|
+
try:
|
|
196
|
+
m = json.load(open('$manifest'))
|
|
197
|
+
print(m.get('installations',{}).get('$agent',{}).get('version',''))
|
|
198
|
+
except: pass
|
|
199
|
+
" 2>/dev/null || echo ""
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
write_manifest_entry() {
|
|
203
|
+
local manifest="$1"
|
|
204
|
+
local agent="$2"
|
|
205
|
+
local ver="$3"
|
|
206
|
+
local mode="$4"
|
|
207
|
+
local target_path="$5"
|
|
208
|
+
|
|
209
|
+
ensure_manifest "$manifest"
|
|
210
|
+
|
|
211
|
+
python3 -c "
|
|
212
|
+
import json, datetime
|
|
213
|
+
m = json.load(open('$manifest'))
|
|
214
|
+
now = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
|
|
215
|
+
entry = m.setdefault('installations',{}).get('$agent',{})
|
|
216
|
+
m['installations']['$agent'] = {
|
|
217
|
+
'version': '$ver',
|
|
218
|
+
'installed_at': entry.get('installed_at', now),
|
|
219
|
+
'updated_at': now,
|
|
220
|
+
'mode': '$mode',
|
|
221
|
+
'target_path': '$target_path'
|
|
222
|
+
}
|
|
223
|
+
json.dump(m, open('$manifest','w'), indent=2)
|
|
224
|
+
" 2>/dev/null
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
remove_manifest_entry() {
|
|
228
|
+
local manifest="$1"
|
|
229
|
+
local agent="$2"
|
|
230
|
+
|
|
231
|
+
if [ ! -f "$manifest" ]; then
|
|
232
|
+
return
|
|
233
|
+
fi
|
|
234
|
+
|
|
235
|
+
python3 -c "
|
|
236
|
+
import json
|
|
237
|
+
m = json.load(open('$manifest'))
|
|
238
|
+
m.get('installations',{}).pop('$agent', None)
|
|
239
|
+
json.dump(m, open('$manifest','w'), indent=2)
|
|
240
|
+
" 2>/dev/null
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
list_manifest_agents() {
|
|
244
|
+
local manifest="$1"
|
|
245
|
+
|
|
246
|
+
if [ ! -f "$manifest" ]; then
|
|
247
|
+
echo ""
|
|
248
|
+
return
|
|
249
|
+
fi
|
|
250
|
+
|
|
251
|
+
python3 -c "
|
|
252
|
+
import json
|
|
253
|
+
try:
|
|
254
|
+
m = json.load(open('$manifest'))
|
|
255
|
+
agents = list(m.get('installations',{}).keys())
|
|
256
|
+
print(' '.join(agents))
|
|
257
|
+
except: pass
|
|
258
|
+
" 2>/dev/null || echo ""
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
262
|
+
# Remote version check
|
|
263
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
264
|
+
|
|
265
|
+
fetch_remote_version() {
|
|
266
|
+
if [ -n "$LOCAL_DIR" ] && [ -f "$LOCAL_DIR/VERSION" ]; then
|
|
267
|
+
cat "$LOCAL_DIR/VERSION" | tr -d '[:space:]'
|
|
268
|
+
return
|
|
269
|
+
fi
|
|
270
|
+
local remote_ver
|
|
271
|
+
remote_ver=$(curl -sSfL "$REPO_MAIN/VERSION" 2>/dev/null | tr -d '[:space:]') || true
|
|
272
|
+
echo "$remote_ver"
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
276
|
+
# Download & assembly
|
|
277
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
278
|
+
|
|
279
|
+
download_files() {
|
|
280
|
+
local tmp_dir="$1"
|
|
281
|
+
|
|
282
|
+
if [ -n "$LOCAL_DIR" ]; then
|
|
283
|
+
if [ ! -d "$LOCAL_DIR" ]; then
|
|
284
|
+
error "CONDUCTOR_SKILLS_LOCAL_DIR=$LOCAL_DIR is not a directory"
|
|
285
|
+
exit 1
|
|
286
|
+
fi
|
|
287
|
+
info "Copying skill files from $LOCAL_DIR..."
|
|
288
|
+
for file in "${SKILL_FILES[@]}"; do
|
|
289
|
+
local src="$LOCAL_DIR/$file"
|
|
290
|
+
local dest="$tmp_dir/$file"
|
|
291
|
+
if [ ! -f "$src" ]; then
|
|
292
|
+
error "Missing file in local source: $file"
|
|
293
|
+
# tmp_dir cleanup handled by EXIT trap
|
|
294
|
+
exit 1
|
|
295
|
+
fi
|
|
296
|
+
mkdir -p "$(dirname "$dest")"
|
|
297
|
+
cp "$src" "$dest"
|
|
298
|
+
done
|
|
299
|
+
ok "Copied ${#SKILL_FILES[@]} files"
|
|
300
|
+
return
|
|
301
|
+
fi
|
|
302
|
+
|
|
303
|
+
info "Downloading skill files..."
|
|
304
|
+
for file in "${SKILL_FILES[@]}"; do
|
|
305
|
+
local dir
|
|
306
|
+
dir=$(dirname "$file")
|
|
307
|
+
mkdir -p "$tmp_dir/$dir"
|
|
308
|
+
if ! curl -sSfL "$REPO_BASE/$file" -o "$tmp_dir/$file" 2>/dev/null; then
|
|
309
|
+
error "Failed to download $file"
|
|
310
|
+
error "Check your internet connection and try again."
|
|
311
|
+
# tmp_dir cleanup handled by EXIT trap
|
|
312
|
+
exit 1
|
|
313
|
+
fi
|
|
314
|
+
done
|
|
315
|
+
ok "Downloaded ${#SKILL_FILES[@]} files"
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
assemble_content() {
|
|
319
|
+
local tmp_dir="$1"
|
|
320
|
+
local output="$2"
|
|
321
|
+
|
|
322
|
+
{
|
|
323
|
+
cat "$tmp_dir/skills/conductor/SKILL.md"
|
|
324
|
+
echo ""
|
|
325
|
+
echo "---"
|
|
326
|
+
echo ""
|
|
327
|
+
echo "# References"
|
|
328
|
+
echo ""
|
|
329
|
+
for f in "$tmp_dir"/skills/conductor/references/*.md; do
|
|
330
|
+
cat "$f"
|
|
331
|
+
echo ""
|
|
332
|
+
echo "---"
|
|
333
|
+
echo ""
|
|
334
|
+
done
|
|
335
|
+
echo "# Examples"
|
|
336
|
+
echo ""
|
|
337
|
+
for f in "$tmp_dir"/skills/conductor/examples/*.md; do
|
|
338
|
+
cat "$f"
|
|
339
|
+
echo ""
|
|
340
|
+
echo "---"
|
|
341
|
+
echo ""
|
|
342
|
+
done
|
|
343
|
+
} > "$output"
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
347
|
+
# Safe file writing (respects --force)
|
|
348
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
349
|
+
|
|
350
|
+
safe_write() {
|
|
351
|
+
local target="$1"
|
|
352
|
+
local source="$2"
|
|
353
|
+
local force="$3"
|
|
354
|
+
|
|
355
|
+
if [ -f "$target" ] && [ "$force" != "true" ]; then
|
|
356
|
+
warn "File already exists: $target"
|
|
357
|
+
printf " Overwrite? [y/N] "
|
|
358
|
+
read -r answer
|
|
359
|
+
if [[ ! "$answer" =~ ^[Yy] ]]; then
|
|
360
|
+
info "Skipped. Use --force to overwrite."
|
|
361
|
+
return 1
|
|
362
|
+
fi
|
|
363
|
+
fi
|
|
364
|
+
|
|
365
|
+
local dir
|
|
366
|
+
dir=$(dirname "$target")
|
|
367
|
+
mkdir -p "$dir"
|
|
368
|
+
cp "$source" "$target"
|
|
369
|
+
ok "Installed: $target"
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
373
|
+
# Global install paths
|
|
374
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
375
|
+
|
|
376
|
+
supports_global() {
|
|
377
|
+
local agent="$1"
|
|
378
|
+
case "$agent" in
|
|
379
|
+
claude|codex|gemini|cursor|windsurf|roo|amp|aider|opencode) return 0 ;;
|
|
380
|
+
*) return 1 ;;
|
|
381
|
+
esac
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
get_global_path() {
|
|
385
|
+
local agent="$1"
|
|
386
|
+
case "$agent" in
|
|
387
|
+
claude) echo "__claude__" ;;
|
|
388
|
+
codex) echo "${CODEX_HOME:-$HOME/.codex}/AGENTS.md" ;;
|
|
389
|
+
cursor) echo "$HOME/.cursor/skills/conductor/SKILL.md" ;;
|
|
390
|
+
gemini) echo "$HOME/.gemini/GEMINI.md" ;;
|
|
391
|
+
windsurf) echo "$HOME/.codeium/windsurf/memories/global_rules.md" ;;
|
|
392
|
+
roo) echo "$HOME/.roo/rules/conductor.md" ;;
|
|
393
|
+
amp) echo "$HOME/.config/AGENTS.md" ;;
|
|
394
|
+
aider) echo "$HOME/.aider.conf.yml" ;;
|
|
395
|
+
opencode) echo "$HOME/.config/opencode/skills/conductor/SKILL.md" ;;
|
|
396
|
+
esac
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
get_target_path() {
|
|
400
|
+
local agent="$1"
|
|
401
|
+
local project_dir="$2"
|
|
402
|
+
|
|
403
|
+
case "$agent" in
|
|
404
|
+
claude) echo "__claude__" ;;
|
|
405
|
+
codex) echo "$project_dir/AGENTS.md" ;;
|
|
406
|
+
gemini) echo "$project_dir/GEMINI.md" ;;
|
|
407
|
+
cursor) echo "$project_dir/.cursor/rules/conductor.mdc" ;;
|
|
408
|
+
windsurf) echo "$project_dir/.windsurfrules" ;;
|
|
409
|
+
cline) echo "$project_dir/.clinerules" ;;
|
|
410
|
+
aider) echo "$project_dir/.conductor-skills" ;;
|
|
411
|
+
copilot) echo "$project_dir/.github/copilot-instructions.md" ;;
|
|
412
|
+
amazonq) echo "$project_dir/.amazonq/rules/conductor.md" ;;
|
|
413
|
+
opencode) echo "$project_dir/AGENTS.md" ;;
|
|
414
|
+
roo) echo "$project_dir/.roo/rules/conductor.md" ;;
|
|
415
|
+
amp) echo "$project_dir/.amp/instructions.md" ;;
|
|
416
|
+
esac
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
420
|
+
# Per-agent install logic
|
|
421
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
422
|
+
|
|
423
|
+
install_claude() {
|
|
424
|
+
# Claude Code installs plugins via the in-session `/plugin` commands, not a
|
|
425
|
+
# shell subcommand. Print clear instructions; do not try to invoke a CLI
|
|
426
|
+
# subcommand that does not exist.
|
|
427
|
+
if ! command -v claude &>/dev/null; then
|
|
428
|
+
warn "'claude' CLI not found, but the Claude install is in-session anyway."
|
|
429
|
+
fi
|
|
430
|
+
|
|
431
|
+
info "Conductor Skills is a Claude Code plugin. Run these in your Claude Code session:"
|
|
432
|
+
echo ""
|
|
433
|
+
echo " /plugin marketplace add conductor-oss/conductor-skills"
|
|
434
|
+
echo " /plugin install conductor@conductor-skills"
|
|
435
|
+
echo ""
|
|
436
|
+
info "Once installed, slash commands like /conductor, /conductor-setup,"
|
|
437
|
+
info "/conductor-optimize, and /conductor-scaffold-worker become available."
|
|
438
|
+
ok "Claude Code install instructions printed above."
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
install_to_file() {
|
|
442
|
+
local target="$1"
|
|
443
|
+
local assembled="$2"
|
|
444
|
+
local force="$3"
|
|
445
|
+
local prefix="${4:-}"
|
|
446
|
+
|
|
447
|
+
if [ -n "$prefix" ]; then
|
|
448
|
+
local tmp_with_prefix
|
|
449
|
+
tmp_with_prefix=$(mktemp)
|
|
450
|
+
{
|
|
451
|
+
echo "$prefix"
|
|
452
|
+
cat "$assembled"
|
|
453
|
+
} > "$tmp_with_prefix"
|
|
454
|
+
safe_write "$target" "$tmp_with_prefix" "$force"
|
|
455
|
+
rm -f "$tmp_with_prefix"
|
|
456
|
+
else
|
|
457
|
+
safe_write "$target" "$assembled" "$force"
|
|
458
|
+
fi
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
install_aider_to_dir() {
|
|
462
|
+
local skill_dir="$1"
|
|
463
|
+
local tmp_dir="$2"
|
|
464
|
+
local config="$3"
|
|
465
|
+
local read_prefix="$4"
|
|
466
|
+
|
|
467
|
+
mkdir -p "$skill_dir/references" "$skill_dir/examples" "$skill_dir/scripts"
|
|
468
|
+
|
|
469
|
+
info "Copying skill files to $skill_dir ..."
|
|
470
|
+
cp "$tmp_dir/skills/conductor/SKILL.md" "$skill_dir/"
|
|
471
|
+
for f in "$tmp_dir"/skills/conductor/references/*.md; do
|
|
472
|
+
cp "$f" "$skill_dir/references/"
|
|
473
|
+
done
|
|
474
|
+
for f in "$tmp_dir"/skills/conductor/examples/*.md; do
|
|
475
|
+
cp "$f" "$skill_dir/examples/"
|
|
476
|
+
done
|
|
477
|
+
for f in "$tmp_dir"/skills/conductor/scripts/*.py; do
|
|
478
|
+
[ -f "$f" ] && cp "$f" "$skill_dir/scripts/"
|
|
479
|
+
done
|
|
480
|
+
ok "Files copied to $skill_dir"
|
|
481
|
+
|
|
482
|
+
if [ -f "$config" ] && grep -q "conductor-skills" "$config" 2>/dev/null; then
|
|
483
|
+
info "Aider config already references conductor-skills, skipping."
|
|
484
|
+
else
|
|
485
|
+
info "Adding read entries to $config ..."
|
|
486
|
+
{
|
|
487
|
+
echo ""
|
|
488
|
+
echo "# Conductor Skills"
|
|
489
|
+
echo "read:"
|
|
490
|
+
for file in "${SKILL_FILES[@]}"; do
|
|
491
|
+
echo " - ${read_prefix}${file#skills/conductor/}"
|
|
492
|
+
done
|
|
493
|
+
} >> "$config"
|
|
494
|
+
ok "Updated: $config"
|
|
495
|
+
fi
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
# Install a single agent. Returns 0 on success, 1 on skip/failure.
|
|
499
|
+
install_for_agent() {
|
|
500
|
+
local agent="$1"
|
|
501
|
+
local project_dir="$2"
|
|
502
|
+
local is_global="$3"
|
|
503
|
+
local force="$4"
|
|
504
|
+
local tmp_dir="$5"
|
|
505
|
+
local assembled="$6"
|
|
506
|
+
|
|
507
|
+
# Claude has its own install path
|
|
508
|
+
if [ "$agent" = "claude" ]; then
|
|
509
|
+
install_claude
|
|
510
|
+
return $?
|
|
511
|
+
fi
|
|
512
|
+
|
|
513
|
+
if [ "$is_global" = "true" ]; then
|
|
514
|
+
local target_path
|
|
515
|
+
target_path=$(get_global_path "$agent")
|
|
516
|
+
|
|
517
|
+
if [ "$agent" = "aider" ]; then
|
|
518
|
+
install_aider_to_dir "$HOME/.conductor-skills" "$tmp_dir" "$HOME/.aider.conf.yml" "$HOME/.conductor-skills/"
|
|
519
|
+
else
|
|
520
|
+
install_to_file "$target_path" "$assembled" "$force"
|
|
521
|
+
fi
|
|
522
|
+
else
|
|
523
|
+
case "$agent" in
|
|
524
|
+
codex)
|
|
525
|
+
install_to_file "$project_dir/AGENTS.md" "$assembled" "$force"
|
|
526
|
+
;;
|
|
527
|
+
gemini)
|
|
528
|
+
install_to_file "$project_dir/GEMINI.md" "$assembled" "$force"
|
|
529
|
+
;;
|
|
530
|
+
cursor)
|
|
531
|
+
local frontmatter
|
|
532
|
+
frontmatter=$(cat <<'FRONT'
|
|
533
|
+
---
|
|
534
|
+
description: Conductor workflow orchestration - create, run, monitor, and manage workflows
|
|
535
|
+
globs: "**/*"
|
|
536
|
+
alwaysApply: true
|
|
537
|
+
---
|
|
538
|
+
|
|
539
|
+
FRONT
|
|
540
|
+
)
|
|
541
|
+
install_to_file "$project_dir/.cursor/rules/conductor.mdc" "$assembled" "$force" "$frontmatter"
|
|
542
|
+
;;
|
|
543
|
+
windsurf)
|
|
544
|
+
install_to_file "$project_dir/.windsurfrules" "$assembled" "$force"
|
|
545
|
+
;;
|
|
546
|
+
cline)
|
|
547
|
+
install_to_file "$project_dir/.clinerules" "$assembled" "$force"
|
|
548
|
+
;;
|
|
549
|
+
aider)
|
|
550
|
+
install_aider_to_dir "$project_dir/.conductor-skills" "$tmp_dir" "$project_dir/.aider.conf.yml" ".conductor-skills/"
|
|
551
|
+
;;
|
|
552
|
+
copilot)
|
|
553
|
+
install_to_file "$project_dir/.github/copilot-instructions.md" "$assembled" "$force"
|
|
554
|
+
;;
|
|
555
|
+
amazonq)
|
|
556
|
+
install_to_file "$project_dir/.amazonq/rules/conductor.md" "$assembled" "$force"
|
|
557
|
+
;;
|
|
558
|
+
opencode)
|
|
559
|
+
install_to_file "$project_dir/AGENTS.md" "$assembled" "$force"
|
|
560
|
+
;;
|
|
561
|
+
roo)
|
|
562
|
+
install_to_file "$project_dir/.roo/rules/conductor.md" "$assembled" "$force"
|
|
563
|
+
;;
|
|
564
|
+
amp)
|
|
565
|
+
install_to_file "$project_dir/.amp/instructions.md" "$assembled" "$force"
|
|
566
|
+
;;
|
|
567
|
+
esac
|
|
568
|
+
fi
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
572
|
+
# Uninstall
|
|
573
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
574
|
+
|
|
575
|
+
uninstall_agent() {
|
|
576
|
+
local agent="$1"
|
|
577
|
+
local project_dir="$2"
|
|
578
|
+
local is_global="$3"
|
|
579
|
+
|
|
580
|
+
if [ "$agent" = "claude" ]; then
|
|
581
|
+
info "To remove the Conductor skill from Claude Code, run:"
|
|
582
|
+
echo " /plugin uninstall conductor@conductor-skills (in your Claude Code session)"
|
|
583
|
+
return
|
|
584
|
+
fi
|
|
585
|
+
|
|
586
|
+
local target
|
|
587
|
+
if [ "$is_global" = "true" ]; then
|
|
588
|
+
if [ "$agent" = "aider" ]; then
|
|
589
|
+
local skill_dir="$HOME/.conductor-skills"
|
|
590
|
+
if [ -d "$skill_dir" ]; then
|
|
591
|
+
rm -rf "$skill_dir"
|
|
592
|
+
ok "Removed: $skill_dir"
|
|
593
|
+
info "Note: You may also want to remove the 'read:' entries from ~/.aider.conf.yml"
|
|
594
|
+
else
|
|
595
|
+
warn "Nothing to uninstall: $skill_dir not found"
|
|
596
|
+
fi
|
|
597
|
+
return
|
|
598
|
+
fi
|
|
599
|
+
target=$(get_global_path "$agent")
|
|
600
|
+
else
|
|
601
|
+
target=$(get_target_path "$agent" "$project_dir")
|
|
602
|
+
if [ "$agent" = "aider" ]; then
|
|
603
|
+
if [ -d "$target" ]; then
|
|
604
|
+
rm -rf "$target"
|
|
605
|
+
ok "Removed: $target"
|
|
606
|
+
info "Note: You may also want to remove the 'read:' entries from .aider.conf.yml"
|
|
607
|
+
else
|
|
608
|
+
warn "Nothing to uninstall: $target not found"
|
|
609
|
+
fi
|
|
610
|
+
return
|
|
611
|
+
fi
|
|
612
|
+
fi
|
|
613
|
+
|
|
614
|
+
if [ -f "$target" ]; then
|
|
615
|
+
rm -f "$target"
|
|
616
|
+
ok "Removed: $target"
|
|
617
|
+
else
|
|
618
|
+
warn "Nothing to uninstall: $target not found"
|
|
619
|
+
fi
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
623
|
+
# Check mode (dry run)
|
|
624
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
625
|
+
|
|
626
|
+
do_check() {
|
|
627
|
+
local agents=("$@")
|
|
628
|
+
|
|
629
|
+
local manifest
|
|
630
|
+
manifest=$(get_manifest_path "true" "")
|
|
631
|
+
|
|
632
|
+
echo ""
|
|
633
|
+
echo -e "${BOLD}Detected agents:${NC}"
|
|
634
|
+
if [ ${#agents[@]} -eq 0 ]; then
|
|
635
|
+
warn "No AI coding agents detected on this system."
|
|
636
|
+
return
|
|
637
|
+
fi
|
|
638
|
+
|
|
639
|
+
for agent in "${agents[@]}"; do
|
|
640
|
+
local installed_ver
|
|
641
|
+
installed_ver=$(read_manifest_version "$manifest" "$agent")
|
|
642
|
+
local global_support="yes"
|
|
643
|
+
supports_global "$agent" || global_support="no"
|
|
644
|
+
|
|
645
|
+
if [ -n "$installed_ver" ]; then
|
|
646
|
+
if [ "$installed_ver" = "$VERSION" ]; then
|
|
647
|
+
echo -e " ${GREEN}●${NC} $agent v${installed_ver} (up to date)"
|
|
648
|
+
else
|
|
649
|
+
echo -e " ${YELLOW}●${NC} $agent v${installed_ver} → v${VERSION} (upgrade available)"
|
|
650
|
+
fi
|
|
651
|
+
else
|
|
652
|
+
echo -e " ${BLUE}●${NC} $agent (not installed) global: $global_support"
|
|
653
|
+
fi
|
|
654
|
+
done
|
|
655
|
+
echo ""
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
659
|
+
# Main
|
|
660
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
661
|
+
|
|
662
|
+
main() {
|
|
663
|
+
local agent=""
|
|
664
|
+
local project_dir="."
|
|
665
|
+
local force="false"
|
|
666
|
+
local uninstall="false"
|
|
667
|
+
local global="false"
|
|
668
|
+
local all="false"
|
|
669
|
+
local upgrade="false"
|
|
670
|
+
local check="false"
|
|
671
|
+
|
|
672
|
+
while [[ $# -gt 0 ]]; do
|
|
673
|
+
case "$1" in
|
|
674
|
+
--agent) agent="$2"; shift 2 ;;
|
|
675
|
+
--project-dir) project_dir="$2"; shift 2 ;;
|
|
676
|
+
--global) global="true"; shift ;;
|
|
677
|
+
--all) all="true"; shift ;;
|
|
678
|
+
--upgrade) upgrade="true"; shift ;;
|
|
679
|
+
--check) check="true"; shift ;;
|
|
680
|
+
--force) force="true"; shift ;;
|
|
681
|
+
--uninstall) uninstall="true"; shift ;;
|
|
682
|
+
--version) echo "v${VERSION}"; exit 0 ;;
|
|
683
|
+
--help|-h) usage ;;
|
|
684
|
+
*) error "Unknown option: $1"; usage ;;
|
|
685
|
+
esac
|
|
686
|
+
done
|
|
687
|
+
|
|
688
|
+
# Require --agent or --all
|
|
689
|
+
if [ -z "$agent" ] && [ "$all" != "true" ]; then
|
|
690
|
+
error "Missing required --agent flag (or use --all)"
|
|
691
|
+
echo ""
|
|
692
|
+
usage
|
|
693
|
+
fi
|
|
694
|
+
|
|
695
|
+
# Resolve project dir to absolute path
|
|
696
|
+
project_dir=$(cd "$project_dir" && pwd)
|
|
697
|
+
|
|
698
|
+
echo ""
|
|
699
|
+
echo -e "${BOLD}Conductor Skills Installer v${VERSION}${NC}"
|
|
700
|
+
echo ""
|
|
701
|
+
|
|
702
|
+
# Build agent list
|
|
703
|
+
local agents=()
|
|
704
|
+
if [ "$all" = "true" ]; then
|
|
705
|
+
local detected
|
|
706
|
+
detected=$(detect_agents)
|
|
707
|
+
if [ -z "$detected" ]; then
|
|
708
|
+
warn "No AI coding agents detected on this system."
|
|
709
|
+
echo ""
|
|
710
|
+
info "Supported agents: claude, codex, gemini, cursor, windsurf, cline,"
|
|
711
|
+
info " aider, copilot, amazonq, opencode, roo, amp"
|
|
712
|
+
echo ""
|
|
713
|
+
info "Install one of the above, then re-run this command."
|
|
714
|
+
exit 0
|
|
715
|
+
fi
|
|
716
|
+
# shellcheck disable=SC2206
|
|
717
|
+
agents=($detected)
|
|
718
|
+
info "Detected agents: ${agents[*]}"
|
|
719
|
+
echo ""
|
|
720
|
+
else
|
|
721
|
+
agent=$(echo "$agent" | tr '[:upper:]' '[:lower:]')
|
|
722
|
+
case "$agent" in
|
|
723
|
+
claude|codex|gemini|cursor|windsurf|cline|aider|copilot|amazonq|opencode|roo|amp) ;;
|
|
724
|
+
*) error "Unknown agent: $agent"; echo ""; usage ;;
|
|
725
|
+
esac
|
|
726
|
+
agents=("$agent")
|
|
727
|
+
fi
|
|
728
|
+
|
|
729
|
+
# Check mode — dry run
|
|
730
|
+
if [ "$check" = "true" ]; then
|
|
731
|
+
do_check "${agents[@]}"
|
|
732
|
+
exit 0
|
|
733
|
+
fi
|
|
734
|
+
|
|
735
|
+
# Determine manifest path
|
|
736
|
+
local manifest
|
|
737
|
+
if [ "$global" = "true" ] || [ "$all" = "true" ]; then
|
|
738
|
+
manifest=$(get_manifest_path "true" "")
|
|
739
|
+
else
|
|
740
|
+
manifest=$(get_manifest_path "false" "$project_dir")
|
|
741
|
+
fi
|
|
742
|
+
|
|
743
|
+
# Handle uninstall
|
|
744
|
+
if [ "$uninstall" = "true" ]; then
|
|
745
|
+
for a in "${agents[@]}"; do
|
|
746
|
+
local use_global="$global"
|
|
747
|
+
if [ "$all" = "true" ] && supports_global "$a"; then
|
|
748
|
+
use_global="true"
|
|
749
|
+
fi
|
|
750
|
+
info "Uninstalling ${BOLD}${a}${NC} ..."
|
|
751
|
+
uninstall_agent "$a" "$project_dir" "$use_global"
|
|
752
|
+
remove_manifest_entry "$manifest" "$a"
|
|
753
|
+
done
|
|
754
|
+
echo ""
|
|
755
|
+
ok "Done!"
|
|
756
|
+
return
|
|
757
|
+
fi
|
|
758
|
+
|
|
759
|
+
# Check for upgrade
|
|
760
|
+
local target_version="$VERSION"
|
|
761
|
+
if [ "$upgrade" = "true" ]; then
|
|
762
|
+
info "Checking for updates..."
|
|
763
|
+
local remote_ver
|
|
764
|
+
remote_ver=$(fetch_remote_version)
|
|
765
|
+
if [ -z "$remote_ver" ]; then
|
|
766
|
+
warn "Could not check for updates (offline?). Using bundled v${VERSION}."
|
|
767
|
+
elif [ "$remote_ver" != "$VERSION" ]; then
|
|
768
|
+
info "Update available: v${VERSION} → v${remote_ver}"
|
|
769
|
+
target_version="$remote_ver"
|
|
770
|
+
else
|
|
771
|
+
info "Already at latest version (v${VERSION})."
|
|
772
|
+
fi
|
|
773
|
+
echo ""
|
|
774
|
+
fi
|
|
775
|
+
|
|
776
|
+
# Download files to temp dir (not local — the EXIT trap must access it after main returns)
|
|
777
|
+
tmp_dir=$(mktemp -d)
|
|
778
|
+
trap 'rm -rf "$tmp_dir"' EXIT
|
|
779
|
+
|
|
780
|
+
download_files "$tmp_dir"
|
|
781
|
+
|
|
782
|
+
# Assemble into single file
|
|
783
|
+
local assembled="$tmp_dir/_assembled.md"
|
|
784
|
+
assemble_content "$tmp_dir" "$assembled"
|
|
785
|
+
ok "Assembled skill content ($(wc -c < "$assembled" | tr -d ' ') bytes)"
|
|
786
|
+
|
|
787
|
+
# Install for each agent
|
|
788
|
+
local installed_count=0
|
|
789
|
+
local skipped_count=0
|
|
790
|
+
|
|
791
|
+
for a in "${agents[@]}"; do
|
|
792
|
+
echo ""
|
|
793
|
+
|
|
794
|
+
# Determine if global for this agent
|
|
795
|
+
local use_global="$global"
|
|
796
|
+
if [ "$all" = "true" ]; then
|
|
797
|
+
if supports_global "$a"; then
|
|
798
|
+
use_global="true"
|
|
799
|
+
else
|
|
800
|
+
info "${BOLD}${a}${NC}: skipped (project-only install). Use --project-dir <path> to include."
|
|
801
|
+
skipped_count=$((skipped_count + 1))
|
|
802
|
+
continue
|
|
803
|
+
fi
|
|
804
|
+
fi
|
|
805
|
+
|
|
806
|
+
# Validate global support for single-agent mode
|
|
807
|
+
if [ "$use_global" = "true" ] && ! supports_global "$a"; then
|
|
808
|
+
error "Global install is not supported for $a. Run from your project directory instead."
|
|
809
|
+
continue
|
|
810
|
+
fi
|
|
811
|
+
|
|
812
|
+
# Idempotency check
|
|
813
|
+
local installed_ver
|
|
814
|
+
installed_ver=$(read_manifest_version "$manifest" "$a")
|
|
815
|
+
if [ -n "$installed_ver" ] && [ "$installed_ver" = "$target_version" ] && [ "$force" != "true" ] && [ "$upgrade" != "true" ]; then
|
|
816
|
+
ok "${a} already at v${installed_ver}, skipping."
|
|
817
|
+
skipped_count=$((skipped_count + 1))
|
|
818
|
+
continue
|
|
819
|
+
fi
|
|
820
|
+
|
|
821
|
+
if [ -n "$installed_ver" ] && [ "$installed_ver" != "$target_version" ]; then
|
|
822
|
+
info "Upgrading ${BOLD}${a}${NC} from v${installed_ver} to v${target_version} ..."
|
|
823
|
+
else
|
|
824
|
+
info "Installing for ${BOLD}${a}${NC} ..."
|
|
825
|
+
fi
|
|
826
|
+
|
|
827
|
+
# Perform install
|
|
828
|
+
if install_for_agent "$a" "$project_dir" "$use_global" "$force" "$tmp_dir" "$assembled"; then
|
|
829
|
+
# Determine target path for manifest
|
|
830
|
+
local target_path
|
|
831
|
+
if [ "$use_global" = "true" ]; then
|
|
832
|
+
target_path=$(get_global_path "$a")
|
|
833
|
+
else
|
|
834
|
+
target_path=$(get_target_path "$a" "$project_dir")
|
|
835
|
+
fi
|
|
836
|
+
local mode
|
|
837
|
+
if [ "$use_global" = "true" ]; then mode="global"; else mode="project"; fi
|
|
838
|
+
write_manifest_entry "$manifest" "$a" "$target_version" "$mode" "$target_path"
|
|
839
|
+
installed_count=$((installed_count + 1))
|
|
840
|
+
fi
|
|
841
|
+
done
|
|
842
|
+
|
|
843
|
+
echo ""
|
|
844
|
+
echo -e "${GREEN}${BOLD}Done!${NC} Installed: ${installed_count}, Skipped: ${skipped_count}"
|
|
845
|
+
echo ""
|
|
846
|
+
echo "Next steps:"
|
|
847
|
+
echo " Ask your agent to connect to your Conductor server, e.g.:"
|
|
848
|
+
echo ""
|
|
849
|
+
echo ' "Connect to my Conductor server at http://localhost:8080/api"'
|
|
850
|
+
echo ""
|
|
851
|
+
echo -e " Docs: ${BLUE}https://github.com/conductor-oss/conductor-skills${NC}"
|
|
852
|
+
echo ""
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
main "$@"
|