shipwright-cli 2.1.2 → 2.2.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 (136) hide show
  1. package/.claude/agents/devops-engineer.md +14 -12
  2. package/.claude/agents/doc-fleet-agent.md +99 -0
  3. package/.claude/agents/test-specialist.md +5 -3
  4. package/README.md +48 -27
  5. package/claude-code/CLAUDE.md.shipwright +2 -2
  6. package/config/policy.json +73 -0
  7. package/config/policy.schema.json +150 -0
  8. package/docs/AGI-PLATFORM-PLAN.md +126 -0
  9. package/docs/AGI-WHATS-NEXT.md +72 -0
  10. package/docs/KNOWN-ISSUES.md +1 -23
  11. package/docs/PLATFORM-TODO-BACKLOG.md +41 -0
  12. package/docs/PLATFORM-TODO-TRIAGE.md +56 -0
  13. package/docs/README.md +83 -0
  14. package/docs/TIPS.md +39 -2
  15. package/docs/config-policy.md +40 -0
  16. package/docs/definition-of-done.example.md +2 -0
  17. package/docs/patterns/README.md +5 -0
  18. package/docs/strategy/02-mission-and-brand.md +3 -3
  19. package/docs/strategy/README.md +4 -3
  20. package/docs/tmux-research/TMUX-AUDIT.md +2 -0
  21. package/docs/tmux-research/TMUX-RESEARCH-INDEX.md +17 -0
  22. package/package.json +3 -2
  23. package/scripts/lib/daemon-health.sh +32 -0
  24. package/scripts/lib/helpers.sh +30 -1
  25. package/scripts/lib/pipeline-detection.sh +278 -0
  26. package/scripts/lib/pipeline-github.sh +196 -0
  27. package/scripts/lib/pipeline-intelligence.sh +1712 -0
  28. package/scripts/lib/pipeline-quality-checks.sh +1052 -0
  29. package/scripts/lib/pipeline-quality.sh +34 -0
  30. package/scripts/lib/pipeline-stages.sh +2488 -0
  31. package/scripts/lib/pipeline-state.sh +529 -0
  32. package/scripts/lib/policy.sh +32 -0
  33. package/scripts/sw +5 -1
  34. package/scripts/sw-activity.sh +35 -46
  35. package/scripts/sw-adaptive.sh +30 -39
  36. package/scripts/sw-adversarial.sh +30 -36
  37. package/scripts/sw-architecture-enforcer.sh +30 -33
  38. package/scripts/sw-auth.sh +30 -42
  39. package/scripts/sw-autonomous.sh +60 -40
  40. package/scripts/sw-changelog.sh +29 -30
  41. package/scripts/sw-checkpoint.sh +30 -18
  42. package/scripts/sw-ci.sh +30 -42
  43. package/scripts/sw-cleanup.sh +32 -15
  44. package/scripts/sw-code-review.sh +26 -32
  45. package/scripts/sw-connect.sh +30 -19
  46. package/scripts/sw-context.sh +30 -19
  47. package/scripts/sw-cost.sh +30 -40
  48. package/scripts/sw-daemon.sh +66 -36
  49. package/scripts/sw-dashboard.sh +31 -40
  50. package/scripts/sw-db.sh +30 -20
  51. package/scripts/sw-decompose.sh +30 -38
  52. package/scripts/sw-deps.sh +30 -41
  53. package/scripts/sw-developer-simulation.sh +30 -36
  54. package/scripts/sw-discovery.sh +36 -19
  55. package/scripts/sw-doc-fleet.sh +822 -0
  56. package/scripts/sw-docs-agent.sh +30 -36
  57. package/scripts/sw-docs.sh +29 -31
  58. package/scripts/sw-doctor.sh +52 -20
  59. package/scripts/sw-dora.sh +29 -34
  60. package/scripts/sw-durable.sh +30 -20
  61. package/scripts/sw-e2e-orchestrator.sh +36 -21
  62. package/scripts/sw-eventbus.sh +30 -17
  63. package/scripts/sw-feedback.sh +30 -41
  64. package/scripts/sw-fix.sh +30 -40
  65. package/scripts/sw-fleet-discover.sh +30 -41
  66. package/scripts/sw-fleet-viz.sh +30 -20
  67. package/scripts/sw-fleet.sh +30 -40
  68. package/scripts/sw-github-app.sh +30 -41
  69. package/scripts/sw-github-checks.sh +30 -41
  70. package/scripts/sw-github-deploy.sh +30 -41
  71. package/scripts/sw-github-graphql.sh +30 -38
  72. package/scripts/sw-guild.sh +30 -37
  73. package/scripts/sw-heartbeat.sh +30 -19
  74. package/scripts/sw-hygiene.sh +134 -42
  75. package/scripts/sw-incident.sh +30 -39
  76. package/scripts/sw-init.sh +31 -14
  77. package/scripts/sw-instrument.sh +30 -41
  78. package/scripts/sw-intelligence.sh +39 -44
  79. package/scripts/sw-jira.sh +31 -41
  80. package/scripts/sw-launchd.sh +30 -17
  81. package/scripts/sw-linear.sh +31 -41
  82. package/scripts/sw-logs.sh +32 -17
  83. package/scripts/sw-loop.sh +32 -19
  84. package/scripts/sw-memory.sh +32 -43
  85. package/scripts/sw-mission-control.sh +31 -40
  86. package/scripts/sw-model-router.sh +30 -20
  87. package/scripts/sw-otel.sh +30 -20
  88. package/scripts/sw-oversight.sh +30 -36
  89. package/scripts/sw-patrol-meta.sh +31 -0
  90. package/scripts/sw-pipeline-composer.sh +30 -39
  91. package/scripts/sw-pipeline-vitals.sh +30 -44
  92. package/scripts/sw-pipeline.sh +277 -6383
  93. package/scripts/sw-pm.sh +31 -41
  94. package/scripts/sw-pr-lifecycle.sh +30 -42
  95. package/scripts/sw-predictive.sh +32 -34
  96. package/scripts/sw-prep.sh +30 -19
  97. package/scripts/sw-ps.sh +32 -17
  98. package/scripts/sw-public-dashboard.sh +30 -40
  99. package/scripts/sw-quality.sh +42 -40
  100. package/scripts/sw-reaper.sh +32 -15
  101. package/scripts/sw-recruit.sh +428 -48
  102. package/scripts/sw-regression.sh +30 -38
  103. package/scripts/sw-release-manager.sh +30 -38
  104. package/scripts/sw-release.sh +29 -31
  105. package/scripts/sw-remote.sh +31 -40
  106. package/scripts/sw-replay.sh +30 -18
  107. package/scripts/sw-retro.sh +33 -42
  108. package/scripts/sw-scale.sh +41 -24
  109. package/scripts/sw-security-audit.sh +30 -20
  110. package/scripts/sw-self-optimize.sh +33 -37
  111. package/scripts/sw-session.sh +31 -15
  112. package/scripts/sw-setup.sh +30 -16
  113. package/scripts/sw-standup.sh +30 -20
  114. package/scripts/sw-status.sh +33 -13
  115. package/scripts/sw-strategic.sh +55 -43
  116. package/scripts/sw-stream.sh +33 -37
  117. package/scripts/sw-swarm.sh +30 -21
  118. package/scripts/sw-team-stages.sh +30 -38
  119. package/scripts/sw-templates.sh +31 -16
  120. package/scripts/sw-testgen.sh +30 -31
  121. package/scripts/sw-tmux-pipeline.sh +29 -31
  122. package/scripts/sw-tmux-role-color.sh +31 -0
  123. package/scripts/sw-tmux-status.sh +31 -0
  124. package/scripts/sw-tmux.sh +31 -15
  125. package/scripts/sw-trace.sh +30 -19
  126. package/scripts/sw-tracker-github.sh +31 -0
  127. package/scripts/sw-tracker-jira.sh +31 -0
  128. package/scripts/sw-tracker-linear.sh +31 -0
  129. package/scripts/sw-tracker.sh +30 -40
  130. package/scripts/sw-triage.sh +68 -61
  131. package/scripts/sw-upgrade.sh +30 -16
  132. package/scripts/sw-ux.sh +30 -35
  133. package/scripts/sw-webhook.sh +30 -25
  134. package/scripts/sw-widgets.sh +30 -19
  135. package/scripts/sw-worktree.sh +32 -15
  136. package/tmux/templates/doc-fleet.json +43 -0
@@ -6,29 +6,42 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="2.1.2"
9
+ VERSION="2.2.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
- # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
13
- CYAN='\033[38;2;0;212;255m' # #00d4ff — primary accent
14
- PURPLE='\033[38;2;124;58;237m' # #7c3aed — secondary
15
- BLUE='\033[38;2;0;102;255m' # #0066ff — tertiary
16
- GREEN='\033[38;2;74;222;128m' # success
17
- YELLOW='\033[38;2;250;204;21m' # warning
18
- RED='\033[38;2;248;113;113m' # error
19
- DIM='\033[2m'
20
- BOLD='\033[1m'
21
- RESET='\033[0m'
22
-
23
12
  # ─── Cross-platform compatibility ──────────────────────────────────────────
24
13
  # shellcheck source=lib/compat.sh
25
14
  [ -f "$SCRIPT_DIR/lib/compat.sh" ] && source "$SCRIPT_DIR/lib/compat.sh"
26
15
 
27
- # ─── Output Helpers ─────────────────────────────────────────────────────────
28
- info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
29
- success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
30
- warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
31
- error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
16
+ # Canonical helpers (colors, output, events)
17
+ # shellcheck source=lib/helpers.sh
18
+ [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
19
+ # Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
20
+ [[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
21
+ [[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
22
+ [[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
23
+ [[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
24
+ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
25
+ now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
26
+ now_epoch() { date +%s; }
27
+ fi
28
+ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
29
+ emit_event() {
30
+ local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
31
+ local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
32
+ while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
33
+ echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
34
+ }
35
+ fi
36
+ CYAN="${CYAN:-\033[38;2;0;212;255m}"
37
+ PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
38
+ BLUE="${BLUE:-\033[38;2;0;102;255m}"
39
+ GREEN="${GREEN:-\033[38;2;74;222;128m}"
40
+ YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
41
+ RED="${RED:-\033[38;2;248;113;113m}"
42
+ DIM="${DIM:-\033[2m}"
43
+ BOLD="${BOLD:-\033[1m}"
44
+ RESET="${RESET:-\033[0m}"
32
45
 
33
46
  # ─── Event File & Filters ─────────────────────────────────────────────────────
34
47
  EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
@@ -77,30 +90,6 @@ agent_color() {
77
90
  esac
78
91
  }
79
92
 
80
- # Emit structured event (for testing/logging)
81
- emit_event() {
82
- local event_type="$1"
83
- shift
84
- local json_fields=""
85
- for kv in "$@"; do
86
- local key="${kv%%=*}"
87
- local val="${kv#*=}"
88
- if echo "$val" | grep -qE '^-?[0-9]+\.?[0-9]*$'; then
89
- json_fields="${json_fields},\"${key}\":${val}"
90
- else
91
- local escaped_val
92
- escaped_val=$(printf '%s' "$val" | jq -Rs '.' 2>/dev/null || printf '"%s"' "${val//\"/\\\"}")
93
- json_fields="${json_fields},\"${key}\":${escaped_val}"
94
- fi
95
- done
96
- mkdir -p "${HOME}/.shipwright"
97
- local iso_time
98
- iso_time=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
99
- local epoch_time
100
- epoch_time=$(date +%s)
101
- echo "{\"ts\":\"${iso_time}\",\"ts_epoch\":${epoch_time},\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
102
- }
103
-
104
93
  # ─── Formatting Helpers ────────────────────────────────────────────────────────
105
94
  format_timestamp() {
106
95
  local ts="$1"
@@ -162,7 +151,7 @@ cmd_watch() {
162
151
  local ts type agent stage issue
163
152
  ts=$(echo "$line" | jq -r '.ts // ""' 2>/dev/null || true)
164
153
  type=$(echo "$line" | jq -r '.type // ""' 2>/dev/null || true)
165
- agent=$(echo "$line" | jq -r '.agent // "system"' 2>/dev/null || true)
154
+ agent=$(echo "$line" | jq -r '.agent_id // .agent // "system"' 2>/dev/null || true)
166
155
  stage=$(echo "$line" | jq -r '.stage // ""' 2>/dev/null || true)
167
156
  issue=$(echo "$line" | jq -r '.issue // ""' 2>/dev/null || true)
168
157
 
@@ -251,7 +240,7 @@ cmd_snapshot() {
251
240
  [ -z "$line" ] && continue
252
241
 
253
242
  local agent stage ts
254
- agent=$(echo "$line" | jq -r '.agent // "system"' 2>/dev/null || true)
243
+ agent=$(echo "$line" | jq -r '.agent_id // .agent // "system"' 2>/dev/null || true)
255
244
  stage=$(echo "$line" | jq -r '.stage // ""' 2>/dev/null || true)
256
245
  ts=$(echo "$line" | jq -r '.ts // ""' 2>/dev/null || true)
257
246
 
@@ -310,7 +299,7 @@ cmd_history() {
310
299
 
311
300
  local epoch agent ts type
312
301
  epoch=$(echo "$line" | jq -r '.ts_epoch // 0' 2>/dev/null || true)
313
- agent=$(echo "$line" | jq -r '.agent // "system"' 2>/dev/null || true)
302
+ agent=$(echo "$line" | jq -r '.agent_id // .agent // "system"' 2>/dev/null || true)
314
303
  ts=$(echo "$line" | jq -r '.ts // ""' 2>/dev/null || true)
315
304
  type=$(echo "$line" | jq -r '.type // ""' 2>/dev/null || true)
316
305
 
@@ -361,7 +350,7 @@ cmd_stats() {
361
350
 
362
351
  local type agent ts
363
352
  type=$(echo "$line" | jq -r '.type // ""' 2>/dev/null || true)
364
- agent=$(echo "$line" | jq -r '.agent // "system"' 2>/dev/null || true)
353
+ agent=$(echo "$line" | jq -r '.agent_id // .agent // "system"' 2>/dev/null || true)
365
354
  ts=$(echo "$line" | jq -r '.ts // ""' 2>/dev/null || true)
366
355
 
367
356
  # Track unique agents
@@ -413,7 +402,7 @@ cmd_agents() {
413
402
  [ -z "$line" ] && continue
414
403
 
415
404
  local agent ts type
416
- agent=$(echo "$line" | jq -r '.agent // "system"' 2>/dev/null || true)
405
+ agent=$(echo "$line" | jq -r '.agent_id // .agent // "system"' 2>/dev/null || true)
417
406
  ts=$(echo "$line" | jq -r '.ts // ""' 2>/dev/null || true)
418
407
  type=$(echo "$line" | jq -r '.type // ""' 2>/dev/null || true)
419
408
 
@@ -6,32 +6,42 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="2.1.2"
9
+ VERSION="2.2.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
- # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
13
- CYAN='\033[38;2;0;212;255m' # #00d4ff — primary accent
14
- PURPLE='\033[38;2;124;58;237m' # #7c3aed — secondary
15
- BLUE='\033[38;2;0;102;255m' # #0066ff — tertiary
16
- GREEN='\033[38;2;74;222;128m' # success
17
- YELLOW='\033[38;2;250;204;21m' # warning
18
- RED='\033[38;2;248;113;113m' # error
19
- DIM='\033[2m'
20
- BOLD='\033[1m'
21
- RESET='\033[0m'
22
-
23
12
  # ─── Cross-platform compatibility ──────────────────────────────────────────
24
13
  # shellcheck source=lib/compat.sh
25
14
  [[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
26
15
 
27
- # ─── Output Helpers ─────────────────────────────────────────────────────────
28
- info() { echo -e "${CYAN}${BOLD}▸${RESET} $*" >&2; }
29
- success() { echo -e "${GREEN}${BOLD}✓${RESET} $*" >&2; }
30
- warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*" >&2; }
31
- error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
32
-
33
- now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
34
- now_epoch() { date +%s; }
16
+ # Canonical helpers (colors, output, events)
17
+ # shellcheck source=lib/helpers.sh
18
+ [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
19
+ # Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
20
+ [[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
21
+ [[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
22
+ [[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
23
+ [[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
24
+ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
25
+ now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
26
+ now_epoch() { date +%s; }
27
+ fi
28
+ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
29
+ emit_event() {
30
+ local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
31
+ local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
32
+ while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
33
+ echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
34
+ }
35
+ fi
36
+ CYAN="${CYAN:-\033[38;2;0;212;255m}"
37
+ PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
38
+ BLUE="${BLUE:-\033[38;2;0;102;255m}"
39
+ GREEN="${GREEN:-\033[38;2;74;222;128m}"
40
+ YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
41
+ RED="${RED:-\033[38;2;248;113;113m}"
42
+ DIM="${DIM:-\033[2m}"
43
+ BOLD="${BOLD:-\033[1m}"
44
+ RESET="${RESET:-\033[0m}"
35
45
 
36
46
  # ─── Paths ─────────────────────────────────────────────────────────────────
37
47
  EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
@@ -50,25 +60,6 @@ MAX_POLL_INTERVAL=300
50
60
  MIN_COVERAGE=0
51
61
  MAX_COVERAGE=100
52
62
 
53
- # ─── Emit Event ─────────────────────────────────────────────────────────────
54
- emit_event() {
55
- local event_type="$1"
56
- shift
57
- local json_fields=""
58
- for kv in "$@"; do
59
- local key="${kv%%=*}"
60
- local val="${kv#*=}"
61
- if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
62
- json_fields="${json_fields},\"${key}\":${val}"
63
- else
64
- val="${val//\"/\\\"}"
65
- json_fields="${json_fields},\"${key}\":\"${val}\""
66
- fi
67
- done
68
- mkdir -p "${HOME}/.shipwright"
69
- echo "{\"ts\":\"$(now_iso)\",\"ts_epoch\":$(now_epoch),\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
70
- }
71
-
72
63
  # ─── JSON Helper: Percentile ────────────────────────────────────────────────
73
64
  # Compute P-th percentile of sorted numeric array (bash + jq)
74
65
  # Usage: percentile "[1, 5, 10, 15, 20]" 95
@@ -6,49 +6,43 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="2.1.2"
9
+ VERSION="2.2.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
13
- CYAN='\033[38;2;0;212;255m'
14
- PURPLE='\033[38;2;124;58;237m'
15
- BLUE='\033[38;2;0;102;255m'
16
- GREEN='\033[38;2;74;222;128m'
17
- YELLOW='\033[38;2;250;204;21m'
18
- RED='\033[38;2;248;113;113m'
19
- DIM='\033[2m'
20
- BOLD='\033[1m'
21
- RESET='\033[0m'
22
-
23
13
  # ─── Cross-platform compatibility ──────────────────────────────────────────
24
14
  # shellcheck source=lib/compat.sh
25
15
  [[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
26
16
 
27
- info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
28
- success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
29
- warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
30
- error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
31
-
32
- now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
33
- now_epoch() { date +%s; }
34
-
35
- # ─── Structured Event Log ────────────────────────────────────────────────
36
- EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
37
-
38
- emit_event() {
39
- local event_type="$1"; shift
40
- local json_fields=""
41
- for kv in "$@"; do
42
- local key="${kv%%=*}"; local val="${kv#*=}"
43
- if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
44
- json_fields="${json_fields},\"${key}\":${val}"
45
- else
46
- val="${val//\"/\\\"}"; json_fields="${json_fields},\"${key}\":\"${val}\""
47
- fi
48
- done
49
- mkdir -p "${HOME}/.shipwright"
50
- echo "{\"ts\":\"$(now_iso)\",\"ts_epoch\":$(now_epoch),\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
51
- }
17
+ # Canonical helpers (colors, output, events)
18
+ # shellcheck source=lib/helpers.sh
19
+ [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
20
+ # Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
21
+ [[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
22
+ [[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
23
+ [[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
24
+ [[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
25
+ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
26
+ now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
27
+ now_epoch() { date +%s; }
28
+ fi
29
+ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
30
+ emit_event() {
31
+ local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
32
+ local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
33
+ while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
34
+ echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
35
+ }
36
+ fi
37
+ CYAN="${CYAN:-\033[38;2;0;212;255m}"
38
+ PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
39
+ BLUE="${BLUE:-\033[38;2;0;102;255m}"
40
+ GREEN="${GREEN:-\033[38;2;74;222;128m}"
41
+ YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
42
+ RED="${RED:-\033[38;2;248;113;113m}"
43
+ DIM="${DIM:-\033[2m}"
44
+ BOLD="${BOLD:-\033[1m}"
45
+ RESET="${RESET:-\033[0m}"
52
46
 
53
47
  # ─── Source Intelligence Core ─────────────────────────────────────────────
54
48
  if [[ -f "$SCRIPT_DIR/sw-intelligence.sh" ]]; then
@@ -6,50 +6,47 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="2.1.2"
9
+ VERSION="2.2.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
13
- CYAN='\033[38;2;0;212;255m'
14
- PURPLE='\033[38;2;124;58;237m'
15
- BLUE='\033[38;2;0;102;255m'
16
- GREEN='\033[38;2;74;222;128m'
17
- YELLOW='\033[38;2;250;204;21m'
18
- RED='\033[38;2;248;113;113m'
19
- DIM='\033[2m'
20
- BOLD='\033[1m'
21
- RESET='\033[0m'
22
-
23
13
  # ─── Cross-platform compatibility ──────────────────────────────────────────
24
14
  # shellcheck source=lib/compat.sh
25
15
  [[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
26
16
 
27
- info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
28
- success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
29
- warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
30
- error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
31
-
32
- now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
33
- now_epoch() { date +%s; }
17
+ # Canonical helpers (colors, output, events)
18
+ # shellcheck source=lib/helpers.sh
19
+ [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
20
+ # Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
21
+ [[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
22
+ [[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
23
+ [[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
24
+ [[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
25
+ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
26
+ now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
27
+ now_epoch() { date +%s; }
28
+ fi
29
+ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
30
+ emit_event() {
31
+ local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
32
+ local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
33
+ while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
34
+ echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
35
+ }
36
+ fi
37
+ CYAN="${CYAN:-\033[38;2;0;212;255m}"
38
+ PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
39
+ BLUE="${BLUE:-\033[38;2;0;102;255m}"
40
+ GREEN="${GREEN:-\033[38;2;74;222;128m}"
41
+ YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
42
+ RED="${RED:-\033[38;2;248;113;113m}"
43
+ DIM="${DIM:-\033[2m}"
44
+ BOLD="${BOLD:-\033[1m}"
45
+ RESET="${RESET:-\033[0m}"
34
46
 
35
47
  # ─── Structured Event Log ────────────────────────────────────────────────
36
48
  EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
37
49
 
38
- emit_event() {
39
- local event_type="$1"; shift
40
- local json_fields=""
41
- for kv in "$@"; do
42
- local key="${kv%%=*}"; local val="${kv#*=}"
43
- if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
44
- json_fields="${json_fields},\"${key}\":${val}"
45
- else
46
- val="${val//\"/\\\"}"; json_fields="${json_fields},\"${key}\":\"${val}\""
47
- fi
48
- done
49
- mkdir -p "${HOME}/.shipwright"
50
- echo "{\"ts\":\"$(now_iso)\",\"ts_epoch\":$(now_epoch),\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
51
- }
52
-
53
50
  # ─── Source Intelligence Core ─────────────────────────────────────────────
54
51
  if [[ -f "$SCRIPT_DIR/sw-intelligence.sh" ]]; then
55
52
  source "$SCRIPT_DIR/sw-intelligence.sh"
@@ -6,55 +6,43 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="2.1.2"
9
+ VERSION="2.2.1"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
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
13
  # ─── Cross-platform compatibility ──────────────────────────────────────────
25
14
  # shellcheck source=lib/compat.sh
26
15
  [[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
27
16
 
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
- local escaped_val
51
- escaped_val=$(printf '%s' "$val" | jq -Rs '.' 2>/dev/null || printf '"%s"' "${val//\"/\\\"}")
52
- json_fields="${json_fields},\"${key}\":${escaped_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
- }
17
+ # Canonical helpers (colors, output, events)
18
+ # shellcheck source=lib/helpers.sh
19
+ [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
20
+ # Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
21
+ [[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
22
+ [[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
23
+ [[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
24
+ [[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
25
+ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
26
+ now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
27
+ now_epoch() { date +%s; }
28
+ fi
29
+ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
30
+ emit_event() {
31
+ local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
32
+ local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
33
+ while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
34
+ echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
35
+ }
36
+ fi
37
+ CYAN="${CYAN:-\033[38;2;0;212;255m}"
38
+ PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
39
+ BLUE="${BLUE:-\033[38;2;0;102;255m}"
40
+ GREEN="${GREEN:-\033[38;2;74;222;128m}"
41
+ YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
42
+ RED="${RED:-\033[38;2;248;113;113m}"
43
+ DIM="${DIM:-\033[2m}"
44
+ BOLD="${BOLD:-\033[1m}"
45
+ RESET="${RESET:-\033[0m}"
58
46
 
59
47
  # ─── Auth Storage ───────────────────────────────────────────────────────────
60
48
  AUTH_FILE="${HOME}/.shipwright/auth.json"
@@ -7,33 +7,42 @@
7
7
  set -euo pipefail
8
8
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
9
9
 
10
- VERSION="2.1.2"
10
+ VERSION="2.2.1"
11
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
12
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
13
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
14
  # ─── Cross-platform compatibility ──────────────────────────────────────────
26
15
  # shellcheck source=lib/compat.sh
27
16
  [[ -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; }
17
+ # Canonical helpers (colors, output, events)
18
+ # shellcheck source=lib/helpers.sh
19
+ [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
20
+ # Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
21
+ [[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
22
+ [[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
23
+ [[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
24
+ [[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
25
+ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
26
+ now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
27
+ now_epoch() { date +%s; }
28
+ fi
29
+ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
30
+ emit_event() {
31
+ local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
32
+ local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
33
+ while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
34
+ echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
35
+ }
36
+ fi
37
+ CYAN="${CYAN:-\033[38;2;0;212;255m}"
38
+ PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
39
+ BLUE="${BLUE:-\033[38;2;0;102;255m}"
40
+ GREEN="${GREEN:-\033[38;2;74;222;128m}"
41
+ YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
42
+ RED="${RED:-\033[38;2;248;113;113m}"
43
+ DIM="${DIM:-\033[2m}"
44
+ BOLD="${BOLD:-\033[1m}"
45
+ RESET="${RESET:-\033[0m}"
37
46
 
38
47
  format_duration() {
39
48
  local secs="$1"
@@ -49,24 +58,6 @@ format_duration() {
49
58
  # ─── Structured Event Log ──────────────────────────────────────────────────
50
59
  EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
51
60
 
52
- emit_event() {
53
- local event_type="$1"
54
- shift
55
- local json_fields=""
56
- for kv in "$@"; do
57
- local key="${kv%%=*}"
58
- local val="${kv#*=}"
59
- if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
60
- json_fields="${json_fields},\"${key}\":${val}"
61
- else
62
- val="${val//\"/\\\"}"
63
- json_fields="${json_fields},\"${key}\":\"${val}\""
64
- fi
65
- done
66
- mkdir -p "${HOME}/.shipwright"
67
- echo "{\"ts\":\"$(now_iso)\",\"ts_epoch\":$(now_epoch),\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
68
- }
69
-
70
61
  # ─── State & Config Paths ─────────────────────────────────────────────────
71
62
  STATE_DIR="${HOME}/.shipwright/autonomous"
72
63
  STATE_FILE="${STATE_DIR}/state.json"
@@ -310,8 +301,22 @@ trigger_pipeline_for_finding() {
310
301
  if [[ ! -x "$SCRIPT_DIR/sw-pipeline.sh" ]]; then
311
302
  return 0
312
303
  fi
304
+
305
+ # Use recruit for model/team selection when available
306
+ local -a recruit_args=()
307
+ if [[ -x "$SCRIPT_DIR/sw-recruit.sh" ]]; then
308
+ local recruit_match
309
+ recruit_match=$(bash "$SCRIPT_DIR/sw-recruit.sh" match --json "$title" 2>/dev/null) || true
310
+ if [[ -n "$recruit_match" ]]; then
311
+ local rec_model
312
+ rec_model=$(echo "$recruit_match" | jq -r '.model // ""' 2>/dev/null) || true
313
+ [[ -n "$rec_model" && "$rec_model" != "null" ]] && recruit_args=(--model "$rec_model")
314
+ emit_event "autonomous.recruit_match" "issue=$issue_num" "role=$(echo "$recruit_match" | jq -r '.primary_role // ""' 2>/dev/null)" "model=$rec_model"
315
+ fi
316
+ fi
317
+
313
318
  info "Triggering pipeline for finding issue #${issue_num}: $title"
314
- (cd "$REPO_DIR" && export REPO_DIR SCRIPT_DIR && bash "$SCRIPT_DIR/sw-pipeline.sh" start --issue "$issue_num" 2>/dev/null) &
319
+ (cd "$REPO_DIR" && export REPO_DIR SCRIPT_DIR && bash "$SCRIPT_DIR/sw-pipeline.sh" start --issue "$issue_num" "${recruit_args[@]}" 2>/dev/null) &
315
320
  emit_event "autonomous.pipeline_triggered" "issue=$issue_num" "title=$title"
316
321
  }
317
322
 
@@ -400,6 +405,21 @@ process_findings() {
400
405
  labels="${category}${labels:+,$labels}"
401
406
  fi
402
407
 
408
+ # Use recruit to decompose complex findings and assess team needs
409
+ if [[ -x "$SCRIPT_DIR/sw-recruit.sh" && "$effort" == "L" ]]; then
410
+ local team_json
411
+ team_json=$(bash "$SCRIPT_DIR/sw-recruit.sh" team --json "$title" 2>/dev/null) || true
412
+ if [[ -n "$team_json" ]]; then
413
+ local team_size
414
+ team_size=$(echo "$team_json" | jq -r '.agents // 0' 2>/dev/null) || true
415
+ [[ -n "$team_size" && "$team_size" -gt 0 ]] && \
416
+ description="${description}
417
+
418
+ ---
419
+ **Recruit Recommendation:** ${team_size}-agent team ($(echo "$team_json" | jq -r '.team | join(", ")' 2>/dev/null))"
420
+ fi
421
+ fi
422
+
403
423
  local issue_num
404
424
  issue_num=$(create_issue_from_finding "$title" "$description" "$priority" "$effort" "$labels")
405
425
  if [[ $? -eq 0 && -n "$issue_num" ]]; then