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,573 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ╔═══════════════════════════════════════════════════════════════════════════╗
|
|
3
|
+
# ║ sw-recruit.sh — Agent Recruitment & Talent Management System ║
|
|
4
|
+
# ║ ║
|
|
5
|
+
# ║ Role definitions · Skill matching · Performance evaluation · Team ║
|
|
6
|
+
# ║ composition recommendations · Agent promotion/demotion based on metrics ║
|
|
7
|
+
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
10
|
+
|
|
11
|
+
VERSION="2.0.0"
|
|
12
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
|
+
|
|
14
|
+
# ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
|
|
15
|
+
CYAN='\033[38;2;0;212;255m' # #00d4ff — primary accent
|
|
16
|
+
PURPLE='\033[38;2;124;58;237m' # #7c3aed — secondary
|
|
17
|
+
BLUE='\033[38;2;0;102;255m' # #0066ff — tertiary
|
|
18
|
+
GREEN='\033[38;2;74;222;128m' # success
|
|
19
|
+
YELLOW='\033[38;2;250;204;21m' # warning
|
|
20
|
+
RED='\033[38;2;248;113;113m' # error
|
|
21
|
+
DIM='\033[2m'
|
|
22
|
+
BOLD='\033[1m'
|
|
23
|
+
RESET='\033[0m'
|
|
24
|
+
|
|
25
|
+
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
|
26
|
+
# shellcheck source=lib/compat.sh
|
|
27
|
+
[[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
|
|
28
|
+
|
|
29
|
+
# ─── Output Helpers ─────────────────────────────────────────────────────────
|
|
30
|
+
info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
|
|
31
|
+
success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
|
|
32
|
+
warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
|
|
33
|
+
error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
|
|
34
|
+
|
|
35
|
+
now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
|
|
36
|
+
now_epoch() { date +%s; }
|
|
37
|
+
|
|
38
|
+
# ─── Structured Event Log ──────────────────────────────────────────────────
|
|
39
|
+
EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
|
|
40
|
+
|
|
41
|
+
emit_event() {
|
|
42
|
+
local event_type="$1"
|
|
43
|
+
shift
|
|
44
|
+
local json_fields=""
|
|
45
|
+
for kv in "$@"; do
|
|
46
|
+
local key="${kv%%=*}"
|
|
47
|
+
local val="${kv#*=}"
|
|
48
|
+
if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
|
|
49
|
+
json_fields="${json_fields},\"${key}\":${val}"
|
|
50
|
+
else
|
|
51
|
+
val="${val//\"/\\\"}"
|
|
52
|
+
json_fields="${json_fields},\"${key}\":\"${val}\""
|
|
53
|
+
fi
|
|
54
|
+
done
|
|
55
|
+
mkdir -p "${HOME}/.shipwright"
|
|
56
|
+
echo "{\"ts\":\"$(now_iso)\",\"ts_epoch\":$(now_epoch),\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# ─── Recruitment Storage Paths ─────────────────────────────────────────────
|
|
60
|
+
RECRUIT_ROOT="${HOME}/.shipwright/recruitment"
|
|
61
|
+
ROLES_DB="${RECRUIT_ROOT}/roles.json"
|
|
62
|
+
PROFILES_DB="${RECRUIT_ROOT}/profiles.json"
|
|
63
|
+
TALENT_DB="${RECRUIT_ROOT}/talent.json"
|
|
64
|
+
ONBOARDING_DB="${RECRUIT_ROOT}/onboarding.json"
|
|
65
|
+
|
|
66
|
+
ensure_recruit_dir() {
|
|
67
|
+
mkdir -p "$RECRUIT_ROOT"
|
|
68
|
+
[[ -f "$ROLES_DB" ]] || echo '{}' > "$ROLES_DB"
|
|
69
|
+
[[ -f "$PROFILES_DB" ]] || echo '{}' > "$PROFILES_DB"
|
|
70
|
+
[[ -f "$TALENT_DB" ]] || echo '[]' > "$TALENT_DB"
|
|
71
|
+
[[ -f "$ONBOARDING_DB" ]] || echo '{}' > "$ONBOARDING_DB"
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# ─── Built-in Role Definitions ────────────────────────────────────────────
|
|
75
|
+
initialize_builtin_roles() {
|
|
76
|
+
ensure_recruit_dir
|
|
77
|
+
|
|
78
|
+
# Check if roles already initialized
|
|
79
|
+
if jq -e '.architect' "$ROLES_DB" &>/dev/null 2>&1; then
|
|
80
|
+
return 0
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
local roles_json=$(cat <<'EOF'
|
|
84
|
+
{
|
|
85
|
+
"architect": {
|
|
86
|
+
"title": "Architect",
|
|
87
|
+
"description": "System design, architecture decisions, scalability planning",
|
|
88
|
+
"required_skills": ["system-design", "technology-evaluation", "code-review", "documentation"],
|
|
89
|
+
"recommended_model": "opus",
|
|
90
|
+
"context_needs": ["codebase-architecture", "system-patterns", "past-designs", "dependency-graph"],
|
|
91
|
+
"success_metrics": ["design-quality", "implementation-feasibility", "team-alignment"],
|
|
92
|
+
"estimated_cost_per_task_usd": 2.5
|
|
93
|
+
},
|
|
94
|
+
"builder": {
|
|
95
|
+
"title": "Builder",
|
|
96
|
+
"description": "Feature implementation, core development, code generation",
|
|
97
|
+
"required_skills": ["coding", "testing", "debugging", "performance-optimization"],
|
|
98
|
+
"recommended_model": "sonnet",
|
|
99
|
+
"context_needs": ["codebase-structure", "api-specs", "test-patterns", "build-system"],
|
|
100
|
+
"success_metrics": ["tests-passing", "code-quality", "productivity", "bug-rate"],
|
|
101
|
+
"estimated_cost_per_task_usd": 1.5
|
|
102
|
+
},
|
|
103
|
+
"reviewer": {
|
|
104
|
+
"title": "Code Reviewer",
|
|
105
|
+
"description": "Code review, quality assurance, best practices enforcement",
|
|
106
|
+
"required_skills": ["code-review", "static-analysis", "security-review", "best-practices"],
|
|
107
|
+
"recommended_model": "sonnet",
|
|
108
|
+
"context_needs": ["coding-standards", "previous-reviews", "common-errors", "team-patterns"],
|
|
109
|
+
"success_metrics": ["review-quality", "issue-detection-rate", "feedback-clarity"],
|
|
110
|
+
"estimated_cost_per_task_usd": 1.2
|
|
111
|
+
},
|
|
112
|
+
"tester": {
|
|
113
|
+
"title": "Test Specialist",
|
|
114
|
+
"description": "Test strategy, test case generation, test automation, quality validation",
|
|
115
|
+
"required_skills": ["testing", "coverage-analysis", "automation", "edge-case-detection"],
|
|
116
|
+
"recommended_model": "sonnet",
|
|
117
|
+
"context_needs": ["test-framework", "coverage-metrics", "failure-patterns", "requirements"],
|
|
118
|
+
"success_metrics": ["coverage-increase", "bug-detection", "test-execution-time"],
|
|
119
|
+
"estimated_cost_per_task_usd": 1.2
|
|
120
|
+
},
|
|
121
|
+
"security-auditor": {
|
|
122
|
+
"title": "Security Auditor",
|
|
123
|
+
"description": "Security analysis, vulnerability detection, compliance verification",
|
|
124
|
+
"required_skills": ["security-analysis", "threat-modeling", "penetration-testing", "compliance"],
|
|
125
|
+
"recommended_model": "opus",
|
|
126
|
+
"context_needs": ["security-policies", "vulnerability-database", "threat-models", "compliance-reqs"],
|
|
127
|
+
"success_metrics": ["vulnerabilities-found", "severity-accuracy", "remediation-quality"],
|
|
128
|
+
"estimated_cost_per_task_usd": 2.0
|
|
129
|
+
},
|
|
130
|
+
"docs-writer": {
|
|
131
|
+
"title": "Documentation Writer",
|
|
132
|
+
"description": "Documentation creation, API docs, user guides, onboarding materials",
|
|
133
|
+
"required_skills": ["documentation", "clarity", "completeness", "example-generation"],
|
|
134
|
+
"recommended_model": "haiku",
|
|
135
|
+
"context_needs": ["codebase-knowledge", "api-specs", "user-personas", "doc-templates"],
|
|
136
|
+
"success_metrics": ["documentation-completeness", "clarity-score", "example-coverage"],
|
|
137
|
+
"estimated_cost_per_task_usd": 0.8
|
|
138
|
+
},
|
|
139
|
+
"optimizer": {
|
|
140
|
+
"title": "Performance Optimizer",
|
|
141
|
+
"description": "Performance analysis, optimization, profiling, efficiency improvements",
|
|
142
|
+
"required_skills": ["performance-analysis", "profiling", "optimization", "metrics-analysis"],
|
|
143
|
+
"recommended_model": "sonnet",
|
|
144
|
+
"context_needs": ["performance-benchmarks", "profiling-tools", "optimization-history"],
|
|
145
|
+
"success_metrics": ["performance-gain", "memory-efficiency", "latency-reduction"],
|
|
146
|
+
"estimated_cost_per_task_usd": 1.5
|
|
147
|
+
},
|
|
148
|
+
"devops": {
|
|
149
|
+
"title": "DevOps Engineer",
|
|
150
|
+
"description": "Infrastructure, deployment pipelines, CI/CD, monitoring, reliability",
|
|
151
|
+
"required_skills": ["infrastructure-as-code", "deployment", "monitoring", "incident-response"],
|
|
152
|
+
"recommended_model": "sonnet",
|
|
153
|
+
"context_needs": ["infrastructure-config", "deployment-pipelines", "monitoring-setup", "runbooks"],
|
|
154
|
+
"success_metrics": ["deployment-success-rate", "incident-response-time", "uptime"],
|
|
155
|
+
"estimated_cost_per_task_usd": 1.8
|
|
156
|
+
},
|
|
157
|
+
"pm": {
|
|
158
|
+
"title": "Project Manager",
|
|
159
|
+
"description": "Task decomposition, priority management, stakeholder communication, tracking",
|
|
160
|
+
"required_skills": ["task-decomposition", "prioritization", "communication", "planning"],
|
|
161
|
+
"recommended_model": "sonnet",
|
|
162
|
+
"context_needs": ["project-state", "requirements", "team-capacity", "past-estimates"],
|
|
163
|
+
"success_metrics": ["estimation-accuracy", "deadline-met", "scope-management"],
|
|
164
|
+
"estimated_cost_per_task_usd": 1.0
|
|
165
|
+
},
|
|
166
|
+
"incident-responder": {
|
|
167
|
+
"title": "Incident Responder",
|
|
168
|
+
"description": "Crisis management, root cause analysis, rapid issue resolution, hotfixes",
|
|
169
|
+
"required_skills": ["crisis-management", "root-cause-analysis", "debugging", "communication"],
|
|
170
|
+
"recommended_model": "opus",
|
|
171
|
+
"context_needs": ["incident-history", "system-health", "alerting-rules", "past-incidents"],
|
|
172
|
+
"success_metrics": ["incident-resolution-time", "accuracy", "escalation-prevention"],
|
|
173
|
+
"estimated_cost_per_task_usd": 2.0
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
EOF
|
|
177
|
+
)
|
|
178
|
+
echo "$roles_json" | jq '.' > "$ROLES_DB"
|
|
179
|
+
success "Initialized 10 built-in agent roles"
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
# ─── Command Implementations ───────────────────────────────────────────────
|
|
183
|
+
|
|
184
|
+
cmd_roles() {
|
|
185
|
+
ensure_recruit_dir
|
|
186
|
+
initialize_builtin_roles
|
|
187
|
+
|
|
188
|
+
info "Available Agent Roles:"
|
|
189
|
+
echo ""
|
|
190
|
+
|
|
191
|
+
jq -r 'to_entries | .[] |
|
|
192
|
+
"\(.key): \(.value.title) — \(.value.description)\n Model: \(.value.recommended_model) | Cost: $\(.value.estimated_cost_per_task_usd)/task\n Skills: \(.value.required_skills | join(", "))\n"' \
|
|
193
|
+
"$ROLES_DB"
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
cmd_match() {
|
|
197
|
+
local task_description="${1:-}"
|
|
198
|
+
|
|
199
|
+
if [[ -z "$task_description" ]]; then
|
|
200
|
+
error "Usage: shipwright recruit match \"<task description>\""
|
|
201
|
+
exit 1
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
ensure_recruit_dir
|
|
205
|
+
initialize_builtin_roles
|
|
206
|
+
|
|
207
|
+
info "Analyzing task: ${CYAN}${task_description}${RESET}"
|
|
208
|
+
echo ""
|
|
209
|
+
|
|
210
|
+
# Simple keyword-based matching (can be enhanced with Claude)
|
|
211
|
+
local detected_skills=""
|
|
212
|
+
|
|
213
|
+
[[ "$task_description" =~ (architecture|design|scalability) ]] && detected_skills="${detected_skills}architect "
|
|
214
|
+
[[ "$task_description" =~ (build|feature|implement|code) ]] && detected_skills="${detected_skills}builder "
|
|
215
|
+
[[ "$task_description" =~ (review|quality|best.practice) ]] && detected_skills="${detected_skills}reviewer "
|
|
216
|
+
[[ "$task_description" =~ (test|coverage|automation) ]] && detected_skills="${detected_skills}tester "
|
|
217
|
+
[[ "$task_description" =~ (security|vulnerability|compliance) ]] && detected_skills="${detected_skills}security-auditor "
|
|
218
|
+
[[ "$task_description" =~ (doc|guide|readme) ]] && detected_skills="${detected_skills}docs-writer "
|
|
219
|
+
[[ "$task_description" =~ (performance|optimization|profile) ]] && detected_skills="${detected_skills}optimizer "
|
|
220
|
+
[[ "$task_description" =~ (deploy|infra|ci.cd|monitoring) ]] && detected_skills="${detected_skills}devops "
|
|
221
|
+
[[ "$task_description" =~ (plan|decompose|estimate|priorit) ]] && detected_skills="${detected_skills}pm "
|
|
222
|
+
[[ "$task_description" =~ (urgent|incident|crisis|hotfix) ]] && detected_skills="${detected_skills}incident-responder "
|
|
223
|
+
|
|
224
|
+
# Default to builder if no match
|
|
225
|
+
if [[ -z "$detected_skills" ]]; then
|
|
226
|
+
detected_skills="builder"
|
|
227
|
+
fi
|
|
228
|
+
|
|
229
|
+
# Show top recommendations
|
|
230
|
+
local primary_role
|
|
231
|
+
primary_role=$(echo "$detected_skills" | awk '{print $1}')
|
|
232
|
+
|
|
233
|
+
success "Recommended role: ${CYAN}${primary_role}${RESET}"
|
|
234
|
+
echo ""
|
|
235
|
+
|
|
236
|
+
local role_info
|
|
237
|
+
role_info=$(jq ".\"${primary_role}\"" "$ROLES_DB")
|
|
238
|
+
echo " $(echo "$role_info" | jq -r '.description')"
|
|
239
|
+
echo " Model: $(echo "$role_info" | jq -r '.recommended_model')"
|
|
240
|
+
echo " Skills: $(echo "$role_info" | jq -r '.required_skills | join(", ")')"
|
|
241
|
+
|
|
242
|
+
if [[ "$(echo "$detected_skills" | wc -w)" -gt 1 ]]; then
|
|
243
|
+
echo ""
|
|
244
|
+
warn "Secondary roles detected: $(echo "$detected_skills" | cut -d' ' -f2-)"
|
|
245
|
+
fi
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
cmd_evaluate() {
|
|
249
|
+
local agent_id="${1:-}"
|
|
250
|
+
|
|
251
|
+
if [[ -z "$agent_id" ]]; then
|
|
252
|
+
error "Usage: shipwright recruit evaluate <agent-id>"
|
|
253
|
+
exit 1
|
|
254
|
+
fi
|
|
255
|
+
|
|
256
|
+
ensure_recruit_dir
|
|
257
|
+
|
|
258
|
+
info "Evaluating agent: ${CYAN}${agent_id}${RESET}"
|
|
259
|
+
echo ""
|
|
260
|
+
|
|
261
|
+
# Get agent profile
|
|
262
|
+
local profile
|
|
263
|
+
profile=$(jq ".\"${agent_id}\"" "$PROFILES_DB" 2>/dev/null || echo "{}")
|
|
264
|
+
|
|
265
|
+
if [[ "$profile" == "{}" ]]; then
|
|
266
|
+
warn "No evaluation history for ${agent_id}"
|
|
267
|
+
return 0
|
|
268
|
+
fi
|
|
269
|
+
|
|
270
|
+
echo "Performance Metrics:"
|
|
271
|
+
echo " Success Rate: $(echo "$profile" | jq -r '.success_rate // "N/A"')%"
|
|
272
|
+
echo " Avg Time: $(echo "$profile" | jq -r '.avg_time_minutes // "N/A"') minutes"
|
|
273
|
+
echo " Quality Score: $(echo "$profile" | jq -r '.quality_score // "N/A"')/10"
|
|
274
|
+
echo " Cost Efficiency: $(echo "$profile" | jq -r '.cost_efficiency // "N/A"')%"
|
|
275
|
+
echo " Tasks Completed: $(echo "$profile" | jq -r '.tasks_completed // "0"')"
|
|
276
|
+
echo ""
|
|
277
|
+
|
|
278
|
+
# Recommendation
|
|
279
|
+
local success_rate
|
|
280
|
+
success_rate=$(echo "$profile" | jq -r '.success_rate // 0')
|
|
281
|
+
|
|
282
|
+
if (( $(echo "$success_rate < 70" | bc -l 2>/dev/null || echo "1") )); then
|
|
283
|
+
warn "Performance below threshold. Consider downgrading or retraining."
|
|
284
|
+
elif (( $(echo "$success_rate >= 90" | bc -l 2>/dev/null || echo "0") )); then
|
|
285
|
+
success "Excellent performance. Consider for promotion."
|
|
286
|
+
else
|
|
287
|
+
success "Acceptable performance. Continue current assignment."
|
|
288
|
+
fi
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
cmd_team() {
|
|
292
|
+
local issue_or_project="${1:-}"
|
|
293
|
+
|
|
294
|
+
if [[ -z "$issue_or_project" ]]; then
|
|
295
|
+
error "Usage: shipwright recruit team <issue|project>"
|
|
296
|
+
exit 1
|
|
297
|
+
fi
|
|
298
|
+
|
|
299
|
+
ensure_recruit_dir
|
|
300
|
+
initialize_builtin_roles
|
|
301
|
+
|
|
302
|
+
info "Recommending team composition for: ${CYAN}${issue_or_project}${RESET}"
|
|
303
|
+
echo ""
|
|
304
|
+
|
|
305
|
+
# Default recommendation: builder + reviewer + tester
|
|
306
|
+
local recommended_team=("builder" "reviewer" "tester")
|
|
307
|
+
|
|
308
|
+
# Add security auditor for security-related issues
|
|
309
|
+
if echo "$issue_or_project" | grep -qiE "security|vulnerability|compliance"; then
|
|
310
|
+
recommended_team+=("security-auditor")
|
|
311
|
+
fi
|
|
312
|
+
|
|
313
|
+
# Add architect for design issues
|
|
314
|
+
if echo "$issue_or_project" | grep -qiE "architecture|design|refactor"; then
|
|
315
|
+
recommended_team+=("architect")
|
|
316
|
+
fi
|
|
317
|
+
|
|
318
|
+
success "Recommended Team Composition (${#recommended_team[@]} members):"
|
|
319
|
+
echo ""
|
|
320
|
+
|
|
321
|
+
for role in "${recommended_team[@]}"; do
|
|
322
|
+
local role_info
|
|
323
|
+
role_info=$(jq ".\"${role}\"" "$ROLES_DB")
|
|
324
|
+
printf " • ${CYAN}%-20s${RESET} (${PURPLE}%s${RESET}) — %s\n" \
|
|
325
|
+
"$role" \
|
|
326
|
+
"$(echo "$role_info" | jq -r '.recommended_model')" \
|
|
327
|
+
"$(echo "$role_info" | jq -r '.title')"
|
|
328
|
+
done
|
|
329
|
+
|
|
330
|
+
echo ""
|
|
331
|
+
local total_cost
|
|
332
|
+
total_cost=$(printf "%.2f" $(
|
|
333
|
+
for role in "${recommended_team[@]}"; do
|
|
334
|
+
jq ".\"${role}\".estimated_cost_per_task_usd" "$ROLES_DB"
|
|
335
|
+
done | awk '{sum+=$1} END {print sum}'
|
|
336
|
+
))
|
|
337
|
+
echo "Estimated Team Cost: \$${total_cost}/task"
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
cmd_profiles() {
|
|
341
|
+
ensure_recruit_dir
|
|
342
|
+
|
|
343
|
+
info "Agent Performance Profiles:"
|
|
344
|
+
echo ""
|
|
345
|
+
|
|
346
|
+
if [[ ! -s "$PROFILES_DB" || "$(jq 'length' "$PROFILES_DB" 2>/dev/null || echo 0)" -eq 0 ]]; then
|
|
347
|
+
warn "No performance profiles recorded yet"
|
|
348
|
+
return 0
|
|
349
|
+
fi
|
|
350
|
+
|
|
351
|
+
jq -r 'to_entries | .[] |
|
|
352
|
+
"\(.key):\n Success: \(.value.success_rate // "N/A")% | Quality: \(.value.quality_score // "N/A")/10 | Tasks: \(.value.tasks_completed // 0)\n Avg Time: \(.value.avg_time_minutes // "N/A")min | Efficiency: \(.value.cost_efficiency // "N/A")%\n"' \
|
|
353
|
+
"$PROFILES_DB"
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
cmd_promote() {
|
|
357
|
+
local agent_id="${1:-}"
|
|
358
|
+
|
|
359
|
+
if [[ -z "$agent_id" ]]; then
|
|
360
|
+
error "Usage: shipwright recruit promote <agent-id>"
|
|
361
|
+
exit 1
|
|
362
|
+
fi
|
|
363
|
+
|
|
364
|
+
ensure_recruit_dir
|
|
365
|
+
|
|
366
|
+
info "Evaluating promotion eligibility for: ${CYAN}${agent_id}${RESET}"
|
|
367
|
+
echo ""
|
|
368
|
+
|
|
369
|
+
local profile
|
|
370
|
+
profile=$(jq ".\"${agent_id}\"" "$PROFILES_DB" 2>/dev/null || echo "{}")
|
|
371
|
+
|
|
372
|
+
if [[ "$profile" == "{}" ]]; then
|
|
373
|
+
warn "No profile found for ${agent_id}"
|
|
374
|
+
return 1
|
|
375
|
+
fi
|
|
376
|
+
|
|
377
|
+
local success_rate quality_score
|
|
378
|
+
success_rate=$(echo "$profile" | jq -r '.success_rate // 0')
|
|
379
|
+
quality_score=$(echo "$profile" | jq -r '.quality_score // 0')
|
|
380
|
+
|
|
381
|
+
local current_model
|
|
382
|
+
current_model=$(echo "$profile" | jq -r '.model // "haiku"')
|
|
383
|
+
|
|
384
|
+
local recommended_model="$current_model"
|
|
385
|
+
local promotion_reason=""
|
|
386
|
+
|
|
387
|
+
if (( $(echo "$success_rate >= 95 && $quality_score >= 9" | bc -l 2>/dev/null || echo "0") )); then
|
|
388
|
+
case "$current_model" in
|
|
389
|
+
haiku) recommended_model="sonnet"; promotion_reason="Excellent performance on Haiku" ;;
|
|
390
|
+
sonnet) recommended_model="opus"; promotion_reason="Outstanding results on Sonnet" ;;
|
|
391
|
+
opus) promotion_reason="Already on best model"; recommended_model="opus" ;;
|
|
392
|
+
esac
|
|
393
|
+
elif (( $(echo "$success_rate < 60 || $quality_score < 5" | bc -l 2>/dev/null || echo "0") )); then
|
|
394
|
+
case "$current_model" in
|
|
395
|
+
opus) recommended_model="sonnet"; promotion_reason="Struggling on Opus, try Sonnet" ;;
|
|
396
|
+
sonnet) recommended_model="haiku"; promotion_reason="Poor performance, reduce cost" ;;
|
|
397
|
+
haiku) promotion_reason="Consider retraining"; recommended_model="haiku" ;;
|
|
398
|
+
esac
|
|
399
|
+
fi
|
|
400
|
+
|
|
401
|
+
if [[ "$recommended_model" != "$current_model" ]]; then
|
|
402
|
+
success "Recommend upgrading from ${CYAN}${current_model}${RESET} to ${PURPLE}${recommended_model}${RESET}"
|
|
403
|
+
echo " Reason: $promotion_reason"
|
|
404
|
+
emit_event "recruit_promotion" "agent_id=${agent_id}" "from=${current_model}" "to=${recommended_model}" "reason=${promotion_reason}"
|
|
405
|
+
else
|
|
406
|
+
info "No model change recommended for ${agent_id}"
|
|
407
|
+
echo " Current: ${current_model} | Success: ${success_rate}% | Quality: ${quality_score}/10"
|
|
408
|
+
fi
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
cmd_onboard() {
|
|
412
|
+
local agent_role="${1:-builder}"
|
|
413
|
+
|
|
414
|
+
ensure_recruit_dir
|
|
415
|
+
initialize_builtin_roles
|
|
416
|
+
|
|
417
|
+
info "Generating onboarding context for: ${CYAN}${agent_role}${RESET}"
|
|
418
|
+
echo ""
|
|
419
|
+
|
|
420
|
+
local role_info
|
|
421
|
+
role_info=$(jq ".${agent_role}" "$ROLES_DB" 2>/dev/null)
|
|
422
|
+
|
|
423
|
+
if [[ -z "$role_info" || "$role_info" == "null" ]]; then
|
|
424
|
+
error "Unknown role: ${agent_role}"
|
|
425
|
+
exit 1
|
|
426
|
+
fi
|
|
427
|
+
|
|
428
|
+
# Create onboarding document
|
|
429
|
+
local onboarding_doc=$(cat <<EOF
|
|
430
|
+
# Onboarding Context: ${agent_role}
|
|
431
|
+
|
|
432
|
+
## Role Profile
|
|
433
|
+
**Title:** $(echo "$role_info" | jq -r '.title')
|
|
434
|
+
**Description:** $(echo "$role_info" | jq -r '.description')
|
|
435
|
+
**Recommended Model:** $(echo "$role_info" | jq -r '.recommended_model')
|
|
436
|
+
|
|
437
|
+
## Required Skills
|
|
438
|
+
$(echo "$role_info" | jq -r '.required_skills[]' | sed 's/^/- /')
|
|
439
|
+
|
|
440
|
+
## Context Needs
|
|
441
|
+
$(echo "$role_info" | jq -r '.context_needs[]' | sed 's/^/- /')
|
|
442
|
+
|
|
443
|
+
## Success Metrics
|
|
444
|
+
$(echo "$role_info" | jq -r '.success_metrics[]' | sed 's/^/- /')
|
|
445
|
+
|
|
446
|
+
## Cost Profile
|
|
447
|
+
Estimated cost per task: \$$(echo "$role_info" | jq -r '.estimated_cost_per_task_usd')
|
|
448
|
+
|
|
449
|
+
## Getting Started
|
|
450
|
+
1. Review the role profile above
|
|
451
|
+
2. Study the codebase architecture
|
|
452
|
+
3. Familiarize yourself with coding standards
|
|
453
|
+
4. Review past pipeline runs for patterns
|
|
454
|
+
5. Ask questions about unclear requirements
|
|
455
|
+
|
|
456
|
+
## Resources
|
|
457
|
+
- Codebase: /path/to/repo
|
|
458
|
+
- Documentation: See .claude/ directory
|
|
459
|
+
- Team patterns: Reviewed in memory system
|
|
460
|
+
- Past learnings: Available in ~/.shipwright/memory/
|
|
461
|
+
EOF
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
# Save to onboarding DB
|
|
465
|
+
local onboarding_key=$(date +%s)
|
|
466
|
+
jq --arg key "$onboarding_key" --arg doc "$onboarding_doc" '.[$key] = $doc' "$ONBOARDING_DB" > "${ONBOARDING_DB}.tmp"
|
|
467
|
+
mv "${ONBOARDING_DB}.tmp" "$ONBOARDING_DB"
|
|
468
|
+
|
|
469
|
+
success "Onboarding context generated for ${agent_role}"
|
|
470
|
+
echo ""
|
|
471
|
+
echo "$onboarding_doc"
|
|
472
|
+
emit_event "recruit_onboarding" "role=${agent_role}" "timestamp=$(now_epoch)"
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
cmd_stats() {
|
|
476
|
+
ensure_recruit_dir
|
|
477
|
+
|
|
478
|
+
info "Recruitment Statistics & Talent Trends:"
|
|
479
|
+
echo ""
|
|
480
|
+
|
|
481
|
+
# Count roles
|
|
482
|
+
local role_count
|
|
483
|
+
role_count=$(jq 'length' "$ROLES_DB" 2>/dev/null || echo 0)
|
|
484
|
+
|
|
485
|
+
# Count profiles
|
|
486
|
+
local profile_count
|
|
487
|
+
profile_count=$(jq 'length' "$PROFILES_DB" 2>/dev/null || echo 0)
|
|
488
|
+
|
|
489
|
+
# Count talent entries
|
|
490
|
+
local talent_count
|
|
491
|
+
talent_count=$(jq 'length' "$TALENT_DB" 2>/dev/null || echo 0)
|
|
492
|
+
|
|
493
|
+
echo " Roles Defined: $role_count"
|
|
494
|
+
echo " Agents Profiled: $profile_count"
|
|
495
|
+
echo " Talent Records: $talent_count"
|
|
496
|
+
echo ""
|
|
497
|
+
|
|
498
|
+
# Average metrics
|
|
499
|
+
if [[ "$profile_count" -gt 0 ]]; then
|
|
500
|
+
local avg_success
|
|
501
|
+
avg_success=$(jq '[.[].success_rate // 0] | add / length' "$PROFILES_DB" 2>/dev/null || echo "0")
|
|
502
|
+
|
|
503
|
+
local avg_quality
|
|
504
|
+
avg_quality=$(jq '[.[].quality_score // 0] | add / length' "$PROFILES_DB" 2>/dev/null || echo "0")
|
|
505
|
+
|
|
506
|
+
echo " Avg Success Rate: ${avg_success}%"
|
|
507
|
+
echo " Avg Quality Score: ${avg_quality}/10"
|
|
508
|
+
echo ""
|
|
509
|
+
fi
|
|
510
|
+
|
|
511
|
+
success "Use 'shipwright recruit profiles' for detailed breakdown"
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
cmd_help() {
|
|
515
|
+
cat <<EOF
|
|
516
|
+
${BOLD}${CYAN}shipwright recruit${RESET} — Agent Recruitment & Talent Management
|
|
517
|
+
|
|
518
|
+
${BOLD}USAGE${RESET}
|
|
519
|
+
${CYAN}shipwright recruit${RESET} <command> [options]
|
|
520
|
+
|
|
521
|
+
${BOLD}COMMANDS${RESET}
|
|
522
|
+
${CYAN}roles${RESET} List all available agent roles and skill requirements
|
|
523
|
+
${CYAN}match${RESET} "<task>" Analyze task and recommend best agent role
|
|
524
|
+
${CYAN}evaluate${RESET} <id> Score an agent's recent performance
|
|
525
|
+
${CYAN}team${RESET} "<issue>" Recommend optimal team composition for an issue/project
|
|
526
|
+
${CYAN}profiles${RESET} Show performance profiles by agent type
|
|
527
|
+
${CYAN}promote${RESET} <id> Recommend model upgrades for agents (haiku→sonnet→opus)
|
|
528
|
+
${CYAN}onboard${RESET} <role> Generate onboarding context for a new agent
|
|
529
|
+
${CYAN}stats${RESET} Show recruitment statistics and talent trends
|
|
530
|
+
${CYAN}help${RESET} Show this help message
|
|
531
|
+
|
|
532
|
+
${BOLD}EXAMPLES${RESET}
|
|
533
|
+
${DIM}shipwright recruit roles${RESET}
|
|
534
|
+
${DIM}shipwright recruit match "Add authentication system"${RESET}
|
|
535
|
+
${DIM}shipwright recruit team issue-123${RESET}
|
|
536
|
+
${DIM}shipwright recruit evaluate agent-builder-001${RESET}
|
|
537
|
+
${DIM}shipwright recruit promote agent-builder-001${RESET}
|
|
538
|
+
${DIM}shipwright recruit onboard architect${RESET}
|
|
539
|
+
|
|
540
|
+
${BOLD}ROLE CATALOG${RESET}
|
|
541
|
+
Built-in roles: architect, builder, reviewer, tester, security-auditor,
|
|
542
|
+
docs-writer, optimizer, devops, pm, incident-responder
|
|
543
|
+
|
|
544
|
+
${DIM}Store: ~/.shipwright/recruitment/${RESET}
|
|
545
|
+
EOF
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
# ─── Main Router ──────────────────────────────────────────────────────────
|
|
549
|
+
|
|
550
|
+
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
|
551
|
+
ensure_recruit_dir
|
|
552
|
+
|
|
553
|
+
cmd="${1:-help}"
|
|
554
|
+
shift 2>/dev/null || true
|
|
555
|
+
|
|
556
|
+
case "$cmd" in
|
|
557
|
+
roles) cmd_roles ;;
|
|
558
|
+
match) cmd_match "$@" ;;
|
|
559
|
+
evaluate) cmd_evaluate "$@" ;;
|
|
560
|
+
team) cmd_team "$@" ;;
|
|
561
|
+
profiles) cmd_profiles ;;
|
|
562
|
+
promote) cmd_promote "$@" ;;
|
|
563
|
+
onboard) cmd_onboard "$@" ;;
|
|
564
|
+
stats) cmd_stats ;;
|
|
565
|
+
help|--help|-h) cmd_help ;;
|
|
566
|
+
*)
|
|
567
|
+
error "Unknown command: ${cmd}"
|
|
568
|
+
echo ""
|
|
569
|
+
cmd_help
|
|
570
|
+
exit 1
|
|
571
|
+
;;
|
|
572
|
+
esac
|
|
573
|
+
fi
|