shipwright-cli 2.2.1 → 2.3.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 +19 -19
- package/dashboard/public/index.html +224 -8
- package/dashboard/public/styles.css +1078 -4
- package/dashboard/server.ts +1100 -15
- package/dashboard/src/canvas/interactions.ts +74 -0
- package/dashboard/src/canvas/layout.ts +85 -0
- package/dashboard/src/canvas/overlays.ts +117 -0
- package/dashboard/src/canvas/particles.ts +105 -0
- package/dashboard/src/canvas/renderer.ts +191 -0
- package/dashboard/src/components/charts/bar.ts +54 -0
- package/dashboard/src/components/charts/donut.ts +25 -0
- package/dashboard/src/components/charts/pipeline-rail.ts +105 -0
- package/dashboard/src/components/charts/sparkline.ts +82 -0
- package/dashboard/src/components/header.ts +616 -0
- package/dashboard/src/components/modal.ts +413 -0
- package/dashboard/src/components/terminal.ts +144 -0
- package/dashboard/src/core/api.ts +381 -0
- package/dashboard/src/core/helpers.ts +118 -0
- package/dashboard/src/core/router.ts +190 -0
- package/dashboard/src/core/sse.ts +38 -0
- package/dashboard/src/core/state.ts +150 -0
- package/dashboard/src/core/ws.ts +143 -0
- package/dashboard/src/design/icons.ts +131 -0
- package/dashboard/src/design/tokens.ts +160 -0
- package/dashboard/src/main.ts +68 -0
- package/dashboard/src/types/api.ts +337 -0
- package/dashboard/src/views/activity.ts +185 -0
- package/dashboard/src/views/agent-cockpit.ts +236 -0
- package/dashboard/src/views/agents.ts +72 -0
- package/dashboard/src/views/fleet-map.ts +299 -0
- package/dashboard/src/views/insights.ts +298 -0
- package/dashboard/src/views/machines.ts +162 -0
- package/dashboard/src/views/metrics.ts +420 -0
- package/dashboard/src/views/overview.ts +409 -0
- package/dashboard/src/views/pipeline-theater.ts +219 -0
- package/dashboard/src/views/pipelines.ts +595 -0
- package/dashboard/src/views/team.ts +362 -0
- package/dashboard/src/views/timeline.ts +389 -0
- package/dashboard/tsconfig.json +21 -0
- package/docs/AGI-PLATFORM-PLAN.md +5 -5
- package/docs/AGI-WHATS-NEXT.md +19 -16
- package/docs/README.md +2 -0
- package/package.json +8 -1
- package/scripts/check-version-consistency.sh +72 -0
- package/scripts/lib/daemon-adaptive.sh +610 -0
- package/scripts/lib/daemon-dispatch.sh +489 -0
- package/scripts/lib/daemon-failure.sh +387 -0
- package/scripts/lib/daemon-patrol.sh +1113 -0
- package/scripts/lib/daemon-poll.sh +1202 -0
- package/scripts/lib/daemon-state.sh +550 -0
- package/scripts/lib/daemon-triage.sh +490 -0
- package/scripts/lib/helpers.sh +81 -0
- package/scripts/lib/pipeline-intelligence.sh +0 -6
- package/scripts/lib/pipeline-quality-checks.sh +3 -1
- package/scripts/lib/pipeline-stages.sh +20 -0
- package/scripts/sw +109 -168
- package/scripts/sw-activity.sh +1 -1
- package/scripts/sw-adaptive.sh +2 -2
- package/scripts/sw-adversarial.sh +1 -1
- package/scripts/sw-architecture-enforcer.sh +1 -1
- package/scripts/sw-auth.sh +14 -6
- package/scripts/sw-autonomous.sh +1 -1
- package/scripts/sw-changelog.sh +2 -2
- package/scripts/sw-checkpoint.sh +1 -1
- package/scripts/sw-ci.sh +1 -1
- package/scripts/sw-cleanup.sh +1 -1
- package/scripts/sw-code-review.sh +1 -1
- package/scripts/sw-connect.sh +1 -1
- package/scripts/sw-context.sh +1 -1
- package/scripts/sw-cost.sh +1 -1
- package/scripts/sw-daemon.sh +53 -4817
- package/scripts/sw-dashboard.sh +1 -1
- package/scripts/sw-db.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 +1 -1
- 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 +49 -1
- package/scripts/sw-dora.sh +1 -1
- package/scripts/sw-durable.sh +1 -1
- package/scripts/sw-e2e-orchestrator.sh +1 -1
- package/scripts/sw-eventbus.sh +1 -1
- package/scripts/sw-feedback.sh +1 -1
- package/scripts/sw-fix.sh +6 -5
- package/scripts/sw-fleet-discover.sh +1 -1
- package/scripts/sw-fleet-viz.sh +3 -3
- package/scripts/sw-fleet.sh +1 -1
- package/scripts/sw-github-app.sh +5 -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 +1 -1
- package/scripts/sw-incident.sh +1 -1
- package/scripts/sw-init.sh +112 -9
- package/scripts/sw-instrument.sh +6 -1
- package/scripts/sw-intelligence.sh +5 -1
- package/scripts/sw-jira.sh +1 -1
- package/scripts/sw-launchd.sh +1 -1
- package/scripts/sw-linear.sh +20 -9
- package/scripts/sw-logs.sh +1 -1
- package/scripts/sw-loop.sh +2 -1
- package/scripts/sw-memory.sh +10 -1
- package/scripts/sw-mission-control.sh +1 -1
- package/scripts/sw-model-router.sh +4 -1
- package/scripts/sw-otel.sh +4 -4
- package/scripts/sw-oversight.sh +1 -1
- package/scripts/sw-pipeline-composer.sh +3 -1
- package/scripts/sw-pipeline-vitals.sh +4 -6
- package/scripts/sw-pipeline.sh +19 -56
- package/scripts/sw-pipeline.sh.mock +7 -0
- package/scripts/sw-pm.sh +5 -2
- package/scripts/sw-pr-lifecycle.sh +1 -1
- package/scripts/sw-predictive.sh +4 -1
- package/scripts/sw-prep.sh +3 -2
- package/scripts/sw-ps.sh +1 -1
- package/scripts/sw-public-dashboard.sh +10 -4
- package/scripts/sw-quality.sh +1 -1
- package/scripts/sw-reaper.sh +1 -1
- package/scripts/sw-recruit.sh +25 -1
- package/scripts/sw-regression.sh +2 -1
- package/scripts/sw-release-manager.sh +1 -1
- package/scripts/sw-release.sh +7 -5
- package/scripts/sw-remote.sh +1 -1
- package/scripts/sw-replay.sh +1 -1
- package/scripts/sw-retro.sh +1 -1
- package/scripts/sw-scale.sh +11 -5
- package/scripts/sw-security-audit.sh +1 -1
- package/scripts/sw-self-optimize.sh +172 -7
- package/scripts/sw-session.sh +1 -1
- package/scripts/sw-setup.sh +1 -1
- package/scripts/sw-standup.sh +4 -3
- package/scripts/sw-status.sh +1 -1
- package/scripts/sw-strategic.sh +2 -1
- package/scripts/sw-stream.sh +8 -2
- package/scripts/sw-swarm.sh +12 -10
- package/scripts/sw-team-stages.sh +1 -1
- package/scripts/sw-templates.sh +1 -1
- package/scripts/sw-testgen.sh +3 -2
- package/scripts/sw-tmux-pipeline.sh +2 -1
- package/scripts/sw-tmux.sh +1 -1
- package/scripts/sw-trace.sh +1 -1
- package/scripts/sw-tracker-jira.sh +1 -0
- package/scripts/sw-tracker-linear.sh +1 -0
- package/scripts/sw-tracker.sh +24 -6
- package/scripts/sw-triage.sh +1 -1
- package/scripts/sw-upgrade.sh +1 -1
- package/scripts/sw-ux.sh +1 -1
- package/scripts/sw-webhook.sh +1 -1
- package/scripts/sw-widgets.sh +2 -2
- package/scripts/sw-worktree.sh +1 -1
- package/dashboard/public/app.js +0 -4422
|
@@ -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="2.
|
|
9
|
+
VERSION="2.3.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="${REPO_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
|
|
12
12
|
|
|
@@ -75,6 +75,7 @@ _intelligence_track_cache_access() {
|
|
|
75
75
|
|
|
76
76
|
local tmp_file
|
|
77
77
|
tmp_file=$(mktemp "${TMPDIR:-/tmp}/sw-cache-stats.XXXXXX")
|
|
78
|
+
trap "rm -f '$tmp_file'" RETURN
|
|
78
79
|
if [[ "$hit_or_miss" == "hit" ]]; then
|
|
79
80
|
jq '.hits += 1 | .total += 1' "$CACHE_STATS_FILE" > "$tmp_file" && mv "$tmp_file" "$CACHE_STATS_FILE" || rm -f "$tmp_file"
|
|
80
81
|
else
|
|
@@ -118,6 +119,7 @@ _intelligence_adjust_cache_ttl() {
|
|
|
118
119
|
if [[ "$new_ttl" != "$current_ttl" ]]; then
|
|
119
120
|
local tmp_file
|
|
120
121
|
tmp_file=$(mktemp "${TMPDIR:-/tmp}/sw-cache-ttl.XXXXXX")
|
|
122
|
+
trap "rm -f '$tmp_file'" RETURN
|
|
121
123
|
jq -n \
|
|
122
124
|
--argjson ttl "$new_ttl" \
|
|
123
125
|
--argjson miss_rate "$miss_rate" \
|
|
@@ -134,6 +136,7 @@ _intelligence_adjust_cache_ttl() {
|
|
|
134
136
|
# Reset stats for next window
|
|
135
137
|
local tmp_reset
|
|
136
138
|
tmp_reset=$(mktemp "${TMPDIR:-/tmp}/sw-cache-reset.XXXXXX")
|
|
139
|
+
trap "rm -f '$tmp_reset'" RETURN
|
|
137
140
|
echo '{"hits":0,"misses":0,"total":0}' > "$tmp_reset" && mv "$tmp_reset" "$CACHE_STATS_FILE" || rm -f "$tmp_reset"
|
|
138
141
|
}
|
|
139
142
|
|
|
@@ -212,6 +215,7 @@ _intelligence_cache_set() {
|
|
|
212
215
|
|
|
213
216
|
local tmp_file
|
|
214
217
|
tmp_file=$(mktemp "${TMPDIR:-/tmp}/sw-intel-cache.XXXXXX")
|
|
218
|
+
trap "rm -f '$tmp_file'" RETURN
|
|
215
219
|
jq --arg h "$hash" \
|
|
216
220
|
--argjson result "$result" \
|
|
217
221
|
--argjson ts "$now" \
|
package/scripts/sw-jira.sh
CHANGED
package/scripts/sw-launchd.sh
CHANGED
package/scripts/sw-linear.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="2.
|
|
9
|
+
VERSION="2.3.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -48,12 +48,14 @@ RESET="${RESET:-\033[0m}"
|
|
|
48
48
|
CONFIG_DIR="${HOME}/.shipwright"
|
|
49
49
|
LINEAR_CONFIG="${CONFIG_DIR}/linear-config.json"
|
|
50
50
|
|
|
51
|
-
# Linear Status IDs
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
# Linear Status IDs — loaded from config, with env var overrides
|
|
52
|
+
# Configure via: shipwright tracker init --provider linear
|
|
53
|
+
# Or set env vars: LINEAR_STATUS_BACKLOG, LINEAR_STATUS_TODO, etc.
|
|
54
|
+
STATUS_BACKLOG="${LINEAR_STATUS_BACKLOG:-}"
|
|
55
|
+
STATUS_TODO="${LINEAR_STATUS_TODO:-}"
|
|
56
|
+
STATUS_IN_PROGRESS="${LINEAR_STATUS_IN_PROGRESS:-}"
|
|
57
|
+
STATUS_IN_REVIEW="${LINEAR_STATUS_IN_REVIEW:-}"
|
|
58
|
+
STATUS_DONE="${LINEAR_STATUS_DONE:-}"
|
|
57
59
|
|
|
58
60
|
LINEAR_API="https://api.linear.app/graphql"
|
|
59
61
|
|
|
@@ -65,8 +67,17 @@ load_config() {
|
|
|
65
67
|
fi
|
|
66
68
|
|
|
67
69
|
LINEAR_API_KEY="${LINEAR_API_KEY:-}"
|
|
68
|
-
LINEAR_TEAM_ID="${LINEAR_TEAM_ID
|
|
69
|
-
LINEAR_PROJECT_ID="${LINEAR_PROJECT_ID
|
|
70
|
+
LINEAR_TEAM_ID="${LINEAR_TEAM_ID:-$(jq -r '.team_id // empty' "$LINEAR_CONFIG" 2>/dev/null || true)}"
|
|
71
|
+
LINEAR_PROJECT_ID="${LINEAR_PROJECT_ID:-$(jq -r '.project_id // empty' "$LINEAR_CONFIG" 2>/dev/null || true)}"
|
|
72
|
+
|
|
73
|
+
# Load status IDs from config if not set via env
|
|
74
|
+
if [[ -f "$LINEAR_CONFIG" ]]; then
|
|
75
|
+
STATUS_BACKLOG="${STATUS_BACKLOG:-$(jq -r '.status_ids.backlog // empty' "$LINEAR_CONFIG" 2>/dev/null || true)}"
|
|
76
|
+
STATUS_TODO="${STATUS_TODO:-$(jq -r '.status_ids.todo // empty' "$LINEAR_CONFIG" 2>/dev/null || true)}"
|
|
77
|
+
STATUS_IN_PROGRESS="${STATUS_IN_PROGRESS:-$(jq -r '.status_ids.in_progress // empty' "$LINEAR_CONFIG" 2>/dev/null || true)}"
|
|
78
|
+
STATUS_IN_REVIEW="${STATUS_IN_REVIEW:-$(jq -r '.status_ids.in_review // empty' "$LINEAR_CONFIG" 2>/dev/null || true)}"
|
|
79
|
+
STATUS_DONE="${STATUS_DONE:-$(jq -r '.status_ids.done // empty' "$LINEAR_CONFIG" 2>/dev/null || true)}"
|
|
80
|
+
fi
|
|
70
81
|
}
|
|
71
82
|
|
|
72
83
|
check_api_key() {
|
package/scripts/sw-logs.sh
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# ║ ║
|
|
5
5
|
# ║ Captures tmux pane scrollback and provides log browsing/search. ║
|
|
6
6
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
7
|
-
VERSION="2.
|
|
7
|
+
VERSION="2.3.0"
|
|
8
8
|
set -euo pipefail
|
|
9
9
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
10
10
|
|
package/scripts/sw-loop.sh
CHANGED
|
@@ -71,7 +71,7 @@ MAX_RESTARTS=0
|
|
|
71
71
|
SESSION_RESTART=false
|
|
72
72
|
RESTART_COUNT=0
|
|
73
73
|
REPO_OVERRIDE=""
|
|
74
|
-
VERSION="2.
|
|
74
|
+
VERSION="2.3.0"
|
|
75
75
|
|
|
76
76
|
# ─── Token Tracking ─────────────────────────────────────────────────────────
|
|
77
77
|
LOOP_INPUT_TOKENS=0
|
|
@@ -531,6 +531,7 @@ write_loop_tokens() {
|
|
|
531
531
|
fi
|
|
532
532
|
local tmp_file
|
|
533
533
|
tmp_file=$(mktemp "${token_file}.XXXXXX" 2>/dev/null || mktemp)
|
|
534
|
+
trap "rm -f '$tmp_file'" RETURN
|
|
534
535
|
cat > "$tmp_file" <<TOKJSON
|
|
535
536
|
{"input_tokens":${LOOP_INPUT_TOKENS},"output_tokens":${LOOP_OUTPUT_TOKENS},"cost_usd":${cost_usd},"iterations":${ITERATION:-0}}
|
|
536
537
|
TOKJSON
|
package/scripts/sw-memory.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="2.
|
|
9
|
+
VERSION="2.3.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="${REPO_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
|
|
12
12
|
|
|
@@ -150,6 +150,7 @@ memory_capture_pipeline() {
|
|
|
150
150
|
# Record review patterns to global memory for cross-repo learning
|
|
151
151
|
local tmp_global
|
|
152
152
|
tmp_global=$(mktemp)
|
|
153
|
+
trap "rm -f '$tmp_global'" RETURN
|
|
153
154
|
jq --arg repo "$repo" \
|
|
154
155
|
--arg ts "$captured_at" \
|
|
155
156
|
--argjson bugs "${bug_count:-0}" \
|
|
@@ -211,6 +212,7 @@ memory_capture_failure() {
|
|
|
211
212
|
fi
|
|
212
213
|
local tmp_file
|
|
213
214
|
tmp_file=$(mktemp "${failures_file}.tmp.XXXXXX")
|
|
215
|
+
trap "rm -f '$tmp_file'" EXIT
|
|
214
216
|
|
|
215
217
|
if [[ "$existing_idx" != "-1" && "$existing_idx" != "null" ]]; then
|
|
216
218
|
# Update existing entry
|
|
@@ -277,6 +279,7 @@ memory_record_fix_outcome() {
|
|
|
277
279
|
fi
|
|
278
280
|
local tmp_file
|
|
279
281
|
tmp_file=$(mktemp "${failures_file}.tmp.XXXXXX")
|
|
282
|
+
trap "rm -f '$tmp_file'" EXIT
|
|
280
283
|
|
|
281
284
|
jq --argjson idx "$match_idx" \
|
|
282
285
|
--argjson app "$applied_inc" \
|
|
@@ -442,6 +445,7 @@ _memory_aggregate_global() {
|
|
|
442
445
|
# Add to global, cap at 100 entries
|
|
443
446
|
local tmp_global
|
|
444
447
|
tmp_global=$(mktemp "${global_file}.tmp.XXXXXX")
|
|
448
|
+
trap "rm -f '$tmp_global'" RETURN
|
|
445
449
|
jq --arg p "$pattern" \
|
|
446
450
|
--arg ts "$(now_iso)" \
|
|
447
451
|
--arg cat "general" \
|
|
@@ -593,6 +597,7 @@ Return JSON only, no markdown fences, no explanation."
|
|
|
593
597
|
# Update the most recent failure entry with root_cause, fix, category
|
|
594
598
|
local tmp_file
|
|
595
599
|
tmp_file=$(mktemp)
|
|
600
|
+
trap "rm -f '$tmp_file'" RETURN
|
|
596
601
|
jq --arg rc "$root_cause" \
|
|
597
602
|
--arg fix "$fix" \
|
|
598
603
|
--arg cat "$category" \
|
|
@@ -622,6 +627,7 @@ memory_capture_pattern() {
|
|
|
622
627
|
|
|
623
628
|
local tmp_file
|
|
624
629
|
tmp_file=$(mktemp)
|
|
630
|
+
trap "rm -f '$tmp_file'" RETURN
|
|
625
631
|
|
|
626
632
|
case "$pattern_type" in
|
|
627
633
|
project)
|
|
@@ -1112,6 +1118,7 @@ memory_update_metrics() {
|
|
|
1112
1118
|
# Update baseline using atomic write
|
|
1113
1119
|
local tmp_file
|
|
1114
1120
|
tmp_file=$(mktemp)
|
|
1121
|
+
trap "rm -f '$tmp_file'" RETURN
|
|
1115
1122
|
jq --arg m "$metric_name" \
|
|
1116
1123
|
--argjson v "$value" \
|
|
1117
1124
|
--arg ts "$(now_iso)" \
|
|
@@ -1135,6 +1142,7 @@ memory_capture_decision() {
|
|
|
1135
1142
|
|
|
1136
1143
|
local tmp_file
|
|
1137
1144
|
tmp_file=$(mktemp)
|
|
1145
|
+
trap "rm -f '$tmp_file'" RETURN
|
|
1138
1146
|
jq --arg type "$dec_type" \
|
|
1139
1147
|
--arg summary "$summary" \
|
|
1140
1148
|
--arg detail "$detail" \
|
|
@@ -1454,6 +1462,7 @@ memory_import() {
|
|
|
1454
1462
|
# Extract and write each section
|
|
1455
1463
|
local tmp_file
|
|
1456
1464
|
tmp_file=$(mktemp)
|
|
1465
|
+
trap "rm -f '$tmp_file'" RETURN
|
|
1457
1466
|
|
|
1458
1467
|
jq '.patterns // {}' "$import_file" > "$tmp_file" && mv "$tmp_file" "$mem_dir/patterns.json"
|
|
1459
1468
|
jq '.failures // {"failures":[]}' "$import_file" > "$tmp_file" && mv "$tmp_file" "$mem_dir/failures.json"
|
|
@@ -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="2.
|
|
10
|
+
VERSION="2.3.0"
|
|
11
11
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
12
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
13
13
|
|
|
@@ -204,6 +204,7 @@ set_config() {
|
|
|
204
204
|
# Use jq to safely update the config
|
|
205
205
|
local tmp_config
|
|
206
206
|
tmp_config=$(mktemp)
|
|
207
|
+
trap "rm -f '$tmp_config'" RETURN
|
|
207
208
|
|
|
208
209
|
if [[ "$value" == "true" ]] || [[ "$value" == "false" ]]; then
|
|
209
210
|
jq ".${key} = ${value}" "$MODEL_ROUTING_CONFIG" > "$tmp_config"
|
|
@@ -336,6 +337,7 @@ configure_ab_test() {
|
|
|
336
337
|
|
|
337
338
|
local tmp_config
|
|
338
339
|
tmp_config=$(mktemp)
|
|
340
|
+
trap "rm -f '$tmp_config'" RETURN
|
|
339
341
|
|
|
340
342
|
jq ".a_b_test = {\"enabled\": true, \"percentage\": $percentage, \"variant\": \"$variant\"}" \
|
|
341
343
|
"$MODEL_ROUTING_CONFIG" > "$tmp_config"
|
|
@@ -521,6 +523,7 @@ main() {
|
|
|
521
523
|
if command -v jq &>/dev/null; then
|
|
522
524
|
local tmp_config
|
|
523
525
|
tmp_config=$(mktemp)
|
|
526
|
+
trap "rm -f '$tmp_config'" RETURN
|
|
524
527
|
jq ".a_b_test.enabled = false" "$MODEL_ROUTING_CONFIG" > "$tmp_config"
|
|
525
528
|
mv "$tmp_config" "$MODEL_ROUTING_CONFIG"
|
|
526
529
|
success "Disabled A/B testing"
|
package/scripts/sw-otel.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="2.
|
|
9
|
+
VERSION="2.3.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -94,16 +94,16 @@ cmd_metrics() {
|
|
|
94
94
|
event_type=$(echo "$line" | jq -r '.type // empty' 2>/dev/null || true)
|
|
95
95
|
|
|
96
96
|
case "$event_type" in
|
|
97
|
-
pipeline_start)
|
|
97
|
+
pipeline_start|pipeline.started)
|
|
98
98
|
((total_pipelines++))
|
|
99
99
|
((active_pipelines++))
|
|
100
100
|
;;
|
|
101
|
-
pipeline_complete)
|
|
101
|
+
pipeline_complete|pipeline.completed)
|
|
102
102
|
((active_pipelines--))
|
|
103
103
|
((succeeded_pipelines++))
|
|
104
104
|
((status_success++))
|
|
105
105
|
;;
|
|
106
|
-
pipeline_failed)
|
|
106
|
+
pipeline_failed|pipeline.failed)
|
|
107
107
|
((active_pipelines--))
|
|
108
108
|
((failed_pipelines++))
|
|
109
109
|
((status_failed++))
|
package/scripts/sw-oversight.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="2.
|
|
9
|
+
VERSION="2.3.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -124,6 +124,7 @@ composer_create_pipeline() {
|
|
|
124
124
|
# Atomic write
|
|
125
125
|
local tmp_file
|
|
126
126
|
tmp_file=$(mktemp "${output_file}.XXXXXX")
|
|
127
|
+
trap "rm -f '$tmp_file'" RETURN
|
|
127
128
|
echo "$composed" | jq '.' > "$tmp_file"
|
|
128
129
|
mv "$tmp_file" "$output_file"
|
|
129
130
|
|
|
@@ -152,6 +153,7 @@ composer_create_pipeline() {
|
|
|
152
153
|
info "Using fallback template: standard" >&2
|
|
153
154
|
local tmp_file
|
|
154
155
|
tmp_file=$(mktemp "${output_file}.XXXXXX")
|
|
156
|
+
trap "rm -f '$tmp_file'" RETURN
|
|
155
157
|
cp "$fallback_template" "$tmp_file"
|
|
156
158
|
mv "$tmp_file" "$output_file"
|
|
157
159
|
|
|
@@ -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="2.
|
|
9
|
+
VERSION="2.3.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -316,13 +316,11 @@ _compute_error_maturity() {
|
|
|
316
316
|
# ─── File Locking Helpers ──────────────────────────────────────────────────
|
|
317
317
|
_vitals_acquire_lock() {
|
|
318
318
|
local lockfile="$1.lock"
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
flock -w 5 "$fd" || { warn "Vitals lock timeout"; return 1; }
|
|
319
|
+
exec 200>"$lockfile"
|
|
320
|
+
flock -w 5 200 || { warn "Vitals lock timeout"; return 1; }
|
|
322
321
|
}
|
|
323
322
|
_vitals_release_lock() {
|
|
324
|
-
|
|
325
|
-
flock -u "$fd" 2>/dev/null || true
|
|
323
|
+
flock -u 200 2>/dev/null || true
|
|
326
324
|
}
|
|
327
325
|
|
|
328
326
|
# ═══════════════════════════════════════════════════════════════════════════
|
package/scripts/sw-pipeline.sh
CHANGED
|
@@ -11,7 +11,7 @@ unset CLAUDECODE 2>/dev/null || true
|
|
|
11
11
|
# Ignore SIGHUP so tmux attach/detach doesn't kill long-running plan/design/review stages
|
|
12
12
|
trap '' HUP
|
|
13
13
|
|
|
14
|
-
VERSION="2.
|
|
14
|
+
VERSION="2.3.0"
|
|
15
15
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
16
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
17
17
|
|
|
@@ -49,6 +49,18 @@ BOLD="${BOLD:-\033[1m}"
|
|
|
49
49
|
RESET="${RESET:-\033[0m}"
|
|
50
50
|
# Policy + pipeline quality thresholds (config/policy.json via lib/pipeline-quality.sh)
|
|
51
51
|
[[ -f "$SCRIPT_DIR/lib/pipeline-quality.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-quality.sh"
|
|
52
|
+
# shellcheck source=lib/pipeline-state.sh
|
|
53
|
+
[[ -f "$SCRIPT_DIR/lib/pipeline-state.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-state.sh"
|
|
54
|
+
# shellcheck source=lib/pipeline-github.sh
|
|
55
|
+
[[ -f "$SCRIPT_DIR/lib/pipeline-github.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-github.sh"
|
|
56
|
+
# shellcheck source=lib/pipeline-detection.sh
|
|
57
|
+
[[ -f "$SCRIPT_DIR/lib/pipeline-detection.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-detection.sh"
|
|
58
|
+
# shellcheck source=lib/pipeline-quality-checks.sh
|
|
59
|
+
[[ -f "$SCRIPT_DIR/lib/pipeline-quality-checks.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-quality-checks.sh"
|
|
60
|
+
# shellcheck source=lib/pipeline-intelligence.sh
|
|
61
|
+
[[ -f "$SCRIPT_DIR/lib/pipeline-intelligence.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-intelligence.sh"
|
|
62
|
+
# shellcheck source=lib/pipeline-stages.sh
|
|
63
|
+
[[ -f "$SCRIPT_DIR/lib/pipeline-stages.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-stages.sh"
|
|
52
64
|
PIPELINE_COVERAGE_THRESHOLD="${PIPELINE_COVERAGE_THRESHOLD:-60}"
|
|
53
65
|
PIPELINE_QUALITY_GATE_THRESHOLD="${PIPELINE_QUALITY_GATE_THRESHOLD:-70}"
|
|
54
66
|
|
|
@@ -760,55 +772,7 @@ notify() {
|
|
|
760
772
|
fi
|
|
761
773
|
}
|
|
762
774
|
|
|
763
|
-
# ───
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
# ─── Pipeline libs (extracted for decomposition) ─────────────────────────
|
|
767
|
-
# shellcheck source=lib/pipeline-github.sh
|
|
768
|
-
[[ -f "$SCRIPT_DIR/lib/pipeline-github.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-github.sh"
|
|
769
|
-
# shellcheck source=lib/pipeline-detection.sh
|
|
770
|
-
[[ -f "$SCRIPT_DIR/lib/pipeline-detection.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-detection.sh"
|
|
771
|
-
|
|
772
|
-
PIPELINE_STATUS="pending"
|
|
773
|
-
CURRENT_STAGE=""
|
|
774
|
-
STARTED_AT=""
|
|
775
|
-
UPDATED_AT=""
|
|
776
|
-
STAGE_STATUSES=""
|
|
777
|
-
LOG_ENTRIES=""
|
|
778
|
-
|
|
779
|
-
# shellcheck source=lib/pipeline-state.sh
|
|
780
|
-
[[ -f "$SCRIPT_DIR/lib/pipeline-state.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-state.sh"
|
|
781
|
-
|
|
782
|
-
show_stage_preview() {
|
|
783
|
-
local stage_id="$1"
|
|
784
|
-
echo ""
|
|
785
|
-
echo -e "${PURPLE}${BOLD}━━━ Stage: ${stage_id} ━━━${RESET}"
|
|
786
|
-
case "$stage_id" in
|
|
787
|
-
intake) echo -e " Fetch issue, detect task type, create branch, self-assign" ;;
|
|
788
|
-
plan) echo -e " Generate plan via Claude, post task checklist to issue" ;;
|
|
789
|
-
design) echo -e " Generate Architecture Decision Record (ADR), evaluate alternatives" ;;
|
|
790
|
-
build) echo -e " Delegate to ${CYAN}shipwright loop${RESET} for autonomous building" ;;
|
|
791
|
-
test) echo -e " Run test suite and check coverage" ;;
|
|
792
|
-
review) echo -e " AI code review on the diff, post findings" ;;
|
|
793
|
-
pr) echo -e " Create GitHub PR with labels, reviewers, milestone" ;;
|
|
794
|
-
merge) echo -e " Wait for CI checks, merge PR, optionally delete branch" ;;
|
|
795
|
-
deploy) echo -e " Deploy to staging/production with rollback" ;;
|
|
796
|
-
validate) echo -e " Smoke tests, health checks, close issue" ;;
|
|
797
|
-
monitor) echo -e " Post-deploy monitoring, health checks, auto-rollback" ;;
|
|
798
|
-
esac
|
|
799
|
-
echo ""
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
# ─── Stage Functions ────────────────────────────────────────────────────────
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
# shellcheck source=lib/pipeline-stages.sh
|
|
806
|
-
[[ -f "$SCRIPT_DIR/lib/pipeline-stages.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-stages.sh"
|
|
807
|
-
# shellcheck source=lib/pipeline-quality-checks.sh
|
|
808
|
-
[[ -f "$SCRIPT_DIR/lib/pipeline-quality-checks.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-quality-checks.sh"
|
|
809
|
-
# shellcheck source=lib/pipeline-intelligence.sh
|
|
810
|
-
[[ -f "$SCRIPT_DIR/lib/pipeline-intelligence.sh" ]] && source "$SCRIPT_DIR/lib/pipeline-intelligence.sh"
|
|
811
|
-
|
|
775
|
+
# ─── Error Classification ──────────────────────────────────────────────────
|
|
812
776
|
# Classifies errors to determine whether retrying makes sense.
|
|
813
777
|
# Returns: "infrastructure", "logic", "configuration", or "unknown"
|
|
814
778
|
|
|
@@ -886,6 +850,7 @@ Reply with ONLY the classification word, nothing else." --model haiku < /dev/nul
|
|
|
886
850
|
mkdir -p "$class_dir" 2>/dev/null || true
|
|
887
851
|
local tmp_class
|
|
888
852
|
tmp_class="$(mktemp)"
|
|
853
|
+
trap "rm -f '$tmp_class'" RETURN
|
|
889
854
|
if [[ -f "$class_history" ]]; then
|
|
890
855
|
jq --arg sig "$error_sig" --arg cls "$classification" --arg canon "$canonical_category" --arg stage "$stage_id" \
|
|
891
856
|
'.[$sig] = {"classification": $cls, "canonical": $canon, "stage": $stage, "recorded_at": now}' \
|
|
@@ -1305,6 +1270,7 @@ run_pipeline() {
|
|
|
1305
1270
|
# Remove this stage from the skip file
|
|
1306
1271
|
local tmp_skip
|
|
1307
1272
|
tmp_skip="$(mktemp)"
|
|
1273
|
+
trap "rm -f '$tmp_skip'" RETURN
|
|
1308
1274
|
grep -vx "$id" "$ARTIFACTS_DIR/skip-stage.txt" > "$tmp_skip" 2>/dev/null || true
|
|
1309
1275
|
mv "$tmp_skip" "$ARTIFACTS_DIR/skip-stage.txt"
|
|
1310
1276
|
continue
|
|
@@ -1636,12 +1602,9 @@ pipeline_post_completion_cleanup() {
|
|
|
1636
1602
|
# Reset status to idle (preserves the file for reference but unblocks new runs)
|
|
1637
1603
|
local tmp_state
|
|
1638
1604
|
tmp_state=$(mktemp)
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
rm -f "$tmp_state"
|
|
1643
|
-
warn "Failed to reset state file status to idle" 2>/dev/null || true
|
|
1644
|
-
fi
|
|
1605
|
+
trap "rm -f '$tmp_state'" RETURN
|
|
1606
|
+
sed 's/^status: .*/status: idle/' "$STATE_FILE" > "$tmp_state" 2>/dev/null || true
|
|
1607
|
+
mv "$tmp_state" "$STATE_FILE"
|
|
1645
1608
|
fi
|
|
1646
1609
|
|
|
1647
1610
|
if [[ "$cleaned" -gt 0 ]]; then
|
package/scripts/sw-pm.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="2.
|
|
9
|
+
VERSION="2.3.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
|
@@ -77,7 +77,7 @@ show_help() {
|
|
|
77
77
|
echo -e " ${DIM}shipwright pm history${RESET} # Show past decisions"
|
|
78
78
|
echo -e " ${DIM}shipwright pm history --pattern${RESET} # Show success patterns"
|
|
79
79
|
echo ""
|
|
80
|
-
echo -e "${DIM}Docs:
|
|
80
|
+
echo -e "${DIM}Docs: $(_sw_docs_url) | GitHub: $(_sw_github_url)${RESET}"
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
# ─── analyze_issue <issue_num> ───────────────────────────────────────────────
|
|
@@ -522,6 +522,7 @@ cmd_recommend() {
|
|
|
522
522
|
ensure_pm_history
|
|
523
523
|
local tmp_hist
|
|
524
524
|
tmp_hist=$(mktemp)
|
|
525
|
+
trap "rm -f '$tmp_hist'" RETURN
|
|
525
526
|
jq --argjson rec "$recommendation" '.decisions += [$rec]' "$PM_HISTORY" > "$tmp_hist" && mv "$tmp_hist" "$PM_HISTORY"
|
|
526
527
|
emit_event "pm.recommend" "issue=${issue_num}"
|
|
527
528
|
return 0
|
|
@@ -549,6 +550,7 @@ cmd_recommend() {
|
|
|
549
550
|
ensure_pm_history
|
|
550
551
|
local tmp_hist
|
|
551
552
|
tmp_hist=$(mktemp)
|
|
553
|
+
trap "rm -f '$tmp_hist'" RETURN
|
|
552
554
|
jq --argjson rec "$recommendation" '.decisions += [$rec]' "$PM_HISTORY" > "$tmp_hist" && mv "$tmp_hist" "$PM_HISTORY"
|
|
553
555
|
|
|
554
556
|
success "Recommendation saved to history"
|
|
@@ -612,6 +614,7 @@ cmd_learn() {
|
|
|
612
614
|
# Save to history
|
|
613
615
|
local tmp_hist
|
|
614
616
|
tmp_hist=$(mktemp)
|
|
617
|
+
trap "rm -f '$tmp_hist'" RETURN
|
|
615
618
|
jq --argjson outcome "$outcome_record" '.outcomes += [$outcome]' "$PM_HISTORY" > "$tmp_hist" && mv "$tmp_hist" "$PM_HISTORY"
|
|
616
619
|
|
|
617
620
|
success "Recorded ${outcome} outcome for issue #${issue_num}"
|
package/scripts/sw-predictive.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="2.
|
|
9
|
+
VERSION="2.3.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -188,6 +188,7 @@ predictive_confirm_anomaly() {
|
|
|
188
188
|
# Find the most recent unconfirmed anomaly for this stage+metric
|
|
189
189
|
local tmp_file
|
|
190
190
|
tmp_file=$(mktemp "${TMPDIR:-/tmp}/sw-anomaly-confirm.XXXXXX")
|
|
191
|
+
trap "rm -f '$tmp_file'" RETURN
|
|
191
192
|
local found=false
|
|
192
193
|
|
|
193
194
|
# Process file in reverse to find most recent unconfirmed
|
|
@@ -283,6 +284,7 @@ _predictive_update_alarm_rates() {
|
|
|
283
284
|
# Atomic write
|
|
284
285
|
local tmp_file
|
|
285
286
|
tmp_file=$(mktemp "${TMPDIR:-/tmp}/sw-anomaly-thresh.XXXXXX")
|
|
287
|
+
trap "rm -f '$tmp_file'" RETURN
|
|
286
288
|
jq --arg m "$metric_name" \
|
|
287
289
|
--argjson crit "$new_critical" \
|
|
288
290
|
--argjson warn "$new_warning" \
|
|
@@ -755,6 +757,7 @@ predict_update_baseline() {
|
|
|
755
757
|
# Atomic write
|
|
756
758
|
local tmp_file
|
|
757
759
|
tmp_file=$(mktemp)
|
|
760
|
+
trap "rm -f '$tmp_file'" RETURN
|
|
758
761
|
jq --arg key "$key" \
|
|
759
762
|
--argjson val "$new_value" \
|
|
760
763
|
--argjson cnt "$new_count" \
|
package/scripts/sw-prep.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="2.
|
|
9
|
+
VERSION="2.3.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Handle subcommands ───────────────────────────────────────────────────────
|
|
@@ -129,7 +129,7 @@ show_help() {
|
|
|
129
129
|
echo -e " ${DIM}.claude/hooks/*.sh${RESET} Pre/post action hooks"
|
|
130
130
|
echo -e " ${DIM}.github/ISSUE_TEMPLATE/agent-task.md${RESET} Agent task template"
|
|
131
131
|
echo ""
|
|
132
|
-
echo -e "${DIM}Docs:
|
|
132
|
+
echo -e "${DIM}Docs: $(_sw_docs_url) | GitHub: $(_sw_github_url)${RESET}"
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
# ─── CLI Argument Parsing ───────────────────────────────────────────────────
|
|
@@ -828,6 +828,7 @@ prep_learn_patterns() {
|
|
|
828
828
|
# Write patterns file atomically
|
|
829
829
|
local tmp_patterns
|
|
830
830
|
tmp_patterns=$(mktemp)
|
|
831
|
+
trap "rm -f '$tmp_patterns'" RETURN
|
|
831
832
|
jq -n \
|
|
832
833
|
--arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
|
|
833
834
|
--arg lang "${LANG_DETECTED:-}" \
|
package/scripts/sw-ps.sh
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# ║ Displays a table of agents running in claude-* tmux windows with ║
|
|
6
6
|
# ║ PID, status, idle time, and pane references. ║
|
|
7
7
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
8
|
-
VERSION="2.
|
|
8
|
+
VERSION="2.3.0"
|
|
9
9
|
set -euo pipefail
|
|
10
10
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
11
11
|
|
|
@@ -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="2.
|
|
9
|
+
VERSION="2.3.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -323,7 +323,7 @@ generate_html() {
|
|
|
323
323
|
</div>
|
|
324
324
|
|
|
325
325
|
<div class="footer">
|
|
326
|
-
<p>Generated by <a href="
|
|
326
|
+
<p>Generated by <a href="GITHUB_URL_PLACEHOLDER">Shipwright</a> v1.13.0</p>
|
|
327
327
|
<p style="margin-top: 8px; color: #555;">Dashboard auto-refreshes every 30s when served from dashboard server</p>
|
|
328
328
|
<p style="margin-top: 8px;" id="footer-timestamp">Generated: —</p>
|
|
329
329
|
</div>
|
|
@@ -384,7 +384,12 @@ generate_html() {
|
|
|
384
384
|
const newDoc = parser.parseFromString(html, 'text/html');
|
|
385
385
|
const newScript = newDoc.querySelector('script');
|
|
386
386
|
if (newScript) {
|
|
387
|
-
eval
|
|
387
|
+
// Use DOM script insertion instead of eval: script comes from same-origin
|
|
388
|
+
// fetch of this page; DOM insertion executes in global scope without eval
|
|
389
|
+
const s = document.createElement('script');
|
|
390
|
+
s.textContent = newScript.textContent;
|
|
391
|
+
document.body.appendChild(s);
|
|
392
|
+
s.remove();
|
|
388
393
|
renderDashboard();
|
|
389
394
|
}
|
|
390
395
|
})
|
|
@@ -417,6 +422,7 @@ cmd_export() {
|
|
|
417
422
|
html="${html//TITLE_PLACEHOLDER/$title}"
|
|
418
423
|
html="${html//PRIVACY_PLACEHOLDER/$privacy}"
|
|
419
424
|
html="${html//\{DATA_PLACEHOLDER\}/$state_data}"
|
|
425
|
+
html="${html//GITHUB_URL_PLACEHOLDER/$(_sw_github_url)}"
|
|
420
426
|
|
|
421
427
|
# Atomic write
|
|
422
428
|
local tmp_file
|
|
@@ -736,7 +742,7 @@ ${BOLD}SHARE LINKS${RESET}
|
|
|
736
742
|
Share links require a running dashboard server to serve the public endpoint.
|
|
737
743
|
By default, requires dashboard to serve at: https://your-domain.com/public-dashboard/<token>
|
|
738
744
|
|
|
739
|
-
${DIM}Docs:
|
|
745
|
+
${DIM}Docs: $(_sw_docs_url)${RESET}
|
|
740
746
|
EOF
|
|
741
747
|
}
|
|
742
748
|
|