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.
@@ -0,0 +1,373 @@
1
+ #!/bin/bash
2
+ # Orchestrix tmux Multi-Agent Session Starter (MCP Version)
3
+ # Purpose: Create 4 separate windows, each running a Claude Code agent
4
+ # Supports multi-repo: Each repo gets its own tmux session based on repository_id
5
+ #
6
+ # Pro/Team Feature: This script is only available for Pro and Team subscribers.
7
+
8
+ set -e
9
+
10
+ # Dynamically get project root directory (where .orchestrix-core is located)
11
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
+ WORK_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
13
+
14
+ echo "Working directory: $WORK_DIR"
15
+
16
+ # ============================================
17
+ # Dynamic Session Naming (Multi-Repo Support)
18
+ # ============================================
19
+
20
+ # Try to read repository_id from core-config.yaml
21
+ CONFIG_FILE="$WORK_DIR/.orchestrix-core/core-config.yaml"
22
+ REPO_ID=""
23
+
24
+ if [ -f "$CONFIG_FILE" ]; then
25
+ # Extract repository_id using grep and sed (POSIX compatible)
26
+ REPO_ID=$(grep -E "^\s*repository_id:" "$CONFIG_FILE" 2>/dev/null | head -1 | sed "s/.*repository_id:[[:space:]]*['\"]*//" | sed "s/['\"].*//")
27
+
28
+ # Clean up: remove quotes and whitespace
29
+ REPO_ID=$(echo "$REPO_ID" | tr -d "'" | tr -d '"' | tr -d ' ')
30
+ fi
31
+
32
+ # Fallback: use directory name if repository_id is empty
33
+ if [ -z "$REPO_ID" ]; then
34
+ REPO_ID=$(basename "$WORK_DIR")
35
+ echo "Warning: No repository_id in config, using directory name: $REPO_ID"
36
+ fi
37
+
38
+ # Sanitize REPO_ID for tmux session name (alphanumeric, dash, underscore only)
39
+ REPO_ID=$(echo "$REPO_ID" | tr -cd 'a-zA-Z0-9_-')
40
+
41
+ # Sanitized REPO_ID must not be empty
42
+ if [ -z "$REPO_ID" ]; then
43
+ REPO_ID="default"
44
+ echo "⚠️ REPO_ID is empty after sanitization, using fallback: $REPO_ID"
45
+ fi
46
+
47
+ # Generate dynamic session name and log file
48
+ SESSION_NAME="orchestrix-${REPO_ID}"
49
+ # IMPORTANT: Must match handoff-detector.sh pattern: /tmp/${SESSION_NAME}-handoff.log
50
+ LOG_FILE="/tmp/${SESSION_NAME}-handoff.log"
51
+
52
+ echo "🏷️ Repository ID: $REPO_ID"
53
+ echo "📺 tmux Session: $SESSION_NAME"
54
+ echo "📝 Log file: $LOG_FILE"
55
+
56
+ # Check if tmux is installed
57
+ if ! command -v tmux &> /dev/null; then
58
+ echo "❌ Error: tmux is not installed"
59
+ echo "Please run: brew install tmux"
60
+ exit 1
61
+ fi
62
+
63
+ # Check if cc command is available
64
+ if ! command -v cc &> /dev/null; then
65
+ echo "❌ Error: cc command not available"
66
+ echo "Please ensure Claude Code alias is configured: alias cc='claude'"
67
+ exit 1
68
+ fi
69
+
70
+ # If session already exists, kill it first
71
+ if tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
72
+ echo "⚠️ Session '$SESSION_NAME' already exists, closing..."
73
+ tmux kill-session -t "$SESSION_NAME"
74
+ fi
75
+
76
+ # Create new session with first window (Architect)
77
+ echo "🚀 Creating tmux session: $SESSION_NAME"
78
+ tmux new-session -d -s "$SESSION_NAME" -n "Arch" -c "$WORK_DIR"
79
+
80
+ # ============================================
81
+ # Inject handoff-detector hook into target project
82
+ # ============================================
83
+ # CRITICAL: The tmux agents run Claude Code in WORK_DIR, so their Stop hooks
84
+ # come from WORK_DIR/.claude/settings*.json, NOT from the orchestrix-mcp-server project.
85
+ # We must inject the handoff-detector hook into the target project's settings.local.json
86
+ # so that agent Stop events trigger local handoff detection.
87
+ SETTINGS_LOCAL="$WORK_DIR/.claude/settings.local.json"
88
+ HANDOFF_HOOK_CMD="bash -c 'cd \"\$(git rev-parse --show-toplevel)\" && .orchestrix-core/scripts/handoff-detector.sh'"
89
+
90
+ # Ensure .claude directory exists
91
+ mkdir -p "$WORK_DIR/.claude"
92
+
93
+ # Check if settings.local.json already has handoff-detector configured
94
+ if [ -f "$SETTINGS_LOCAL" ]; then
95
+ if grep -q "handoff-detector" "$SETTINGS_LOCAL" 2>/dev/null; then
96
+ echo "✅ Handoff hook already configured in $SETTINGS_LOCAL"
97
+ else
98
+ echo "⚠️ settings.local.json exists but missing handoff hook, injecting..."
99
+ # Use jq to merge if available, otherwise create new
100
+ if command -v jq &>/dev/null; then
101
+ EXISTING=$(cat "$SETTINGS_LOCAL")
102
+ echo "$EXISTING" | jq --arg cmd "$HANDOFF_HOOK_CMD" \
103
+ '.hooks.Stop = (.hooks.Stop // []) + [{"hooks": [{"type": "command", "command": $cmd}]}]' \
104
+ > "$SETTINGS_LOCAL.tmp" && mv "$SETTINGS_LOCAL.tmp" "$SETTINGS_LOCAL"
105
+ echo "✅ Handoff hook injected into existing settings.local.json"
106
+ else
107
+ echo "⚠️ jq not found, cannot safely merge. Please add handoff hook manually."
108
+ fi
109
+ fi
110
+ else
111
+ # Create new settings.local.json with handoff hook
112
+ cat > "$SETTINGS_LOCAL" << SETTINGS_EOF
113
+ {
114
+ "hooks": {
115
+ "Stop": [
116
+ {
117
+ "hooks": [
118
+ {
119
+ "type": "command",
120
+ "command": "$HANDOFF_HOOK_CMD"
121
+ }
122
+ ]
123
+ }
124
+ ]
125
+ }
126
+ }
127
+ SETTINGS_EOF
128
+ echo "✅ Created $SETTINGS_LOCAL with handoff hook"
129
+ fi
130
+
131
+ # ============================================
132
+ # Ensure handoff-detector.sh exists in target project
133
+ # ============================================
134
+ HANDOFF_SCRIPT="$WORK_DIR/.orchestrix-core/scripts/handoff-detector.sh"
135
+ if [ ! -f "$HANDOFF_SCRIPT" ]; then
136
+ SCRIPT_DIR_SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
137
+ if [ -f "$SCRIPT_DIR_SRC/handoff-detector.sh" ]; then
138
+ mkdir -p "$(dirname "$HANDOFF_SCRIPT")"
139
+ cp "$SCRIPT_DIR_SRC/handoff-detector.sh" "$HANDOFF_SCRIPT"
140
+ chmod +x "$HANDOFF_SCRIPT"
141
+ echo "✅ Copied handoff-detector.sh to target project"
142
+ else
143
+ echo "⚠️ handoff-detector.sh not found in setup directory"
144
+ fi
145
+ fi
146
+
147
+ # ============================================
148
+ # Create tmux automation marker
149
+ # ============================================
150
+ # This file signals to agents that they're running in tmux automation mode
151
+ # Agents check for this file to decide whether to register pending-handoff fallback
152
+ RUNTIME_DIR="$WORK_DIR/.orchestrix-core/runtime"
153
+ TMUX_MARKER="$RUNTIME_DIR/tmux-automation-active"
154
+
155
+ mkdir -p "$RUNTIME_DIR"
156
+ echo "{\"session\": \"$SESSION_NAME\", \"started_at\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}" > "$TMUX_MARKER"
157
+ echo "📌 tmux automation marker: $TMUX_MARKER"
158
+
159
+ # Cleanup marker file on script exit (detach, kill, Ctrl+C)
160
+ cleanup() {
161
+ rm -f "$TMUX_MARKER"
162
+ echo "🧹 Cleaned up tmux automation marker"
163
+ }
164
+ trap cleanup EXIT INT TERM
165
+
166
+ # Configure status bar for better display
167
+ tmux set-option -t "$SESSION_NAME" status-left-length 20
168
+ tmux set-option -t "$SESSION_NAME" status-right-length 60
169
+ tmux set-option -t "$SESSION_NAME" window-status-format "#I:#W"
170
+ tmux set-option -t "$SESSION_NAME" window-status-current-format "#I:#W*"
171
+
172
+ # Set environment variables for Architect window
173
+ # ORCHESTRIX_SESSION and ORCHESTRIX_LOG are used by handoff-detector.sh
174
+ tmux send-keys -t "$SESSION_NAME:0" "export AGENT_ID=architect" C-m
175
+ tmux send-keys -t "$SESSION_NAME:0" "export ORCHESTRIX_SESSION=$SESSION_NAME" C-m
176
+ tmux send-keys -t "$SESSION_NAME:0" "export ORCHESTRIX_LOG=$LOG_FILE" C-m
177
+ tmux send-keys -t "$SESSION_NAME:0" "clear" C-m
178
+ tmux send-keys -t "$SESSION_NAME:0" "echo '╔════════════════════════════════════════╗'" C-m
179
+ tmux send-keys -t "$SESSION_NAME:0" "echo '║ 🏛️ Architect Agent (Window 0) ║'" C-m
180
+ tmux send-keys -t "$SESSION_NAME:0" "echo '╚════════════════════════════════════════╝'" C-m
181
+ tmux send-keys -t "$SESSION_NAME:0" "echo ''" C-m
182
+
183
+ # Create window 1 - SM
184
+ tmux new-window -t "$SESSION_NAME:1" -n "SM" -c "$WORK_DIR"
185
+ tmux send-keys -t "$SESSION_NAME:1" "export AGENT_ID=sm" C-m
186
+ tmux send-keys -t "$SESSION_NAME:1" "export ORCHESTRIX_SESSION=$SESSION_NAME" C-m
187
+ tmux send-keys -t "$SESSION_NAME:1" "export ORCHESTRIX_LOG=$LOG_FILE" C-m
188
+ tmux send-keys -t "$SESSION_NAME:1" "clear" C-m
189
+ tmux send-keys -t "$SESSION_NAME:1" "echo '╔════════════════════════════════════════╗'" C-m
190
+ tmux send-keys -t "$SESSION_NAME:1" "echo '║ 📋 SM Agent (Window 1) ║'" C-m
191
+ tmux send-keys -t "$SESSION_NAME:1" "echo '╚════════════════════════════════════════╝'" C-m
192
+ tmux send-keys -t "$SESSION_NAME:1" "echo ''" C-m
193
+
194
+ # Create window 2 - Dev
195
+ tmux new-window -t "$SESSION_NAME:2" -n "Dev" -c "$WORK_DIR"
196
+ tmux send-keys -t "$SESSION_NAME:2" "export AGENT_ID=dev" C-m
197
+ tmux send-keys -t "$SESSION_NAME:2" "export ORCHESTRIX_SESSION=$SESSION_NAME" C-m
198
+ tmux send-keys -t "$SESSION_NAME:2" "export ORCHESTRIX_LOG=$LOG_FILE" C-m
199
+ tmux send-keys -t "$SESSION_NAME:2" "clear" C-m
200
+ tmux send-keys -t "$SESSION_NAME:2" "echo '╔════════════════════════════════════════╗'" C-m
201
+ tmux send-keys -t "$SESSION_NAME:2" "echo '║ 💻 Dev Agent (Window 2) ║'" C-m
202
+ tmux send-keys -t "$SESSION_NAME:2" "echo '╚════════════════════════════════════════╝'" C-m
203
+ tmux send-keys -t "$SESSION_NAME:2" "echo ''" C-m
204
+
205
+ # Create window 3 - QA
206
+ tmux new-window -t "$SESSION_NAME:3" -n "QA" -c "$WORK_DIR"
207
+ tmux send-keys -t "$SESSION_NAME:3" "export AGENT_ID=qa" C-m
208
+ tmux send-keys -t "$SESSION_NAME:3" "export ORCHESTRIX_SESSION=$SESSION_NAME" C-m
209
+ tmux send-keys -t "$SESSION_NAME:3" "export ORCHESTRIX_LOG=$LOG_FILE" C-m
210
+ tmux send-keys -t "$SESSION_NAME:3" "clear" C-m
211
+ tmux send-keys -t "$SESSION_NAME:3" "echo '╔════════════════════════════════════════╗'" C-m
212
+ tmux send-keys -t "$SESSION_NAME:3" "echo '║ 🧪 QA Agent (Window 3) ║'" C-m
213
+ tmux send-keys -t "$SESSION_NAME:3" "echo '╚════════════════════════════════════════╝'" C-m
214
+ tmux send-keys -t "$SESSION_NAME:3" "echo ''" C-m
215
+
216
+ # ============================================
217
+ # Configuration
218
+ # ============================================
219
+
220
+ # Wait time for Claude Code to start (seconds)
221
+ CC_STARTUP_WAIT=12
222
+
223
+ # Wait time between command text and Enter key (seconds)
224
+ COMMAND_ENTER_DELAY=1
225
+
226
+ # Wait time between activating agents (seconds)
227
+ AGENT_ACTIVATION_DELAY=2
228
+
229
+ # Wait time for agents to fully load before starting workflow (seconds)
230
+ AGENT_LOAD_WAIT=15
231
+
232
+ # Auto-start workflow command (sent to SM window)
233
+ AUTO_START_COMMAND="1"
234
+
235
+ # Agent activation commands (MCP version uses /o command)
236
+ declare -a AGENT_COMMANDS=(
237
+ "/o architect" # Window 0 - Architect
238
+ "/o sm" # Window 1 - SM
239
+ "/o dev" # Window 2 - Dev
240
+ "/o qa" # Window 3 - QA
241
+ )
242
+
243
+ declare -a AGENT_NAMES=(
244
+ "Architect"
245
+ "SM"
246
+ "Dev"
247
+ "QA"
248
+ )
249
+
250
+ # ============================================
251
+ # Function: Send command with delay before Enter
252
+ # Usage: send_command_with_delay <window> <command>
253
+ # ============================================
254
+ send_command_with_delay() {
255
+ local window="$1"
256
+ local command="$2"
257
+
258
+ # Send command text first
259
+ tmux send-keys -t "$SESSION_NAME:$window" "$command"
260
+
261
+ # Wait before sending Enter (prevents race condition)
262
+ sleep "$COMMAND_ENTER_DELAY"
263
+
264
+ # Send Enter key
265
+ tmux send-keys -t "$SESSION_NAME:$window" "Enter"
266
+ }
267
+
268
+ # ============================================
269
+ # Start Claude Code in all windows
270
+ # ============================================
271
+
272
+ echo "🤖 Starting Claude Code in all windows..."
273
+
274
+ # Window 0 - Architect
275
+ tmux send-keys -t "$SESSION_NAME:0" "cc" C-m
276
+
277
+ # Window 1 - SM
278
+ tmux send-keys -t "$SESSION_NAME:1" "cc" C-m
279
+
280
+ # Window 2 - Dev
281
+ tmux send-keys -t "$SESSION_NAME:2" "cc" C-m
282
+
283
+ # Window 3 - QA
284
+ tmux send-keys -t "$SESSION_NAME:3" "cc" C-m
285
+
286
+ # ============================================
287
+ # Wait for Claude Code to fully initialize
288
+ # ============================================
289
+
290
+ echo ""
291
+ echo "⏳ Waiting ${CC_STARTUP_WAIT}s for Claude Code to start..."
292
+ echo ""
293
+
294
+ # Show countdown
295
+ for i in $(seq "$CC_STARTUP_WAIT" -1 1); do
296
+ printf "\r %2d seconds remaining..." "$i"
297
+ sleep 1
298
+ done
299
+ printf "\r ✓ Claude Code should be ready now! \n"
300
+ echo ""
301
+
302
+ # ============================================
303
+ # Auto-activate agents in each window
304
+ # ============================================
305
+
306
+ echo "🚀 Auto-activating agents..."
307
+ echo ""
308
+
309
+ for window in 0 1 2 3; do
310
+ agent_name="${AGENT_NAMES[$window]}"
311
+ agent_cmd="${AGENT_COMMANDS[$window]}"
312
+
313
+ echo " [Window $window] Activating $agent_name..."
314
+ send_command_with_delay "$window" "$agent_cmd"
315
+
316
+ # Wait before activating next agent (avoid overwhelming the system)
317
+ if [ "$window" -lt 3 ]; then
318
+ sleep "$AGENT_ACTIVATION_DELAY"
319
+ fi
320
+ done
321
+
322
+ echo ""
323
+ echo "✅ All agents activated!"
324
+
325
+ # ============================================
326
+ # Wait for agents to fully load
327
+ # ============================================
328
+
329
+ echo ""
330
+ echo "⏳ Waiting ${AGENT_LOAD_WAIT}s for agents to load..."
331
+ echo ""
332
+
333
+ for i in $(seq "$AGENT_LOAD_WAIT" -1 1); do
334
+ printf "\r %2d seconds remaining..." "$i"
335
+ sleep 1
336
+ done
337
+ printf "\r ✓ Agents should be ready now! \n"
338
+
339
+ # ============================================
340
+ # Auto-start workflow in SM window
341
+ # ============================================
342
+
343
+ echo ""
344
+ echo "🎬 Starting workflow in SM window..."
345
+ send_command_with_delay "1" "$AUTO_START_COMMAND"
346
+
347
+ # Select SM window (window 1) as starting point
348
+ tmux select-window -t "$SESSION_NAME:1"
349
+
350
+ # Display startup completion message
351
+ echo ""
352
+ echo "═══════════════════════════════════════════════════════════════"
353
+ echo "✅ Orchestrix automation started!"
354
+ echo "═══════════════════════════════════════════════════════════════"
355
+ echo ""
356
+ echo "📋 Window Layout:"
357
+ echo " Window 0: 🏛️ Architect"
358
+ echo " Window 1: 📋 SM (current window) ← workflow started"
359
+ echo " Window 2: 💻 Dev"
360
+ echo " Window 3: 🧪 QA"
361
+ echo ""
362
+ echo "⌨️ tmux navigation:"
363
+ echo " Ctrl+b → 0/1/2/3 Jump to window"
364
+ echo " Ctrl+b → n/p Next/Previous window"
365
+ echo " Ctrl+b → d Detach (runs in background)"
366
+ echo " Ctrl+b → [ Scroll mode (q to exit)"
367
+ echo ""
368
+ echo "📝 Monitor: tail -f $LOG_FILE"
369
+ echo "📝 Reconnect: tmux attach -t $SESSION_NAME"
370
+ echo ""
371
+
372
+ # Attach to session
373
+ tmux attach-session -t "$SESSION_NAME"
@@ -0,0 +1,61 @@
1
+ #!/bin/bash
2
+ # Yuri Session Ensurer — lazy recreation of tmux sessions
3
+ # Usage: ensure-session.sh <type> <project_root>
4
+ # type: "planning" or "dev"
5
+ set +e
6
+
7
+ TYPE="$1"
8
+ PROJECT_ROOT="$2"
9
+
10
+ if [ -z "$TYPE" ] || [ -z "$PROJECT_ROOT" ]; then
11
+ echo "Usage: ensure-session.sh <planning|dev> <project_root>"
12
+ exit 1
13
+ fi
14
+
15
+ PROJECT_ROOT=$(cd "$PROJECT_ROOT" && pwd)
16
+
17
+ if [ "$TYPE" = "planning" ]; then
18
+ PROJECT_NAME=$(basename "$PROJECT_ROOT")
19
+ SESSION="op-$(echo "$PROJECT_NAME" | tr -cd 'a-zA-Z0-9_-')"
20
+
21
+ if tmux has-session -t "$SESSION" 2>/dev/null; then
22
+ echo "$SESSION"
23
+ exit 0
24
+ fi
25
+
26
+ # Recreate planning session
27
+ tmux new-session -d -s "$SESSION" -n "Plan" -c "$PROJECT_ROOT"
28
+ tmux send-keys -t "$SESSION:0" "cc" C-m
29
+ sleep 12
30
+ echo "$SESSION"
31
+
32
+ elif [ "$TYPE" = "dev" ]; then
33
+ CONFIG="$PROJECT_ROOT/.orchestrix-core/core-config.yaml"
34
+ REPO_ID=""
35
+
36
+ if [ -f "$CONFIG" ]; then
37
+ REPO_ID=$(grep -E '^\s*repository_id:' "$CONFIG" 2>/dev/null | head -1 | sed "s/.*repository_id:[[:space:]]*//" | tr -d "'" | tr -d '"' | tr -d ' ')
38
+ fi
39
+
40
+ if [ -z "$REPO_ID" ]; then
41
+ REPO_ID=$(basename "$PROJECT_ROOT")
42
+ fi
43
+
44
+ REPO_ID=$(echo "$REPO_ID" | tr -cd 'a-zA-Z0-9_-')
45
+ SESSION="orchestrix-${REPO_ID}"
46
+
47
+ if tmux has-session -t "$SESSION" 2>/dev/null; then
48
+ echo "$SESSION"
49
+ exit 0
50
+ fi
51
+
52
+ # Recreate dev session
53
+ cd "$PROJECT_ROOT"
54
+ bash .orchestrix-core/scripts/start-orchestrix.sh &
55
+ sleep 30
56
+ echo "$SESSION"
57
+
58
+ else
59
+ echo "Unknown type: $TYPE. Use 'planning' or 'dev'."
60
+ exit 1
61
+ fi
@@ -0,0 +1,61 @@
1
+ #!/bin/bash
2
+ # Yuri Agent Completion Monitor
3
+ # Polls a tmux pane for agent completion signals.
4
+ # Usage: monitor-agent.sh <session> <window> [expected_file] [timeout_min] [poll_sec]
5
+ set +e
6
+
7
+ SESSION="$1"
8
+ WINDOW="$2"
9
+ EXPECTED_FILE="${3:-}"
10
+ TIMEOUT_MIN="${4:-30}"
11
+ POLL_SEC="${5:-30}"
12
+
13
+ MAX_POLLS=$((TIMEOUT_MIN * 60 / POLL_SEC))
14
+ STABLE_COUNT=0
15
+ LAST_HASH=""
16
+
17
+ for i in $(seq 1 $MAX_POLLS); do
18
+ OUTPUT=$(tmux capture-pane -t "$SESSION:$WINDOW" -p -S -200 2>/dev/null)
19
+ LAST_LINES=$(echo "$OUTPUT" | tail -10)
20
+
21
+ # Priority 1: Claude Code completion message ("Baked for 31s", "Worked for 2m", etc.)
22
+ if echo "$LAST_LINES" | grep -qE '[A-Z][a-z]*ed for [0-9]'; then
23
+ if [ -z "$EXPECTED_FILE" ] || [ -f "$EXPECTED_FILE" ]; then
24
+ echo "COMPLETE"
25
+ exit 0
26
+ fi
27
+ fi
28
+
29
+ # Priority 2: TUI idle indicator
30
+ if echo "$LAST_LINES" | grep -q '○'; then
31
+ if [ -z "$EXPECTED_FILE" ] || [ -f "$EXPECTED_FILE" ]; then
32
+ echo "IDLE"
33
+ exit 0
34
+ fi
35
+ fi
36
+
37
+ # Priority 3: Handle approval prompt — auto-approve
38
+ if echo "$LAST_LINES" | grep -q '◐'; then
39
+ tmux send-keys -t "$SESSION:$WINDOW" "y" Enter
40
+ sleep 2
41
+ continue
42
+ fi
43
+
44
+ # Priority 4: Content stability fallback
45
+ HASH=$(echo "$OUTPUT" | md5 2>/dev/null || echo "$OUTPUT" | md5sum 2>/dev/null | cut -d' ' -f1)
46
+ if [ "$HASH" = "$LAST_HASH" ]; then
47
+ STABLE_COUNT=$((STABLE_COUNT + 1))
48
+ if [ $STABLE_COUNT -ge 3 ]; then
49
+ echo "STABLE_IDLE"
50
+ exit 0
51
+ fi
52
+ else
53
+ STABLE_COUNT=0
54
+ fi
55
+ LAST_HASH="$HASH"
56
+
57
+ sleep "$POLL_SEC"
58
+ done
59
+
60
+ echo "TIMEOUT"
61
+ exit 1
@@ -0,0 +1,16 @@
1
+ #!/bin/bash
2
+ # Yuri Story Status Scanner
3
+ # Usage: scan-stories.sh <project_root>
4
+ set +e
5
+
6
+ STORIES_DIR="$1/docs/stories"
7
+
8
+ if [ ! -d "$STORIES_DIR" ]; then
9
+ echo "NO_STORIES_DIR"
10
+ exit 1
11
+ fi
12
+
13
+ for status in Done InProgress Review Blocked Approved AwaitingArchReview RequiresRevision Escalated; do
14
+ count=$(grep -rl "Status:.*$status" "$STORIES_DIR" 2>/dev/null | wc -l | tr -d ' ')
15
+ echo "$status:$count"
16
+ done
@@ -0,0 +1,20 @@
1
+ #!/bin/bash
2
+ # Yuri Planning Session Creator
3
+ # Usage: start-planning.sh <project_dir>
4
+ set -e
5
+
6
+ PROJECT_DIR="${1:-.}"
7
+ PROJECT_DIR=$(cd "$PROJECT_DIR" && pwd)
8
+ PROJECT_NAME=$(basename "$PROJECT_DIR")
9
+ SESSION="op-$(echo "$PROJECT_NAME" | tr -cd 'a-zA-Z0-9_-')"
10
+
11
+ # Kill existing session if present
12
+ tmux has-session -t "$SESSION" 2>/dev/null && tmux kill-session -t "$SESSION"
13
+
14
+ # Create session with initial window
15
+ tmux new-session -d -s "$SESSION" -n "Plan" -c "$PROJECT_DIR"
16
+
17
+ # Start Claude Code
18
+ tmux send-keys -t "$SESSION:0" "cc" C-m
19
+
20
+ echo "$SESSION"