shipwright-cli 2.1.1 → 2.2.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.
Files changed (129) 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 +75 -0
  8. package/docs/AGI-PLATFORM-PLAN.md +122 -0
  9. package/docs/AGI-WHATS-NEXT.md +69 -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/pipeline-quality.sh +23 -0
  25. package/scripts/lib/policy.sh +32 -0
  26. package/scripts/sw +5 -1
  27. package/scripts/sw-activity.sh +35 -46
  28. package/scripts/sw-adaptive.sh +30 -39
  29. package/scripts/sw-adversarial.sh +30 -36
  30. package/scripts/sw-architecture-enforcer.sh +30 -33
  31. package/scripts/sw-auth.sh +30 -42
  32. package/scripts/sw-autonomous.sh +60 -40
  33. package/scripts/sw-changelog.sh +29 -30
  34. package/scripts/sw-checkpoint.sh +30 -18
  35. package/scripts/sw-ci.sh +30 -42
  36. package/scripts/sw-cleanup.sh +32 -15
  37. package/scripts/sw-code-review.sh +26 -32
  38. package/scripts/sw-connect.sh +30 -19
  39. package/scripts/sw-context.sh +30 -19
  40. package/scripts/sw-cost.sh +30 -40
  41. package/scripts/sw-daemon.sh +150 -39
  42. package/scripts/sw-dashboard.sh +31 -40
  43. package/scripts/sw-db.sh +30 -20
  44. package/scripts/sw-decompose.sh +30 -38
  45. package/scripts/sw-deps.sh +30 -41
  46. package/scripts/sw-developer-simulation.sh +30 -36
  47. package/scripts/sw-discovery.sh +36 -19
  48. package/scripts/sw-doc-fleet.sh +822 -0
  49. package/scripts/sw-docs-agent.sh +30 -36
  50. package/scripts/sw-docs.sh +29 -31
  51. package/scripts/sw-doctor.sh +52 -20
  52. package/scripts/sw-dora.sh +29 -34
  53. package/scripts/sw-durable.sh +30 -20
  54. package/scripts/sw-e2e-orchestrator.sh +36 -21
  55. package/scripts/sw-eventbus.sh +30 -17
  56. package/scripts/sw-feedback.sh +30 -41
  57. package/scripts/sw-fix.sh +30 -40
  58. package/scripts/sw-fleet-discover.sh +30 -41
  59. package/scripts/sw-fleet-viz.sh +30 -20
  60. package/scripts/sw-fleet.sh +30 -40
  61. package/scripts/sw-github-app.sh +30 -41
  62. package/scripts/sw-github-checks.sh +30 -41
  63. package/scripts/sw-github-deploy.sh +30 -41
  64. package/scripts/sw-github-graphql.sh +30 -38
  65. package/scripts/sw-guild.sh +30 -37
  66. package/scripts/sw-heartbeat.sh +30 -19
  67. package/scripts/sw-hygiene.sh +134 -42
  68. package/scripts/sw-incident.sh +30 -39
  69. package/scripts/sw-init.sh +31 -14
  70. package/scripts/sw-instrument.sh +30 -41
  71. package/scripts/sw-intelligence.sh +39 -44
  72. package/scripts/sw-jira.sh +31 -41
  73. package/scripts/sw-launchd.sh +30 -17
  74. package/scripts/sw-linear.sh +31 -41
  75. package/scripts/sw-logs.sh +32 -17
  76. package/scripts/sw-loop.sh +55 -26
  77. package/scripts/sw-memory.sh +90 -99
  78. package/scripts/sw-mission-control.sh +31 -40
  79. package/scripts/sw-model-router.sh +30 -20
  80. package/scripts/sw-otel.sh +30 -20
  81. package/scripts/sw-oversight.sh +30 -36
  82. package/scripts/sw-patrol-meta.sh +31 -0
  83. package/scripts/sw-pipeline-composer.sh +30 -39
  84. package/scripts/sw-pipeline-vitals.sh +30 -44
  85. package/scripts/sw-pipeline.sh +315 -6388
  86. package/scripts/sw-pm.sh +31 -41
  87. package/scripts/sw-pr-lifecycle.sh +30 -42
  88. package/scripts/sw-predictive.sh +32 -34
  89. package/scripts/sw-prep.sh +47 -32
  90. package/scripts/sw-ps.sh +32 -17
  91. package/scripts/sw-public-dashboard.sh +30 -40
  92. package/scripts/sw-quality.sh +42 -40
  93. package/scripts/sw-reaper.sh +32 -15
  94. package/scripts/sw-recruit.sh +428 -48
  95. package/scripts/sw-regression.sh +30 -38
  96. package/scripts/sw-release-manager.sh +30 -38
  97. package/scripts/sw-release.sh +29 -31
  98. package/scripts/sw-remote.sh +31 -40
  99. package/scripts/sw-replay.sh +30 -18
  100. package/scripts/sw-retro.sh +33 -42
  101. package/scripts/sw-scale.sh +41 -24
  102. package/scripts/sw-security-audit.sh +30 -20
  103. package/scripts/sw-self-optimize.sh +33 -37
  104. package/scripts/sw-session.sh +31 -15
  105. package/scripts/sw-setup.sh +30 -16
  106. package/scripts/sw-standup.sh +30 -20
  107. package/scripts/sw-status.sh +33 -13
  108. package/scripts/sw-strategic.sh +55 -43
  109. package/scripts/sw-stream.sh +33 -37
  110. package/scripts/sw-swarm.sh +30 -21
  111. package/scripts/sw-team-stages.sh +30 -38
  112. package/scripts/sw-templates.sh +31 -16
  113. package/scripts/sw-testgen.sh +30 -31
  114. package/scripts/sw-tmux-pipeline.sh +29 -31
  115. package/scripts/sw-tmux-role-color.sh +31 -0
  116. package/scripts/sw-tmux-status.sh +31 -0
  117. package/scripts/sw-tmux.sh +31 -15
  118. package/scripts/sw-trace.sh +30 -19
  119. package/scripts/sw-tracker-github.sh +31 -0
  120. package/scripts/sw-tracker-jira.sh +31 -0
  121. package/scripts/sw-tracker-linear.sh +31 -0
  122. package/scripts/sw-tracker.sh +30 -40
  123. package/scripts/sw-triage.sh +68 -61
  124. package/scripts/sw-upgrade.sh +30 -16
  125. package/scripts/sw-ux.sh +30 -35
  126. package/scripts/sw-webhook.sh +30 -25
  127. package/scripts/sw-widgets.sh +30 -19
  128. package/scripts/sw-worktree.sh +32 -15
  129. package/tmux/templates/doc-fleet.json +43 -0
@@ -4,26 +4,41 @@
4
4
  # ║ ║
5
5
  # ║ Captures tmux pane scrollback and provides log browsing/search. ║
6
6
  # ╚═══════════════════════════════════════════════════════════════════════════╝
7
- VERSION="2.1.1"
7
+ VERSION="2.2.0"
8
8
  set -euo pipefail
9
9
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
10
10
 
11
- # ─── Colors ──────────────────────────────────────────────────────────────────
12
- CYAN='\033[38;2;0;212;255m'
13
- PURPLE='\033[38;2;124;58;237m'
14
- BLUE='\033[38;2;0;102;255m'
15
- GREEN='\033[38;2;74;222;128m'
16
- YELLOW='\033[38;2;250;204;21m'
17
- RED='\033[38;2;248;113;113m'
18
- DIM='\033[2m'
19
- BOLD='\033[1m'
20
- RESET='\033[0m'
21
-
22
- # ─── Helpers ─────────────────────────────────────────────────────────────────
23
- info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
24
- success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
25
- warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
26
- error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
11
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
+
13
+ # Canonical helpers (colors, output, events)
14
+ # shellcheck source=lib/helpers.sh
15
+ [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
16
+ # Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
17
+ [[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
18
+ [[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
19
+ [[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
20
+ [[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
21
+ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
22
+ now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
23
+ now_epoch() { date +%s; }
24
+ fi
25
+ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
26
+ emit_event() {
27
+ local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
28
+ local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
29
+ while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
30
+ echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
31
+ }
32
+ fi
33
+ CYAN="${CYAN:-\033[38;2;0;212;255m}"
34
+ PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
35
+ BLUE="${BLUE:-\033[38;2;0;102;255m}"
36
+ GREEN="${GREEN:-\033[38;2;74;222;128m}"
37
+ YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
38
+ RED="${RED:-\033[38;2;248;113;113m}"
39
+ DIM="${DIM:-\033[2m}"
40
+ BOLD="${BOLD:-\033[1m}"
41
+ RESET="${RESET:-\033[0m}"
27
42
 
28
43
  LOGS_DIR="$HOME/.shipwright/logs"
29
44
 
@@ -17,25 +17,38 @@ trap '' HUP
17
17
 
18
18
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19
19
 
20
- # ─── Colors (matches shipwright theme) ──────────────────────────────────────────────
21
- CYAN='\033[38;2;0;212;255m'
22
- PURPLE='\033[38;2;124;58;237m'
23
- BLUE='\033[38;2;0;102;255m'
24
- GREEN='\033[38;2;74;222;128m'
25
- YELLOW='\033[38;2;250;204;21m'
26
- RED='\033[38;2;248;113;113m'
27
- DIM='\033[2m'
28
- BOLD='\033[1m'
29
- RESET='\033[0m'
30
-
31
20
  # ─── Cross-platform compatibility ──────────────────────────────────────────
32
21
  # shellcheck source=lib/compat.sh
33
22
  [[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
34
-
35
- info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
36
- success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
37
- warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
38
- error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
23
+ # Canonical helpers (colors, output, events)
24
+ # shellcheck source=lib/helpers.sh
25
+ [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
26
+ # Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
27
+ [[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
28
+ [[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
29
+ [[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
30
+ [[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
31
+ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
32
+ now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
33
+ now_epoch() { date +%s; }
34
+ fi
35
+ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
36
+ emit_event() {
37
+ local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
38
+ local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
39
+ while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
40
+ echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
41
+ }
42
+ fi
43
+ CYAN="${CYAN:-\033[38;2;0;212;255m}"
44
+ PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
45
+ BLUE="${BLUE:-\033[38;2;0;102;255m}"
46
+ GREEN="${GREEN:-\033[38;2;74;222;128m}"
47
+ YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
48
+ RED="${RED:-\033[38;2;248;113;113m}"
49
+ DIM="${DIM:-\033[2m}"
50
+ BOLD="${BOLD:-\033[1m}"
51
+ RESET="${RESET:-\033[0m}"
39
52
 
40
53
  # ─── Defaults ─────────────────────────────────────────────────────────────────
41
54
  GOAL=""
@@ -58,7 +71,7 @@ MAX_RESTARTS=0
58
71
  SESSION_RESTART=false
59
72
  RESTART_COUNT=0
60
73
  REPO_OVERRIDE=""
61
- VERSION="2.1.1"
74
+ VERSION="2.2.0"
62
75
 
63
76
  # ─── Token Tracking ─────────────────────────────────────────────────────────
64
77
  LOOP_INPUT_TOKENS=0
@@ -1021,19 +1034,34 @@ run_test_gate() {
1021
1034
  write_error_summary() {
1022
1035
  local error_json="$LOG_DIR/error-summary.json"
1023
1036
 
1024
- # Only write on test failure
1037
+ # Write on test failure OR build failure (non-zero exit from Claude iteration)
1038
+ local build_log="$LOG_DIR/iteration-${ITERATION}.log"
1025
1039
  if [[ "${TEST_PASSED:-}" != "false" ]]; then
1026
- # Clear previous error summary on success
1027
- rm -f "$error_json" 2>/dev/null || true
1028
- return
1040
+ # Check for build-level failures (Claude iteration exited non-zero or produced errors)
1041
+ local build_had_errors=false
1042
+ if [[ -f "$build_log" ]]; then
1043
+ local build_err_count
1044
+ build_err_count=$(tail -30 "$build_log" 2>/dev/null | grep -ciE '(error|fail|exception|panic|FATAL)' || true)
1045
+ [[ "${build_err_count:-0}" -gt 0 ]] && build_had_errors=true
1046
+ fi
1047
+ if [[ "$build_had_errors" != "true" ]]; then
1048
+ # Clear previous error summary on success
1049
+ rm -f "$error_json" 2>/dev/null || true
1050
+ return
1051
+ fi
1029
1052
  fi
1030
1053
 
1054
+ # Prefer test log, fall back to build log
1031
1055
  local test_log="${TEST_LOG_FILE:-$LOG_DIR/tests-iter-${ITERATION}.log}"
1032
- [[ ! -f "$test_log" ]] && return
1056
+ local source_log="$test_log"
1057
+ if [[ ! -f "$source_log" ]]; then
1058
+ source_log="$build_log"
1059
+ fi
1060
+ [[ ! -f "$source_log" ]] && return
1033
1061
 
1034
1062
  # Extract error lines (last 30 lines, grep for error patterns)
1035
1063
  local error_lines_raw
1036
- error_lines_raw=$(tail -30 "$test_log" 2>/dev/null | grep -iE '(error|fail|assert|exception|panic|FAIL|TypeError|ReferenceError|SyntaxError)' | head -10 || true)
1064
+ error_lines_raw=$(tail -30 "$source_log" 2>/dev/null | grep -iE '(error|fail|assert|exception|panic|FAIL|TypeError|ReferenceError|SyntaxError)' | head -10 || true)
1037
1065
 
1038
1066
  local error_count=0
1039
1067
  if [[ -n "$error_lines_raw" ]]; then
@@ -1660,8 +1688,8 @@ compose_worker_prompt() {
1660
1688
  reviewer) role_desc="Focus on code review — look for bugs, security issues, edge cases in recent commits. Make fixes via commits." ;;
1661
1689
  tester) role_desc="Focus on test coverage — write new tests, fix failing tests, improve assertions and edge case coverage." ;;
1662
1690
  optimizer) role_desc="Focus on performance — profile hot paths, reduce complexity, optimize algorithms and data structures." ;;
1663
- docs) role_desc="Focus on documentation — update README, add docstrings, write usage guides for new features." ;;
1664
- security) role_desc="Focus on security — audit for vulnerabilities, fix injection risks, validate inputs, check auth boundaries." ;;
1691
+ docs|docs-writer) role_desc="Focus on documentation — update README, add docstrings, write usage guides for new features." ;;
1692
+ security|security-auditor) role_desc="Focus on security — audit for vulnerabilities, fix injection risks, validate inputs, check auth boundaries." ;;
1665
1693
  *) role_desc="Focus on: ${role}. Apply your expertise in this area to advance the goal." ;;
1666
1694
  esac
1667
1695
  fi
@@ -2434,8 +2462,9 @@ run_loop_with_restarts() {
2434
2462
  [[ -f "$old_log" ]] && mv "$old_log" "$restart_archive/" 2>/dev/null || true
2435
2463
  done
2436
2464
  # Archive progress.md and error-summary.json from previous session
2465
+ # IMPORTANT: copy (not move) error-summary.json so the fresh session can still read it
2437
2466
  [[ -f "$LOG_DIR/progress.md" ]] && cp "$LOG_DIR/progress.md" "$restart_archive/progress.md" 2>/dev/null || true
2438
- [[ -f "$LOG_DIR/error-summary.json" ]] && mv "$LOG_DIR/error-summary.json" "$restart_archive/" 2>/dev/null || true
2467
+ [[ -f "$LOG_DIR/error-summary.json" ]] && cp "$LOG_DIR/error-summary.json" "$restart_archive/" 2>/dev/null || true
2439
2468
 
2440
2469
  write_state
2441
2470
 
@@ -6,59 +6,48 @@
6
6
  set -euo pipefail
7
7
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
8
8
 
9
- VERSION="2.1.1"
9
+ VERSION="2.2.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
- REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
-
13
- # ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
14
- CYAN='\033[38;2;0;212;255m' # #00d4ff — primary accent
15
- PURPLE='\033[38;2;124;58;237m' # #7c3aed — secondary
16
- BLUE='\033[38;2;0;102;255m' # #0066ff — tertiary
17
- GREEN='\033[38;2;74;222;128m' # success
18
- YELLOW='\033[38;2;250;204;21m' # warning
19
- RED='\033[38;2;248;113;113m' # error
20
- DIM='\033[2m'
21
- BOLD='\033[1m'
22
- RESET='\033[0m'
11
+ REPO_DIR="${REPO_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
23
12
 
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
 
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}"
46
+
28
47
  # ─── Intelligence Engine (optional) ──────────────────────────────────────────
29
48
  # shellcheck source=sw-intelligence.sh
30
49
  [[ -f "$SCRIPT_DIR/sw-intelligence.sh" ]] && source "$SCRIPT_DIR/sw-intelligence.sh"
31
50
 
32
- # ─── Output Helpers ─────────────────────────────────────────────────────────
33
- info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
34
- success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
35
- warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
36
- error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
37
-
38
- now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
39
- now_epoch() { date +%s; }
40
-
41
- # ─── Structured Event Log ──────────────────────────────────────────────────
42
- EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
43
-
44
- emit_event() {
45
- local event_type="$1"
46
- shift
47
- local json_fields=""
48
- for kv in "$@"; do
49
- local key="${kv%%=*}"
50
- local val="${kv#*=}"
51
- if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
52
- json_fields="${json_fields},\"${key}\":${val}"
53
- else
54
- val="${val//\"/\\\"}"
55
- json_fields="${json_fields},\"${key}\":\"${val}\""
56
- fi
57
- done
58
- mkdir -p "${HOME}/.shipwright"
59
- echo "{\"ts\":\"$(now_iso)\",\"ts_epoch\":$(now_epoch),\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
60
- }
61
-
62
51
  # ─── Memory Storage Paths ──────────────────────────────────────────────────
63
52
  MEMORY_ROOT="${HOME}/.shipwright/memory"
64
53
  GLOBAL_MEMORY="${MEMORY_ROOT}/global.json"
@@ -1585,59 +1574,61 @@ show_help() {
1585
1574
 
1586
1575
  # ─── Command Router ─────────────────────────────────────────────────────────
1587
1576
 
1588
- SUBCOMMAND="${1:-help}"
1589
- shift 2>/dev/null || true
1590
-
1591
- case "$SUBCOMMAND" in
1592
- show)
1593
- memory_show "$@"
1594
- ;;
1595
- search)
1596
- memory_search "$@"
1597
- ;;
1598
- forget)
1599
- memory_forget "$@"
1600
- ;;
1601
- export)
1602
- memory_export
1603
- ;;
1604
- import)
1605
- memory_import "$@"
1606
- ;;
1607
- stats)
1608
- memory_stats
1609
- ;;
1610
- capture)
1611
- memory_capture_pipeline "$@"
1612
- ;;
1613
- inject)
1614
- memory_inject_context "$@"
1615
- ;;
1616
- pattern)
1617
- memory_capture_pattern "$@"
1618
- ;;
1619
- get)
1620
- memory_get_baseline "$@"
1621
- ;;
1622
- metric)
1623
- memory_update_metrics "$@"
1624
- ;;
1625
- decision)
1626
- memory_capture_decision "$@"
1627
- ;;
1628
- analyze-failure)
1629
- memory_analyze_failure "$@"
1630
- ;;
1631
- fix-outcome)
1632
- memory_record_fix_outcome "$@"
1633
- ;;
1634
- help|--help|-h)
1635
- show_help
1636
- ;;
1637
- *)
1638
- error "Unknown command: ${SUBCOMMAND}"
1639
- echo ""
1640
- show_help
1641
- exit 1
1642
- ;;
1643
- esac
1577
+ if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
1578
+ SUBCOMMAND="${1:-help}"
1579
+ shift 2>/dev/null || true
1580
+
1581
+ case "$SUBCOMMAND" in
1582
+ show)
1583
+ memory_show "$@"
1584
+ ;;
1585
+ search)
1586
+ memory_search "$@"
1587
+ ;;
1588
+ forget)
1589
+ memory_forget "$@"
1590
+ ;;
1591
+ export)
1592
+ memory_export
1593
+ ;;
1594
+ import)
1595
+ memory_import "$@"
1596
+ ;;
1597
+ stats)
1598
+ memory_stats
1599
+ ;;
1600
+ capture)
1601
+ memory_capture_pipeline "$@"
1602
+ ;;
1603
+ inject)
1604
+ memory_inject_context "$@"
1605
+ ;;
1606
+ pattern)
1607
+ memory_capture_pattern "$@"
1608
+ ;;
1609
+ get)
1610
+ memory_get_baseline "$@"
1611
+ ;;
1612
+ metric)
1613
+ memory_update_metrics "$@"
1614
+ ;;
1615
+ decision)
1616
+ memory_capture_decision "$@"
1617
+ ;;
1618
+ analyze-failure)
1619
+ memory_analyze_failure "$@"
1620
+ ;;
1621
+ fix-outcome)
1622
+ memory_record_fix_outcome "$@"
1623
+ ;;
1624
+ help|--help|-h)
1625
+ show_help
1626
+ ;;
1627
+ *)
1628
+ error "Unknown command: ${SUBCOMMAND}"
1629
+ echo ""
1630
+ show_help
1631
+ exit 1
1632
+ ;;
1633
+ esac
1634
+ fi
@@ -7,33 +7,43 @@
7
7
  set -euo pipefail
8
8
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
9
9
 
10
- VERSION="2.1.1"
10
+ VERSION="2.2.0"
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
17
 
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; }
18
+ # Canonical helpers (colors, output, events)
19
+ # shellcheck source=lib/helpers.sh
20
+ [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
21
+ # Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
22
+ [[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
23
+ [[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
24
+ [[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
25
+ [[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
26
+ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
27
+ now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
28
+ now_epoch() { date +%s; }
29
+ fi
30
+ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
31
+ emit_event() {
32
+ local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
33
+ local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
34
+ while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
35
+ echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
36
+ }
37
+ fi
38
+ CYAN="${CYAN:-\033[38;2;0;212;255m}"
39
+ PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
40
+ BLUE="${BLUE:-\033[38;2;0;102;255m}"
41
+ GREEN="${GREEN:-\033[38;2;74;222;128m}"
42
+ YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
43
+ RED="${RED:-\033[38;2;248;113;113m}"
44
+ DIM="${DIM:-\033[2m}"
45
+ BOLD="${BOLD:-\033[1m}"
46
+ RESET="${RESET:-\033[0m}"
37
47
 
38
48
  format_duration() {
39
49
  local secs="$1"
@@ -46,29 +56,10 @@ format_duration() {
46
56
  fi
47
57
  }
48
58
 
49
- # ─── Structured Event Log ──────────────────────────────────────────────────
59
+ # ─── Daemon State ───────────────────────────────────────────────────────────
50
60
  EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
51
61
  DAEMON_STATE="${HOME}/.shipwright/daemon-state.json"
52
62
 
53
- emit_event() {
54
- local event_type="$1"
55
- shift
56
- local json_fields=""
57
- for kv in "$@"; do
58
- local key="${kv%%=*}"
59
- local val="${kv#*=}"
60
- if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
61
- json_fields="${json_fields},\"${key}\":${val}"
62
- else
63
- local escaped_val
64
- escaped_val=$(printf '%s' "$val" | jq -Rs '.' 2>/dev/null || printf '"%s"' "${val//\"/\\\"}")
65
- json_fields="${json_fields},\"${key}\":${escaped_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
  # ─── Daemon State Access ───────────────────────────────────────────────────
73
64
  load_daemon_state() {
74
65
  if [[ ! -f "$DAEMON_STATE" ]]; then
@@ -7,33 +7,43 @@
7
7
  set -euo pipefail
8
8
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
9
9
 
10
- VERSION="2.1.1"
10
+ VERSION="2.2.0"
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
17
 
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; }
18
+ # Canonical helpers (colors, output, events)
19
+ # shellcheck source=lib/helpers.sh
20
+ [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
21
+ # Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
22
+ [[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
23
+ [[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
24
+ [[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
25
+ [[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
26
+ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
27
+ now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
28
+ now_epoch() { date +%s; }
29
+ fi
30
+ if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
31
+ emit_event() {
32
+ local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
33
+ local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
34
+ while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
35
+ echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
36
+ }
37
+ fi
38
+ CYAN="${CYAN:-\033[38;2;0;212;255m}"
39
+ PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
40
+ BLUE="${BLUE:-\033[38;2;0;102;255m}"
41
+ GREEN="${GREEN:-\033[38;2;74;222;128m}"
42
+ YELLOW="${YELLOW:-\033[38;2;250;204;21m}"
43
+ RED="${RED:-\033[38;2;248;113;113m}"
44
+ DIM="${DIM:-\033[2m}"
45
+ BOLD="${BOLD:-\033[1m}"
46
+ RESET="${RESET:-\033[0m}"
37
47
 
38
48
  # ─── File Paths ────────────────────────────────────────────────────────────
39
49
  MODEL_ROUTING_CONFIG="${HOME}/.shipwright/model-routing.json"
@@ -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.1"
9
+ VERSION="2.2.0"
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
  # ─── State Directories ──────────────────────────────────────────────────────
38
48
  OTEL_DIR="${HOME}/.shipwright/otel"