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
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
# pipeline-stages-monitor.sh — validate, monitor stages
|
|
2
|
+
# Source from pipeline-stages.sh. Requires all pipeline globals and dependencies.
|
|
3
|
+
[[ -n "${_PIPELINE_STAGES_MONITOR_LOADED:-}" ]] && return 0
|
|
4
|
+
_PIPELINE_STAGES_MONITOR_LOADED=1
|
|
5
|
+
|
|
6
|
+
stage_validate() {
|
|
7
|
+
CURRENT_STAGE_ID="validate"
|
|
8
|
+
# Consume retry context if this is a retry attempt
|
|
9
|
+
local _retry_ctx="${ARTIFACTS_DIR}/.retry-context-validate.md"
|
|
10
|
+
if [[ -s "$_retry_ctx" ]]; then
|
|
11
|
+
local _validate_retry_hints
|
|
12
|
+
_validate_retry_hints=$(cat "$_retry_ctx" 2>/dev/null || true)
|
|
13
|
+
rm -f "$_retry_ctx"
|
|
14
|
+
fi
|
|
15
|
+
# Load validation thoroughness skills
|
|
16
|
+
if type skill_load_prompts >/dev/null 2>&1; then
|
|
17
|
+
local _validate_skills
|
|
18
|
+
_validate_skills=$(skill_load_prompts "${INTELLIGENCE_ISSUE_TYPE:-backend}" "validate" 2>/dev/null || true)
|
|
19
|
+
if [[ -n "$_validate_skills" ]]; then
|
|
20
|
+
echo "$_validate_skills" > "${ARTIFACTS_DIR}/.validation-skills.md" 2>/dev/null || true
|
|
21
|
+
fi
|
|
22
|
+
fi
|
|
23
|
+
local smoke_cmd
|
|
24
|
+
smoke_cmd=$(jq -r --arg id "validate" '(.stages[] | select(.id == $id) | .config.smoke_cmd) // ""' "$PIPELINE_CONFIG" 2>/dev/null) || true
|
|
25
|
+
[[ "$smoke_cmd" == "null" ]] && smoke_cmd=""
|
|
26
|
+
|
|
27
|
+
local health_url
|
|
28
|
+
health_url=$(jq -r --arg id "validate" '(.stages[] | select(.id == $id) | .config.health_url) // ""' "$PIPELINE_CONFIG" 2>/dev/null) || true
|
|
29
|
+
[[ "$health_url" == "null" ]] && health_url=""
|
|
30
|
+
|
|
31
|
+
local close_issue
|
|
32
|
+
close_issue=$(jq -r --arg id "validate" '(.stages[] | select(.id == $id) | .config.close_issue) // false' "$PIPELINE_CONFIG" 2>/dev/null) || true
|
|
33
|
+
|
|
34
|
+
# Smoke tests
|
|
35
|
+
if [[ -n "$smoke_cmd" ]]; then
|
|
36
|
+
info "Running smoke tests..."
|
|
37
|
+
bash -c "$smoke_cmd" > "$ARTIFACTS_DIR/smoke.log" 2>&1 || {
|
|
38
|
+
error "Smoke tests failed"
|
|
39
|
+
if [[ -n "$ISSUE_NUMBER" ]]; then
|
|
40
|
+
gh issue create --title "Deploy validation failed: $GOAL" \
|
|
41
|
+
--label "incident" --body "Pipeline smoke tests failed after deploy.
|
|
42
|
+
|
|
43
|
+
Related issue: ${GITHUB_ISSUE}
|
|
44
|
+
Branch: ${GIT_BRANCH}
|
|
45
|
+
PR: $(cat "$ARTIFACTS_DIR/pr-url.txt" 2>/dev/null || echo 'unknown')" 2>/dev/null || true
|
|
46
|
+
fi
|
|
47
|
+
return 1
|
|
48
|
+
}
|
|
49
|
+
success "Smoke tests passed"
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Health check with retry
|
|
53
|
+
if [[ -n "$health_url" ]]; then
|
|
54
|
+
info "Health check: $health_url"
|
|
55
|
+
local attempts=0
|
|
56
|
+
while [[ $attempts -lt 5 ]]; do
|
|
57
|
+
if curl -sf "$health_url" >/dev/null 2>&1; then
|
|
58
|
+
success "Health check passed"
|
|
59
|
+
break
|
|
60
|
+
fi
|
|
61
|
+
attempts=$((attempts + 1))
|
|
62
|
+
[[ $attempts -lt 5 ]] && { info "Retry ${attempts}/5..."; sleep "$(_exponential_backoff "$attempts" 5 60)"; }
|
|
63
|
+
done
|
|
64
|
+
if [[ $attempts -ge 5 ]]; then
|
|
65
|
+
error "Health check failed after 5 attempts"
|
|
66
|
+
return 1
|
|
67
|
+
fi
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# Compute total duration once for both issue close and wiki report
|
|
71
|
+
local total_dur=""
|
|
72
|
+
if [[ -n "$PIPELINE_START_EPOCH" ]]; then
|
|
73
|
+
total_dur=$(format_duration $(( $(now_epoch) - PIPELINE_START_EPOCH )))
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
# Close original issue with comprehensive summary
|
|
77
|
+
if [[ "$close_issue" == "true" && -n "$ISSUE_NUMBER" ]]; then
|
|
78
|
+
gh issue close "$ISSUE_NUMBER" --comment "## ✅ Complete — Deployed & Validated
|
|
79
|
+
|
|
80
|
+
| Metric | Value |
|
|
81
|
+
|--------|-------|
|
|
82
|
+
| Pipeline | \`${PIPELINE_NAME}\` |
|
|
83
|
+
| Branch | \`${GIT_BRANCH}\` |
|
|
84
|
+
| PR | $(cat "$ARTIFACTS_DIR/pr-url.txt" 2>/dev/null || echo 'N/A') |
|
|
85
|
+
| Duration | ${total_dur:-unknown} |
|
|
86
|
+
|
|
87
|
+
_Closed automatically by \`shipwright pipeline\`_" 2>/dev/null || true
|
|
88
|
+
|
|
89
|
+
gh_remove_label "$ISSUE_NUMBER" "pipeline/pr-created"
|
|
90
|
+
gh_add_labels "$ISSUE_NUMBER" "pipeline/complete"
|
|
91
|
+
success "Issue #$ISSUE_NUMBER closed"
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# Push pipeline report to wiki
|
|
95
|
+
local report="# Pipeline Report — ${GOAL}
|
|
96
|
+
|
|
97
|
+
| Metric | Value |
|
|
98
|
+
|--------|-------|
|
|
99
|
+
| Pipeline | \`${PIPELINE_NAME}\` |
|
|
100
|
+
| Branch | \`${GIT_BRANCH}\` |
|
|
101
|
+
| PR | $(cat "$ARTIFACTS_DIR/pr-url.txt" 2>/dev/null || echo 'N/A') |
|
|
102
|
+
| Duration | ${total_dur:-unknown} |
|
|
103
|
+
| Stages | $(echo "$STAGE_TIMINGS" | tr '|' '\n' | wc -l | xargs) completed |
|
|
104
|
+
|
|
105
|
+
## Stage Timings
|
|
106
|
+
$(echo "$STAGE_TIMINGS" | tr '|' '\n' | sed 's/^/- /')
|
|
107
|
+
|
|
108
|
+
## Artifacts
|
|
109
|
+
$(ls -1 "$ARTIFACTS_DIR" 2>/dev/null | sed 's/^/- /')
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
_Generated by \`shipwright pipeline\` at $(now_iso)_"
|
|
113
|
+
gh_wiki_page "Pipeline-Report-${ISSUE_NUMBER:-inline}" "$report"
|
|
114
|
+
|
|
115
|
+
log_stage "validate" "Validation complete"
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
stage_monitor() {
|
|
119
|
+
CURRENT_STAGE_ID="monitor"
|
|
120
|
+
# Consume retry context if this is a retry attempt
|
|
121
|
+
local _retry_ctx="${ARTIFACTS_DIR}/.retry-context-monitor.md"
|
|
122
|
+
if [[ -s "$_retry_ctx" ]]; then
|
|
123
|
+
local _monitor_retry_hints
|
|
124
|
+
_monitor_retry_hints=$(cat "$_retry_ctx" 2>/dev/null || true)
|
|
125
|
+
rm -f "$_retry_ctx"
|
|
126
|
+
fi
|
|
127
|
+
# Load observability skills
|
|
128
|
+
if type skill_load_prompts >/dev/null 2>&1; then
|
|
129
|
+
local _monitor_skills
|
|
130
|
+
_monitor_skills=$(skill_load_prompts "${INTELLIGENCE_ISSUE_TYPE:-backend}" "monitor" 2>/dev/null || true)
|
|
131
|
+
if [[ -n "$_monitor_skills" ]]; then
|
|
132
|
+
echo "$_monitor_skills" > "${ARTIFACTS_DIR}/.monitoring-skills.md" 2>/dev/null || true
|
|
133
|
+
fi
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
# Read config from pipeline template
|
|
137
|
+
local duration_minutes health_url error_threshold log_pattern log_cmd rollback_cmd auto_rollback
|
|
138
|
+
duration_minutes=$(jq -r --arg id "monitor" '(.stages[] | select(.id == $id) | .config.duration_minutes) // 5' "$PIPELINE_CONFIG" 2>/dev/null) || true
|
|
139
|
+
[[ -z "$duration_minutes" || "$duration_minutes" == "null" ]] && duration_minutes=5
|
|
140
|
+
health_url=$(jq -r --arg id "monitor" '(.stages[] | select(.id == $id) | .config.health_url) // ""' "$PIPELINE_CONFIG" 2>/dev/null) || true
|
|
141
|
+
[[ "$health_url" == "null" ]] && health_url=""
|
|
142
|
+
error_threshold=$(jq -r --arg id "monitor" '(.stages[] | select(.id == $id) | .config.error_threshold) // 5' "$PIPELINE_CONFIG" 2>/dev/null) || true
|
|
143
|
+
[[ -z "$error_threshold" || "$error_threshold" == "null" ]] && error_threshold=5
|
|
144
|
+
|
|
145
|
+
# Adaptive monitor: use historical baselines if available
|
|
146
|
+
local repo_hash
|
|
147
|
+
repo_hash=$(echo "${PROJECT_ROOT:-$(pwd)}" | cksum | awk '{print $1}')
|
|
148
|
+
local baseline_file="${HOME}/.shipwright/baselines/${repo_hash}/deploy-monitor.json"
|
|
149
|
+
if [[ -f "$baseline_file" ]]; then
|
|
150
|
+
local hist_duration hist_threshold
|
|
151
|
+
hist_duration=$(jq -r '.p90_stabilization_minutes // empty' "$baseline_file" 2>/dev/null || true)
|
|
152
|
+
hist_threshold=$(jq -r '.p90_error_threshold // empty' "$baseline_file" 2>/dev/null || true)
|
|
153
|
+
if [[ -n "$hist_duration" && "$hist_duration" != "null" ]]; then
|
|
154
|
+
duration_minutes="$hist_duration"
|
|
155
|
+
info "Monitor duration: ${duration_minutes}m ${DIM}(from baseline)${RESET}"
|
|
156
|
+
fi
|
|
157
|
+
if [[ -n "$hist_threshold" && "$hist_threshold" != "null" ]]; then
|
|
158
|
+
error_threshold="$hist_threshold"
|
|
159
|
+
info "Error threshold: ${error_threshold} ${DIM}(from baseline)${RESET}"
|
|
160
|
+
fi
|
|
161
|
+
fi
|
|
162
|
+
log_pattern=$(jq -r --arg id "monitor" '(.stages[] | select(.id == $id) | .config.log_pattern) // "ERROR|FATAL|PANIC"' "$PIPELINE_CONFIG" 2>/dev/null) || true
|
|
163
|
+
[[ -z "$log_pattern" || "$log_pattern" == "null" ]] && log_pattern="ERROR|FATAL|PANIC"
|
|
164
|
+
log_cmd=$(jq -r --arg id "monitor" '(.stages[] | select(.id == $id) | .config.log_cmd) // ""' "$PIPELINE_CONFIG" 2>/dev/null) || true
|
|
165
|
+
[[ "$log_cmd" == "null" ]] && log_cmd=""
|
|
166
|
+
rollback_cmd=$(jq -r --arg id "monitor" '(.stages[] | select(.id == $id) | .config.rollback_cmd) // ""' "$PIPELINE_CONFIG" 2>/dev/null) || true
|
|
167
|
+
[[ "$rollback_cmd" == "null" ]] && rollback_cmd=""
|
|
168
|
+
auto_rollback=$(jq -r --arg id "monitor" '(.stages[] | select(.id == $id) | .config.auto_rollback) // false' "$PIPELINE_CONFIG" 2>/dev/null) || true
|
|
169
|
+
[[ -z "$auto_rollback" || "$auto_rollback" == "null" ]] && auto_rollback="false"
|
|
170
|
+
|
|
171
|
+
if [[ -z "$health_url" && -z "$log_cmd" ]]; then
|
|
172
|
+
warn "No health_url or log_cmd configured — skipping monitor stage"
|
|
173
|
+
log_stage "monitor" "Skipped (no monitoring configured)"
|
|
174
|
+
return 0
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
local report_file="$ARTIFACTS_DIR/monitor-report.md"
|
|
178
|
+
local deploy_log_file="$ARTIFACTS_DIR/deploy-logs.txt"
|
|
179
|
+
: > "$deploy_log_file"
|
|
180
|
+
local total_errors=0
|
|
181
|
+
local poll_interval=30 # seconds between polls
|
|
182
|
+
local total_polls=$(( (duration_minutes * 60) / poll_interval ))
|
|
183
|
+
[[ "$total_polls" -lt 1 ]] && total_polls=1
|
|
184
|
+
|
|
185
|
+
info "Post-deploy monitoring: ${duration_minutes}m (${total_polls} polls, threshold: ${error_threshold} errors)"
|
|
186
|
+
|
|
187
|
+
emit_event "monitor.started" \
|
|
188
|
+
"issue=${ISSUE_NUMBER:-0}" \
|
|
189
|
+
"duration_minutes=$duration_minutes" \
|
|
190
|
+
"error_threshold=$error_threshold"
|
|
191
|
+
|
|
192
|
+
{
|
|
193
|
+
echo "# Post-Deploy Monitor Report"
|
|
194
|
+
echo ""
|
|
195
|
+
echo "- Duration: ${duration_minutes} minutes"
|
|
196
|
+
echo "- Health URL: ${health_url:-none}"
|
|
197
|
+
echo "- Log command: ${log_cmd:-none}"
|
|
198
|
+
echo "- Error threshold: ${error_threshold}"
|
|
199
|
+
echo "- Auto-rollback: ${auto_rollback}"
|
|
200
|
+
echo ""
|
|
201
|
+
echo "## Poll Results"
|
|
202
|
+
echo ""
|
|
203
|
+
} > "$report_file"
|
|
204
|
+
|
|
205
|
+
local poll=0
|
|
206
|
+
local health_failures=0
|
|
207
|
+
local log_errors=0
|
|
208
|
+
while [[ "$poll" -lt "$total_polls" ]]; do
|
|
209
|
+
poll=$((poll + 1))
|
|
210
|
+
local poll_time
|
|
211
|
+
poll_time=$(now_iso)
|
|
212
|
+
|
|
213
|
+
# Health URL check
|
|
214
|
+
if [[ -n "$health_url" ]]; then
|
|
215
|
+
local http_status
|
|
216
|
+
http_status=$(curl -sf -o /dev/null -w "%{http_code}" "$health_url" 2>/dev/null || echo "000")
|
|
217
|
+
if [[ "$http_status" -ge 200 && "$http_status" -lt 400 ]]; then
|
|
218
|
+
echo "- [${poll_time}] Health: ✅ (HTTP ${http_status})" >> "$report_file"
|
|
219
|
+
else
|
|
220
|
+
health_failures=$((health_failures + 1))
|
|
221
|
+
total_errors=$((total_errors + 1))
|
|
222
|
+
echo "- [${poll_time}] Health: ❌ (HTTP ${http_status})" >> "$report_file"
|
|
223
|
+
warn "Health check failed: HTTP ${http_status}"
|
|
224
|
+
fi
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
# Log command check (accumulate deploy logs for feedback collect)
|
|
228
|
+
if [[ -n "$log_cmd" ]]; then
|
|
229
|
+
local log_output
|
|
230
|
+
log_output=$(bash -c "$log_cmd" 2>/dev/null || true)
|
|
231
|
+
[[ -n "$log_output" ]] && echo "$log_output" >> "$deploy_log_file"
|
|
232
|
+
local error_count=0
|
|
233
|
+
if [[ -n "$log_output" ]]; then
|
|
234
|
+
error_count=$(echo "$log_output" | grep -cE "$log_pattern" 2>/dev/null || true)
|
|
235
|
+
error_count="${error_count:-0}"
|
|
236
|
+
fi
|
|
237
|
+
if [[ "$error_count" -gt 0 ]]; then
|
|
238
|
+
log_errors=$((log_errors + error_count))
|
|
239
|
+
total_errors=$((total_errors + error_count))
|
|
240
|
+
echo "- [${poll_time}] Logs: ⚠️ ${error_count} error(s) matching '${log_pattern}'" >> "$report_file"
|
|
241
|
+
warn "Log errors detected: ${error_count}"
|
|
242
|
+
else
|
|
243
|
+
echo "- [${poll_time}] Logs: ✅ clean" >> "$report_file"
|
|
244
|
+
fi
|
|
245
|
+
fi
|
|
246
|
+
|
|
247
|
+
emit_event "monitor.check" \
|
|
248
|
+
"issue=${ISSUE_NUMBER:-0}" \
|
|
249
|
+
"poll=$poll" \
|
|
250
|
+
"total_errors=$total_errors" \
|
|
251
|
+
"health_failures=$health_failures"
|
|
252
|
+
|
|
253
|
+
# Check threshold
|
|
254
|
+
if [[ "$total_errors" -ge "$error_threshold" ]]; then
|
|
255
|
+
error "Error threshold exceeded: ${total_errors} >= ${error_threshold}"
|
|
256
|
+
|
|
257
|
+
echo "" >> "$report_file"
|
|
258
|
+
echo "## ❌ THRESHOLD EXCEEDED" >> "$report_file"
|
|
259
|
+
echo "Total errors: ${total_errors} (threshold: ${error_threshold})" >> "$report_file"
|
|
260
|
+
|
|
261
|
+
emit_event "monitor.alert" \
|
|
262
|
+
"issue=${ISSUE_NUMBER:-0}" \
|
|
263
|
+
"total_errors=$total_errors" \
|
|
264
|
+
"threshold=$error_threshold"
|
|
265
|
+
|
|
266
|
+
# Feedback loop: collect deploy logs and optionally create issue
|
|
267
|
+
if [[ -f "$deploy_log_file" ]] && [[ -s "$deploy_log_file" ]] && [[ -x "$SCRIPT_DIR/sw-feedback.sh" ]]; then
|
|
268
|
+
(cd "$PROJECT_ROOT" && ARTIFACTS_DIR="$ARTIFACTS_DIR" bash "$SCRIPT_DIR/sw-feedback.sh" collect "$deploy_log_file" 2>/dev/null) || true
|
|
269
|
+
(cd "$PROJECT_ROOT" && ARTIFACTS_DIR="$ARTIFACTS_DIR" bash "$SCRIPT_DIR/sw-feedback.sh" create-issue 2>/dev/null) || true
|
|
270
|
+
fi
|
|
271
|
+
|
|
272
|
+
# Auto-rollback: feedback rollback (GitHub Deployments API) and/or config rollback_cmd
|
|
273
|
+
if [[ "$auto_rollback" == "true" ]]; then
|
|
274
|
+
warn "Auto-rolling back..."
|
|
275
|
+
echo "" >> "$report_file"
|
|
276
|
+
echo "## Rollback" >> "$report_file"
|
|
277
|
+
|
|
278
|
+
# Trigger feedback rollback (calls sw-github-deploy.sh rollback)
|
|
279
|
+
if [[ -x "$SCRIPT_DIR/sw-feedback.sh" ]]; then
|
|
280
|
+
(cd "$PROJECT_ROOT" && ARTIFACTS_DIR="$ARTIFACTS_DIR" bash "$SCRIPT_DIR/sw-feedback.sh" rollback production "Monitor threshold exceeded (${total_errors} errors)" >> "$report_file" 2>&1) || true
|
|
281
|
+
fi
|
|
282
|
+
|
|
283
|
+
if [[ -n "$rollback_cmd" ]] && bash -c "$rollback_cmd" >> "$report_file" 2>&1; then
|
|
284
|
+
success "Rollback executed"
|
|
285
|
+
echo "Rollback: ✅ success" >> "$report_file"
|
|
286
|
+
|
|
287
|
+
# Post-rollback smoke test verification
|
|
288
|
+
local smoke_cmd
|
|
289
|
+
smoke_cmd=$(jq -r --arg id "validate" '(.stages[] | select(.id == $id) | .config.smoke_cmd) // ""' "$PIPELINE_CONFIG" 2>/dev/null) || true
|
|
290
|
+
[[ "$smoke_cmd" == "null" ]] && smoke_cmd=""
|
|
291
|
+
|
|
292
|
+
if [[ -n "$smoke_cmd" ]]; then
|
|
293
|
+
info "Verifying rollback with smoke tests..."
|
|
294
|
+
if bash -c "$smoke_cmd" > "$ARTIFACTS_DIR/rollback-smoke.log" 2>&1; then
|
|
295
|
+
success "Rollback verified — smoke tests pass"
|
|
296
|
+
echo "Rollback verification: ✅ smoke tests pass" >> "$report_file"
|
|
297
|
+
emit_event "monitor.rollback_verified" \
|
|
298
|
+
"issue=${ISSUE_NUMBER:-0}" \
|
|
299
|
+
"status=pass"
|
|
300
|
+
else
|
|
301
|
+
error "Rollback verification FAILED — smoke tests still failing"
|
|
302
|
+
echo "Rollback verification: ❌ smoke tests FAILED — manual intervention required" >> "$report_file"
|
|
303
|
+
emit_event "monitor.rollback_verified" \
|
|
304
|
+
"issue=${ISSUE_NUMBER:-0}" \
|
|
305
|
+
"status=fail"
|
|
306
|
+
if [[ -n "$ISSUE_NUMBER" ]]; then
|
|
307
|
+
gh_comment_issue "$ISSUE_NUMBER" "🚨 **Rollback executed but verification failed** — smoke tests still failing after rollback. Manual intervention required.
|
|
308
|
+
|
|
309
|
+
Smoke command: \`${smoke_cmd}\`
|
|
310
|
+
Log: see \`pipeline-artifacts/rollback-smoke.log\`" 2>/dev/null || true
|
|
311
|
+
fi
|
|
312
|
+
fi
|
|
313
|
+
fi
|
|
314
|
+
else
|
|
315
|
+
error "Rollback failed!"
|
|
316
|
+
echo "Rollback: ❌ failed" >> "$report_file"
|
|
317
|
+
fi
|
|
318
|
+
|
|
319
|
+
emit_event "monitor.rollback" \
|
|
320
|
+
"issue=${ISSUE_NUMBER:-0}" \
|
|
321
|
+
"total_errors=$total_errors"
|
|
322
|
+
|
|
323
|
+
# Post to GitHub
|
|
324
|
+
if [[ -n "$ISSUE_NUMBER" ]]; then
|
|
325
|
+
gh_comment_issue "$ISSUE_NUMBER" "🚨 **Auto-rollback triggered** — ${total_errors} errors exceeded threshold (${error_threshold})
|
|
326
|
+
|
|
327
|
+
Rollback command: \`${rollback_cmd}\`" 2>/dev/null || true
|
|
328
|
+
|
|
329
|
+
# Create hotfix issue
|
|
330
|
+
if [[ "$GH_AVAILABLE" == "true" ]]; then
|
|
331
|
+
gh issue create \
|
|
332
|
+
--title "Hotfix: Deploy regression for ${GOAL}" \
|
|
333
|
+
--label "hotfix,incident" \
|
|
334
|
+
--body "Auto-rollback triggered during post-deploy monitoring.
|
|
335
|
+
|
|
336
|
+
**Original issue:** ${GITHUB_ISSUE:-N/A}
|
|
337
|
+
**Errors detected:** ${total_errors}
|
|
338
|
+
**Threshold:** ${error_threshold}
|
|
339
|
+
**Branch:** ${GIT_BRANCH}
|
|
340
|
+
|
|
341
|
+
## Monitor Report
|
|
342
|
+
$(cat "$report_file")
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
_Created automatically by \`shipwright pipeline\` monitor stage_" 2>/dev/null || true
|
|
346
|
+
fi
|
|
347
|
+
fi
|
|
348
|
+
fi
|
|
349
|
+
|
|
350
|
+
log_stage "monitor" "Failed — ${total_errors} errors (threshold: ${error_threshold})"
|
|
351
|
+
return 1
|
|
352
|
+
fi
|
|
353
|
+
|
|
354
|
+
# Sleep between polls (skip on last poll)
|
|
355
|
+
if [[ "$poll" -lt "$total_polls" ]]; then
|
|
356
|
+
sleep "$poll_interval"
|
|
357
|
+
fi
|
|
358
|
+
done
|
|
359
|
+
|
|
360
|
+
# Monitoring complete — all clear
|
|
361
|
+
echo "" >> "$report_file"
|
|
362
|
+
echo "## ✅ Monitoring Complete" >> "$report_file"
|
|
363
|
+
echo "Total errors: ${total_errors} (threshold: ${error_threshold})" >> "$report_file"
|
|
364
|
+
echo "Health failures: ${health_failures}" >> "$report_file"
|
|
365
|
+
echo "Log errors: ${log_errors}" >> "$report_file"
|
|
366
|
+
|
|
367
|
+
success "Post-deploy monitoring clean (${total_errors} errors in ${duration_minutes}m)"
|
|
368
|
+
|
|
369
|
+
# Proactive feedback collection: always collect deploy logs for trend analysis
|
|
370
|
+
if [[ -f "$deploy_log_file" ]] && [[ -s "$deploy_log_file" ]] && [[ -x "$SCRIPT_DIR/sw-feedback.sh" ]]; then
|
|
371
|
+
(cd "$PROJECT_ROOT" && ARTIFACTS_DIR="$ARTIFACTS_DIR" bash "$SCRIPT_DIR/sw-feedback.sh" collect "$deploy_log_file" 2>/dev/null) || true
|
|
372
|
+
fi
|
|
373
|
+
|
|
374
|
+
if [[ -n "$ISSUE_NUMBER" ]]; then
|
|
375
|
+
gh_comment_issue "$ISSUE_NUMBER" "✅ **Post-deploy monitoring passed** — ${duration_minutes}m, ${total_errors} errors" 2>/dev/null || true
|
|
376
|
+
fi
|
|
377
|
+
|
|
378
|
+
log_stage "monitor" "Clean — ${total_errors} errors in ${duration_minutes}m"
|
|
379
|
+
|
|
380
|
+
# Record baseline for adaptive monitoring on future runs
|
|
381
|
+
local baseline_dir="${HOME}/.shipwright/baselines/${repo_hash}"
|
|
382
|
+
mkdir -p "$baseline_dir" 2>/dev/null || true
|
|
383
|
+
local baseline_tmp
|
|
384
|
+
baseline_tmp="$(mktemp)"
|
|
385
|
+
if [[ -f "${baseline_dir}/deploy-monitor.json" ]]; then
|
|
386
|
+
# Append to history and recalculate p90
|
|
387
|
+
jq --arg dur "$duration_minutes" --arg errs "$total_errors" \
|
|
388
|
+
'.history += [{"duration_minutes": ($dur | tonumber), "errors": ($errs | tonumber)}] |
|
|
389
|
+
.p90_stabilization_minutes = ([.history[].duration_minutes] | sort | .[length * 9 / 10 | floor]) |
|
|
390
|
+
.p90_error_threshold = (([.history[].errors] | sort | .[length * 9 / 10 | floor]) + 2) |
|
|
391
|
+
.updated_at = now' \
|
|
392
|
+
"${baseline_dir}/deploy-monitor.json" > "$baseline_tmp" 2>/dev/null && \
|
|
393
|
+
mv "$baseline_tmp" "${baseline_dir}/deploy-monitor.json" || rm -f "$baseline_tmp"
|
|
394
|
+
else
|
|
395
|
+
jq -n --arg dur "$duration_minutes" --arg errs "$total_errors" \
|
|
396
|
+
'{history: [{"duration_minutes": ($dur | tonumber), "errors": ($errs | tonumber)}],
|
|
397
|
+
p90_stabilization_minutes: ($dur | tonumber),
|
|
398
|
+
p90_error_threshold: (($errs | tonumber) + 2),
|
|
399
|
+
updated_at: now}' \
|
|
400
|
+
> "$baseline_tmp" 2>/dev/null && \
|
|
401
|
+
mv "$baseline_tmp" "${baseline_dir}/deploy-monitor.json" || rm -f "$baseline_tmp"
|
|
402
|
+
fi
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
# ─── Multi-Dimensional Quality Checks ─────────────────────────────────────
|
|
406
|
+
# Beyond tests: security, bundle size, perf regression, API compat, coverage
|
|
407
|
+
|