shipwright-cli 2.1.2 → 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.
- package/.claude/agents/devops-engineer.md +14 -12
- package/.claude/agents/doc-fleet-agent.md +99 -0
- package/.claude/agents/test-specialist.md +5 -3
- package/README.md +48 -27
- package/claude-code/CLAUDE.md.shipwright +2 -2
- package/config/policy.json +73 -0
- package/config/policy.schema.json +75 -0
- package/docs/AGI-PLATFORM-PLAN.md +122 -0
- package/docs/AGI-WHATS-NEXT.md +69 -0
- package/docs/KNOWN-ISSUES.md +1 -23
- package/docs/PLATFORM-TODO-BACKLOG.md +41 -0
- package/docs/PLATFORM-TODO-TRIAGE.md +56 -0
- package/docs/README.md +83 -0
- package/docs/TIPS.md +39 -2
- package/docs/config-policy.md +40 -0
- package/docs/definition-of-done.example.md +2 -0
- package/docs/patterns/README.md +5 -0
- package/docs/strategy/02-mission-and-brand.md +3 -3
- package/docs/strategy/README.md +4 -3
- package/docs/tmux-research/TMUX-AUDIT.md +2 -0
- package/docs/tmux-research/TMUX-RESEARCH-INDEX.md +17 -0
- package/package.json +3 -2
- package/scripts/lib/daemon-health.sh +32 -0
- package/scripts/lib/pipeline-quality.sh +23 -0
- package/scripts/lib/policy.sh +32 -0
- package/scripts/sw +5 -1
- package/scripts/sw-activity.sh +35 -46
- package/scripts/sw-adaptive.sh +30 -39
- package/scripts/sw-adversarial.sh +30 -36
- package/scripts/sw-architecture-enforcer.sh +30 -33
- package/scripts/sw-auth.sh +30 -42
- package/scripts/sw-autonomous.sh +60 -40
- package/scripts/sw-changelog.sh +29 -30
- package/scripts/sw-checkpoint.sh +30 -18
- package/scripts/sw-ci.sh +30 -42
- package/scripts/sw-cleanup.sh +32 -15
- package/scripts/sw-code-review.sh +26 -32
- package/scripts/sw-connect.sh +30 -19
- package/scripts/sw-context.sh +30 -19
- package/scripts/sw-cost.sh +30 -40
- package/scripts/sw-daemon.sh +66 -36
- package/scripts/sw-dashboard.sh +31 -40
- package/scripts/sw-db.sh +30 -20
- package/scripts/sw-decompose.sh +30 -38
- package/scripts/sw-deps.sh +30 -41
- package/scripts/sw-developer-simulation.sh +30 -36
- package/scripts/sw-discovery.sh +36 -19
- package/scripts/sw-doc-fleet.sh +822 -0
- package/scripts/sw-docs-agent.sh +30 -36
- package/scripts/sw-docs.sh +29 -31
- package/scripts/sw-doctor.sh +52 -20
- package/scripts/sw-dora.sh +29 -34
- package/scripts/sw-durable.sh +30 -20
- package/scripts/sw-e2e-orchestrator.sh +36 -21
- package/scripts/sw-eventbus.sh +30 -17
- package/scripts/sw-feedback.sh +30 -41
- package/scripts/sw-fix.sh +30 -40
- package/scripts/sw-fleet-discover.sh +30 -41
- package/scripts/sw-fleet-viz.sh +30 -20
- package/scripts/sw-fleet.sh +30 -40
- package/scripts/sw-github-app.sh +30 -41
- package/scripts/sw-github-checks.sh +30 -41
- package/scripts/sw-github-deploy.sh +30 -41
- package/scripts/sw-github-graphql.sh +30 -38
- package/scripts/sw-guild.sh +30 -37
- package/scripts/sw-heartbeat.sh +30 -19
- package/scripts/sw-hygiene.sh +134 -42
- package/scripts/sw-incident.sh +30 -39
- package/scripts/sw-init.sh +31 -14
- package/scripts/sw-instrument.sh +30 -41
- package/scripts/sw-intelligence.sh +39 -44
- package/scripts/sw-jira.sh +31 -41
- package/scripts/sw-launchd.sh +30 -17
- package/scripts/sw-linear.sh +31 -41
- package/scripts/sw-logs.sh +32 -17
- package/scripts/sw-loop.sh +32 -19
- package/scripts/sw-memory.sh +32 -43
- package/scripts/sw-mission-control.sh +31 -40
- package/scripts/sw-model-router.sh +30 -20
- package/scripts/sw-otel.sh +30 -20
- package/scripts/sw-oversight.sh +30 -36
- package/scripts/sw-patrol-meta.sh +31 -0
- package/scripts/sw-pipeline-composer.sh +30 -39
- package/scripts/sw-pipeline-vitals.sh +30 -44
- package/scripts/sw-pipeline.sh +275 -6388
- package/scripts/sw-pm.sh +31 -41
- package/scripts/sw-pr-lifecycle.sh +30 -42
- package/scripts/sw-predictive.sh +32 -34
- package/scripts/sw-prep.sh +30 -19
- package/scripts/sw-ps.sh +32 -17
- package/scripts/sw-public-dashboard.sh +30 -40
- package/scripts/sw-quality.sh +42 -40
- package/scripts/sw-reaper.sh +32 -15
- package/scripts/sw-recruit.sh +428 -48
- package/scripts/sw-regression.sh +30 -38
- package/scripts/sw-release-manager.sh +30 -38
- package/scripts/sw-release.sh +29 -31
- package/scripts/sw-remote.sh +31 -40
- package/scripts/sw-replay.sh +30 -18
- package/scripts/sw-retro.sh +33 -42
- package/scripts/sw-scale.sh +41 -24
- package/scripts/sw-security-audit.sh +30 -20
- package/scripts/sw-self-optimize.sh +33 -37
- package/scripts/sw-session.sh +31 -15
- package/scripts/sw-setup.sh +30 -16
- package/scripts/sw-standup.sh +30 -20
- package/scripts/sw-status.sh +33 -13
- package/scripts/sw-strategic.sh +55 -43
- package/scripts/sw-stream.sh +33 -37
- package/scripts/sw-swarm.sh +30 -21
- package/scripts/sw-team-stages.sh +30 -38
- package/scripts/sw-templates.sh +31 -16
- package/scripts/sw-testgen.sh +30 -31
- package/scripts/sw-tmux-pipeline.sh +29 -31
- package/scripts/sw-tmux-role-color.sh +31 -0
- package/scripts/sw-tmux-status.sh +31 -0
- package/scripts/sw-tmux.sh +31 -15
- package/scripts/sw-trace.sh +30 -19
- package/scripts/sw-tracker-github.sh +31 -0
- package/scripts/sw-tracker-jira.sh +31 -0
- package/scripts/sw-tracker-linear.sh +31 -0
- package/scripts/sw-tracker.sh +30 -40
- package/scripts/sw-triage.sh +68 -61
- package/scripts/sw-upgrade.sh +30 -16
- package/scripts/sw-ux.sh +30 -35
- package/scripts/sw-webhook.sh +30 -25
- package/scripts/sw-widgets.sh +30 -19
- package/scripts/sw-worktree.sh +32 -15
- package/tmux/templates/doc-fleet.json +43 -0
package/scripts/sw-cost.sh
CHANGED
|
@@ -6,32 +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.
|
|
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
|
-
# ─── 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
16
|
|
|
33
|
-
|
|
34
|
-
|
|
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}"
|
|
35
46
|
|
|
36
47
|
format_duration() {
|
|
37
48
|
local secs="$1"
|
|
@@ -44,27 +55,6 @@ format_duration() {
|
|
|
44
55
|
fi
|
|
45
56
|
}
|
|
46
57
|
|
|
47
|
-
# ─── Structured Event Log ──────────────────────────────────────────────────
|
|
48
|
-
EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
|
|
49
|
-
|
|
50
|
-
emit_event() {
|
|
51
|
-
local event_type="$1"
|
|
52
|
-
shift
|
|
53
|
-
local json_fields=""
|
|
54
|
-
for kv in "$@"; do
|
|
55
|
-
local key="${kv%%=*}"
|
|
56
|
-
local val="${kv#*=}"
|
|
57
|
-
if [[ "$val" =~ ^-?[0-9]+\.?[0-9]*$ ]]; then
|
|
58
|
-
json_fields="${json_fields},\"${key}\":${val}"
|
|
59
|
-
else
|
|
60
|
-
val="${val//\"/\\\"}"
|
|
61
|
-
json_fields="${json_fields},\"${key}\":\"${val}\""
|
|
62
|
-
fi
|
|
63
|
-
done
|
|
64
|
-
mkdir -p "${HOME}/.shipwright"
|
|
65
|
-
echo "{\"ts\":\"$(now_iso)\",\"ts_epoch\":$(now_epoch),\"type\":\"${event_type}\"${json_fields}}" >> "$EVENTS_FILE"
|
|
66
|
-
}
|
|
67
|
-
|
|
68
58
|
# ─── Cost Storage ──────────────────────────────────────────────────────────
|
|
69
59
|
COST_DIR="${HOME}/.shipwright"
|
|
70
60
|
COST_FILE="${COST_DIR}/costs.json"
|
package/scripts/sw-daemon.sh
CHANGED
|
@@ -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.
|
|
12
|
+
VERSION="2.2.0"
|
|
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 (
|
|
636
|
+
# Stage-specific defaults (daemon-health.sh when sourced, else policy_get, else literal)
|
|
616
637
|
local default_timeout="${HEALTH_HEARTBEAT_TIMEOUT:-120}"
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
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
|
package/scripts/sw-dashboard.sh
CHANGED
|
@@ -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.
|
|
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
|
-
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
|
-
|
|
35
|
-
|
|
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.
|
|
17
|
+
VERSION="2.2.0"
|
|
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
|
-
#
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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"
|
package/scripts/sw-decompose.sh
CHANGED
|
@@ -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.
|
|
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
|
-
#
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
package/scripts/sw-deps.sh
CHANGED
|
@@ -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.
|
|
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
|
-
#
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
|
|
37
|
-
now_epoch() { date +%s; }
|
|
38
|
-
|
|
39
|
-
emit_event
|
|
40
|
-
|
|
41
|
-
shift
|
|
42
|
-
local
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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"
|