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
|
@@ -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
|
|
|
@@ -112,7 +112,8 @@ gather_pipeline_state() {
|
|
|
112
112
|
# Read pipeline artifacts if available
|
|
113
113
|
if [[ -d "$pipeline_artifacts" ]]; then
|
|
114
114
|
local stage_count
|
|
115
|
-
stage_count=$(find "$pipeline_artifacts" -name "*.md" -o -name "*.json" | wc -l ||
|
|
115
|
+
stage_count=$(find "$pipeline_artifacts" -name "*.md" -o -name "*.json" | wc -l || true)
|
|
116
|
+
stage_count="${stage_count:-0}"
|
|
116
117
|
pipeline_data=$(jq --arg count "$stage_count" '.artifact_count = $count' <<<"$pipeline_data")
|
|
117
118
|
fi
|
|
118
119
|
|
package/scripts/sw-quality.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
|
|
|
@@ -16,6 +16,8 @@ REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
|
16
16
|
# Canonical helpers (colors, output, events)
|
|
17
17
|
# shellcheck source=lib/helpers.sh
|
|
18
18
|
[[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
|
|
19
|
+
# shellcheck source=lib/config.sh
|
|
20
|
+
[[ -f "$SCRIPT_DIR/lib/config.sh" ]] && source "$SCRIPT_DIR/lib/config.sh"
|
|
19
21
|
# Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
|
|
20
22
|
[[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
|
|
21
23
|
[[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
|
|
@@ -81,7 +83,8 @@ validate_quality() {
|
|
|
81
83
|
local uncommitted_pass=true
|
|
82
84
|
if [[ -d "$REPO_DIR/.git" ]]; then
|
|
83
85
|
local dirty_count
|
|
84
|
-
dirty_count=$(cd "$REPO_DIR" && git status --short 2>/dev/null | wc -l ||
|
|
86
|
+
dirty_count=$(cd "$REPO_DIR" && git status --short 2>/dev/null | wc -l || true)
|
|
87
|
+
dirty_count="${dirty_count:-0}"
|
|
85
88
|
if [[ "$dirty_count" -gt 0 ]]; then
|
|
86
89
|
uncommitted_pass=false
|
|
87
90
|
all_pass=false
|
|
@@ -102,14 +105,16 @@ validate_quality() {
|
|
|
102
105
|
json_output=$(echo "$json_output" | jq --arg tp "$todos_pass" '.checks.todos=$tp' 2>/dev/null || true)
|
|
103
106
|
fi
|
|
104
107
|
|
|
105
|
-
# Check 5:
|
|
108
|
+
# Check 5: Secrets patterns in diff
|
|
106
109
|
local secrets_pass=true
|
|
107
110
|
local secret_patterns="(password|secret|token|api[_-]?key|aws_access|private_key)"
|
|
111
|
+
local secret_threshold
|
|
112
|
+
secret_threshold=$(_config_get_int "quality.secret_threshold" 3 2>/dev/null || echo 3)
|
|
108
113
|
if [[ -d "$REPO_DIR/.git" ]]; then
|
|
109
114
|
local secret_count
|
|
110
115
|
secret_count=$(cd "$REPO_DIR" && git diff --cached 2>/dev/null | grep -ciE "$secret_patterns" || true)
|
|
111
116
|
secret_count="${secret_count:-0}"
|
|
112
|
-
if [[ "$secret_count" -gt
|
|
117
|
+
if [[ "$secret_count" -gt "$secret_threshold" ]]; then
|
|
113
118
|
secrets_pass=false
|
|
114
119
|
all_pass=false
|
|
115
120
|
fi
|
|
@@ -403,14 +408,16 @@ calculate_quality_score() {
|
|
|
403
408
|
# Security audit (20%)
|
|
404
409
|
local security_files=0
|
|
405
410
|
if [[ -d "$REPO_DIR" ]]; then
|
|
406
|
-
security_files=$(find "$REPO_DIR" -type f \( -name "*.js" -o -name "*.py" -o -name "*.go" \) 2>/dev/null | wc -l ||
|
|
411
|
+
security_files=$(find "$REPO_DIR" -type f \( -name "*.js" -o -name "*.py" -o -name "*.go" \) 2>/dev/null | wc -l || true)
|
|
412
|
+
security_files="${security_files:-0}"
|
|
407
413
|
security_score=$((security_files > 0 ? 85 : 0))
|
|
408
414
|
fi
|
|
409
415
|
|
|
410
416
|
# Architecture audit (15%)
|
|
411
417
|
local architecture_files=0
|
|
412
418
|
if [[ -d "$REPO_DIR" ]]; then
|
|
413
|
-
architecture_files=$(find "$REPO_DIR" -type f \( -name "*.js" -o -name "*.py" \) 2>/dev/null | wc -l ||
|
|
419
|
+
architecture_files=$(find "$REPO_DIR" -type f \( -name "*.js" -o -name "*.py" \) 2>/dev/null | wc -l || true)
|
|
420
|
+
architecture_files="${architecture_files:-0}"
|
|
414
421
|
architecture_score=$((architecture_files > 0 ? 80 : 0))
|
|
415
422
|
fi
|
|
416
423
|
|
package/scripts/sw-reaper.sh
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
# ║ shipwright reaper --watch Continuous loop (default: 5s) ║
|
|
12
12
|
# ║ shipwright reaper --dry-run Preview what would be reaped ║
|
|
13
13
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
14
|
-
VERSION="3.
|
|
14
|
+
VERSION="3.2.0"
|
|
15
15
|
set -euo pipefail
|
|
16
16
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
17
17
|
|
package/scripts/sw-recruit.sh
CHANGED
|
@@ -2026,7 +2026,7 @@ cmd_evaluate() {
|
|
|
2026
2026
|
echo " Tasks Completed: $(echo "$profile" | jq -r '.tasks_completed // "0"')"
|
|
2027
2027
|
echo ""
|
|
2028
2028
|
|
|
2029
|
-
# Use population-aware thresholds
|
|
2029
|
+
# Use population-aware thresholds for performance evaluation
|
|
2030
2030
|
local pop_stats
|
|
2031
2031
|
pop_stats=$(_recruit_compute_population_stats)
|
|
2032
2032
|
local mean_success
|
package/scripts/sw-regression.sh
CHANGED
package/scripts/sw-release.sh
CHANGED
|
@@ -7,7 +7,7 @@ set -euo pipefail
|
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
trap 'rm -f "${tmp_file:-}" "${tmp_changelog:-}"' EXIT
|
|
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
|
|
package/scripts/sw-remote.sh
CHANGED
package/scripts/sw-replay.sh
CHANGED
package/scripts/sw-retro.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-scale.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
|
# ─── Dependency check ─────────────────────────────────────────────────────────
|
|
@@ -357,7 +357,8 @@ cmd_status() {
|
|
|
357
357
|
fi
|
|
358
358
|
|
|
359
359
|
if [[ -f "$SCALE_EVENTS_FILE" ]]; then
|
|
360
|
-
event_count=$(wc -l < "$SCALE_EVENTS_FILE" ||
|
|
360
|
+
event_count=$(wc -l < "$SCALE_EVENTS_FILE" || true)
|
|
361
|
+
event_count="${event_count:-0}"
|
|
361
362
|
fi
|
|
362
363
|
|
|
363
364
|
local last_scale_time
|
|
@@ -445,7 +446,8 @@ cmd_recommend() {
|
|
|
445
446
|
local base_branch="${BASE_BRANCH:-main}"
|
|
446
447
|
if git rev-parse --verify "$base_branch" >/dev/null 2>&1; then
|
|
447
448
|
module_count=$(git diff --name-only "${base_branch}..HEAD" 2>/dev/null \
|
|
448
|
-
| sed 's|/[^/]*$||' | sort -u | wc -l
|
|
449
|
+
| sed 's|/[^/]*$||' | sort -u | wc -l || true)
|
|
450
|
+
module_count="${module_count:-0}"
|
|
449
451
|
fi
|
|
450
452
|
module_count="${module_count:-0}"
|
|
451
453
|
fi
|
|
@@ -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
|
|
|
@@ -1181,6 +1181,162 @@ optimize_evolve_memory() {
|
|
|
1181
1181
|
success "Memory evolved: pruned=$pruned, strengthened=$strengthened, promoted=$promoted"
|
|
1182
1182
|
}
|
|
1183
1183
|
|
|
1184
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
1185
|
+
# CONTEXT EFFICIENCY CLOSED LOOP
|
|
1186
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
1187
|
+
|
|
1188
|
+
# optimize_tune_context_efficiency
|
|
1189
|
+
# Read loop.context_efficiency events and recommend context budget adjustments.
|
|
1190
|
+
# If avg budget_utilization > 90%, recommend increasing context_budget_chars.
|
|
1191
|
+
# If avg trim_ratio > 30%, recommend reducing verbose context sections.
|
|
1192
|
+
optimize_tune_context_efficiency() {
|
|
1193
|
+
local events_file="${EVENTS_FILE:-${HOME}/.shipwright/events.jsonl}"
|
|
1194
|
+
|
|
1195
|
+
if [[ ! -f "$events_file" ]]; then
|
|
1196
|
+
info "No events file found — skipping context efficiency tuning"
|
|
1197
|
+
return 0
|
|
1198
|
+
fi
|
|
1199
|
+
|
|
1200
|
+
ensure_optimization_dir
|
|
1201
|
+
|
|
1202
|
+
info "Analyzing context efficiency..."
|
|
1203
|
+
|
|
1204
|
+
# Extract recent loop.context_efficiency events (last 200)
|
|
1205
|
+
local ctx_events
|
|
1206
|
+
ctx_events=$(grep '"loop.context_efficiency"' "$events_file" 2>/dev/null | tail -200 || true)
|
|
1207
|
+
|
|
1208
|
+
if [[ -z "$ctx_events" ]]; then
|
|
1209
|
+
info "No context efficiency events found — skipping"
|
|
1210
|
+
return 0
|
|
1211
|
+
fi
|
|
1212
|
+
|
|
1213
|
+
local event_count
|
|
1214
|
+
event_count=$(echo "$ctx_events" | wc -l | tr -d ' ')
|
|
1215
|
+
event_count="${event_count:-0}"
|
|
1216
|
+
|
|
1217
|
+
if [[ "$event_count" -lt 3 ]]; then
|
|
1218
|
+
info "Insufficient context efficiency events ($event_count) — need at least 3"
|
|
1219
|
+
return 0
|
|
1220
|
+
fi
|
|
1221
|
+
|
|
1222
|
+
# Calculate averages using jq (handles both string and numeric JSON values)
|
|
1223
|
+
local stats
|
|
1224
|
+
stats=$(echo "$ctx_events" | jq -rs '
|
|
1225
|
+
if length == 0 then {u:0,r:0,raw:0,tr:0,b:0,n:0}
|
|
1226
|
+
else {
|
|
1227
|
+
u: ([.[] | .budget_utilization | tonumber] | add / length),
|
|
1228
|
+
r: ([.[] | .trim_ratio | tonumber] | add / length),
|
|
1229
|
+
raw: ([.[] | .raw_prompt_chars | tonumber] | add / length),
|
|
1230
|
+
tr: ([.[] | .trimmed_prompt_chars | tonumber] | add / length),
|
|
1231
|
+
b: ([.[] | .budget_chars | tonumber] | last // 0),
|
|
1232
|
+
n: length
|
|
1233
|
+
} end
|
|
1234
|
+
| "\(.u) \(.r) \(.raw) \(.tr) \(.b) \(.n)"
|
|
1235
|
+
' 2>/dev/null || echo "0 0 0 0 0 0")
|
|
1236
|
+
|
|
1237
|
+
local avg_utilization avg_trim_ratio avg_raw avg_trimmed current_budget sample_count
|
|
1238
|
+
avg_utilization=$(echo "$stats" | awk '{printf "%.1f", $1}')
|
|
1239
|
+
avg_trim_ratio=$(echo "$stats" | awk '{printf "%.1f", $2}')
|
|
1240
|
+
avg_raw=$(echo "$stats" | awk '{printf "%.0f", $3}')
|
|
1241
|
+
avg_trimmed=$(echo "$stats" | awk '{printf "%.0f", $4}')
|
|
1242
|
+
current_budget=$(echo "$stats" | awk '{printf "%.0f", $5}')
|
|
1243
|
+
sample_count=$(echo "$stats" | awk '{printf "%d", $6}')
|
|
1244
|
+
|
|
1245
|
+
info "Context efficiency: avg_utilization=${avg_utilization}%, avg_trim_ratio=${avg_trim_ratio}%, samples=${sample_count}"
|
|
1246
|
+
|
|
1247
|
+
local recommendations=""
|
|
1248
|
+
local rec_count=0
|
|
1249
|
+
|
|
1250
|
+
# Rule 1: If avg budget_utilization > 90%, recommend increasing context_budget_chars
|
|
1251
|
+
if awk -v u="$avg_utilization" 'BEGIN { exit !(u > 90) }' 2>/dev/null; then
|
|
1252
|
+
local new_budget
|
|
1253
|
+
new_budget=$(awk -v b="$current_budget" 'BEGIN { printf "%.0f", b * 1.2 }')
|
|
1254
|
+
# Cap at 300000
|
|
1255
|
+
if awk -v nb="$new_budget" 'BEGIN { exit !(nb > 300000) }' 2>/dev/null; then
|
|
1256
|
+
new_budget=300000
|
|
1257
|
+
fi
|
|
1258
|
+
recommendations="${recommendations}increase_budget:${new_budget} "
|
|
1259
|
+
rec_count=$((rec_count + 1))
|
|
1260
|
+
warn "Budget utilization high (${avg_utilization}%) — recommend increasing context_budget_chars from ${current_budget} to ${new_budget}"
|
|
1261
|
+
|
|
1262
|
+
emit_event "optimize.context_recommendation" \
|
|
1263
|
+
"action=increase_budget" \
|
|
1264
|
+
"current=${current_budget}" \
|
|
1265
|
+
"recommended=${new_budget}" \
|
|
1266
|
+
"avg_utilization=${avg_utilization}" \
|
|
1267
|
+
"samples=${sample_count}"
|
|
1268
|
+
fi
|
|
1269
|
+
|
|
1270
|
+
# Rule 2: If avg trim_ratio > 30%, recommend reducing verbose context sections
|
|
1271
|
+
if awk -v r="$avg_trim_ratio" 'BEGIN { exit !(r > 30) }' 2>/dev/null; then
|
|
1272
|
+
local avg_discarded
|
|
1273
|
+
avg_discarded=$(awk -v raw="$avg_raw" -v trimmed="$avg_trimmed" 'BEGIN { printf "%.0f", raw - trimmed }')
|
|
1274
|
+
recommendations="${recommendations}reduce_verbose:${avg_discarded} "
|
|
1275
|
+
rec_count=$((rec_count + 1))
|
|
1276
|
+
warn "Trim ratio high (${avg_trim_ratio}%) — avg ${avg_discarded} chars discarded per iteration"
|
|
1277
|
+
warn "Recommend reducing verbose context: lower context_trim_memory_chars, context_trim_git_entries, or context_trim_test_lines"
|
|
1278
|
+
|
|
1279
|
+
emit_event "optimize.context_recommendation" \
|
|
1280
|
+
"action=reduce_verbose" \
|
|
1281
|
+
"avg_trim_ratio=${avg_trim_ratio}" \
|
|
1282
|
+
"avg_discarded=${avg_discarded}" \
|
|
1283
|
+
"samples=${sample_count}"
|
|
1284
|
+
fi
|
|
1285
|
+
|
|
1286
|
+
# Rule 3: If budget utilization is very low (<50%), recommend decreasing budget to save tokens
|
|
1287
|
+
if awk -v u="$avg_utilization" 'BEGIN { exit !(u < 50) }' 2>/dev/null && [[ "$sample_count" -ge 10 ]]; then
|
|
1288
|
+
local smaller_budget
|
|
1289
|
+
smaller_budget=$(awk -v b="$current_budget" 'BEGIN { printf "%.0f", b * 0.85 }')
|
|
1290
|
+
# Floor at 100000
|
|
1291
|
+
if awk -v sb="$smaller_budget" 'BEGIN { exit !(sb < 100000) }' 2>/dev/null; then
|
|
1292
|
+
smaller_budget=100000
|
|
1293
|
+
fi
|
|
1294
|
+
recommendations="${recommendations}decrease_budget:${smaller_budget} "
|
|
1295
|
+
rec_count=$((rec_count + 1))
|
|
1296
|
+
info "Budget utilization low (${avg_utilization}%) — recommend decreasing context_budget_chars from ${current_budget} to ${smaller_budget} to save tokens"
|
|
1297
|
+
|
|
1298
|
+
emit_event "optimize.context_recommendation" \
|
|
1299
|
+
"action=decrease_budget" \
|
|
1300
|
+
"current=${current_budget}" \
|
|
1301
|
+
"recommended=${smaller_budget}" \
|
|
1302
|
+
"avg_utilization=${avg_utilization}" \
|
|
1303
|
+
"samples=${sample_count}"
|
|
1304
|
+
fi
|
|
1305
|
+
|
|
1306
|
+
# Write context efficiency summary to optimization dir
|
|
1307
|
+
local summary_file="${OPTIMIZATION_DIR}/context-efficiency.json"
|
|
1308
|
+
local tmp_summary
|
|
1309
|
+
tmp_summary=$(mktemp "${summary_file}.tmp.XXXXXX")
|
|
1310
|
+
trap "rm -f '$tmp_summary'" RETURN
|
|
1311
|
+
jq -n \
|
|
1312
|
+
--argjson avg_utilization "$avg_utilization" \
|
|
1313
|
+
--argjson avg_trim_ratio "$avg_trim_ratio" \
|
|
1314
|
+
--argjson avg_raw "$avg_raw" \
|
|
1315
|
+
--argjson avg_trimmed "$avg_trimmed" \
|
|
1316
|
+
--argjson current_budget "${current_budget:-0}" \
|
|
1317
|
+
--argjson sample_count "$sample_count" \
|
|
1318
|
+
--argjson rec_count "$rec_count" \
|
|
1319
|
+
--arg recommendations "${recommendations}" \
|
|
1320
|
+
--arg updated "$(now_iso)" \
|
|
1321
|
+
'{
|
|
1322
|
+
avg_budget_utilization: $avg_utilization,
|
|
1323
|
+
avg_trim_ratio: $avg_trim_ratio,
|
|
1324
|
+
avg_raw_chars: $avg_raw,
|
|
1325
|
+
avg_trimmed_chars: $avg_trimmed,
|
|
1326
|
+
current_budget_chars: $current_budget,
|
|
1327
|
+
sample_count: $sample_count,
|
|
1328
|
+
recommendation_count: $rec_count,
|
|
1329
|
+
recommendations: $recommendations,
|
|
1330
|
+
updated_at: $updated
|
|
1331
|
+
}' > "$tmp_summary" && mv "$tmp_summary" "$summary_file" || rm -f "$tmp_summary"
|
|
1332
|
+
|
|
1333
|
+
if [[ "$rec_count" -eq 0 ]]; then
|
|
1334
|
+
success "Context efficiency is healthy (utilization: ${avg_utilization}%, trim: ${avg_trim_ratio}%)"
|
|
1335
|
+
else
|
|
1336
|
+
success "Context efficiency analysis complete — $rec_count recommendation(s)"
|
|
1337
|
+
fi
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1184
1340
|
# ═════════════════════════════════════════════════════════════════════════════
|
|
1185
1341
|
# QUALITY INDEX (LONGITUDINAL TRACKING)
|
|
1186
1342
|
# ═════════════════════════════════════════════════════════════════════════════
|
|
@@ -1206,10 +1362,14 @@ optimize_track_quality_index() {
|
|
|
1206
1362
|
[[ -z "$recent" ]] && return 0
|
|
1207
1363
|
|
|
1208
1364
|
local total success_count
|
|
1209
|
-
total=$(echo "$recent" | wc -l
|
|
1365
|
+
total=$(echo "$recent" | wc -l || true)
|
|
1366
|
+
total="${total:-0}"
|
|
1367
|
+
total=$(echo "$total" | tr -d ' ')
|
|
1210
1368
|
[[ "$total" -lt 3 ]] && return 0
|
|
1211
1369
|
|
|
1212
|
-
success_count=$(echo "$recent" | jq -c 'select(.result == "success" or .result == "completed")' 2>/dev/null | wc -l
|
|
1370
|
+
success_count=$(echo "$recent" | jq -c 'select(.result == "success" or .result == "completed")' 2>/dev/null | wc -l || true)
|
|
1371
|
+
success_count="${success_count:-0}"
|
|
1372
|
+
success_count=$(echo "$success_count" | tr -d ' ')
|
|
1213
1373
|
success_count="${success_count:-0}"
|
|
1214
1374
|
|
|
1215
1375
|
local avg_iterations avg_quality
|
|
@@ -1235,7 +1395,8 @@ optimize_track_quality_index() {
|
|
|
1235
1395
|
# Detect trend
|
|
1236
1396
|
if [[ -f "$quality_file" ]]; then
|
|
1237
1397
|
local line_count
|
|
1238
|
-
line_count=$(wc -l < "$quality_file" 2>/dev/null | tr -d ' ' ||
|
|
1398
|
+
line_count=$(wc -l < "$quality_file" 2>/dev/null | tr -d ' ' || true)
|
|
1399
|
+
line_count="${line_count:-0}"
|
|
1239
1400
|
if [[ "$line_count" -ge 2 ]]; then
|
|
1240
1401
|
local prev_index
|
|
1241
1402
|
prev_index=$(tail -2 "$quality_file" | head -1 | jq -r '.quality_index // 0' 2>/dev/null || echo "0")
|
|
@@ -1295,6 +1456,7 @@ optimize_full_analysis() {
|
|
|
1295
1456
|
optimize_route_models
|
|
1296
1457
|
optimize_learn_risk_keywords
|
|
1297
1458
|
optimize_evolve_memory
|
|
1459
|
+
optimize_tune_context_efficiency 2>/dev/null || true
|
|
1298
1460
|
optimize_track_quality_index 2>/dev/null || true
|
|
1299
1461
|
optimize_report >> "${OPTIMIZATION_DIR}/last-report.txt" 2>/dev/null || true
|
|
1300
1462
|
optimize_adjust_audit_intensity 2>/dev/null || true
|
|
@@ -1489,6 +1651,7 @@ show_help() {
|
|
|
1489
1651
|
echo " quality-index Show quality trend (last 10 snapshots)"
|
|
1490
1652
|
echo " ingest-retro Ingest most recent retro into optimization loop"
|
|
1491
1653
|
echo " evolve-memory Prune/strengthen/promote memory patterns"
|
|
1654
|
+
echo " context-efficiency Analyze context budget usage and recommend tuning"
|
|
1492
1655
|
echo " help Show this help"
|
|
1493
1656
|
echo ""
|
|
1494
1657
|
echo -e "${CYAN}STORAGE${RESET}"
|
|
@@ -1513,6 +1676,7 @@ main() {
|
|
|
1513
1676
|
report) optimize_report ;;
|
|
1514
1677
|
quality-index) cmd_quality_index ;;
|
|
1515
1678
|
evolve-memory) optimize_evolve_memory ;;
|
|
1679
|
+
context-efficiency) optimize_tune_context_efficiency ;;
|
|
1516
1680
|
help|--help|-h) show_help ;;
|
|
1517
1681
|
*) error "Unknown command: $cmd"; exit 1 ;;
|
|
1518
1682
|
esac
|
package/scripts/sw-session.sh
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
# ║ Supports --template to scaffold from a team template and --terminal ║
|
|
9
9
|
# ║ to select a terminal adapter (tmux, iterm2, wezterm). ║
|
|
10
10
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
11
|
-
VERSION="3.
|
|
11
|
+
VERSION="3.2.0"
|
|
12
12
|
set -euo pipefail
|
|
13
13
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
14
14
|
|
package/scripts/sw-setup.sh
CHANGED
package/scripts/sw-standup.sh
CHANGED
package/scripts/sw-status.sh
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# ║ ║
|
|
5
5
|
# ║ Shows running teams, agent windows, and task progress. ║
|
|
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-strategic.sh
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# When sourced, do NOT add set -euo pipefail — the parent handles that.
|
|
8
8
|
# When run directly, main() sets up the error handling.
|
|
9
9
|
|
|
10
|
-
VERSION="3.
|
|
10
|
+
VERSION="3.2.0"
|
|
11
11
|
|
|
12
12
|
# ─── Paths (set defaults if not provided by parent) ──────────────────────────
|
|
13
13
|
SCRIPT_DIR="${SCRIPT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
|
@@ -821,12 +821,14 @@ strategic_status() {
|
|
|
821
821
|
|
|
822
822
|
# Total issues created
|
|
823
823
|
local total_created
|
|
824
|
-
total_created=$(grep '"strategic.issue_created"' "$events_file" 2>/dev/null | wc -l | tr -d ' ' ||
|
|
824
|
+
total_created=$(grep '"strategic.issue_created"' "$events_file" 2>/dev/null | wc -l | tr -d ' ' || true)
|
|
825
|
+
total_created="${total_created:-0}"
|
|
825
826
|
echo -e " Total created: ${total_created} issues (all time)"
|
|
826
827
|
|
|
827
828
|
# Total cycles
|
|
828
829
|
local total_cycles
|
|
829
|
-
total_cycles=$(grep '"strategic.cycle_complete"' "$events_file" 2>/dev/null | wc -l | tr -d ' ' ||
|
|
830
|
+
total_cycles=$(grep '"strategic.cycle_complete"' "$events_file" 2>/dev/null | wc -l | tr -d ' ' || true)
|
|
831
|
+
total_cycles="${total_cycles:-0}"
|
|
830
832
|
echo -e " Total cycles: ${total_cycles}"
|
|
831
833
|
|
|
832
834
|
echo ""
|
|
@@ -845,9 +847,12 @@ strategic_outcomes() {
|
|
|
845
847
|
fi
|
|
846
848
|
|
|
847
849
|
local shipped_count failed_count pending_count
|
|
848
|
-
shipped_count=$(grep -c '"outcome":"shipped"' "$outcomes_file" 2>/dev/null ||
|
|
849
|
-
|
|
850
|
-
|
|
850
|
+
shipped_count=$(grep -c '"outcome":"shipped"' "$outcomes_file" 2>/dev/null || true)
|
|
851
|
+
shipped_count="${shipped_count:-0}"
|
|
852
|
+
failed_count=$(grep -cE '"outcome":"closed_unshipped"' "$outcomes_file" 2>/dev/null || true)
|
|
853
|
+
failed_count="${failed_count:-0}"
|
|
854
|
+
pending_count=$(grep -c '"outcome":"pending"' "$outcomes_file" 2>/dev/null || true)
|
|
855
|
+
pending_count="${pending_count:-0}"
|
|
851
856
|
|
|
852
857
|
echo -e " ${GREEN}Shipped:${RESET} $shipped_count (closed with merged PR)"
|
|
853
858
|
echo -e " ${RED}Closed unshipped:${RESET} $failed_count (closed without merge)"
|
package/scripts/sw-stream.sh
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# ║ Streams tmux pane output in real-time to the dashboard or CLI. ║
|
|
6
6
|
# ║ Captures output periodically, tags by agent/team, supports replay. ║
|
|
7
7
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
8
|
-
VERSION="3.
|
|
8
|
+
VERSION="3.2.0"
|
|
9
9
|
set -euo pipefail
|
|
10
10
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
11
11
|
|
|
@@ -113,7 +113,8 @@ capture_pane_output() {
|
|
|
113
113
|
|
|
114
114
|
# Trim to buffer size (keep latest N lines)
|
|
115
115
|
local line_count
|
|
116
|
-
line_count=$(wc -l < "$pane_file" 2>/dev/null ||
|
|
116
|
+
line_count=$(wc -l < "$pane_file" 2>/dev/null || true)
|
|
117
|
+
line_count="${line_count:-0}"
|
|
117
118
|
if [[ "$line_count" -gt "$BUFFER_LINES" ]]; then
|
|
118
119
|
local skip=$((line_count - BUFFER_LINES))
|
|
119
120
|
tail -n "$BUFFER_LINES" "$pane_file" > "${pane_file}.tmp"
|
|
@@ -273,8 +274,10 @@ stream_list() {
|
|
|
273
274
|
|
|
274
275
|
# Get file size and line count
|
|
275
276
|
local file_size lines_count
|
|
276
|
-
file_size=$(stat -f%z "$stream_file" 2>/dev/null || stat -c%s "$stream_file" 2>/dev/null ||
|
|
277
|
-
|
|
277
|
+
file_size=$(stat -f%z "$stream_file" 2>/dev/null || stat -c%s "$stream_file" 2>/dev/null || true)
|
|
278
|
+
file_size="${file_size:-0}"
|
|
279
|
+
lines_count=$(wc -l < "$stream_file" 2>/dev/null || true)
|
|
280
|
+
lines_count="${lines_count:-0}"
|
|
278
281
|
|
|
279
282
|
# Get latest timestamp
|
|
280
283
|
local latest_ts
|
package/scripts/sw-swarm.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
|
|
|
@@ -359,7 +359,8 @@ cmd_scale() {
|
|
|
359
359
|
fi
|
|
360
360
|
|
|
361
361
|
local current_agents
|
|
362
|
-
current_agents=$(tmux list-sessions -F '#{session_name}' 2>/dev/null | grep -cE '^shipwright-sw-agent|^swarm-' ||
|
|
362
|
+
current_agents=$(tmux list-sessions -F '#{session_name}' 2>/dev/null | grep -cE '^shipwright-sw-agent|^swarm-' || true)
|
|
363
|
+
current_agents="${current_agents:-0}"
|
|
363
364
|
|
|
364
365
|
local target_agents=1
|
|
365
366
|
if [[ "$queue_depth" -gt 5 ]]; then
|
package/scripts/sw-templates.sh
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# ║ Templates define reusable agent team configurations (roles, layout, ║
|
|
6
6
|
# ║ focus areas) that shipwright session --template can use to scaffold teams. ║
|
|
7
7
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
8
|
-
VERSION="3.
|
|
8
|
+
VERSION="3.2.0"
|
|
9
9
|
set -euo pipefail
|
|
10
10
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
11
11
|
|
|
@@ -82,8 +82,8 @@ json_agent_count() {
|
|
|
82
82
|
if command -v jq >/dev/null 2>&1; then
|
|
83
83
|
jq -r '.agents // [] | length' "$file" 2>/dev/null
|
|
84
84
|
else
|
|
85
|
-
grep -c '"name"' "$file" 2>/dev/null ||
|
|
86
|
-
fi
|
|
85
|
+
grep -c '"name"' "$file" 2>/dev/null || true
|
|
86
|
+
fi | tr -d ' ' | sed 's/^$/0/'
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
# Print agent details from a template
|