shipwright-cli 3.1.0 → 3.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/README.md +21 -7
- package/config/defaults.json +25 -2
- package/config/policy.json +1 -1
- package/dashboard/public/index.html +6 -0
- package/dashboard/public/styles.css +76 -0
- package/dashboard/server.ts +51 -0
- package/dashboard/src/core/api.ts +5 -0
- package/dashboard/src/types/api.ts +10 -0
- package/dashboard/src/views/metrics.ts +69 -1
- package/package.json +1 -1
- package/scripts/lib/daemon-adaptive.sh +4 -2
- package/scripts/lib/daemon-patrol.sh +2 -2
- package/scripts/lib/daemon-state.sh +7 -0
- package/scripts/lib/helpers.sh +3 -1
- package/scripts/lib/pipeline-detection.sh +1 -1
- package/scripts/lib/pipeline-intelligence.sh +5 -3
- package/scripts/lib/pipeline-quality-checks.sh +8 -4
- package/scripts/lib/pipeline-stages.sh +132 -2
- package/scripts/sw +1 -1
- package/scripts/sw-activity.sh +1 -7
- package/scripts/sw-adaptive.sh +7 -7
- package/scripts/sw-adversarial.sh +1 -1
- package/scripts/sw-architecture-enforcer.sh +1 -1
- package/scripts/sw-auth.sh +1 -1
- package/scripts/sw-autonomous.sh +1 -1
- package/scripts/sw-changelog.sh +1 -1
- package/scripts/sw-checkpoint.sh +1 -1
- package/scripts/sw-ci.sh +11 -6
- package/scripts/sw-cleanup.sh +1 -1
- package/scripts/sw-code-review.sh +36 -17
- package/scripts/sw-connect.sh +1 -1
- package/scripts/sw-context.sh +1 -1
- package/scripts/sw-cost.sh +60 -3
- package/scripts/sw-daemon.sh +5 -2
- package/scripts/sw-dashboard.sh +1 -1
- package/scripts/sw-db.sh +13 -5
- package/scripts/sw-decide.sh +1 -1
- package/scripts/sw-decompose.sh +1 -1
- package/scripts/sw-deps.sh +1 -1
- package/scripts/sw-developer-simulation.sh +1 -1
- package/scripts/sw-discovery.sh +54 -4
- package/scripts/sw-doc-fleet.sh +1 -1
- package/scripts/sw-docs-agent.sh +1 -1
- package/scripts/sw-docs.sh +1 -1
- package/scripts/sw-doctor.sh +1 -1
- package/scripts/sw-dora.sh +1 -1
- package/scripts/sw-durable.sh +9 -5
- package/scripts/sw-e2e-orchestrator.sh +1 -1
- package/scripts/sw-eventbus.sh +7 -4
- package/scripts/sw-evidence.sh +1 -1
- package/scripts/sw-feedback.sh +1 -1
- package/scripts/sw-fix.sh +1 -1
- package/scripts/sw-fleet-discover.sh +1 -1
- package/scripts/sw-fleet-viz.sh +6 -4
- package/scripts/sw-fleet.sh +1 -1
- package/scripts/sw-github-app.sh +3 -2
- package/scripts/sw-github-checks.sh +1 -1
- package/scripts/sw-github-deploy.sh +1 -1
- package/scripts/sw-github-graphql.sh +1 -1
- package/scripts/sw-guild.sh +1 -1
- package/scripts/sw-heartbeat.sh +1 -1
- package/scripts/sw-hygiene.sh +5 -3
- package/scripts/sw-incident.sh +9 -5
- package/scripts/sw-init.sh +1 -1
- package/scripts/sw-instrument.sh +1 -1
- package/scripts/sw-intelligence.sh +3 -2
- package/scripts/sw-jira.sh +1 -1
- package/scripts/sw-launchd.sh +1 -1
- package/scripts/sw-linear.sh +1 -1
- package/scripts/sw-logs.sh +1 -1
- package/scripts/sw-loop.sh +72 -16
- package/scripts/sw-memory.sh +2 -2
- package/scripts/sw-mission-control.sh +1 -1
- package/scripts/sw-model-router.sh +3 -2
- package/scripts/sw-otel.sh +4 -2
- package/scripts/sw-oversight.sh +1 -1
- package/scripts/sw-pipeline-composer.sh +3 -1
- package/scripts/sw-pipeline-vitals.sh +11 -6
- package/scripts/sw-pipeline.sh +20 -8
- package/scripts/sw-pm.sh +5 -4
- package/scripts/sw-pr-lifecycle.sh +1 -1
- package/scripts/sw-predictive.sh +11 -5
- package/scripts/sw-prep.sh +1 -1
- package/scripts/sw-ps.sh +1 -1
- package/scripts/sw-public-dashboard.sh +3 -2
- package/scripts/sw-quality.sh +13 -6
- package/scripts/sw-reaper.sh +1 -1
- package/scripts/sw-recruit.sh +1 -1
- package/scripts/sw-regression.sh +1 -1
- package/scripts/sw-release-manager.sh +1 -1
- package/scripts/sw-release.sh +1 -1
- package/scripts/sw-remote.sh +1 -1
- package/scripts/sw-replay.sh +1 -1
- package/scripts/sw-retro.sh +1 -1
- package/scripts/sw-review-rerun.sh +1 -1
- package/scripts/sw-scale.sh +5 -3
- package/scripts/sw-security-audit.sh +1 -1
- package/scripts/sw-self-optimize.sh +168 -4
- package/scripts/sw-session.sh +1 -1
- package/scripts/sw-setup.sh +1 -1
- package/scripts/sw-standup.sh +1 -1
- package/scripts/sw-status.sh +1 -1
- package/scripts/sw-strategic.sh +11 -6
- package/scripts/sw-stream.sh +7 -4
- package/scripts/sw-swarm.sh +3 -2
- package/scripts/sw-team-stages.sh +1 -1
- package/scripts/sw-templates.sh +3 -3
- package/scripts/sw-testgen.sh +11 -6
- package/scripts/sw-tmux-pipeline.sh +1 -1
- package/scripts/sw-tmux.sh +35 -1
- package/scripts/sw-trace.sh +1 -1
- package/scripts/sw-tracker.sh +1 -1
- package/scripts/sw-triage.sh +2 -2
- package/scripts/sw-upgrade.sh +1 -1
- package/scripts/sw-ux.sh +1 -1
- package/scripts/sw-webhook.sh +3 -2
- package/scripts/sw-widgets.sh +7 -4
- package/scripts/sw-worktree.sh +1 -1
package/scripts/sw-cost.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="3.
|
|
9
|
+
VERSION="3.2.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -154,7 +154,7 @@ cost_record() {
|
|
|
154
154
|
fi
|
|
155
155
|
local tmp_file
|
|
156
156
|
tmp_file=$(mktemp "${COST_FILE}.tmp.XXXXXX")
|
|
157
|
-
jq --argjson input "$input_tokens" \
|
|
157
|
+
if ! jq --argjson input "$input_tokens" \
|
|
158
158
|
--argjson output "$output_tokens" \
|
|
159
159
|
--arg model "$model" \
|
|
160
160
|
--arg stage "$stage" \
|
|
@@ -172,7 +172,16 @@ cost_record() {
|
|
|
172
172
|
ts: $ts,
|
|
173
173
|
ts_epoch: $epoch
|
|
174
174
|
}] | .entries = (.entries | .[-1000:])' \
|
|
175
|
-
"$COST_FILE" > "$tmp_file"
|
|
175
|
+
"$COST_FILE" > "$tmp_file" 2>/dev/null; then
|
|
176
|
+
error "Cost jq transformation failed — entry may be lost"
|
|
177
|
+
rm -f "$tmp_file"
|
|
178
|
+
# Continue without updating cost file
|
|
179
|
+
else
|
|
180
|
+
mv "$tmp_file" "$COST_FILE" || {
|
|
181
|
+
error "Failed to update cost file"
|
|
182
|
+
rm -f "$tmp_file"
|
|
183
|
+
}
|
|
184
|
+
fi
|
|
176
185
|
) 200>"${COST_FILE}.lock"
|
|
177
186
|
|
|
178
187
|
emit_event "cost.record" \
|
|
@@ -790,6 +799,54 @@ cost_dashboard() {
|
|
|
790
799
|
fi
|
|
791
800
|
fi
|
|
792
801
|
|
|
802
|
+
# Context efficiency (from loop.context_efficiency events)
|
|
803
|
+
local events_file="${HOME}/.shipwright/events.jsonl"
|
|
804
|
+
if [[ -f "$events_file" ]]; then
|
|
805
|
+
local ctx_events
|
|
806
|
+
ctx_events=$(grep '"type":"loop.context_efficiency"' "$events_file" 2>/dev/null | tail -200 || true)
|
|
807
|
+
local ctx_count
|
|
808
|
+
ctx_count=$(echo "$ctx_events" | grep -c '"loop.context_efficiency"' 2>/dev/null || echo "0")
|
|
809
|
+
ctx_count="${ctx_count:-0}"
|
|
810
|
+
|
|
811
|
+
if [[ "$ctx_count" -gt 0 ]]; then
|
|
812
|
+
# Parse metrics using awk (Bash 3.2 safe — no arrays needed)
|
|
813
|
+
local avg_utilization avg_trim_ratio total_raw total_trimmed trim_count
|
|
814
|
+
eval "$(echo "$ctx_events" | awk -F'"' '
|
|
815
|
+
/"loop.context_efficiency"/ {
|
|
816
|
+
for (i=1; i<=NF; i++) {
|
|
817
|
+
if ($i == "budget_utilization") util = $(i+2)
|
|
818
|
+
if ($i == "trim_ratio") ratio = $(i+2)
|
|
819
|
+
if ($i == "raw_prompt_chars") raw = $(i+2)
|
|
820
|
+
if ($i == "trimmed_prompt_chars") trimmed = $(i+2)
|
|
821
|
+
}
|
|
822
|
+
total_util += util; total_ratio += ratio
|
|
823
|
+
total_raw += raw; total_trimmed += trimmed
|
|
824
|
+
if (ratio + 0 > 0) trim_events++
|
|
825
|
+
n++
|
|
826
|
+
}
|
|
827
|
+
END {
|
|
828
|
+
if (n > 0) {
|
|
829
|
+
printf "avg_utilization=%.1f\n", total_util / n
|
|
830
|
+
printf "avg_trim_ratio=%.1f\n", total_ratio / n
|
|
831
|
+
} else {
|
|
832
|
+
printf "avg_utilization=0\navg_trim_ratio=0\n"
|
|
833
|
+
}
|
|
834
|
+
printf "total_raw=%d\ntotal_trimmed=%d\ntrim_count=%d\n", total_raw, total_trimmed, (trim_events+0)
|
|
835
|
+
}
|
|
836
|
+
')"
|
|
837
|
+
|
|
838
|
+
local total_discarded=$(( total_raw - total_trimmed ))
|
|
839
|
+
|
|
840
|
+
echo -e "${BOLD} CONTEXT EFFICIENCY${RESET}"
|
|
841
|
+
echo -e " Avg budget used ${avg_utilization}%"
|
|
842
|
+
echo -e " Avg trim ratio ${avg_trim_ratio}%"
|
|
843
|
+
echo -e " Chars generated $(printf "%'d" "$total_raw")"
|
|
844
|
+
echo -e " Chars discarded $(printf "%'d" "$total_discarded")"
|
|
845
|
+
echo -e " Trim events ${trim_count} / ${ctx_count} iterations"
|
|
846
|
+
echo ""
|
|
847
|
+
fi
|
|
848
|
+
fi
|
|
849
|
+
|
|
793
850
|
echo -e "${PURPLE}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
|
|
794
851
|
echo ""
|
|
795
852
|
}
|
package/scripts/sw-daemon.sh
CHANGED
|
@@ -8,8 +8,11 @@ trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
|
8
8
|
|
|
9
9
|
# Allow spawning Claude CLI from within a Claude Code session (daemon, fleet, etc.)
|
|
10
10
|
unset CLAUDECODE 2>/dev/null || true
|
|
11
|
+
# Ignore SIGHUP so daemon survives tmux attach/detach
|
|
12
|
+
trap '' HUP
|
|
13
|
+
trap '' SIGPIPE
|
|
11
14
|
|
|
12
|
-
VERSION="3.
|
|
15
|
+
VERSION="3.2.0"
|
|
13
16
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
17
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
15
18
|
|
|
@@ -554,7 +557,7 @@ setup_dirs() {
|
|
|
554
557
|
# ─── Adaptive Threshold Helpers ──────────────────────────────────────────────
|
|
555
558
|
# When intelligence.adaptive_enabled=true, operational thresholds are learned
|
|
556
559
|
# from historical data instead of using fixed defaults.
|
|
557
|
-
# Every function falls back to the
|
|
560
|
+
# Every function falls back to the config default when no data exists.
|
|
558
561
|
|
|
559
562
|
ADAPTIVE_THRESHOLDS_ENABLED="${ADAPTIVE_THRESHOLDS_ENABLED:-false}"
|
|
560
563
|
PRIORITY_STRATEGY="${PRIORITY_STRATEGY:-quick-wins-first}"
|
package/scripts/sw-dashboard.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="3.
|
|
9
|
+
VERSION="3.2.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
package/scripts/sw-db.sh
CHANGED
|
@@ -14,7 +14,7 @@ if [[ -n "${_SW_DB_LOADED:-}" ]] && [[ "${BASH_SOURCE[0]}" != "$0" ]]; then
|
|
|
14
14
|
fi
|
|
15
15
|
_SW_DB_LOADED=1
|
|
16
16
|
|
|
17
|
-
VERSION="3.
|
|
17
|
+
VERSION="3.2.0"
|
|
18
18
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
19
19
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
20
20
|
|
|
@@ -812,7 +812,9 @@ add_event() {
|
|
|
812
812
|
|
|
813
813
|
# Try SQLite first
|
|
814
814
|
if db_available; then
|
|
815
|
-
_db_exec "INSERT OR IGNORE INTO events (ts, ts_epoch, type, job_id, stage, status, duration_secs, metadata, created_at, synced) VALUES ('${ts}', ${ts_epoch}, '${event_type}', '${job_id}', '${stage}', '${status}', ${duration_secs}, '${metadata}', '${ts}', 0);"
|
|
815
|
+
if ! _db_exec "INSERT OR IGNORE INTO events (ts, ts_epoch, type, job_id, stage, status, duration_secs, metadata, created_at, synced) VALUES ('${ts}', ${ts_epoch}, '${event_type}', '${job_id}', '${stage}', '${status}', ${duration_secs}, '${metadata}', '${ts}', 0);" 2>/dev/null; then
|
|
816
|
+
warn "db_add_event: SQLite insert failed for event type=${event_type}" >&2
|
|
817
|
+
fi
|
|
816
818
|
fi
|
|
817
819
|
|
|
818
820
|
# Always write to JSONL for backward compat (dual-write period)
|
|
@@ -934,7 +936,9 @@ db_dequeue_next() {
|
|
|
934
936
|
next=$(_db_query "SELECT issue_key FROM daemon_queue ORDER BY added_at ASC LIMIT 1;" || echo "")
|
|
935
937
|
if [[ -n "$next" ]]; then
|
|
936
938
|
escaped="${next//$_SQL_SQ/$_SQL_SQ$_SQL_SQ}"
|
|
937
|
-
_db_exec "DELETE FROM daemon_queue WHERE issue_key = '${escaped}';" 2>/dev/null
|
|
939
|
+
if ! _db_exec "DELETE FROM daemon_queue WHERE issue_key = '${escaped}';" 2>/dev/null; then
|
|
940
|
+
warn "db_dequeue_next: failed to delete queue entry for ${next}" >&2
|
|
941
|
+
fi
|
|
938
942
|
echo "$next"
|
|
939
943
|
fi
|
|
940
944
|
}
|
|
@@ -1829,8 +1833,12 @@ main() {
|
|
|
1829
1833
|
ensure_db_dir
|
|
1830
1834
|
init_schema
|
|
1831
1835
|
# Set schema version
|
|
1832
|
-
_db_exec "INSERT OR REPLACE INTO _schema (version, created_at, applied_at) VALUES (${SCHEMA_VERSION}, '$(now_iso)', '$(now_iso)');" 2>/dev/null
|
|
1833
|
-
|
|
1836
|
+
if ! _db_exec "INSERT OR REPLACE INTO _schema (version, created_at, applied_at) VALUES (${SCHEMA_VERSION}, '$(now_iso)', '$(now_iso)');" 2>/dev/null; then
|
|
1837
|
+
warn "db init: failed to write schema version ${SCHEMA_VERSION}" >&2
|
|
1838
|
+
fi
|
|
1839
|
+
if ! _db_exec "INSERT OR IGNORE INTO _sync_metadata (key, value, updated_at) VALUES ('device_id', '$(uname -n)-$$-$(now_epoch)', '$(now_iso)');" 2>/dev/null; then
|
|
1840
|
+
warn "db init: failed to write device_id metadata" >&2
|
|
1841
|
+
fi
|
|
1834
1842
|
success "Database initialized at ${DB_FILE} (WAL mode, schema v${SCHEMA_VERSION})"
|
|
1835
1843
|
;;
|
|
1836
1844
|
migrate)
|
package/scripts/sw-decide.sh
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
|
|
8
|
-
VERSION="3.
|
|
8
|
+
VERSION="3.2.0"
|
|
9
9
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
10
10
|
|
|
11
11
|
# ─── Dependencies ─────────────────────────────────────────────────────────────
|
package/scripts/sw-decompose.sh
CHANGED
package/scripts/sw-deps.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="3.
|
|
9
|
+
VERSION="3.2.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
package/scripts/sw-discovery.sh
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
9
9
|
|
|
10
|
-
VERSION="3.
|
|
10
|
+
VERSION="3.2.0"
|
|
11
11
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
12
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
13
13
|
|
|
@@ -156,10 +156,60 @@ query_discoveries() {
|
|
|
156
156
|
fi
|
|
157
157
|
done < "$DISCOVERIES_FILE"
|
|
158
158
|
|
|
159
|
-
#
|
|
159
|
+
# Use Claude to rank candidates by relevance when there are many
|
|
160
160
|
if [[ "${INTELLIGENCE_ENABLED:-auto}" != "false" ]] && command -v claude &>/dev/null 2>&1 && [[ ${#candidates[@]} -gt 5 ]]; then
|
|
161
|
-
|
|
162
|
-
|
|
161
|
+
local ranked_json=""
|
|
162
|
+
local candidate_summaries=""
|
|
163
|
+
local idx=0
|
|
164
|
+
for line in "${candidates[@]+"${candidates[@]}"}"; do
|
|
165
|
+
local disc cat_name
|
|
166
|
+
disc=$(echo "$line" | jq -r '.discovery // ""' 2>/dev/null || echo "")
|
|
167
|
+
cat_name=$(echo "$line" | jq -r '.category // ""' 2>/dev/null || echo "")
|
|
168
|
+
candidate_summaries="${candidate_summaries}${idx}: [${cat_name}] ${disc}"$'\n'
|
|
169
|
+
idx=$((idx + 1))
|
|
170
|
+
done
|
|
171
|
+
|
|
172
|
+
local rank_prompt
|
|
173
|
+
rank_prompt="Given these discoveries and the query context '${query_context}', return a JSON array of indices sorted by relevance (most relevant first). Only return the JSON array, no explanation.
|
|
174
|
+
|
|
175
|
+
Discoveries:
|
|
176
|
+
${candidate_summaries}"
|
|
177
|
+
|
|
178
|
+
local _claude_timeout
|
|
179
|
+
_claude_timeout=30
|
|
180
|
+
local _timeout_cmd=""
|
|
181
|
+
if command -v gtimeout >/dev/null 2>&1; then _timeout_cmd="gtimeout $_claude_timeout"
|
|
182
|
+
elif command -v timeout >/dev/null 2>&1; then _timeout_cmd="timeout $_claude_timeout"
|
|
183
|
+
fi
|
|
184
|
+
|
|
185
|
+
ranked_json=$($_timeout_cmd claude -p "$rank_prompt" 2>/dev/null || true)
|
|
186
|
+
|
|
187
|
+
# Extract array from response (handle markdown fences)
|
|
188
|
+
local indices_str=""
|
|
189
|
+
if [[ -n "$ranked_json" ]]; then
|
|
190
|
+
indices_str=$(echo "$ranked_json" | sed -n 's/.*\(\[[ 0-9,]*\]\).*/\1/p' | head -1)
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
if [[ -n "$indices_str" ]] && echo "$indices_str" | jq -e 'type == "array"' >/dev/null 2>&1; then
|
|
194
|
+
local reordered=()
|
|
195
|
+
local seen=""
|
|
196
|
+
while IFS= read -r rank_idx; do
|
|
197
|
+
[[ -z "$rank_idx" ]] && continue
|
|
198
|
+
if [[ "$rank_idx" -ge 0 && "$rank_idx" -lt "${#candidates[@]}" ]]; then
|
|
199
|
+
# Avoid duplicates
|
|
200
|
+
case " $seen " in *" $rank_idx "*) continue ;; esac
|
|
201
|
+
seen="$seen $rank_idx"
|
|
202
|
+
reordered+=("${candidates[$rank_idx]}")
|
|
203
|
+
fi
|
|
204
|
+
done < <(echo "$indices_str" | jq -r '.[]' 2>/dev/null)
|
|
205
|
+
# Append any candidates not in the ranking
|
|
206
|
+
idx=0
|
|
207
|
+
for line in "${candidates[@]+"${candidates[@]}"}"; do
|
|
208
|
+
case " $seen " in *" $idx "*) ;; *) reordered+=("$line") ;; esac
|
|
209
|
+
idx=$((idx + 1))
|
|
210
|
+
done
|
|
211
|
+
candidates=("${reordered[@]+"${reordered[@]}"}")
|
|
212
|
+
fi
|
|
163
213
|
fi
|
|
164
214
|
|
|
165
215
|
# Output up to limit
|
package/scripts/sw-doc-fleet.sh
CHANGED
package/scripts/sw-docs-agent.sh
CHANGED
package/scripts/sw-docs.sh
CHANGED
package/scripts/sw-doctor.sh
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# ║ ║
|
|
5
5
|
# ║ Checks prerequisites, installed files, PATH, and common issues. ║
|
|
6
6
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
7
|
-
VERSION="3.
|
|
7
|
+
VERSION="3.2.0"
|
|
8
8
|
set -euo pipefail
|
|
9
9
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
10
10
|
|
package/scripts/sw-dora.sh
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
set -euo pipefail
|
|
9
9
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
10
10
|
|
|
11
|
-
VERSION="3.
|
|
11
|
+
VERSION="3.2.0"
|
|
12
12
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
13
|
|
|
14
14
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
package/scripts/sw-durable.sh
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
9
9
|
|
|
10
|
-
VERSION="3.
|
|
10
|
+
VERSION="3.2.0"
|
|
11
11
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
12
|
|
|
13
13
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
|
@@ -481,17 +481,21 @@ cmd_status() {
|
|
|
481
481
|
locks_dir="${DURABLE_DIR}/locks"
|
|
482
482
|
|
|
483
483
|
local log_events log_size
|
|
484
|
-
log_events=$(wc -l < "$log_file" 2>/dev/null ||
|
|
484
|
+
log_events=$(wc -l < "$log_file" 2>/dev/null || true)
|
|
485
|
+
log_events="${log_events:-0}"
|
|
485
486
|
log_size=$(du -h "$log_file" 2>/dev/null | awk '{print $1}' || echo "0")
|
|
486
487
|
|
|
487
488
|
local dlq_events
|
|
488
|
-
dlq_events=$(wc -l < "$dlq_file" 2>/dev/null ||
|
|
489
|
+
dlq_events=$(wc -l < "$dlq_file" 2>/dev/null || true)
|
|
490
|
+
dlq_events="${dlq_events:-0}"
|
|
489
491
|
|
|
490
492
|
local consumer_count
|
|
491
|
-
consumer_count=$(find "$offsets_dir" -name "consumer-*.offset" 2>/dev/null | wc -l ||
|
|
493
|
+
consumer_count=$(find "$offsets_dir" -name "consumer-*.offset" 2>/dev/null | wc -l || true)
|
|
494
|
+
consumer_count="${consumer_count:-0}"
|
|
492
495
|
|
|
493
496
|
local active_locks
|
|
494
|
-
active_locks=$(find "$locks_dir" -type d -mindepth 1 2>/dev/null | wc -l ||
|
|
497
|
+
active_locks=$(find "$locks_dir" -type d -mindepth 1 2>/dev/null | wc -l || true)
|
|
498
|
+
active_locks="${active_locks:-0}"
|
|
495
499
|
|
|
496
500
|
echo ""
|
|
497
501
|
echo -e "${CYAN}${BOLD} Durable Workflow Status${RESET} ${DIM}v${VERSION}${RESET}"
|
package/scripts/sw-eventbus.sh
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
9
9
|
|
|
10
|
-
VERSION="3.
|
|
10
|
+
VERSION="3.2.0"
|
|
11
11
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
12
|
|
|
13
13
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
|
@@ -251,7 +251,8 @@ cmd_status() {
|
|
|
251
251
|
fi
|
|
252
252
|
elif [[ -f "$EVENTS_FILE" ]]; then
|
|
253
253
|
local total_events last_event_ts
|
|
254
|
-
total_events=$(wc -l < "$EVENTS_FILE" ||
|
|
254
|
+
total_events=$(wc -l < "$EVENTS_FILE" || true)
|
|
255
|
+
total_events="${total_events:-0}"
|
|
255
256
|
last_event_ts=$(tail -1 "$EVENTS_FILE" | jq -r '.ts // "never"' 2>/dev/null || echo "never")
|
|
256
257
|
echo -e " ${CYAN}Event Store:${RESET} $EVENTS_FILE (file fallback)"
|
|
257
258
|
echo -e " ${CYAN}Total Events:${RESET} ${BOLD}${total_events}${RESET}"
|
|
@@ -290,7 +291,8 @@ cmd_clean() {
|
|
|
290
291
|
elif [[ -f "$EVENTS_FILE" ]]; then
|
|
291
292
|
info "Cleaning events older than ${ttl_days} days..."
|
|
292
293
|
local old_count tmp_file new_count removed
|
|
293
|
-
old_count=$(grep -c "ts" "$EVENTS_FILE" 2>/dev/null ||
|
|
294
|
+
old_count=$(grep -c "ts" "$EVENTS_FILE" 2>/dev/null || true)
|
|
295
|
+
old_count="${old_count:-0}"
|
|
294
296
|
tmp_file="$(mktemp)"
|
|
295
297
|
while IFS= read -r line; do
|
|
296
298
|
[[ -z "$line" ]] && continue
|
|
@@ -299,7 +301,8 @@ cmd_clean() {
|
|
|
299
301
|
[[ -n "$ts" && "$ts" > "$cutoff_iso" ]] && echo "$line" >> "$tmp_file"
|
|
300
302
|
done < "$EVENTS_FILE"
|
|
301
303
|
mv "$tmp_file" "$EVENTS_FILE"
|
|
302
|
-
new_count=$(wc -l < "$EVENTS_FILE" ||
|
|
304
|
+
new_count=$(wc -l < "$EVENTS_FILE" || true)
|
|
305
|
+
new_count="${new_count:-0}"
|
|
303
306
|
removed=$((old_count - new_count))
|
|
304
307
|
success "Removed $removed old events. Remaining: $new_count"
|
|
305
308
|
else
|
package/scripts/sw-evidence.sh
CHANGED
package/scripts/sw-feedback.sh
CHANGED
package/scripts/sw-fix.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="3.
|
|
9
|
+
VERSION="3.2.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
package/scripts/sw-fleet-viz.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="3.
|
|
9
|
+
VERSION="3.2.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -176,7 +176,7 @@ show_workers() {
|
|
|
176
176
|
echo -e "${BOLD}Remote Machines:${RESET}"
|
|
177
177
|
echo ""
|
|
178
178
|
|
|
179
|
-
if jq '.machines[]?' "$MACHINES_FILE" 2>/dev/null | grep -q
|
|
179
|
+
if jq '.machines[]?' "$MACHINES_FILE" 2>/dev/null | grep -q . 2>/dev/null; then
|
|
180
180
|
jq -r '.machines[]? | "\(.name) (\(.hostname)) — \(.status) — \(.active_jobs // 0) active"' "$MACHINES_FILE" 2>/dev/null | while read -r machine; do
|
|
181
181
|
echo -e " ${machine}"
|
|
182
182
|
done
|
|
@@ -205,8 +205,10 @@ show_insights() {
|
|
|
205
205
|
|
|
206
206
|
# Fleet-wide success rate (last 30 days)
|
|
207
207
|
local total_pipelines successful_pipelines
|
|
208
|
-
total_pipelines=$(grep '"type":"pipeline.completed"' "$EVENTS_FILE" 2>/dev/null | tail -5000 | wc -l ||
|
|
209
|
-
|
|
208
|
+
total_pipelines=$(grep '"type":"pipeline.completed"' "$EVENTS_FILE" 2>/dev/null | tail -5000 | wc -l || true)
|
|
209
|
+
total_pipelines="${total_pipelines:-0}"
|
|
210
|
+
successful_pipelines=$(grep '"type":"pipeline.completed".*"status":"success"' "$EVENTS_FILE" 2>/dev/null | tail -5000 | wc -l || true)
|
|
211
|
+
successful_pipelines="${successful_pipelines:-0}"
|
|
210
212
|
|
|
211
213
|
local success_rate=0
|
|
212
214
|
if [[ "$total_pipelines" -gt 0 ]]; then
|
package/scripts/sw-fleet.sh
CHANGED
package/scripts/sw-github-app.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="3.
|
|
9
|
+
VERSION="3.2.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -454,7 +454,8 @@ cmd_status() {
|
|
|
454
454
|
# Show recent webhook events
|
|
455
455
|
if [[ -f "$WEBHOOK_LOG" ]]; then
|
|
456
456
|
local count
|
|
457
|
-
count=$(wc -l < "$WEBHOOK_LOG" 2>/dev/null ||
|
|
457
|
+
count=$(wc -l < "$WEBHOOK_LOG" 2>/dev/null || true)
|
|
458
|
+
count="${count:-0}"
|
|
458
459
|
if [[ "$count" -gt 0 ]]; then
|
|
459
460
|
echo -e "${BOLD}Recent Webhook Events (last 10):${RESET}"
|
|
460
461
|
tail -10 "$WEBHOOK_LOG" | jq '{timestamp, event_type}' -c
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="3.
|
|
9
|
+
VERSION="3.2.0"
|
|
10
10
|
SCRIPT_DIR="${SCRIPT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
|
11
11
|
REPO_DIR="${REPO_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
|
|
12
12
|
|
package/scripts/sw-guild.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="3.
|
|
9
|
+
VERSION="3.2.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
package/scripts/sw-heartbeat.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="3.
|
|
9
|
+
VERSION="3.2.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
package/scripts/sw-hygiene.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="3.
|
|
9
|
+
VERSION="3.2.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -103,7 +103,8 @@ detect_dead_code() {
|
|
|
103
103
|
|
|
104
104
|
# Check if function is used in other files (count lines with this function name)
|
|
105
105
|
local usage_count
|
|
106
|
-
usage_count=$(grep -r "$func" "$REPO_DIR/scripts" --include="*.sh" 2>/dev/null | wc -l
|
|
106
|
+
usage_count=$(grep -r "$func" "$REPO_DIR/scripts" --include="*.sh" 2>/dev/null | wc -l || true)
|
|
107
|
+
usage_count="${usage_count:-0}"
|
|
107
108
|
usage_count=$(printf '%s' "$usage_count" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
108
109
|
|
|
109
110
|
# Function definition counts as 1 usage; if only 1, it's unused
|
|
@@ -417,7 +418,8 @@ scan_platform_refactor() {
|
|
|
417
418
|
sizes_file=$(mktemp)
|
|
418
419
|
find "$scripts_dir" -maxdepth 1 -name "*.sh" -type f 2>/dev/null | while read -r f; do
|
|
419
420
|
local lines
|
|
420
|
-
lines=$(wc -l < "$f" 2>/dev/null ||
|
|
421
|
+
lines=$(wc -l < "$f" 2>/dev/null || true)
|
|
422
|
+
lines="${lines:-0}"
|
|
421
423
|
printf '{"script":"%s","lines":%s}\n' "$(basename "$f")" "$lines"
|
|
422
424
|
done | jq -s 'sort_by(-.lines) | .[0:15]' 2>/dev/null > "$sizes_file"
|
|
423
425
|
local script_sizes
|
package/scripts/sw-incident.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="3.
|
|
9
|
+
VERSION="3.2.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -133,10 +133,14 @@ analyze_root_cause() {
|
|
|
133
133
|
local config="$2"
|
|
134
134
|
|
|
135
135
|
local timeout_hits error_hits memory_hits dependency_hits
|
|
136
|
-
timeout_hits=$(echo "$failure_log" | grep -ic "timeout\|deadline\|too slow" ||
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
136
|
+
timeout_hits=$(echo "$failure_log" | grep -ic "timeout\|deadline\|too slow" || true)
|
|
137
|
+
timeout_hits="${timeout_hits:-0}"
|
|
138
|
+
memory_hits=$(echo "$failure_log" | grep -ic "out of memory\|OOM\|heap" || true)
|
|
139
|
+
memory_hits="${memory_hits:-0}"
|
|
140
|
+
dependency_hits=$(echo "$failure_log" | grep -ic "dependency\|import\|require\|not found" || true)
|
|
141
|
+
dependency_hits="${dependency_hits:-0}"
|
|
142
|
+
error_hits=$(echo "$failure_log" | grep -c . || true)
|
|
143
|
+
error_hits="${error_hits:-0}"
|
|
140
144
|
|
|
141
145
|
if [[ "$timeout_hits" -gt 0 ]]; then
|
|
142
146
|
echo "Performance degradation: Timeout detected (${timeout_hits} occurrences)"
|