shipwright-cli 2.0.0 → 2.1.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/README.md +160 -72
- package/completions/_shipwright +59 -7
- package/completions/shipwright.bash +24 -4
- package/completions/shipwright.fish +80 -2
- package/dashboard/server.ts +208 -0
- package/docs/tmux-research/TMUX-ARCHITECTURE.md +567 -0
- package/docs/tmux-research/TMUX-AUDIT.md +925 -0
- package/docs/tmux-research/TMUX-BEST-PRACTICES-2025-2026.md +829 -0
- package/docs/tmux-research/TMUX-QUICK-REFERENCE.md +543 -0
- package/docs/tmux-research/TMUX-RESEARCH-INDEX.md +438 -0
- package/package.json +2 -2
- package/scripts/lib/helpers.sh +7 -0
- package/scripts/sw +116 -2
- package/scripts/sw-activity.sh +1 -1
- package/scripts/sw-adaptive.sh +1 -1
- package/scripts/sw-adversarial.sh +1 -1
- package/scripts/sw-architecture-enforcer.sh +1 -1
- package/scripts/sw-auth.sh +1 -1
- package/scripts/sw-autonomous.sh +128 -38
- package/scripts/sw-changelog.sh +1 -1
- package/scripts/sw-checkpoint.sh +1 -1
- package/scripts/sw-ci.sh +1 -1
- package/scripts/sw-cleanup.sh +1 -1
- package/scripts/sw-code-review.sh +62 -1
- package/scripts/sw-connect.sh +1 -1
- package/scripts/sw-context.sh +1 -1
- package/scripts/sw-cost.sh +44 -3
- package/scripts/sw-daemon.sh +155 -27
- package/scripts/sw-dashboard.sh +1 -1
- package/scripts/sw-db.sh +958 -118
- package/scripts/sw-decompose.sh +1 -1
- package/scripts/sw-deps.sh +1 -1
- package/scripts/sw-developer-simulation.sh +1 -1
- package/scripts/sw-discovery.sh +1 -1
- package/scripts/sw-docs-agent.sh +1 -1
- package/scripts/sw-docs.sh +1 -1
- package/scripts/sw-doctor.sh +49 -1
- package/scripts/sw-dora.sh +1 -1
- package/scripts/sw-durable.sh +1 -1
- package/scripts/sw-e2e-orchestrator.sh +1 -1
- package/scripts/sw-eventbus.sh +1 -1
- package/scripts/sw-feedback.sh +23 -15
- package/scripts/sw-fix.sh +1 -1
- package/scripts/sw-fleet-discover.sh +1 -1
- package/scripts/sw-fleet-viz.sh +1 -1
- package/scripts/sw-fleet.sh +1 -1
- package/scripts/sw-github-app.sh +1 -1
- package/scripts/sw-github-checks.sh +4 -4
- package/scripts/sw-github-deploy.sh +1 -1
- package/scripts/sw-github-graphql.sh +1 -1
- package/scripts/sw-guild.sh +1 -1
- package/scripts/sw-heartbeat.sh +1 -1
- package/scripts/sw-hygiene.sh +1 -1
- package/scripts/sw-incident.sh +45 -6
- package/scripts/sw-init.sh +150 -24
- package/scripts/sw-instrument.sh +1 -1
- package/scripts/sw-intelligence.sh +1 -1
- package/scripts/sw-jira.sh +1 -1
- package/scripts/sw-launchd.sh +1 -1
- package/scripts/sw-linear.sh +1 -1
- package/scripts/sw-logs.sh +1 -1
- package/scripts/sw-loop.sh +204 -19
- package/scripts/sw-memory.sh +18 -1
- package/scripts/sw-mission-control.sh +1 -1
- package/scripts/sw-model-router.sh +1 -1
- package/scripts/sw-otel.sh +1 -1
- package/scripts/sw-oversight.sh +76 -1
- package/scripts/sw-pipeline-composer.sh +1 -1
- package/scripts/sw-pipeline-vitals.sh +1 -1
- package/scripts/sw-pipeline.sh +261 -12
- package/scripts/sw-pm.sh +70 -5
- package/scripts/sw-pr-lifecycle.sh +1 -1
- package/scripts/sw-predictive.sh +8 -1
- package/scripts/sw-prep.sh +1 -1
- package/scripts/sw-ps.sh +1 -1
- package/scripts/sw-public-dashboard.sh +1 -1
- package/scripts/sw-quality.sh +1 -1
- package/scripts/sw-reaper.sh +1 -1
- package/scripts/sw-recruit.sh +1853 -178
- package/scripts/sw-regression.sh +1 -1
- package/scripts/sw-release-manager.sh +1 -1
- package/scripts/sw-release.sh +1 -1
- package/scripts/sw-remote.sh +1 -1
- package/scripts/sw-replay.sh +1 -1
- package/scripts/sw-retro.sh +1 -1
- package/scripts/sw-scale.sh +1 -1
- package/scripts/sw-security-audit.sh +1 -1
- package/scripts/sw-self-optimize.sh +1 -1
- package/scripts/sw-session.sh +1 -1
- package/scripts/sw-setup.sh +263 -127
- package/scripts/sw-standup.sh +1 -1
- package/scripts/sw-status.sh +44 -2
- package/scripts/sw-strategic.sh +189 -41
- package/scripts/sw-stream.sh +1 -1
- package/scripts/sw-swarm.sh +42 -5
- package/scripts/sw-team-stages.sh +1 -1
- package/scripts/sw-templates.sh +4 -4
- package/scripts/sw-testgen.sh +66 -15
- package/scripts/sw-tmux-pipeline.sh +1 -1
- package/scripts/sw-tmux-role-color.sh +58 -0
- package/scripts/sw-tmux-status.sh +128 -0
- package/scripts/sw-tmux.sh +1 -1
- package/scripts/sw-trace.sh +1 -1
- package/scripts/sw-tracker.sh +1 -1
- package/scripts/sw-triage.sh +61 -37
- package/scripts/sw-upgrade.sh +1 -1
- package/scripts/sw-ux.sh +1 -1
- package/scripts/sw-webhook.sh +1 -1
- package/scripts/sw-widgets.sh +1 -1
- package/scripts/sw-worktree.sh +1 -1
- package/templates/pipelines/autonomous.json +2 -2
- package/tmux/shipwright-overlay.conf +35 -17
- package/tmux/tmux.conf +23 -21
package/scripts/sw-testgen.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="1.
|
|
9
|
+
VERSION="2.1.0"
|
|
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
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
|
|
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
|
-
}
|
|
296
|
+
} >> "$test_template_file"
|
|
246
297
|
|
|
247
298
|
chmod +x "$test_template_file"
|
|
248
299
|
success "Generated test template: $test_template_file"
|
|
249
|
-
info "
|
|
300
|
+
[[ "$use_claude" == "true" ]] && info "Used Claude for assertions; review and run tests to validate"
|
|
250
301
|
}
|
|
251
302
|
|
|
252
303
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -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
|
package/scripts/sw-tmux.sh
CHANGED
|
@@ -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.
|
|
14
|
+
VERSION="2.1.0"
|
|
15
15
|
set -euo pipefail
|
|
16
16
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
17
17
|
|
package/scripts/sw-trace.sh
CHANGED
package/scripts/sw-tracker.sh
CHANGED
package/scripts/sw-triage.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.
|
|
9
|
+
VERSION="2.1.0"
|
|
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
|
-
#
|
|
407
|
-
local template model max_iterations agents
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
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 ────────────────────────────────────────────────────
|
package/scripts/sw-upgrade.sh
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# ╔═══════════════════════════════════════════════════════════════════════════╗
|
|
3
3
|
# ║ sw upgrade — Detect and apply updates from the repo ║
|
|
4
4
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
5
|
-
VERSION="2.
|
|
5
|
+
VERSION="2.1.0"
|
|
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.
|
|
9
|
+
VERSION="2.1.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
|
package/scripts/sw-webhook.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.
|
|
9
|
+
VERSION="2.1.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
|
package/scripts/sw-widgets.sh
CHANGED
package/scripts/sw-worktree.sh
CHANGED
|
@@ -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.
|
|
8
|
+
VERSION="2.1.0"
|
|
9
9
|
set -euo pipefail
|
|
10
10
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
11
11
|
|
|
@@ -27,9 +27,10 @@
|
|
|
27
27
|
set -g pane-border-status top
|
|
28
28
|
|
|
29
29
|
# Format: pane index, agent name, running command, zoom indicator
|
|
30
|
-
# Active pane
|
|
30
|
+
# Active pane: bold + bright │ Inactive: muted, recessed
|
|
31
31
|
# Uses #{pane_title} which each agent sets via OSC 2 escape sequence
|
|
32
|
-
|
|
32
|
+
# The ● dot gives a visual "alive" indicator on the active pane
|
|
33
|
+
set -g pane-border-format "#{?pane_active,#[fg=#00d4ff]#[bold] ● #P │ #{pane_title} #[fg=#52525b]│#[fg=#a1a1aa] #{pane_current_command}#{?window_zoomed_flag, #[fg=#facc15]#[bold]⊞ FOCUS,},#[fg=#52525b] #P │ #[fg=#71717a]#{pane_title} #[fg=#333355]│ #[fg=#52525b]#{pane_current_command}}"
|
|
33
34
|
|
|
34
35
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
35
36
|
# LAYOUT — Optimize for multi-agent pane layouts
|
|
@@ -40,19 +41,35 @@ set -g pane-border-format "#{?pane_active,#[fg=#00d4ff]#[bold],#[fg=#71717a]} #P
|
|
|
40
41
|
setw -g aggressive-resize on
|
|
41
42
|
|
|
42
43
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
43
|
-
# DARK THEME
|
|
44
|
+
# DARK THEME — Active pane gets a subtle background lift
|
|
44
45
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
# Inactive panes: deep navy, dimmed text — recedes visually
|
|
47
|
+
# Active pane: subtle bg lift, softer warm gray text — easy on the eyes
|
|
48
|
+
# NOTE: Claude Code renders its own colors for TUI elements. These fg values
|
|
49
|
+
# only affect plain terminal output (shell prompts, command output, etc.)
|
|
50
|
+
# The bg lift (#1a1a2e → #1e1e36) gives the active pane a "floating" feel.
|
|
51
|
+
set -g window-style 'bg=#1a1a2e,fg=#8888a0'
|
|
52
|
+
set -g window-active-style 'bg=#1e1e36,fg=#b4b4c8'
|
|
49
53
|
|
|
50
|
-
# Hooks
|
|
51
|
-
#
|
|
52
|
-
|
|
53
|
-
set-hook -g after-
|
|
54
|
-
set-hook -g after-new-
|
|
55
|
-
|
|
54
|
+
# Hooks: set pane colors on creation to prevent white flash.
|
|
55
|
+
# New panes start with inactive colors; active pane lift applies automatically.
|
|
56
|
+
set-hook -g after-split-window "select-pane -P 'bg=#1a1a2e,fg=#8888a0'"
|
|
57
|
+
set-hook -g after-new-window "select-pane -P 'bg=#1a1a2e,fg=#8888a0'"
|
|
58
|
+
set-hook -g after-new-session "select-pane -P 'bg=#1a1a2e,fg=#8888a0'"
|
|
59
|
+
|
|
60
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
61
|
+
# ROLE-COLORED BORDERS — Active pane border reflects agent role
|
|
62
|
+
# ═══════════════════════════════════════════════════════════════════════════
|
|
63
|
+
# When you switch panes, a hook reads the pane title and sets the active
|
|
64
|
+
# border color to match the agent's role:
|
|
65
|
+
# leader/pm → cyan (#00d4ff) builder/dev → blue (#0066ff)
|
|
66
|
+
# reviewer → orange (#f97316) tester → yellow (#facc15)
|
|
67
|
+
# security → red (#ef4444) docs → violet (#a78bfa)
|
|
68
|
+
# optimizer → green (#4ade80) researcher → purple (#7c3aed)
|
|
69
|
+
#
|
|
70
|
+
# The hook script must exist; -q makes source-file silent if missing.
|
|
71
|
+
# Falls back to cyan for non-agent panes (plain shell, vim, etc.)
|
|
72
|
+
set-hook -g pane-focus-in "run-shell -b 'bash ~/.shipwright/scripts/sw-tmux-role-color.sh 2>/dev/null || true'"
|
|
56
73
|
|
|
57
74
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
58
75
|
# SAFETY — Confirm before killing agent panes
|
|
@@ -88,13 +105,14 @@ bind M-t setw synchronize-panes \; display-message "Team sync #{?synchronize-pan
|
|
|
88
105
|
bind M-l next-layout
|
|
89
106
|
|
|
90
107
|
# prefix + M-s → capture current pane's full scrollback to file
|
|
91
|
-
bind M-s run-shell "tmux capture-pane -pS - > /tmp/claude-pane-#{pane_title}
|
|
108
|
+
bind M-s run-shell "tmux capture-pane -pS - > /tmp/claude-pane-#{pane_title}-\$(date +%%s).txt && tmux display-message 'Captured #{pane_title} to /tmp/'"
|
|
92
109
|
|
|
93
110
|
# prefix + M-a → capture ALL panes in current window (full scrollback each)
|
|
111
|
+
# NOTE: All $() must be escaped as \$() so they run at keypress time, not config load
|
|
94
112
|
bind M-a run-shell "\
|
|
95
|
-
for pane_id in
|
|
96
|
-
title
|
|
97
|
-
tmux capture-pane -t \$pane_id -pS - > /tmp/claude-pane-\${title:-\$pane_id}
|
|
113
|
+
for pane_id in \$(tmux list-panes -F '#{pane_id}'); do \
|
|
114
|
+
title=\$(tmux display-message -t \$pane_id -p '#{pane_title}'); \
|
|
115
|
+
tmux capture-pane -t \$pane_id -pS - > /tmp/claude-pane-\${title:-\$pane_id}-\$(date +%%s).txt; \
|
|
98
116
|
done && tmux display-message 'Captured all panes to /tmp/'"
|
|
99
117
|
|
|
100
118
|
# ═══════════════════════════════════════════════════════════════════════════
|