shipwright-cli 1.9.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/.claude/hooks/post-tool-use.sh +12 -5
- 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 +217 -2
- 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 +79 -1
- package/scripts/sw-ci.sh +602 -0
- package/scripts/sw-cleanup.sh +192 -7
- 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 +812 -138
- 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 +366 -31
- package/scripts/sw-linear.sh +1 -1
- package/scripts/sw-logs.sh +1 -1
- package/scripts/sw-loop.sh +507 -51
- package/scripts/sw-memory.sh +198 -3
- 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 +8 -8
- package/scripts/sw-pipeline-vitals.sh +1096 -0
- package/scripts/sw-pipeline.sh +2451 -180
- 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 +4 -3
- package/scripts/sw-public-dashboard.sh +798 -0
- package/scripts/sw-quality.sh +595 -0
- package/scripts/sw-reaper.sh +5 -3
- 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 +109 -8
- package/scripts/sw-session.sh +31 -9
- package/scripts/sw-setup.sh +1 -1
- package/scripts/sw-standup.sh +712 -0
- package/scripts/sw-status.sh +192 -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
- package/templates/pipelines/autonomous.json +8 -1
- package/templates/pipelines/cost-aware.json +21 -0
- package/templates/pipelines/deployed.json +40 -6
- package/templates/pipelines/enterprise.json +16 -2
- package/templates/pipelines/fast.json +19 -0
- package/templates/pipelines/full.json +16 -2
- package/templates/pipelines/hotfix.json +19 -0
- package/templates/pipelines/standard.json +19 -0
package/scripts/sw-memory.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="
|
|
9
|
+
VERSION="2.0.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
12
|
|
|
@@ -218,7 +218,7 @@ memory_capture_failure() {
|
|
|
218
218
|
|
|
219
219
|
(
|
|
220
220
|
if command -v flock &>/dev/null; then
|
|
221
|
-
flock -w 10 200 2>/dev/null || { warn "Memory lock timeout"; }
|
|
221
|
+
flock -w 10 200 2>/dev/null || { warn "Memory lock timeout"; return 1; }
|
|
222
222
|
fi
|
|
223
223
|
local tmp_file
|
|
224
224
|
tmp_file=$(mktemp "${failures_file}.tmp.XXXXXX")
|
|
@@ -284,7 +284,7 @@ memory_record_fix_outcome() {
|
|
|
284
284
|
|
|
285
285
|
(
|
|
286
286
|
if command -v flock &>/dev/null; then
|
|
287
|
-
flock -w 10 200 2>/dev/null || { warn "Memory lock timeout"; }
|
|
287
|
+
flock -w 10 200 2>/dev/null || { warn "Memory lock timeout"; return 1; }
|
|
288
288
|
fi
|
|
289
289
|
local tmp_file
|
|
290
290
|
tmp_file=$(mktemp "${failures_file}.tmp.XXXXXX")
|
|
@@ -312,6 +312,178 @@ memory_record_fix_outcome() {
|
|
|
312
312
|
"resolved=${fix_resolved}"
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
+
# memory_track_fix <error_sig> <success_bool>
|
|
316
|
+
# Convenience wrapper for memory_record_fix_outcome
|
|
317
|
+
memory_track_fix() {
|
|
318
|
+
local error_sig="${1:-}"
|
|
319
|
+
local success="${2:-false}"
|
|
320
|
+
[[ -z "$error_sig" ]] && return 0
|
|
321
|
+
memory_record_fix_outcome "$error_sig" "true" "$success" 2>/dev/null || true
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
# memory_query_fix_for_error <error_pattern>
|
|
325
|
+
# Searches failure memory for known fixes matching the given error pattern.
|
|
326
|
+
# Returns JSON with the best fix (highest effectiveness rate) or empty.
|
|
327
|
+
memory_query_fix_for_error() {
|
|
328
|
+
local error_pattern="$1"
|
|
329
|
+
[[ -z "$error_pattern" ]] && return 0
|
|
330
|
+
|
|
331
|
+
ensure_memory_dir
|
|
332
|
+
local mem_dir
|
|
333
|
+
mem_dir="$(repo_memory_dir)"
|
|
334
|
+
local failures_file="$mem_dir/failures.json"
|
|
335
|
+
|
|
336
|
+
[[ ! -f "$failures_file" ]] && return 0
|
|
337
|
+
|
|
338
|
+
# Search for matching failures with successful fixes
|
|
339
|
+
local matches
|
|
340
|
+
matches=$(jq -r --arg pat "$error_pattern" '
|
|
341
|
+
[.failures[]
|
|
342
|
+
| select(.pattern != null and .pattern != "")
|
|
343
|
+
| select(.pattern | test($pat; "i") // false)
|
|
344
|
+
| select(.fix != null and .fix != "")
|
|
345
|
+
| select((.fix_effectiveness_rate // 0) > 30)
|
|
346
|
+
| {fix, fix_effectiveness_rate, seen_count, category, stage, pattern}]
|
|
347
|
+
| sort_by(-.fix_effectiveness_rate)
|
|
348
|
+
| .[0] // null
|
|
349
|
+
' "$failures_file" 2>/dev/null) || true
|
|
350
|
+
|
|
351
|
+
if [[ -n "$matches" && "$matches" != "null" ]]; then
|
|
352
|
+
echo "$matches"
|
|
353
|
+
fi
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
# memory_closed_loop_inject <error_sig>
|
|
357
|
+
# Combines error → memory → fix into injectable text for build retries.
|
|
358
|
+
# Returns a one-line summary suitable for goal augmentation.
|
|
359
|
+
memory_closed_loop_inject() {
|
|
360
|
+
local error_sig="$1"
|
|
361
|
+
[[ -z "$error_sig" ]] && return 0
|
|
362
|
+
|
|
363
|
+
local fix_json
|
|
364
|
+
fix_json=$(memory_query_fix_for_error "$error_sig") || true
|
|
365
|
+
[[ -z "$fix_json" || "$fix_json" == "null" ]] && return 0
|
|
366
|
+
|
|
367
|
+
local fix_text success_rate category
|
|
368
|
+
fix_text=$(echo "$fix_json" | jq -r '.fix // ""')
|
|
369
|
+
success_rate=$(echo "$fix_json" | jq -r '.fix_effectiveness_rate // 0')
|
|
370
|
+
category=$(echo "$fix_json" | jq -r '.category // "unknown"')
|
|
371
|
+
|
|
372
|
+
[[ -z "$fix_text" ]] && return 0
|
|
373
|
+
|
|
374
|
+
echo "[$category, ${success_rate}% success rate] $fix_text"
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
memory_capture_failure_from_log() {
|
|
378
|
+
local artifacts_dir="${1:-}"
|
|
379
|
+
local error_log="${artifacts_dir}/error-log.jsonl"
|
|
380
|
+
[[ ! -f "$error_log" ]] && return 0
|
|
381
|
+
|
|
382
|
+
ensure_memory_dir
|
|
383
|
+
local mem_dir
|
|
384
|
+
mem_dir="$(repo_memory_dir)"
|
|
385
|
+
local failures_file="$mem_dir/failures.json"
|
|
386
|
+
|
|
387
|
+
# Read last 50 entries
|
|
388
|
+
local entries
|
|
389
|
+
entries=$(tail -50 "$error_log" 2>/dev/null) || return 0
|
|
390
|
+
[[ -z "$entries" ]] && return 0
|
|
391
|
+
|
|
392
|
+
local captured=0
|
|
393
|
+
while IFS= read -r line; do
|
|
394
|
+
[[ -z "$line" ]] && continue
|
|
395
|
+
|
|
396
|
+
local err_type err_text
|
|
397
|
+
err_type=$(echo "$line" | jq -r '.type // "unknown"' 2>/dev/null) || continue
|
|
398
|
+
err_text=$(echo "$line" | jq -r '.error // ""' 2>/dev/null) || continue
|
|
399
|
+
[[ -z "$err_text" ]] && continue
|
|
400
|
+
|
|
401
|
+
# Deduplicate: skip if this exact pattern already exists in failures
|
|
402
|
+
local pattern_short
|
|
403
|
+
pattern_short=$(echo "$err_text" | head -1 | cut -c1-200)
|
|
404
|
+
local already_exists
|
|
405
|
+
already_exists=$(jq --arg pat "$pattern_short" \
|
|
406
|
+
'[.failures[] | select(.pattern == $pat)] | length' \
|
|
407
|
+
"$failures_file" 2>/dev/null || echo "0")
|
|
408
|
+
if [[ "${already_exists:-0}" -gt 0 ]]; then
|
|
409
|
+
continue
|
|
410
|
+
fi
|
|
411
|
+
|
|
412
|
+
# Feed into memory_capture_failure with the error type as stage
|
|
413
|
+
memory_capture_failure "$err_type" "$err_text" 2>/dev/null || true
|
|
414
|
+
captured=$((captured + 1))
|
|
415
|
+
done <<< "$entries"
|
|
416
|
+
|
|
417
|
+
if [[ "$captured" -gt 0 ]]; then
|
|
418
|
+
emit_event "memory.error_log_processed" "captured=$captured"
|
|
419
|
+
fi
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
# _memory_aggregate_global
|
|
423
|
+
# Promotes high-frequency failure patterns to global.json for cross-repo learning
|
|
424
|
+
_memory_aggregate_global() {
|
|
425
|
+
ensure_memory_dir
|
|
426
|
+
local mem_dir
|
|
427
|
+
mem_dir="$(repo_memory_dir)"
|
|
428
|
+
local failures_file="$mem_dir/failures.json"
|
|
429
|
+
[[ ! -f "$failures_file" ]] && return 0
|
|
430
|
+
|
|
431
|
+
local global_file="$GLOBAL_MEMORY"
|
|
432
|
+
[[ ! -f "$global_file" ]] && return 0
|
|
433
|
+
|
|
434
|
+
# Find patterns with seen_count >= 3
|
|
435
|
+
local frequent_patterns
|
|
436
|
+
frequent_patterns=$(jq -r '.failures[] | select(.seen_count >= 3) | .pattern' \
|
|
437
|
+
"$failures_file" 2>/dev/null) || return 0
|
|
438
|
+
[[ -z "$frequent_patterns" ]] && return 0
|
|
439
|
+
|
|
440
|
+
local promoted=0
|
|
441
|
+
while IFS= read -r pattern; do
|
|
442
|
+
[[ -z "$pattern" ]] && continue
|
|
443
|
+
|
|
444
|
+
# Check if already in global
|
|
445
|
+
local exists
|
|
446
|
+
exists=$(jq --arg p "$pattern" \
|
|
447
|
+
'[.common_patterns[] | select(.pattern == $p)] | length' \
|
|
448
|
+
"$global_file" 2>/dev/null || echo "0")
|
|
449
|
+
if [[ "${exists:-0}" -gt 0 ]]; then
|
|
450
|
+
continue
|
|
451
|
+
fi
|
|
452
|
+
|
|
453
|
+
# Add to global, cap at 100 entries
|
|
454
|
+
local tmp_global
|
|
455
|
+
tmp_global=$(mktemp "${global_file}.tmp.XXXXXX")
|
|
456
|
+
jq --arg p "$pattern" \
|
|
457
|
+
--arg ts "$(now_iso)" \
|
|
458
|
+
--arg cat "general" \
|
|
459
|
+
'.common_patterns += [{pattern: $p, promoted_at: $ts, category: $cat, source: "aggregate"}] |
|
|
460
|
+
.common_patterns = (.common_patterns | .[-100:])' \
|
|
461
|
+
"$global_file" > "$tmp_global" && mv "$tmp_global" "$global_file" || rm -f "$tmp_global"
|
|
462
|
+
promoted=$((promoted + 1))
|
|
463
|
+
done <<< "$frequent_patterns"
|
|
464
|
+
|
|
465
|
+
if [[ "$promoted" -gt 0 ]]; then
|
|
466
|
+
emit_event "memory.global_aggregated" "promoted=$promoted"
|
|
467
|
+
fi
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
# memory_finalize_pipeline <state_file> <artifacts_dir>
|
|
471
|
+
# Single call that closes multiple feedback loops at pipeline completion
|
|
472
|
+
memory_finalize_pipeline() {
|
|
473
|
+
local state_file="${1:-}"
|
|
474
|
+
local artifacts_dir="${2:-}"
|
|
475
|
+
[[ -z "$state_file" || ! -f "$state_file" ]] && return 0
|
|
476
|
+
|
|
477
|
+
# Step 1: Capture pipeline-level learnings
|
|
478
|
+
memory_capture_pipeline "$state_file" "$artifacts_dir" 2>/dev/null || true
|
|
479
|
+
|
|
480
|
+
# Step 2: Process error log into failures.json
|
|
481
|
+
memory_capture_failure_from_log "$artifacts_dir" 2>/dev/null || true
|
|
482
|
+
|
|
483
|
+
# Step 3: Aggregate high-frequency patterns to global memory
|
|
484
|
+
_memory_aggregate_global 2>/dev/null || true
|
|
485
|
+
}
|
|
486
|
+
|
|
315
487
|
# memory_analyze_failure <log_file> <stage>
|
|
316
488
|
# Uses Claude to analyze a pipeline failure and fill in root_cause/fix/category.
|
|
317
489
|
memory_analyze_failure() {
|
|
@@ -793,6 +965,29 @@ memory_inject_context() {
|
|
|
793
965
|
;;
|
|
794
966
|
esac
|
|
795
967
|
|
|
968
|
+
# ── Cross-repo memory injection (global learnings) ──
|
|
969
|
+
if [[ -f "$GLOBAL_MEMORY" ]]; then
|
|
970
|
+
local global_patterns
|
|
971
|
+
global_patterns=$(jq -r --arg stage "$stage_id" '
|
|
972
|
+
.common_patterns // [] | .[] |
|
|
973
|
+
select(.category == $stage or .category == "general" or .category == null) |
|
|
974
|
+
.summary // .description // empty
|
|
975
|
+
' "$GLOBAL_MEMORY" 2>/dev/null | head -5 || true)
|
|
976
|
+
|
|
977
|
+
local cross_repo_learnings
|
|
978
|
+
cross_repo_learnings=$(jq -r '
|
|
979
|
+
.cross_repo_learnings // [] | .[-5:][] |
|
|
980
|
+
"- [\(.repo // "unknown")] \(.type // "learning"): bugs=\(.bugs // 0), warnings=\(.warnings // 0)"
|
|
981
|
+
' "$GLOBAL_MEMORY" 2>/dev/null | head -5 || true)
|
|
982
|
+
|
|
983
|
+
if [[ -n "$global_patterns" || -n "$cross_repo_learnings" ]]; then
|
|
984
|
+
echo ""
|
|
985
|
+
echo "## Cross-Repo Learnings (Global)"
|
|
986
|
+
[[ -n "$global_patterns" ]] && echo "$global_patterns"
|
|
987
|
+
[[ -n "$cross_repo_learnings" ]] && echo "$cross_repo_learnings"
|
|
988
|
+
fi
|
|
989
|
+
fi
|
|
990
|
+
|
|
796
991
|
echo ""
|
|
797
992
|
emit_event "memory.inject" "stage=${stage_id}"
|
|
798
993
|
}
|