squad-bmad 1.2.5 → 1.2.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "squad-bmad",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "description": "Automated project orchestration boilerplate with Gemini CLI & Claude Code via Tmux, following the BMAD methodology.",
5
5
  "keywords": [
6
6
  "gemini",
@@ -0,0 +1,48 @@
1
+ #!/bin/bash
2
+ # _common.sh — Shared helpers for squad-bmad tmux scripts.
3
+ #
4
+ # SOURCE this file; do not execute it directly.
5
+ # source "$(dirname "$0")/_common.sh"
6
+
7
+ # ── sanitize_for_tmux ──────────────────────────────────────────────────────
8
+ # Make a string safe for use as a tmux session name.
9
+ # • '.' → tmux uses it as session.window.pane separator
10
+ # • ':' → tmux uses it as session:window separator
11
+ # • ' ' → causes quoting headaches in targets
12
+ # Replace all of them with underscores.
13
+ sanitize_for_tmux() {
14
+ local name="$1"
15
+ name="${name//./_}"
16
+ name="${name//:/_}"
17
+ name="${name// /_}"
18
+ echo "$name"
19
+ }
20
+
21
+ # ── resolve_folder ─────────────────────────────────────────────────────────
22
+ # Determine the project folder name (already sanitised for tmux).
23
+ # $1 — explicit folder name (optional; falls back to git root or $PWD)
24
+ resolve_folder() {
25
+ local folder
26
+ if [ -n "$1" ]; then
27
+ folder="$1"
28
+ else
29
+ local git_root
30
+ git_root=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
31
+ if [ -n "$git_root" ]; then
32
+ folder=$(basename "$git_root")
33
+ else
34
+ folder=$(basename "$PWD")
35
+ fi
36
+ fi
37
+ sanitize_for_tmux "$folder"
38
+ }
39
+
40
+ # ── derive_session_names ───────────────────────────────────────────────────
41
+ # Sets SESSION_GEMINI, SESSION_IMPLEMENT, SESSION_BRAINSTORM globals.
42
+ # $1 — sanitised folder name (output of resolve_folder)
43
+ derive_session_names() {
44
+ local folder="$1"
45
+ SESSION_GEMINI="gemini-orchestrator-${folder}"
46
+ SESSION_IMPLEMENT="claude-implement-${folder}"
47
+ SESSION_BRAINSTORM="claude-brainstorm-${folder}"
48
+ }
@@ -17,25 +17,14 @@
17
17
 
18
18
  set -e
19
19
 
20
- # ── Resolve folder name ──────────────────────────────────────────────────────
21
- if [ -n "$1" ]; then
22
- FOLDER="$1"
23
- else
24
- # Use git root to resolve correctly from any subdirectory
25
- GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
26
- if [ -n "$GIT_ROOT" ]; then
27
- FOLDER=$(basename "$GIT_ROOT")
28
- else
29
- FOLDER=$(basename "$PWD")
30
- fi
31
- fi
20
+ # ── Load shared helpers ────────────────────────────────────────────────────
21
+ source "$(dirname "$0")/_common.sh"
32
22
 
33
- # ── Derive session names ─────────────────────────────────────────────────────
34
- SESSION_GEMINI="gemini-orchestrator-${FOLDER}"
35
- SESSION_IMPLEMENT="claude-implement-${FOLDER}"
36
- SESSION_BRAINSTORM="claude-brainstorm-${FOLDER}"
23
+ # ── Resolve folder & session names ─────────────────────────────────────────
24
+ FOLDER=$(resolve_folder "$1")
25
+ derive_session_names "$FOLDER"
37
26
 
38
- # ── Helper: create session only if it does not already exist ─────────────────
27
+ # ── Helper: create session only if it does not already exist ─────────────
39
28
  create_session_if_missing() {
40
29
  local session_name="$1"
41
30
  local start_cmd="$2" # command to run inside the new session
@@ -46,7 +35,6 @@ create_session_if_missing() {
46
35
  else
47
36
  # -d : start detached
48
37
  # -s : session name
49
- # The shell command is passed via tmux's 'new-session' so it runs immediately
50
38
  tmux new-session -d -s "$session_name" -x 220 -y 50
51
39
  # Give the shell a moment to initialise before sending the startup command
52
40
  sleep 0.5
@@ -55,7 +43,7 @@ create_session_if_missing() {
55
43
  fi
56
44
  }
57
45
 
58
- # ── Print plan ────────────────────────────────────────────────────────────────
46
+ # ── Print plan ────────────────────────────────────────────────────────────
59
47
  echo ""
60
48
  echo "╔══════════════════════════════════════════════════════════════╗"
61
49
  echo "║ squad-bmad • Session Setup ║"
@@ -17,24 +17,14 @@
17
17
 
18
18
  set -e
19
19
 
20
- # ── Resolve folder name ──────────────────────────────────────────────────────
21
- if [ -n "$1" ]; then
22
- FOLDER="$1"
23
- else
24
- GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
25
- if [ -n "$GIT_ROOT" ]; then
26
- FOLDER=$(basename "$GIT_ROOT")
27
- else
28
- FOLDER=$(basename "$PWD")
29
- fi
30
- fi
20
+ # ── Load shared helpers ────────────────────────────────────────────────────
21
+ source "$(dirname "$0")/_common.sh"
31
22
 
32
- # ── Derive session names ─────────────────────────────────────────────────────
33
- SESSION_GEMINI="gemini-orchestrator-${FOLDER}"
34
- SESSION_IMPLEMENT="claude-implement-${FOLDER}"
35
- SESSION_BRAINSTORM="claude-brainstorm-${FOLDER}"
23
+ # ── Resolve folder & session names ─────────────────────────────────────────
24
+ FOLDER=$(resolve_folder "$1")
25
+ derive_session_names "$FOLDER"
36
26
 
37
- # ── Helper: kill session if it exists ─────────────────────────────────────────
27
+ # ── Helper: kill session if it exists ─────────────────────────────────────
38
28
  kill_session_if_exists() {
39
29
  local session_name="$1"
40
30
  local label="$2"
@@ -47,7 +37,7 @@ kill_session_if_exists() {
47
37
  fi
48
38
  }
49
39
 
50
- # ── Print plan ────────────────────────────────────────────────────────────────
40
+ # ── Print plan ────────────────────────────────────────────────────────────
51
41
  echo ""
52
42
  echo "╔══════════════════════════════════════════════════════════════╗"
53
43
  echo "║ squad-bmad • Session Teardown ║"
@@ -61,12 +51,12 @@ echo " 2. ${SESSION_IMPLEMENT}"
61
51
  echo " 3. ${SESSION_BRAINSTORM}"
62
52
  echo ""
63
53
 
64
- # ── Kill sessions ─────────────────────────────────────────────────────────────
54
+ # ── Kill sessions ─────────────────────────────────────────────────────────
65
55
  kill_session_if_exists "$SESSION_GEMINI" "Gemini Orchestrator"
66
56
  kill_session_if_exists "$SESSION_IMPLEMENT" "Claude Implement (Sonnet)"
67
57
  kill_session_if_exists "$SESSION_BRAINSTORM" "Claude Brainstorm (Opus)"
68
58
 
69
- # ── Summary ───────────────────────────────────────────────────────────────────
59
+ # ── Summary ───────────────────────────────────────────────────────────────
70
60
  echo ""
71
61
  REMAINING=$(tmux list-sessions 2>/dev/null || true)
72
62
  if [ -n "$REMAINING" ]; then
@@ -2,33 +2,40 @@
2
2
  # tmux-send.sh — Reliably send text to a tmux pane.
3
3
  #
4
4
  # USAGE:
5
- # ./tmux-send.sh <pane-target> <message> [wait-seconds]
5
+ # ./tmux-send.sh <session-name> <message> [wait-seconds]
6
6
  #
7
7
  # ARGUMENTS:
8
- # pane-target — tmux target, e.g.: gemini-orchestrator:0.0
8
+ # session-name — tmux session (will be sanitised and targeted at :0.0)
9
9
  # message — content to send (wrap in quotes if it contains spaces)
10
10
  # wait-seconds — (optional) seconds to wait between text and Enter, default: 5
11
11
  #
12
12
  # EXAMPLES:
13
- # .gemini/scripts/tmux-send.sh "gemini-orchestrator:0.0" "Hello from Claude Code"
14
- # .gemini/scripts/tmux-send.sh "cc-implement:0" "/dev-story" 3
13
+ # .gemini/scripts/tmux-send.sh "gemini-orchestrator-squad-bmad" "Hello from Claude Code"
14
+ # .gemini/scripts/tmux-send.sh "claude-implement-squad-bmad" "/dev-story" 3
15
15
 
16
16
  set -e
17
17
 
18
- PANE_TARGET="$1"
18
+ # ── Load shared helpers ────────────────────────────────────────────────────
19
+ source "$(dirname "$0")/_common.sh"
20
+
21
+ SESSION_NAME="$1"
19
22
  MESSAGE="$2"
20
23
  WAIT_SECONDS="${3:-5}"
21
24
 
22
25
  # Validate required arguments
23
- if [ -z "$PANE_TARGET" ] || [ -z "$MESSAGE" ]; then
26
+ if [ -z "$SESSION_NAME" ] || [ -z "$MESSAGE" ]; then
24
27
  echo "Error: Missing arguments." >&2
25
- echo "Usage: $0 <pane-target> <message> [wait-seconds]" >&2
28
+ echo "Usage: $0 <session-name> <message> [wait-seconds]" >&2
26
29
  exit 1
27
30
  fi
28
31
 
29
- # Check that the pane exists
30
- if ! tmux has-session -t "$PANE_TARGET" 2>/dev/null; then
31
- echo "Error: Tmux target '$PANE_TARGET' does not exist." >&2
32
+ # Sanitise the session name (in case caller passed raw folder name inside it)
33
+ SESSION_NAME=$(sanitize_for_tmux "$SESSION_NAME")
34
+ PANE_TARGET="${SESSION_NAME}:0.0"
35
+
36
+ # Check that the session exists
37
+ if ! tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
38
+ echo "Error: Tmux session '$SESSION_NAME' does not exist." >&2
32
39
  exit 1
33
40
  fi
34
41
 
@@ -41,4 +48,4 @@ sleep "$WAIT_SECONDS"
41
48
  # Send Enter (C-m) — do NOT use 'Enter' or '\n'
42
49
  tmux send-keys -t "$PANE_TARGET" C-m
43
50
 
44
- echo "Sent to '$PANE_TARGET': $MESSAGE"
51
+ echo "Sent to '$PANE_TARGET': $MESSAGE"