shipwright-cli 2.3.1 → 2.4.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.
Files changed (102) hide show
  1. package/README.md +82 -20
  2. package/config/policy.json +160 -2
  3. package/config/policy.schema.json +162 -1
  4. package/package.json +14 -2
  5. package/scripts/sw +1 -1
  6. package/scripts/sw-activity.sh +1 -1
  7. package/scripts/sw-adaptive.sh +1 -1
  8. package/scripts/sw-adversarial.sh +1 -1
  9. package/scripts/sw-architecture-enforcer.sh +1 -1
  10. package/scripts/sw-auth.sh +1 -1
  11. package/scripts/sw-autonomous.sh +1 -1
  12. package/scripts/sw-changelog.sh +1 -1
  13. package/scripts/sw-checkpoint.sh +1 -1
  14. package/scripts/sw-ci.sh +1 -1
  15. package/scripts/sw-cleanup.sh +1 -1
  16. package/scripts/sw-code-review.sh +1 -1
  17. package/scripts/sw-connect.sh +1 -1
  18. package/scripts/sw-context.sh +1 -1
  19. package/scripts/sw-cost.sh +1 -1
  20. package/scripts/sw-daemon.sh +1 -1
  21. package/scripts/sw-dashboard.sh +1 -1
  22. package/scripts/sw-db.sh +1 -1
  23. package/scripts/sw-decompose.sh +1 -1
  24. package/scripts/sw-deps.sh +1 -1
  25. package/scripts/sw-developer-simulation.sh +1 -1
  26. package/scripts/sw-discovery.sh +1 -1
  27. package/scripts/sw-doc-fleet.sh +1 -1
  28. package/scripts/sw-docs-agent.sh +1 -1
  29. package/scripts/sw-docs.sh +1 -1
  30. package/scripts/sw-doctor.sh +1 -1
  31. package/scripts/sw-dora.sh +1 -1
  32. package/scripts/sw-durable.sh +1 -1
  33. package/scripts/sw-e2e-orchestrator.sh +1 -1
  34. package/scripts/sw-eventbus.sh +1 -1
  35. package/scripts/sw-evidence.sh +664 -0
  36. package/scripts/sw-feedback.sh +1 -1
  37. package/scripts/sw-fix.sh +1 -1
  38. package/scripts/sw-fleet-discover.sh +1 -1
  39. package/scripts/sw-fleet-viz.sh +1 -1
  40. package/scripts/sw-fleet.sh +1 -1
  41. package/scripts/sw-github-app.sh +1 -1
  42. package/scripts/sw-github-checks.sh +1 -1
  43. package/scripts/sw-github-deploy.sh +1 -1
  44. package/scripts/sw-github-graphql.sh +1 -1
  45. package/scripts/sw-guild.sh +1 -1
  46. package/scripts/sw-heartbeat.sh +1 -1
  47. package/scripts/sw-hygiene.sh +1 -1
  48. package/scripts/sw-incident.sh +244 -1
  49. package/scripts/sw-init.sh +1 -1
  50. package/scripts/sw-instrument.sh +1 -1
  51. package/scripts/sw-intelligence.sh +1 -1
  52. package/scripts/sw-jira.sh +1 -1
  53. package/scripts/sw-launchd.sh +1 -1
  54. package/scripts/sw-linear.sh +1 -1
  55. package/scripts/sw-logs.sh +1 -1
  56. package/scripts/sw-loop.sh +1 -1
  57. package/scripts/sw-memory.sh +1 -1
  58. package/scripts/sw-mission-control.sh +1 -1
  59. package/scripts/sw-model-router.sh +1 -1
  60. package/scripts/sw-otel.sh +1 -1
  61. package/scripts/sw-oversight.sh +1 -1
  62. package/scripts/sw-pipeline-composer.sh +1 -1
  63. package/scripts/sw-pipeline-vitals.sh +1 -1
  64. package/scripts/sw-pipeline.sh +1 -1
  65. package/scripts/sw-pm.sh +1 -1
  66. package/scripts/sw-pr-lifecycle.sh +177 -5
  67. package/scripts/sw-predictive.sh +1 -1
  68. package/scripts/sw-prep.sh +1 -1
  69. package/scripts/sw-ps.sh +1 -1
  70. package/scripts/sw-public-dashboard.sh +1 -1
  71. package/scripts/sw-quality.sh +1 -1
  72. package/scripts/sw-reaper.sh +1 -1
  73. package/scripts/sw-regression.sh +1 -1
  74. package/scripts/sw-release-manager.sh +1 -1
  75. package/scripts/sw-release.sh +1 -1
  76. package/scripts/sw-remote.sh +1 -1
  77. package/scripts/sw-replay.sh +1 -1
  78. package/scripts/sw-retro.sh +1 -1
  79. package/scripts/sw-review-rerun.sh +220 -0
  80. package/scripts/sw-scale.sh +1 -1
  81. package/scripts/sw-security-audit.sh +1 -1
  82. package/scripts/sw-self-optimize.sh +1 -1
  83. package/scripts/sw-session.sh +1 -1
  84. package/scripts/sw-setup.sh +1 -1
  85. package/scripts/sw-standup.sh +1 -1
  86. package/scripts/sw-status.sh +1 -1
  87. package/scripts/sw-strategic.sh +1 -1
  88. package/scripts/sw-stream.sh +1 -1
  89. package/scripts/sw-swarm.sh +1 -1
  90. package/scripts/sw-team-stages.sh +1 -1
  91. package/scripts/sw-templates.sh +1 -1
  92. package/scripts/sw-testgen.sh +1 -1
  93. package/scripts/sw-tmux-pipeline.sh +1 -1
  94. package/scripts/sw-tmux.sh +1 -1
  95. package/scripts/sw-trace.sh +1 -1
  96. package/scripts/sw-tracker.sh +1 -1
  97. package/scripts/sw-triage.sh +1 -1
  98. package/scripts/sw-upgrade.sh +1 -1
  99. package/scripts/sw-ux.sh +1 -1
  100. package/scripts/sw-webhook.sh +1 -1
  101. package/scripts/sw-widgets.sh +1 -1
  102. package/scripts/sw-worktree.sh +1 -1
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="${SCRIPT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
11
11
  REPO_DIR="${REPO_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
12
12
 
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Cross-platform compatibility ──────────────────────────────────────────
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -334,6 +334,9 @@ cmd_watch() {
334
334
  info "Incident $incident_id created (severity: $severity)"
335
335
  emit_event "incident.detected" "incident_id=$incident_id" "severity=$severity"
336
336
 
337
+ # Create harness gap for test case tracking (Code Factory pattern)
338
+ create_harness_gap "$incident_id" "$severity" "$root_cause" 2>/dev/null || true
339
+
337
340
  # Auto-response for P0/P1: hotfix issue, trigger pipeline, optional rollback
338
341
  if [[ "$severity" == "P0" ]] || [[ "$severity" == "P1" ]]; then
339
342
  local auto_rollback
@@ -556,6 +559,242 @@ cmd_stats() {
556
559
  esac
557
560
  }
558
561
 
562
+ # ─── Harness Gap Loop ─────────────────────────────────────────────────────
563
+ # Code Factory pattern: production regression → harness gap issue → test case
564
+ # added → SLA tracked. Every incident must produce a test case within SLA.
565
+
566
+ HARNESS_GAPS_DIR="${INCIDENTS_DIR}/harness-gaps"
567
+
568
+ load_harness_gap_policy() {
569
+ local policy="${REPO_DIR}/config/policy.json"
570
+ if [[ -f "$policy" ]]; then
571
+ HARNESS_GAP_ENABLED=$(jq -r '.harnessGapPolicy.enabled // false' "$policy" 2>/dev/null || echo "false")
572
+ HARNESS_GAP_P0_SLA=$(jq -r '.harnessGapPolicy.p0SlaHours // 24' "$policy" 2>/dev/null || echo "24")
573
+ HARNESS_GAP_P1_SLA=$(jq -r '.harnessGapPolicy.p1SlaHours // 72' "$policy" 2>/dev/null || echo "72")
574
+ HARNESS_GAP_P2_SLA=$(jq -r '.harnessGapPolicy.p2SlaHours // 168' "$policy" 2>/dev/null || echo "168")
575
+ HARNESS_GAP_AUTO_CREATE=$(jq -r '.harnessGapPolicy.autoCreateGapIssue // true' "$policy" 2>/dev/null || echo "true")
576
+ HARNESS_GAP_REQUIRE_TEST=$(jq -r '.harnessGapPolicy.requireTestCaseBeforeClose // true' "$policy" 2>/dev/null || echo "true")
577
+ else
578
+ HARNESS_GAP_ENABLED="false"
579
+ fi
580
+ }
581
+
582
+ create_harness_gap() {
583
+ local incident_id="$1"
584
+ local severity="$2"
585
+ local root_cause="$3"
586
+
587
+ mkdir -p "$HARNESS_GAPS_DIR"
588
+ load_harness_gap_policy
589
+
590
+ if [[ "$HARNESS_GAP_ENABLED" != "true" ]]; then
591
+ return 0
592
+ fi
593
+
594
+ local gap_id="gap-${incident_id}"
595
+ local gap_file="${HARNESS_GAPS_DIR}/${gap_id}.json"
596
+ local sla_hours
597
+
598
+ case "$severity" in
599
+ P0) sla_hours="$HARNESS_GAP_P0_SLA" ;;
600
+ P1) sla_hours="$HARNESS_GAP_P1_SLA" ;;
601
+ P2) sla_hours="$HARNESS_GAP_P2_SLA" ;;
602
+ *) sla_hours="$HARNESS_GAP_P2_SLA" ;;
603
+ esac
604
+
605
+ local created_at
606
+ created_at=$(now_iso)
607
+ local created_epoch
608
+ created_epoch=$(now_epoch)
609
+ local sla_deadline_epoch=$((created_epoch + sla_hours * 3600))
610
+
611
+ cat > "$gap_file" << EOF
612
+ {
613
+ "gap_id": "${gap_id}",
614
+ "incident_id": "${incident_id}",
615
+ "severity": "${severity}",
616
+ "root_cause": "${root_cause}",
617
+ "created_at": "${created_at}",
618
+ "created_epoch": ${created_epoch},
619
+ "sla_hours": ${sla_hours},
620
+ "sla_deadline_epoch": ${sla_deadline_epoch},
621
+ "status": "open",
622
+ "test_case_file": null,
623
+ "github_issue": null,
624
+ "resolved_at": null
625
+ }
626
+ EOF
627
+
628
+ info "Harness gap created: ${gap_id} (SLA: ${sla_hours}h)"
629
+ emit_event "harness_gap.created" "gap_id=${gap_id}" "incident=${incident_id}" "sla_hours=${sla_hours}"
630
+
631
+ # Auto-create GitHub issue for gap tracking
632
+ if [[ "$HARNESS_GAP_AUTO_CREATE" == "true" ]] && command -v gh &>/dev/null; then
633
+ local title="[HARNESS GAP] ${severity}: Add test case for ${root_cause}"
634
+ local body="## Harness Gap
635
+
636
+ **Incident:** \`${incident_id}\`
637
+ **Severity:** ${severity}
638
+ **Root Cause:** ${root_cause}
639
+ **SLA:** ${sla_hours} hours
640
+
641
+ ## Required Action
642
+ Add a regression test case that covers this failure scenario.
643
+
644
+ ## Acceptance Criteria
645
+ - [ ] Test case file created in \`scripts/\`
646
+ - [ ] Test reproduces the original failure condition
647
+ - [ ] Test passes after the fix is applied
648
+ - [ ] Gap record resolved via \`shipwright incident gap resolve ${gap_id} <test_file>\`
649
+
650
+ ## Context
651
+ This gap was automatically created by the Shipwright incident commander.
652
+ Part of the Code Factory harness-gap loop: every production regression
653
+ must produce a harness test case within the SLA window.
654
+
655
+ ---
656
+ *Auto-generated by Shipwright Code Factory*"
657
+
658
+ local issue_url
659
+ issue_url=$(gh issue create --title "$title" --body "$body" --label "harness-gap,shipwright" 2>/dev/null || echo "")
660
+ if [[ -n "$issue_url" ]]; then
661
+ local issue_num
662
+ issue_num=$(echo "$issue_url" | sed -n 's|.*/issues/\([0-9]*\)|\1|p')
663
+ jq --arg issue "$issue_num" '.github_issue = $issue' "$gap_file" > "${gap_file}.tmp" && mv "${gap_file}.tmp" "$gap_file"
664
+ success "Created harness gap issue: $issue_url"
665
+ fi
666
+ fi
667
+ }
668
+
669
+ resolve_harness_gap() {
670
+ local gap_id="$1"
671
+ local test_case_file="${2:-}"
672
+
673
+ local gap_file="${HARNESS_GAPS_DIR}/${gap_id}.json"
674
+ if [[ ! -f "$gap_file" ]]; then
675
+ error "Harness gap not found: ${gap_id}"
676
+ return 1
677
+ fi
678
+
679
+ load_harness_gap_policy
680
+
681
+ if [[ "$HARNESS_GAP_REQUIRE_TEST" == "true" && -z "$test_case_file" ]]; then
682
+ error "Test case file required to resolve gap (policy: requireTestCaseBeforeClose=true)"
683
+ echo "Usage: shipwright incident gap resolve ${gap_id} <test_case_file>"
684
+ return 1
685
+ fi
686
+
687
+ if [[ -n "$test_case_file" && ! -f "$test_case_file" ]]; then
688
+ error "Test case file not found: ${test_case_file}"
689
+ return 1
690
+ fi
691
+
692
+ local resolved_at
693
+ resolved_at=$(now_iso)
694
+ jq --arg resolved_at "$resolved_at" --arg test_file "${test_case_file:-null}" \
695
+ '.status = "resolved" | .resolved_at = $resolved_at | .test_case_file = $test_file' \
696
+ "$gap_file" > "${gap_file}.tmp" && mv "${gap_file}.tmp" "$gap_file"
697
+
698
+ success "Harness gap resolved: ${gap_id}"
699
+ emit_event "harness_gap.resolved" "gap_id=${gap_id}" "test_file=${test_case_file:-none}"
700
+
701
+ # Close the GitHub issue if it exists
702
+ local github_issue
703
+ github_issue=$(jq -r '.github_issue // empty' "$gap_file" 2>/dev/null)
704
+ if [[ -n "$github_issue" ]] && command -v gh &>/dev/null; then
705
+ gh issue close "$github_issue" --comment "Harness gap resolved. Test case: \`${test_case_file:-none}\`" 2>/dev/null || true
706
+ fi
707
+ }
708
+
709
+ cmd_gap() {
710
+ local subcmd="${1:-list}"
711
+ shift || true
712
+
713
+ mkdir -p "$HARNESS_GAPS_DIR"
714
+
715
+ case "$subcmd" in
716
+ create)
717
+ create_harness_gap "$@"
718
+ ;;
719
+ resolve)
720
+ resolve_harness_gap "$@"
721
+ ;;
722
+ list)
723
+ local current_epoch
724
+ current_epoch=$(now_epoch)
725
+ echo -e "${BOLD}Harness Gaps${RESET}"
726
+ echo -e "${DIM}────────────────────────────────────────────────────────────────${RESET}"
727
+
728
+ local gap_files
729
+ gap_files=$(find "$HARNESS_GAPS_DIR" -name 'gap-*.json' -type f 2>/dev/null || true)
730
+
731
+ if [[ -z "$gap_files" ]]; then
732
+ info "No harness gaps recorded"
733
+ return 0
734
+ fi
735
+
736
+ while IFS= read -r gf; do
737
+ [[ -z "$gf" ]] && continue
738
+ local gid sev status sla_deadline
739
+ gid=$(jq -r '.gap_id // "unknown"' "$gf" 2>/dev/null)
740
+ sev=$(jq -r '.severity // "P3"' "$gf" 2>/dev/null)
741
+ status=$(jq -r '.status // "open"' "$gf" 2>/dev/null)
742
+ sla_deadline=$(jq -r '.sla_deadline_epoch // 0' "$gf" 2>/dev/null)
743
+
744
+ local sla_remaining=""
745
+ if [[ "$status" == "open" ]]; then
746
+ local remaining=$((sla_deadline - current_epoch))
747
+ if [[ "$remaining" -lt 0 ]]; then
748
+ sla_remaining="${RED}OVERDUE${RESET}"
749
+ else
750
+ sla_remaining="$(format_duration "$remaining") remaining"
751
+ fi
752
+ else
753
+ sla_remaining="${GREEN}resolved${RESET}"
754
+ fi
755
+
756
+ printf " %-20s %-4s %-8s %b\n" "$gid" "$sev" "$status" "$sla_remaining"
757
+ done <<< "$gap_files"
758
+ ;;
759
+ sla)
760
+ # Show SLA compliance metrics
761
+ load_harness_gap_policy
762
+ local current_epoch
763
+ current_epoch=$(now_epoch)
764
+ local total=0 resolved=0 overdue=0 within_sla=0
765
+
766
+ local gap_files
767
+ gap_files=$(find "$HARNESS_GAPS_DIR" -name 'gap-*.json' -type f 2>/dev/null || true)
768
+
769
+ while IFS= read -r gf; do
770
+ [[ -z "$gf" ]] && continue
771
+ ((total++))
772
+ local status sla_deadline
773
+ status=$(jq -r '.status // "open"' "$gf" 2>/dev/null)
774
+ sla_deadline=$(jq -r '.sla_deadline_epoch // 0' "$gf" 2>/dev/null)
775
+
776
+ if [[ "$status" == "resolved" ]]; then
777
+ ((resolved++))
778
+ ((within_sla++))
779
+ elif [[ "$current_epoch" -gt "$sla_deadline" ]]; then
780
+ ((overdue++))
781
+ fi
782
+ done <<< "$gap_files"
783
+
784
+ echo -e "${BOLD}Harness Gap SLA Compliance${RESET}"
785
+ echo -e "${DIM}────────────────────────────────────────────────────────────────${RESET}"
786
+ echo "Total gaps: $total"
787
+ echo "Resolved: $resolved"
788
+ echo "Overdue: $overdue"
789
+ echo "SLA compliance: $( [[ $total -gt 0 ]] && echo "$((within_sla * 100 / total))%" || echo "N/A" )"
790
+ ;;
791
+ *)
792
+ echo "Usage: shipwright incident gap <create|resolve|list|sla>"
793
+ return 1
794
+ ;;
795
+ esac
796
+ }
797
+
559
798
  # ─── Stop Command ──────────────────────────────────────────────────────────
560
799
 
561
800
  cmd_stop() {
@@ -589,6 +828,7 @@ show_help() {
589
828
  echo -e " ${CYAN}show${RESET} <incident-id> Show details for an incident"
590
829
  echo -e " ${CYAN}report${RESET} <incident-id> Generate post-mortem report"
591
830
  echo -e " ${CYAN}stats${RESET} [format] Show incident statistics (table|json)"
831
+ echo -e " ${CYAN}gap${RESET} <cmd> Harness gap loop (list|create|resolve|sla)"
592
832
  echo -e " ${CYAN}config${RESET} <cmd> Configure incident response (show|set)"
593
833
  echo -e " ${CYAN}help${RESET} Show this help"
594
834
  echo ""
@@ -627,6 +867,9 @@ main() {
627
867
  stats)
628
868
  cmd_stats "$@"
629
869
  ;;
870
+ gap)
871
+ cmd_gap "$@"
872
+ ;;
630
873
  config)
631
874
  error "config command not yet implemented"
632
875
  return 1
@@ -8,7 +8,7 @@
8
8
  # ║ ║
9
9
  # ║ --deploy Detect platform and generate deployed.json template ║
10
10
  # ╚═══════════════════════════════════════════════════════════════════════════╝
11
- VERSION="2.3.1"
11
+ VERSION="2.4.0"
12
12
  set -euo pipefail
13
13
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
14
14
  trap 'rm -f "${tmp:-}"' EXIT
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="${REPO_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
12
12
 
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -4,7 +4,7 @@
4
4
  # ║ ║
5
5
  # ║ Captures tmux pane scrollback and provides log browsing/search. ║
6
6
  # ╚═══════════════════════════════════════════════════════════════════════════╝
7
- VERSION="2.3.1"
7
+ VERSION="2.4.0"
8
8
  set -euo pipefail
9
9
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
10
10
 
@@ -71,7 +71,7 @@ MAX_RESTARTS=0
71
71
  SESSION_RESTART=false
72
72
  RESTART_COUNT=0
73
73
  REPO_OVERRIDE=""
74
- VERSION="2.3.1"
74
+ VERSION="2.4.0"
75
75
 
76
76
  # ─── Token Tracking ─────────────────────────────────────────────────────────
77
77
  LOOP_INPUT_TOKENS=0
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="${REPO_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
12
12
 
@@ -7,7 +7,7 @@
7
7
  set -euo pipefail
8
8
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
9
9
 
10
- VERSION="2.3.1"
10
+ VERSION="2.4.0"
11
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
12
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
13
13
 
@@ -7,7 +7,7 @@
7
7
  set -euo pipefail
8
8
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
9
9
 
10
- VERSION="2.3.1"
10
+ VERSION="2.4.0"
11
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
12
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
13
13
 
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -7,7 +7,7 @@
7
7
  set -euo pipefail
8
8
  trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
9
9
 
10
- VERSION="2.3.1"
10
+ VERSION="2.4.0"
11
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
12
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
13
13
 
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
12
12
 
@@ -11,7 +11,7 @@ unset CLAUDECODE 2>/dev/null || true
11
11
  # Ignore SIGHUP so tmux attach/detach doesn't kill long-running plan/design/review stages
12
12
  trap '' HUP
13
13
 
14
- VERSION="2.3.1"
14
+ VERSION="2.4.0"
15
15
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
16
  REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
17
17
 
package/scripts/sw-pm.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="2.3.1"
9
+ VERSION="2.4.0"
10
10
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
11
 
12
12
  # ─── Cross-platform compatibility ──────────────────────────────────────────