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
@@ -9,25 +9,49 @@ trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
9
9
  # Allow spawning Claude CLI from within a Claude Code session (daemon, fleet, etc.)
10
10
  unset CLAUDECODE 2>/dev/null || true
11
11
 
12
- VERSION="2.1.2"
12
+ VERSION="2.2.1"
13
13
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
14
14
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
15
15
 
16
- # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
17
- CYAN='\033[38;2;0;212;255m' # #00d4ff — primary accent
18
- PURPLE='\033[38;2;124;58;237m' # #7c3aed — secondary
19
- BLUE='\033[38;2;0;102;255m' # #0066ff — tertiary
20
- GREEN='\033[38;2;74;222;128m' # success
21
- YELLOW='\033[38;2;250;204;21m' # warning
22
- RED='\033[38;2;248;113;113m' # error
23
- DIM='\033[2m'
24
- BOLD='\033[1m'
25
- RESET='\033[0m'
26
-
27
16
  # ─── Cross-platform compatibility ──────────────────────────────────────────
28
17
  # shellcheck source=lib/compat.sh
29
18
  [[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
30
19
 
20
+ # Canonical helpers (colors, output, events)
21
+ # shellcheck source=lib/helpers.sh
22
+ [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
23
+ # Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
24
+ [[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
25
+ [[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
26
+ [[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
27
+ [[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
28
+ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
29
+ now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
30
+ now_epoch() { date +%s; }
31
+ fi
32
+ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
33
+ emit_event() {
34
+ local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
35
+ local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
36
+ while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
37
+ echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
38
+ }
39
+ fi
40
+ CYAN="${CYAN:-\033[38;2;0;212;255m}"
41
+ PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
42
+ BLUE="${BLUE:-\033[38;2;0;102;255m}"
43
+ GREEN="${GREEN:-\033[38;2;74;222;128m}"
44
+ YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
45
+ RED="${RED:-\033[38;2;248;113;113m}"
46
+ DIM="${DIM:-\033[2m}"
47
+ BOLD="${BOLD:-\033[1m}"
48
+ RESET="${RESET:-\033[0m}"
49
+
50
+ # Policy (config/policy.json) — daemon defaults when daemon-config.json missing or silent
51
+ [[ -f "$SCRIPT_DIR/lib/policy.sh" ]] && source "$SCRIPT_DIR/lib/policy.sh"
52
+ # Daemon health timeouts from policy (lib/daemon-health.sh)
53
+ [[ -f "$SCRIPT_DIR/lib/daemon-health.sh" ]] && source "$SCRIPT_DIR/lib/daemon-health.sh"
54
+
31
55
  # ─── Intelligence Engine (optional) ──────────────────────────────────────────
32
56
  # shellcheck source=sw-intelligence.sh
33
57
  [[ -f "$SCRIPT_DIR/sw-intelligence.sh" ]] && source "$SCRIPT_DIR/sw-intelligence.sh"
@@ -52,15 +76,6 @@ RESET='\033[0m'
52
76
  # shellcheck source=sw-github-deploy.sh
53
77
  [[ -f "$SCRIPT_DIR/sw-github-deploy.sh" ]] && source "$SCRIPT_DIR/sw-github-deploy.sh"
54
78
 
55
- # ─── Output Helpers ─────────────────────────────────────────────────────────
56
- info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
57
- success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
58
- warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
59
- error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
60
-
61
- now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
62
- now_epoch() { date +%s; }
63
-
64
79
  epoch_to_iso() {
65
80
  local epoch="$1"
66
81
  date -u -r "$epoch" +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || \
@@ -197,9 +212,12 @@ LOG_FILE=""
197
212
  LOG_DIR=""
198
213
  WORKTREE_DIR=""
199
214
 
200
- # Config defaults (overridden by daemon-config.json)
215
+ # Config defaults (overridden by daemon-config.json; policy overrides when present)
201
216
  WATCH_LABEL="ready-to-build"
202
217
  POLL_INTERVAL=60
218
+ if type policy_get &>/dev/null 2>&1; then
219
+ POLL_INTERVAL=$(policy_get ".daemon.poll_interval_seconds" "60")
220
+ fi
203
221
  MAX_PARALLEL=2
204
222
  PIPELINE_TEMPLATE="autonomous"
205
223
  SKIP_GATES=true
@@ -222,9 +240,12 @@ WATCH_MODE="repo"
222
240
  ORG=""
223
241
  REPO_FILTER=""
224
242
 
225
- # Auto-scaling defaults
243
+ # Auto-scaling defaults (policy overrides when present)
226
244
  AUTO_SCALE=false
227
245
  AUTO_SCALE_INTERVAL=5
246
+ if type policy_get &>/dev/null 2>&1; then
247
+ AUTO_SCALE_INTERVAL=$(policy_get ".daemon.auto_scale_interval_cycles" "5")
248
+ fi
228
249
  MAX_WORKERS=8
229
250
  MIN_WORKERS=1
230
251
  WORKER_MEM_GB=4
@@ -377,7 +398,7 @@ load_config() {
377
398
  info "Loading config: ${DIM}${config_file}${RESET}"
378
399
 
379
400
  WATCH_LABEL=$(jq -r '.watch_label // "ready-to-build"' "$config_file")
380
- POLL_INTERVAL=$(jq -r '.poll_interval // 60' "$config_file")
401
+ POLL_INTERVAL=$(jq -r '.poll_interval // '"$(type policy_get &>/dev/null 2>&1 && policy_get ".daemon.poll_interval_seconds" "60" || echo "60")"'' "$config_file")
381
402
  MAX_PARALLEL=$(jq -r '.max_parallel // 2' "$config_file")
382
403
  PIPELINE_TEMPLATE=$(jq -r '.pipeline_template // "autonomous"' "$config_file")
383
404
  SKIP_GATES=$(jq -r '.skip_gates // true' "$config_file")
@@ -437,7 +458,7 @@ load_config() {
437
458
 
438
459
  # self-optimization
439
460
  SELF_OPTIMIZE=$(jq -r '.self_optimize // false' "$config_file")
440
- OPTIMIZE_INTERVAL=$(jq -r '.optimize_interval // 10' "$config_file")
461
+ OPTIMIZE_INTERVAL=$(jq -r '.optimize_interval // '"$(type policy_get &>/dev/null 2>&1 && policy_get ".daemon.optimize_interval_cycles" "10" || echo "10")"'' "$config_file")
441
462
 
442
463
  # intelligence engine settings
443
464
  INTELLIGENCE_ENABLED=$(jq -r '.intelligence.enabled // false' "$config_file")
@@ -456,7 +477,7 @@ load_config() {
456
477
 
457
478
  # stale state reaper: clean old worktrees, artifacts, state entries
458
479
  STALE_REAPER_ENABLED=$(jq -r '.stale_reaper // true' "$config_file")
459
- STALE_REAPER_INTERVAL=$(jq -r '.stale_reaper_interval // 10' "$config_file")
480
+ STALE_REAPER_INTERVAL=$(jq -r '.stale_reaper_interval // '"$(type policy_get &>/dev/null 2>&1 && policy_get ".daemon.stale_reaper_interval_cycles" "10" || echo "10")"'' "$config_file")
460
481
  STALE_REAPER_AGE_DAYS=$(jq -r '.stale_reaper_age_days // 7' "$config_file")
461
482
 
462
483
  # priority lane settings
@@ -473,14 +494,14 @@ load_config() {
473
494
 
474
495
  # auto-scaling
475
496
  AUTO_SCALE=$(jq -r '.auto_scale // false' "$config_file")
476
- AUTO_SCALE_INTERVAL=$(jq -r '.auto_scale_interval // 5' "$config_file")
497
+ AUTO_SCALE_INTERVAL=$(jq -r '.auto_scale_interval // '"$(type policy_get &>/dev/null 2>&1 && policy_get ".daemon.auto_scale_interval_cycles" "5" || echo "5")"'' "$config_file")
477
498
  MAX_WORKERS=$(jq -r '.max_workers // 8' "$config_file")
478
499
  MIN_WORKERS=$(jq -r '.min_workers // 1' "$config_file")
479
500
  WORKER_MEM_GB=$(jq -r '.worker_mem_gb // 4' "$config_file")
480
501
  EST_COST_PER_JOB=$(jq -r '.estimated_cost_per_job_usd // 5.0' "$config_file")
481
502
 
482
- # heartbeat + checkpoint recovery
483
- HEALTH_HEARTBEAT_TIMEOUT=$(jq -r '.health.heartbeat_timeout_s // 120' "$config_file")
503
+ # heartbeat + checkpoint recovery (policy fallback when config silent)
504
+ HEALTH_HEARTBEAT_TIMEOUT=$(jq -r '.health.heartbeat_timeout_s // '"$(type policy_get &>/dev/null 2>&1 && policy_get ".daemon.health_heartbeat_timeout" "120" || echo "120")"'' "$config_file")
484
505
  CHECKPOINT_ENABLED=$(jq -r '.health.checkpoint_enabled // true' "$config_file")
485
506
 
486
507
  # progress-based health monitoring (replaces static timeouts)
@@ -612,14 +633,23 @@ get_adaptive_heartbeat_timeout() {
612
633
  return
613
634
  fi
614
635
 
615
- # Stage-specific defaults (used when no learned data)
636
+ # Stage-specific defaults (daemon-health.sh when sourced, else policy_get, else literal)
616
637
  local default_timeout="${HEALTH_HEARTBEAT_TIMEOUT:-120}"
617
- case "$stage" in
618
- build) default_timeout=300 ;;
619
- test) default_timeout=180 ;;
620
- review|compound_quality) default_timeout=180 ;;
621
- lint|format|intake|plan|design) default_timeout=60 ;;
622
- esac
638
+ if type daemon_health_timeout_for_stage &>/dev/null 2>&1; then
639
+ default_timeout=$(daemon_health_timeout_for_stage "$stage" "$default_timeout")
640
+ elif type policy_get &>/dev/null 2>&1; then
641
+ local policy_stage
642
+ policy_stage=$(policy_get ".daemon.stage_timeouts.$stage" "")
643
+ [[ -n "$policy_stage" && "$policy_stage" =~ ^[0-9]+$ ]] && default_timeout="$policy_stage"
644
+ else
645
+ case "$stage" in
646
+ build) default_timeout=300 ;;
647
+ test) default_timeout=180 ;;
648
+ review|compound_quality) default_timeout=180 ;;
649
+ lint|format|intake|plan|design) default_timeout=60 ;;
650
+ esac
651
+ fi
652
+ [[ "$default_timeout" =~ ^[0-9]+$ ]] || default_timeout="${HEALTH_HEARTBEAT_TIMEOUT:-120}"
623
653
 
624
654
  local durations_file="$HOME/.shipwright/optimization/stage-durations.json"
625
655
  if [[ ! -f "$durations_file" ]]; then
@@ -6,33 +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
 
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
- UNDERLINE='\033[4m'
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
15
 
34
- now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
35
- 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}"
45
+ UNDERLINE='\033[4m'
36
46
 
37
47
  # ─── Paths ──────────────────────────────────────────────────────────────────
38
48
  TEAMS_DIR="${HOME}/.shipwright"
@@ -42,25 +52,6 @@ LOG_FILE="${LOG_DIR}/dashboard.log"
42
52
  EVENTS_FILE="${TEAMS_DIR}/events.jsonl"
43
53
  DEFAULT_PORT=8767
44
54
 
45
- # ─── Structured Event Log ──────────────────────────────────────────────────
46
- emit_event() {
47
- local event_type="$1"
48
- shift
49
- local json_fields=""
50
- for kv in "$@"; do
51
- local key="${kv%%=*}"
52
- local val="${kv#*=}"
53
- if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
54
- json_fields="${json_fields},\"${key}\":${val}"
55
- else
56
- val="${val//\"/\\\"}"
57
- json_fields="${json_fields},\"${key}\":\"${val}\""
58
- fi
59
- done
60
- mkdir -p "${TEAMS_DIR}"
61
- echo "{\"ts\":\"$(now_iso)\",\"ts_epoch\":$(now_epoch),\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
62
- }
63
-
64
55
  # ─── Header ────────────────────────────────────────────────────────────────
65
56
  dashboard_header() {
66
57
  echo ""
package/scripts/sw-db.sh CHANGED
@@ -14,33 +14,43 @@ if [[ -n "${_SW_DB_LOADED:-}" ]] && [[ "${BASH_SOURCE[0]}" != "$0" ]]; then
14
14
  fi
15
15
  _SW_DB_LOADED=1
16
16
 
17
- VERSION="2.1.2"
17
+ VERSION="2.2.1"
18
18
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19
19
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
20
20
 
21
- # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
22
- CYAN='\033[38;2;0;212;255m' # #00d4ff — primary accent
23
- PURPLE='\033[38;2;124;58;237m' # #7c3aed — secondary
24
- BLUE='\033[38;2;0;102;255m' # #0066ff — tertiary
25
- GREEN='\033[38;2;74;222;128m' # success
26
- YELLOW='\033[38;2;250;204;21m' # warning
27
- RED='\033[38;2;248;113;113m' # error
28
- DIM='\033[2m'
29
- BOLD='\033[1m'
30
- RESET='\033[0m'
31
-
32
21
  # ─── Cross-platform compatibility ──────────────────────────────────────────
33
22
  # shellcheck source=lib/compat.sh
34
23
  [[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
35
24
 
36
- # ─── Output Helpers ─────────────────────────────────────────────────────────
37
- info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
38
- success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
39
- warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
40
- error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
41
-
42
- now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
43
- now_epoch() { date +%s; }
25
+ # Canonical helpers (colors, output, events)
26
+ # shellcheck source=lib/helpers.sh
27
+ [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
28
+ # Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
29
+ [[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
30
+ [[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
31
+ [[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
32
+ [[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
33
+ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
34
+ now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
35
+ now_epoch() { date +%s; }
36
+ fi
37
+ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
38
+ emit_event() {
39
+ local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
40
+ local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
41
+ while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
42
+ echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
43
+ }
44
+ fi
45
+ CYAN="${CYAN:-\033[38;2;0;212;255m}"
46
+ PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
47
+ BLUE="${BLUE:-\033[38;2;0;102;255m}"
48
+ GREEN="${GREEN:-\033[38;2;74;222;128m}"
49
+ YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
50
+ RED="${RED:-\033[38;2;248;113;113m}"
51
+ DIM="${DIM:-\033[2m}"
52
+ BOLD="${BOLD:-\033[1m}"
53
+ RESET="${RESET:-\033[0m}"
44
54
 
45
55
  # ─── Database Configuration ──────────────────────────────────────────────────
46
56
  DB_DIR="${HOME}/.shipwright"
@@ -6,55 +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
- # ─── 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; }
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}"
36
46
 
37
47
  # ─── Structured Event Log ──────────────────────────────────────────────────
38
48
  EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
39
49
 
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
50
  # ─── Configuration ─────────────────────────────────────────────────────────
59
51
  COMPLEXITY_THRESHOLD=70 # Decompose if complexity > this
60
52
  HOURS_THRESHOLD=8 # Decompose if estimated hours > this
@@ -6,53 +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; }
32
-
33
- # ─── Event Logging ──────────────────────────────────────────────────────────
34
- EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
35
-
36
- now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
37
- now_epoch() { date +%s; }
38
-
39
- emit_event() {
40
- local event_type="$1"
41
- shift
42
- local json_fields=""
43
- for kv in "$@"; do
44
- local key="${kv%%=*}"
45
- local val="${kv#*=}"
46
- if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
47
- json_fields="${json_fields},\"${key}\":${val}"
48
- else
49
- val="${val//\"/\\\"}"
50
- json_fields="${json_fields},\"${key}\":\"${val}\""
51
- fi
52
- done
53
- mkdir -p "${HOME}/.shipwright"
54
- echo "{\"ts\":\"$(now_iso)\",\"ts_epoch\":$(now_epoch),\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
55
- }
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}"
56
45
 
57
46
  # ─── Defaults ───────────────────────────────────────────────────────────────
58
47
  DEPS_DIR="${HOME}/.shipwright/deps"
@@ -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