shipwright-cli 2.0.0 → 2.1.1

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.
Files changed (112) hide show
  1. package/README.md +160 -72
  2. package/completions/_shipwright +59 -7
  3. package/completions/shipwright.bash +24 -4
  4. package/completions/shipwright.fish +80 -2
  5. package/dashboard/server.ts +208 -0
  6. package/docs/tmux-research/TMUX-ARCHITECTURE.md +567 -0
  7. package/docs/tmux-research/TMUX-AUDIT.md +925 -0
  8. package/docs/tmux-research/TMUX-BEST-PRACTICES-2025-2026.md +829 -0
  9. package/docs/tmux-research/TMUX-QUICK-REFERENCE.md +543 -0
  10. package/docs/tmux-research/TMUX-RESEARCH-INDEX.md +438 -0
  11. package/package.json +2 -2
  12. package/scripts/lib/helpers.sh +7 -0
  13. package/scripts/sw +116 -2
  14. package/scripts/sw-activity.sh +1 -1
  15. package/scripts/sw-adaptive.sh +1 -1
  16. package/scripts/sw-adversarial.sh +1 -1
  17. package/scripts/sw-architecture-enforcer.sh +1 -1
  18. package/scripts/sw-auth.sh +1 -1
  19. package/scripts/sw-autonomous.sh +128 -38
  20. package/scripts/sw-changelog.sh +1 -1
  21. package/scripts/sw-checkpoint.sh +1 -1
  22. package/scripts/sw-ci.sh +1 -1
  23. package/scripts/sw-cleanup.sh +1 -1
  24. package/scripts/sw-code-review.sh +62 -1
  25. package/scripts/sw-connect.sh +1 -1
  26. package/scripts/sw-context.sh +1 -1
  27. package/scripts/sw-cost.sh +44 -3
  28. package/scripts/sw-daemon.sh +155 -27
  29. package/scripts/sw-dashboard.sh +1 -1
  30. package/scripts/sw-db.sh +958 -118
  31. package/scripts/sw-decompose.sh +1 -1
  32. package/scripts/sw-deps.sh +1 -1
  33. package/scripts/sw-developer-simulation.sh +1 -1
  34. package/scripts/sw-discovery.sh +1 -1
  35. package/scripts/sw-docs-agent.sh +1 -1
  36. package/scripts/sw-docs.sh +1 -1
  37. package/scripts/sw-doctor.sh +49 -1
  38. package/scripts/sw-dora.sh +1 -1
  39. package/scripts/sw-durable.sh +1 -1
  40. package/scripts/sw-e2e-orchestrator.sh +1 -1
  41. package/scripts/sw-eventbus.sh +1 -1
  42. package/scripts/sw-feedback.sh +23 -15
  43. package/scripts/sw-fix.sh +1 -1
  44. package/scripts/sw-fleet-discover.sh +1 -1
  45. package/scripts/sw-fleet-viz.sh +1 -1
  46. package/scripts/sw-fleet.sh +1 -1
  47. package/scripts/sw-github-app.sh +1 -1
  48. package/scripts/sw-github-checks.sh +4 -4
  49. package/scripts/sw-github-deploy.sh +1 -1
  50. package/scripts/sw-github-graphql.sh +1 -1
  51. package/scripts/sw-guild.sh +1 -1
  52. package/scripts/sw-heartbeat.sh +1 -1
  53. package/scripts/sw-hygiene.sh +1 -1
  54. package/scripts/sw-incident.sh +45 -6
  55. package/scripts/sw-init.sh +150 -24
  56. package/scripts/sw-instrument.sh +1 -1
  57. package/scripts/sw-intelligence.sh +1 -1
  58. package/scripts/sw-jira.sh +1 -1
  59. package/scripts/sw-launchd.sh +1 -1
  60. package/scripts/sw-linear.sh +1 -1
  61. package/scripts/sw-logs.sh +1 -1
  62. package/scripts/sw-loop.sh +204 -19
  63. package/scripts/sw-memory.sh +18 -1
  64. package/scripts/sw-mission-control.sh +1 -1
  65. package/scripts/sw-model-router.sh +1 -1
  66. package/scripts/sw-otel.sh +1 -1
  67. package/scripts/sw-oversight.sh +76 -1
  68. package/scripts/sw-pipeline-composer.sh +1 -1
  69. package/scripts/sw-pipeline-vitals.sh +1 -1
  70. package/scripts/sw-pipeline.sh +302 -18
  71. package/scripts/sw-pm.sh +70 -5
  72. package/scripts/sw-pr-lifecycle.sh +1 -1
  73. package/scripts/sw-predictive.sh +8 -1
  74. package/scripts/sw-prep.sh +1 -1
  75. package/scripts/sw-ps.sh +1 -1
  76. package/scripts/sw-public-dashboard.sh +1 -1
  77. package/scripts/sw-quality.sh +1 -1
  78. package/scripts/sw-reaper.sh +1 -1
  79. package/scripts/sw-recruit.sh +1853 -178
  80. package/scripts/sw-regression.sh +1 -1
  81. package/scripts/sw-release-manager.sh +1 -1
  82. package/scripts/sw-release.sh +1 -1
  83. package/scripts/sw-remote.sh +1 -1
  84. package/scripts/sw-replay.sh +1 -1
  85. package/scripts/sw-retro.sh +1 -1
  86. package/scripts/sw-scale.sh +1 -1
  87. package/scripts/sw-security-audit.sh +1 -1
  88. package/scripts/sw-self-optimize.sh +1 -1
  89. package/scripts/sw-session.sh +1 -1
  90. package/scripts/sw-setup.sh +263 -127
  91. package/scripts/sw-standup.sh +1 -1
  92. package/scripts/sw-status.sh +44 -2
  93. package/scripts/sw-strategic.sh +189 -41
  94. package/scripts/sw-stream.sh +1 -1
  95. package/scripts/sw-swarm.sh +42 -5
  96. package/scripts/sw-team-stages.sh +1 -1
  97. package/scripts/sw-templates.sh +4 -4
  98. package/scripts/sw-testgen.sh +66 -15
  99. package/scripts/sw-tmux-pipeline.sh +1 -1
  100. package/scripts/sw-tmux-role-color.sh +58 -0
  101. package/scripts/sw-tmux-status.sh +128 -0
  102. package/scripts/sw-tmux.sh +1 -1
  103. package/scripts/sw-trace.sh +1 -1
  104. package/scripts/sw-tracker.sh +1 -1
  105. package/scripts/sw-triage.sh +61 -37
  106. package/scripts/sw-upgrade.sh +1 -1
  107. package/scripts/sw-ux.sh +30 -2
  108. package/scripts/sw-webhook.sh +1 -1
  109. package/scripts/sw-widgets.sh +1 -1
  110. package/scripts/sw-worktree.sh +1 -1
  111. package/tmux/shipwright-overlay.conf +35 -17
  112. package/tmux/tmux.conf +26 -21
@@ -6,7 +6,7 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="1.13.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Handle subcommands ───────────────────────────────────────────────────────
@@ -208,8 +208,12 @@ EOF
208
208
  done
209
209
  echo ""
210
210
 
211
- # Generate test template
211
+ # Generate test template; use Claude for real assertions when available
212
212
  local test_template_file="$TESTGEN_DIR/generated-tests.sh"
213
+ local use_claude="false"
214
+ command -v claude &>/dev/null && use_claude="true"
215
+ [[ "${TESTGEN_USE_CLAUDE:-true}" == "false" ]] && use_claude="false"
216
+
213
217
  {
214
218
  echo "#!/usr/bin/env bash"
215
219
  echo "# Generated tests for $target_script"
@@ -217,24 +221,71 @@ EOF
217
221
  echo "trap 'echo \"ERROR: \$BASH_SOURCE:\$LINENO exited with status \$?\" >&2' ERR"
218
222
  echo ""
219
223
  echo "SCRIPT_DIR=\"\$(cd \"\$(dirname \"\${BASH_SOURCE[0]}\")\" && pwd)\""
224
+ echo "REPO_DIR=\"\$(cd \"\$SCRIPT_DIR/..\" && pwd)\""
225
+ echo ""
226
+ echo "# Helpers: assert equal (or contains) so tests fail when behavior is wrong"
227
+ echo "assert_equal() { local e=\"\$1\" a=\"\$2\"; if [[ \"\$a\" != \"\$e\" ]]; then echo \"Expected: \$e\"; echo \"Actual: \$a\"; exit 1; fi; }"
228
+ echo "assert_contains() { local sub=\"\$1\" full=\"\$2\"; if [[ \"\$full\" != *\"\$sub\"* ]]; then echo \"Expected to contain: \$sub\"; echo \"In: \$full\"; exit 1; fi; }"
220
229
  echo ""
221
- echo "# Test counters"
222
230
  echo "PASS=0"
223
231
  echo "FAIL=0"
224
232
  echo ""
233
+ } > "$test_template_file"
225
234
 
226
- echo "$untested_functions" | while IFS= read -r func; do
227
- [[ -z "$func" ]] && continue
228
- echo "test_${func}() {"
229
- echo " # TODO: Implement test for $func"
230
- echo " # - Test happy path"
231
- echo " # - Test error cases"
232
- echo " # - Test edge cases"
233
- echo " ((PASS++))"
234
- echo "}"
235
+ local func_count=0
236
+ while IFS= read -r func; do
237
+ [[ -z "$func" ]] && continue
238
+ func_count=$((func_count + 1))
239
+ {
240
+ if [[ "$use_claude" == "true" ]]; then
241
+ local func_snippet
242
+ func_snippet=$(awk "/^${func}\(\\)/,/^[a-zA-Z_][a-zA-Z0-9_]*\(\)|^$/" "$target_script" 2>/dev/null | head -40 || true)
243
+ local prompt_file
244
+ prompt_file=$(mktemp "${TMPDIR:-/tmp}/sw-testgen-prompt.XXXXXX")
245
+ {
246
+ echo "Generate a bash test function for the following shell function. Use real assertions (assert_equal, assert_contains, or test exit code). Test happy path and at least one edge or error case. Output only the bash function body."
247
+ echo "Function name: ${func}"
248
+ echo "Function body:"
249
+ echo "$func_snippet"
250
+ } > "$prompt_file"
251
+ local claude_out
252
+ # Read prompt through pipe to avoid shell expansion of $vars in function body
253
+ claude_out=$(cat "$prompt_file" | claude -p --max-turns 2 2>/dev/null || true)
254
+ rm -f "$prompt_file"
255
+ if [[ -n "$claude_out" ]]; then
256
+ local code_block
257
+ code_block=$(echo "$claude_out" | sed -n '/^test_'"${func}"'()/,/^}/p' || echo "$claude_out" | sed -n '/^test_/,/^}/p' || true)
258
+ [[ -z "$code_block" ]] && code_block="$claude_out"
259
+ if echo "$code_block" | grep -qE 'assert_equal|assert_contains|\[\[.*\]\]|exit 1'; then
260
+ echo "test_${func}() {"
261
+ echo "$code_block" | sed 's/^test_'"${func}"'()//' | sed 's/^{//' | sed 's/^}//' | head -50
262
+ echo " ((PASS++))"
263
+ echo "}"
264
+ else
265
+ echo "test_${func}() {"
266
+ echo " # Claude-generated; review assertions"
267
+ echo "$code_block" | head -30 | sed 's/^/ /'
268
+ echo " ((PASS++))"
269
+ echo "}"
270
+ fi
271
+ else
272
+ echo "test_${func}() { # TODO: Claude unavailable"
273
+ echo " ((PASS++))"
274
+ echo "}"
275
+ fi
276
+ else
277
+ echo "test_${func}() {"
278
+ echo " # TODO: Implement test for $func"
279
+ echo " ((PASS++))"
280
+ echo "}"
281
+ fi
235
282
  echo ""
236
- done
283
+ } >> "$test_template_file"
284
+ done << EOF
285
+ $untested_functions
286
+ EOF
237
287
 
288
+ {
238
289
  echo "# Run all tests"
239
290
  echo "$untested_functions" | while IFS= read -r func; do
240
291
  [[ -z "$func" ]] && continue
@@ -242,11 +293,11 @@ EOF
242
293
  done
243
294
  echo ""
244
295
  echo "echo \"Results: \$PASS passed, \$FAIL failed\""
245
- } > "$test_template_file"
296
+ } >> "$test_template_file"
246
297
 
247
298
  chmod +x "$test_template_file"
248
299
  success "Generated test template: $test_template_file"
249
- info "Review and implement test logic, then move to test suite"
300
+ [[ "$use_claude" == "true" ]] && info "Used Claude for assertions; review and run tests to validate"
250
301
  }
251
302
 
252
303
  # ═══════════════════════════════════════════════════════════════════════════════
@@ -6,7 +6,7 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="2.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env bash
2
+ # ╔═══════════════════════════════════════════════════════════════════════════╗
3
+ # ║ sw-tmux-role-color.sh — Set pane border color by agent role ║
4
+ # ║ ║
5
+ # ║ Called from a tmux hook (after-select-pane) or manually. ║
6
+ # ║ Reads #{pane_title} and sets the active border color to match the ║
7
+ # ║ agent's role. Falls back to cyan (#00d4ff) for unknown roles. ║
8
+ # ║ ║
9
+ # ║ Role → Color mapping: ║
10
+ # ║ leader/pm → #00d4ff (cyan) — command & control ║
11
+ # ║ builder/dev → #0066ff (blue) — implementation ║
12
+ # ║ reviewer → #f97316 (orange) — scrutiny ║
13
+ # ║ tester → #facc15 (yellow) — validation ║
14
+ # ║ security → #ef4444 (red) — vigilance ║
15
+ # ║ docs/writer → #a78bfa (violet) — documentation ║
16
+ # ║ optimizer → #4ade80 (green) — performance ║
17
+ # ║ researcher → #7c3aed (purple) — exploration ║
18
+ # ╚═══════════════════════════════════════════════════════════════════════════╝
19
+ set -euo pipefail
20
+
21
+ # Get the active pane's title
22
+ PANE_TITLE="$(tmux display-message -p '#{pane_title}' 2>/dev/null || echo "")"
23
+
24
+ # Normalize to lowercase for matching
25
+ TITLE_LOWER="$(echo "$PANE_TITLE" | tr '[:upper:]' '[:lower:]')"
26
+
27
+ # Map role keywords to colors
28
+ COLOR="#00d4ff" # default: cyan
29
+
30
+ case "$TITLE_LOWER" in
31
+ *leader*|*lead*|*pm*|*manager*|*orchestrat*)
32
+ COLOR="#00d4ff" # cyan — command & control
33
+ ;;
34
+ *build*|*dev*|*implement*|*code*|*engineer*)
35
+ COLOR="#0066ff" # blue — implementation
36
+ ;;
37
+ *review*|*audit*|*inspect*|*oversight*)
38
+ COLOR="#f97316" # orange — scrutiny
39
+ ;;
40
+ *test*|*qa*|*validat*|*verify*)
41
+ COLOR="#facc15" # yellow — validation
42
+ ;;
43
+ *secur*|*vuln*|*threat*|*pentest*)
44
+ COLOR="#ef4444" # red — vigilance
45
+ ;;
46
+ *doc*|*writ*|*readme*|*changelog*)
47
+ COLOR="#a78bfa" # violet — documentation
48
+ ;;
49
+ *optim*|*perf*|*speed*|*deploy*)
50
+ COLOR="#4ade80" # green — performance/deploy
51
+ ;;
52
+ *research*|*explor*|*investigat*|*analyz*)
53
+ COLOR="#7c3aed" # purple — exploration
54
+ ;;
55
+ esac
56
+
57
+ # Set the active pane border color
58
+ tmux set -g pane-active-border-style "fg=${COLOR},bg=#1a1a2e" 2>/dev/null || true
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env bash
2
+ # ╔═══════════════════════════════════════════════════════════════════════════╗
3
+ # ║ sw-tmux-status.sh — Status bar widgets for tmux ║
4
+ # ║ ║
5
+ # ║ Called by tmux via #() in status-right. Must be FAST (<100ms). ║
6
+ # ║ Reads pipeline state from .claude/pipeline-state.md and heartbeats ║
7
+ # ║ from ~/.shipwright/heartbeats/. Outputs styled tmux format strings. ║
8
+ # ╚═══════════════════════════════════════════════════════════════════════════╝
9
+ set -euo pipefail
10
+
11
+ # ─── Stage colors (match Shipwright brand palette) ────────────────────────
12
+ # Each pipeline stage gets a distinct color for instant visual recognition
13
+ stage_color() {
14
+ case "${1:-}" in
15
+ intake) echo "#71717a" ;; # muted — gathering
16
+ plan) echo "#7c3aed" ;; # purple — thinking
17
+ design) echo "#7c3aed" ;; # purple — thinking
18
+ build) echo "#0066ff" ;; # blue — working
19
+ test) echo "#facc15" ;; # yellow — validating
20
+ review) echo "#f97316" ;; # orange — scrutinizing
21
+ compound_quality) echo "#f97316" ;; # orange — scrutinizing
22
+ pr) echo "#00d4ff" ;; # cyan — shipping
23
+ merge) echo "#00d4ff" ;; # cyan — shipping
24
+ deploy) echo "#4ade80" ;; # green — deploying
25
+ validate) echo "#4ade80" ;; # green — verifying
26
+ monitor) echo "#4ade80" ;; # green — watching
27
+ *) echo "#71717a" ;; # muted fallback
28
+ esac
29
+ }
30
+
31
+ # ─── Stage icons ──────────────────────────────────────────────────────────
32
+ stage_icon() {
33
+ case "${1:-}" in
34
+ intake) echo "◇" ;;
35
+ plan) echo "◆" ;;
36
+ design) echo "△" ;;
37
+ build) echo "⚙" ;;
38
+ test) echo "⚡" ;;
39
+ review) echo "◎" ;;
40
+ compound_quality) echo "◎" ;;
41
+ pr) echo "↑" ;;
42
+ merge) echo "⊕" ;;
43
+ deploy) echo "▲" ;;
44
+ validate) echo "✦" ;;
45
+ monitor) echo "◉" ;;
46
+ *) echo "·" ;;
47
+ esac
48
+ }
49
+
50
+ # ─── Pipeline stage widget ────────────────────────────────────────────────
51
+ # Reads current pipeline stage from state file, outputs tmux format string
52
+ pipeline_widget() {
53
+ local state_file=".claude/pipeline-state.md"
54
+
55
+ # Try current directory, then walk up to find repo root
56
+ if [[ ! -f "$state_file" ]]; then
57
+ local dir
58
+ dir="$(pwd)"
59
+ while [[ "$dir" != "/" ]]; do
60
+ if [[ -f "$dir/$state_file" ]]; then
61
+ state_file="$dir/$state_file"
62
+ break
63
+ fi
64
+ dir="$(dirname "$dir")"
65
+ done
66
+ fi
67
+
68
+ [[ -f "$state_file" ]] || return 0
69
+
70
+ # Extract current stage — look for "Stage:" or "## Stage:" pattern
71
+ local stage=""
72
+ stage="$(grep -iE '^\*?\*?(current )?stage:?\*?\*?' "$state_file" 2>/dev/null | head -1 | sed 's/.*: *//' | tr -d '*' | tr '[:upper:]' '[:lower:]' | tr -d ' ')" || true
73
+
74
+ [[ -n "$stage" ]] || return 0
75
+
76
+ local color icon
77
+ color="$(stage_color "$stage")"
78
+ icon="$(stage_icon "$stage")"
79
+ local label
80
+ label="$(echo "$stage" | tr '[:lower:]' '[:upper:]')"
81
+
82
+ # Output: colored badge with icon
83
+ echo "#[fg=#1e1e32,bg=${color},bold] ${icon} ${label} #[fg=${color},bg=#1a1a2e]"
84
+ }
85
+
86
+ # ─── Agent count widget ──────────────────────────────────────────────────
87
+ # Shows number of active agents from heartbeat files
88
+ agent_widget() {
89
+ local hb_dir="${HOME}/.shipwright/heartbeats"
90
+ [[ -d "$hb_dir" ]] || return 0
91
+
92
+ local now count=0
93
+ now="$(date +%s)"
94
+
95
+ for hb in "$hb_dir"/*.json; do
96
+ [[ -f "$hb" ]] || continue
97
+ # Heartbeat is alive if updated within last 60 seconds
98
+ local mtime
99
+ if [[ "$(uname)" == "Darwin" ]]; then
100
+ mtime="$(stat -f %m "$hb" 2>/dev/null || echo 0)"
101
+ else
102
+ mtime="$(stat -c %Y "$hb" 2>/dev/null || echo 0)"
103
+ fi
104
+ if (( now - mtime < 60 )); then
105
+ count=$((count + 1))
106
+ fi
107
+ done
108
+
109
+ if [[ $count -gt 0 ]]; then
110
+ echo "#[fg=#1e1e32,bg=#7c3aed,bold] λ${count} #[fg=#7c3aed,bg=#1a1a2e]"
111
+ fi
112
+ }
113
+
114
+ # ─── Dispatch ─────────────────────────────────────────────────────────────
115
+ case "${1:-pipeline}" in
116
+ pipeline) pipeline_widget ;;
117
+ agents) agent_widget ;;
118
+ all)
119
+ # Combine both widgets
120
+ local p a
121
+ p="$(pipeline_widget)"
122
+ a="$(agent_widget)"
123
+ echo "${a}${p}"
124
+ ;;
125
+ *)
126
+ echo ""
127
+ ;;
128
+ esac
@@ -11,7 +11,7 @@
11
11
  # ║ shipwright tmux fix — Auto-fix common issues ║
12
12
  # ║ shipwright tmux reload — Reload tmux config ║
13
13
  # ╚═══════════════════════════════════════════════════════════════════════════╝
14
- VERSION="2.0.0"
14
+ VERSION="2.1.1"
15
15
  set -euo pipefail
16
16
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
17
17
 
@@ -6,7 +6,7 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="2.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -6,7 +6,7 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="2.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -6,7 +6,7 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="2.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -403,40 +403,63 @@ cmd_team() {
403
403
  risk=$(echo "$analysis" | jq -r '.risk')
404
404
  effort=$(echo "$analysis" | jq -r '.effort')
405
405
 
406
- # Recommend based on complexity/risk
407
- local template model max_iterations agents
408
- case "${complexity}-${risk}" in
409
- trivial-low|simple-low)
410
- template="fast"
411
- model="haiku"
412
- max_iterations=2
413
- agents=1
414
- ;;
415
- simple-*|moderate-low)
416
- template="standard"
417
- model="sonnet"
418
- max_iterations=5
419
- agents=2
420
- ;;
421
- moderate-*|complex-low)
422
- template="standard"
423
- model="sonnet"
424
- max_iterations=8
425
- agents=3
426
- ;;
427
- complex-*|epic-*)
428
- template="full"
429
- model="opus"
430
- max_iterations=15
431
- agents=4
432
- ;;
433
- *)
434
- template="standard"
435
- model="sonnet"
436
- max_iterations=5
437
- agents=2
438
- ;;
439
- esac
406
+ # ── Try recruit-powered team composition first ──
407
+ local template="" model="" max_iterations="" agents=""
408
+ local recruit_source="heuristic"
409
+ if [[ -x "${SCRIPT_DIR:-}/sw-recruit.sh" ]]; then
410
+ local issue_title
411
+ issue_title=$(gh issue view "$issue" --json title -q '.title' 2>/dev/null || echo "")
412
+ if [[ -n "$issue_title" ]]; then
413
+ local recruit_result
414
+ recruit_result=$(bash "$SCRIPT_DIR/sw-recruit.sh" team --json "$issue_title" 2>/dev/null) || true
415
+ if [[ -n "$recruit_result" ]] && echo "$recruit_result" | jq -e '.team' &>/dev/null 2>&1; then
416
+ model=$(echo "$recruit_result" | jq -r '.model // "sonnet"')
417
+ agents=$(echo "$recruit_result" | jq -r '.agents // 2')
418
+ # Map agent count to template
419
+ if [[ "$agents" -ge 4 ]]; then template="full"; max_iterations=15;
420
+ elif [[ "$agents" -ge 3 ]]; then template="standard"; max_iterations=8;
421
+ elif [[ "$agents" -le 1 ]]; then template="fast"; max_iterations=2;
422
+ else template="standard"; max_iterations=5; fi
423
+ recruit_source="recruit"
424
+ fi
425
+ fi
426
+ fi
427
+
428
+ # ── Fallback: hardcoded complexity/risk mapping ──
429
+ if [[ -z "$template" ]]; then
430
+ case "${complexity}-${risk}" in
431
+ trivial-low|simple-low)
432
+ template="fast"
433
+ model="haiku"
434
+ max_iterations=2
435
+ agents=1
436
+ ;;
437
+ simple-*|moderate-low)
438
+ template="standard"
439
+ model="sonnet"
440
+ max_iterations=5
441
+ agents=2
442
+ ;;
443
+ moderate-*|complex-low)
444
+ template="standard"
445
+ model="sonnet"
446
+ max_iterations=8
447
+ agents=3
448
+ ;;
449
+ complex-*|epic-*)
450
+ template="full"
451
+ model="opus"
452
+ max_iterations=15
453
+ agents=4
454
+ ;;
455
+ *)
456
+ template="standard"
457
+ model="sonnet"
458
+ max_iterations=5
459
+ agents=2
460
+ ;;
461
+ esac
462
+ fi
440
463
 
441
464
  cat << EOF
442
465
  {
@@ -448,12 +471,13 @@ cmd_team() {
448
471
  "pipeline_template": "$template",
449
472
  "model": "$model",
450
473
  "max_iterations": $max_iterations,
451
- "agents": $agents
474
+ "agents": $agents,
475
+ "source": "$recruit_source"
452
476
  }
453
477
  }
454
478
  EOF
455
479
 
456
- emit_event "triage_team_recommended" "issue=$issue" "template=$template" "agents=$agents"
480
+ emit_event "triage_team_recommended" "issue=$issue" "template=$template" "agents=$agents" "source=$recruit_source"
457
481
  }
458
482
 
459
483
  # ─── Subcommand: batch ────────────────────────────────────────────────────
@@ -2,7 +2,7 @@
2
2
  # ╔═══════════════════════════════════════════════════════════════════════════╗
3
3
  # ║ sw upgrade — Detect and apply updates from the repo ║
4
4
  # ╚═══════════════════════════════════════════════════════════════════════════╝
5
- VERSION="2.0.0"
5
+ VERSION="2.1.1"
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
package/scripts/sw-ux.sh CHANGED
@@ -6,7 +6,7 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="2.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
@@ -58,7 +58,7 @@ UX_CONFIG_REPO="./.claude/ux-config.json"
58
58
 
59
59
  # Detect accessibility modes
60
60
  should_disable_colors() {
61
- [[ -n "${NO_COLOR:-}" ]] || [[ -n "${CLICOLOR_FORCE:-}" && "$CLICOLOR_FORCE" == "0" ]]
61
+ [[ -n "${NO_COLOR:-}" ]] || [[ "${FORCE_COLOR:-}" == "0" ]] || [[ -n "${CLICOLOR_FORCE:-}" && "$CLICOLOR_FORCE" == "0" ]]
62
62
  }
63
63
 
64
64
  has_reduced_motion() {
@@ -408,11 +408,36 @@ set_reduced_motion() {
408
408
  enable_screen_reader_mode() {
409
409
  # Disable colors and animations for screen reader compatibility
410
410
  export NO_COLOR=1
411
+ export FORCE_COLOR=0
411
412
  export PREFERS_REDUCED_MOTION=1
413
+
414
+ # Propagate to tmux global environment so new panes inherit
415
+ if [[ -n "${TMUX:-}" ]]; then
416
+ tmux set-environment -g NO_COLOR 1
417
+ tmux set-environment -g FORCE_COLOR 0
418
+ tmux set-environment -g PREFERS_REDUCED_MOTION 1
419
+ fi
420
+
412
421
  success "Screen reader mode enabled (colors and animations disabled)"
413
422
  emit_event "ux_accessibility" "feature=screen_reader"
414
423
  }
415
424
 
425
+ disable_screen_reader_mode() {
426
+ unset NO_COLOR
427
+ unset FORCE_COLOR
428
+ unset PREFERS_REDUCED_MOTION
429
+
430
+ # Remove from tmux global environment
431
+ if [[ -n "${TMUX:-}" ]]; then
432
+ tmux set-environment -g -u NO_COLOR 2>/dev/null || true
433
+ tmux set-environment -g -u FORCE_COLOR 2>/dev/null || true
434
+ tmux set-environment -g -u PREFERS_REDUCED_MOTION 2>/dev/null || true
435
+ fi
436
+
437
+ success "Screen reader mode disabled (colors and animations restored)"
438
+ emit_event "ux_accessibility" "feature=screen_reader_disabled"
439
+ }
440
+
416
441
  # ─── Formatting Helpers ───────────────────────────────────────────────────
417
442
  format_diff_line() {
418
443
  local line="$1"
@@ -648,6 +673,9 @@ main() {
648
673
  --screen-reader)
649
674
  enable_screen_reader_mode
650
675
  ;;
676
+ --no-screen-reader)
677
+ disable_screen_reader_mode
678
+ ;;
651
679
  *)
652
680
  error "Unknown accessibility option: $1"
653
681
  exit 1
@@ -6,7 +6,7 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="2.0.0"
9
+ VERSION="2.1.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
@@ -8,7 +8,7 @@
8
8
  set -euo pipefail
9
9
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
10
10
 
11
- VERSION="2.0.0"
11
+ VERSION="2.1.1"
12
12
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
13
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
14
14
 
@@ -5,7 +5,7 @@
5
5
  # ║ Each agent gets its own worktree so parallel agents don't clobber ║
6
6
  # ║ each other's files. Worktrees live in .worktrees/ relative to root. ║
7
7
  # ╚═══════════════════════════════════════════════════════════════════════════╝
8
- VERSION="2.0.0"
8
+ VERSION="2.1.1"
9
9
  set -euo pipefail
10
10
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
11
11