shipwright-cli 1.10.0 → 2.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/README.md +114 -36
- package/completions/_shipwright +212 -32
- package/completions/shipwright.bash +97 -25
- package/docs/strategy/01-market-research.md +619 -0
- package/docs/strategy/02-mission-and-brand.md +587 -0
- package/docs/strategy/03-gtm-and-roadmap.md +759 -0
- package/docs/strategy/QUICK-START.txt +289 -0
- package/docs/strategy/README.md +172 -0
- package/package.json +4 -2
- package/scripts/sw +208 -1
- package/scripts/sw-activity.sh +500 -0
- package/scripts/sw-adaptive.sh +925 -0
- package/scripts/sw-adversarial.sh +1 -1
- package/scripts/sw-architecture-enforcer.sh +1 -1
- package/scripts/sw-auth.sh +613 -0
- package/scripts/sw-autonomous.sh +664 -0
- package/scripts/sw-changelog.sh +704 -0
- package/scripts/sw-checkpoint.sh +1 -1
- package/scripts/sw-ci.sh +602 -0
- package/scripts/sw-cleanup.sh +1 -1
- package/scripts/sw-code-review.sh +637 -0
- package/scripts/sw-connect.sh +1 -1
- package/scripts/sw-context.sh +605 -0
- package/scripts/sw-cost.sh +1 -1
- package/scripts/sw-daemon.sh +432 -130
- package/scripts/sw-dashboard.sh +1 -1
- package/scripts/sw-db.sh +540 -0
- package/scripts/sw-decompose.sh +539 -0
- package/scripts/sw-deps.sh +551 -0
- package/scripts/sw-developer-simulation.sh +1 -1
- package/scripts/sw-discovery.sh +412 -0
- package/scripts/sw-docs-agent.sh +539 -0
- package/scripts/sw-docs.sh +1 -1
- package/scripts/sw-doctor.sh +59 -1
- package/scripts/sw-dora.sh +615 -0
- package/scripts/sw-durable.sh +710 -0
- package/scripts/sw-e2e-orchestrator.sh +535 -0
- package/scripts/sw-eventbus.sh +393 -0
- package/scripts/sw-feedback.sh +471 -0
- package/scripts/sw-fix.sh +1 -1
- package/scripts/sw-fleet-discover.sh +567 -0
- package/scripts/sw-fleet-viz.sh +404 -0
- package/scripts/sw-fleet.sh +8 -1
- package/scripts/sw-github-app.sh +596 -0
- package/scripts/sw-github-checks.sh +1 -1
- package/scripts/sw-github-deploy.sh +1 -1
- package/scripts/sw-github-graphql.sh +1 -1
- package/scripts/sw-guild.sh +569 -0
- package/scripts/sw-heartbeat.sh +1 -1
- package/scripts/sw-hygiene.sh +559 -0
- package/scripts/sw-incident.sh +617 -0
- package/scripts/sw-init.sh +88 -1
- package/scripts/sw-instrument.sh +699 -0
- package/scripts/sw-intelligence.sh +1 -1
- package/scripts/sw-jira.sh +1 -1
- package/scripts/sw-launchd.sh +363 -28
- package/scripts/sw-linear.sh +1 -1
- package/scripts/sw-logs.sh +1 -1
- package/scripts/sw-loop.sh +64 -3
- package/scripts/sw-memory.sh +1 -1
- package/scripts/sw-mission-control.sh +487 -0
- package/scripts/sw-model-router.sh +545 -0
- package/scripts/sw-otel.sh +596 -0
- package/scripts/sw-oversight.sh +689 -0
- package/scripts/sw-pipeline-composer.sh +1 -1
- package/scripts/sw-pipeline-vitals.sh +1 -1
- package/scripts/sw-pipeline.sh +687 -24
- package/scripts/sw-pm.sh +693 -0
- package/scripts/sw-pr-lifecycle.sh +522 -0
- package/scripts/sw-predictive.sh +1 -1
- package/scripts/sw-prep.sh +1 -1
- package/scripts/sw-ps.sh +1 -1
- package/scripts/sw-public-dashboard.sh +798 -0
- package/scripts/sw-quality.sh +595 -0
- package/scripts/sw-reaper.sh +1 -1
- package/scripts/sw-recruit.sh +573 -0
- package/scripts/sw-regression.sh +642 -0
- package/scripts/sw-release-manager.sh +736 -0
- package/scripts/sw-release.sh +706 -0
- package/scripts/sw-remote.sh +1 -1
- package/scripts/sw-replay.sh +520 -0
- package/scripts/sw-retro.sh +691 -0
- package/scripts/sw-scale.sh +444 -0
- package/scripts/sw-security-audit.sh +505 -0
- package/scripts/sw-self-optimize.sh +1 -1
- package/scripts/sw-session.sh +1 -1
- package/scripts/sw-setup.sh +1 -1
- package/scripts/sw-standup.sh +712 -0
- package/scripts/sw-status.sh +1 -1
- package/scripts/sw-strategic.sh +658 -0
- package/scripts/sw-stream.sh +450 -0
- package/scripts/sw-swarm.sh +583 -0
- package/scripts/sw-team-stages.sh +511 -0
- package/scripts/sw-templates.sh +1 -1
- package/scripts/sw-testgen.sh +515 -0
- package/scripts/sw-tmux-pipeline.sh +554 -0
- package/scripts/sw-tmux.sh +1 -1
- package/scripts/sw-trace.sh +485 -0
- package/scripts/sw-tracker-github.sh +188 -0
- package/scripts/sw-tracker-jira.sh +172 -0
- package/scripts/sw-tracker-linear.sh +251 -0
- package/scripts/sw-tracker.sh +117 -2
- package/scripts/sw-triage.sh +603 -0
- package/scripts/sw-upgrade.sh +1 -1
- package/scripts/sw-ux.sh +677 -0
- package/scripts/sw-webhook.sh +627 -0
- package/scripts/sw-widgets.sh +530 -0
- package/scripts/sw-worktree.sh +1 -1
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ╔═══════════════════════════════════════════════════════════════════════════╗
|
|
3
|
+
# ║ shipwright team-stages — Multi-agent execution with leader/specialist roles ║
|
|
4
|
+
# ║ Decompose stages into parallel tasks · Consensus voting · Result aggregation║
|
|
5
|
+
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
|
+
|
|
9
|
+
VERSION="2.0.0"
|
|
10
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
|
+
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
|
+
|
|
13
|
+
# ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
|
|
14
|
+
CYAN='\033[38;2;0;212;255m' # #00d4ff — primary accent
|
|
15
|
+
PURPLE='\033[38;2;124;58;237m' # #7c3aed — secondary
|
|
16
|
+
BLUE='\033[38;2;0;102;255m' # #0066ff — tertiary
|
|
17
|
+
GREEN='\033[38;2;74;222;128m' # success
|
|
18
|
+
YELLOW='\033[38;2;250;204;21m' # warning
|
|
19
|
+
RED='\033[38;2;248;113;113m' # error
|
|
20
|
+
DIM='\033[2m'
|
|
21
|
+
BOLD='\033[1m'
|
|
22
|
+
RESET='\033[0m'
|
|
23
|
+
|
|
24
|
+
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
|
25
|
+
# shellcheck source=lib/compat.sh
|
|
26
|
+
[[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
|
|
27
|
+
|
|
28
|
+
# ─── Output Helpers ─────────────────────────────────────────────────────────
|
|
29
|
+
info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
|
|
30
|
+
success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
|
|
31
|
+
warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
|
|
32
|
+
error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
|
|
33
|
+
|
|
34
|
+
now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
|
|
35
|
+
now_epoch() { date +%s; }
|
|
36
|
+
|
|
37
|
+
# ─── Structured Event Log ──────────────────────────────────────────────────
|
|
38
|
+
EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
|
|
39
|
+
|
|
40
|
+
emit_event() {
|
|
41
|
+
local event_type="$1"
|
|
42
|
+
shift
|
|
43
|
+
local json_fields=""
|
|
44
|
+
for kv in "$@"; do
|
|
45
|
+
local key="${kv%%=*}"
|
|
46
|
+
local val="${kv#*=}"
|
|
47
|
+
if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
|
|
48
|
+
json_fields="${json_fields},\"${key}\":${val}"
|
|
49
|
+
else
|
|
50
|
+
val="${val//\"/\\\"}"
|
|
51
|
+
json_fields="${json_fields},\"${key}\":\"${val}\""
|
|
52
|
+
fi
|
|
53
|
+
done
|
|
54
|
+
mkdir -p "${HOME}/.shipwright"
|
|
55
|
+
echo "{\"ts\":\"$(now_iso)\",\"ts_epoch\":$(now_epoch),\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# ─── Team Configuration ─────────────────────────────────────────────────────
|
|
59
|
+
TEAM_STATE_DIR="${HOME}/.shipwright/team-state"
|
|
60
|
+
INTELLIGENCE_CACHE="${REPO_DIR}/.claude/intelligence-cache.json"
|
|
61
|
+
|
|
62
|
+
ensure_team_dir() {
|
|
63
|
+
mkdir -p "$TEAM_STATE_DIR"
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# ─── Role Definitions ───────────────────────────────────────────────────────
|
|
67
|
+
# Each role has a prompt injection template that guides the agent's focus
|
|
68
|
+
|
|
69
|
+
declare_role() {
|
|
70
|
+
local role="$1"
|
|
71
|
+
case "$role" in
|
|
72
|
+
builder)
|
|
73
|
+
echo "Implementation specialist — focuses on code quality, architecture, patterns"
|
|
74
|
+
;;
|
|
75
|
+
reviewer)
|
|
76
|
+
echo "Code reviewer — validates correctness, design, performance, security"
|
|
77
|
+
;;
|
|
78
|
+
tester)
|
|
79
|
+
echo "Test specialist — writes tests, validates coverage, detects edge cases"
|
|
80
|
+
;;
|
|
81
|
+
security)
|
|
82
|
+
echo "Security engineer — scans for vulns, auth issues, injection risks"
|
|
83
|
+
;;
|
|
84
|
+
docs)
|
|
85
|
+
echo "Documentation specialist — API docs, examples, type definitions"
|
|
86
|
+
;;
|
|
87
|
+
*)
|
|
88
|
+
echo "$role — specialist agent"
|
|
89
|
+
;;
|
|
90
|
+
esac
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
# ─── Compose: Generate team for a stage ─────────────────────────────────────
|
|
94
|
+
cmd_compose() {
|
|
95
|
+
local stage="${1:-build}"
|
|
96
|
+
local complexity="${2:-medium}"
|
|
97
|
+
|
|
98
|
+
ensure_team_dir
|
|
99
|
+
|
|
100
|
+
local team_json
|
|
101
|
+
local leader="lead-agent"
|
|
102
|
+
local specialists=""
|
|
103
|
+
|
|
104
|
+
case "$stage" in
|
|
105
|
+
build)
|
|
106
|
+
specialists="builder builder reviewer"
|
|
107
|
+
;;
|
|
108
|
+
test)
|
|
109
|
+
specialists="tester tester security"
|
|
110
|
+
;;
|
|
111
|
+
review)
|
|
112
|
+
specialists="reviewer reviewer security"
|
|
113
|
+
;;
|
|
114
|
+
*)
|
|
115
|
+
specialists="builder reviewer tester"
|
|
116
|
+
;;
|
|
117
|
+
esac
|
|
118
|
+
|
|
119
|
+
# Count specialists
|
|
120
|
+
local spec_count
|
|
121
|
+
spec_count=$(echo "$specialists" | wc -w)
|
|
122
|
+
|
|
123
|
+
team_json=$(jq -n \
|
|
124
|
+
--arg stage "$stage" \
|
|
125
|
+
--arg complexity "$complexity" \
|
|
126
|
+
--arg leader "$leader" \
|
|
127
|
+
--argjson spec_count "$spec_count" \
|
|
128
|
+
--arg specialists "$specialists" \
|
|
129
|
+
'{
|
|
130
|
+
stage: $stage,
|
|
131
|
+
complexity: $complexity,
|
|
132
|
+
created_at: "'$(now_iso)'",
|
|
133
|
+
leader: $leader,
|
|
134
|
+
specialists: ($specialists | split(" ")),
|
|
135
|
+
specialist_count: $spec_count,
|
|
136
|
+
status: "pending"
|
|
137
|
+
}')
|
|
138
|
+
|
|
139
|
+
echo "$team_json"
|
|
140
|
+
|
|
141
|
+
emit_event "team_composed" \
|
|
142
|
+
"stage=$stage" \
|
|
143
|
+
"complexity=$complexity" \
|
|
144
|
+
"specialist_count=$spec_count"
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
# ─── Delegate: Break stage into agent tasks with file assignments ───────────
|
|
148
|
+
cmd_delegate() {
|
|
149
|
+
local stage="${1:-build}"
|
|
150
|
+
local complexity="${2:-medium}"
|
|
151
|
+
|
|
152
|
+
ensure_team_dir
|
|
153
|
+
|
|
154
|
+
local team_json
|
|
155
|
+
team_json=$(cmd_compose "$stage" "$complexity")
|
|
156
|
+
|
|
157
|
+
# Read hotspots from intelligence cache if available
|
|
158
|
+
local hotspots=""
|
|
159
|
+
if [[ -f "$INTELLIGENCE_CACHE" ]]; then
|
|
160
|
+
hotspots=$(jq -r '.hotspots[]? // empty' "$INTELLIGENCE_CACHE" 2>/dev/null | head -10 || true)
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
# Collect changed files for this stage
|
|
164
|
+
local changed_files=""
|
|
165
|
+
if git rev-parse HEAD >/dev/null 2>&1; then
|
|
166
|
+
changed_files=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || git ls-files || true)
|
|
167
|
+
fi
|
|
168
|
+
|
|
169
|
+
# Distribute files across specialists
|
|
170
|
+
local specialist_count
|
|
171
|
+
specialist_count=$(echo "$team_json" | jq -r '.specialist_count // 1')
|
|
172
|
+
|
|
173
|
+
local tasks="[]"
|
|
174
|
+
local file_count=0
|
|
175
|
+
|
|
176
|
+
# Assign files round-robin to specialists
|
|
177
|
+
while IFS= read -r file; do
|
|
178
|
+
[[ -z "$file" ]] && continue
|
|
179
|
+
local spec_idx=$((file_count % specialist_count))
|
|
180
|
+
local task_json
|
|
181
|
+
task_json=$(jq -n \
|
|
182
|
+
--arg file "$file" \
|
|
183
|
+
--arg spec_idx "$spec_idx" \
|
|
184
|
+
--arg status "pending" \
|
|
185
|
+
'{
|
|
186
|
+
file: $file,
|
|
187
|
+
specialist_idx: ($spec_idx | tonumber),
|
|
188
|
+
status: $status,
|
|
189
|
+
assigned_at: "'$(now_iso)'",
|
|
190
|
+
result: null
|
|
191
|
+
}')
|
|
192
|
+
tasks=$(echo "$tasks" | jq ". += [$task_json]")
|
|
193
|
+
((file_count++))
|
|
194
|
+
done < <(echo "$changed_files")
|
|
195
|
+
|
|
196
|
+
# Output delegation result
|
|
197
|
+
local result
|
|
198
|
+
result=$(echo "$team_json" | jq \
|
|
199
|
+
--argjson tasks "$tasks" \
|
|
200
|
+
--argjson file_count "$file_count" \
|
|
201
|
+
'.tasks = $tasks | .file_count = $file_count')
|
|
202
|
+
|
|
203
|
+
echo "$result"
|
|
204
|
+
|
|
205
|
+
emit_event "stage_delegated" \
|
|
206
|
+
"stage=$stage" \
|
|
207
|
+
"specialist_count=$specialist_count" \
|
|
208
|
+
"file_count=$file_count"
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
# ─── Status: Show team member status for active stage ───────────────────────
|
|
212
|
+
cmd_status() {
|
|
213
|
+
local stage="${1:-}"
|
|
214
|
+
|
|
215
|
+
ensure_team_dir
|
|
216
|
+
|
|
217
|
+
if [[ -z "$stage" ]]; then
|
|
218
|
+
# List all active teams
|
|
219
|
+
if [[ ! -d "$TEAM_STATE_DIR" ]] || [[ -z "$(ls -A "$TEAM_STATE_DIR" 2>/dev/null)" ]]; then
|
|
220
|
+
info "No active teams"
|
|
221
|
+
return 0
|
|
222
|
+
fi
|
|
223
|
+
|
|
224
|
+
for team_file in "$TEAM_STATE_DIR"/*.json; do
|
|
225
|
+
[[ -f "$team_file" ]] || continue
|
|
226
|
+
local ts
|
|
227
|
+
ts=$(stat -f %Bm "$team_file" 2>/dev/null || stat -c %Y "$team_file" 2>/dev/null || echo 0)
|
|
228
|
+
local name
|
|
229
|
+
name=$(basename "$team_file" .json)
|
|
230
|
+
local status
|
|
231
|
+
status=$(jq -r '.status // "unknown"' "$team_file" 2>/dev/null || echo "error")
|
|
232
|
+
printf " %-30s %-15s %-20s\n" "$name" "$status" "$(date -r "$ts" +'%Y-%m-%d %H:%M:%S' 2>/dev/null || echo 'unknown')"
|
|
233
|
+
done
|
|
234
|
+
return 0
|
|
235
|
+
fi
|
|
236
|
+
|
|
237
|
+
# Show details for specific stage
|
|
238
|
+
local team_file="$TEAM_STATE_DIR/${stage}.json"
|
|
239
|
+
if [[ ! -f "$team_file" ]]; then
|
|
240
|
+
error "No team state for stage: $stage"
|
|
241
|
+
exit 1
|
|
242
|
+
fi
|
|
243
|
+
|
|
244
|
+
local team_json
|
|
245
|
+
team_json=$(cat "$team_file")
|
|
246
|
+
|
|
247
|
+
# Display leader
|
|
248
|
+
local leader
|
|
249
|
+
leader=$(echo "$team_json" | jq -r '.leader // "unknown"')
|
|
250
|
+
echo ""
|
|
251
|
+
echo -e " ${BOLD}${CYAN}Stage:${RESET} $(echo "$team_json" | jq -r '.stage')"
|
|
252
|
+
echo -e " ${BOLD}${CYAN}Leader:${RESET} $leader"
|
|
253
|
+
echo -e " ${BOLD}${CYAN}Status:${RESET} $(echo "$team_json" | jq -r '.status // "unknown"')"
|
|
254
|
+
echo ""
|
|
255
|
+
|
|
256
|
+
# Display specialists
|
|
257
|
+
echo -e " ${BOLD}Specialists${RESET}"
|
|
258
|
+
local specs
|
|
259
|
+
specs=$(echo "$team_json" | jq -r '.specialists[]? // empty')
|
|
260
|
+
local spec_idx=0
|
|
261
|
+
while IFS= read -r spec; do
|
|
262
|
+
[[ -z "$spec" ]] && continue
|
|
263
|
+
local spec_status
|
|
264
|
+
spec_status=$(echo "$team_json" | jq -r ".specialist_status[$spec_idx] // \"pending\"" 2>/dev/null || echo "pending")
|
|
265
|
+
printf " ${DIM}%-3d${RESET} %-20s %-15s\n" "$((spec_idx + 1))" "$spec" "$spec_status"
|
|
266
|
+
((spec_idx++))
|
|
267
|
+
done < <(echo "$specs")
|
|
268
|
+
echo ""
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
# ─── Vote: Collect and tally review votes ──────────────────────────────────
|
|
272
|
+
cmd_vote() {
|
|
273
|
+
local stage="${1:-}"
|
|
274
|
+
local team_file="$TEAM_STATE_DIR/${stage}.json"
|
|
275
|
+
|
|
276
|
+
if [[ -z "$stage" ]]; then
|
|
277
|
+
error "Usage: shipwright team-stages vote <stage>"
|
|
278
|
+
exit 1
|
|
279
|
+
fi
|
|
280
|
+
|
|
281
|
+
if [[ ! -f "$team_file" ]]; then
|
|
282
|
+
error "No team state for stage: $stage"
|
|
283
|
+
exit 1
|
|
284
|
+
fi
|
|
285
|
+
|
|
286
|
+
local team_json
|
|
287
|
+
team_json=$(cat "$team_file")
|
|
288
|
+
|
|
289
|
+
# Collect verdicts from all specialists
|
|
290
|
+
local approve_count=0
|
|
291
|
+
local reject_count=0
|
|
292
|
+
local neutral_count=0
|
|
293
|
+
local total=0
|
|
294
|
+
|
|
295
|
+
local specs
|
|
296
|
+
specs=$(echo "$team_json" | jq -r '.specialists[]? // empty')
|
|
297
|
+
|
|
298
|
+
while IFS= read -r spec; do
|
|
299
|
+
[[ -z "$spec" ]] && continue
|
|
300
|
+
local verdict
|
|
301
|
+
verdict=$(echo "$team_json" | jq -r ".verdicts[\"$spec\"]? // \"neutral\"" 2>/dev/null || echo "neutral")
|
|
302
|
+
case "$verdict" in
|
|
303
|
+
approve) ((approve_count++)) ;;
|
|
304
|
+
reject) ((reject_count++)) ;;
|
|
305
|
+
*) ((neutral_count++)) ;;
|
|
306
|
+
esac
|
|
307
|
+
((total++))
|
|
308
|
+
done < <(echo "$specs")
|
|
309
|
+
|
|
310
|
+
# Consensus: majority vote with leader tiebreak
|
|
311
|
+
local consensus="neutral"
|
|
312
|
+
if [[ $approve_count -gt $reject_count ]]; then
|
|
313
|
+
consensus="approve"
|
|
314
|
+
elif [[ $reject_count -gt $approve_count ]]; then
|
|
315
|
+
consensus="reject"
|
|
316
|
+
elif [[ $approve_count -eq $reject_count ]] && [[ $approve_count -gt 0 ]]; then
|
|
317
|
+
# Tiebreak: check leader verdict
|
|
318
|
+
local leader_verdict
|
|
319
|
+
leader_verdict=$(echo "$team_json" | jq -r '.verdicts.leader? // "neutral"' 2>/dev/null || echo "neutral")
|
|
320
|
+
consensus="$leader_verdict"
|
|
321
|
+
fi
|
|
322
|
+
|
|
323
|
+
local result
|
|
324
|
+
result=$(jq -n \
|
|
325
|
+
--argjson approve_count "$approve_count" \
|
|
326
|
+
--argjson reject_count "$reject_count" \
|
|
327
|
+
--argjson neutral_count "$neutral_count" \
|
|
328
|
+
--argjson total "$total" \
|
|
329
|
+
--arg consensus "$consensus" \
|
|
330
|
+
'{
|
|
331
|
+
approve: $approve_count,
|
|
332
|
+
reject: $reject_count,
|
|
333
|
+
neutral: $neutral_count,
|
|
334
|
+
total: $total,
|
|
335
|
+
consensus: $consensus,
|
|
336
|
+
decided_at: "'$(now_iso)'"
|
|
337
|
+
}')
|
|
338
|
+
|
|
339
|
+
echo "$result"
|
|
340
|
+
|
|
341
|
+
emit_event "vote_tallied" \
|
|
342
|
+
"stage=$stage" \
|
|
343
|
+
"consensus=$consensus" \
|
|
344
|
+
"approve=$approve_count" \
|
|
345
|
+
"reject=$reject_count"
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
# ─── Aggregate: Combine outputs from all agents ──────────────────────────────
|
|
349
|
+
cmd_aggregate() {
|
|
350
|
+
local stage="${1:-}"
|
|
351
|
+
local team_file="$TEAM_STATE_DIR/${stage}.json"
|
|
352
|
+
|
|
353
|
+
if [[ -z "$stage" ]]; then
|
|
354
|
+
error "Usage: shipwright team-stages aggregate <stage>"
|
|
355
|
+
exit 1
|
|
356
|
+
fi
|
|
357
|
+
|
|
358
|
+
if [[ ! -f "$team_file" ]]; then
|
|
359
|
+
error "No team state for stage: $stage"
|
|
360
|
+
exit 1
|
|
361
|
+
fi
|
|
362
|
+
|
|
363
|
+
local team_json
|
|
364
|
+
team_json=$(cat "$team_file")
|
|
365
|
+
|
|
366
|
+
# Collect task results from all specialists
|
|
367
|
+
local results="[]"
|
|
368
|
+
local success_count=0
|
|
369
|
+
local failure_count=0
|
|
370
|
+
|
|
371
|
+
local tasks
|
|
372
|
+
tasks=$(echo "$team_json" | jq -r '.tasks[]? // empty' 2>/dev/null)
|
|
373
|
+
|
|
374
|
+
while IFS= read -r task_line; do
|
|
375
|
+
[[ -z "$task_line" ]] && continue
|
|
376
|
+
local result
|
|
377
|
+
result=$(echo "$task_line" | jq -r '.result? // empty' 2>/dev/null)
|
|
378
|
+
|
|
379
|
+
if [[ -n "$result" ]]; then
|
|
380
|
+
if echo "$result" | jq -e '.success' >/dev/null 2>&1; then
|
|
381
|
+
((success_count++))
|
|
382
|
+
else
|
|
383
|
+
((failure_count++))
|
|
384
|
+
fi
|
|
385
|
+
results=$(echo "$results" | jq ". += [$result]")
|
|
386
|
+
fi
|
|
387
|
+
done < <(echo "$tasks" | jq -c '.[]')
|
|
388
|
+
|
|
389
|
+
# Build aggregated output
|
|
390
|
+
local aggregated
|
|
391
|
+
aggregated=$(jq -n \
|
|
392
|
+
--arg stage "$stage" \
|
|
393
|
+
--argjson results "$results" \
|
|
394
|
+
--argjson success_count "$success_count" \
|
|
395
|
+
--argjson failure_count "$failure_count" \
|
|
396
|
+
'{
|
|
397
|
+
stage: $stage,
|
|
398
|
+
task_count: ($results | length),
|
|
399
|
+
success_count: $success_count,
|
|
400
|
+
failure_count: $failure_count,
|
|
401
|
+
success_rate: (if ($results | length) > 0 then ($success_count / ($results | length) * 100) | floor else 0 end),
|
|
402
|
+
results: $results,
|
|
403
|
+
aggregated_at: "'$(now_iso)'"
|
|
404
|
+
}')
|
|
405
|
+
|
|
406
|
+
echo "$aggregated"
|
|
407
|
+
|
|
408
|
+
emit_event "results_aggregated" \
|
|
409
|
+
"stage=$stage" \
|
|
410
|
+
"task_count=$(echo "$aggregated" | jq -r '.task_count')" \
|
|
411
|
+
"success_rate=$(echo "$aggregated" | jq -r '.success_rate')"
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
# ─── Roles: List available roles and their descriptions ──────────────────────
|
|
415
|
+
cmd_roles() {
|
|
416
|
+
echo ""
|
|
417
|
+
echo -e " ${BOLD}${CYAN}Available Roles${RESET}"
|
|
418
|
+
echo -e " ${DIM}═══════════════════════════════════════════════════════════${RESET}"
|
|
419
|
+
echo ""
|
|
420
|
+
echo -e " ${CYAN}builder${RESET}"
|
|
421
|
+
echo " $(declare_role builder)"
|
|
422
|
+
echo ""
|
|
423
|
+
echo -e " ${CYAN}reviewer${RESET}"
|
|
424
|
+
echo " $(declare_role reviewer)"
|
|
425
|
+
echo ""
|
|
426
|
+
echo -e " ${CYAN}tester${RESET}"
|
|
427
|
+
echo " $(declare_role tester)"
|
|
428
|
+
echo ""
|
|
429
|
+
echo -e " ${CYAN}security${RESET}"
|
|
430
|
+
echo " $(declare_role security)"
|
|
431
|
+
echo ""
|
|
432
|
+
echo -e " ${CYAN}docs${RESET}"
|
|
433
|
+
echo " $(declare_role docs)"
|
|
434
|
+
echo ""
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
# ─── Help ───────────────────────────────────────────────────────────────────
|
|
438
|
+
show_help() {
|
|
439
|
+
echo ""
|
|
440
|
+
echo -e " ${CYAN}${BOLD}Shipwright Team Stages${RESET} ${DIM}v${VERSION}${RESET}"
|
|
441
|
+
echo -e " ${DIM}════════════════════════════════════════════════${RESET}"
|
|
442
|
+
echo ""
|
|
443
|
+
echo -e " ${BOLD}USAGE${RESET}"
|
|
444
|
+
echo -e " shipwright team-stages <command> [options]"
|
|
445
|
+
echo ""
|
|
446
|
+
echo -e " ${BOLD}COMMANDS${RESET}"
|
|
447
|
+
echo -e " ${CYAN}compose${RESET} <stage> [complexity] Generate team for a stage"
|
|
448
|
+
echo -e " ${CYAN}delegate${RESET} <stage> [complexity] Break stage into agent tasks"
|
|
449
|
+
echo -e " ${CYAN}status${RESET} [stage] Show team member status"
|
|
450
|
+
echo -e " ${CYAN}vote${RESET} <stage> Collect and tally review votes"
|
|
451
|
+
echo -e " ${CYAN}aggregate${RESET} <stage> Combine agent outputs into stage result"
|
|
452
|
+
echo -e " ${CYAN}roles${RESET} List available roles and descriptions"
|
|
453
|
+
echo -e " ${CYAN}help${RESET} Show this help message"
|
|
454
|
+
echo ""
|
|
455
|
+
echo -e " ${BOLD}EXAMPLES${RESET}"
|
|
456
|
+
echo -e " ${DIM}# Compose a team for the build stage${RESET}"
|
|
457
|
+
echo -e " shipwright team-stages compose build medium"
|
|
458
|
+
echo ""
|
|
459
|
+
echo -e " ${DIM}# Delegate build stage into parallel tasks${RESET}"
|
|
460
|
+
echo -e " shipwright team-stages delegate build medium"
|
|
461
|
+
echo ""
|
|
462
|
+
echo -e " ${DIM}# Show status of all active teams${RESET}"
|
|
463
|
+
echo -e " shipwright team-stages status"
|
|
464
|
+
echo ""
|
|
465
|
+
echo -e " ${DIM}# Tally votes from review team${RESET}"
|
|
466
|
+
echo -e " shipwright team-stages vote review"
|
|
467
|
+
echo ""
|
|
468
|
+
echo -e " ${DIM}# Combine results from all agents${RESET}"
|
|
469
|
+
echo -e " shipwright team-stages aggregate build"
|
|
470
|
+
echo ""
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
# ─── Main ───────────────────────────────────────────────────────────────────
|
|
474
|
+
main() {
|
|
475
|
+
local cmd="${1:-help}"
|
|
476
|
+
shift 2>/dev/null || true
|
|
477
|
+
|
|
478
|
+
case "$cmd" in
|
|
479
|
+
compose)
|
|
480
|
+
cmd_compose "$@"
|
|
481
|
+
;;
|
|
482
|
+
delegate)
|
|
483
|
+
cmd_delegate "$@"
|
|
484
|
+
;;
|
|
485
|
+
status)
|
|
486
|
+
cmd_status "$@"
|
|
487
|
+
;;
|
|
488
|
+
vote)
|
|
489
|
+
cmd_vote "$@"
|
|
490
|
+
;;
|
|
491
|
+
aggregate)
|
|
492
|
+
cmd_aggregate "$@"
|
|
493
|
+
;;
|
|
494
|
+
roles)
|
|
495
|
+
cmd_roles
|
|
496
|
+
;;
|
|
497
|
+
help|--help|-h)
|
|
498
|
+
show_help
|
|
499
|
+
;;
|
|
500
|
+
*)
|
|
501
|
+
error "Unknown command: $cmd"
|
|
502
|
+
echo ""
|
|
503
|
+
show_help
|
|
504
|
+
exit 1
|
|
505
|
+
;;
|
|
506
|
+
esac
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
|
510
|
+
main "$@"
|
|
511
|
+
fi
|
package/scripts/sw-templates.sh
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# ║ Templates define reusable agent team configurations (roles, layout, ║
|
|
6
6
|
# ║ focus areas) that shipwright session --template can use to scaffold teams. ║
|
|
7
7
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
8
|
-
VERSION="
|
|
8
|
+
VERSION="2.0.0"
|
|
9
9
|
set -euo pipefail
|
|
10
10
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
11
11
|
|