shipwright-cli 3.1.0 → 3.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/.claude/agents/code-reviewer.md +2 -0
- package/.claude/agents/devops-engineer.md +2 -0
- package/.claude/agents/doc-fleet-agent.md +2 -0
- package/.claude/agents/pipeline-agent.md +2 -0
- package/.claude/agents/shell-script-specialist.md +2 -0
- package/.claude/agents/test-specialist.md +2 -0
- package/.claude/hooks/agent-crash-capture.sh +32 -0
- package/.claude/hooks/post-tool-use.sh +3 -2
- package/.claude/hooks/pre-tool-use.sh +35 -3
- package/README.md +22 -8
- package/claude-code/hooks/config-change.sh +18 -0
- package/claude-code/hooks/instructions-reloaded.sh +7 -0
- package/claude-code/hooks/worktree-create.sh +25 -0
- package/claude-code/hooks/worktree-remove.sh +20 -0
- package/config/code-constitution.json +130 -0
- package/config/defaults.json +25 -2
- package/config/policy.json +1 -1
- package/dashboard/middleware/auth.ts +134 -0
- package/dashboard/middleware/constants.ts +21 -0
- package/dashboard/public/index.html +8 -6
- package/dashboard/public/styles.css +176 -97
- package/dashboard/routes/auth.ts +38 -0
- package/dashboard/server.ts +117 -25
- package/dashboard/services/config.ts +26 -0
- package/dashboard/services/db.ts +118 -0
- package/dashboard/src/canvas/pixel-agent.ts +298 -0
- package/dashboard/src/canvas/pixel-sprites.ts +440 -0
- package/dashboard/src/canvas/shipyard-effects.ts +367 -0
- package/dashboard/src/canvas/shipyard-scene.ts +616 -0
- package/dashboard/src/canvas/submarine-layout.ts +267 -0
- package/dashboard/src/components/header.ts +8 -7
- package/dashboard/src/core/api.ts +5 -0
- package/dashboard/src/core/router.ts +1 -0
- package/dashboard/src/design/submarine-theme.ts +253 -0
- package/dashboard/src/main.ts +2 -0
- package/dashboard/src/types/api.ts +12 -1
- package/dashboard/src/views/activity.ts +2 -1
- package/dashboard/src/views/metrics.ts +69 -1
- package/dashboard/src/views/shipyard.ts +39 -0
- package/dashboard/types/index.ts +166 -0
- package/docs/plans/2026-02-28-compound-audit-and-shipyard-design.md +186 -0
- package/docs/plans/2026-02-28-skipper-shipwright-implementation-plan.md +1182 -0
- package/docs/plans/2026-02-28-skipper-shipwright-integration-design.md +531 -0
- package/docs/plans/2026-03-01-ai-powered-skill-injection-design.md +298 -0
- package/docs/plans/2026-03-01-ai-powered-skill-injection-plan.md +1109 -0
- package/docs/plans/2026-03-01-capabilities-cleanup-plan.md +658 -0
- package/docs/plans/2026-03-01-clean-architecture-plan.md +924 -0
- package/docs/plans/2026-03-01-compound-audit-cascade-design.md +191 -0
- package/docs/plans/2026-03-01-compound-audit-cascade-plan.md +921 -0
- package/docs/plans/2026-03-01-deep-integration-plan.md +851 -0
- package/docs/plans/2026-03-01-pipeline-audit-trail-design.md +145 -0
- package/docs/plans/2026-03-01-pipeline-audit-trail-plan.md +770 -0
- package/docs/plans/2026-03-01-refined-depths-brand-design.md +382 -0
- package/docs/plans/2026-03-01-refined-depths-implementation.md +599 -0
- package/docs/plans/2026-03-01-skipper-kernel-integration-design.md +203 -0
- package/docs/plans/2026-03-01-unified-platform-design.md +272 -0
- package/docs/plans/2026-03-07-claude-code-feature-integration-design.md +189 -0
- package/docs/plans/2026-03-07-claude-code-feature-integration-plan.md +1165 -0
- package/docs/research/BACKLOG_QUICK_REFERENCE.md +352 -0
- package/docs/research/CUTTING_EDGE_RESEARCH_2026.md +546 -0
- package/docs/research/RESEARCH_INDEX.md +439 -0
- package/docs/research/RESEARCH_SOURCES.md +440 -0
- package/docs/research/RESEARCH_SUMMARY.txt +275 -0
- package/docs/superpowers/specs/2026-03-10-pipeline-quality-revolution-design.md +341 -0
- package/package.json +2 -2
- package/scripts/lib/adaptive-model.sh +427 -0
- package/scripts/lib/adaptive-timeout.sh +316 -0
- package/scripts/lib/audit-trail.sh +309 -0
- package/scripts/lib/auto-recovery.sh +471 -0
- package/scripts/lib/bandit-selector.sh +431 -0
- package/scripts/lib/bootstrap.sh +104 -2
- package/scripts/lib/causal-graph.sh +455 -0
- package/scripts/lib/compat.sh +126 -0
- package/scripts/lib/compound-audit.sh +337 -0
- package/scripts/lib/constitutional.sh +454 -0
- package/scripts/lib/context-budget.sh +359 -0
- package/scripts/lib/convergence.sh +594 -0
- package/scripts/lib/cost-optimizer.sh +634 -0
- package/scripts/lib/daemon-adaptive.sh +14 -2
- package/scripts/lib/daemon-dispatch.sh +106 -17
- package/scripts/lib/daemon-failure.sh +34 -4
- package/scripts/lib/daemon-patrol.sh +25 -4
- package/scripts/lib/daemon-poll-github.sh +361 -0
- package/scripts/lib/daemon-poll-health.sh +299 -0
- package/scripts/lib/daemon-poll.sh +27 -611
- package/scripts/lib/daemon-state.sh +119 -66
- package/scripts/lib/daemon-triage.sh +10 -0
- package/scripts/lib/dod-scorecard.sh +442 -0
- package/scripts/lib/error-actionability.sh +300 -0
- package/scripts/lib/formal-spec.sh +461 -0
- package/scripts/lib/helpers.sh +180 -5
- package/scripts/lib/intent-analysis.sh +409 -0
- package/scripts/lib/loop-convergence.sh +350 -0
- package/scripts/lib/loop-iteration.sh +682 -0
- package/scripts/lib/loop-progress.sh +48 -0
- package/scripts/lib/loop-restart.sh +185 -0
- package/scripts/lib/memory-effectiveness.sh +506 -0
- package/scripts/lib/mutation-executor.sh +352 -0
- package/scripts/lib/outcome-feedback.sh +521 -0
- package/scripts/lib/pipeline-cli.sh +336 -0
- package/scripts/lib/pipeline-commands.sh +1216 -0
- package/scripts/lib/pipeline-detection.sh +101 -3
- package/scripts/lib/pipeline-execution.sh +897 -0
- package/scripts/lib/pipeline-github.sh +28 -3
- package/scripts/lib/pipeline-intelligence-compound.sh +431 -0
- package/scripts/lib/pipeline-intelligence-scoring.sh +407 -0
- package/scripts/lib/pipeline-intelligence-skip.sh +181 -0
- package/scripts/lib/pipeline-intelligence.sh +104 -1138
- package/scripts/lib/pipeline-quality-bash-compat.sh +182 -0
- package/scripts/lib/pipeline-quality-checks.sh +17 -711
- package/scripts/lib/pipeline-quality-gates.sh +563 -0
- package/scripts/lib/pipeline-stages-build.sh +730 -0
- package/scripts/lib/pipeline-stages-delivery.sh +965 -0
- package/scripts/lib/pipeline-stages-intake.sh +1133 -0
- package/scripts/lib/pipeline-stages-monitor.sh +407 -0
- package/scripts/lib/pipeline-stages-review.sh +1022 -0
- package/scripts/lib/pipeline-stages.sh +161 -2901
- package/scripts/lib/pipeline-state.sh +36 -5
- package/scripts/lib/pipeline-util.sh +487 -0
- package/scripts/lib/policy-learner.sh +438 -0
- package/scripts/lib/process-reward.sh +493 -0
- package/scripts/lib/project-detect.sh +649 -0
- package/scripts/lib/quality-profile.sh +334 -0
- package/scripts/lib/recruit-commands.sh +885 -0
- package/scripts/lib/recruit-learning.sh +739 -0
- package/scripts/lib/recruit-roles.sh +648 -0
- package/scripts/lib/reward-aggregator.sh +458 -0
- package/scripts/lib/rl-optimizer.sh +362 -0
- package/scripts/lib/root-cause.sh +427 -0
- package/scripts/lib/scope-enforcement.sh +445 -0
- package/scripts/lib/session-restart.sh +493 -0
- package/scripts/lib/skill-memory.sh +300 -0
- package/scripts/lib/skill-registry.sh +775 -0
- package/scripts/lib/spec-driven.sh +476 -0
- package/scripts/lib/test-helpers.sh +18 -7
- package/scripts/lib/test-holdout.sh +429 -0
- package/scripts/lib/test-optimizer.sh +511 -0
- package/scripts/shipwright-file-suggest.sh +45 -0
- package/scripts/skills/adversarial-quality.md +61 -0
- package/scripts/skills/api-design.md +44 -0
- package/scripts/skills/architecture-design.md +50 -0
- package/scripts/skills/brainstorming.md +43 -0
- package/scripts/skills/data-pipeline.md +44 -0
- package/scripts/skills/deploy-safety.md +64 -0
- package/scripts/skills/documentation.md +38 -0
- package/scripts/skills/frontend-design.md +45 -0
- package/scripts/skills/generated/.gitkeep +0 -0
- package/scripts/skills/generated/_refinements/.gitkeep +0 -0
- package/scripts/skills/generated/_refinements/adversarial-quality.patch.md +3 -0
- package/scripts/skills/generated/_refinements/architecture-design.patch.md +3 -0
- package/scripts/skills/generated/_refinements/brainstorming.patch.md +3 -0
- package/scripts/skills/generated/cli-version-management.md +29 -0
- package/scripts/skills/generated/collection-system-validation.md +99 -0
- package/scripts/skills/generated/large-scale-c-refactoring-coordination.md +97 -0
- package/scripts/skills/generated/pattern-matching-similarity-scoring.md +195 -0
- package/scripts/skills/generated/test-parallelization-detection.md +65 -0
- package/scripts/skills/observability.md +79 -0
- package/scripts/skills/performance.md +48 -0
- package/scripts/skills/pr-quality.md +49 -0
- package/scripts/skills/product-thinking.md +43 -0
- package/scripts/skills/security-audit.md +49 -0
- package/scripts/skills/systematic-debugging.md +40 -0
- package/scripts/skills/testing-strategy.md +47 -0
- package/scripts/skills/two-stage-review.md +52 -0
- package/scripts/skills/validation-thoroughness.md +55 -0
- package/scripts/sw +9 -3
- package/scripts/sw-activity.sh +9 -8
- package/scripts/sw-adaptive.sh +8 -7
- package/scripts/sw-adversarial.sh +2 -1
- package/scripts/sw-architecture-enforcer.sh +3 -1
- package/scripts/sw-auth.sh +12 -2
- package/scripts/sw-autonomous.sh +5 -1
- package/scripts/sw-changelog.sh +4 -1
- package/scripts/sw-checkpoint.sh +2 -1
- package/scripts/sw-ci.sh +15 -6
- package/scripts/sw-cleanup.sh +4 -26
- package/scripts/sw-code-review.sh +45 -20
- package/scripts/sw-connect.sh +2 -1
- package/scripts/sw-context.sh +2 -1
- package/scripts/sw-cost.sh +107 -5
- package/scripts/sw-daemon.sh +71 -11
- package/scripts/sw-dashboard.sh +3 -1
- package/scripts/sw-db.sh +71 -20
- package/scripts/sw-decide.sh +8 -2
- package/scripts/sw-decompose.sh +360 -17
- package/scripts/sw-deps.sh +4 -1
- package/scripts/sw-developer-simulation.sh +4 -1
- package/scripts/sw-discovery.sh +378 -5
- package/scripts/sw-doc-fleet.sh +4 -1
- package/scripts/sw-docs-agent.sh +3 -1
- package/scripts/sw-docs.sh +2 -1
- package/scripts/sw-doctor.sh +453 -2
- package/scripts/sw-dora.sh +4 -1
- package/scripts/sw-durable.sh +12 -7
- package/scripts/sw-e2e-orchestrator.sh +17 -16
- package/scripts/sw-eventbus.sh +13 -4
- package/scripts/sw-evidence.sh +364 -12
- package/scripts/sw-feedback.sh +550 -9
- package/scripts/sw-fix.sh +20 -1
- package/scripts/sw-fleet-discover.sh +6 -2
- package/scripts/sw-fleet-viz.sh +9 -4
- package/scripts/sw-fleet.sh +5 -1
- package/scripts/sw-github-app.sh +18 -4
- package/scripts/sw-github-checks.sh +3 -2
- package/scripts/sw-github-deploy.sh +3 -2
- package/scripts/sw-github-graphql.sh +18 -7
- package/scripts/sw-guild.sh +5 -1
- package/scripts/sw-heartbeat.sh +5 -30
- package/scripts/sw-hello.sh +67 -0
- package/scripts/sw-hygiene.sh +10 -3
- package/scripts/sw-incident.sh +273 -5
- package/scripts/sw-init.sh +18 -2
- package/scripts/sw-instrument.sh +10 -2
- package/scripts/sw-intelligence.sh +44 -7
- package/scripts/sw-jira.sh +5 -1
- package/scripts/sw-launchd.sh +2 -1
- package/scripts/sw-linear.sh +4 -1
- package/scripts/sw-logs.sh +4 -1
- package/scripts/sw-loop.sh +436 -1076
- package/scripts/sw-memory.sh +357 -3
- package/scripts/sw-mission-control.sh +6 -1
- package/scripts/sw-model-router.sh +483 -27
- package/scripts/sw-otel.sh +15 -4
- package/scripts/sw-oversight.sh +14 -5
- package/scripts/sw-patrol-meta.sh +334 -0
- package/scripts/sw-pipeline-composer.sh +7 -1
- package/scripts/sw-pipeline-vitals.sh +12 -6
- package/scripts/sw-pipeline.sh +54 -2653
- package/scripts/sw-pm.sh +16 -8
- package/scripts/sw-pr-lifecycle.sh +2 -1
- package/scripts/sw-predictive.sh +17 -5
- package/scripts/sw-prep.sh +185 -2
- package/scripts/sw-ps.sh +5 -25
- package/scripts/sw-public-dashboard.sh +17 -4
- package/scripts/sw-quality.sh +14 -6
- package/scripts/sw-reaper.sh +8 -25
- package/scripts/sw-recruit.sh +156 -2303
- package/scripts/sw-regression.sh +19 -12
- package/scripts/sw-release-manager.sh +3 -1
- package/scripts/sw-release.sh +4 -1
- package/scripts/sw-remote.sh +3 -1
- package/scripts/sw-replay.sh +7 -1
- package/scripts/sw-retro.sh +158 -1
- package/scripts/sw-review-rerun.sh +3 -1
- package/scripts/sw-scale.sh +14 -5
- package/scripts/sw-security-audit.sh +6 -1
- package/scripts/sw-self-optimize.sh +173 -6
- package/scripts/sw-session.sh +9 -3
- package/scripts/sw-setup.sh +3 -1
- package/scripts/sw-stall-detector.sh +406 -0
- package/scripts/sw-standup.sh +15 -7
- package/scripts/sw-status.sh +3 -1
- package/scripts/sw-strategic.sh +14 -6
- package/scripts/sw-stream.sh +13 -4
- package/scripts/sw-swarm.sh +20 -7
- package/scripts/sw-team-stages.sh +13 -6
- package/scripts/sw-templates.sh +7 -31
- package/scripts/sw-testgen.sh +17 -6
- package/scripts/sw-tmux-pipeline.sh +4 -1
- package/scripts/sw-tmux-role-color.sh +2 -0
- package/scripts/sw-tmux-status.sh +1 -1
- package/scripts/sw-tmux.sh +37 -1
- package/scripts/sw-trace.sh +3 -1
- package/scripts/sw-tracker-github.sh +3 -0
- package/scripts/sw-tracker-jira.sh +3 -0
- package/scripts/sw-tracker-linear.sh +3 -0
- package/scripts/sw-tracker.sh +3 -1
- package/scripts/sw-triage.sh +3 -2
- package/scripts/sw-upgrade.sh +3 -1
- package/scripts/sw-ux.sh +5 -2
- package/scripts/sw-webhook.sh +5 -2
- package/scripts/sw-widgets.sh +9 -4
- package/scripts/sw-worktree.sh +15 -3
- package/scripts/test-skill-injection.sh +1233 -0
- package/templates/pipelines/autonomous.json +27 -3
- package/templates/pipelines/cost-aware.json +34 -8
- package/templates/pipelines/deployed.json +12 -0
- package/templates/pipelines/enterprise.json +12 -0
- package/templates/pipelines/fast.json +6 -0
- package/templates/pipelines/full.json +27 -3
- package/templates/pipelines/hotfix.json +6 -0
- package/templates/pipelines/standard.json +12 -0
- package/templates/pipelines/tdd.json +12 -0
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Module guard - prevent double-sourcing
|
|
3
|
+
[[ -n "${_BANDIT_SELECTOR_LOADED:-}" ]] && return 0
|
|
4
|
+
_BANDIT_SELECTOR_LOADED=1
|
|
5
|
+
|
|
6
|
+
# ╔═══════════════════════════════════════════════════════════════════════════╗
|
|
7
|
+
# ║ shipwright bandit-selector — Thompson Sampling for Model/Template ║
|
|
8
|
+
# ║ Multi-armed bandit: Beta(α,β) priors, Thompson sampling selection ║
|
|
9
|
+
# ║ Replaces static model routing with learned optimal selection ║
|
|
10
|
+
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
11
|
+
|
|
12
|
+
# shellcheck disable=SC2034
|
|
13
|
+
VERSION="3.3.0"
|
|
14
|
+
|
|
15
|
+
# ─── Output Helpers ──────────────────────────────────────────────────────────
|
|
16
|
+
[[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
|
|
17
|
+
[[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
|
|
18
|
+
[[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
|
|
19
|
+
[[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
|
|
20
|
+
|
|
21
|
+
# ─── Configuration ───────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
BANDIT_STATE_FILE="${BANDIT_STATE_FILE:-$HOME/.shipwright/bandits.json}"
|
|
24
|
+
|
|
25
|
+
# Default models and stages for arm initialization
|
|
26
|
+
BANDIT_MODELS="${BANDIT_MODELS:-haiku,sonnet,opus}"
|
|
27
|
+
BANDIT_STAGES="${BANDIT_STAGES:-build,test,review,design,plan,intake,pr}"
|
|
28
|
+
BANDIT_TEMPLATES="${BANDIT_TEMPLATES:-fast,standard,full,hotfix,autonomous}"
|
|
29
|
+
BANDIT_ISSUE_TYPES="${BANDIT_ISSUE_TYPES:-bug,feature,refactor,docs}"
|
|
30
|
+
|
|
31
|
+
# ─── Beta Sampling ───────────────────────────────────────────────────────────
|
|
32
|
+
# Sample from Beta(alpha, beta) using Gamma decomposition.
|
|
33
|
+
# If X~Gamma(a,1) and Y~Gamma(b,1), then X/(X+Y)~Beta(a,b).
|
|
34
|
+
# Gamma(k,1) for integer k = sum of k Exponential(1) samples.
|
|
35
|
+
|
|
36
|
+
_beta_sample() {
|
|
37
|
+
local alpha="$1" beta="$2"
|
|
38
|
+
awk -v a="$alpha" -v b="$beta" -v seed="$RANDOM" 'BEGIN {
|
|
39
|
+
srand(seed)
|
|
40
|
+
x = 0; y = 0
|
|
41
|
+
for (i = 0; i < a; i++) { r = rand(); if (r < 1e-10) r = 1e-10; x += -log(r) }
|
|
42
|
+
for (i = 0; i < b; i++) { r = rand(); if (r < 1e-10) r = 1e-10; y += -log(r) }
|
|
43
|
+
if (x + y > 0) printf "%.6f", x / (x + y)
|
|
44
|
+
else printf "0.500000"
|
|
45
|
+
}'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# ─── JSON Helpers ────────────────────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
_bandit_ensure_dir() {
|
|
51
|
+
local dir
|
|
52
|
+
dir="$(dirname "$BANDIT_STATE_FILE")"
|
|
53
|
+
[[ -d "$dir" ]] || mkdir -p "$dir"
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
_bandit_read_state() {
|
|
57
|
+
if [[ -f "$BANDIT_STATE_FILE" ]]; then
|
|
58
|
+
cat "$BANDIT_STATE_FILE"
|
|
59
|
+
else
|
|
60
|
+
echo '{}'
|
|
61
|
+
fi
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
_bandit_write_state() {
|
|
65
|
+
local json="$1"
|
|
66
|
+
_bandit_ensure_dir
|
|
67
|
+
local tmp_file="${BANDIT_STATE_FILE}.tmp.$$"
|
|
68
|
+
echo "$json" > "$tmp_file"
|
|
69
|
+
mv "$tmp_file" "$BANDIT_STATE_FILE"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# ─── Arm Key Helpers ─────────────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
_arm_key() {
|
|
75
|
+
# Create arm key from context:value pair, e.g. "build:haiku"
|
|
76
|
+
echo "${1}:${2}"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# ─── Core Functions ──────────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
# Initialize Beta(1,1) distributions for all model and template arms.
|
|
82
|
+
# Idempotent: does not overwrite existing arms.
|
|
83
|
+
bandit_init() {
|
|
84
|
+
_bandit_ensure_dir
|
|
85
|
+
local state
|
|
86
|
+
state="$(_bandit_read_state)"
|
|
87
|
+
|
|
88
|
+
# Ensure model_arms and template_arms keys exist
|
|
89
|
+
local has_model_arms has_template_arms
|
|
90
|
+
has_model_arms=$(echo "$state" | jq -r 'has("model_arms")' 2>/dev/null || echo "false")
|
|
91
|
+
has_template_arms=$(echo "$state" | jq -r 'has("template_arms")' 2>/dev/null || echo "false")
|
|
92
|
+
|
|
93
|
+
if [[ "$has_model_arms" != "true" ]]; then
|
|
94
|
+
state=$(echo "$state" | jq '. + {"model_arms": {}}')
|
|
95
|
+
fi
|
|
96
|
+
if [[ "$has_template_arms" != "true" ]]; then
|
|
97
|
+
state=$(echo "$state" | jq '. + {"template_arms": {}}')
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
# Initialize model arms: stage × model
|
|
101
|
+
local IFS_OLD="$IFS"
|
|
102
|
+
IFS=','
|
|
103
|
+
local stages_arr=($BANDIT_STAGES)
|
|
104
|
+
local models_arr=($BANDIT_MODELS)
|
|
105
|
+
local templates_arr=($BANDIT_TEMPLATES)
|
|
106
|
+
local types_arr=($BANDIT_ISSUE_TYPES)
|
|
107
|
+
IFS="$IFS_OLD"
|
|
108
|
+
|
|
109
|
+
local stage model key existing
|
|
110
|
+
for stage in "${stages_arr[@]}"; do
|
|
111
|
+
for model in "${models_arr[@]}"; do
|
|
112
|
+
key="$(_arm_key "$stage" "$model")"
|
|
113
|
+
existing=$(echo "$state" | jq -r --arg k "$key" '.model_arms | has($k)' 2>/dev/null || echo "false")
|
|
114
|
+
if [[ "$existing" != "true" ]]; then
|
|
115
|
+
state=$(echo "$state" | jq --arg k "$key" \
|
|
116
|
+
'.model_arms[$k] = {"alpha": 1, "beta": 1, "pulls": 0, "successes": 0}')
|
|
117
|
+
fi
|
|
118
|
+
done
|
|
119
|
+
done
|
|
120
|
+
|
|
121
|
+
# Initialize template arms: issue_type × template
|
|
122
|
+
local itype tmpl
|
|
123
|
+
for itype in "${types_arr[@]}"; do
|
|
124
|
+
for tmpl in "${templates_arr[@]}"; do
|
|
125
|
+
key="$(_arm_key "$itype" "$tmpl")"
|
|
126
|
+
existing=$(echo "$state" | jq -r --arg k "$key" '.template_arms | has($k)' 2>/dev/null || echo "false")
|
|
127
|
+
if [[ "$existing" != "true" ]]; then
|
|
128
|
+
state=$(echo "$state" | jq --arg k "$key" \
|
|
129
|
+
'.template_arms[$k] = {"alpha": 1, "beta": 1, "pulls": 0, "successes": 0}')
|
|
130
|
+
fi
|
|
131
|
+
done
|
|
132
|
+
done
|
|
133
|
+
|
|
134
|
+
# Add metadata
|
|
135
|
+
state=$(echo "$state" | jq --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
|
|
136
|
+
'. + {"initialized_at": $ts, "version": "3.2.4"}')
|
|
137
|
+
|
|
138
|
+
_bandit_write_state "$state"
|
|
139
|
+
info "Bandit arms initialized ($(echo "$state" | jq '.model_arms | length') model, $(echo "$state" | jq '.template_arms | length') template)"
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
# Select model for a given stage via Thompson sampling.
|
|
143
|
+
# Usage: bandit_select_model <stage> [models_csv]
|
|
144
|
+
# Output: model_name (to stdout)
|
|
145
|
+
# Returns 0 on success, 1 on error.
|
|
146
|
+
bandit_select_model() {
|
|
147
|
+
local stage="${1:-build}"
|
|
148
|
+
local models_csv="${2:-$BANDIT_MODELS}"
|
|
149
|
+
|
|
150
|
+
local state
|
|
151
|
+
state="$(_bandit_read_state)"
|
|
152
|
+
|
|
153
|
+
# Check if state has model_arms
|
|
154
|
+
local has_arms
|
|
155
|
+
has_arms=$(echo "$state" | jq -r 'has("model_arms")' 2>/dev/null || echo "false")
|
|
156
|
+
if [[ "$has_arms" != "true" ]]; then
|
|
157
|
+
# Auto-init if missing
|
|
158
|
+
bandit_init >/dev/null 2>&1
|
|
159
|
+
state="$(_bandit_read_state)"
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
local IFS_OLD="$IFS"
|
|
163
|
+
IFS=','
|
|
164
|
+
local models_arr=($models_csv)
|
|
165
|
+
IFS="$IFS_OLD"
|
|
166
|
+
|
|
167
|
+
local best_model="" best_sample="-1"
|
|
168
|
+
local model key alpha beta sample
|
|
169
|
+
|
|
170
|
+
for model in "${models_arr[@]}"; do
|
|
171
|
+
key="$(_arm_key "$stage" "$model")"
|
|
172
|
+
alpha=$(echo "$state" | jq -r --arg k "$key" '.model_arms[$k].alpha // 1' 2>/dev/null)
|
|
173
|
+
beta=$(echo "$state" | jq -r --arg k "$key" '.model_arms[$k].beta // 1' 2>/dev/null)
|
|
174
|
+
sample=$(_beta_sample "$alpha" "$beta")
|
|
175
|
+
|
|
176
|
+
# Compare floats in awk
|
|
177
|
+
local is_better
|
|
178
|
+
is_better=$(awk -v s="$sample" -v b="$best_sample" 'BEGIN { print (s > b) ? "1" : "0" }')
|
|
179
|
+
if [[ "$is_better" == "1" ]]; then
|
|
180
|
+
best_sample="$sample"
|
|
181
|
+
best_model="$model"
|
|
182
|
+
fi
|
|
183
|
+
done
|
|
184
|
+
|
|
185
|
+
if [[ -z "$best_model" ]]; then
|
|
186
|
+
# Fallback to first model
|
|
187
|
+
best_model="${models_arr[0]}"
|
|
188
|
+
fi
|
|
189
|
+
|
|
190
|
+
echo "$best_model"
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
# Select template for a given issue type via Thompson sampling.
|
|
194
|
+
# Usage: bandit_select_template <issue_type> [templates_csv]
|
|
195
|
+
# Output: template_name (to stdout)
|
|
196
|
+
bandit_select_template() {
|
|
197
|
+
local issue_type="${1:-bug}"
|
|
198
|
+
local templates_csv="${2:-$BANDIT_TEMPLATES}"
|
|
199
|
+
|
|
200
|
+
local state
|
|
201
|
+
state="$(_bandit_read_state)"
|
|
202
|
+
|
|
203
|
+
local has_arms
|
|
204
|
+
has_arms=$(echo "$state" | jq -r 'has("template_arms")' 2>/dev/null || echo "false")
|
|
205
|
+
if [[ "$has_arms" != "true" ]]; then
|
|
206
|
+
bandit_init >/dev/null 2>&1
|
|
207
|
+
state="$(_bandit_read_state)"
|
|
208
|
+
fi
|
|
209
|
+
|
|
210
|
+
local IFS_OLD="$IFS"
|
|
211
|
+
IFS=','
|
|
212
|
+
local templates_arr=($templates_csv)
|
|
213
|
+
IFS="$IFS_OLD"
|
|
214
|
+
|
|
215
|
+
local best_template="" best_sample="-1"
|
|
216
|
+
local tmpl key alpha beta sample
|
|
217
|
+
|
|
218
|
+
for tmpl in "${templates_arr[@]}"; do
|
|
219
|
+
key="$(_arm_key "$issue_type" "$tmpl")"
|
|
220
|
+
alpha=$(echo "$state" | jq -r --arg k "$key" '.template_arms[$k].alpha // 1' 2>/dev/null)
|
|
221
|
+
beta=$(echo "$state" | jq -r --arg k "$key" '.template_arms[$k].beta // 1' 2>/dev/null)
|
|
222
|
+
sample=$(_beta_sample "$alpha" "$beta")
|
|
223
|
+
|
|
224
|
+
local is_better
|
|
225
|
+
is_better=$(awk -v s="$sample" -v b="$best_sample" 'BEGIN { print (s > b) ? "1" : "0" }')
|
|
226
|
+
if [[ "$is_better" == "1" ]]; then
|
|
227
|
+
best_sample="$sample"
|
|
228
|
+
best_template="$tmpl"
|
|
229
|
+
fi
|
|
230
|
+
done
|
|
231
|
+
|
|
232
|
+
if [[ -z "$best_template" ]]; then
|
|
233
|
+
best_template="${templates_arr[0]}"
|
|
234
|
+
fi
|
|
235
|
+
|
|
236
|
+
echo "$best_template"
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
# Update arm after pipeline completion.
|
|
240
|
+
# Usage: bandit_update <arm_type> <key> <outcome>
|
|
241
|
+
# arm_type: "model" or "template"
|
|
242
|
+
# key: e.g. "build:opus" or "bug:fast"
|
|
243
|
+
# outcome: "success" or "failure"
|
|
244
|
+
bandit_update() {
|
|
245
|
+
local arm_type="${1:-model}"
|
|
246
|
+
local key="${2:-}"
|
|
247
|
+
local outcome="${3:-failure}"
|
|
248
|
+
|
|
249
|
+
if [[ -z "$key" ]]; then
|
|
250
|
+
error "bandit_update: arm key required"
|
|
251
|
+
return 1
|
|
252
|
+
fi
|
|
253
|
+
|
|
254
|
+
local state
|
|
255
|
+
state="$(_bandit_read_state)"
|
|
256
|
+
|
|
257
|
+
local section
|
|
258
|
+
if [[ "$arm_type" == "model" ]]; then
|
|
259
|
+
section="model_arms"
|
|
260
|
+
else
|
|
261
|
+
section="template_arms"
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
# Check arm exists
|
|
265
|
+
local arm_exists
|
|
266
|
+
arm_exists=$(echo "$state" | jq -r --arg s "$section" --arg k "$key" '.[$s] | has($k)' 2>/dev/null || echo "false")
|
|
267
|
+
if [[ "$arm_exists" != "true" ]]; then
|
|
268
|
+
# Create arm on the fly with Beta(1,1)
|
|
269
|
+
state=$(echo "$state" | jq --arg s "$section" --arg k "$key" \
|
|
270
|
+
'.[$s][$k] = {"alpha": 1, "beta": 1, "pulls": 0, "successes": 0}')
|
|
271
|
+
fi
|
|
272
|
+
|
|
273
|
+
# Update based on outcome
|
|
274
|
+
if [[ "$outcome" == "success" ]]; then
|
|
275
|
+
state=$(echo "$state" | jq --arg s "$section" --arg k "$key" \
|
|
276
|
+
'.[$s][$k].alpha += 1 | .[$s][$k].pulls += 1 | .[$s][$k].successes += 1')
|
|
277
|
+
else
|
|
278
|
+
state=$(echo "$state" | jq --arg s "$section" --arg k "$key" \
|
|
279
|
+
'.[$s][$k].beta += 1 | .[$s][$k].pulls += 1')
|
|
280
|
+
fi
|
|
281
|
+
|
|
282
|
+
# Add last_updated timestamp
|
|
283
|
+
state=$(echo "$state" | jq --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
|
|
284
|
+
'. + {"last_updated": $ts}')
|
|
285
|
+
|
|
286
|
+
_bandit_write_state "$state"
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
# Return exploration rate for a given arm set.
|
|
290
|
+
# Exploration rate = proportion of arms where pulls < threshold (default 10).
|
|
291
|
+
# As arms accumulate data, exploration naturally decreases.
|
|
292
|
+
# Usage: bandit_explore_rate [arm_type] [threshold]
|
|
293
|
+
# Output: float between 0 and 1
|
|
294
|
+
bandit_explore_rate() {
|
|
295
|
+
local arm_type="${1:-model}"
|
|
296
|
+
local threshold="${2:-10}"
|
|
297
|
+
|
|
298
|
+
local state
|
|
299
|
+
state="$(_bandit_read_state)"
|
|
300
|
+
|
|
301
|
+
local section
|
|
302
|
+
if [[ "$arm_type" == "model" ]]; then
|
|
303
|
+
section="model_arms"
|
|
304
|
+
else
|
|
305
|
+
section="template_arms"
|
|
306
|
+
fi
|
|
307
|
+
|
|
308
|
+
echo "$state" | jq -r --arg s "$section" --arg t "$threshold" '
|
|
309
|
+
.[$s] // {} | to_entries |
|
|
310
|
+
if length == 0 then "1.0000"
|
|
311
|
+
else
|
|
312
|
+
(map(select(.value.pulls < ($t | tonumber))) | length) as $under |
|
|
313
|
+
(length) as $total |
|
|
314
|
+
($under / $total) | tostring | .[0:6]
|
|
315
|
+
end
|
|
316
|
+
' 2>/dev/null || echo "1.0000"
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
# Show arm statistics with success rates.
|
|
320
|
+
# Usage: bandit_report [arm_type] [filter_prefix]
|
|
321
|
+
bandit_report() {
|
|
322
|
+
local arm_type="${1:-model}"
|
|
323
|
+
local filter_prefix="${2:-}"
|
|
324
|
+
|
|
325
|
+
local state
|
|
326
|
+
state="$(_bandit_read_state)"
|
|
327
|
+
|
|
328
|
+
local section
|
|
329
|
+
if [[ "$arm_type" == "model" ]]; then
|
|
330
|
+
section="model_arms"
|
|
331
|
+
echo "╔═══════════════════════════════════════════════════════════════╗"
|
|
332
|
+
echo "║ Model Arm Statistics ║"
|
|
333
|
+
echo "╚═══════════════════════════════════════════════════════════════╝"
|
|
334
|
+
else
|
|
335
|
+
section="template_arms"
|
|
336
|
+
echo "╔═══════════════════════════════════════════════════════════════╗"
|
|
337
|
+
echo "║ Template Arm Statistics ║"
|
|
338
|
+
echo "╚═══════════════════════════════════════════════════════════════╝"
|
|
339
|
+
fi
|
|
340
|
+
|
|
341
|
+
local jq_filter
|
|
342
|
+
if [[ -n "$filter_prefix" ]]; then
|
|
343
|
+
jq_filter='.[$s] // {} | to_entries | map(select(.key | startswith($p)))'
|
|
344
|
+
else
|
|
345
|
+
jq_filter='.[$s] // {} | to_entries'
|
|
346
|
+
fi
|
|
347
|
+
|
|
348
|
+
# Get sorted arms (by success rate descending)
|
|
349
|
+
local arms_json
|
|
350
|
+
arms_json=$(echo "$state" | jq -r --arg s "$section" --arg p "$filter_prefix" "
|
|
351
|
+
$jq_filter |
|
|
352
|
+
sort_by(-(.value.successes / ([.value.pulls, 1] | max))) |
|
|
353
|
+
.[] |
|
|
354
|
+
.key + \"|\" +
|
|
355
|
+
(.value.alpha | tostring) + \"|\" +
|
|
356
|
+
(.value.beta | tostring) + \"|\" +
|
|
357
|
+
(.value.pulls | tostring) + \"|\" +
|
|
358
|
+
(.value.successes | tostring)
|
|
359
|
+
" 2>/dev/null || true)
|
|
360
|
+
|
|
361
|
+
if [[ -z "$arms_json" ]]; then
|
|
362
|
+
echo " No arms found."
|
|
363
|
+
return 0
|
|
364
|
+
fi
|
|
365
|
+
|
|
366
|
+
local first=1
|
|
367
|
+
echo ""
|
|
368
|
+
printf " %-25s %8s %8s %8s %10s\n" "Arm" "α" "β" "Pulls" "Success%"
|
|
369
|
+
printf " %-25s %8s %8s %8s %10s\n" "-------------------------" "--------" "--------" "--------" "----------"
|
|
370
|
+
|
|
371
|
+
echo "$arms_json" | while IFS='|' read -r key alpha beta pulls successes; do
|
|
372
|
+
local rate
|
|
373
|
+
if [[ "$pulls" -gt 0 ]]; then
|
|
374
|
+
rate=$(awk -v s="$successes" -v p="$pulls" 'BEGIN { printf "%.1f%%", (s/p)*100 }')
|
|
375
|
+
else
|
|
376
|
+
rate="N/A"
|
|
377
|
+
fi
|
|
378
|
+
local marker=""
|
|
379
|
+
if [[ "$first" -eq 1 ]] && [[ "$pulls" -gt 0 ]]; then
|
|
380
|
+
marker=" ★"
|
|
381
|
+
first=0
|
|
382
|
+
fi
|
|
383
|
+
printf " %-25s %8s %8s %8s %10s%s\n" "$key" "$alpha" "$beta" "$pulls" "$rate" "$marker"
|
|
384
|
+
done
|
|
385
|
+
|
|
386
|
+
echo ""
|
|
387
|
+
local explore_rate
|
|
388
|
+
explore_rate=$(bandit_explore_rate "$arm_type")
|
|
389
|
+
echo " Exploration rate: $explore_rate"
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
# Get arm statistics as JSON for a specific arm.
|
|
393
|
+
# Usage: bandit_get_arm <arm_type> <key>
|
|
394
|
+
bandit_get_arm() {
|
|
395
|
+
local arm_type="${1:-model}"
|
|
396
|
+
local key="${2:-}"
|
|
397
|
+
|
|
398
|
+
local state
|
|
399
|
+
state="$(_bandit_read_state)"
|
|
400
|
+
|
|
401
|
+
local section
|
|
402
|
+
if [[ "$arm_type" == "model" ]]; then
|
|
403
|
+
section="model_arms"
|
|
404
|
+
else
|
|
405
|
+
section="template_arms"
|
|
406
|
+
fi
|
|
407
|
+
|
|
408
|
+
echo "$state" | jq -r --arg s "$section" --arg k "$key" '.[$s][$k] // empty' 2>/dev/null
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
# Reset a specific arm back to Beta(1,1).
|
|
412
|
+
# Usage: bandit_reset_arm <arm_type> <key>
|
|
413
|
+
bandit_reset_arm() {
|
|
414
|
+
local arm_type="${1:-model}"
|
|
415
|
+
local key="${2:-}"
|
|
416
|
+
|
|
417
|
+
local state
|
|
418
|
+
state="$(_bandit_read_state)"
|
|
419
|
+
|
|
420
|
+
local section
|
|
421
|
+
if [[ "$arm_type" == "model" ]]; then
|
|
422
|
+
section="model_arms"
|
|
423
|
+
else
|
|
424
|
+
section="template_arms"
|
|
425
|
+
fi
|
|
426
|
+
|
|
427
|
+
state=$(echo "$state" | jq --arg s "$section" --arg k "$key" \
|
|
428
|
+
'.[$s][$k] = {"alpha": 1, "beta": 1, "pulls": 0, "successes": 0}')
|
|
429
|
+
|
|
430
|
+
_bandit_write_state "$state"
|
|
431
|
+
}
|
package/scripts/lib/bootstrap.sh
CHANGED
|
@@ -1,9 +1,111 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# ╔═══════════════════════════════════════════════════════════════════════════╗
|
|
3
|
-
# ║ shipwright bootstrap —
|
|
4
|
-
# ║
|
|
3
|
+
# ║ shipwright bootstrap — Boilerplate consolidation + initialization ║
|
|
4
|
+
# ║ ║
|
|
5
|
+
# ║ Part 1: Boilerplate elimination (SCRIPT_DIR, ERR trap, library loading) ║
|
|
6
|
+
# ║ Part 2: Cold-start initialization (optimization, memory defaults) ║
|
|
7
|
+
# ║ Part 3: Helper functions (show_help_header for standard boxed headers) ║
|
|
5
8
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
6
9
|
|
|
10
|
+
# ─── Module Guard (prevent double-sourcing) ─────────────────────────────
|
|
11
|
+
[[ -n "${_SW_BOOTSTRAP_LOADED:-}" ]] && return 0
|
|
12
|
+
_SW_BOOTSTRAP_LOADED=1
|
|
13
|
+
|
|
14
|
+
# ─── Part 1: Boilerplate Elimination ───────────────────────────────────
|
|
15
|
+
#
|
|
16
|
+
# SCRIPT_DIR Resolution: Caller's BASH_SOURCE[0] is expected to be in scripts/
|
|
17
|
+
# We derive SCRIPT_DIR from the call stack, skipping lib/ sources.
|
|
18
|
+
if [[ -z "${SCRIPT_DIR:-}" ]]; then
|
|
19
|
+
# Find the first non-lib caller (skip lib/bootstrap.sh itself)
|
|
20
|
+
for _src in "${BASH_SOURCE[@]}"; do
|
|
21
|
+
if [[ "$_src" != *"/lib/"* && "$_src" != "$BASH_SOURCE" ]]; then
|
|
22
|
+
SCRIPT_DIR="$(cd "$(dirname "$_src")" && pwd)"
|
|
23
|
+
break
|
|
24
|
+
fi
|
|
25
|
+
done
|
|
26
|
+
# Fallback if all sources are in lib/
|
|
27
|
+
if [[ -z "${SCRIPT_DIR:-}" ]]; then
|
|
28
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
29
|
+
SCRIPT_DIR="${SCRIPT_DIR%/lib}" # strip /lib suffix if present
|
|
30
|
+
fi
|
|
31
|
+
fi
|
|
32
|
+
export SCRIPT_DIR
|
|
33
|
+
|
|
34
|
+
# Set up ERR trap (if not already set)
|
|
35
|
+
if [[ "$(trap -p ERR)" == "" ]]; then
|
|
36
|
+
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# Source lib/compat.sh (cross-platform compatibility)
|
|
40
|
+
# shellcheck source=./compat.sh
|
|
41
|
+
if [[ -f "$SCRIPT_DIR/lib/compat.sh" ]]; then
|
|
42
|
+
source "$SCRIPT_DIR/lib/compat.sh"
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# Source lib/helpers.sh (colors, output, timestamps)
|
|
46
|
+
# shellcheck source=./helpers.sh
|
|
47
|
+
if [[ -f "$SCRIPT_DIR/lib/helpers.sh" ]]; then
|
|
48
|
+
source "$SCRIPT_DIR/lib/helpers.sh"
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# Fallbacks (when helpers not loaded, e.g. test env)
|
|
52
|
+
[[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
|
|
53
|
+
[[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
|
|
54
|
+
[[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
|
|
55
|
+
[[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
|
|
56
|
+
|
|
57
|
+
# Color fallbacks (when NO_COLOR is set or lib/helpers.sh not sourced)
|
|
58
|
+
if [[ -z "${CYAN:-}" ]]; then
|
|
59
|
+
CYAN='\033[38;2;0;212;255m'
|
|
60
|
+
PURPLE='\033[38;2;124;58;237m'
|
|
61
|
+
BLUE='\033[38;2;0;102;255m'
|
|
62
|
+
GREEN='\033[38;2;74;222;128m'
|
|
63
|
+
YELLOW='\033[38;2;250;204;21m'
|
|
64
|
+
RED='\033[38;2;248;113;113m'
|
|
65
|
+
DIM='\033[2m'
|
|
66
|
+
BOLD='\033[1m'
|
|
67
|
+
RESET='\033[0m'
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
|
|
71
|
+
now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
|
|
72
|
+
now_epoch() { date +%s; }
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
76
|
+
emit_event() {
|
|
77
|
+
local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
|
|
78
|
+
# shellcheck disable=SC2155
|
|
79
|
+
local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
|
|
80
|
+
while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
|
|
81
|
+
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
82
|
+
}
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# ─── Part 3: Standard Header Helper ────────────────────────────────────
|
|
86
|
+
#
|
|
87
|
+
# show_help_header — Prints a standard boxed header with script name, description, and version.
|
|
88
|
+
# Usage:
|
|
89
|
+
# show_help_header "Script Name" "Optional description line"
|
|
90
|
+
show_help_header() {
|
|
91
|
+
local name="$1"
|
|
92
|
+
local desc="${2:-}"
|
|
93
|
+
|
|
94
|
+
echo ""
|
|
95
|
+
if [[ -n "$desc" ]]; then
|
|
96
|
+
echo -e "${CYAN}${BOLD} ${name}${RESET} ${DIM}v${VERSION:-unknown}${RESET}"
|
|
97
|
+
echo -e "${DIM} $(printf '%0.s═' $(seq 1 42))${RESET}"
|
|
98
|
+
echo ""
|
|
99
|
+
echo -e " ${desc}"
|
|
100
|
+
else
|
|
101
|
+
echo -e "${CYAN}${BOLD} ${name}${RESET} ${DIM}v${VERSION:-unknown}${RESET}"
|
|
102
|
+
echo -e "${DIM} $(printf '%0.s═' $(seq 1 42))${RESET}"
|
|
103
|
+
fi
|
|
104
|
+
echo ""
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
# ─── Part 2: Cold-Start Initialization ────────────────────────────────
|
|
108
|
+
#
|
|
7
109
|
# bootstrap_optimization — create default iteration model, template weights, model routing
|
|
8
110
|
bootstrap_optimization() {
|
|
9
111
|
local opt_dir="$HOME/.shipwright/optimization"
|