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
@@ -6,54 +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; }
36
-
37
- # ─── Structured Event Log ────────────────────────────────────────────────────
38
- EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
39
-
40
- emit_event() {
41
- local event_type="$1"
42
- shift
43
- local json_fields=""
44
- for kv in "$@"; do
45
- local key="${kv%%=*}"
46
- local val="${kv#*=}"
47
- if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
48
- json_fields="${json_fields},\"${key}\":${val}"
49
- else
50
- val="${val//\"/\\\"}"
51
- json_fields="${json_fields},\"${key}\":\"${val}\""
52
- fi
53
- done
54
- mkdir -p "${HOME}/.shipwright"
55
- echo "{\"ts\":\"$(now_iso)\",\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
56
- }
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}"
57
46
 
58
47
  # ─── Artifacts Directory ─────────────────────────────────────────────────────
59
48
  ARTIFACTS_DIR="${REPO_DIR}/.claude/pipeline-artifacts"
@@ -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.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
  # ─── 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
  # ─── Cache Configuration ───────────────────────────────────────────────────
59
51
  GH_CACHE_DIR="${HOME}/.shipwright/github-cache"
60
52
 
@@ -6,31 +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.1"
9
+ VERSION="2.2.0"
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} $*" >&2; }
31
- error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
32
-
33
- now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
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}"
34
45
 
35
46
  # ─── Guild Storage Paths ───────────────────────────────────────────────────
36
47
  GUILD_ROOT="${HOME}/.shipwright/guilds"
@@ -40,24 +51,6 @@ GUILD_DATA="${GUILD_ROOT}/guilds.json"
40
51
  # ─── Event Logging ────────────────────────────────────────────────────────
41
52
  EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
42
53
 
43
- emit_event() {
44
- local event_type="$1"
45
- shift
46
- local json_fields=""
47
- for kv in "$@"; do
48
- local key="${kv%%=*}"
49
- local val="${kv#*=}"
50
- if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
51
- json_fields="${json_fields},\"${key}\":${val}"
52
- else
53
- val="${val//\"/\\\"}"
54
- json_fields="${json_fields},\"${key}\":\"${val}\""
55
- fi
56
- done
57
- mkdir -p "${HOME}/.shipwright"
58
- echo "{\"ts\":\"$(now_iso)\",\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
59
- }
60
-
61
54
  # ─── Initialization ────────────────────────────────────────────────────────
62
55
  ensure_guild_dir() {
63
56
  mkdir -p "$GUILD_ROOT"
@@ -6,35 +6,46 @@
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
 
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
  # ─── Constants ──────────────────────────────────────────────────────────────
34
47
  HEARTBEAT_DIR="$HOME/.shipwright/heartbeats"
35
48
 
36
- now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
37
-
38
49
  # ─── Ensure heartbeat directory exists ──────────────────────────────────────
39
50
  ensure_dir() {
40
51
  mkdir -p "$HEARTBEAT_DIR"
@@ -6,50 +6,49 @@
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
-
28
- # ─── 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
- emit_event() {
16
+ # Policy (config/policy.json) — tunables override defaults when present
17
+ [[ -f "$SCRIPT_DIR/lib/policy.sh" ]] && source "$SCRIPT_DIR/lib/policy.sh"
18
+ # Canonical helpers (colors, output, events)
19
+ [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
20
+ # Fallback when helpers.sh not loaded
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 emit_event 2>/dev/null)" != "function" ]]; then
26
+ emit_event() {
35
27
  local event_type="$1"; shift
36
- local events_file="${HOME}/.shipwright/events.jsonl"
37
- mkdir -p "$(dirname "$events_file")"
28
+ mkdir -p "${HOME}/.shipwright"
38
29
  local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
39
- while [[ $# -gt 0 ]]; do
40
- local key="${1%%=*}" val="${1#*=}"
41
- payload="${payload},\"${key}\":\"${val}\""
42
- shift
43
- done
44
- payload="${payload}}"
45
- echo "$payload" >> "$events_file"
46
- }
47
-
48
- # ─── Default Settings ───────────────────────────────────────────────────────
30
+ while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
31
+ echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
32
+ }
33
+ fi
34
+ CYAN="${CYAN:-\033[38;2;0;212;255m}"
35
+ PURPLE="${PURPLE:-\033[38;2;124;58;237m}"
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}"
42
+ BLUE="${BLUE:-\033[38;2;0;102;255m}"
43
+
44
+ # ─── Default Settings (policy overrides when config/policy.json exists) ──────
49
45
  SUBCOMMAND="${1:-help}"
50
46
  AUTO_FIX=false
51
47
  VERBOSE=false
52
48
  ARTIFACT_AGE_DAYS=7
49
+ if type policy_get &>/dev/null 2>&1; then
50
+ ARTIFACT_AGE_DAYS=$(policy_get ".hygiene.artifact_age_days" "7")
51
+ fi
53
52
  JSON_OUTPUT=false
54
53
 
55
54
  # ─── Help ───────────────────────────────────────────────────────────────────
@@ -68,6 +67,7 @@ show_help() {
68
67
  echo -e " ${CYAN}naming${RESET} Check naming conventions (files, functions, vars)"
69
68
  echo -e " ${CYAN}branches${RESET} List stale and merged remote branches"
70
69
  echo -e " ${CYAN}size${RESET} Size analysis and bloat detection"
70
+ echo -e " ${CYAN}platform-refactor${RESET} Scan for hardcoded/fallback/TODO/FIXME — for AGI-level self-improvement"
71
71
  echo -e " ${CYAN}fix${RESET} Auto-fix safe issues (naming, whitespace)"
72
72
  echo -e " ${CYAN}report${RESET} Generate comprehensive hygiene report"
73
73
  echo -e " ${CYAN}help${RESET} Show this help message"
@@ -373,6 +373,84 @@ analyze_size() {
373
373
  return 0
374
374
  }
375
375
 
376
+ # ─── Platform Refactor / Hardcoded Scan (AGI-Level Self-Improvement) ───
377
+ # Outputs JSON to REPO_DIR/.claude/platform-hygiene.json for strategic agent.
378
+ scan_platform_refactor() {
379
+ info "Scanning for hardcoded/static/platform-refactor signals..."
380
+
381
+ mkdir -p "$REPO_DIR/.claude"
382
+ local out_file="$REPO_DIR/.claude/platform-hygiene.json"
383
+ local scripts_dir="${REPO_DIR}/scripts"
384
+
385
+ local hardcoded_count fallback_count todo_count fixme_count hack_count
386
+ hardcoded_count=$(grep -rE "hardcoded|Hardcoded|HARDCODED" "$scripts_dir" --include="*.sh" 2>/dev/null | wc -l | tr -d ' ')
387
+ fallback_count=$(grep -rE "Fallback:|fallback:" "$scripts_dir" --include="*.sh" 2>/dev/null | wc -l | tr -d ' ')
388
+ todo_count=$(grep -rE "TODO" "$scripts_dir" --include="*.sh" 2>/dev/null | wc -l | tr -d ' ')
389
+ fixme_count=$(grep -rE "FIXME" "$scripts_dir" --include="*.sh" 2>/dev/null | wc -l | tr -d ' ')
390
+ hack_count=$(grep -rE "HACK|KLUDGE" "$scripts_dir" --include="*.sh" 2>/dev/null | wc -l | tr -d ' ')
391
+ hardcoded_count=${hardcoded_count:-0}
392
+ fallback_count=${fallback_count:-0}
393
+ todo_count=${todo_count:-0}
394
+ fixme_count=${fixme_count:-0}
395
+ hack_count=${hack_count:-0}
396
+
397
+ # Sample findings: file:line (first 25) for strategic context (grep -n gives file:line:content)
398
+ local findings_file findings_raw
399
+ findings_file=$(mktemp)
400
+ findings_raw=$(mktemp)
401
+ grep -rnE "hardcoded|Hardcoded|Fallback:|fallback:|TODO|FIXME|HACK|KLUDGE" "$scripts_dir" --include="*.sh" 2>/dev/null | head -25 > "$findings_raw" || true
402
+ while IFS= read -r line; do
403
+ [[ -z "$line" ]] && continue
404
+ local f="${line%%:*}" rest="${line#*:}" ln="${rest%%:*}"
405
+ ln="${ln:-0}"
406
+ printf '{"file":"%s","line":%s}\n' "${f#$REPO_DIR/}" "$ln"
407
+ done < "$findings_raw" > "$findings_file.raw" 2>/dev/null || true
408
+ jq -s '.' "$findings_file.raw" 2>/dev/null > "$findings_file" || echo "[]" > "$findings_file"
409
+ local findings
410
+ findings=$(cat "$findings_file" 2>/dev/null || echo "[]")
411
+ rm -f "$findings_file" "$findings_file.raw" "$findings_raw"
412
+
413
+ # Script sizes (lines) for hotspot detection
414
+ local sizes_file
415
+ sizes_file=$(mktemp)
416
+ find "$scripts_dir" -maxdepth 1 -name "*.sh" -type f 2>/dev/null | while read -r f; do
417
+ local lines
418
+ lines=$(wc -l < "$f" 2>/dev/null || echo 0)
419
+ printf '{"script":"%s","lines":%s}\n' "$(basename "$f")" "$lines"
420
+ done | jq -s 'sort_by(-.lines) | .[0:15]' 2>/dev/null > "$sizes_file"
421
+ local script_sizes
422
+ script_sizes=$(cat "$sizes_file" 2>/dev/null || echo "[]")
423
+ rm -f "$sizes_file"
424
+
425
+ local timestamp
426
+ timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
427
+ local report
428
+ report=$(jq -n \
429
+ --arg ts "$timestamp" \
430
+ --arg repo "$(basename "$REPO_DIR")" \
431
+ --argjson hc "$hardcoded_count" \
432
+ --argjson fb "$fallback_count" \
433
+ --argjson todo "$todo_count" \
434
+ --argjson fixme "$fixme_count" \
435
+ --argjson hack "$hack_count" \
436
+ --argjson findings "$findings" \
437
+ --argjson script_sizes "$script_sizes" \
438
+ '{timestamp:$ts,repository:$repo,counts:{hardcoded:$hc,fallback:$fb,todo:$todo,fixme:$fixme,hack:$hack},findings_sample:$findings,script_size_hotspots:$script_sizes}' 2>/dev/null)
439
+ if [[ -n "$report" ]]; then
440
+ echo "$report" > "$out_file"
441
+ success "Platform refactor scan saved to: $out_file"
442
+ if [[ "$JSON_OUTPUT" == true ]]; then
443
+ echo "$report" | jq .
444
+ else
445
+ info " hardcoded: $hardcoded_count fallback: $fallback_count TODO: $todo_count FIXME: $fixme_count HACK/KLUDGE: $hack_count"
446
+ fi
447
+ else
448
+ warn "Could not build platform-hygiene JSON (jq missing?)"
449
+ fi
450
+ emit_event "hygiene_platform_refactor" "hardcoded=$hardcoded_count" "fallback=$fallback_count" "todo=$todo_count"
451
+ return 0
452
+ }
453
+
376
454
  # ─── Auto-Fix Mode ────────────────────────────────────────────────────────
377
455
 
378
456
  auto_fix_issues() {
@@ -446,29 +524,39 @@ generate_report() {
446
524
  info "Generating comprehensive hygiene report..."
447
525
  mkdir -p "$REPO_DIR/.claude"
448
526
 
527
+ # Include platform-hygiene if available (for strategic agent)
528
+ local platform_refactor="{}"
529
+ if [[ -f "$REPO_DIR/.claude/platform-hygiene.json" ]]; then
530
+ platform_refactor=$(jq -c '.' "$REPO_DIR/.claude/platform-hygiene.json" 2>/dev/null || echo "{}")
531
+ fi
532
+
449
533
  # Build JSON report
450
534
  local report
451
- report=$(cat <<'EOF'
535
+ report=$(jq -n \
536
+ --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
537
+ --arg repo "$(basename "$REPO_DIR")" \
538
+ --arg ver "$VERSION" \
539
+ --argjson platform "$platform_refactor" \
540
+ '{timestamp:$ts,repository:$repo,version:$ver,sections:{dead_code:{},structure:{},dependencies:{},naming:{},branches:{},size:{}},platform_refactor:$platform}' 2>/dev/null)
541
+ if [[ -z "$report" ]]; then
542
+ report=$(cat <<EOF
452
543
  {
453
- "timestamp": "TIMESTAMP",
454
- "repository": "REPO",
455
- "version": "VERSION",
544
+ "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
545
+ "repository": "$(basename "$REPO_DIR")",
546
+ "version": "$VERSION",
456
547
  "sections": {
457
548
  "dead_code": {},
458
549
  "structure": {},
459
550
  "dependencies": {},
460
551
  "naming": {},
461
552
  "branches": {},
462
- "size": {}
553
+ "size": {},
554
+ "platform_refactor": $platform_refactor
463
555
  }
464
556
  }
465
557
  EOF
466
558
  )
467
-
468
- # Replace placeholders
469
- report="${report//TIMESTAMP/$(date -u +%Y-%m-%dT%H:%M:%SZ)}"
470
- report="${report//REPO/$(basename "$REPO_DIR")}"
471
- report="${report//VERSION/$VERSION}"
559
+ fi
472
560
 
473
561
  if [[ $JSON_OUTPUT == true ]]; then
474
562
  echo "$report" | jq .
@@ -489,6 +577,7 @@ run_full_scan() {
489
577
  check_naming
490
578
  list_stale_branches
491
579
  analyze_size
580
+ scan_platform_refactor
492
581
 
493
582
  echo -e "${CYAN}${BOLD}╰────────────────────────────────────────────────────────────────╯${RESET}"
494
583
 
@@ -532,6 +621,9 @@ main() {
532
621
  size)
533
622
  analyze_size
534
623
  ;;
624
+ platform-refactor)
625
+ scan_platform_refactor
626
+ ;;
535
627
  fix)
536
628
  if [[ $AUTO_FIX != true ]]; then
537
629
  AUTO_FIX=true