orchestrix-yuri 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/LICENSE +21 -0
- package/README.md +122 -0
- package/bin/install.js +25 -0
- package/lib/installer.js +86 -0
- package/package.json +31 -0
- package/skill/SKILL.md +136 -0
- package/skill/data/deployment-options.yaml +44 -0
- package/skill/data/phase-routing.yaml +50 -0
- package/skill/resources/.gitignore.template +29 -0
- package/skill/resources/core-config.template.yaml +67 -0
- package/skill/resources/handoff-detector.sh +374 -0
- package/skill/resources/mcp.json.template +18 -0
- package/skill/resources/o-help.md +23 -0
- package/skill/resources/o-status.md +37 -0
- package/skill/resources/o.md +87 -0
- package/skill/resources/settings.local.json +15 -0
- package/skill/resources/start-orchestrix.sh +373 -0
- package/skill/scripts/ensure-session.sh +61 -0
- package/skill/scripts/monitor-agent.sh +61 -0
- package/skill/scripts/scan-stories.sh +16 -0
- package/skill/scripts/start-planning.sh +20 -0
- package/skill/tasks/yuri-create-project.md +258 -0
- package/skill/tasks/yuri-deploy-project.md +139 -0
- package/skill/tasks/yuri-develop-project.md +150 -0
- package/skill/tasks/yuri-handle-change.md +239 -0
- package/skill/tasks/yuri-plan-project.md +158 -0
- package/skill/tasks/yuri-resume.md +132 -0
- package/skill/tasks/yuri-status.md +156 -0
- package/skill/tasks/yuri-test-project.md +172 -0
- package/skill/templates/memory.template.yaml +77 -0
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Orchestrix HANDOFF Detector - tmux Automation Hook (MCP Version)
|
|
3
|
+
# Triggers on Claude Code Stop event, detects HANDOFF and routes to target agent
|
|
4
|
+
#
|
|
5
|
+
# Design principles:
|
|
6
|
+
# - NO dependency on environment variables (robust)
|
|
7
|
+
# - Scans ALL tmux windows to find HANDOFF message
|
|
8
|
+
# - Uses hash-based deduplication to prevent re-processing
|
|
9
|
+
# - Background process handles cleanup and lock release
|
|
10
|
+
#
|
|
11
|
+
# Pro/Team Feature: This script is only available for Pro and Team subscribers.
|
|
12
|
+
|
|
13
|
+
set +e # Don't exit on errors
|
|
14
|
+
|
|
15
|
+
# ============================================
|
|
16
|
+
# Configuration
|
|
17
|
+
# ============================================
|
|
18
|
+
# Try to get session from env, otherwise detect from tmux context
|
|
19
|
+
SESSION_NAME="${ORCHESTRIX_SESSION:-}"
|
|
20
|
+
|
|
21
|
+
# Agent mappings
|
|
22
|
+
get_agent_name() {
|
|
23
|
+
case "$1" in
|
|
24
|
+
0) echo "architect" ;;
|
|
25
|
+
1) echo "sm" ;;
|
|
26
|
+
2) echo "dev" ;;
|
|
27
|
+
3) echo "qa" ;;
|
|
28
|
+
*) echo "" ;;
|
|
29
|
+
esac
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get_window_num() {
|
|
33
|
+
case "$1" in
|
|
34
|
+
architect) echo "0" ;;
|
|
35
|
+
sm) echo "1" ;;
|
|
36
|
+
dev) echo "2" ;;
|
|
37
|
+
qa) echo "3" ;;
|
|
38
|
+
*) echo "" ;;
|
|
39
|
+
esac
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
# MCP version: use /o {agent} format
|
|
43
|
+
get_agent_command() {
|
|
44
|
+
case "$1" in
|
|
45
|
+
architect) echo "/o architect" ;;
|
|
46
|
+
sm) echo "/o sm" ;;
|
|
47
|
+
dev) echo "/o dev" ;;
|
|
48
|
+
qa) echo "/o qa" ;;
|
|
49
|
+
*) echo "" ;;
|
|
50
|
+
esac
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# Infer target agent from command (for simplified format like "*develop-story 10.4")
|
|
54
|
+
get_target_from_command() {
|
|
55
|
+
local cmd="$1"
|
|
56
|
+
case "$cmd" in
|
|
57
|
+
develop-story|apply-qa-fixes|quick-develop)
|
|
58
|
+
echo "dev" ;;
|
|
59
|
+
review|quick-verify|test-design|finalize-commit)
|
|
60
|
+
echo "qa" ;;
|
|
61
|
+
draft|revise-story|revise|apply-proposal|create-next-story)
|
|
62
|
+
echo "sm" ;;
|
|
63
|
+
review-escalation|resolve-change)
|
|
64
|
+
echo "architect" ;;
|
|
65
|
+
*)
|
|
66
|
+
echo "" ;;
|
|
67
|
+
esac
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# ============================================
|
|
71
|
+
# Find Orchestrix Session (before any logging)
|
|
72
|
+
# ============================================
|
|
73
|
+
|
|
74
|
+
# Priority 1: Explicit env var
|
|
75
|
+
# Priority 2: Detect current tmux session (if inside tmux and it's an orchestrix session)
|
|
76
|
+
# Priority 3: Scan all tmux sessions for orchestrix prefix
|
|
77
|
+
if [[ -z "$SESSION_NAME" && -n "$TMUX" ]]; then
|
|
78
|
+
CURRENT_SESSION=$(tmux display-message -p '#{session_name}' 2>/dev/null)
|
|
79
|
+
if [[ "$CURRENT_SESSION" == orchestrix* ]]; then
|
|
80
|
+
SESSION_NAME="$CURRENT_SESSION"
|
|
81
|
+
fi
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
if [[ -z "$SESSION_NAME" ]]; then
|
|
85
|
+
SESSION_NAME=$(tmux list-sessions -F '#{session_name}' 2>/dev/null | grep -E '^orchestrix' | head -1)
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
if [[ -z "$SESSION_NAME" ]]; then
|
|
89
|
+
exit 0
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
if ! tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
|
|
93
|
+
exit 0
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# Session-specific log file (all logging starts AFTER session detection)
|
|
97
|
+
LOG_FILE="/tmp/${SESSION_NAME}-handoff.log"
|
|
98
|
+
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"; }
|
|
99
|
+
|
|
100
|
+
log "========== Hook triggered =========="
|
|
101
|
+
log "Session: $SESSION_NAME"
|
|
102
|
+
|
|
103
|
+
# ============================================
|
|
104
|
+
# Scan All Windows for HANDOFF
|
|
105
|
+
# ============================================
|
|
106
|
+
PROCESSED_FILE="/tmp/${SESSION_NAME}-processed.txt"
|
|
107
|
+
touch "$PROCESSED_FILE"
|
|
108
|
+
|
|
109
|
+
SOURCE_WIN=""
|
|
110
|
+
TARGET=""
|
|
111
|
+
CMD=""
|
|
112
|
+
HANDOFF_HASH=""
|
|
113
|
+
|
|
114
|
+
for win in 0 1 2 3; do
|
|
115
|
+
OUTPUT=$(tmux capture-pane -t "$SESSION_NAME:$win" -p -S - 2>/dev/null)
|
|
116
|
+
[[ -z "$OUTPUT" ]] && continue
|
|
117
|
+
|
|
118
|
+
# Pattern 1: Standard HANDOFF format (🎯 HANDOFF TO agent: *command args)
|
|
119
|
+
LINE=$(echo "$OUTPUT" | grep -E '🎯.*HANDOFF.*TO' | tail -1)
|
|
120
|
+
if [[ -n "$LINE" ]]; then
|
|
121
|
+
# Calculate hash to avoid re-processing
|
|
122
|
+
HASH=$(echo "$LINE" | md5 2>/dev/null || echo "$LINE" | md5sum 2>/dev/null | cut -d' ' -f1)
|
|
123
|
+
|
|
124
|
+
# Skip if already processed
|
|
125
|
+
if grep -q "$HASH" "$PROCESSED_FILE" 2>/dev/null; then
|
|
126
|
+
continue
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
# Parse HANDOFF message
|
|
130
|
+
if [[ "$LINE" =~ HANDOFF[[:space:]]+TO[[:space:]]+([a-zA-Z0-9_-]+):[[:space:]]*\*?([a-z0-9-]+)([[:space:]]+([0-9]+\.[0-9]+))? ]]; then
|
|
131
|
+
SOURCE_WIN=$win
|
|
132
|
+
TARGET=$(echo "${BASH_REMATCH[1]}" | tr '[:upper:]' '[:lower:]')
|
|
133
|
+
CMD="*${BASH_REMATCH[2]}${BASH_REMATCH[4]:+ ${BASH_REMATCH[4]}}"
|
|
134
|
+
HANDOFF_HASH=$HASH
|
|
135
|
+
log "Found HANDOFF in window $win: $LINE"
|
|
136
|
+
break
|
|
137
|
+
fi
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
# Pattern 2: Simplified format - more flexible detection
|
|
141
|
+
# Handles: "*develop-story 10.4", "*draft", "* review 10.4", etc.
|
|
142
|
+
if [[ -z "$TARGET" ]]; then
|
|
143
|
+
# Search last 30 lines for command patterns (more tolerant)
|
|
144
|
+
LAST_LINES=$(echo "$OUTPUT" | tail -30)
|
|
145
|
+
|
|
146
|
+
# Try multiple patterns in order of specificity
|
|
147
|
+
# Pattern 2a: *command story_id (e.g., "*develop-story 10.4")
|
|
148
|
+
SIMPLE_LINE=$(echo "$LAST_LINES" | grep -E '\*[a-z]+-?[a-z-]*\s+[0-9]+\.[0-9]+' | tail -1)
|
|
149
|
+
|
|
150
|
+
if [[ -z "$SIMPLE_LINE" ]]; then
|
|
151
|
+
# Pattern 2b: *command without story_id (e.g., "*draft")
|
|
152
|
+
SIMPLE_LINE=$(echo "$LAST_LINES" | grep -E '^\s*\*[a-z]+-?[a-z-]*\s*$' | tail -1)
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
if [[ -n "$SIMPLE_LINE" ]]; then
|
|
156
|
+
# Extract command and optional story_id
|
|
157
|
+
# Handle: "*develop-story 10.4", "* review 10.4", "*draft"
|
|
158
|
+
if [[ "$SIMPLE_LINE" =~ \*[[:space:]]*([a-z][a-z-]*)[[:space:]]*([0-9]+\.[0-9]+)? ]]; then
|
|
159
|
+
simple_cmd="${BASH_REMATCH[1]}"
|
|
160
|
+
story_id="${BASH_REMATCH[2]}"
|
|
161
|
+
inferred_target=$(get_target_from_command "$simple_cmd")
|
|
162
|
+
|
|
163
|
+
if [[ -n "$inferred_target" ]]; then
|
|
164
|
+
# Calculate hash
|
|
165
|
+
HASH=$(echo "$SIMPLE_LINE" | md5 2>/dev/null || echo "$SIMPLE_LINE" | md5sum 2>/dev/null | cut -d' ' -f1)
|
|
166
|
+
|
|
167
|
+
# Skip if already processed
|
|
168
|
+
if grep -q "$HASH" "$PROCESSED_FILE" 2>/dev/null; then
|
|
169
|
+
continue
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
SOURCE_WIN=$win
|
|
173
|
+
TARGET=$inferred_target
|
|
174
|
+
if [[ -n "$story_id" ]]; then
|
|
175
|
+
CMD="*${simple_cmd} ${story_id}"
|
|
176
|
+
else
|
|
177
|
+
CMD="*${simple_cmd}"
|
|
178
|
+
fi
|
|
179
|
+
HANDOFF_HASH=$HASH
|
|
180
|
+
log "[SIMPLE] Found in window $win: '$SIMPLE_LINE' -> $TARGET: $CMD"
|
|
181
|
+
break
|
|
182
|
+
fi
|
|
183
|
+
fi
|
|
184
|
+
fi
|
|
185
|
+
fi
|
|
186
|
+
done
|
|
187
|
+
|
|
188
|
+
# No HANDOFF found - try fallback from pending-handoff file
|
|
189
|
+
if [[ -z "$TARGET" || -z "$CMD" ]]; then
|
|
190
|
+
log "No HANDOFF in terminal output, checking fallback file..."
|
|
191
|
+
|
|
192
|
+
# ============================================
|
|
193
|
+
# Fallback: Check pending-handoff.json
|
|
194
|
+
# ============================================
|
|
195
|
+
# Find project root (look for .orchestrix-core directory)
|
|
196
|
+
FALLBACK_FILE=""
|
|
197
|
+
for win in 0 1 2 3; do
|
|
198
|
+
# Get the pane's current directory
|
|
199
|
+
PANE_DIR=$(tmux display-message -t "$SESSION_NAME:$win" -p '#{pane_current_path}' 2>/dev/null)
|
|
200
|
+
if [[ -n "$PANE_DIR" && -f "$PANE_DIR/.orchestrix-core/runtime/pending-handoff.json" ]]; then
|
|
201
|
+
FALLBACK_FILE="$PANE_DIR/.orchestrix-core/runtime/pending-handoff.json"
|
|
202
|
+
SOURCE_WIN=$win
|
|
203
|
+
break
|
|
204
|
+
fi
|
|
205
|
+
done
|
|
206
|
+
|
|
207
|
+
if [[ -z "$FALLBACK_FILE" ]]; then
|
|
208
|
+
log "No pending-handoff.json found"
|
|
209
|
+
exit 0
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
log "Found fallback file: $FALLBACK_FILE"
|
|
213
|
+
|
|
214
|
+
# Read and parse the JSON file
|
|
215
|
+
if command -v jq &>/dev/null; then
|
|
216
|
+
# Use jq if available
|
|
217
|
+
STATUS=$(jq -r '.status // "unknown"' "$FALLBACK_FILE" 2>/dev/null)
|
|
218
|
+
if [[ "$STATUS" != "pending" ]]; then
|
|
219
|
+
log "Fallback file status is '$STATUS', not 'pending'. Skipping."
|
|
220
|
+
exit 0
|
|
221
|
+
fi
|
|
222
|
+
|
|
223
|
+
TARGET=$(jq -r '.target_agent // ""' "$FALLBACK_FILE" 2>/dev/null)
|
|
224
|
+
CMD=$(jq -r '.command // ""' "$FALLBACK_FILE" 2>/dev/null)
|
|
225
|
+
STORY_ID=$(jq -r '.story_id // ""' "$FALLBACK_FILE" 2>/dev/null)
|
|
226
|
+
SOURCE_AGENT=$(jq -r '.source_agent // ""' "$FALLBACK_FILE" 2>/dev/null)
|
|
227
|
+
else
|
|
228
|
+
# Fallback to grep/sed parsing
|
|
229
|
+
STATUS=$(grep -o '"status"[[:space:]]*:[[:space:]]*"[^"]*"' "$FALLBACK_FILE" | sed 's/.*"\([^"]*\)"$/\1/')
|
|
230
|
+
if [[ "$STATUS" != "pending" ]]; then
|
|
231
|
+
log "Fallback file status is '$STATUS', not 'pending'. Skipping."
|
|
232
|
+
exit 0
|
|
233
|
+
fi
|
|
234
|
+
|
|
235
|
+
TARGET=$(grep -o '"target_agent"[[:space:]]*:[[:space:]]*"[^"]*"' "$FALLBACK_FILE" | sed 's/.*"\([^"]*\)"$/\1/')
|
|
236
|
+
CMD=$(grep -o '"command"[[:space:]]*:[[:space:]]*"[^"]*"' "$FALLBACK_FILE" | sed 's/.*"\([^"]*\)"$/\1/')
|
|
237
|
+
STORY_ID=$(grep -o '"story_id"[[:space:]]*:[[:space:]]*"[^"]*"' "$FALLBACK_FILE" | sed 's/.*"\([^"]*\)"$/\1/')
|
|
238
|
+
SOURCE_AGENT=$(grep -o '"source_agent"[[:space:]]*:[[:space:]]*"[^"]*"' "$FALLBACK_FILE" | sed 's/.*"\([^"]*\)"$/\1/')
|
|
239
|
+
fi
|
|
240
|
+
|
|
241
|
+
if [[ -z "$TARGET" || -z "$CMD" ]]; then
|
|
242
|
+
log "Invalid fallback file content"
|
|
243
|
+
exit 0
|
|
244
|
+
fi
|
|
245
|
+
|
|
246
|
+
# Create a hash to prevent re-processing
|
|
247
|
+
# Include STORY_ID to differentiate handoffs for different stories with same command
|
|
248
|
+
HANDOFF_HASH=$(echo "fallback-$SOURCE_AGENT-$TARGET-$CMD-$STORY_ID" | md5 2>/dev/null || echo "fallback-$SOURCE_AGENT-$TARGET-$CMD-$STORY_ID" | md5sum 2>/dev/null | cut -d' ' -f1)
|
|
249
|
+
|
|
250
|
+
# Skip if already processed
|
|
251
|
+
if grep -q "$HANDOFF_HASH" "$PROCESSED_FILE" 2>/dev/null; then
|
|
252
|
+
log "Fallback handoff already processed"
|
|
253
|
+
exit 0
|
|
254
|
+
fi
|
|
255
|
+
|
|
256
|
+
# Get SOURCE_WIN from SOURCE_AGENT (override the window where file was found)
|
|
257
|
+
SOURCE_WIN=$(get_window_num "$SOURCE_AGENT")
|
|
258
|
+
|
|
259
|
+
log "[FALLBACK] Recovered handoff from file: $SOURCE_AGENT (win $SOURCE_WIN) -> $TARGET: $CMD"
|
|
260
|
+
|
|
261
|
+
# Mark the fallback file as completed
|
|
262
|
+
if command -v jq &>/dev/null; then
|
|
263
|
+
jq --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" '.status = "completed_by_fallback" | .completed_at = $ts' "$FALLBACK_FILE" > "$FALLBACK_FILE.tmp.$$" 2>/dev/null && mv "$FALLBACK_FILE.tmp.$$" "$FALLBACK_FILE"
|
|
264
|
+
else
|
|
265
|
+
sed -i.bak 's/"status"[[:space:]]*:[[:space:]]*"pending"/"status": "completed_by_fallback"/' "$FALLBACK_FILE" 2>/dev/null
|
|
266
|
+
rm -f "$FALLBACK_FILE.bak" 2>/dev/null
|
|
267
|
+
fi
|
|
268
|
+
fi
|
|
269
|
+
|
|
270
|
+
# Mark as processed
|
|
271
|
+
echo "$HANDOFF_HASH" >> "$PROCESSED_FILE"
|
|
272
|
+
|
|
273
|
+
# Keep processed file small (last 100 entries)
|
|
274
|
+
# Use PID in tmp filename to avoid race with concurrent hook instances or background processes
|
|
275
|
+
tail -100 "$PROCESSED_FILE" > "$PROCESSED_FILE.tmp.$$" 2>/dev/null && mv "$PROCESSED_FILE.tmp.$$" "$PROCESSED_FILE"
|
|
276
|
+
|
|
277
|
+
# Get source agent name (only if not already set by fallback)
|
|
278
|
+
if [[ -z "$SOURCE_AGENT" ]]; then
|
|
279
|
+
SOURCE_AGENT=$(get_agent_name "$SOURCE_WIN")
|
|
280
|
+
fi
|
|
281
|
+
TARGET_WIN=$(get_window_num "$TARGET")
|
|
282
|
+
|
|
283
|
+
# Validate
|
|
284
|
+
if [[ -z "$TARGET_WIN" ]]; then
|
|
285
|
+
log "ERROR: Unknown target agent '$TARGET'"
|
|
286
|
+
exit 0
|
|
287
|
+
fi
|
|
288
|
+
|
|
289
|
+
if [[ "$TARGET_WIN" == "$SOURCE_WIN" ]]; then
|
|
290
|
+
log "ERROR: Source and target are same window"
|
|
291
|
+
exit 0
|
|
292
|
+
fi
|
|
293
|
+
|
|
294
|
+
log "HANDOFF: $SOURCE_AGENT (win $SOURCE_WIN) -> $TARGET (win $TARGET_WIN)"
|
|
295
|
+
log "Command: $CMD"
|
|
296
|
+
|
|
297
|
+
# ============================================
|
|
298
|
+
# Atomic Lock
|
|
299
|
+
# ============================================
|
|
300
|
+
LOCK="/tmp/${SESSION_NAME}-${SOURCE_WIN}.lock"
|
|
301
|
+
LOCK_TIMEOUT=60
|
|
302
|
+
|
|
303
|
+
if ! mkdir "$LOCK" 2>/dev/null; then
|
|
304
|
+
if [[ -f "$LOCK/ts" ]]; then
|
|
305
|
+
ts=$(cat "$LOCK/ts" 2>/dev/null || echo 0)
|
|
306
|
+
now=$(date +%s)
|
|
307
|
+
age=$((now - ts))
|
|
308
|
+
if [[ $age -lt $LOCK_TIMEOUT ]]; then
|
|
309
|
+
log "SKIP: Window $SOURCE_WIN locked (${age}s ago)"
|
|
310
|
+
exit 0
|
|
311
|
+
fi
|
|
312
|
+
log "Stale lock (${age}s), cleaning"
|
|
313
|
+
fi
|
|
314
|
+
rm -rf "$LOCK" 2>/dev/null
|
|
315
|
+
mkdir "$LOCK" 2>/dev/null || { log "SKIP: lock race"; exit 0; }
|
|
316
|
+
fi
|
|
317
|
+
date +%s > "$LOCK/ts"
|
|
318
|
+
|
|
319
|
+
# ============================================
|
|
320
|
+
# Send to Target
|
|
321
|
+
# ============================================
|
|
322
|
+
log "Sending '$CMD' to $TARGET (window $TARGET_WIN)..."
|
|
323
|
+
|
|
324
|
+
if tmux send-keys -t "$SESSION_NAME:$TARGET_WIN" "$CMD" 2>/dev/null; then
|
|
325
|
+
sleep 0.5
|
|
326
|
+
tmux send-keys -t "$SESSION_NAME:$TARGET_WIN" Enter
|
|
327
|
+
log "SUCCESS: Command sent to $TARGET"
|
|
328
|
+
else
|
|
329
|
+
log "ERROR: Failed to send command"
|
|
330
|
+
rm -rf "$LOCK"
|
|
331
|
+
exit 0
|
|
332
|
+
fi
|
|
333
|
+
|
|
334
|
+
# ============================================
|
|
335
|
+
# Background: Clear & Reload Source Agent
|
|
336
|
+
# ============================================
|
|
337
|
+
RELOAD_CMD=$(get_agent_command "$SOURCE_AGENT")
|
|
338
|
+
|
|
339
|
+
(
|
|
340
|
+
log "[BG] Starting cleanup for $SOURCE_AGENT (window $SOURCE_WIN)"
|
|
341
|
+
sleep 2
|
|
342
|
+
|
|
343
|
+
# Clear
|
|
344
|
+
tmux send-keys -t "$SESSION_NAME:$SOURCE_WIN" "/clear" 2>/dev/null
|
|
345
|
+
sleep 0.5
|
|
346
|
+
tmux send-keys -t "$SESSION_NAME:$SOURCE_WIN" Enter
|
|
347
|
+
log "[BG] /clear sent to $SOURCE_AGENT"
|
|
348
|
+
|
|
349
|
+
sleep 5
|
|
350
|
+
|
|
351
|
+
# Reload
|
|
352
|
+
if [[ -n "$RELOAD_CMD" ]]; then
|
|
353
|
+
tmux send-keys -t "$SESSION_NAME:$SOURCE_WIN" "$RELOAD_CMD" 2>/dev/null
|
|
354
|
+
sleep 0.5
|
|
355
|
+
tmux send-keys -t "$SESSION_NAME:$SOURCE_WIN" Enter
|
|
356
|
+
log "[BG] Reload sent: $RELOAD_CMD"
|
|
357
|
+
sleep 15
|
|
358
|
+
fi
|
|
359
|
+
|
|
360
|
+
# Remove hash from processed file to allow future same-message HANDOFF
|
|
361
|
+
# This fixes the issue where repeated identical messages (e.g., "*draft") are skipped
|
|
362
|
+
if [[ -n "$HANDOFF_HASH" && -f "$PROCESSED_FILE" ]]; then
|
|
363
|
+
grep -v "^${HANDOFF_HASH}$" "$PROCESSED_FILE" > "$PROCESSED_FILE.tmp.$$" 2>/dev/null && mv -f "$PROCESSED_FILE.tmp.$$" "$PROCESSED_FILE"
|
|
364
|
+
log "[BG] Hash removed from processed file: $HANDOFF_HASH"
|
|
365
|
+
fi
|
|
366
|
+
|
|
367
|
+
# Release lock
|
|
368
|
+
rm -rf "$LOCK"
|
|
369
|
+
log "[BG] Cleanup complete, lock released"
|
|
370
|
+
) >> "$LOG_FILE" 2>&1 &
|
|
371
|
+
|
|
372
|
+
log "Background process started (PID $!)"
|
|
373
|
+
log "========== Hook complete =========="
|
|
374
|
+
exit 0
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"orchestrix": {
|
|
4
|
+
"type": "http",
|
|
5
|
+
"url": "https://orchestrix-mcp.youlidao.ai/api/mcp",
|
|
6
|
+
"headers": {
|
|
7
|
+
"Authorization": "Bearer {{ORCHESTRIX_LICENSE_KEY}}"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
"sequential-thinking": {
|
|
11
|
+
"command": "npx",
|
|
12
|
+
"args": [
|
|
13
|
+
"-y",
|
|
14
|
+
"@modelcontextprotocol/server-sequential-thinking"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Show Orchestrix help and available agents
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Orchestrix Help
|
|
6
|
+
|
|
7
|
+
Please call the Orchestrix MCP Server's `list-agents` tool to display all available agents.
|
|
8
|
+
|
|
9
|
+
Then display the following usage guide:
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
/o [agent_id] Activate an agent (e.g., /o dev, /o sm)
|
|
15
|
+
/o-help Show this help message
|
|
16
|
+
/o-status Show current Orchestrix status
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
1. Use `/o dev` to activate the Developer agent for coding tasks
|
|
22
|
+
2. Use `/o sm` to activate the Scrum Master for story management
|
|
23
|
+
3. Use `/o qa` to activate QA Engineer for testing
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Show Orchestrix server status
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Orchestrix Status
|
|
6
|
+
|
|
7
|
+
Please check and display the current Orchestrix status:
|
|
8
|
+
|
|
9
|
+
## Status Check Items
|
|
10
|
+
|
|
11
|
+
1. **MCP Server Connection**: Check if Orchestrix MCP Server is connected
|
|
12
|
+
2. **Available Agents**: Call `list-agents` tool to verify agents are loaded
|
|
13
|
+
3. **License Status**: Display current license tier (if applicable)
|
|
14
|
+
|
|
15
|
+
## Expected Output
|
|
16
|
+
|
|
17
|
+
Display the status in this format:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
Orchestrix Status
|
|
21
|
+
=================
|
|
22
|
+
Server: Connected / Disconnected
|
|
23
|
+
Agents: [count] agents available
|
|
24
|
+
License: [tier] mode
|
|
25
|
+
|
|
26
|
+
Available Commands:
|
|
27
|
+
/o [agent] - Activate agent
|
|
28
|
+
/o-help - Show help
|
|
29
|
+
/o-status - This status
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Troubleshooting
|
|
33
|
+
|
|
34
|
+
If the server is not connected:
|
|
35
|
+
1. Check `.mcp.json` configuration
|
|
36
|
+
2. Verify the MCP server process is running
|
|
37
|
+
3. Check server logs for errors
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Activate Orchestrix Agent (e.g., /o dev, /o sm --lang=zh)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Orchestrix Agent Activation
|
|
6
|
+
|
|
7
|
+
## Available Agents
|
|
8
|
+
|
|
9
|
+
| ID | Agent | Description |
|
|
10
|
+
|----|-------|-------------|
|
|
11
|
+
| `dev` | Full Stack Developer | implementation, debugging, refactoring |
|
|
12
|
+
| `sm` | Scrum Master | story creation, epic management, agile guidance |
|
|
13
|
+
| `qa` | QA Engineer | E2E testing, quality verification |
|
|
14
|
+
| `architect` | Solution Architect | system design, tech selection, API design |
|
|
15
|
+
| `pm` | Product Manager | PRDs, product strategy, roadmap planning |
|
|
16
|
+
| `po` | Product Owner | backlog management, story refinement |
|
|
17
|
+
| `analyst` | Business Analyst | market research, competitive analysis |
|
|
18
|
+
| `ux-expert` | UX Expert | UI/UX design, wireframes, prototypes |
|
|
19
|
+
| `orchestrix-orchestrator` | Workflow Coordinator | multi-agent tasks |
|
|
20
|
+
| `orchestrix-master` | Master Agent | one-off tasks across domains |
|
|
21
|
+
| `decision-evaluator` | Decision Evaluator | execute decision rules |
|
|
22
|
+
|
|
23
|
+
## Language Support
|
|
24
|
+
|
|
25
|
+
Use `--lang=xx` to load agent content in a specific language:
|
|
26
|
+
- `--lang=en` - English (default)
|
|
27
|
+
- `--lang=zh` - Chinese / 中文
|
|
28
|
+
|
|
29
|
+
Examples:
|
|
30
|
+
- `/o dev` - Load Developer agent in English (default)
|
|
31
|
+
- `/o dev --lang=zh` - Load Developer agent in Chinese
|
|
32
|
+
- `/o sm --lang=zh` - Load Scrum Master agent in Chinese
|
|
33
|
+
|
|
34
|
+
## Action Required
|
|
35
|
+
|
|
36
|
+
**FIRST**: Parse `$ARGUMENTS` to extract agent ID and language option.
|
|
37
|
+
|
|
38
|
+
Arguments format: `[agent_id] [--lang=xx]`
|
|
39
|
+
|
|
40
|
+
Parsing rules:
|
|
41
|
+
1. If `$ARGUMENTS` is empty or blank → Show agent table, ask user to select
|
|
42
|
+
2. If `$ARGUMENTS` contains `--lang=xx` → Extract language code (en or zh)
|
|
43
|
+
3. Extract agent ID (everything before `--lang` or the entire argument if no `--lang`)
|
|
44
|
+
|
|
45
|
+
If `$ARGUMENTS` is empty or blank:
|
|
46
|
+
- Show the table above directly
|
|
47
|
+
- Ask user to select an agent
|
|
48
|
+
- **DO NOT** call ReadMcpResourceTool with empty arguments
|
|
49
|
+
|
|
50
|
+
If agent ID is provided, proceed to load the agent:
|
|
51
|
+
|
|
52
|
+
## Step 1: Read Agent Configuration
|
|
53
|
+
|
|
54
|
+
**CRITICAL**: You MUST use `ReadMcpResourceTool` (NOT prompts!) with the EXACT parameters below.
|
|
55
|
+
|
|
56
|
+
`ReadMcpResourceTool` only accepts `server` and `uri` parameters. Language MUST be encoded in the URI as a query parameter.
|
|
57
|
+
|
|
58
|
+
**Without language** (default English):
|
|
59
|
+
- server: `orchestrix`
|
|
60
|
+
- uri: `orchestrix://agents/{agent_id}.yaml`
|
|
61
|
+
|
|
62
|
+
**With language** (e.g., `--lang=zh`):
|
|
63
|
+
- server: `orchestrix`
|
|
64
|
+
- uri: `orchestrix://agents/{agent_id}.yaml?lang=zh`
|
|
65
|
+
|
|
66
|
+
### Examples
|
|
67
|
+
|
|
68
|
+
For `/o pm`:
|
|
69
|
+
```
|
|
70
|
+
ReadMcpResourceTool(server="orchestrix", uri="orchestrix://agents/pm.yaml")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
For `/o pm --lang=zh`:
|
|
74
|
+
```
|
|
75
|
+
ReadMcpResourceTool(server="orchestrix", uri="orchestrix://agents/pm.yaml?lang=zh")
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**DO NOT** use `orchestrix://prompts/` - agents are exposed as **resources**, not prompts!
|
|
79
|
+
**DO NOT** pass `lang` as a separate parameter - it MUST be in the URI query string.
|
|
80
|
+
|
|
81
|
+
## Step 2: After Loading Agent
|
|
82
|
+
|
|
83
|
+
1. Adopt the persona defined in the `agent` section completely
|
|
84
|
+
2. Follow `activation_instructions` exactly
|
|
85
|
+
3. Display greeting with agent name/role
|
|
86
|
+
4. Show the numbered command list from `commands.help.output_format`
|
|
87
|
+
5. Wait for user selection
|