shipwright-cli 3.1.0 → 3.2.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 +21 -7
- package/config/defaults.json +25 -2
- package/config/policy.json +1 -1
- package/dashboard/public/index.html +6 -0
- package/dashboard/public/styles.css +76 -0
- package/dashboard/server.ts +51 -0
- package/dashboard/src/core/api.ts +5 -0
- package/dashboard/src/types/api.ts +10 -0
- package/dashboard/src/views/metrics.ts +69 -1
- package/package.json +1 -1
- package/scripts/lib/daemon-adaptive.sh +4 -2
- package/scripts/lib/daemon-patrol.sh +2 -2
- package/scripts/lib/daemon-state.sh +7 -0
- package/scripts/lib/helpers.sh +3 -1
- package/scripts/lib/pipeline-detection.sh +1 -1
- package/scripts/lib/pipeline-intelligence.sh +5 -3
- package/scripts/lib/pipeline-quality-checks.sh +8 -4
- package/scripts/lib/pipeline-stages.sh +132 -2
- package/scripts/sw +1 -1
- package/scripts/sw-activity.sh +1 -7
- package/scripts/sw-adaptive.sh +7 -7
- package/scripts/sw-adversarial.sh +1 -1
- package/scripts/sw-architecture-enforcer.sh +1 -1
- package/scripts/sw-auth.sh +1 -1
- package/scripts/sw-autonomous.sh +1 -1
- package/scripts/sw-changelog.sh +1 -1
- package/scripts/sw-checkpoint.sh +1 -1
- package/scripts/sw-ci.sh +11 -6
- package/scripts/sw-cleanup.sh +1 -1
- package/scripts/sw-code-review.sh +36 -17
- package/scripts/sw-connect.sh +1 -1
- package/scripts/sw-context.sh +1 -1
- package/scripts/sw-cost.sh +60 -3
- package/scripts/sw-daemon.sh +5 -2
- package/scripts/sw-dashboard.sh +1 -1
- package/scripts/sw-db.sh +13 -5
- package/scripts/sw-decide.sh +1 -1
- package/scripts/sw-decompose.sh +1 -1
- package/scripts/sw-deps.sh +1 -1
- package/scripts/sw-developer-simulation.sh +1 -1
- package/scripts/sw-discovery.sh +54 -4
- package/scripts/sw-doc-fleet.sh +1 -1
- package/scripts/sw-docs-agent.sh +1 -1
- package/scripts/sw-docs.sh +1 -1
- package/scripts/sw-doctor.sh +1 -1
- package/scripts/sw-dora.sh +1 -1
- package/scripts/sw-durable.sh +9 -5
- package/scripts/sw-e2e-orchestrator.sh +1 -1
- package/scripts/sw-eventbus.sh +7 -4
- package/scripts/sw-evidence.sh +1 -1
- package/scripts/sw-feedback.sh +1 -1
- package/scripts/sw-fix.sh +1 -1
- package/scripts/sw-fleet-discover.sh +1 -1
- package/scripts/sw-fleet-viz.sh +6 -4
- package/scripts/sw-fleet.sh +1 -1
- package/scripts/sw-github-app.sh +3 -2
- package/scripts/sw-github-checks.sh +1 -1
- package/scripts/sw-github-deploy.sh +1 -1
- package/scripts/sw-github-graphql.sh +1 -1
- package/scripts/sw-guild.sh +1 -1
- package/scripts/sw-heartbeat.sh +1 -1
- package/scripts/sw-hygiene.sh +5 -3
- package/scripts/sw-incident.sh +9 -5
- package/scripts/sw-init.sh +1 -1
- package/scripts/sw-instrument.sh +1 -1
- package/scripts/sw-intelligence.sh +3 -2
- package/scripts/sw-jira.sh +1 -1
- package/scripts/sw-launchd.sh +1 -1
- package/scripts/sw-linear.sh +1 -1
- package/scripts/sw-logs.sh +1 -1
- package/scripts/sw-loop.sh +72 -16
- package/scripts/sw-memory.sh +2 -2
- package/scripts/sw-mission-control.sh +1 -1
- package/scripts/sw-model-router.sh +3 -2
- package/scripts/sw-otel.sh +4 -2
- package/scripts/sw-oversight.sh +1 -1
- package/scripts/sw-pipeline-composer.sh +3 -1
- package/scripts/sw-pipeline-vitals.sh +11 -6
- package/scripts/sw-pipeline.sh +20 -8
- package/scripts/sw-pm.sh +5 -4
- package/scripts/sw-pr-lifecycle.sh +1 -1
- package/scripts/sw-predictive.sh +11 -5
- package/scripts/sw-prep.sh +1 -1
- package/scripts/sw-ps.sh +1 -1
- package/scripts/sw-public-dashboard.sh +3 -2
- package/scripts/sw-quality.sh +13 -6
- package/scripts/sw-reaper.sh +1 -1
- package/scripts/sw-recruit.sh +1 -1
- package/scripts/sw-regression.sh +1 -1
- package/scripts/sw-release-manager.sh +1 -1
- package/scripts/sw-release.sh +1 -1
- package/scripts/sw-remote.sh +1 -1
- package/scripts/sw-replay.sh +1 -1
- package/scripts/sw-retro.sh +1 -1
- package/scripts/sw-review-rerun.sh +1 -1
- package/scripts/sw-scale.sh +5 -3
- package/scripts/sw-security-audit.sh +1 -1
- package/scripts/sw-self-optimize.sh +168 -4
- package/scripts/sw-session.sh +1 -1
- package/scripts/sw-setup.sh +1 -1
- package/scripts/sw-standup.sh +1 -1
- package/scripts/sw-status.sh +1 -1
- package/scripts/sw-strategic.sh +11 -6
- package/scripts/sw-stream.sh +7 -4
- package/scripts/sw-swarm.sh +3 -2
- package/scripts/sw-team-stages.sh +1 -1
- package/scripts/sw-templates.sh +3 -3
- package/scripts/sw-testgen.sh +11 -6
- package/scripts/sw-tmux-pipeline.sh +1 -1
- package/scripts/sw-tmux.sh +35 -1
- package/scripts/sw-trace.sh +1 -1
- package/scripts/sw-tracker.sh +1 -1
- package/scripts/sw-triage.sh +2 -2
- package/scripts/sw-upgrade.sh +1 -1
- package/scripts/sw-ux.sh +1 -1
- package/scripts/sw-webhook.sh +3 -2
- package/scripts/sw-widgets.sh +7 -4
- package/scripts/sw-worktree.sh +1 -1
|
@@ -3,6 +3,108 @@
|
|
|
3
3
|
[[ -n "${_PIPELINE_STAGES_LOADED:-}" ]] && return 0
|
|
4
4
|
_PIPELINE_STAGES_LOADED=1
|
|
5
5
|
|
|
6
|
+
# ─── Context pruning helpers ────────────────────────────────────────────────
|
|
7
|
+
|
|
8
|
+
# prune_context_section — Intelligently truncate a context section to fit a char budget.
|
|
9
|
+
# $1: section name (for logging/markers)
|
|
10
|
+
# $2: content string
|
|
11
|
+
# $3: max_chars (default 5000)
|
|
12
|
+
# For JSON content (starts with { or [): extracts summary fields via jq.
|
|
13
|
+
# For text content: sandwich approach — keeps first + last N lines.
|
|
14
|
+
# Outputs the (possibly truncated) content to stdout.
|
|
15
|
+
prune_context_section() {
|
|
16
|
+
local section_name="${1:-section}"
|
|
17
|
+
local content="${2:-}"
|
|
18
|
+
local max_chars="${3:-5000}"
|
|
19
|
+
|
|
20
|
+
[[ -z "$content" ]] && return 0
|
|
21
|
+
|
|
22
|
+
local content_len=${#content}
|
|
23
|
+
if [[ "$content_len" -le "$max_chars" ]]; then
|
|
24
|
+
printf '%s' "$content"
|
|
25
|
+
return 0
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# JSON content — try jq summary extraction
|
|
29
|
+
local first_char="${content:0:1}"
|
|
30
|
+
if [[ "$first_char" == "{" || "$first_char" == "[" ]]; then
|
|
31
|
+
local summary=""
|
|
32
|
+
# Try extracting summary/results fields
|
|
33
|
+
summary=$(printf '%s' "$content" | jq -r '
|
|
34
|
+
if type == "object" then
|
|
35
|
+
to_entries | map(
|
|
36
|
+
if (.value | type) == "array" then
|
|
37
|
+
"\(.key): \(.value | length) items"
|
|
38
|
+
elif (.value | type) == "object" then
|
|
39
|
+
"\(.key): \(.value | keys | join(", "))"
|
|
40
|
+
else
|
|
41
|
+
"\(.key): \(.value)"
|
|
42
|
+
end
|
|
43
|
+
) | join("\n")
|
|
44
|
+
elif type == "array" then
|
|
45
|
+
.[:5] | map(tostring) | join("\n")
|
|
46
|
+
else . end
|
|
47
|
+
' 2>/dev/null) || true
|
|
48
|
+
|
|
49
|
+
if [[ -n "$summary" && ${#summary} -le "$max_chars" ]]; then
|
|
50
|
+
printf '%s' "$summary"
|
|
51
|
+
return 0
|
|
52
|
+
fi
|
|
53
|
+
# jq failed or still too large — fall through to text truncation
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# Text content — sandwich approach (first N + last N lines)
|
|
57
|
+
local line_count=0
|
|
58
|
+
line_count=$(printf '%s\n' "$content" | wc -l | xargs)
|
|
59
|
+
|
|
60
|
+
# Calculate how many lines to keep from each end
|
|
61
|
+
# Approximate chars-per-line to figure out line budget
|
|
62
|
+
local avg_chars_per_line=80
|
|
63
|
+
if [[ "$line_count" -gt 0 ]]; then
|
|
64
|
+
avg_chars_per_line=$(( content_len / line_count ))
|
|
65
|
+
[[ "$avg_chars_per_line" -lt 20 ]] && avg_chars_per_line=20
|
|
66
|
+
fi
|
|
67
|
+
local total_lines_budget=$(( max_chars / avg_chars_per_line ))
|
|
68
|
+
[[ "$total_lines_budget" -lt 4 ]] && total_lines_budget=4
|
|
69
|
+
local half=$(( total_lines_budget / 2 ))
|
|
70
|
+
|
|
71
|
+
local head_part=""
|
|
72
|
+
local tail_part=""
|
|
73
|
+
head_part=$(printf '%s\n' "$content" | head -"$half")
|
|
74
|
+
tail_part=$(printf '%s\n' "$content" | tail -"$half")
|
|
75
|
+
|
|
76
|
+
printf '%s\n[... %s truncated: %d→%d chars ...]\n%s' \
|
|
77
|
+
"$head_part" "$section_name" "$content_len" "$max_chars" "$tail_part"
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
# guard_prompt_size — Warn and hard-truncate if prompt exceeds budget.
|
|
81
|
+
# $1: stage name (for logging)
|
|
82
|
+
# $2: prompt content
|
|
83
|
+
# $3: max_chars (default 100000)
|
|
84
|
+
# Outputs the (possibly truncated) prompt to stdout.
|
|
85
|
+
PIPELINE_PROMPT_BUDGET="${PIPELINE_PROMPT_BUDGET:-100000}"
|
|
86
|
+
|
|
87
|
+
guard_prompt_size() {
|
|
88
|
+
local stage_name="${1:-stage}"
|
|
89
|
+
local prompt="${2:-}"
|
|
90
|
+
local max_chars="${3:-$PIPELINE_PROMPT_BUDGET}"
|
|
91
|
+
|
|
92
|
+
local prompt_len=${#prompt}
|
|
93
|
+
if [[ "$prompt_len" -le "$max_chars" ]]; then
|
|
94
|
+
printf '%s' "$prompt"
|
|
95
|
+
return 0
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
warn "${stage_name} prompt too large (${prompt_len} chars, budget ${max_chars}) — truncating"
|
|
99
|
+
emit_event "pipeline.prompt_truncated" \
|
|
100
|
+
"stage=$stage_name" \
|
|
101
|
+
"original=$prompt_len" \
|
|
102
|
+
"budget=$max_chars" 2>/dev/null || true
|
|
103
|
+
|
|
104
|
+
printf '%s\n\n... [CONTEXT TRUNCATED: %s prompt exceeded %d char budget. Focus on the goal and requirements.]' \
|
|
105
|
+
"${prompt:0:$max_chars}" "$stage_name" "$max_chars"
|
|
106
|
+
}
|
|
107
|
+
|
|
6
108
|
# ─── Safe git helpers ────────────────────────────────────────────────────────
|
|
7
109
|
# BASE_BRANCH may not exist locally (e.g. --local mode with no remote).
|
|
8
110
|
# These helpers return empty output instead of crashing under set -euo pipefail.
|
|
@@ -178,6 +280,7 @@ ${ISSUE_BODY}
|
|
|
178
280
|
|
|
179
281
|
# Inject architecture context (import graph, modules, test map)
|
|
180
282
|
if [[ -n "$arch_context" ]]; then
|
|
283
|
+
arch_context=$(prune_context_section "architecture" "$arch_context" 5000)
|
|
181
284
|
plan_prompt="${plan_prompt}
|
|
182
285
|
## Architecture Context
|
|
183
286
|
${arch_context}
|
|
@@ -189,6 +292,7 @@ ${arch_context}
|
|
|
189
292
|
if [[ -f "$_context_bundle" ]]; then
|
|
190
293
|
local _cb_content
|
|
191
294
|
_cb_content=$(cat "$_context_bundle" 2>/dev/null | head -100 || true)
|
|
295
|
+
_cb_content=$(prune_context_section "context-bundle" "$_cb_content" 8000)
|
|
192
296
|
if [[ -n "$_cb_content" ]]; then
|
|
193
297
|
plan_prompt="${plan_prompt}
|
|
194
298
|
## Pipeline Context
|
|
@@ -204,6 +308,7 @@ ${_cb_content}
|
|
|
204
308
|
if [[ -n "$plan_memory" && "$plan_memory" != *'"results":[]'* && "$plan_memory" != *'"error"'* ]]; then
|
|
205
309
|
local memory_summary
|
|
206
310
|
memory_summary=$(echo "$plan_memory" | jq -r '.results[]? | "- \(.)"' 2>/dev/null | head -10 || true)
|
|
311
|
+
memory_summary=$(prune_context_section "memory" "$memory_summary" 10000)
|
|
207
312
|
if [[ -n "$memory_summary" ]]; then
|
|
208
313
|
plan_prompt="${plan_prompt}
|
|
209
314
|
## Historical Context (from previous pipelines)
|
|
@@ -228,6 +333,7 @@ ${plan_hint}
|
|
|
228
333
|
if [[ -x "$SCRIPT_DIR/sw-discovery.sh" ]]; then
|
|
229
334
|
local plan_discoveries
|
|
230
335
|
plan_discoveries=$("$SCRIPT_DIR/sw-discovery.sh" inject "*.md,*.json" 2>/dev/null | head -20 || true)
|
|
336
|
+
plan_discoveries=$(prune_context_section "discoveries" "$plan_discoveries" 3000)
|
|
231
337
|
if [[ -n "$plan_discoveries" ]]; then
|
|
232
338
|
plan_prompt="${plan_prompt}
|
|
233
339
|
## Discoveries from Other Pipelines
|
|
@@ -248,6 +354,7 @@ ${plan_discoveries}
|
|
|
248
354
|
"Patterns: \((.patterns // []) | join(", "))",
|
|
249
355
|
"Rules: \((.rules // []) | join("; "))"
|
|
250
356
|
' "$arch_file_plan" 2>/dev/null || true)
|
|
357
|
+
arch_patterns=$(prune_context_section "intelligence" "$arch_patterns" 5000)
|
|
251
358
|
if [[ -n "$arch_patterns" ]]; then
|
|
252
359
|
plan_prompt="${plan_prompt}
|
|
253
360
|
## Architecture Patterns
|
|
@@ -284,6 +391,12 @@ Focus on: threat modeling, OWASP top 10, input validation, authentication/author
|
|
|
284
391
|
- Test command: ${TEST_CMD:-not configured}
|
|
285
392
|
- Task type: ${TASK_TYPE:-feature}
|
|
286
393
|
|
|
394
|
+
## Context Efficiency
|
|
395
|
+
- Batch independent tool calls in parallel when possible
|
|
396
|
+
- Read specific file sections (offset/limit) instead of entire large files
|
|
397
|
+
- Use targeted grep searches — avoid scanning entire codebases into context
|
|
398
|
+
- Delegate multi-file analysis to subagents when available
|
|
399
|
+
|
|
287
400
|
## Required Output
|
|
288
401
|
Create a Markdown plan with these sections:
|
|
289
402
|
|
|
@@ -306,6 +419,9 @@ How to verify the implementation works.
|
|
|
306
419
|
Checklist of completion criteria.
|
|
307
420
|
"
|
|
308
421
|
|
|
422
|
+
# Guard total prompt size
|
|
423
|
+
plan_prompt=$(guard_prompt_size "plan" "$plan_prompt")
|
|
424
|
+
|
|
309
425
|
local plan_model
|
|
310
426
|
plan_model=$(jq -r --arg id "plan" '(.stages[] | select(.id == $id) | .config.model) // .defaults.model // "opus"' "$PIPELINE_CONFIG" 2>/dev/null) || true
|
|
311
427
|
[[ -n "$MODEL" ]] && plan_model="$MODEL"
|
|
@@ -615,6 +731,7 @@ stage_design() {
|
|
|
615
731
|
if type gather_architecture_context &>/dev/null; then
|
|
616
732
|
arch_struct_context=$(gather_architecture_context "${PROJECT_ROOT:-.}" 2>/dev/null || true)
|
|
617
733
|
fi
|
|
734
|
+
arch_struct_context=$(prune_context_section "architecture" "$arch_struct_context" 5000)
|
|
618
735
|
|
|
619
736
|
# Memory integration — inject context if memory system available
|
|
620
737
|
local memory_context=""
|
|
@@ -625,12 +742,14 @@ stage_design() {
|
|
|
625
742
|
if [[ -z "$memory_context" ]] && [[ -x "$SCRIPT_DIR/sw-memory.sh" ]]; then
|
|
626
743
|
memory_context=$(bash "$SCRIPT_DIR/sw-memory.sh" inject "design" 2>/dev/null) || true
|
|
627
744
|
fi
|
|
745
|
+
memory_context=$(prune_context_section "memory" "$memory_context" 10000)
|
|
628
746
|
|
|
629
747
|
# Inject cross-pipeline discoveries for design stage
|
|
630
748
|
local design_discoveries=""
|
|
631
749
|
if [[ -x "$SCRIPT_DIR/sw-discovery.sh" ]]; then
|
|
632
750
|
design_discoveries=$("$SCRIPT_DIR/sw-discovery.sh" inject "*.md,*.ts,*.tsx,*.js" 2>/dev/null | head -20 || true)
|
|
633
751
|
fi
|
|
752
|
+
design_discoveries=$(prune_context_section "discoveries" "$design_discoveries" 3000)
|
|
634
753
|
|
|
635
754
|
# Inject architecture model patterns if available
|
|
636
755
|
local arch_context=""
|
|
@@ -654,6 +773,7 @@ ${arch_patterns}
|
|
|
654
773
|
${arch_layers}}"
|
|
655
774
|
fi
|
|
656
775
|
fi
|
|
776
|
+
arch_context=$(prune_context_section "intelligence" "$arch_context" 5000)
|
|
657
777
|
|
|
658
778
|
# Inject rejected design approaches and anti-patterns from memory
|
|
659
779
|
local design_antipatterns=""
|
|
@@ -661,6 +781,7 @@ ${arch_layers}}"
|
|
|
661
781
|
local rejected_designs
|
|
662
782
|
rejected_designs=$(intelligence_search_memory "rejected design approaches anti-patterns for: ${GOAL:-}" "${HOME}/.shipwright/memory" 3 2>/dev/null) || true
|
|
663
783
|
if [[ -n "$rejected_designs" ]]; then
|
|
784
|
+
rejected_designs=$(prune_context_section "antipatterns" "$rejected_designs" 5000)
|
|
664
785
|
design_antipatterns="
|
|
665
786
|
## Rejected Approaches (from past reviews)
|
|
666
787
|
These design approaches were rejected in past reviews. Avoid repeating them:
|
|
@@ -726,6 +847,9 @@ Produce this EXACT format:
|
|
|
726
847
|
|
|
727
848
|
Be concrete and specific. Reference actual file paths in the codebase. Consider edge cases and failure modes."
|
|
728
849
|
|
|
850
|
+
# Guard total prompt size
|
|
851
|
+
design_prompt=$(guard_prompt_size "design" "$design_prompt")
|
|
852
|
+
|
|
729
853
|
local design_model
|
|
730
854
|
design_model=$(jq -r --arg id "design" '(.stages[] | select(.id == $id) | .config.model) // .defaults.model // "opus"' "$PIPELINE_CONFIG" 2>/dev/null) || true
|
|
731
855
|
[[ -n "$MODEL" ]] && design_model="$MODEL"
|
|
@@ -1242,7 +1366,8 @@ stage_test() {
|
|
|
1242
1366
|
# Post failure to GitHub with more context
|
|
1243
1367
|
if [[ -n "$ISSUE_NUMBER" ]]; then
|
|
1244
1368
|
local log_lines
|
|
1245
|
-
log_lines=$(wc -l < "$test_log" 2>/dev/null ||
|
|
1369
|
+
log_lines=$(wc -l < "$test_log" 2>/dev/null || true)
|
|
1370
|
+
log_lines="${log_lines:-0}"
|
|
1246
1371
|
local log_excerpt
|
|
1247
1372
|
if [[ "$log_lines" -lt 60 ]]; then
|
|
1248
1373
|
log_excerpt="$(cat "$test_log" 2>/dev/null || true)"
|
|
@@ -1383,6 +1508,7 @@ If no issues are found, write: \"Review clean — no issues found.\"
|
|
|
1383
1508
|
if type intelligence_search_memory >/dev/null 2>&1; then
|
|
1384
1509
|
local review_memory
|
|
1385
1510
|
review_memory=$(intelligence_search_memory "code review findings anti-patterns for: ${GOAL:-}" "${HOME}/.shipwright/memory" 5 2>/dev/null) || true
|
|
1511
|
+
review_memory=$(prune_context_section "memory" "$review_memory" 10000)
|
|
1386
1512
|
if [[ -n "$review_memory" ]]; then
|
|
1387
1513
|
review_prompt+="
|
|
1388
1514
|
## Known Issues from Previous Reviews
|
|
@@ -1430,6 +1556,9 @@ $(cat "$dod_file")
|
|
|
1430
1556
|
## Diff to Review
|
|
1431
1557
|
$(cat "$diff_file")"
|
|
1432
1558
|
|
|
1559
|
+
# Guard total prompt size
|
|
1560
|
+
review_prompt=$(guard_prompt_size "review" "$review_prompt")
|
|
1561
|
+
|
|
1433
1562
|
# Skip permissions — pipeline runs headlessly (claude -p) and has no terminal
|
|
1434
1563
|
# for interactive permission prompts. Same rationale as build stage (line ~1083).
|
|
1435
1564
|
local review_args=(--print --model "$review_model" --max-turns 25 --dangerously-skip-permissions)
|
|
@@ -1837,7 +1966,8 @@ stage_pr() {
|
|
|
1837
1966
|
real_changes=$(_safe_base_diff --name-only \
|
|
1838
1967
|
-- . ':!.claude/loop-state.md' ':!.claude/pipeline-state.md' \
|
|
1839
1968
|
':!.claude/pipeline-artifacts/*' ':!**/progress.md' \
|
|
1840
|
-
':!**/error-summary.json' | wc -l | xargs ||
|
|
1969
|
+
':!**/error-summary.json' | wc -l | xargs || true)
|
|
1970
|
+
real_changes="${real_changes:-0}"
|
|
1841
1971
|
if [[ "${real_changes:-0}" -eq 0 ]]; then
|
|
1842
1972
|
error "No meaningful code changes detected — only bookkeeping files modified"
|
|
1843
1973
|
error "Refusing to create PR with zero real changes"
|
package/scripts/sw
CHANGED
package/scripts/sw-activity.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="3.
|
|
9
|
+
VERSION="3.2.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
|
@@ -332,7 +332,6 @@ cmd_stats() {
|
|
|
332
332
|
local end_time=""
|
|
333
333
|
|
|
334
334
|
# Read directly to avoid subshell issues
|
|
335
|
-
echo "DEBUG: Starting read loop..." >&2
|
|
336
335
|
while IFS= read -r line; do
|
|
337
336
|
[ -z "$line" ] && continue
|
|
338
337
|
|
|
@@ -363,14 +362,9 @@ cmd_stats() {
|
|
|
363
362
|
end_time="$ts"
|
|
364
363
|
done < <(grep -v '^$' "$EVENTS_FILE" 2>/dev/null)
|
|
365
364
|
|
|
366
|
-
echo "DEBUG: Read complete, total=$total_events" >&2
|
|
367
|
-
echo "DEBUG: agents_seen length: ${#agents_seen}" >&2
|
|
368
365
|
local unique_agents
|
|
369
|
-
echo "DEBUG: About to compute unique..." >&2
|
|
370
366
|
unique_agents=$(sort -u <<< "$agents_seen" | grep -v '^$' | wc -l | tr -d ' ')
|
|
371
|
-
echo "DEBUG: unique_agents=$unique_agents" >&2
|
|
372
367
|
|
|
373
|
-
echo "DEBUG: About to print results..." >&2
|
|
374
368
|
printf "${BOLD}Total Events:${RESET} %d\n" "$total_events"
|
|
375
369
|
printf "${BOLD}Commits:${RESET} %d\n" "$commits"
|
|
376
370
|
printf "${BOLD}Tests:${RESET} %d\n" "$tests"
|
package/scripts/sw-adaptive.sh
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# ╔═══════════════════════════════════════════════════════════════════════════╗
|
|
3
3
|
# ║ shipwright adaptive — data-driven pipeline tuning ║
|
|
4
|
-
# ║ Replace
|
|
4
|
+
# ║ Replace static defaults with learned values from historical runs ║
|
|
5
5
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="3.
|
|
9
|
+
VERSION="3.2.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
|
@@ -712,10 +712,10 @@ cmd_compare() {
|
|
|
712
712
|
esac
|
|
713
713
|
done
|
|
714
714
|
|
|
715
|
-
info "Learned vs
|
|
715
|
+
info "Learned vs Default Values for ${CYAN}${repo}${RESET}"
|
|
716
716
|
echo ""
|
|
717
717
|
|
|
718
|
-
printf "%-25s %-15s %-15s %-15s\n" "Metric" "
|
|
718
|
+
printf "%-25s %-15s %-15s %-15s\n" "Metric" "Default" "Learned" "Difference"
|
|
719
719
|
printf "%s\n" "$(printf '%.0s─' {1..70})"
|
|
720
720
|
|
|
721
721
|
# Timeout
|
|
@@ -841,7 +841,7 @@ ${BOLD}USAGE${RESET}
|
|
|
841
841
|
|
|
842
842
|
${BOLD}SUBCOMMANDS${RESET}
|
|
843
843
|
${CYAN}get${RESET} <metric> [--stage S] [--repo R] [--complexity C] [--default V]
|
|
844
|
-
Return adaptive value for a metric (replaces
|
|
844
|
+
Return adaptive value for a metric (replaces static defaults)
|
|
845
845
|
Metrics: timeout, iterations, model, team_size, template, poll_interval,
|
|
846
846
|
retry_limit, quality_threshold, coverage_min
|
|
847
847
|
|
|
@@ -852,7 +852,7 @@ ${BOLD}SUBCOMMANDS${RESET}
|
|
|
852
852
|
Rebuild models from events.jsonl (run after significant pipeline activity)
|
|
853
853
|
|
|
854
854
|
${CYAN}compare${RESET} [--repo REPO]
|
|
855
|
-
Side-by-side table: learned vs
|
|
855
|
+
Side-by-side table: learned vs default values
|
|
856
856
|
|
|
857
857
|
${CYAN}recommend${RESET} --issue N [--repo REPO]
|
|
858
858
|
Full JSON recommendation for an issue (template, model, team_size, etc.)
|
|
@@ -876,7 +876,7 @@ ${BOLD}EXAMPLES${RESET}
|
|
|
876
876
|
# Get complete recommendation for issue #42
|
|
877
877
|
sw adaptive recommend --issue 42
|
|
878
878
|
|
|
879
|
-
# Compare learned vs
|
|
879
|
+
# Compare learned vs defaults
|
|
880
880
|
sw adaptive compare
|
|
881
881
|
|
|
882
882
|
${BOLD}STORAGE${RESET}
|
package/scripts/sw-auth.sh
CHANGED
package/scripts/sw-autonomous.sh
CHANGED
package/scripts/sw-changelog.sh
CHANGED
package/scripts/sw-checkpoint.sh
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
set -euo pipefail
|
|
9
9
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
10
10
|
|
|
11
|
-
VERSION="3.
|
|
11
|
+
VERSION="3.2.0"
|
|
12
12
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
|
|
13
13
|
|
|
14
14
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
package/scripts/sw-ci.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="3.
|
|
9
|
+
VERSION="3.2.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -227,15 +227,20 @@ cmd_analyze() {
|
|
|
227
227
|
info "Analyzing workflow efficiency"
|
|
228
228
|
|
|
229
229
|
local job_count step_count matrix_enabled
|
|
230
|
-
job_count=$(grep -c "^ [a-z_-]*:" "$workflow_file" 2>/dev/null ||
|
|
231
|
-
|
|
232
|
-
|
|
230
|
+
job_count=$(grep -c "^ [a-z_-]*:" "$workflow_file" 2>/dev/null || true)
|
|
231
|
+
job_count="${job_count:-0}"
|
|
232
|
+
step_count=$(grep -c " - name:" "$workflow_file" 2>/dev/null || true)
|
|
233
|
+
step_count="${step_count:-0}"
|
|
234
|
+
matrix_enabled=$(grep -c "matrix:" "$workflow_file" 2>/dev/null || true)
|
|
235
|
+
matrix_enabled="${matrix_enabled:-0}"
|
|
233
236
|
|
|
234
237
|
local has_cache
|
|
235
|
-
has_cache=$(grep -c "actions/cache" "$workflow_file" 2>/dev/null ||
|
|
238
|
+
has_cache=$(grep -c "actions/cache" "$workflow_file" 2>/dev/null || true)
|
|
239
|
+
has_cache="${has_cache:-0}"
|
|
236
240
|
|
|
237
241
|
local has_timeout
|
|
238
|
-
has_timeout=$(grep -c "timeout-minutes:" "$workflow_file" 2>/dev/null ||
|
|
242
|
+
has_timeout=$(grep -c "timeout-minutes:" "$workflow_file" 2>/dev/null || true)
|
|
243
|
+
has_timeout="${has_timeout:-0}"
|
|
239
244
|
|
|
240
245
|
echo ""
|
|
241
246
|
echo -e "${BOLD}Workflow Analysis: $(basename "$workflow_file")${RESET}"
|
package/scripts/sw-cleanup.sh
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# ║ Default: dry-run (shows what would be cleaned). ║
|
|
6
6
|
# ║ Use --force to actually kill sessions and remove files. ║
|
|
7
7
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
8
|
-
VERSION="3.
|
|
8
|
+
VERSION="3.2.0"
|
|
9
9
|
set -euo pipefail
|
|
10
10
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
11
11
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="3.
|
|
9
|
+
VERSION="3.2.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -72,7 +72,8 @@ detect_code_smells() {
|
|
|
72
72
|
|
|
73
73
|
# Check 1: Long functions (>60 lines in bash)
|
|
74
74
|
local func_count
|
|
75
|
-
func_count=$(grep -c "^[a-zA-Z_][a-zA-Z0-9_]*().*{" "$target_file" 2>/dev/null ||
|
|
75
|
+
func_count=$(grep -c "^[a-zA-Z_][a-zA-Z0-9_]*().*{" "$target_file" 2>/dev/null || true)
|
|
76
|
+
func_count="${func_count:-0}"
|
|
76
77
|
if [[ "$func_count" -gt 0 ]]; then
|
|
77
78
|
while IFS= read -r line; do
|
|
78
79
|
if [[ "$line" =~ ^[a-zA-Z_][a-zA-Z0-9_]*\(\).*\{ ]]; then
|
|
@@ -106,7 +107,8 @@ detect_code_smells() {
|
|
|
106
107
|
|
|
107
108
|
# Check 3: Duplicate code patterns (repeated >3 times)
|
|
108
109
|
local dup_count=0
|
|
109
|
-
dup_count=$(grep -c '^\s*\(cd\|cd\|mkdir\|rm\|echo\)' "$target_file" 2>/dev/null ||
|
|
110
|
+
dup_count=$(grep -c '^\s*\(cd\|cd\|mkdir\|rm\|echo\)' "$target_file" 2>/dev/null || true)
|
|
111
|
+
dup_count="${dup_count:-0}"
|
|
110
112
|
if [[ $dup_count -gt 3 ]]; then
|
|
111
113
|
issues+=("REPEATED_PATTERNS: Common operations appear $dup_count times (consider helper functions)")
|
|
112
114
|
fi
|
|
@@ -139,7 +141,8 @@ check_solid_principles() {
|
|
|
139
141
|
|
|
140
142
|
# Single Responsibility: Check if scripts do multiple unrelated things
|
|
141
143
|
local sourced_count
|
|
142
|
-
sourced_count=$(grep -c '^\s*source\|^\s*\.\s' "$target_file" 2>/dev/null ||
|
|
144
|
+
sourced_count=$(grep -c '^\s*source\|^\s*\.\s' "$target_file" 2>/dev/null || true)
|
|
145
|
+
sourced_count="${sourced_count:-0}"
|
|
143
146
|
if [[ $sourced_count -gt 3 ]]; then
|
|
144
147
|
violations+=("SRP_VIOLATION: Script sources $sourced_count modules (too many responsibilities)")
|
|
145
148
|
fi
|
|
@@ -159,7 +162,8 @@ check_solid_principles() {
|
|
|
159
162
|
if [[ "$line" =~ ^[a-zA-Z_][a-zA-Z0-9_]*\(\) ]]; then
|
|
160
163
|
local func_name="${line%%(*}"
|
|
161
164
|
local body
|
|
162
|
-
body=$(awk "/^${func_name}\\(\\)/,/^}/" "$target_file" | grep -c '\$[0-9]' ||
|
|
165
|
+
body=$(awk "/^${func_name}\\(\\)/,/^}/" "$target_file" | grep -c '\$[0-9]' || true)
|
|
166
|
+
body="${body:-0}"
|
|
163
167
|
if [[ $body -gt 5 ]]; then
|
|
164
168
|
violations+=("ISP_VIOLATION: Function $func_name uses >5 parameters")
|
|
165
169
|
fi
|
|
@@ -227,7 +231,9 @@ analyze_complexity() {
|
|
|
227
231
|
|
|
228
232
|
# Cyclomatic complexity: count decision points (if, elif, case, &&, ||)
|
|
229
233
|
local cc=1
|
|
230
|
-
|
|
234
|
+
local _cc_count
|
|
235
|
+
_cc_count=$(sed -n "${start_line},${end_line}p" "$target_file" | grep -cE '\s(if|elif|case|&&|\|\|)' || true)
|
|
236
|
+
cc=$((cc + ${_cc_count:-0}))
|
|
231
237
|
|
|
232
238
|
# Lines of code
|
|
233
239
|
local loc=$((end_line - start_line))
|
|
@@ -266,8 +272,12 @@ check_style_consistency() {
|
|
|
266
272
|
local has_trap=false
|
|
267
273
|
local has_set_e=false
|
|
268
274
|
|
|
269
|
-
|
|
270
|
-
|
|
275
|
+
local _trap_count
|
|
276
|
+
_trap_count=$(grep -c 'trap.*ERR' "$target_file" 2>/dev/null || true)
|
|
277
|
+
[[ "${_trap_count:-0}" -gt 0 ]] && has_trap=true
|
|
278
|
+
local _set_e_count
|
|
279
|
+
_set_e_count=$(grep -c 'set -e' "$target_file" 2>/dev/null || true)
|
|
280
|
+
[[ "${_set_e_count:-0}" -gt 0 ]] && has_set_e=true
|
|
271
281
|
|
|
272
282
|
if [[ "$has_set_e" == "true" ]] && [[ "$has_trap" == "false" ]]; then
|
|
273
283
|
issues+=("STYLE: Missing ERR trap despite 'set -e' (inconsistent error handling)")
|
|
@@ -276,8 +286,10 @@ check_style_consistency() {
|
|
|
276
286
|
# Check for inconsistent quote usage
|
|
277
287
|
local single_quotes
|
|
278
288
|
local double_quotes
|
|
279
|
-
single_quotes=$(grep -o "'" "$target_file" 2>/dev/null | wc -l ||
|
|
280
|
-
|
|
289
|
+
single_quotes=$(grep -o "'" "$target_file" 2>/dev/null | wc -l || true)
|
|
290
|
+
single_quotes="${single_quotes:-0}"
|
|
291
|
+
double_quotes=$(grep -o '"' "$target_file" 2>/dev/null | wc -l || true)
|
|
292
|
+
double_quotes="${double_quotes:-0}"
|
|
281
293
|
if [[ $single_quotes -gt $((double_quotes * 3)) ]] || [[ $double_quotes -gt $((single_quotes * 3)) ]]; then
|
|
282
294
|
issues+=("STYLE: Inconsistent quote style (mix of single and double quotes)")
|
|
283
295
|
fi
|
|
@@ -285,8 +297,10 @@ check_style_consistency() {
|
|
|
285
297
|
# Check for inconsistent spacing/indentation
|
|
286
298
|
local tab_count
|
|
287
299
|
local space_count
|
|
288
|
-
tab_count=$(grep -c $'^\t' "$target_file" 2>/dev/null ||
|
|
289
|
-
|
|
300
|
+
tab_count=$(grep -c $'^\t' "$target_file" 2>/dev/null || true)
|
|
301
|
+
tab_count="${tab_count:-0}"
|
|
302
|
+
space_count=$(grep -c '^ ' "$target_file" 2>/dev/null || true)
|
|
303
|
+
space_count="${space_count:-0}"
|
|
290
304
|
if [[ $tab_count -gt 0 ]] && [[ $space_count -gt 0 ]]; then
|
|
291
305
|
issues+=("STYLE: Mixed tabs and spaces")
|
|
292
306
|
fi
|
|
@@ -333,7 +347,8 @@ auto_fix() {
|
|
|
333
347
|
|
|
334
348
|
# Fix 2: Trailing whitespace
|
|
335
349
|
local trailing_ws
|
|
336
|
-
trailing_ws=$(grep -c '[[:space:]]$' "$target_file" 2>/dev/null ||
|
|
350
|
+
trailing_ws=$(grep -c '[[:space:]]$' "$target_file" 2>/dev/null || true)
|
|
351
|
+
trailing_ws="${trailing_ws:-0}"
|
|
337
352
|
if [[ $trailing_ws -gt 0 ]]; then
|
|
338
353
|
sed -i '' 's/[[:space:]]*$//' "$target_file"
|
|
339
354
|
info "Removed $trailing_ws lines of trailing whitespace"
|
|
@@ -349,7 +364,8 @@ auto_fix() {
|
|
|
349
364
|
|
|
350
365
|
# Fix 4: Consistent spacing around operators (simple cases)
|
|
351
366
|
local spacing_fixes=0
|
|
352
|
-
spacing_fixes=$(grep -c '==' "$target_file" 2>/dev/null ||
|
|
367
|
+
spacing_fixes=$(grep -c '==' "$target_file" 2>/dev/null || true)
|
|
368
|
+
spacing_fixes="${spacing_fixes:-0}"
|
|
353
369
|
if [[ $spacing_fixes -gt 0 ]]; then
|
|
354
370
|
info "Flagged $spacing_fixes operator spacing cases (manual review recommended)"
|
|
355
371
|
fi
|
|
@@ -507,9 +523,12 @@ scan_codebase() {
|
|
|
507
523
|
local solids=0
|
|
508
524
|
local arch_issues=0
|
|
509
525
|
|
|
510
|
-
smells=$(detect_code_smells "$file" 2>/dev/null | wc -l ||
|
|
511
|
-
|
|
512
|
-
|
|
526
|
+
smells=$(detect_code_smells "$file" 2>/dev/null | wc -l || true)
|
|
527
|
+
smells="${smells:-0}"
|
|
528
|
+
solids=$(check_solid_principles "$file" 2>/dev/null | wc -l || true)
|
|
529
|
+
solids="${solids:-0}"
|
|
530
|
+
arch_issues=$(check_architecture_boundaries "$file" 2>/dev/null | wc -l || true)
|
|
531
|
+
arch_issues="${arch_issues:-0}"
|
|
513
532
|
|
|
514
533
|
local file_issues=$((smells + solids + arch_issues))
|
|
515
534
|
total_issues=$((total_issues + file_issues))
|
package/scripts/sw-connect.sh
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
set -euo pipefail
|
|
9
9
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
10
10
|
|
|
11
|
-
VERSION="3.
|
|
11
|
+
VERSION="3.2.0"
|
|
12
12
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
13
|
|
|
14
14
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
package/scripts/sw-context.sh
CHANGED