shipwright-cli 1.10.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +114 -36
- package/completions/_shipwright +212 -32
- package/completions/shipwright.bash +97 -25
- package/docs/strategy/01-market-research.md +619 -0
- package/docs/strategy/02-mission-and-brand.md +587 -0
- package/docs/strategy/03-gtm-and-roadmap.md +759 -0
- package/docs/strategy/QUICK-START.txt +289 -0
- package/docs/strategy/README.md +172 -0
- package/package.json +4 -2
- package/scripts/sw +208 -1
- package/scripts/sw-activity.sh +500 -0
- package/scripts/sw-adaptive.sh +925 -0
- package/scripts/sw-adversarial.sh +1 -1
- package/scripts/sw-architecture-enforcer.sh +1 -1
- package/scripts/sw-auth.sh +613 -0
- package/scripts/sw-autonomous.sh +664 -0
- package/scripts/sw-changelog.sh +704 -0
- package/scripts/sw-checkpoint.sh +1 -1
- package/scripts/sw-ci.sh +602 -0
- package/scripts/sw-cleanup.sh +1 -1
- package/scripts/sw-code-review.sh +637 -0
- package/scripts/sw-connect.sh +1 -1
- package/scripts/sw-context.sh +605 -0
- package/scripts/sw-cost.sh +1 -1
- package/scripts/sw-daemon.sh +432 -130
- package/scripts/sw-dashboard.sh +1 -1
- package/scripts/sw-db.sh +540 -0
- package/scripts/sw-decompose.sh +539 -0
- package/scripts/sw-deps.sh +551 -0
- package/scripts/sw-developer-simulation.sh +1 -1
- package/scripts/sw-discovery.sh +412 -0
- package/scripts/sw-docs-agent.sh +539 -0
- package/scripts/sw-docs.sh +1 -1
- package/scripts/sw-doctor.sh +59 -1
- package/scripts/sw-dora.sh +615 -0
- package/scripts/sw-durable.sh +710 -0
- package/scripts/sw-e2e-orchestrator.sh +535 -0
- package/scripts/sw-eventbus.sh +393 -0
- package/scripts/sw-feedback.sh +471 -0
- package/scripts/sw-fix.sh +1 -1
- package/scripts/sw-fleet-discover.sh +567 -0
- package/scripts/sw-fleet-viz.sh +404 -0
- package/scripts/sw-fleet.sh +8 -1
- package/scripts/sw-github-app.sh +596 -0
- package/scripts/sw-github-checks.sh +1 -1
- package/scripts/sw-github-deploy.sh +1 -1
- package/scripts/sw-github-graphql.sh +1 -1
- package/scripts/sw-guild.sh +569 -0
- package/scripts/sw-heartbeat.sh +1 -1
- package/scripts/sw-hygiene.sh +559 -0
- package/scripts/sw-incident.sh +617 -0
- package/scripts/sw-init.sh +88 -1
- package/scripts/sw-instrument.sh +699 -0
- package/scripts/sw-intelligence.sh +1 -1
- package/scripts/sw-jira.sh +1 -1
- package/scripts/sw-launchd.sh +363 -28
- package/scripts/sw-linear.sh +1 -1
- package/scripts/sw-logs.sh +1 -1
- package/scripts/sw-loop.sh +64 -3
- package/scripts/sw-memory.sh +1 -1
- package/scripts/sw-mission-control.sh +487 -0
- package/scripts/sw-model-router.sh +545 -0
- package/scripts/sw-otel.sh +596 -0
- package/scripts/sw-oversight.sh +689 -0
- package/scripts/sw-pipeline-composer.sh +1 -1
- package/scripts/sw-pipeline-vitals.sh +1 -1
- package/scripts/sw-pipeline.sh +687 -24
- package/scripts/sw-pm.sh +693 -0
- package/scripts/sw-pr-lifecycle.sh +522 -0
- package/scripts/sw-predictive.sh +1 -1
- package/scripts/sw-prep.sh +1 -1
- package/scripts/sw-ps.sh +1 -1
- package/scripts/sw-public-dashboard.sh +798 -0
- package/scripts/sw-quality.sh +595 -0
- package/scripts/sw-reaper.sh +1 -1
- package/scripts/sw-recruit.sh +573 -0
- package/scripts/sw-regression.sh +642 -0
- package/scripts/sw-release-manager.sh +736 -0
- package/scripts/sw-release.sh +706 -0
- package/scripts/sw-remote.sh +1 -1
- package/scripts/sw-replay.sh +520 -0
- package/scripts/sw-retro.sh +691 -0
- package/scripts/sw-scale.sh +444 -0
- package/scripts/sw-security-audit.sh +505 -0
- package/scripts/sw-self-optimize.sh +1 -1
- package/scripts/sw-session.sh +1 -1
- package/scripts/sw-setup.sh +1 -1
- package/scripts/sw-standup.sh +712 -0
- package/scripts/sw-status.sh +1 -1
- package/scripts/sw-strategic.sh +658 -0
- package/scripts/sw-stream.sh +450 -0
- package/scripts/sw-swarm.sh +583 -0
- package/scripts/sw-team-stages.sh +511 -0
- package/scripts/sw-templates.sh +1 -1
- package/scripts/sw-testgen.sh +515 -0
- package/scripts/sw-tmux-pipeline.sh +554 -0
- package/scripts/sw-tmux.sh +1 -1
- package/scripts/sw-trace.sh +485 -0
- package/scripts/sw-tracker-github.sh +188 -0
- package/scripts/sw-tracker-jira.sh +172 -0
- package/scripts/sw-tracker-linear.sh +251 -0
- package/scripts/sw-tracker.sh +117 -2
- package/scripts/sw-triage.sh +603 -0
- package/scripts/sw-upgrade.sh +1 -1
- package/scripts/sw-ux.sh +677 -0
- package/scripts/sw-webhook.sh +627 -0
- package/scripts/sw-widgets.sh +530 -0
- package/scripts/sw-worktree.sh +1 -1
|
@@ -0,0 +1,605 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ╔═══════════════════════════════════════════════════════════════════════════╗
|
|
3
|
+
# ║ shipwright context — Context Engine for Pipeline Stages ║
|
|
4
|
+
# ║ Gather architecture decisions · File hotspots · PR outcomes · Memory ║
|
|
5
|
+
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
|
+
|
|
9
|
+
VERSION="2.0.0"
|
|
10
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
|
+
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
|
+
|
|
13
|
+
# ─── Colors (matches Seth's tmux theme) ─────────────────────────────────────
|
|
14
|
+
CYAN='\033[38;2;0;212;255m' # #00d4ff — primary accent
|
|
15
|
+
PURPLE='\033[38;2;124;58;237m' # #7c3aed — secondary
|
|
16
|
+
BLUE='\033[38;2;0;102;255m' # #0066ff — tertiary
|
|
17
|
+
GREEN='\033[38;2;74;222;128m' # success
|
|
18
|
+
YELLOW='\033[38;2;250;204;21m' # warning
|
|
19
|
+
RED='\033[38;2;248;113;113m' # error
|
|
20
|
+
DIM='\033[2m'
|
|
21
|
+
BOLD='\033[1m'
|
|
22
|
+
RESET='\033[0m'
|
|
23
|
+
|
|
24
|
+
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
|
25
|
+
# shellcheck source=lib/compat.sh
|
|
26
|
+
[[ -f "$SCRIPT_DIR/lib/compat.sh" ]] && source "$SCRIPT_DIR/lib/compat.sh"
|
|
27
|
+
|
|
28
|
+
# ─── Output Helpers ─────────────────────────────────────────────────────────
|
|
29
|
+
info() { echo -e "${CYAN}${BOLD}▸${RESET} $*"; }
|
|
30
|
+
success() { echo -e "${GREEN}${BOLD}✓${RESET} $*"; }
|
|
31
|
+
warn() { echo -e "${YELLOW}${BOLD}⚠${RESET} $*"; }
|
|
32
|
+
error() { echo -e "${RED}${BOLD}✗${RESET} $*" >&2; }
|
|
33
|
+
|
|
34
|
+
now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
|
|
35
|
+
|
|
36
|
+
# ─── Paths ────────────────────────────────────────────────────────────────
|
|
37
|
+
ARTIFACTS_DIR="${REPO_DIR}/.claude/pipeline-artifacts"
|
|
38
|
+
CONTEXT_BUNDLE="${ARTIFACTS_DIR}/context-bundle.md"
|
|
39
|
+
CLAUDE_CONFIG="${REPO_DIR}/.claude/CLAUDE.md"
|
|
40
|
+
INTELLIGENCE_CACHE="${REPO_DIR}/.claude/intelligence-cache.json"
|
|
41
|
+
MEMORY_ROOT="${HOME}/.shipwright/memory"
|
|
42
|
+
|
|
43
|
+
# ─── Get repo identifier for memory lookups ────────────────────────────────
|
|
44
|
+
repo_hash() {
|
|
45
|
+
local origin
|
|
46
|
+
origin=$(git config --get remote.origin.url 2>/dev/null || echo "local")
|
|
47
|
+
echo -n "$origin" | shasum -a 256 | cut -c1-12
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
repo_memory_dir() {
|
|
51
|
+
echo "${MEMORY_ROOT}/$(repo_hash)"
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# ─── Extract codebase patterns from CLAUDE.md ──────────────────────────────
|
|
55
|
+
extract_codebase_patterns() {
|
|
56
|
+
if [[ ! -f "$CLAUDE_CONFIG" ]]; then
|
|
57
|
+
echo "# Codebase Patterns"
|
|
58
|
+
echo "(No CLAUDE.md found)"
|
|
59
|
+
return
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
local patterns_section
|
|
63
|
+
patterns_section=$(sed -n '/^## Shell Standards/,/^## [A-Z]/p' "$CLAUDE_CONFIG" 2>/dev/null || true)
|
|
64
|
+
|
|
65
|
+
if [[ -n "$patterns_section" ]]; then
|
|
66
|
+
echo "$patterns_section"
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
echo ""
|
|
70
|
+
echo "### Common Pitfalls"
|
|
71
|
+
local pitfalls_section
|
|
72
|
+
pitfalls_section=$(sed -n '/^### Common Pitfalls/,/^## [A-Z]/p' "$CLAUDE_CONFIG" 2>/dev/null || true)
|
|
73
|
+
if [[ -n "$pitfalls_section" ]]; then
|
|
74
|
+
echo "$pitfalls_section"
|
|
75
|
+
fi
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# ─── Extract file hotspots from intelligence cache ────────────────────────
|
|
79
|
+
extract_file_hotspots() {
|
|
80
|
+
if [[ ! -f "$INTELLIGENCE_CACHE" ]]; then
|
|
81
|
+
echo "# File Hotspots"
|
|
82
|
+
echo "(Intelligence cache not available)"
|
|
83
|
+
return
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
echo "# File Hotspots"
|
|
87
|
+
echo ""
|
|
88
|
+
echo "From intelligence analysis:"
|
|
89
|
+
echo ""
|
|
90
|
+
|
|
91
|
+
# Try to extract relevance data from cache
|
|
92
|
+
local hotspots
|
|
93
|
+
hotspots=$(jq -r '.entries[].result.results[]? | "\(.file): \(.relevance)% — \(.summary)"' "$INTELLIGENCE_CACHE" 2>/dev/null || true)
|
|
94
|
+
|
|
95
|
+
if [[ -n "$hotspots" ]]; then
|
|
96
|
+
echo "$hotspots" | sort -rn | uniq
|
|
97
|
+
else
|
|
98
|
+
echo "(No file hotspot data in cache)"
|
|
99
|
+
fi
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# ─── Get recent merged PRs ───────────────────────────────────────────────
|
|
103
|
+
extract_recent_prs() {
|
|
104
|
+
echo "# Recent PR Outcomes"
|
|
105
|
+
echo ""
|
|
106
|
+
|
|
107
|
+
if [[ "${NO_GITHUB:-}" == "true" ]]; then
|
|
108
|
+
echo "(GitHub disabled, using git log)"
|
|
109
|
+
echo ""
|
|
110
|
+
local recent_commits
|
|
111
|
+
recent_commits=$(git log --oneline --all --max-count=5 2>/dev/null || echo "(no git history)" | head -5)
|
|
112
|
+
echo "$recent_commits"
|
|
113
|
+
return
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
if ! command -v gh &>/dev/null; then
|
|
117
|
+
echo "(gh CLI not available, using git log)"
|
|
118
|
+
echo ""
|
|
119
|
+
local recent_commits
|
|
120
|
+
recent_commits=$(git log --oneline --all --max-count=5 2>/dev/null | head -5 || echo "(no history)")
|
|
121
|
+
echo "$recent_commits"
|
|
122
|
+
return
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
# Fetch last 5 merged PRs
|
|
126
|
+
local prs_json
|
|
127
|
+
prs_json=$(gh pr list --state merged --limit 5 --json title,mergedAt,additions,deletions,author 2>/dev/null || echo "[]")
|
|
128
|
+
|
|
129
|
+
if [[ "$prs_json" != "[]" ]] && [[ -n "$prs_json" ]]; then
|
|
130
|
+
echo "## Merged PRs (last 5)"
|
|
131
|
+
echo ""
|
|
132
|
+
echo "$prs_json" | jq -r '.[] | "\(.title) (author: \(.author.login), +\(.additions)−\(.deletions))"' 2>/dev/null || true
|
|
133
|
+
else
|
|
134
|
+
echo "(No merged PRs found or GitHub access limited)"
|
|
135
|
+
fi
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
# ─── Extract relevant memory entries ───────────────────────────────────────
|
|
139
|
+
extract_memory_entries() {
|
|
140
|
+
echo "# Relevant Memory"
|
|
141
|
+
echo ""
|
|
142
|
+
|
|
143
|
+
local mem_dir
|
|
144
|
+
mem_dir="$(repo_memory_dir)"
|
|
145
|
+
|
|
146
|
+
if [[ ! -d "$mem_dir" ]]; then
|
|
147
|
+
echo "(No memory entries yet)"
|
|
148
|
+
return
|
|
149
|
+
fi
|
|
150
|
+
|
|
151
|
+
# Check for failures
|
|
152
|
+
if [[ -f "$mem_dir/failures.json" ]]; then
|
|
153
|
+
local failure_count
|
|
154
|
+
failure_count=$(jq '.failures | length' "$mem_dir/failures.json" 2>/dev/null || echo "0")
|
|
155
|
+
if [[ "$failure_count" -gt 0 ]]; then
|
|
156
|
+
echo "## Failure Patterns"
|
|
157
|
+
echo ""
|
|
158
|
+
jq -r '.failures[] | "- **\(.category)**: \(.summary)"' "$mem_dir/failures.json" 2>/dev/null | head -5 || true
|
|
159
|
+
echo ""
|
|
160
|
+
fi
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
# Check for patterns
|
|
164
|
+
if [[ -f "$mem_dir/patterns.json" ]]; then
|
|
165
|
+
local pattern_count
|
|
166
|
+
pattern_count=$(jq 'length' "$mem_dir/patterns.json" 2>/dev/null || echo "0")
|
|
167
|
+
if [[ "$pattern_count" -gt 0 ]]; then
|
|
168
|
+
echo "## Successful Patterns"
|
|
169
|
+
echo ""
|
|
170
|
+
jq -r 'to_entries[] | "- **\(.key)**: \(.value)"' "$mem_dir/patterns.json" 2>/dev/null | head -5 || true
|
|
171
|
+
echo ""
|
|
172
|
+
fi
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
# Check for decisions
|
|
176
|
+
if [[ -f "$mem_dir/decisions.json" ]]; then
|
|
177
|
+
local decision_count
|
|
178
|
+
decision_count=$(jq '.decisions | length' "$mem_dir/decisions.json" 2>/dev/null || echo "0")
|
|
179
|
+
if [[ "$decision_count" -gt 0 ]]; then
|
|
180
|
+
echo "## Architecture Decisions"
|
|
181
|
+
echo ""
|
|
182
|
+
jq -r '.decisions[] | "- \(.decision): \(.rationale)"' "$mem_dir/decisions.json" 2>/dev/null | head -5 || true
|
|
183
|
+
echo ""
|
|
184
|
+
fi
|
|
185
|
+
fi
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
# ─── Extract relevant file previews based on goal ─────────────────────────
|
|
189
|
+
extract_file_previews() {
|
|
190
|
+
local goal="$1"
|
|
191
|
+
echo "# Relevant File Previews"
|
|
192
|
+
echo ""
|
|
193
|
+
|
|
194
|
+
# Try to identify relevant files from goal keywords
|
|
195
|
+
local keywords
|
|
196
|
+
keywords=$(echo "$goal" | tr '[:upper:]' '[:lower:]' | grep -oE '\b[a-z]+\b' | sort -u | head -10 || true)
|
|
197
|
+
|
|
198
|
+
if [[ -z "$keywords" ]]; then
|
|
199
|
+
echo "(Could not identify relevant files from goal)"
|
|
200
|
+
return
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
# Find files matching keywords in their name or content
|
|
204
|
+
local relevant_files=""
|
|
205
|
+
local count=0
|
|
206
|
+
|
|
207
|
+
for kw in $keywords; do
|
|
208
|
+
if [[ $count -ge 3 ]]; then break; fi
|
|
209
|
+
|
|
210
|
+
# Search for files matching keyword
|
|
211
|
+
local found
|
|
212
|
+
found=$(find "$REPO_DIR" -type f \( -name "*.sh" -o -name "*.md" -o -name "*.ts" -o -name "*.json" \) \
|
|
213
|
+
-not -path "*/.git/*" \
|
|
214
|
+
-not -path "*/node_modules/*" \
|
|
215
|
+
-not -path "*/.claude/*" \
|
|
216
|
+
! -size +100k \
|
|
217
|
+
2>/dev/null | grep -i "$kw" | head -2 || true)
|
|
218
|
+
|
|
219
|
+
while IFS= read -r file; do
|
|
220
|
+
[[ -z "$file" ]] && continue
|
|
221
|
+
echo "$relevant_files" | grep -q "$file" && continue
|
|
222
|
+
relevant_files="${relevant_files}${file}"$'\n'
|
|
223
|
+
((count++)) || true
|
|
224
|
+
if [[ $count -ge 3 ]]; then break 2; fi
|
|
225
|
+
done <<< "$found"
|
|
226
|
+
done
|
|
227
|
+
|
|
228
|
+
if [[ -z "$relevant_files" ]]; then
|
|
229
|
+
echo "(No matching files found)"
|
|
230
|
+
return
|
|
231
|
+
fi
|
|
232
|
+
|
|
233
|
+
while IFS= read -r file; do
|
|
234
|
+
[[ -z "$file" ]] && continue
|
|
235
|
+
if [[ ! -f "$file" ]]; then continue; fi
|
|
236
|
+
|
|
237
|
+
echo "## File: $(basename "$file")"
|
|
238
|
+
echo ""
|
|
239
|
+
echo '```'
|
|
240
|
+
head -20 "$file" 2>/dev/null | sed 's/^/ /'
|
|
241
|
+
echo '```'
|
|
242
|
+
echo ""
|
|
243
|
+
done <<< "$relevant_files"
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
# ─── Extract architecture decisions from docs ──────────────────────────────
|
|
247
|
+
extract_architecture_decisions() {
|
|
248
|
+
echo "# Architecture Decision Records"
|
|
249
|
+
echo ""
|
|
250
|
+
|
|
251
|
+
local adr_file="${REPO_DIR}/.claude/ARCHITECTURE.md"
|
|
252
|
+
if [[ -f "$adr_file" ]]; then
|
|
253
|
+
head -40 "$adr_file" | sed 's/^//'
|
|
254
|
+
echo ""
|
|
255
|
+
else
|
|
256
|
+
echo "(No ARCHITECTURE.md found)"
|
|
257
|
+
fi
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
# ─── Stage-specific guidance ───────────────────────────────────────────────
|
|
261
|
+
stage_guidance() {
|
|
262
|
+
local stage="$1"
|
|
263
|
+
|
|
264
|
+
case "$stage" in
|
|
265
|
+
plan)
|
|
266
|
+
cat <<'EOF'
|
|
267
|
+
# Plan Stage Guidance
|
|
268
|
+
|
|
269
|
+
## Focus Areas
|
|
270
|
+
- Break down goal into measurable milestones
|
|
271
|
+
- Identify dependencies and blockers
|
|
272
|
+
- Estimate scope and complexity
|
|
273
|
+
- Consider edge cases and error paths
|
|
274
|
+
|
|
275
|
+
## Key Questions
|
|
276
|
+
- What are the success criteria?
|
|
277
|
+
- What are the known constraints?
|
|
278
|
+
- What existing patterns apply here?
|
|
279
|
+
- Are there similar completed features to reference?
|
|
280
|
+
|
|
281
|
+
## Anti-patterns to Avoid
|
|
282
|
+
- Over-scoping the initial plan
|
|
283
|
+
- Missing edge cases in requirement analysis
|
|
284
|
+
- Ignoring technical debt in design phase
|
|
285
|
+
EOF
|
|
286
|
+
;;
|
|
287
|
+
design)
|
|
288
|
+
cat <<'EOF'
|
|
289
|
+
# Design Stage Guidance
|
|
290
|
+
|
|
291
|
+
## Focus Areas
|
|
292
|
+
- Define interfaces and contracts
|
|
293
|
+
- Establish layer boundaries
|
|
294
|
+
- Document state management approach
|
|
295
|
+
- Plan error handling and recovery
|
|
296
|
+
|
|
297
|
+
## Architectural Constraints
|
|
298
|
+
- Follow established naming conventions from codebase
|
|
299
|
+
- Respect layer dependencies (check ARCHITECTURE.md)
|
|
300
|
+
- Use patterns validated in memory system
|
|
301
|
+
- Consider testability from the start
|
|
302
|
+
|
|
303
|
+
## Common Pitfalls
|
|
304
|
+
- Designing without understanding existing patterns
|
|
305
|
+
- Over-engineering for future extensibility
|
|
306
|
+
- Inconsistent error handling strategies
|
|
307
|
+
EOF
|
|
308
|
+
;;
|
|
309
|
+
build)
|
|
310
|
+
cat <<'EOF'
|
|
311
|
+
# Build Stage Guidance
|
|
312
|
+
|
|
313
|
+
## Standards to Follow
|
|
314
|
+
- Match existing code style (imports, naming, structure)
|
|
315
|
+
- Use patterns from hotspot files
|
|
316
|
+
- Implement with full error handling
|
|
317
|
+
- Write as you go, not after
|
|
318
|
+
|
|
319
|
+
## Testing Strategy
|
|
320
|
+
- Write tests alongside implementation
|
|
321
|
+
- Test error paths and edge cases
|
|
322
|
+
- Verify integration with existing code
|
|
323
|
+
- Use coverage targets from memory
|
|
324
|
+
|
|
325
|
+
## Quick Wins
|
|
326
|
+
- Look at similar recently-merged PRs for patterns
|
|
327
|
+
- Check failure patterns to avoid repeating mistakes
|
|
328
|
+
- Use mock patterns from test specialists
|
|
329
|
+
- Reference file previews for coding style
|
|
330
|
+
EOF
|
|
331
|
+
;;
|
|
332
|
+
test)
|
|
333
|
+
cat <<'EOF'
|
|
334
|
+
# Test Stage Guidance
|
|
335
|
+
|
|
336
|
+
## Testing Focus
|
|
337
|
+
- Cover both happy and error paths
|
|
338
|
+
- Test boundaries and edge cases
|
|
339
|
+
- Verify integration with existing code
|
|
340
|
+
- Achieve coverage targets from memory
|
|
341
|
+
|
|
342
|
+
## Mock Patterns
|
|
343
|
+
- Study existing test files for mock approach
|
|
344
|
+
- Use established test harness conventions
|
|
345
|
+
- Mock external dependencies consistently
|
|
346
|
+
- Validate error scenarios
|
|
347
|
+
|
|
348
|
+
## Coverage Requirements
|
|
349
|
+
- Unit tests for all public functions
|
|
350
|
+
- Integration tests for multi-component flows
|
|
351
|
+
- End-to-end tests for user-facing features
|
|
352
|
+
- Document coverage gaps
|
|
353
|
+
EOF
|
|
354
|
+
;;
|
|
355
|
+
review)
|
|
356
|
+
cat <<'EOF'
|
|
357
|
+
# Review Stage Guidance
|
|
358
|
+
|
|
359
|
+
## Review Checklist
|
|
360
|
+
- Code matches established patterns from hotspots
|
|
361
|
+
- No violations of architecture layer boundaries
|
|
362
|
+
- Error handling is complete and tested
|
|
363
|
+
- Breaking changes are documented
|
|
364
|
+
- Performance impact is acceptable
|
|
365
|
+
|
|
366
|
+
## Security Check
|
|
367
|
+
- No credential or secret exposure
|
|
368
|
+
- Input validation at boundaries
|
|
369
|
+
- Authorization checks where needed
|
|
370
|
+
- Dependencies are reviewed
|
|
371
|
+
|
|
372
|
+
## Common Issues
|
|
373
|
+
- Deviations from established patterns
|
|
374
|
+
- Incomplete error handling
|
|
375
|
+
- Test coverage gaps
|
|
376
|
+
- Missing documentation updates
|
|
377
|
+
EOF
|
|
378
|
+
;;
|
|
379
|
+
*)
|
|
380
|
+
echo "# Stage-Specific Guidance"
|
|
381
|
+
echo "(No specific guidance for stage: $stage)"
|
|
382
|
+
;;
|
|
383
|
+
esac
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
# ─── Main gather function ─────────────────────────────────────────────────
|
|
387
|
+
gather_context() {
|
|
388
|
+
local goal="$1"
|
|
389
|
+
local stage="${2:-build}"
|
|
390
|
+
|
|
391
|
+
info "Building context bundle for ${CYAN}${stage}${RESET} stage..."
|
|
392
|
+
|
|
393
|
+
mkdir -p "$ARTIFACTS_DIR"
|
|
394
|
+
|
|
395
|
+
local tmp_file
|
|
396
|
+
tmp_file=$(mktemp "${TMPDIR:-/tmp}/sw-context-bundle.XXXXXX")
|
|
397
|
+
|
|
398
|
+
# Write bundle header
|
|
399
|
+
{
|
|
400
|
+
echo "# Pipeline Context Bundle"
|
|
401
|
+
echo ""
|
|
402
|
+
echo "Generated: $(now_iso)"
|
|
403
|
+
echo "Stage: ${stage}"
|
|
404
|
+
echo "Goal: ${goal}"
|
|
405
|
+
echo ""
|
|
406
|
+
echo "---"
|
|
407
|
+
echo ""
|
|
408
|
+
} >> "$tmp_file"
|
|
409
|
+
|
|
410
|
+
# Section: Codebase Patterns
|
|
411
|
+
{
|
|
412
|
+
echo ""
|
|
413
|
+
extract_codebase_patterns
|
|
414
|
+
echo ""
|
|
415
|
+
echo "---"
|
|
416
|
+
echo ""
|
|
417
|
+
} >> "$tmp_file"
|
|
418
|
+
|
|
419
|
+
# Section: File Hotspots
|
|
420
|
+
{
|
|
421
|
+
extract_file_hotspots
|
|
422
|
+
echo ""
|
|
423
|
+
echo "---"
|
|
424
|
+
echo ""
|
|
425
|
+
} >> "$tmp_file"
|
|
426
|
+
|
|
427
|
+
# Section: Recent PR Outcomes
|
|
428
|
+
{
|
|
429
|
+
extract_recent_prs
|
|
430
|
+
echo ""
|
|
431
|
+
echo "---"
|
|
432
|
+
echo ""
|
|
433
|
+
} >> "$tmp_file"
|
|
434
|
+
|
|
435
|
+
# Section: Memory Entries
|
|
436
|
+
{
|
|
437
|
+
extract_memory_entries
|
|
438
|
+
echo ""
|
|
439
|
+
echo "---"
|
|
440
|
+
echo ""
|
|
441
|
+
} >> "$tmp_file"
|
|
442
|
+
|
|
443
|
+
# Section: File Previews
|
|
444
|
+
{
|
|
445
|
+
extract_file_previews "$goal"
|
|
446
|
+
echo ""
|
|
447
|
+
echo "---"
|
|
448
|
+
echo ""
|
|
449
|
+
} >> "$tmp_file"
|
|
450
|
+
|
|
451
|
+
# Section: Architecture Decisions
|
|
452
|
+
{
|
|
453
|
+
extract_architecture_decisions
|
|
454
|
+
echo ""
|
|
455
|
+
echo "---"
|
|
456
|
+
echo ""
|
|
457
|
+
} >> "$tmp_file"
|
|
458
|
+
|
|
459
|
+
# Section: Stage-Specific Guidance
|
|
460
|
+
{
|
|
461
|
+
echo ""
|
|
462
|
+
stage_guidance "$stage"
|
|
463
|
+
echo ""
|
|
464
|
+
} >> "$tmp_file"
|
|
465
|
+
|
|
466
|
+
# Atomically move to final location
|
|
467
|
+
mv "$tmp_file" "$CONTEXT_BUNDLE"
|
|
468
|
+
success "Context bundle written to ${CYAN}${CONTEXT_BUNDLE}${RESET}"
|
|
469
|
+
|
|
470
|
+
return 0
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
# ─── Show current bundle ───────────────────────────────────────────────────
|
|
474
|
+
show_context() {
|
|
475
|
+
if [[ ! -f "$CONTEXT_BUNDLE" ]]; then
|
|
476
|
+
warn "No context bundle found at ${CONTEXT_BUNDLE}"
|
|
477
|
+
echo "Run '${CYAN}shipwright context gather --goal \"...\" --stage plan${RESET}' first"
|
|
478
|
+
return 1
|
|
479
|
+
fi
|
|
480
|
+
|
|
481
|
+
cat "$CONTEXT_BUNDLE"
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
# ─── Clear stale bundle ────────────────────────────────────────────────────
|
|
485
|
+
clear_context() {
|
|
486
|
+
if [[ -f "$CONTEXT_BUNDLE" ]]; then
|
|
487
|
+
rm -f "$CONTEXT_BUNDLE"
|
|
488
|
+
success "Context bundle cleared"
|
|
489
|
+
else
|
|
490
|
+
warn "No context bundle to clear"
|
|
491
|
+
fi
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
# ─── Help ──────────────────────────────────────────────────────────────────
|
|
495
|
+
show_help() {
|
|
496
|
+
cat <<EOF
|
|
497
|
+
${CYAN}${BOLD}shipwright context${RESET} ${DIM}v${VERSION}${RESET} — Context gathering engine for pipeline stages
|
|
498
|
+
|
|
499
|
+
${BOLD}USAGE${RESET}
|
|
500
|
+
${CYAN}shipwright context${RESET} <command> [options]
|
|
501
|
+
|
|
502
|
+
${BOLD}COMMANDS${RESET}
|
|
503
|
+
${CYAN}gather${RESET} --goal "..." --stage plan Generate context bundle
|
|
504
|
+
${CYAN}gather${RESET} --issue N --stage build Generate from GitHub issue
|
|
505
|
+
${CYAN}show${RESET} Display current bundle
|
|
506
|
+
${CYAN}clear${RESET} Remove stale bundle
|
|
507
|
+
${CYAN}help${RESET} Show this help
|
|
508
|
+
|
|
509
|
+
${BOLD}OPTIONS${RESET}
|
|
510
|
+
${CYAN}--goal${RESET} TEXT Goal or description for context gathering
|
|
511
|
+
${CYAN}--issue${RESET} N GitHub issue number
|
|
512
|
+
${CYAN}--stage${RESET} STAGE Pipeline stage: plan, design, build, test, review
|
|
513
|
+
|
|
514
|
+
${BOLD}EXAMPLES${RESET}
|
|
515
|
+
${DIM}shipwright context gather --goal "Add OAuth" --stage design${RESET}
|
|
516
|
+
${DIM}shipwright context gather --issue 42 --stage build${RESET}
|
|
517
|
+
${DIM}shipwright context show${RESET}
|
|
518
|
+
${DIM}shipwright context clear${RESET}
|
|
519
|
+
|
|
520
|
+
${BOLD}BUNDLE INCLUDES${RESET}
|
|
521
|
+
• Codebase patterns and standards
|
|
522
|
+
• File hotspots from intelligence analysis
|
|
523
|
+
• Recent merged PR outcomes
|
|
524
|
+
• Failure patterns and learned patterns
|
|
525
|
+
• Relevant file previews with code samples
|
|
526
|
+
• Architecture decision records
|
|
527
|
+
• Stage-specific guidance and checklists
|
|
528
|
+
|
|
529
|
+
${DIM}The context bundle is written to .claude/pipeline-artifacts/context-bundle.md${RESET}
|
|
530
|
+
${DIM}and automatically included in pipeline prompts.${RESET}
|
|
531
|
+
|
|
532
|
+
EOF
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
# ─── Main dispatcher ───────────────────────────────────────────────────────
|
|
536
|
+
main() {
|
|
537
|
+
local cmd="${1:-help}"
|
|
538
|
+
shift 2>/dev/null || true
|
|
539
|
+
|
|
540
|
+
case "$cmd" in
|
|
541
|
+
gather)
|
|
542
|
+
local goal="" issue="" stage="build"
|
|
543
|
+
|
|
544
|
+
while [[ $# -gt 0 ]]; do
|
|
545
|
+
case "$1" in
|
|
546
|
+
--goal)
|
|
547
|
+
goal="$2"
|
|
548
|
+
shift 2
|
|
549
|
+
;;
|
|
550
|
+
--issue)
|
|
551
|
+
issue="$2"
|
|
552
|
+
shift 2
|
|
553
|
+
;;
|
|
554
|
+
--stage)
|
|
555
|
+
stage="$2"
|
|
556
|
+
shift 2
|
|
557
|
+
;;
|
|
558
|
+
*)
|
|
559
|
+
error "Unknown option: $1"
|
|
560
|
+
echo ""
|
|
561
|
+
show_help
|
|
562
|
+
exit 1
|
|
563
|
+
;;
|
|
564
|
+
esac
|
|
565
|
+
done
|
|
566
|
+
|
|
567
|
+
if [[ -z "$goal" && -z "$issue" ]]; then
|
|
568
|
+
error "Must provide --goal or --issue"
|
|
569
|
+
echo ""
|
|
570
|
+
show_help
|
|
571
|
+
exit 1
|
|
572
|
+
fi
|
|
573
|
+
|
|
574
|
+
# If issue provided, fetch from GitHub
|
|
575
|
+
if [[ -n "$issue" ]]; then
|
|
576
|
+
if [[ "${NO_GITHUB:-}" == "true" ]] || ! command -v gh &>/dev/null; then
|
|
577
|
+
goal="GitHub issue #$issue (fetch unavailable)"
|
|
578
|
+
else
|
|
579
|
+
goal=$(gh issue view "$issue" --json title,body --template '{{.title}}: {{.body}}' 2>/dev/null || echo "GitHub issue #$issue")
|
|
580
|
+
fi
|
|
581
|
+
fi
|
|
582
|
+
|
|
583
|
+
gather_context "$goal" "$stage"
|
|
584
|
+
;;
|
|
585
|
+
show)
|
|
586
|
+
show_context
|
|
587
|
+
;;
|
|
588
|
+
clear)
|
|
589
|
+
clear_context
|
|
590
|
+
;;
|
|
591
|
+
help|--help|-h)
|
|
592
|
+
show_help
|
|
593
|
+
;;
|
|
594
|
+
*)
|
|
595
|
+
error "Unknown command: $cmd"
|
|
596
|
+
echo ""
|
|
597
|
+
show_help
|
|
598
|
+
exit 1
|
|
599
|
+
;;
|
|
600
|
+
esac
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
|
604
|
+
main "$@"
|
|
605
|
+
fi
|
package/scripts/sw-cost.sh
CHANGED