shipwright-cli 3.2.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 +4 -4
- 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/dashboard/middleware/auth.ts +134 -0
- package/dashboard/middleware/constants.ts +21 -0
- package/dashboard/public/index.html +2 -6
- package/dashboard/public/styles.css +100 -97
- package/dashboard/routes/auth.ts +38 -0
- package/dashboard/server.ts +66 -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/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 +2 -1
- package/dashboard/src/views/activity.ts +2 -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 +10 -0
- package/scripts/lib/daemon-dispatch.sh +106 -17
- package/scripts/lib/daemon-failure.sh +34 -4
- package/scripts/lib/daemon-patrol.sh +23 -2
- 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 +112 -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 +177 -4
- 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 +100 -2
- 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 +100 -1136
- package/scripts/lib/pipeline-quality-bash-compat.sh +182 -0
- package/scripts/lib/pipeline-quality-checks.sh +17 -715
- 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 +59 -2929
- 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 -2
- package/scripts/sw-adaptive.sh +2 -1
- 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 +5 -1
- package/scripts/sw-cleanup.sh +4 -26
- package/scripts/sw-code-review.sh +10 -4
- package/scripts/sw-connect.sh +2 -1
- package/scripts/sw-context.sh +2 -1
- package/scripts/sw-cost.sh +48 -3
- package/scripts/sw-daemon.sh +66 -9
- package/scripts/sw-dashboard.sh +3 -1
- package/scripts/sw-db.sh +59 -16
- 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 +325 -2
- 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 +4 -3
- package/scripts/sw-e2e-orchestrator.sh +17 -16
- package/scripts/sw-eventbus.sh +7 -1
- 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 +4 -1
- package/scripts/sw-fleet.sh +5 -1
- package/scripts/sw-github-app.sh +16 -3
- 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 +6 -1
- package/scripts/sw-incident.sh +265 -1
- package/scripts/sw-init.sh +18 -2
- package/scripts/sw-instrument.sh +10 -2
- package/scripts/sw-intelligence.sh +42 -6
- 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 +432 -1128
- package/scripts/sw-memory.sh +356 -2
- package/scripts/sw-mission-control.sh +6 -1
- package/scripts/sw-model-router.sh +481 -26
- package/scripts/sw-otel.sh +13 -4
- package/scripts/sw-oversight.sh +14 -5
- package/scripts/sw-patrol-meta.sh +334 -0
- package/scripts/sw-pipeline-composer.sh +5 -1
- package/scripts/sw-pipeline-vitals.sh +2 -1
- package/scripts/sw-pipeline.sh +53 -2664
- package/scripts/sw-pm.sh +12 -5
- package/scripts/sw-pr-lifecycle.sh +2 -1
- package/scripts/sw-predictive.sh +7 -1
- package/scripts/sw-prep.sh +185 -2
- package/scripts/sw-ps.sh +5 -25
- package/scripts/sw-public-dashboard.sh +15 -3
- package/scripts/sw-quality.sh +2 -1
- 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 +10 -3
- package/scripts/sw-security-audit.sh +6 -1
- package/scripts/sw-self-optimize.sh +6 -3
- 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 +4 -1
- package/scripts/sw-stream.sh +7 -1
- package/scripts/sw-swarm.sh +18 -6
- package/scripts/sw-team-stages.sh +13 -6
- package/scripts/sw-templates.sh +5 -29
- package/scripts/sw-testgen.sh +7 -1
- 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 +3 -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 +2 -1
- package/scripts/sw-upgrade.sh +3 -1
- package/scripts/sw-ux.sh +5 -2
- package/scripts/sw-webhook.sh +3 -1
- package/scripts/sw-widgets.sh +3 -1
- 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
package/scripts/sw-doctor.sh
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# ║ ║
|
|
5
5
|
# ║ Checks prerequisites, installed files, PATH, and common issues. ║
|
|
6
6
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
7
|
-
VERSION="3.
|
|
7
|
+
VERSION="3.3.0"
|
|
8
8
|
set -euo pipefail
|
|
9
9
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
10
10
|
|
|
@@ -27,6 +27,7 @@ fi
|
|
|
27
27
|
if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
28
28
|
emit_event() {
|
|
29
29
|
local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
|
|
30
|
+
# shellcheck disable=SC2155
|
|
30
31
|
local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
|
|
31
32
|
while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
|
|
32
33
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
@@ -39,10 +40,14 @@ SKIP_PLATFORM_SCAN=false
|
|
|
39
40
|
|
|
40
41
|
# Parse doctor flags
|
|
41
42
|
INTELLIGENCE_ONLY=false
|
|
43
|
+
DOCTOR_FIX_MODE=false
|
|
44
|
+
DOCTOR_FIX_DRY_RUN=false
|
|
42
45
|
for _arg in "$@"; do
|
|
43
46
|
case "$_arg" in
|
|
44
47
|
--skip-platform-scan) SKIP_PLATFORM_SCAN=true ;;
|
|
45
48
|
--intelligence) INTELLIGENCE_ONLY=true ;;
|
|
49
|
+
--fix) DOCTOR_FIX_MODE=true ;;
|
|
50
|
+
--fix-dry) DOCTOR_FIX_DRY_RUN=true; DOCTOR_FIX_MODE=true ;;
|
|
46
51
|
--version|-V) echo "sw-doctor $VERSION"; exit 0 ;;
|
|
47
52
|
esac
|
|
48
53
|
done
|
|
@@ -51,6 +56,291 @@ check_pass() { success "$*"; PASS=$((PASS + 1)); }
|
|
|
51
56
|
check_warn() { warn "$*"; WARN=$((WARN + 1)); }
|
|
52
57
|
check_fail() { error "$*"; FAIL=$((FAIL + 1)); }
|
|
53
58
|
|
|
59
|
+
# ─── Auto-fix helper functions ──────────────────────────────────────────────
|
|
60
|
+
doctor_fix_missing_dirs() {
|
|
61
|
+
local result="fixed"
|
|
62
|
+
local dirs=(
|
|
63
|
+
"$HOME/.shipwright"
|
|
64
|
+
"$HOME/.shipwright/optimization"
|
|
65
|
+
"$HOME/.shipwright/memory"
|
|
66
|
+
".claude"
|
|
67
|
+
".claude/pipeline-artifacts"
|
|
68
|
+
".claude/agents"
|
|
69
|
+
".claude/hooks"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
for dir in "${dirs[@]}"; do
|
|
73
|
+
if [[ ! -d "$dir" ]]; then
|
|
74
|
+
if [[ "$DOCTOR_FIX_DRY_RUN" == "true" ]]; then
|
|
75
|
+
info " [DRY] Would create directory: $dir"
|
|
76
|
+
else
|
|
77
|
+
if ! mkdir -p "$dir" 2>/dev/null; then
|
|
78
|
+
result="skipped"
|
|
79
|
+
else
|
|
80
|
+
emit_event "doctor_fix" "type=mkdir" "path=$dir"
|
|
81
|
+
fi
|
|
82
|
+
fi
|
|
83
|
+
fi
|
|
84
|
+
done
|
|
85
|
+
echo "$result"
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
doctor_fix_permissions() {
|
|
89
|
+
local result="fixed"
|
|
90
|
+
local script_dir="${1:-.}"
|
|
91
|
+
|
|
92
|
+
if [[ ! -d "$script_dir" ]]; then
|
|
93
|
+
echo "skipped"
|
|
94
|
+
return
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
# Fix script permissions
|
|
98
|
+
for script in "$script_dir"/sw-*.sh; do
|
|
99
|
+
if [[ -f "$script" && ! -x "$script" ]]; then
|
|
100
|
+
if [[ "$DOCTOR_FIX_DRY_RUN" == "true" ]]; then
|
|
101
|
+
info " [DRY] Would chmod +x: $script"
|
|
102
|
+
else
|
|
103
|
+
chmod +x "$script"
|
|
104
|
+
emit_event "doctor_fix" "type=chmod" "path=$script"
|
|
105
|
+
fi
|
|
106
|
+
fi
|
|
107
|
+
done
|
|
108
|
+
|
|
109
|
+
echo "$result"
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
doctor_fix_missing_config() {
|
|
113
|
+
local result="fixed"
|
|
114
|
+
|
|
115
|
+
# Ensure .claude directory exists
|
|
116
|
+
mkdir -p .claude 2>/dev/null || { result="skipped"; echo "$result"; return; }
|
|
117
|
+
|
|
118
|
+
# Create .claude/daemon-config.json
|
|
119
|
+
local daemon_cfg=".claude/daemon-config.json"
|
|
120
|
+
if [[ ! -f "$daemon_cfg" ]]; then
|
|
121
|
+
if [[ "$DOCTOR_FIX_DRY_RUN" == "true" ]]; then
|
|
122
|
+
info " [DRY] Would create: $daemon_cfg"
|
|
123
|
+
else
|
|
124
|
+
local tmp_cfg="${daemon_cfg}.tmp.$$"
|
|
125
|
+
cat > "$tmp_cfg" <<'EOF'
|
|
126
|
+
{
|
|
127
|
+
"max_parallel": 2,
|
|
128
|
+
"auto_scale": false,
|
|
129
|
+
"max_workers": 8,
|
|
130
|
+
"min_workers": 1,
|
|
131
|
+
"auto_scale_interval": 5,
|
|
132
|
+
"worker_mem_gb": 4,
|
|
133
|
+
"estimated_cost_per_job_usd": 5.0,
|
|
134
|
+
"auto_template": false,
|
|
135
|
+
"max_retries": 2,
|
|
136
|
+
"priority_lane": false,
|
|
137
|
+
"self_optimize": false,
|
|
138
|
+
"intelligence": {
|
|
139
|
+
"enabled": "auto",
|
|
140
|
+
"composer_enabled": "auto",
|
|
141
|
+
"prediction_enabled": true,
|
|
142
|
+
"cache_ttl_seconds": 3600,
|
|
143
|
+
"adversarial_enabled": false,
|
|
144
|
+
"simulation_enabled": false,
|
|
145
|
+
"architecture_enabled": false,
|
|
146
|
+
"ab_test_ratio": 0.2,
|
|
147
|
+
"anomaly_threshold": 3.0
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
EOF
|
|
151
|
+
mv "$tmp_cfg" "$daemon_cfg"
|
|
152
|
+
emit_event "doctor_fix" "type=create_config" "path=$daemon_cfg"
|
|
153
|
+
fi
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
# Create .claude/settings.json
|
|
157
|
+
local settings_cfg=".claude/settings.json"
|
|
158
|
+
if [[ ! -f "$settings_cfg" ]]; then
|
|
159
|
+
if [[ "$DOCTOR_FIX_DRY_RUN" == "true" ]]; then
|
|
160
|
+
info " [DRY] Would create: $settings_cfg"
|
|
161
|
+
else
|
|
162
|
+
local tmp_cfg="${settings_cfg}.tmp.$$"
|
|
163
|
+
cat > "$tmp_cfg" <<'EOF'
|
|
164
|
+
{
|
|
165
|
+
"hooks": {
|
|
166
|
+
"pre-tool-use": ".claude/hooks/pre-tool-use.sh",
|
|
167
|
+
"post-tool-use": ".claude/hooks/post-tool-use.sh",
|
|
168
|
+
"session-started": ".claude/hooks/session-started.sh"
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
EOF
|
|
172
|
+
mv "$tmp_cfg" "$settings_cfg"
|
|
173
|
+
emit_event "doctor_fix" "type=create_config" "path=$settings_cfg"
|
|
174
|
+
fi
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
# Create ~/.shipwright/budget.json
|
|
178
|
+
local budget_file="$HOME/.shipwright/budget.json"
|
|
179
|
+
if [[ ! -f "$budget_file" ]]; then
|
|
180
|
+
if [[ "$DOCTOR_FIX_DRY_RUN" == "true" ]]; then
|
|
181
|
+
info " [DRY] Would create: $budget_file"
|
|
182
|
+
else
|
|
183
|
+
local tmp_file="${budget_file}.tmp.$$"
|
|
184
|
+
cat > "$tmp_file" <<'EOF'
|
|
185
|
+
{
|
|
186
|
+
"daily_limit_usd": 10.0,
|
|
187
|
+
"reset_hour_utc": 0,
|
|
188
|
+
"enabled": true
|
|
189
|
+
}
|
|
190
|
+
EOF
|
|
191
|
+
mkdir -p "$(dirname "$budget_file")"
|
|
192
|
+
mv "$tmp_file" "$budget_file"
|
|
193
|
+
emit_event "doctor_fix" "type=create_config" "path=$budget_file"
|
|
194
|
+
fi
|
|
195
|
+
fi
|
|
196
|
+
|
|
197
|
+
echo "$result"
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
doctor_fix_tmux_config() {
|
|
201
|
+
local result="fixed"
|
|
202
|
+
local home_tmux_conf="$HOME/.tmux.conf"
|
|
203
|
+
|
|
204
|
+
# Check if overlay exists
|
|
205
|
+
local overlay_path="$HOME/.tmux/shipwright-overlay.conf"
|
|
206
|
+
if [[ ! -f "$overlay_path" ]]; then
|
|
207
|
+
# Try to find it in the Shipwright repo
|
|
208
|
+
local repo_overlay="${SCRIPT_DIR}/../tmux/shipwright-overlay.conf"
|
|
209
|
+
if [[ -f "$repo_overlay" ]]; then
|
|
210
|
+
if [[ "$DOCTOR_FIX_DRY_RUN" == "true" ]]; then
|
|
211
|
+
info " [DRY] Would copy tmux overlay to: $overlay_path"
|
|
212
|
+
else
|
|
213
|
+
mkdir -p "$(dirname "$overlay_path")"
|
|
214
|
+
cp "$repo_overlay" "$overlay_path"
|
|
215
|
+
emit_event "doctor_fix" "type=copy_tmux" "path=$overlay_path"
|
|
216
|
+
fi
|
|
217
|
+
else
|
|
218
|
+
result="skipped"
|
|
219
|
+
fi
|
|
220
|
+
fi
|
|
221
|
+
|
|
222
|
+
# Check if .tmux.conf sources the overlay
|
|
223
|
+
if [[ -f "$home_tmux_conf" ]] && ! grep -q "shipwright-overlay" "$home_tmux_conf"; then
|
|
224
|
+
if [[ "$DOCTOR_FIX_DRY_RUN" == "true" ]]; then
|
|
225
|
+
info " [DRY] Would update .tmux.conf to source overlay"
|
|
226
|
+
else
|
|
227
|
+
# Backup existing config
|
|
228
|
+
cp "$home_tmux_conf" "${home_tmux_conf}.bak"
|
|
229
|
+
echo "source-file ~/.tmux/shipwright-overlay.conf" >> "$home_tmux_conf"
|
|
230
|
+
emit_event "doctor_fix" "type=update_tmux" "path=$home_tmux_conf"
|
|
231
|
+
fi
|
|
232
|
+
fi
|
|
233
|
+
|
|
234
|
+
echo "$result"
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
doctor_fix_hooks() {
|
|
238
|
+
local result="fixed"
|
|
239
|
+
local hooks_dir=".claude/hooks"
|
|
240
|
+
|
|
241
|
+
mkdir -p "$hooks_dir" 2>/dev/null || true
|
|
242
|
+
|
|
243
|
+
# Try to copy hooks from Shipwright repo templates
|
|
244
|
+
local repo_hooks="${SCRIPT_DIR}/../templates/hooks"
|
|
245
|
+
if [[ -d "$repo_hooks" ]]; then
|
|
246
|
+
for hook_file in "$repo_hooks"/*.sh; do
|
|
247
|
+
if [[ -f "$hook_file" ]]; then
|
|
248
|
+
local hook_name="$(basename "$hook_file")"
|
|
249
|
+
local dest_hook="$hooks_dir/$hook_name"
|
|
250
|
+
if [[ ! -f "$dest_hook" ]]; then
|
|
251
|
+
if [[ "$DOCTOR_FIX_DRY_RUN" == "true" ]]; then
|
|
252
|
+
info " [DRY] Would install hook: $dest_hook"
|
|
253
|
+
else
|
|
254
|
+
cp "$hook_file" "$dest_hook"
|
|
255
|
+
chmod +x "$dest_hook"
|
|
256
|
+
emit_event "doctor_fix" "type=install_hook" "hook=$hook_name"
|
|
257
|
+
fi
|
|
258
|
+
fi
|
|
259
|
+
fi
|
|
260
|
+
done
|
|
261
|
+
else
|
|
262
|
+
result="skipped"
|
|
263
|
+
fi
|
|
264
|
+
|
|
265
|
+
echo "$result"
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
doctor_auto_fix() {
|
|
269
|
+
echo ""
|
|
270
|
+
echo -e "${PURPLE}${BOLD} AUTO-FIX SUMMARY${RESET}"
|
|
271
|
+
echo -e "${DIM} ──────────────────────────────────────────${RESET}"
|
|
272
|
+
echo ""
|
|
273
|
+
|
|
274
|
+
local fixes_applied=0
|
|
275
|
+
local fixes_skipped=0
|
|
276
|
+
|
|
277
|
+
# Fix 1: Missing directories
|
|
278
|
+
info "Creating missing directories..."
|
|
279
|
+
result=$(doctor_fix_missing_dirs)
|
|
280
|
+
if [[ "$result" == "fixed" ]]; then
|
|
281
|
+
success " Directories created/verified"
|
|
282
|
+
fixes_applied=$((fixes_applied + 1))
|
|
283
|
+
else
|
|
284
|
+
warn " Some directories could not be created"
|
|
285
|
+
fixes_skipped=$((fixes_skipped + 1))
|
|
286
|
+
fi
|
|
287
|
+
|
|
288
|
+
# Fix 2: Permissions
|
|
289
|
+
info "Fixing script permissions..."
|
|
290
|
+
result=$(doctor_fix_permissions "${SCRIPT_DIR}")
|
|
291
|
+
if [[ "$result" == "fixed" ]]; then
|
|
292
|
+
success " Script permissions fixed"
|
|
293
|
+
fixes_applied=$((fixes_applied + 1))
|
|
294
|
+
else
|
|
295
|
+
warn " Could not fix some permissions"
|
|
296
|
+
fixes_skipped=$((fixes_skipped + 1))
|
|
297
|
+
fi
|
|
298
|
+
|
|
299
|
+
# Fix 3: Missing config files
|
|
300
|
+
info "Creating missing config files..."
|
|
301
|
+
result=$(doctor_fix_missing_config)
|
|
302
|
+
if [[ "$result" == "fixed" ]]; then
|
|
303
|
+
success " Config files created"
|
|
304
|
+
fixes_applied=$((fixes_applied + 1))
|
|
305
|
+
else
|
|
306
|
+
warn " Could not create some config files"
|
|
307
|
+
fixes_skipped=$((fixes_skipped + 1))
|
|
308
|
+
fi
|
|
309
|
+
|
|
310
|
+
# Fix 4: tmux configuration
|
|
311
|
+
info "Configuring tmux..."
|
|
312
|
+
result=$(doctor_fix_tmux_config)
|
|
313
|
+
if [[ "$result" == "fixed" ]]; then
|
|
314
|
+
success " tmux configured"
|
|
315
|
+
fixes_applied=$((fixes_applied + 1))
|
|
316
|
+
elif [[ "$result" == "skipped" ]]; then
|
|
317
|
+
warn " tmux configuration skipped (overlay not found)"
|
|
318
|
+
fixes_skipped=$((fixes_skipped + 1))
|
|
319
|
+
fi
|
|
320
|
+
|
|
321
|
+
# Fix 5: Install hooks
|
|
322
|
+
info "Installing hooks..."
|
|
323
|
+
result=$(doctor_fix_hooks)
|
|
324
|
+
if [[ "$result" == "fixed" ]]; then
|
|
325
|
+
success " Hooks installed"
|
|
326
|
+
fixes_applied=$((fixes_applied + 1))
|
|
327
|
+
elif [[ "$result" == "skipped" ]]; then
|
|
328
|
+
warn " Hooks skipped (templates not found)"
|
|
329
|
+
fixes_skipped=$((fixes_skipped + 1))
|
|
330
|
+
fi
|
|
331
|
+
|
|
332
|
+
echo ""
|
|
333
|
+
echo -e " ${GREEN}${BOLD}${fixes_applied}${RESET} fixes applied ${YELLOW}${BOLD}${fixes_skipped}${RESET} skipped"
|
|
334
|
+
echo ""
|
|
335
|
+
|
|
336
|
+
if [[ "$DOCTOR_FIX_DRY_RUN" == "true" ]]; then
|
|
337
|
+
info "Dry-run complete — no changes made"
|
|
338
|
+
else
|
|
339
|
+
info "Re-running doctor checks to verify fixes..."
|
|
340
|
+
echo ""
|
|
341
|
+
fi
|
|
342
|
+
}
|
|
343
|
+
|
|
54
344
|
# ─── Header ─────────────────────────────────────────────────────────────────
|
|
55
345
|
echo ""
|
|
56
346
|
echo -e "${CYAN}${BOLD} Shipwright — Doctor${RESET}"
|
|
@@ -221,6 +511,7 @@ fi
|
|
|
221
511
|
|
|
222
512
|
# Bash version
|
|
223
513
|
BASH_MAJOR="${BASH_VERSINFO[0]:-0}"
|
|
514
|
+
# shellcheck disable=SC2034
|
|
224
515
|
BASH_MINOR="${BASH_VERSINFO[1]:-0}"
|
|
225
516
|
if [[ "$BASH_MAJOR" -ge 5 ]]; then
|
|
226
517
|
check_pass "bash ${BASH_VERSION}"
|
|
@@ -266,6 +557,33 @@ else
|
|
|
266
557
|
echo -e " ${DIM}Copy from settings.json.template${RESET}"
|
|
267
558
|
fi
|
|
268
559
|
|
|
560
|
+
# ─── File Permission Validation ───────────────────────────────────
|
|
561
|
+
# Check sensitive config files have restrictive permissions (600)
|
|
562
|
+
_perm_issues=0
|
|
563
|
+
for config_file in "$HOME/.claude/settings.json" "$HOME/.shipwright/daemon-config.json" "$(pwd)/.claude/daemon-config.json"; do
|
|
564
|
+
if [[ -f "$config_file" ]]; then
|
|
565
|
+
# Get file permissions
|
|
566
|
+
_perms=""
|
|
567
|
+
if command -v stat >/dev/null 2>&1; then
|
|
568
|
+
# GNU stat: stat -c %a, BSD stat: stat -f %OLp
|
|
569
|
+
if [[ "$(uname -s)" == "Darwin" ]]; then
|
|
570
|
+
_perms=$(stat -f %OLp "$config_file" 2>/dev/null | tail -c 4)
|
|
571
|
+
else
|
|
572
|
+
_perms=$(stat -c %a "$config_file" 2>/dev/null)
|
|
573
|
+
fi
|
|
574
|
+
fi
|
|
575
|
+
|
|
576
|
+
if [[ -n "${_perms:-}" && "$_perms" != "600" ]]; then
|
|
577
|
+
check_warn "File $config_file is world-readable (perms: $_perms, should be 600)"
|
|
578
|
+
_perm_issues=$((_perm_issues + 1))
|
|
579
|
+
fi
|
|
580
|
+
fi
|
|
581
|
+
done
|
|
582
|
+
|
|
583
|
+
if [[ $_perm_issues -eq 0 ]]; then
|
|
584
|
+
check_pass "File permissions: all sensitive configs restricted to owner-only"
|
|
585
|
+
fi
|
|
586
|
+
|
|
269
587
|
# Hooks directory
|
|
270
588
|
HOOKS_DIR="$HOME/.claude/hooks"
|
|
271
589
|
if [[ -d "$HOOKS_DIR" ]]; then
|
|
@@ -320,6 +638,39 @@ if [[ -d "$HOOKS_DIR" && -f "$HOME/.claude/settings.json" ]] && jq -e '.' "$HOME
|
|
|
320
638
|
fi
|
|
321
639
|
fi
|
|
322
640
|
|
|
641
|
+
# Hook security validation — check for untrusted repo-level hooks
|
|
642
|
+
# Warn if repo-level .claude/hooks/ contains unexpected commands
|
|
643
|
+
if [[ -d "$(pwd)/.claude/hooks" ]]; then
|
|
644
|
+
_repo_hook_dir="$(pwd)/.claude/hooks"
|
|
645
|
+
_trusted_hooks_dir="${HOME}/.claude/hooks"
|
|
646
|
+
_untrusted_hook_count=0
|
|
647
|
+
|
|
648
|
+
# Check if CLAUDE_CODE_VERIFY_HOOKS is enabled for extra caution
|
|
649
|
+
if [[ -n "${CLAUDE_CODE_VERIFY_HOOKS:-}" ]]; then
|
|
650
|
+
for repo_hook in "$_repo_hook_dir"/*.sh; do
|
|
651
|
+
[[ -f "$repo_hook" ]] || continue
|
|
652
|
+
_hook_name="$(basename "$repo_hook")"
|
|
653
|
+
_trusted_hook="$_trusted_hooks_dir/$_hook_name"
|
|
654
|
+
|
|
655
|
+
# If a trusted version exists, compare checksums
|
|
656
|
+
if [[ -f "$_trusted_hook" ]]; then
|
|
657
|
+
if ! cmp -s "$repo_hook" "$_trusted_hook"; then
|
|
658
|
+
check_warn "Repo hook differs from trusted version: .claude/hooks/$_hook_name"
|
|
659
|
+
_untrusted_hook_count=$((_untrusted_hook_count + 1))
|
|
660
|
+
fi
|
|
661
|
+
else
|
|
662
|
+
# No trusted version — this is an unknown hook
|
|
663
|
+
check_warn "Repo contains unknown hook: .claude/hooks/$_hook_name"
|
|
664
|
+
_untrusted_hook_count=$((_untrusted_hook_count + 1))
|
|
665
|
+
fi
|
|
666
|
+
done
|
|
667
|
+
|
|
668
|
+
if [[ $_untrusted_hook_count -gt 0 ]]; then
|
|
669
|
+
echo -e " ${DIM}Enable hook verification with: export CLAUDE_CODE_VERIFY_HOOKS=1${RESET}"
|
|
670
|
+
fi
|
|
671
|
+
fi
|
|
672
|
+
fi
|
|
673
|
+
|
|
323
674
|
# ═════════════════════════════════════════════════════════════════════════════
|
|
324
675
|
# 3. Agent Teams
|
|
325
676
|
# ═════════════════════════════════════════════════════════════════════════════
|
|
@@ -853,7 +1204,7 @@ if [[ -f "$MACHINES_FILE" ]]; then
|
|
|
853
1204
|
|
|
854
1205
|
if [[ -n "$m_host" ]]; then
|
|
855
1206
|
ssh_target="${m_user:+${m_user}@}${m_host}"
|
|
856
|
-
if ssh -o ConnectTimeout=5 -o BatchMode=yes -p "$m_port" "$ssh_target" true 2>/dev/null; then
|
|
1207
|
+
if ssh -n -o ConnectTimeout=5 -o BatchMode=yes -p "$m_port" "$ssh_target" true 2>/dev/null; then
|
|
857
1208
|
check_pass "SSH: ${m_name} (${ssh_target}) reachable"
|
|
858
1209
|
else
|
|
859
1210
|
check_warn "SSH: ${m_name} (${ssh_target}) unreachable"
|
|
@@ -1127,6 +1478,86 @@ else
|
|
|
1127
1478
|
echo -e " ${DIM}Install: brew install sqlite (macOS) or apt install sqlite3 (Linux)${RESET}"
|
|
1128
1479
|
fi
|
|
1129
1480
|
|
|
1481
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
1482
|
+
# 15a. Claude Code Feature Configuration
|
|
1483
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
1484
|
+
echo ""
|
|
1485
|
+
echo -e "${PURPLE}${BOLD} CLAUDE CODE FEATURES${RESET}"
|
|
1486
|
+
echo -e "${DIM} ──────────────────────────────────────────${RESET}"
|
|
1487
|
+
|
|
1488
|
+
_SETTINGS_FILE="$(pwd)/.claude/settings.json"
|
|
1489
|
+
if [[ ! -f "$_SETTINGS_FILE" ]]; then
|
|
1490
|
+
_SCRIPT_DIR_CLAUDE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
1491
|
+
_REPO_ROOT_CLAUDE="$(cd "$_SCRIPT_DIR_CLAUDE/.." 2>/dev/null && pwd)"
|
|
1492
|
+
[[ -f "$_REPO_ROOT_CLAUDE/.claude/settings.json" ]] && _SETTINGS_FILE="$_REPO_ROOT_CLAUDE/.claude/settings.json"
|
|
1493
|
+
fi
|
|
1494
|
+
|
|
1495
|
+
if [[ -f "$_SETTINGS_FILE" ]] && command -v jq >/dev/null 2>&1; then
|
|
1496
|
+
# Check effort level
|
|
1497
|
+
_effort_val=$(jq -r '.env.CLAUDE_CODE_EFFORT_LEVEL // empty' "$_SETTINGS_FILE" 2>/dev/null || echo "")
|
|
1498
|
+
if [[ -n "$_effort_val" ]]; then
|
|
1499
|
+
case "$_effort_val" in
|
|
1500
|
+
low|medium|high) check_pass "Effort level configured: ${_effort_val}" ;;
|
|
1501
|
+
*) check_fail "Invalid effort level in settings.json: ${_effort_val} (must be low/medium/high)" ;;
|
|
1502
|
+
esac
|
|
1503
|
+
else
|
|
1504
|
+
check_warn "CLAUDE_CODE_EFFORT_LEVEL not configured"
|
|
1505
|
+
fi
|
|
1506
|
+
|
|
1507
|
+
# Check ENABLE_TOOL_SEARCH
|
|
1508
|
+
_tool_search=$(jq -r '.env.ENABLE_TOOL_SEARCH // empty' "$_SETTINGS_FILE" 2>/dev/null || echo "")
|
|
1509
|
+
if [[ -n "$_tool_search" ]]; then
|
|
1510
|
+
check_pass "MCP Tool Search: ${_tool_search}"
|
|
1511
|
+
else
|
|
1512
|
+
check_warn "ENABLE_TOOL_SEARCH not set (recommend: auto)"
|
|
1513
|
+
fi
|
|
1514
|
+
|
|
1515
|
+
# Check MAX_MCP_OUTPUT_TOKENS
|
|
1516
|
+
_mcp_tokens=$(jq -r '.env.MAX_MCP_OUTPUT_TOKENS // empty' "$_SETTINGS_FILE" 2>/dev/null || echo "")
|
|
1517
|
+
if [[ -n "$_mcp_tokens" ]]; then
|
|
1518
|
+
check_pass "MCP output limit: ${_mcp_tokens} tokens"
|
|
1519
|
+
else
|
|
1520
|
+
check_warn "MAX_MCP_OUTPUT_TOKENS not set (recommend: 50000)"
|
|
1521
|
+
fi
|
|
1522
|
+
|
|
1523
|
+
# Check managed-mcp.json
|
|
1524
|
+
if [[ -f "$_SETTINGS_FILE" ]]; then
|
|
1525
|
+
_settings_dir=$(dirname "$_SETTINGS_FILE")
|
|
1526
|
+
if [[ -f "$_settings_dir/managed-mcp.json" ]]; then
|
|
1527
|
+
if jq empty "$_settings_dir/managed-mcp.json" 2>/dev/null; then
|
|
1528
|
+
check_pass "managed-mcp.json present and valid"
|
|
1529
|
+
else
|
|
1530
|
+
check_fail "managed-mcp.json has invalid JSON"
|
|
1531
|
+
fi
|
|
1532
|
+
fi
|
|
1533
|
+
fi
|
|
1534
|
+
|
|
1535
|
+
# Check schemas directory
|
|
1536
|
+
if [[ -d "$(pwd)/schemas" ]]; then
|
|
1537
|
+
_schema_count=$(find "$(pwd)/schemas" -name "*.json" 2>/dev/null | wc -l | tr -d ' ')
|
|
1538
|
+
check_pass "Schemas directory: ${_schema_count} schema(s) found"
|
|
1539
|
+
elif [[ -d "$(pwd)/../schemas" ]]; then
|
|
1540
|
+
_schema_count=$(find "$(pwd)/../schemas" -name "*.json" 2>/dev/null | wc -l | tr -d ' ')
|
|
1541
|
+
check_pass "Schemas directory: ${_schema_count} schema(s) found"
|
|
1542
|
+
fi
|
|
1543
|
+
|
|
1544
|
+
# Check lifecycle hooks registered
|
|
1545
|
+
_hook_count=0
|
|
1546
|
+
for _hook_name in WorktreeCreate WorktreeRemove InstructionsLoaded ConfigChange; do
|
|
1547
|
+
if jq -e ".hooks.${_hook_name}" "$_SETTINGS_FILE" >/dev/null 2>&1; then
|
|
1548
|
+
_hook_count=$((_hook_count + 1))
|
|
1549
|
+
fi
|
|
1550
|
+
done
|
|
1551
|
+
if [[ "$_hook_count" -eq 4 ]]; then
|
|
1552
|
+
check_pass "Lifecycle hooks: all 4 registered"
|
|
1553
|
+
elif [[ "$_hook_count" -gt 0 ]]; then
|
|
1554
|
+
check_warn "Lifecycle hooks: ${_hook_count}/4 registered"
|
|
1555
|
+
fi
|
|
1556
|
+
else
|
|
1557
|
+
check_warn "Claude Code configuration not found or jq unavailable"
|
|
1558
|
+
echo -e " ${DIM}Run: shipwright prep${RESET}"
|
|
1559
|
+
fi
|
|
1560
|
+
|
|
1130
1561
|
# ═════════════════════════════════════════════════════════════════════════════
|
|
1131
1562
|
# 15b. Intelligence Features
|
|
1132
1563
|
# ═════════════════════════════════════════════════════════════════════════════
|
|
@@ -1162,6 +1593,26 @@ else
|
|
|
1162
1593
|
check_warn "Platform hygiene not run — run: shipwright hygiene platform-refactor"
|
|
1163
1594
|
fi
|
|
1164
1595
|
|
|
1596
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
1597
|
+
# Auto-fix (if enabled)
|
|
1598
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
1599
|
+
if [[ "$DOCTOR_FIX_MODE" == "true" ]]; then
|
|
1600
|
+
doctor_auto_fix
|
|
1601
|
+
|
|
1602
|
+
# Re-run checks after fixes if not in dry-run mode
|
|
1603
|
+
if [[ "$DOCTOR_FIX_DRY_RUN" != "true" ]]; then
|
|
1604
|
+
info "Re-running doctor checks..."
|
|
1605
|
+
# Reset counters
|
|
1606
|
+
PASS=0
|
|
1607
|
+
WARN=0
|
|
1608
|
+
FAIL=0
|
|
1609
|
+
# Re-execute the doctor script to get fresh results
|
|
1610
|
+
# We'll just continue with a message for now
|
|
1611
|
+
echo ""
|
|
1612
|
+
echo -e "${DIM} (Running full doctor check with fixes applied)${RESET}"
|
|
1613
|
+
fi
|
|
1614
|
+
fi
|
|
1615
|
+
|
|
1165
1616
|
# ═════════════════════════════════════════════════════════════════════════════
|
|
1166
1617
|
# Summary
|
|
1167
1618
|
# ═════════════════════════════════════════════════════════════════════════════
|
package/scripts/sw-dora.sh
CHANGED
|
@@ -8,11 +8,13 @@
|
|
|
8
8
|
set -euo pipefail
|
|
9
9
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
# shellcheck disable=SC2034
|
|
12
|
+
VERSION="3.3.0"
|
|
12
13
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
14
|
|
|
14
15
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
|
15
16
|
_COMPAT="$SCRIPT_DIR/lib/compat.sh"
|
|
17
|
+
# shellcheck disable=SC1090
|
|
16
18
|
[[ -f "$_COMPAT" ]] && source "$_COMPAT"
|
|
17
19
|
|
|
18
20
|
# Canonical helpers (colors, output, events)
|
|
@@ -32,6 +34,7 @@ fi
|
|
|
32
34
|
if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
33
35
|
emit_event() {
|
|
34
36
|
local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
|
|
37
|
+
# shellcheck disable=SC2155
|
|
35
38
|
local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
|
|
36
39
|
while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
|
|
37
40
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
package/scripts/sw-durable.sh
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
9
9
|
|
|
10
|
-
VERSION="3.
|
|
10
|
+
VERSION="3.3.0"
|
|
11
11
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
12
|
|
|
13
13
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
|
@@ -31,6 +31,7 @@ fi
|
|
|
31
31
|
if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
32
32
|
emit_event() {
|
|
33
33
|
local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
|
|
34
|
+
# shellcheck disable=SC2155
|
|
34
35
|
local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
|
|
35
36
|
while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
|
|
36
37
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
@@ -50,8 +51,8 @@ ensure_durable_dir() {
|
|
|
50
51
|
# ─── Event ID Generation ────────────────────────────────────────────────────
|
|
51
52
|
generate_event_id() {
|
|
52
53
|
local prefix="${1:-evt}"
|
|
53
|
-
local ts=$(now_epoch)
|
|
54
|
-
local rand=$(od -An -N4 -tu4 /dev/urandom | tr -d ' ')
|
|
54
|
+
local ts; ts=$(now_epoch)
|
|
55
|
+
local rand; rand=$(od -An -N4 -tu4 /dev/urandom | tr -d ' ')
|
|
55
56
|
echo "${prefix}-${ts}-${rand}"
|
|
56
57
|
}
|
|
57
58
|
|