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-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="3.
|
|
9
|
+
VERSION="3.3.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
REPO_DIR="${REPO_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
|
|
12
12
|
|
|
@@ -29,7 +29,8 @@ fi
|
|
|
29
29
|
if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
30
30
|
emit_event() {
|
|
31
31
|
local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
|
|
32
|
-
local payload
|
|
32
|
+
local payload
|
|
33
|
+
payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
|
|
33
34
|
while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
|
|
34
35
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
35
36
|
}
|
|
@@ -42,6 +43,10 @@ fi
|
|
|
42
43
|
# shellcheck source=sw-intelligence.sh
|
|
43
44
|
[[ -f "$SCRIPT_DIR/sw-intelligence.sh" ]] && source "$SCRIPT_DIR/sw-intelligence.sh"
|
|
44
45
|
|
|
46
|
+
# ─── Memory Effectiveness Tracker ──────────────────────────────────────────
|
|
47
|
+
# shellcheck source=lib/memory-effectiveness.sh
|
|
48
|
+
[[ -f "$SCRIPT_DIR/lib/memory-effectiveness.sh" ]] && source "$SCRIPT_DIR/lib/memory-effectiveness.sh"
|
|
49
|
+
|
|
45
50
|
# ─── Memory Storage Paths ──────────────────────────────────────────────────
|
|
46
51
|
MEMORY_ROOT="${HOME}/.shipwright/memory"
|
|
47
52
|
GLOBAL_MEMORY="${MEMORY_ROOT}/global.json"
|
|
@@ -217,6 +222,7 @@ memory_semantic_search() {
|
|
|
217
222
|
|
|
218
223
|
# Inject relevant memories into agent prompts (goal-based)
|
|
219
224
|
memory_inject_goal_context() {
|
|
225
|
+
# shellcheck disable=SC2034
|
|
220
226
|
local goal="$1" repo_hash="${2:-}" max_tokens="${3:-2000}"
|
|
221
227
|
|
|
222
228
|
local memories
|
|
@@ -330,6 +336,7 @@ memory_capture_pipeline() {
|
|
|
330
336
|
# Record review patterns to global memory for cross-repo learning
|
|
331
337
|
local tmp_global
|
|
332
338
|
tmp_global=$(mktemp)
|
|
339
|
+
# shellcheck disable=SC2064
|
|
333
340
|
trap "rm -f '$tmp_global'" RETURN
|
|
334
341
|
jq --arg repo "$repo" \
|
|
335
342
|
--arg ts "$captured_at" \
|
|
@@ -395,6 +402,7 @@ memory_capture_failure() {
|
|
|
395
402
|
fi
|
|
396
403
|
local tmp_file
|
|
397
404
|
tmp_file=$(mktemp "${failures_file}.tmp.XXXXXX")
|
|
405
|
+
# shellcheck disable=SC2064
|
|
398
406
|
trap "rm -f '$tmp_file'" EXIT
|
|
399
407
|
|
|
400
408
|
if [[ "$existing_idx" != "-1" && "$existing_idx" != "null" ]]; then
|
|
@@ -471,6 +479,7 @@ memory_record_fix_outcome() {
|
|
|
471
479
|
fi
|
|
472
480
|
local tmp_file
|
|
473
481
|
tmp_file=$(mktemp "${failures_file}.tmp.XXXXXX")
|
|
482
|
+
# shellcheck disable=SC2064
|
|
474
483
|
trap "rm -f '$tmp_file'" EXIT
|
|
475
484
|
|
|
476
485
|
jq --argjson idx "$match_idx" \
|
|
@@ -637,6 +646,7 @@ _memory_aggregate_global() {
|
|
|
637
646
|
# Add to global, cap at 100 entries
|
|
638
647
|
local tmp_global
|
|
639
648
|
tmp_global=$(mktemp "${global_file}.tmp.XXXXXX")
|
|
649
|
+
# shellcheck disable=SC2064
|
|
640
650
|
trap "rm -f '$tmp_global'" RETURN
|
|
641
651
|
jq --arg p "$pattern" \
|
|
642
652
|
--arg ts "$(now_iso)" \
|
|
@@ -725,7 +735,7 @@ memory_analyze_failure() {
|
|
|
725
735
|
"$failures_file" 2>/dev/null || true)
|
|
726
736
|
fi
|
|
727
737
|
|
|
728
|
-
# Build valid categories list (from compat.sh if available, else
|
|
738
|
+
# Build valid categories list (from compat.sh if available, else built-in defaults)
|
|
729
739
|
local valid_cats="test_failure, build_error, lint_error, timeout, dependency, flaky, config"
|
|
730
740
|
if [[ -n "${SW_ERROR_CATEGORIES:-}" ]]; then
|
|
731
741
|
valid_cats=$(echo "$SW_ERROR_CATEGORIES" | tr ' ' ', ')
|
|
@@ -789,6 +799,7 @@ Return JSON only, no markdown fences, no explanation."
|
|
|
789
799
|
# Update the most recent failure entry with root_cause, fix, category
|
|
790
800
|
local tmp_file
|
|
791
801
|
tmp_file=$(mktemp)
|
|
802
|
+
# shellcheck disable=SC2064
|
|
792
803
|
trap "rm -f '$tmp_file'" RETURN
|
|
793
804
|
jq --arg rc "$root_cause" \
|
|
794
805
|
--arg fix "$fix" \
|
|
@@ -819,6 +830,7 @@ memory_capture_pattern() {
|
|
|
819
830
|
|
|
820
831
|
local tmp_file
|
|
821
832
|
tmp_file=$(mktemp)
|
|
833
|
+
# shellcheck disable=SC2064
|
|
822
834
|
trap "rm -f '$tmp_file'" RETURN
|
|
823
835
|
|
|
824
836
|
case "$pattern_type" in
|
|
@@ -1337,6 +1349,7 @@ memory_update_metrics() {
|
|
|
1337
1349
|
# Update baseline using atomic write
|
|
1338
1350
|
local tmp_file
|
|
1339
1351
|
tmp_file=$(mktemp)
|
|
1352
|
+
# shellcheck disable=SC2064
|
|
1340
1353
|
trap "rm -f '$tmp_file'" RETURN
|
|
1341
1354
|
jq --arg m "$metric_name" \
|
|
1342
1355
|
--argjson v "$value" \
|
|
@@ -1361,6 +1374,7 @@ memory_capture_decision() {
|
|
|
1361
1374
|
|
|
1362
1375
|
local tmp_file
|
|
1363
1376
|
tmp_file=$(mktemp)
|
|
1377
|
+
# shellcheck disable=SC2064
|
|
1364
1378
|
trap "rm -f '$tmp_file'" RETURN
|
|
1365
1379
|
jq --arg type "$dec_type" \
|
|
1366
1380
|
--arg summary "$summary" \
|
|
@@ -1702,6 +1716,7 @@ memory_import() {
|
|
|
1702
1716
|
# Extract and write each section
|
|
1703
1717
|
local tmp_file
|
|
1704
1718
|
tmp_file=$(mktemp)
|
|
1719
|
+
# shellcheck disable=SC2064
|
|
1705
1720
|
trap "rm -f '$tmp_file'" RETURN
|
|
1706
1721
|
|
|
1707
1722
|
jq '.patterns // {}' "$import_file" > "$tmp_file" && mv "$tmp_file" "$mem_dir/patterns.json"
|
|
@@ -1787,6 +1802,219 @@ memory_stats() {
|
|
|
1787
1802
|
echo ""
|
|
1788
1803
|
}
|
|
1789
1804
|
|
|
1805
|
+
# ─── A/B Testing Framework ─────────────────────────────────────────────────
|
|
1806
|
+
# Test memory system effectiveness by randomly assigning control vs treatment.
|
|
1807
|
+
# - Control: pipeline runs without memory injection
|
|
1808
|
+
# - Treatment: pipeline runs with memory injection
|
|
1809
|
+
# Emits events to track metrics: iterations, cost, test_failures, completion_status
|
|
1810
|
+
|
|
1811
|
+
AB_RESULTS_DIR="${HOME}/.shipwright/memory"
|
|
1812
|
+
AB_RESULTS_FILE="${AB_RESULTS_DIR}/ab-results.jsonl"
|
|
1813
|
+
|
|
1814
|
+
# Assign control or treatment for this pipeline run
|
|
1815
|
+
# Returns: "control" or "treatment"
|
|
1816
|
+
memory_ab_assign_group() {
|
|
1817
|
+
local ab_ratio="${1:-0.2}" # Read from daemon-config intelligence.ab_test_ratio
|
|
1818
|
+
|
|
1819
|
+
# Validate ratio is between 0 and 1
|
|
1820
|
+
if ! echo "$ab_ratio" | grep -qE '^0(\.[0-9]+)?$|^1(\.0+)?$'; then
|
|
1821
|
+
ab_ratio="0.2"
|
|
1822
|
+
fi
|
|
1823
|
+
|
|
1824
|
+
# Generate random 0-100
|
|
1825
|
+
local rand=$((RANDOM % 100))
|
|
1826
|
+
local threshold=$(echo "$ab_ratio * 100" | bc 2>/dev/null || echo "20")
|
|
1827
|
+
threshold=${threshold%.*} # Remove decimal
|
|
1828
|
+
|
|
1829
|
+
if [[ "$rand" -lt "$threshold" ]]; then
|
|
1830
|
+
echo "control"
|
|
1831
|
+
else
|
|
1832
|
+
echo "treatment"
|
|
1833
|
+
fi
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
# Record A/B test assignment at pipeline start
|
|
1837
|
+
# $1: pipeline_id
|
|
1838
|
+
# $2: group (control|treatment)
|
|
1839
|
+
memory_ab_record_assignment() {
|
|
1840
|
+
local pipeline_id="$1"
|
|
1841
|
+
local group="${2:-}"
|
|
1842
|
+
|
|
1843
|
+
[[ -z "$pipeline_id" || -z "$group" ]] && return 1
|
|
1844
|
+
|
|
1845
|
+
# Emit event for tracking
|
|
1846
|
+
emit_event "memory.ab_assigned" \
|
|
1847
|
+
"pipeline_id=$pipeline_id" \
|
|
1848
|
+
"group=$group" \
|
|
1849
|
+
"timestamp=$(now_iso)"
|
|
1850
|
+
|
|
1851
|
+
return 0
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
# Record A/B test result after pipeline completion
|
|
1855
|
+
# $1: pipeline_id
|
|
1856
|
+
# $2: group (control|treatment)
|
|
1857
|
+
# $3: iterations (number of build iterations)
|
|
1858
|
+
# $4: cost (estimated token cost)
|
|
1859
|
+
# $5: test_failures (number of test failures)
|
|
1860
|
+
# $6: completion_status (success|failure)
|
|
1861
|
+
memory_ab_record_result() {
|
|
1862
|
+
local pipeline_id="$1"
|
|
1863
|
+
local group="$2"
|
|
1864
|
+
local iterations="$3"
|
|
1865
|
+
local cost="$4"
|
|
1866
|
+
local test_failures="$5"
|
|
1867
|
+
local completion_status="$6"
|
|
1868
|
+
|
|
1869
|
+
[[ -z "$pipeline_id" || -z "$group" ]] && return 1
|
|
1870
|
+
|
|
1871
|
+
mkdir -p "$AB_RESULTS_DIR"
|
|
1872
|
+
|
|
1873
|
+
# Record result as JSONL
|
|
1874
|
+
local result_json
|
|
1875
|
+
result_json=$(jq -n \
|
|
1876
|
+
--arg pipeline_id "$pipeline_id" \
|
|
1877
|
+
--arg group "$group" \
|
|
1878
|
+
--arg timestamp "$(now_iso)" \
|
|
1879
|
+
--arg iterations "$iterations" \
|
|
1880
|
+
--arg cost "$cost" \
|
|
1881
|
+
--arg test_failures "$test_failures" \
|
|
1882
|
+
--arg completion_status "$completion_status" \
|
|
1883
|
+
'{
|
|
1884
|
+
pipeline_id: $pipeline_id,
|
|
1885
|
+
group: $group,
|
|
1886
|
+
timestamp: $timestamp,
|
|
1887
|
+
iterations: ($iterations | tonumber? // 0),
|
|
1888
|
+
cost: ($cost | tonumber? // 0),
|
|
1889
|
+
test_failures: ($test_failures | tonumber? // 0),
|
|
1890
|
+
completion_status: $completion_status
|
|
1891
|
+
}')
|
|
1892
|
+
|
|
1893
|
+
echo "$result_json" >> "$AB_RESULTS_FILE"
|
|
1894
|
+
|
|
1895
|
+
# Emit event
|
|
1896
|
+
emit_event "memory.ab_result" \
|
|
1897
|
+
"pipeline_id=$pipeline_id" \
|
|
1898
|
+
"group=$group" \
|
|
1899
|
+
"iterations=$iterations" \
|
|
1900
|
+
"cost=$cost" \
|
|
1901
|
+
"test_failures=$test_failures" \
|
|
1902
|
+
"completion_status=$completion_status"
|
|
1903
|
+
|
|
1904
|
+
return 0
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
# Generate A/B test report comparing control vs treatment
|
|
1908
|
+
cmd_memory_ab_report() {
|
|
1909
|
+
if [[ ! -f "$AB_RESULTS_FILE" ]]; then
|
|
1910
|
+
warn "No A/B test results found at $AB_RESULTS_FILE"
|
|
1911
|
+
return 1
|
|
1912
|
+
fi
|
|
1913
|
+
|
|
1914
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
1915
|
+
error "jq required for A/B report generation"
|
|
1916
|
+
return 1
|
|
1917
|
+
fi
|
|
1918
|
+
|
|
1919
|
+
info "Memory A/B Test Report"
|
|
1920
|
+
echo ""
|
|
1921
|
+
|
|
1922
|
+
local control_count treatment_count
|
|
1923
|
+
control_count=$(grep -c '"control"' "$AB_RESULTS_FILE" 2>/dev/null || echo "0")
|
|
1924
|
+
treatment_count=$(grep -c '"treatment"' "$AB_RESULTS_FILE" 2>/dev/null || echo "0")
|
|
1925
|
+
|
|
1926
|
+
echo -e "${BOLD}Sample Sizes${RESET}"
|
|
1927
|
+
printf " Control: %3d pipelines\n" "$control_count"
|
|
1928
|
+
printf " Treatment: %3d pipelines\n" "$treatment_count"
|
|
1929
|
+
echo ""
|
|
1930
|
+
|
|
1931
|
+
# Calculate metrics for control group
|
|
1932
|
+
local control_data
|
|
1933
|
+
control_data=$(grep '"control"' "$AB_RESULTS_FILE" 2>/dev/null | jq -s '
|
|
1934
|
+
if length == 0 then
|
|
1935
|
+
{count: 0, avg_iterations: 0, avg_cost: 0, success_rate: 0}
|
|
1936
|
+
else
|
|
1937
|
+
{
|
|
1938
|
+
count: length,
|
|
1939
|
+
avg_iterations: ([.[].iterations // 0] | add / length | floor),
|
|
1940
|
+
avg_cost: ([.[].cost // 0] | add / length | floor),
|
|
1941
|
+
success_rate: (([.[] | select(.completion_status == "success")] | length) / length * 100 | floor)
|
|
1942
|
+
}
|
|
1943
|
+
end
|
|
1944
|
+
' || echo '{"count": 0, "avg_iterations": 0, "avg_cost": 0, "success_rate": 0}')
|
|
1945
|
+
|
|
1946
|
+
# Calculate metrics for treatment group
|
|
1947
|
+
local treatment_data
|
|
1948
|
+
treatment_data=$(grep '"treatment"' "$AB_RESULTS_FILE" 2>/dev/null | jq -s '
|
|
1949
|
+
if length == 0 then
|
|
1950
|
+
{count: 0, avg_iterations: 0, avg_cost: 0, success_rate: 0}
|
|
1951
|
+
else
|
|
1952
|
+
{
|
|
1953
|
+
count: length,
|
|
1954
|
+
avg_iterations: ([.[].iterations // 0] | add / length | floor),
|
|
1955
|
+
avg_cost: ([.[].cost // 0] | add / length | floor),
|
|
1956
|
+
success_rate: (([.[] | select(.completion_status == "success")] | length) / length * 100 | floor)
|
|
1957
|
+
}
|
|
1958
|
+
end
|
|
1959
|
+
' || echo '{"count": 0, "avg_iterations": 0, "avg_cost": 0, "success_rate": 0}')
|
|
1960
|
+
|
|
1961
|
+
# Extract values
|
|
1962
|
+
local c_iterations t_iterations c_cost t_cost c_success t_success
|
|
1963
|
+
c_iterations=$(echo "$control_data" | jq -r '.avg_iterations // 0')
|
|
1964
|
+
t_iterations=$(echo "$treatment_data" | jq -r '.avg_iterations // 0')
|
|
1965
|
+
c_cost=$(echo "$control_data" | jq -r '.avg_cost // 0')
|
|
1966
|
+
t_cost=$(echo "$treatment_data" | jq -r '.avg_cost // 0')
|
|
1967
|
+
c_success=$(echo "$control_data" | jq -r '.success_rate // 0')
|
|
1968
|
+
t_success=$(echo "$treatment_data" | jq -r '.success_rate // 0')
|
|
1969
|
+
|
|
1970
|
+
# Calculate deltas
|
|
1971
|
+
local iter_delta cost_delta success_delta
|
|
1972
|
+
iter_delta=$((c_iterations - t_iterations))
|
|
1973
|
+
cost_delta=$((c_cost - t_cost))
|
|
1974
|
+
success_delta=$((t_success - c_success))
|
|
1975
|
+
|
|
1976
|
+
# Direction indicators
|
|
1977
|
+
local iter_dir cost_dir success_dir
|
|
1978
|
+
[[ $iter_delta -gt 0 ]] && iter_dir="${GREEN}↓${RESET}" || iter_dir="${RED}↑${RESET}"
|
|
1979
|
+
[[ $cost_delta -gt 0 ]] && cost_dir="${GREEN}↓${RESET}" || cost_dir="${RED}↑${RESET}"
|
|
1980
|
+
[[ $success_delta -gt 0 ]] && success_dir="${GREEN}↑${RESET}" || success_dir="${RED}↓${RESET}"
|
|
1981
|
+
|
|
1982
|
+
echo -e "${BOLD}Metrics${RESET}"
|
|
1983
|
+
echo ""
|
|
1984
|
+
printf " %-28s %10s %10s %10s\n" "Metric" "Control" "Treatment" "Delta"
|
|
1985
|
+
printf " %s\n" "$(printf '%.0s-' {1..60})"
|
|
1986
|
+
printf " %-28s %10d %10d %10s %s\n" "Avg Iterations" "$c_iterations" "$t_iterations" "$iter_delta" "$iter_dir"
|
|
1987
|
+
printf " %-28s %10d %10d %10s %s\n" "Avg Cost (tokens)" "$c_cost" "$t_cost" "$cost_delta" "$cost_dir"
|
|
1988
|
+
printf " %-28s %10d%% %10d%% %10s %s\n" "Success Rate" "$c_success" "$t_success" "$success_delta" "$success_dir"
|
|
1989
|
+
echo ""
|
|
1990
|
+
|
|
1991
|
+
# Summary
|
|
1992
|
+
echo -e "${BOLD}Summary${RESET}"
|
|
1993
|
+
if [[ $iter_delta -gt 0 ]]; then
|
|
1994
|
+
success "Memory injection reduces iterations by ${iter_delta} (${GREEN}$(echo "scale=1; $iter_delta * 100 / $c_iterations" | bc)% improvement${RESET})"
|
|
1995
|
+
elif [[ $iter_delta -lt 0 ]]; then
|
|
1996
|
+
warn "Memory injection increases iterations by $((iter_delta * -1)) (regression)"
|
|
1997
|
+
else
|
|
1998
|
+
info "No significant difference in iteration count"
|
|
1999
|
+
fi
|
|
2000
|
+
|
|
2001
|
+
if [[ $cost_delta -gt 0 ]]; then
|
|
2002
|
+
success "Memory injection reduces cost by ${cost_delta} tokens (${GREEN}$(echo "scale=1; $cost_delta * 100 / $c_cost" | bc)% savings${RESET})"
|
|
2003
|
+
elif [[ $cost_delta -lt 0 ]]; then
|
|
2004
|
+
warn "Memory injection increases cost by $((cost_delta * -1)) tokens (regression)"
|
|
2005
|
+
fi
|
|
2006
|
+
|
|
2007
|
+
if [[ $success_delta -gt 0 ]]; then
|
|
2008
|
+
success "Memory injection improves success rate by ${success_delta}pp (${GREEN}$(echo "scale=1; $success_delta" | bc)% better${RESET})"
|
|
2009
|
+
elif [[ $success_delta -lt 0 ]]; then
|
|
2010
|
+
warn "Memory injection reduces success rate by $((success_delta * -1))pp (regression)"
|
|
2011
|
+
fi
|
|
2012
|
+
|
|
2013
|
+
echo ""
|
|
2014
|
+
echo -e "${PURPLE}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
|
|
2015
|
+
echo ""
|
|
2016
|
+
}
|
|
2017
|
+
|
|
1790
2018
|
# ─── Help ──────────────────────────────────────────────────────────────────
|
|
1791
2019
|
|
|
1792
2020
|
show_help() {
|
|
@@ -1813,6 +2041,7 @@ show_help() {
|
|
|
1813
2041
|
echo -e " ${CYAN}decision${RESET} <type> <summary> Record a design decision"
|
|
1814
2042
|
echo -e " ${CYAN}analyze-failure${RESET} <log> <stage> Analyze failure root cause via AI"
|
|
1815
2043
|
echo -e " ${CYAN}fix-outcome${RESET} <pattern> <applied> <resolved> Record fix effectiveness"
|
|
2044
|
+
echo -e " ${CYAN}ab-report${RESET} Compare control vs treatment in A/B tests"
|
|
1816
2045
|
echo ""
|
|
1817
2046
|
echo -e "${BOLD}EXAMPLES${RESET}"
|
|
1818
2047
|
echo -e " ${DIM}shipwright memory show${RESET} # View repo memory"
|
|
@@ -1824,6 +2053,122 @@ show_help() {
|
|
|
1824
2053
|
echo -e " ${DIM}shipwright memory inject build${RESET} # Get context for build stage"
|
|
1825
2054
|
}
|
|
1826
2055
|
|
|
2056
|
+
# ─── Weighted Search (RL integration) ──────────────────────────────────────
|
|
2057
|
+
|
|
2058
|
+
# Search memory with recency + success weighting.
|
|
2059
|
+
# Args: $1=query, $2=memory_dir (optional), $3=max_results (default 5)
|
|
2060
|
+
# Returns JSON array of results with recency_weight applied.
|
|
2061
|
+
memory_search_weighted() {
|
|
2062
|
+
local query="${1:-}"
|
|
2063
|
+
local memory_dir="${2:-}"
|
|
2064
|
+
local max_results="${3:-5}"
|
|
2065
|
+
|
|
2066
|
+
if [[ -z "$memory_dir" ]] && type repo_memory_dir >/dev/null 2>&1; then
|
|
2067
|
+
memory_dir="$(repo_memory_dir)"
|
|
2068
|
+
fi
|
|
2069
|
+
memory_dir="${memory_dir:-$HOME/.shipwright/memory}"
|
|
2070
|
+
|
|
2071
|
+
if [[ ! -d "$memory_dir" ]]; then
|
|
2072
|
+
echo "[]"
|
|
2073
|
+
return 0
|
|
2074
|
+
fi
|
|
2075
|
+
|
|
2076
|
+
# Get base ranked results
|
|
2077
|
+
local base_results
|
|
2078
|
+
base_results="$(memory_ranked_search "$query" "$memory_dir" "$max_results" 2>/dev/null || echo "[]")"
|
|
2079
|
+
|
|
2080
|
+
if [[ "$base_results" == "[]" ]] || [[ -z "$base_results" ]]; then
|
|
2081
|
+
echo "[]"
|
|
2082
|
+
return 0
|
|
2083
|
+
fi
|
|
2084
|
+
|
|
2085
|
+
# Apply recency weighting: boost results from files modified recently
|
|
2086
|
+
local now_epoch
|
|
2087
|
+
now_epoch="$(date +%s)"
|
|
2088
|
+
|
|
2089
|
+
echo "$base_results" | jq --argjson now "$now_epoch" '
|
|
2090
|
+
[.[] | . + {
|
|
2091
|
+
recency_weight: (
|
|
2092
|
+
if .timestamp then
|
|
2093
|
+
(($now - (.timestamp // $now)) / 86400) as $age |
|
|
2094
|
+
if $age <= 7 then 1.5
|
|
2095
|
+
elif $age <= 30 then 1.0
|
|
2096
|
+
elif $age <= 90 then 0.7
|
|
2097
|
+
else 0.4 end
|
|
2098
|
+
else 0.8 end
|
|
2099
|
+
)
|
|
2100
|
+
}] |
|
|
2101
|
+
[.[] | .combined_score = ((.relevance // 50) * .recency_weight)] |
|
|
2102
|
+
sort_by(-.combined_score)
|
|
2103
|
+
' 2>/dev/null || echo "$base_results"
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
# Reduce weight of memory entries older than threshold.
|
|
2107
|
+
# Args: $1=days_threshold (default 30), $2=memory_dir (optional)
|
|
2108
|
+
memory_decay_old() {
|
|
2109
|
+
local days_threshold="${1:-30}"
|
|
2110
|
+
local memory_dir="${2:-}"
|
|
2111
|
+
|
|
2112
|
+
if [[ -z "$memory_dir" ]] && type repo_memory_dir >/dev/null 2>&1; then
|
|
2113
|
+
memory_dir="$(repo_memory_dir)"
|
|
2114
|
+
fi
|
|
2115
|
+
memory_dir="${memory_dir:-$HOME/.shipwright/memory}"
|
|
2116
|
+
|
|
2117
|
+
if [[ ! -d "$memory_dir" ]]; then
|
|
2118
|
+
return 0
|
|
2119
|
+
fi
|
|
2120
|
+
|
|
2121
|
+
local now_epoch decayed_count
|
|
2122
|
+
now_epoch="$(date +%s)"
|
|
2123
|
+
decayed_count=0
|
|
2124
|
+
local threshold_epoch
|
|
2125
|
+
threshold_epoch=$(( now_epoch - (days_threshold * 86400) ))
|
|
2126
|
+
|
|
2127
|
+
# Process failure patterns file if it exists
|
|
2128
|
+
local failures_file="${memory_dir}/failures.json"
|
|
2129
|
+
if [[ -f "$failures_file" ]]; then
|
|
2130
|
+
local tmp
|
|
2131
|
+
tmp="$(mktemp 2>/dev/null || echo "${TMPDIR:-/tmp}/mem-decay-$$.tmp")"
|
|
2132
|
+
jq --argjson threshold "$threshold_epoch" --argjson half "$days_threshold" '
|
|
2133
|
+
if type == "array" then
|
|
2134
|
+
[.[] | if (.timestamp // 0) < $threshold then
|
|
2135
|
+
.weight = ((.weight // 1) * 0.5 | if . < 0.1 then 0.1 else . end)
|
|
2136
|
+
else . end]
|
|
2137
|
+
else . end
|
|
2138
|
+
' "$failures_file" > "$tmp" 2>/dev/null
|
|
2139
|
+
if [[ -s "$tmp" ]]; then
|
|
2140
|
+
mv "$tmp" "$failures_file"
|
|
2141
|
+
decayed_count=$((decayed_count + 1))
|
|
2142
|
+
else
|
|
2143
|
+
rm -f "$tmp"
|
|
2144
|
+
fi
|
|
2145
|
+
fi
|
|
2146
|
+
|
|
2147
|
+
# Process decisions file if it exists
|
|
2148
|
+
local decisions_file="${memory_dir}/decisions.json"
|
|
2149
|
+
if [[ -f "$decisions_file" ]]; then
|
|
2150
|
+
local tmp
|
|
2151
|
+
tmp="$(mktemp 2>/dev/null || echo "${TMPDIR:-/tmp}/mem-decay2-$$.tmp")"
|
|
2152
|
+
jq --argjson threshold "$threshold_epoch" '
|
|
2153
|
+
if type == "array" then
|
|
2154
|
+
[.[] | if (.timestamp // 0) < $threshold then
|
|
2155
|
+
.weight = ((.weight // 1) * 0.5 | if . < 0.1 then 0.1 else . end)
|
|
2156
|
+
else . end]
|
|
2157
|
+
else . end
|
|
2158
|
+
' "$decisions_file" > "$tmp" 2>/dev/null
|
|
2159
|
+
if [[ -s "$tmp" ]]; then
|
|
2160
|
+
mv "$tmp" "$decisions_file"
|
|
2161
|
+
decayed_count=$((decayed_count + 1))
|
|
2162
|
+
else
|
|
2163
|
+
rm -f "$tmp"
|
|
2164
|
+
fi
|
|
2165
|
+
fi
|
|
2166
|
+
|
|
2167
|
+
if [[ "$decayed_count" -gt 0 ]]; then
|
|
2168
|
+
emit_event "memory.decay_applied" "files=$decayed_count" "threshold_days=$days_threshold"
|
|
2169
|
+
fi
|
|
2170
|
+
}
|
|
2171
|
+
|
|
1827
2172
|
# ─── Command Router ─────────────────────────────────────────────────────────
|
|
1828
2173
|
|
|
1829
2174
|
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
|
@@ -1873,6 +2218,15 @@ if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
|
|
1873
2218
|
fix-outcome)
|
|
1874
2219
|
memory_record_fix_outcome "$@"
|
|
1875
2220
|
;;
|
|
2221
|
+
search-weighted)
|
|
2222
|
+
memory_search_weighted "$@"
|
|
2223
|
+
;;
|
|
2224
|
+
decay)
|
|
2225
|
+
memory_decay_old "$@"
|
|
2226
|
+
;;
|
|
2227
|
+
ab-report)
|
|
2228
|
+
cmd_memory_ab_report "$@"
|
|
2229
|
+
;;
|
|
1876
2230
|
help|--help|-h)
|
|
1877
2231
|
show_help
|
|
1878
2232
|
;;
|
|
@@ -7,8 +7,10 @@
|
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
# shellcheck disable=SC2034
|
|
11
|
+
VERSION="3.3.0"
|
|
11
12
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
|
+
# shellcheck disable=SC2034
|
|
12
14
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
13
15
|
|
|
14
16
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
|
@@ -30,6 +32,7 @@ fi
|
|
|
30
32
|
if [[ "$(type -t emit_event 2>/dev/null)" != "function" ]]; then
|
|
31
33
|
emit_event() {
|
|
32
34
|
local event_type="$1"; shift; mkdir -p "${HOME}/.shipwright"
|
|
35
|
+
# shellcheck disable=SC2155
|
|
33
36
|
local payload="{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"$event_type\""
|
|
34
37
|
while [[ $# -gt 0 ]]; do local key="${1%%=*}" val="${1#*=}"; payload="${payload},\"${key}\":\"${val}\""; shift; done
|
|
35
38
|
echo "${payload}}" >> "${HOME}/.shipwright/events.jsonl"
|
|
@@ -100,6 +103,7 @@ get_recent_alerts() {
|
|
|
100
103
|
tail -"$limit" | while IFS= read -r line; do
|
|
101
104
|
local ts
|
|
102
105
|
local type
|
|
106
|
+
# shellcheck disable=SC2034
|
|
103
107
|
local msg
|
|
104
108
|
|
|
105
109
|
ts=$(echo "$line" | jq -r '.ts // ""' 2>/dev/null || echo "")
|
|
@@ -167,6 +171,7 @@ show_overview() {
|
|
|
167
171
|
2>/dev/null | while IFS= read -r line; do
|
|
168
172
|
local issue
|
|
169
173
|
local title
|
|
174
|
+
# shellcheck disable=SC2034
|
|
170
175
|
local worktree
|
|
171
176
|
|
|
172
177
|
issue=$(echo "$line" | jq -r '.[0]' 2>/dev/null || echo "")
|