shipwright-cli 3.1.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/code-reviewer.md +2 -0
- package/.claude/agents/devops-engineer.md +2 -0
- package/.claude/agents/doc-fleet-agent.md +2 -0
- package/.claude/agents/pipeline-agent.md +2 -0
- package/.claude/agents/shell-script-specialist.md +2 -0
- package/.claude/agents/test-specialist.md +2 -0
- package/.claude/hooks/agent-crash-capture.sh +32 -0
- package/.claude/hooks/post-tool-use.sh +3 -2
- package/.claude/hooks/pre-tool-use.sh +35 -3
- package/README.md +22 -8
- package/claude-code/hooks/config-change.sh +18 -0
- package/claude-code/hooks/instructions-reloaded.sh +7 -0
- package/claude-code/hooks/worktree-create.sh +25 -0
- package/claude-code/hooks/worktree-remove.sh +20 -0
- package/config/code-constitution.json +130 -0
- package/config/defaults.json +25 -2
- package/config/policy.json +1 -1
- package/dashboard/middleware/auth.ts +134 -0
- package/dashboard/middleware/constants.ts +21 -0
- package/dashboard/public/index.html +8 -6
- package/dashboard/public/styles.css +176 -97
- package/dashboard/routes/auth.ts +38 -0
- package/dashboard/server.ts +117 -25
- package/dashboard/services/config.ts +26 -0
- package/dashboard/services/db.ts +118 -0
- package/dashboard/src/canvas/pixel-agent.ts +298 -0
- package/dashboard/src/canvas/pixel-sprites.ts +440 -0
- package/dashboard/src/canvas/shipyard-effects.ts +367 -0
- package/dashboard/src/canvas/shipyard-scene.ts +616 -0
- package/dashboard/src/canvas/submarine-layout.ts +267 -0
- package/dashboard/src/components/header.ts +8 -7
- package/dashboard/src/core/api.ts +5 -0
- package/dashboard/src/core/router.ts +1 -0
- package/dashboard/src/design/submarine-theme.ts +253 -0
- package/dashboard/src/main.ts +2 -0
- package/dashboard/src/types/api.ts +12 -1
- package/dashboard/src/views/activity.ts +2 -1
- package/dashboard/src/views/metrics.ts +69 -1
- package/dashboard/src/views/shipyard.ts +39 -0
- package/dashboard/types/index.ts +166 -0
- package/docs/plans/2026-02-28-compound-audit-and-shipyard-design.md +186 -0
- package/docs/plans/2026-02-28-skipper-shipwright-implementation-plan.md +1182 -0
- package/docs/plans/2026-02-28-skipper-shipwright-integration-design.md +531 -0
- package/docs/plans/2026-03-01-ai-powered-skill-injection-design.md +298 -0
- package/docs/plans/2026-03-01-ai-powered-skill-injection-plan.md +1109 -0
- package/docs/plans/2026-03-01-capabilities-cleanup-plan.md +658 -0
- package/docs/plans/2026-03-01-clean-architecture-plan.md +924 -0
- package/docs/plans/2026-03-01-compound-audit-cascade-design.md +191 -0
- package/docs/plans/2026-03-01-compound-audit-cascade-plan.md +921 -0
- package/docs/plans/2026-03-01-deep-integration-plan.md +851 -0
- package/docs/plans/2026-03-01-pipeline-audit-trail-design.md +145 -0
- package/docs/plans/2026-03-01-pipeline-audit-trail-plan.md +770 -0
- package/docs/plans/2026-03-01-refined-depths-brand-design.md +382 -0
- package/docs/plans/2026-03-01-refined-depths-implementation.md +599 -0
- package/docs/plans/2026-03-01-skipper-kernel-integration-design.md +203 -0
- package/docs/plans/2026-03-01-unified-platform-design.md +272 -0
- package/docs/plans/2026-03-07-claude-code-feature-integration-design.md +189 -0
- package/docs/plans/2026-03-07-claude-code-feature-integration-plan.md +1165 -0
- package/docs/research/BACKLOG_QUICK_REFERENCE.md +352 -0
- package/docs/research/CUTTING_EDGE_RESEARCH_2026.md +546 -0
- package/docs/research/RESEARCH_INDEX.md +439 -0
- package/docs/research/RESEARCH_SOURCES.md +440 -0
- package/docs/research/RESEARCH_SUMMARY.txt +275 -0
- package/docs/superpowers/specs/2026-03-10-pipeline-quality-revolution-design.md +341 -0
- package/package.json +2 -2
- package/scripts/lib/adaptive-model.sh +427 -0
- package/scripts/lib/adaptive-timeout.sh +316 -0
- package/scripts/lib/audit-trail.sh +309 -0
- package/scripts/lib/auto-recovery.sh +471 -0
- package/scripts/lib/bandit-selector.sh +431 -0
- package/scripts/lib/bootstrap.sh +104 -2
- package/scripts/lib/causal-graph.sh +455 -0
- package/scripts/lib/compat.sh +126 -0
- package/scripts/lib/compound-audit.sh +337 -0
- package/scripts/lib/constitutional.sh +454 -0
- package/scripts/lib/context-budget.sh +359 -0
- package/scripts/lib/convergence.sh +594 -0
- package/scripts/lib/cost-optimizer.sh +634 -0
- package/scripts/lib/daemon-adaptive.sh +14 -2
- package/scripts/lib/daemon-dispatch.sh +106 -17
- package/scripts/lib/daemon-failure.sh +34 -4
- package/scripts/lib/daemon-patrol.sh +25 -4
- package/scripts/lib/daemon-poll-github.sh +361 -0
- package/scripts/lib/daemon-poll-health.sh +299 -0
- package/scripts/lib/daemon-poll.sh +27 -611
- package/scripts/lib/daemon-state.sh +119 -66
- package/scripts/lib/daemon-triage.sh +10 -0
- package/scripts/lib/dod-scorecard.sh +442 -0
- package/scripts/lib/error-actionability.sh +300 -0
- package/scripts/lib/formal-spec.sh +461 -0
- package/scripts/lib/helpers.sh +180 -5
- package/scripts/lib/intent-analysis.sh +409 -0
- package/scripts/lib/loop-convergence.sh +350 -0
- package/scripts/lib/loop-iteration.sh +682 -0
- package/scripts/lib/loop-progress.sh +48 -0
- package/scripts/lib/loop-restart.sh +185 -0
- package/scripts/lib/memory-effectiveness.sh +506 -0
- package/scripts/lib/mutation-executor.sh +352 -0
- package/scripts/lib/outcome-feedback.sh +521 -0
- package/scripts/lib/pipeline-cli.sh +336 -0
- package/scripts/lib/pipeline-commands.sh +1216 -0
- package/scripts/lib/pipeline-detection.sh +101 -3
- package/scripts/lib/pipeline-execution.sh +897 -0
- package/scripts/lib/pipeline-github.sh +28 -3
- package/scripts/lib/pipeline-intelligence-compound.sh +431 -0
- package/scripts/lib/pipeline-intelligence-scoring.sh +407 -0
- package/scripts/lib/pipeline-intelligence-skip.sh +181 -0
- package/scripts/lib/pipeline-intelligence.sh +104 -1138
- package/scripts/lib/pipeline-quality-bash-compat.sh +182 -0
- package/scripts/lib/pipeline-quality-checks.sh +17 -711
- package/scripts/lib/pipeline-quality-gates.sh +563 -0
- package/scripts/lib/pipeline-stages-build.sh +730 -0
- package/scripts/lib/pipeline-stages-delivery.sh +965 -0
- package/scripts/lib/pipeline-stages-intake.sh +1133 -0
- package/scripts/lib/pipeline-stages-monitor.sh +407 -0
- package/scripts/lib/pipeline-stages-review.sh +1022 -0
- package/scripts/lib/pipeline-stages.sh +161 -2901
- package/scripts/lib/pipeline-state.sh +36 -5
- package/scripts/lib/pipeline-util.sh +487 -0
- package/scripts/lib/policy-learner.sh +438 -0
- package/scripts/lib/process-reward.sh +493 -0
- package/scripts/lib/project-detect.sh +649 -0
- package/scripts/lib/quality-profile.sh +334 -0
- package/scripts/lib/recruit-commands.sh +885 -0
- package/scripts/lib/recruit-learning.sh +739 -0
- package/scripts/lib/recruit-roles.sh +648 -0
- package/scripts/lib/reward-aggregator.sh +458 -0
- package/scripts/lib/rl-optimizer.sh +362 -0
- package/scripts/lib/root-cause.sh +427 -0
- package/scripts/lib/scope-enforcement.sh +445 -0
- package/scripts/lib/session-restart.sh +493 -0
- package/scripts/lib/skill-memory.sh +300 -0
- package/scripts/lib/skill-registry.sh +775 -0
- package/scripts/lib/spec-driven.sh +476 -0
- package/scripts/lib/test-helpers.sh +18 -7
- package/scripts/lib/test-holdout.sh +429 -0
- package/scripts/lib/test-optimizer.sh +511 -0
- package/scripts/shipwright-file-suggest.sh +45 -0
- package/scripts/skills/adversarial-quality.md +61 -0
- package/scripts/skills/api-design.md +44 -0
- package/scripts/skills/architecture-design.md +50 -0
- package/scripts/skills/brainstorming.md +43 -0
- package/scripts/skills/data-pipeline.md +44 -0
- package/scripts/skills/deploy-safety.md +64 -0
- package/scripts/skills/documentation.md +38 -0
- package/scripts/skills/frontend-design.md +45 -0
- package/scripts/skills/generated/.gitkeep +0 -0
- package/scripts/skills/generated/_refinements/.gitkeep +0 -0
- package/scripts/skills/generated/_refinements/adversarial-quality.patch.md +3 -0
- package/scripts/skills/generated/_refinements/architecture-design.patch.md +3 -0
- package/scripts/skills/generated/_refinements/brainstorming.patch.md +3 -0
- package/scripts/skills/generated/cli-version-management.md +29 -0
- package/scripts/skills/generated/collection-system-validation.md +99 -0
- package/scripts/skills/generated/large-scale-c-refactoring-coordination.md +97 -0
- package/scripts/skills/generated/pattern-matching-similarity-scoring.md +195 -0
- package/scripts/skills/generated/test-parallelization-detection.md +65 -0
- package/scripts/skills/observability.md +79 -0
- package/scripts/skills/performance.md +48 -0
- package/scripts/skills/pr-quality.md +49 -0
- package/scripts/skills/product-thinking.md +43 -0
- package/scripts/skills/security-audit.md +49 -0
- package/scripts/skills/systematic-debugging.md +40 -0
- package/scripts/skills/testing-strategy.md +47 -0
- package/scripts/skills/two-stage-review.md +52 -0
- package/scripts/skills/validation-thoroughness.md +55 -0
- package/scripts/sw +9 -3
- package/scripts/sw-activity.sh +9 -8
- package/scripts/sw-adaptive.sh +8 -7
- package/scripts/sw-adversarial.sh +2 -1
- package/scripts/sw-architecture-enforcer.sh +3 -1
- package/scripts/sw-auth.sh +12 -2
- package/scripts/sw-autonomous.sh +5 -1
- package/scripts/sw-changelog.sh +4 -1
- package/scripts/sw-checkpoint.sh +2 -1
- package/scripts/sw-ci.sh +15 -6
- package/scripts/sw-cleanup.sh +4 -26
- package/scripts/sw-code-review.sh +45 -20
- package/scripts/sw-connect.sh +2 -1
- package/scripts/sw-context.sh +2 -1
- package/scripts/sw-cost.sh +107 -5
- package/scripts/sw-daemon.sh +71 -11
- package/scripts/sw-dashboard.sh +3 -1
- package/scripts/sw-db.sh +71 -20
- package/scripts/sw-decide.sh +8 -2
- package/scripts/sw-decompose.sh +360 -17
- package/scripts/sw-deps.sh +4 -1
- package/scripts/sw-developer-simulation.sh +4 -1
- package/scripts/sw-discovery.sh +378 -5
- package/scripts/sw-doc-fleet.sh +4 -1
- package/scripts/sw-docs-agent.sh +3 -1
- package/scripts/sw-docs.sh +2 -1
- package/scripts/sw-doctor.sh +453 -2
- package/scripts/sw-dora.sh +4 -1
- package/scripts/sw-durable.sh +12 -7
- package/scripts/sw-e2e-orchestrator.sh +17 -16
- package/scripts/sw-eventbus.sh +13 -4
- package/scripts/sw-evidence.sh +364 -12
- package/scripts/sw-feedback.sh +550 -9
- package/scripts/sw-fix.sh +20 -1
- package/scripts/sw-fleet-discover.sh +6 -2
- package/scripts/sw-fleet-viz.sh +9 -4
- package/scripts/sw-fleet.sh +5 -1
- package/scripts/sw-github-app.sh +18 -4
- package/scripts/sw-github-checks.sh +3 -2
- package/scripts/sw-github-deploy.sh +3 -2
- package/scripts/sw-github-graphql.sh +18 -7
- package/scripts/sw-guild.sh +5 -1
- package/scripts/sw-heartbeat.sh +5 -30
- package/scripts/sw-hello.sh +67 -0
- package/scripts/sw-hygiene.sh +10 -3
- package/scripts/sw-incident.sh +273 -5
- package/scripts/sw-init.sh +18 -2
- package/scripts/sw-instrument.sh +10 -2
- package/scripts/sw-intelligence.sh +44 -7
- package/scripts/sw-jira.sh +5 -1
- package/scripts/sw-launchd.sh +2 -1
- package/scripts/sw-linear.sh +4 -1
- package/scripts/sw-logs.sh +4 -1
- package/scripts/sw-loop.sh +436 -1076
- package/scripts/sw-memory.sh +357 -3
- package/scripts/sw-mission-control.sh +6 -1
- package/scripts/sw-model-router.sh +483 -27
- package/scripts/sw-otel.sh +15 -4
- package/scripts/sw-oversight.sh +14 -5
- package/scripts/sw-patrol-meta.sh +334 -0
- package/scripts/sw-pipeline-composer.sh +7 -1
- package/scripts/sw-pipeline-vitals.sh +12 -6
- package/scripts/sw-pipeline.sh +54 -2653
- package/scripts/sw-pm.sh +16 -8
- package/scripts/sw-pr-lifecycle.sh +2 -1
- package/scripts/sw-predictive.sh +17 -5
- package/scripts/sw-prep.sh +185 -2
- package/scripts/sw-ps.sh +5 -25
- package/scripts/sw-public-dashboard.sh +17 -4
- package/scripts/sw-quality.sh +14 -6
- package/scripts/sw-reaper.sh +8 -25
- package/scripts/sw-recruit.sh +156 -2303
- package/scripts/sw-regression.sh +19 -12
- package/scripts/sw-release-manager.sh +3 -1
- package/scripts/sw-release.sh +4 -1
- package/scripts/sw-remote.sh +3 -1
- package/scripts/sw-replay.sh +7 -1
- package/scripts/sw-retro.sh +158 -1
- package/scripts/sw-review-rerun.sh +3 -1
- package/scripts/sw-scale.sh +14 -5
- package/scripts/sw-security-audit.sh +6 -1
- package/scripts/sw-self-optimize.sh +173 -6
- package/scripts/sw-session.sh +9 -3
- package/scripts/sw-setup.sh +3 -1
- package/scripts/sw-stall-detector.sh +406 -0
- package/scripts/sw-standup.sh +15 -7
- package/scripts/sw-status.sh +3 -1
- package/scripts/sw-strategic.sh +14 -6
- package/scripts/sw-stream.sh +13 -4
- package/scripts/sw-swarm.sh +20 -7
- package/scripts/sw-team-stages.sh +13 -6
- package/scripts/sw-templates.sh +7 -31
- package/scripts/sw-testgen.sh +17 -6
- package/scripts/sw-tmux-pipeline.sh +4 -1
- package/scripts/sw-tmux-role-color.sh +2 -0
- package/scripts/sw-tmux-status.sh +1 -1
- package/scripts/sw-tmux.sh +37 -1
- package/scripts/sw-trace.sh +3 -1
- package/scripts/sw-tracker-github.sh +3 -0
- package/scripts/sw-tracker-jira.sh +3 -0
- package/scripts/sw-tracker-linear.sh +3 -0
- package/scripts/sw-tracker.sh +3 -1
- package/scripts/sw-triage.sh +3 -2
- package/scripts/sw-upgrade.sh +3 -1
- package/scripts/sw-ux.sh +5 -2
- package/scripts/sw-webhook.sh +5 -2
- package/scripts/sw-widgets.sh +9 -4
- package/scripts/sw-worktree.sh +15 -3
- package/scripts/test-skill-injection.sh +1233 -0
- package/templates/pipelines/autonomous.json +27 -3
- package/templates/pipelines/cost-aware.json +34 -8
- package/templates/pipelines/deployed.json +12 -0
- package/templates/pipelines/enterprise.json +12 -0
- package/templates/pipelines/fast.json +6 -0
- package/templates/pipelines/full.json +27 -3
- package/templates/pipelines/hotfix.json +6 -0
- package/templates/pipelines/standard.json +12 -0
- package/templates/pipelines/tdd.json +12 -0
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="3.
|
|
9
|
+
VERSION="3.3.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
|
@@ -26,18 +26,20 @@ if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
|
|
|
26
26
|
fi
|
|
27
27
|
if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
28
28
|
emit_event() {
|
|
29
|
-
local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
|
|
29
|
+
local event_type="$1"; shift; mkdir -p "${PM_STATE_DIR:=${HOME}/.shipwright}"
|
|
30
|
+
# shellcheck disable=SC2155
|
|
30
31
|
local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
|
|
31
32
|
while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
|
|
32
|
-
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
33
|
+
echo "${payload}}" >> "${PM_STATE_DIR:=${HOME}/.shipwright}/events.jsonl"
|
|
33
34
|
}
|
|
34
35
|
fi
|
|
35
36
|
# ─── PM History Storage ──────────────────────────────────────────────────────
|
|
36
|
-
|
|
37
|
+
PM_STATE_DIR="${PM_STATE_DIR:-${HOME}/.shipwright}"
|
|
38
|
+
PM_HISTORY="${PM_STATE_DIR}/pm-history.json"
|
|
37
39
|
|
|
38
40
|
# ─── Ensure PM history file exists ───────────────────────────────────────────
|
|
39
41
|
ensure_pm_history() {
|
|
40
|
-
mkdir -p "${
|
|
42
|
+
mkdir -p "${PM_STATE_DIR}"
|
|
41
43
|
if [[ ! -f "$PM_HISTORY" ]]; then
|
|
42
44
|
echo '{"decisions":[],"outcomes":[]}' > "$PM_HISTORY"
|
|
43
45
|
fi
|
|
@@ -121,7 +123,8 @@ analyze_issue() {
|
|
|
121
123
|
# Count estimated files affected by analyzing body content
|
|
122
124
|
local file_scope complexity risk estimated_hours
|
|
123
125
|
local files_mentioned
|
|
124
|
-
files_mentioned=$(echo "$body" | grep -o '\b[a-zA-Z0-9_.-]*\.[a-z]*' | sort -u | wc -l ||
|
|
126
|
+
files_mentioned=$(echo "$body" | grep -o '\b[a-zA-Z0-9_.-]*\.[a-z]*' | sort -u | wc -l || true)
|
|
127
|
+
files_mentioned="${files_mentioned:-0}"
|
|
125
128
|
files_mentioned=$((files_mentioned + 1)) # At least 1 file
|
|
126
129
|
|
|
127
130
|
# Determine file scope
|
|
@@ -203,7 +206,7 @@ analyze_issue() {
|
|
|
203
206
|
|
|
204
207
|
# ─── recommend_team <analysis_json> ──────────────────────────────────────────
|
|
205
208
|
# Based on analysis, recommend team composition
|
|
206
|
-
# Tries recruit's AI/heuristic team composition first, falls back to
|
|
209
|
+
# Tries recruit's AI/heuristic team composition first, falls back to built-in rules.
|
|
207
210
|
recommend_team() {
|
|
208
211
|
local analysis="$1"
|
|
209
212
|
|
|
@@ -253,7 +256,7 @@ recommend_team() {
|
|
|
253
256
|
fi
|
|
254
257
|
fi
|
|
255
258
|
|
|
256
|
-
# ── Fallback:
|
|
259
|
+
# ── Fallback: heuristic team composition ──
|
|
257
260
|
local complexity risk is_security is_perf file_scope
|
|
258
261
|
complexity=$(echo "$analysis" | jq -r '.complexity')
|
|
259
262
|
risk=$(echo "$analysis" | jq -r '.risk')
|
|
@@ -494,6 +497,7 @@ cmd_recommend() {
|
|
|
494
497
|
|
|
495
498
|
# Combine into comprehensive recommendation
|
|
496
499
|
local recommendation
|
|
500
|
+
# shellcheck disable=SC2046
|
|
497
501
|
recommendation=$(jq -n \
|
|
498
502
|
--argjson analysis "$analysis" \
|
|
499
503
|
--argjson team "$team_rec" \
|
|
@@ -512,6 +516,7 @@ cmd_recommend() {
|
|
|
512
516
|
ensure_pm_history
|
|
513
517
|
local tmp_hist
|
|
514
518
|
tmp_hist=$(mktemp)
|
|
519
|
+
# shellcheck disable=SC2064
|
|
515
520
|
trap "rm -f '$tmp_hist'" RETURN
|
|
516
521
|
jq --argjson rec "$recommendation" '.decisions += [$rec]' "$PM_HISTORY" > "$tmp_hist" && mv "$tmp_hist" "$PM_HISTORY"
|
|
517
522
|
emit_event "pm.recommend" "issue=${issue_num}"
|
|
@@ -540,6 +545,7 @@ cmd_recommend() {
|
|
|
540
545
|
ensure_pm_history
|
|
541
546
|
local tmp_hist
|
|
542
547
|
tmp_hist=$(mktemp)
|
|
548
|
+
# shellcheck disable=SC2064
|
|
543
549
|
trap "rm -f '$tmp_hist'" RETURN
|
|
544
550
|
jq --argjson rec "$recommendation" '.decisions += [$rec]' "$PM_HISTORY" > "$tmp_hist" && mv "$tmp_hist" "$PM_HISTORY"
|
|
545
551
|
|
|
@@ -604,6 +610,7 @@ cmd_learn() {
|
|
|
604
610
|
# Save to history
|
|
605
611
|
local tmp_hist
|
|
606
612
|
tmp_hist=$(mktemp)
|
|
613
|
+
# shellcheck disable=SC2064
|
|
607
614
|
trap "rm -f '$tmp_hist'" RETURN
|
|
608
615
|
jq --argjson outcome "$outcome_record" '.outcomes += [$outcome]' "$PM_HISTORY" > "$tmp_hist" && mv "$tmp_hist" "$PM_HISTORY"
|
|
609
616
|
|
|
@@ -629,6 +636,7 @@ cmd_history() {
|
|
|
629
636
|
local total_decisions success_count fail_count
|
|
630
637
|
total_decisions=$(jq '.outcomes | length' "$PM_HISTORY")
|
|
631
638
|
success_count=$(jq '[.outcomes[] | select(.outcome == "success")] | length' "$PM_HISTORY")
|
|
639
|
+
# shellcheck disable=SC2034
|
|
632
640
|
fail_count=$(jq '[.outcomes[] | select(.outcome == "failure")] | length' "$PM_HISTORY")
|
|
633
641
|
|
|
634
642
|
if [[ "$total_decisions" -gt 0 ]]; then
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
# shellcheck disable=SC2034
|
|
10
|
+
VERSION="3.3.0"
|
|
10
11
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
12
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
13
|
|
package/scripts/sw-predictive.sh
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
# shellcheck disable=SC2034
|
|
10
|
+
VERSION="3.3.0"
|
|
10
11
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
12
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
13
|
|
|
@@ -17,6 +18,8 @@ REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
|
17
18
|
# Canonical helpers (colors, output, events)
|
|
18
19
|
# shellcheck source=lib/helpers.sh
|
|
19
20
|
[[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
|
|
21
|
+
# shellcheck source=lib/config.sh
|
|
22
|
+
[[ -f "$SCRIPT_DIR/lib/config.sh" ]] && source "$SCRIPT_DIR/lib/config.sh"
|
|
20
23
|
# Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
|
|
21
24
|
[[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
|
|
22
25
|
[[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
|
|
@@ -29,12 +32,14 @@ fi
|
|
|
29
32
|
if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
30
33
|
emit_event() {
|
|
31
34
|
local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
|
|
35
|
+
# shellcheck disable=SC2155
|
|
32
36
|
local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
|
|
33
37
|
while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
|
|
34
38
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
35
39
|
}
|
|
36
40
|
fi
|
|
37
41
|
# ─── Structured Event Log ──────────────────────────────────────────────────
|
|
42
|
+
# shellcheck disable=SC2034
|
|
38
43
|
EVENTS_FILE="${HOME}/.shipwright/events.jsonl"
|
|
39
44
|
|
|
40
45
|
# ─── Intelligence Engine (optional) ────────────────────────────────────────
|
|
@@ -178,6 +183,7 @@ predictive_confirm_anomaly() {
|
|
|
178
183
|
# Find the most recent unconfirmed anomaly for this stage+metric
|
|
179
184
|
local tmp_file
|
|
180
185
|
tmp_file=$(mktemp "${TMPDIR:-/tmp}/sw-anomaly-confirm.XXXXXX")
|
|
186
|
+
# shellcheck disable=SC2064
|
|
181
187
|
trap "rm -f '$tmp_file'" RETURN
|
|
182
188
|
local found=false
|
|
183
189
|
|
|
@@ -274,6 +280,7 @@ _predictive_update_alarm_rates() {
|
|
|
274
280
|
# Atomic write
|
|
275
281
|
local tmp_file
|
|
276
282
|
tmp_file=$(mktemp "${TMPDIR:-/tmp}/sw-anomaly-thresh.XXXXXX")
|
|
283
|
+
# shellcheck disable=SC2064
|
|
277
284
|
trap "rm -f '$tmp_file'" RETURN
|
|
278
285
|
jq --arg m "$metric_name" \
|
|
279
286
|
--argjson crit "$new_critical" \
|
|
@@ -384,10 +391,12 @@ Return JSON format:
|
|
|
384
391
|
fi
|
|
385
392
|
|
|
386
393
|
# Fallback: heuristic risk assessment
|
|
387
|
-
local
|
|
394
|
+
local default_risk
|
|
395
|
+
default_risk=$(_config_get_int "predictive.default_risk_score" 50 2>/dev/null || echo 50)
|
|
396
|
+
local risk=$default_risk
|
|
388
397
|
local reason="Default medium risk — no AI analysis available"
|
|
389
398
|
|
|
390
|
-
# Check for learned keyword weights first, fall back to
|
|
399
|
+
# Check for learned keyword weights first, fall back to config defaults
|
|
391
400
|
local keywords_json
|
|
392
401
|
keywords_json=$(_predictive_get_risk_keywords)
|
|
393
402
|
|
|
@@ -416,9 +425,11 @@ Return JSON format:
|
|
|
416
425
|
reason="Learned keyword weights: ${matched_keywords%%, }"
|
|
417
426
|
fi
|
|
418
427
|
else
|
|
419
|
-
#
|
|
428
|
+
# Config-driven keyword risk elevation
|
|
429
|
+
local keyword_risk
|
|
430
|
+
keyword_risk=$(_config_get_int "predictive.keyword_risk_score" 70 2>/dev/null || echo 70)
|
|
420
431
|
if echo "$issue_json" | grep -qiE "refactor|migration|breaking|security|deploy"; then
|
|
421
|
-
risk
|
|
432
|
+
risk=$keyword_risk
|
|
422
433
|
reason="Keywords suggest elevated complexity"
|
|
423
434
|
fi
|
|
424
435
|
fi
|
|
@@ -751,6 +762,7 @@ predict_update_baseline() {
|
|
|
751
762
|
# Atomic write
|
|
752
763
|
local tmp_file
|
|
753
764
|
tmp_file=$(mktemp)
|
|
765
|
+
# shellcheck disable=SC2064
|
|
754
766
|
trap "rm -f '$tmp_file'" RETURN
|
|
755
767
|
jq --arg key "$key" \
|
|
756
768
|
--argjson val "$new_value" \
|
package/scripts/sw-prep.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.3.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Handle subcommands ───────────────────────────────────────────────────────
|
|
@@ -33,7 +33,8 @@ fi
|
|
|
33
33
|
if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
34
34
|
emit_event() {
|
|
35
35
|
local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
|
|
36
|
-
local payload
|
|
36
|
+
local payload
|
|
37
|
+
payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
|
|
37
38
|
while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
|
|
38
39
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
39
40
|
}
|
|
@@ -43,6 +44,7 @@ FORCE=false
|
|
|
43
44
|
CHECK_ONLY=false
|
|
44
45
|
UPDATE_MODE=false
|
|
45
46
|
WITH_CLAUDE=false
|
|
47
|
+
INTERACTIVE=false
|
|
46
48
|
PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
47
49
|
|
|
48
50
|
# Detection results
|
|
@@ -99,6 +101,7 @@ show_help() {
|
|
|
99
101
|
echo -e " ${CYAN}--force${RESET} Overwrite existing files"
|
|
100
102
|
echo -e " ${CYAN}--check${RESET} Audit existing prep (dry run)"
|
|
101
103
|
echo -e " ${CYAN}--update${RESET} Refresh auto-generated sections only"
|
|
104
|
+
echo -e " ${CYAN}--interactive${RESET} Interactive quality profile dialogue"
|
|
102
105
|
echo -e " ${CYAN}--with-claude${RESET} Deep analysis using Claude Code (slower, richer)"
|
|
103
106
|
echo -e " ${CYAN}--help, -h${RESET} Show this help message"
|
|
104
107
|
echo ""
|
|
@@ -129,6 +132,7 @@ for arg in "$@"; do
|
|
|
129
132
|
--force) FORCE=true ;;
|
|
130
133
|
--check) CHECK_ONLY=true ;;
|
|
131
134
|
--update) UPDATE_MODE=true ;;
|
|
135
|
+
--interactive) INTERACTIVE=true ;;
|
|
132
136
|
--with-claude) WITH_CLAUDE=true ;;
|
|
133
137
|
--help|-h) show_help; exit 0 ;;
|
|
134
138
|
*)
|
|
@@ -459,6 +463,7 @@ prep_scan_structure() {
|
|
|
459
463
|
for d in docs doc documentation wiki; do
|
|
460
464
|
[[ -d "$root/$d" ]] && ddirs+=("$d")
|
|
461
465
|
done
|
|
466
|
+
# shellcheck disable=SC2034
|
|
462
467
|
DOC_DIRS="${ddirs[*]:-}"
|
|
463
468
|
|
|
464
469
|
# Config files
|
|
@@ -499,6 +504,7 @@ prep_scan_structure() {
|
|
|
499
504
|
-not -path "*/node_modules/*" -not -path "*/.git/*" 2>/dev/null | wc -l | tr -d ' ')
|
|
500
505
|
|
|
501
506
|
# Total lines (approximation from source files)
|
|
507
|
+
# shellcheck disable=SC2227,SC2261
|
|
502
508
|
TOTAL_LINES=$(find "$root" \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" \
|
|
503
509
|
-o -name "*.py" -o -name "*.rb" -o -name "*.go" -o -name "*.rs" -o -name "*.java" \) \
|
|
504
510
|
-not -path "*/node_modules/*" -not -path "*/.git/*" -not -path "*/vendor/*" \
|
|
@@ -572,6 +578,7 @@ prep_extract_patterns() {
|
|
|
572
578
|
|
|
573
579
|
# ── Middleware ──
|
|
574
580
|
if grep -rq "app\.use(" "$root/src" "$root/app" "$root/lib" 2>/dev/null; then
|
|
581
|
+
# shellcheck disable=SC2034
|
|
575
582
|
HAS_MIDDLEWARE=true
|
|
576
583
|
fi
|
|
577
584
|
|
|
@@ -767,8 +774,11 @@ ${style_samples}"
|
|
|
767
774
|
DB_PATTERNS="$smart_val"
|
|
768
775
|
fi
|
|
769
776
|
|
|
777
|
+
# shellcheck disable=SC2034
|
|
770
778
|
SEMICOLONS=$(echo "$analysis" | grep "^SEMICOLONS:" | sed 's/^SEMICOLONS:[[:space:]]*//' | head -1)
|
|
779
|
+
# shellcheck disable=SC2034
|
|
771
780
|
QUOTE_STYLE=$(echo "$analysis" | grep "^QUOTE_STYLE:" | sed 's/^QUOTE_STYLE:[[:space:]]*//' | head -1)
|
|
781
|
+
# shellcheck disable=SC2034
|
|
772
782
|
INDENT_STYLE=$(echo "$analysis" | grep "^INDENT:" | sed 's/^INDENT:[[:space:]]*//' | head -1)
|
|
773
783
|
|
|
774
784
|
success "Smart detection: ${ARCHITECTURE_PATTERN:-unknown} architecture${FRAMEWORK:+, ${FRAMEWORK}}"
|
|
@@ -818,6 +828,7 @@ prep_learn_patterns() {
|
|
|
818
828
|
# Write patterns file atomically
|
|
819
829
|
local tmp_patterns
|
|
820
830
|
tmp_patterns=$(mktemp)
|
|
831
|
+
# shellcheck disable=SC2064
|
|
821
832
|
trap "rm -f '$tmp_patterns'" RETURN
|
|
822
833
|
jq -n \
|
|
823
834
|
--arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
|
|
@@ -947,6 +958,24 @@ prep_generate_settings() {
|
|
|
947
958
|
success "Generated .claude/settings.json"
|
|
948
959
|
}
|
|
949
960
|
|
|
961
|
+
# ─── prep_generate_managed_mcp ────────────────────────────────────────────────
|
|
962
|
+
|
|
963
|
+
prep_generate_managed_mcp() {
|
|
964
|
+
local filepath="$PROJECT_ROOT/.claude/managed-mcp.json"
|
|
965
|
+
if ! should_write "$filepath"; then return; fi
|
|
966
|
+
|
|
967
|
+
info "Generating .claude/managed-mcp.json..."
|
|
968
|
+
|
|
969
|
+
jq -n '{
|
|
970
|
+
"allowedMcpServers": ["*"],
|
|
971
|
+
"deniedMcpServers": [],
|
|
972
|
+
"note": "Configure MCP server access policies for pipeline agents"
|
|
973
|
+
}' > "$filepath"
|
|
974
|
+
|
|
975
|
+
track_file "$filepath"
|
|
976
|
+
success "Generated .claude/managed-mcp.json"
|
|
977
|
+
}
|
|
978
|
+
|
|
950
979
|
# ─── prep_generate_hooks ────────────────────────────────────────────────────
|
|
951
980
|
|
|
952
981
|
prep_generate_hooks() {
|
|
@@ -1572,6 +1601,156 @@ prep_check() {
|
|
|
1572
1601
|
echo ""
|
|
1573
1602
|
}
|
|
1574
1603
|
|
|
1604
|
+
# ─── generate_quality_profile — Interactive quality profile dialogue ────────
|
|
1605
|
+
|
|
1606
|
+
generate_quality_profile() {
|
|
1607
|
+
local profile_path="$PROJECT_ROOT/.claude/quality-profile.json"
|
|
1608
|
+
|
|
1609
|
+
# Load quality-profile library
|
|
1610
|
+
if [[ -f "$SCRIPT_DIR/lib/quality-profile.sh" ]]; then
|
|
1611
|
+
source "$SCRIPT_DIR/lib/quality-profile.sh"
|
|
1612
|
+
else
|
|
1613
|
+
warn "quality-profile.sh library not found"
|
|
1614
|
+
return 1
|
|
1615
|
+
fi
|
|
1616
|
+
|
|
1617
|
+
info "Generating quality profile..."
|
|
1618
|
+
|
|
1619
|
+
# Start with inferred values
|
|
1620
|
+
local inferred
|
|
1621
|
+
inferred=$(qp_infer_from_repo)
|
|
1622
|
+
|
|
1623
|
+
# Generate base profile
|
|
1624
|
+
local base_profile
|
|
1625
|
+
base_profile=$(generate_default_profile)
|
|
1626
|
+
|
|
1627
|
+
# In interactive mode, ask refinement questions
|
|
1628
|
+
if $INTERACTIVE; then
|
|
1629
|
+
echo ""
|
|
1630
|
+
echo -e "${CYAN}${BOLD}Quality Profile Setup${RESET}"
|
|
1631
|
+
echo -e "${DIM}Answer these questions to calibrate quality standards:${RESET}"
|
|
1632
|
+
echo ""
|
|
1633
|
+
|
|
1634
|
+
# Q1: Max PR size
|
|
1635
|
+
local max_pr_lines
|
|
1636
|
+
read -p "Max PR size in lines (default 500): " max_pr_lines
|
|
1637
|
+
max_pr_lines="${max_pr_lines:-500}"
|
|
1638
|
+
|
|
1639
|
+
# Q2: Max files per PR
|
|
1640
|
+
local max_files
|
|
1641
|
+
read -p "Max files per PR (default 15): " max_files
|
|
1642
|
+
max_files="${max_files:-15}"
|
|
1643
|
+
|
|
1644
|
+
# Q3: Test philosophy
|
|
1645
|
+
echo ""
|
|
1646
|
+
echo -e "${DIM}Test philosophy:${RESET}"
|
|
1647
|
+
echo " 1. test_after (default)"
|
|
1648
|
+
echo " 2. tdd"
|
|
1649
|
+
echo " 3. coverage_target"
|
|
1650
|
+
echo " 4. manual"
|
|
1651
|
+
read -p "Choose [1-4]: " test_choice
|
|
1652
|
+
|
|
1653
|
+
local philosophy="test_after"
|
|
1654
|
+
case "$test_choice" in
|
|
1655
|
+
2) philosophy="tdd" ;;
|
|
1656
|
+
3) philosophy="coverage_target" ;;
|
|
1657
|
+
4) philosophy="manual" ;;
|
|
1658
|
+
esac
|
|
1659
|
+
|
|
1660
|
+
# Q4: Architecture pattern
|
|
1661
|
+
echo ""
|
|
1662
|
+
echo -e "${DIM}Architecture pattern:${RESET}"
|
|
1663
|
+
echo " 1. monolith (default)"
|
|
1664
|
+
echo " 2. modular_monolith"
|
|
1665
|
+
echo " 3. microservices"
|
|
1666
|
+
echo " 4. serverless"
|
|
1667
|
+
echo " 5. library"
|
|
1668
|
+
read -p "Choose [1-5]: " arch_choice
|
|
1669
|
+
|
|
1670
|
+
local arch_pattern="monolith"
|
|
1671
|
+
case "$arch_choice" in
|
|
1672
|
+
2) arch_pattern="modular_monolith" ;;
|
|
1673
|
+
3) arch_pattern="microservices" ;;
|
|
1674
|
+
4) arch_pattern="serverless" ;;
|
|
1675
|
+
5) arch_pattern="library" ;;
|
|
1676
|
+
esac
|
|
1677
|
+
|
|
1678
|
+
# Q5: Never ship rules
|
|
1679
|
+
echo ""
|
|
1680
|
+
read -p "Critical rules to never ship (comma-separated, or press Enter to skip): " never_ship
|
|
1681
|
+
|
|
1682
|
+
# Q6: Focus areas for code review
|
|
1683
|
+
echo ""
|
|
1684
|
+
read -p "Focus areas for review (comma-separated, e.g., 'performance,security'): " focus_areas
|
|
1685
|
+
|
|
1686
|
+
# Q7: Deployment strategy
|
|
1687
|
+
echo ""
|
|
1688
|
+
echo -e "${DIM}Deployment strategy:${RESET}"
|
|
1689
|
+
echo " 1. direct (default)"
|
|
1690
|
+
echo " 2. preview_then_production"
|
|
1691
|
+
echo " 3. staged_rollout"
|
|
1692
|
+
read -p "Choose [1-3]: " deploy_choice
|
|
1693
|
+
|
|
1694
|
+
local deploy_strategy="direct"
|
|
1695
|
+
case "$deploy_choice" in
|
|
1696
|
+
2) deploy_strategy="preview_then_production" ;;
|
|
1697
|
+
3) deploy_strategy="staged_rollout" ;;
|
|
1698
|
+
esac
|
|
1699
|
+
|
|
1700
|
+
# Build the updated profile
|
|
1701
|
+
local never_ship_array="[]"
|
|
1702
|
+
if [[ -n "$never_ship" ]]; then
|
|
1703
|
+
never_ship_array=$(echo "$never_ship" | jq -R 'split(",") | map(ltrimstr(" ") | rtrimstr(" "))')
|
|
1704
|
+
fi
|
|
1705
|
+
|
|
1706
|
+
local focus_areas_array="[]"
|
|
1707
|
+
if [[ -n "$focus_areas" ]]; then
|
|
1708
|
+
focus_areas_array=$(echo "$focus_areas" | jq -R 'split(",") | map(ltrimstr(" ") | rtrimstr(" "))')
|
|
1709
|
+
fi
|
|
1710
|
+
|
|
1711
|
+
# Merge updates into base profile
|
|
1712
|
+
base_profile=$(echo "$base_profile" | jq \
|
|
1713
|
+
--arg max_pr "$max_pr_lines" \
|
|
1714
|
+
--arg max_f "$max_files" \
|
|
1715
|
+
--arg phil "$philosophy" \
|
|
1716
|
+
--arg arch "$arch_pattern" \
|
|
1717
|
+
--arg deploy "$deploy_strategy" \
|
|
1718
|
+
--argjson never_ship "$never_ship_array" \
|
|
1719
|
+
--argjson focus "$focus_areas_array" \
|
|
1720
|
+
'.quality.max_pr_lines = ($max_pr | tonumber) |
|
|
1721
|
+
.quality.max_files_per_pr = ($max_f | tonumber) |
|
|
1722
|
+
.quality.never_ship = $never_ship |
|
|
1723
|
+
.testing.philosophy = $phil |
|
|
1724
|
+
.architecture.pattern = $arch |
|
|
1725
|
+
.deployment.strategy = $deploy |
|
|
1726
|
+
.review.focus_areas = $focus'
|
|
1727
|
+
)
|
|
1728
|
+
else
|
|
1729
|
+
# Non-interactive: apply inferred values
|
|
1730
|
+
local test_cmd focus_areas arch_pattern
|
|
1731
|
+
test_cmd=$(echo "$inferred" | jq -r '.test_cmd')
|
|
1732
|
+
arch_pattern=$(echo "$inferred" | jq -r '.framework')
|
|
1733
|
+
|
|
1734
|
+
# Merge inferred test command and architecture
|
|
1735
|
+
if [[ -n "$test_cmd" && "$test_cmd" != "null" && "$test_cmd" != "" ]]; then
|
|
1736
|
+
base_profile=$(echo "$base_profile" | jq --arg cmd "$test_cmd" '.testing.test_cmd = $cmd')
|
|
1737
|
+
fi
|
|
1738
|
+
if [[ -n "$arch_pattern" && "$arch_pattern" != "null" && "$arch_pattern" != "" ]]; then
|
|
1739
|
+
base_profile=$(echo "$base_profile" | jq --arg arch "$arch_pattern" '.architecture.pattern = $arch')
|
|
1740
|
+
fi
|
|
1741
|
+
fi
|
|
1742
|
+
|
|
1743
|
+
# Save the profile
|
|
1744
|
+
if qp_save "$base_profile"; then
|
|
1745
|
+
success "Quality profile saved to .claude/quality-profile.json"
|
|
1746
|
+
track_file ".claude/quality-profile.json"
|
|
1747
|
+
return 0
|
|
1748
|
+
else
|
|
1749
|
+
error "Failed to save quality profile"
|
|
1750
|
+
return 1
|
|
1751
|
+
fi
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1575
1754
|
# ─── prep_report — Summary output ──────────────────────────────────────────
|
|
1576
1755
|
|
|
1577
1756
|
prep_report() {
|
|
@@ -1627,6 +1806,7 @@ main() {
|
|
|
1627
1806
|
# Generation
|
|
1628
1807
|
prep_generate_claude_md
|
|
1629
1808
|
prep_generate_settings
|
|
1809
|
+
prep_generate_managed_mcp
|
|
1630
1810
|
prep_generate_hooks
|
|
1631
1811
|
prep_generate_agents
|
|
1632
1812
|
prep_generate_architecture
|
|
@@ -1634,6 +1814,9 @@ main() {
|
|
|
1634
1814
|
prep_generate_dod
|
|
1635
1815
|
prep_generate_issue_templates
|
|
1636
1816
|
|
|
1817
|
+
# Quality profile (auto or interactive)
|
|
1818
|
+
generate_quality_profile
|
|
1819
|
+
|
|
1637
1820
|
# Deep analysis (optional)
|
|
1638
1821
|
prep_with_claude
|
|
1639
1822
|
|
package/scripts/sw-ps.sh
CHANGED
|
@@ -5,32 +5,12 @@
|
|
|
5
5
|
# ║ Displays a table of agents running in claude-* tmux windows with ║
|
|
6
6
|
# ║ PID, status, idle time, and pane references. ║
|
|
7
7
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
8
|
-
|
|
8
|
+
# shellcheck disable=SC2034
|
|
9
|
+
VERSION="3.3.0"
|
|
9
10
|
set -euo pipefail
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
# Canonical helpers (colors, output, events)
|
|
15
|
-
# shellcheck source=lib/helpers.sh
|
|
16
|
-
[[ -f "$SCRIPT_DIR/lib/helpers.sh" ]] && source "$SCRIPT_DIR/lib/helpers.sh"
|
|
17
|
-
# Fallbacks when helpers not loaded (e.g. test env with overridden SCRIPT_DIR)
|
|
18
|
-
[[ "$(type -t info 2>/dev/null)" == "function" ]] || info() { echo -e "\033[38;2;0;212;255m\033[1m▸\033[0m $*"; }
|
|
19
|
-
[[ "$(type -t success 2>/dev/null)" == "function" ]] || success() { echo -e "\033[38;2;74;222;128m\033[1m✓\033[0m $*"; }
|
|
20
|
-
[[ "$(type -t warn 2>/dev/null)" == "function" ]] || warn() { echo -e "\033[38;2;250;204;21m\033[1m⚠\033[0m $*"; }
|
|
21
|
-
[[ "$(type -t error 2>/dev/null)" == "function" ]] || error() { echo -e "\033[38;2;248;113;113m\033[1m✗\033[0m $*" >&2; }
|
|
22
|
-
if [[ "$(type -t now_iso 2>/dev/null)" != "function" ]]; then
|
|
23
|
-
now_iso() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
|
|
24
|
-
now_epoch() { date +%s; }
|
|
25
|
-
fi
|
|
26
|
-
if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
27
|
-
emit_event() {
|
|
28
|
-
local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
|
|
29
|
-
local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
|
|
30
|
-
while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
|
|
31
|
-
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
32
|
-
}
|
|
33
|
-
fi
|
|
11
|
+
|
|
12
|
+
# shellcheck source=lib/bootstrap.sh
|
|
13
|
+
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib/bootstrap.sh"
|
|
34
14
|
# ─── Format idle time ───────────────────────────────────────────────────────
|
|
35
15
|
format_idle() {
|
|
36
16
|
local seconds="$1"
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
# shellcheck disable=SC2034
|
|
10
|
+
VERSION="3.3.0"
|
|
10
11
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
12
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
12
13
|
|
|
@@ -29,7 +30,8 @@ fi
|
|
|
29
30
|
if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
30
31
|
emit_event() {
|
|
31
32
|
local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
|
|
32
|
-
local payload
|
|
33
|
+
local payload
|
|
34
|
+
payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
|
|
33
35
|
while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
|
|
34
36
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
35
37
|
}
|
|
@@ -79,11 +81,13 @@ sanitize_for_privacy() {
|
|
|
79
81
|
gather_pipeline_state() {
|
|
80
82
|
local privacy="${1:-stages_only}"
|
|
81
83
|
|
|
84
|
+
# shellcheck disable=SC2034
|
|
82
85
|
local state_file="${REPO_DIR}/.claude/pipeline-state.md"
|
|
83
86
|
local daemon_state="${HOME}/.shipwright/daemon-state.json"
|
|
84
87
|
local pipeline_artifacts="${REPO_DIR}/.claude/pipeline-artifacts"
|
|
85
88
|
|
|
86
|
-
local pipeline_data
|
|
89
|
+
local pipeline_data
|
|
90
|
+
pipeline_data='{
|
|
87
91
|
"status":"unknown",
|
|
88
92
|
"stages":[],
|
|
89
93
|
"agents":[],
|
|
@@ -112,7 +116,8 @@ gather_pipeline_state() {
|
|
|
112
116
|
# Read pipeline artifacts if available
|
|
113
117
|
if [[ -d "$pipeline_artifacts" ]]; then
|
|
114
118
|
local stage_count
|
|
115
|
-
stage_count=$(find "$pipeline_artifacts" -name "*.md" -o -name "*.json" | wc -l ||
|
|
119
|
+
stage_count=$(find "$pipeline_artifacts" -name "*.md" -o -name "*.json" | wc -l || true)
|
|
120
|
+
stage_count="${stage_count:-0}"
|
|
116
121
|
pipeline_data=$(jq --arg count "$stage_count" '.artifact_count = $count' <<<"$pipeline_data")
|
|
117
122
|
fi
|
|
118
123
|
|
|
@@ -139,6 +144,7 @@ generate_html() {
|
|
|
139
144
|
|
|
140
145
|
# Escape JSON for embedding in HTML
|
|
141
146
|
local json_escaped
|
|
147
|
+
# shellcheck disable=SC2034
|
|
142
148
|
json_escaped=$(echo "$data_json" | sed 's/"/\\"/g' | tr '\n' ' ')
|
|
143
149
|
|
|
144
150
|
cat <<'EOF'
|
|
@@ -417,6 +423,7 @@ cmd_export() {
|
|
|
417
423
|
# Atomic write
|
|
418
424
|
local tmp_file
|
|
419
425
|
tmp_file=$(mktemp)
|
|
426
|
+
# shellcheck disable=SC2064
|
|
420
427
|
trap "rm -f '$tmp_file'" EXIT
|
|
421
428
|
echo "$html" > "$tmp_file"
|
|
422
429
|
mv "$tmp_file" "$output_file"
|
|
@@ -452,6 +459,7 @@ cmd_share() {
|
|
|
452
459
|
# Append to share links file (atomic)
|
|
453
460
|
local tmp_file
|
|
454
461
|
tmp_file=$(mktemp)
|
|
462
|
+
# shellcheck disable=SC2064
|
|
455
463
|
trap "rm -f '$tmp_file'" EXIT
|
|
456
464
|
jq ".links += [$link_entry]" "$SHARE_LINKS_FILE" > "$tmp_file"
|
|
457
465
|
mv "$tmp_file" "$SHARE_LINKS_FILE"
|
|
@@ -479,6 +487,7 @@ cmd_revoke() {
|
|
|
479
487
|
|
|
480
488
|
local tmp_file
|
|
481
489
|
tmp_file=$(mktemp)
|
|
490
|
+
# shellcheck disable=SC2064
|
|
482
491
|
trap "rm -f '$tmp_file'" EXIT
|
|
483
492
|
|
|
484
493
|
if jq ".links |= map(select(.token != \"$token\"))" "$SHARE_LINKS_FILE" > "$tmp_file"; then
|
|
@@ -544,6 +553,7 @@ cmd_config() {
|
|
|
544
553
|
[[ -z "$value" ]] && error "Value required for privacy" && return 1
|
|
545
554
|
local tmp_file
|
|
546
555
|
tmp_file=$(mktemp)
|
|
556
|
+
# shellcheck disable=SC2064
|
|
547
557
|
trap "rm -f '$tmp_file'" EXIT
|
|
548
558
|
jq ".privacy = \"$value\"" "$SHARE_CONFIG_FILE" > "$tmp_file"
|
|
549
559
|
mv "$tmp_file" "$SHARE_CONFIG_FILE"
|
|
@@ -553,6 +563,7 @@ cmd_config() {
|
|
|
553
563
|
[[ -z "$value" ]] && error "Value required for expiry (hours)" && return 1
|
|
554
564
|
local tmp_file
|
|
555
565
|
tmp_file=$(mktemp)
|
|
566
|
+
# shellcheck disable=SC2064
|
|
556
567
|
trap "rm -f '$tmp_file'" EXIT
|
|
557
568
|
jq ".expiry_hours = $value" "$SHARE_CONFIG_FILE" > "$tmp_file"
|
|
558
569
|
mv "$tmp_file" "$SHARE_CONFIG_FILE"
|
|
@@ -562,6 +573,7 @@ cmd_config() {
|
|
|
562
573
|
[[ -z "$value" ]] && error "Value required for domain" && return 1
|
|
563
574
|
local tmp_file
|
|
564
575
|
tmp_file=$(mktemp)
|
|
576
|
+
# shellcheck disable=SC2064
|
|
565
577
|
trap "rm -f '$tmp_file'" EXIT
|
|
566
578
|
jq ".custom_domain = \"$value\"" "$SHARE_CONFIG_FILE" > "$tmp_file"
|
|
567
579
|
mv "$tmp_file" "$SHARE_CONFIG_FILE"
|
|
@@ -641,6 +653,7 @@ cmd_cleanup() {
|
|
|
641
653
|
|
|
642
654
|
local tmp_file
|
|
643
655
|
tmp_file=$(mktemp)
|
|
656
|
+
# shellcheck disable=SC2064
|
|
644
657
|
trap "rm -f '$tmp_file'" EXIT
|
|
645
658
|
|
|
646
659
|
jq ".links |= map(select((.expires | fromdateiso8601) > $now_epoch_val))" "$SHARE_LINKS_FILE" > "$tmp_file"
|