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
|
@@ -3,10 +3,27 @@
|
|
|
3
3
|
[[ -n "${_DAEMON_STATE_LOADED:-}" ]] && return 0
|
|
4
4
|
_DAEMON_STATE_LOADED=1
|
|
5
5
|
|
|
6
|
+
# Defaults for variables normally set by sw-daemon.sh (safe under set -u).
|
|
7
|
+
DAEMON_DIR="${DAEMON_DIR:-${HOME}/.shipwright}"
|
|
8
|
+
STATE_FILE="${STATE_FILE:-${DAEMON_DIR}/daemon-state.json}"
|
|
9
|
+
LOG_FILE="${LOG_FILE:-${DAEMON_DIR}/daemon.log}"
|
|
10
|
+
LOG_DIR="${LOG_DIR:-${DAEMON_DIR}/logs}"
|
|
11
|
+
PAUSE_FLAG="${PAUSE_FLAG:-${DAEMON_DIR}/daemon-pause.flag}"
|
|
12
|
+
DB_FILE="${DB_FILE:-${DAEMON_DIR}/shipwright.db}"
|
|
13
|
+
BASE_BRANCH="${BASE_BRANCH:-main}"
|
|
14
|
+
MAX_PARALLEL="${MAX_PARALLEL:-4}"
|
|
15
|
+
POLL_INTERVAL="${POLL_INTERVAL:-60}"
|
|
16
|
+
WATCH_LABEL="${WATCH_LABEL:-shipwright}"
|
|
17
|
+
WATCH_MODE="${WATCH_MODE:-repo}"
|
|
18
|
+
DASHBOARD_URL="${DASHBOARD_URL:-}"
|
|
19
|
+
SLACK_WEBHOOK="${SLACK_WEBHOOK:-}"
|
|
20
|
+
|
|
6
21
|
# SQLite persistence (DB as primary read path)
|
|
7
22
|
_DAEMON_STATE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
23
|
[[ -f "${_DAEMON_STATE_DIR}/../sw-db.sh" ]] && source "${_DAEMON_STATE_DIR}/../sw-db.sh"
|
|
9
24
|
|
|
25
|
+
DAEMON_LOG_WRITE_COUNT=0
|
|
26
|
+
|
|
10
27
|
daemon_log() {
|
|
11
28
|
local level="$1"
|
|
12
29
|
shift
|
|
@@ -133,47 +150,37 @@ daemon_preflight_auth_check() {
|
|
|
133
150
|
pause_json=$(jq -n --arg reason "gh_auth_failure" --arg ts "$(now_iso)" \
|
|
134
151
|
'{reason: $reason, timestamp: $ts}')
|
|
135
152
|
local _tmp_pause
|
|
136
|
-
_tmp_pause=$(mktemp "${TMPDIR:-/tmp}/sw-pause.XXXXXX")
|
|
153
|
+
_tmp_pause=$(mktemp "${TMPDIR:-/tmp}/sw-pause.XXXXXX") || { daemon_log ERROR "mktemp failed for pause flag"; return 1; }
|
|
137
154
|
echo "$pause_json" > "$_tmp_pause"
|
|
138
|
-
mv "$_tmp_pause" "$PAUSE_FLAG"
|
|
155
|
+
mv "$_tmp_pause" "$PAUSE_FLAG" || rm -f "$_tmp_pause"
|
|
139
156
|
emit_event "daemon.auto_pause" "reason=gh_auth_failure"
|
|
140
157
|
return 1
|
|
141
158
|
fi
|
|
142
159
|
fi
|
|
143
160
|
|
|
144
|
-
# claude auth check
|
|
161
|
+
# claude auth check — verify CLI is available and responsive
|
|
162
|
+
# Note: `claude --print` hangs in non-interactive environments (tmux, background).
|
|
163
|
+
# Use `claude --version` (fast, non-interactive) to verify the binary works.
|
|
164
|
+
# Actual API auth is validated when pipelines run `claude` with real prompts.
|
|
145
165
|
local claude_auth_ok=false
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
sleep 1
|
|
153
|
-
_auth_waited=$((_auth_waited + 1))
|
|
154
|
-
done
|
|
155
|
-
if kill -0 "$_auth_pid" 2>/dev/null; then
|
|
156
|
-
kill "$_auth_pid" 2>/dev/null || true
|
|
157
|
-
wait "$_auth_pid" 2>/dev/null || true
|
|
158
|
-
else
|
|
159
|
-
wait "$_auth_pid" 2>/dev/null || true
|
|
160
|
-
fi
|
|
161
|
-
|
|
162
|
-
if [[ -s "$_auth_tmp" ]]; then
|
|
163
|
-
claude_auth_ok=true
|
|
166
|
+
if command -v claude >/dev/null 2>&1; then
|
|
167
|
+
local _ver
|
|
168
|
+
_ver=$(unset CLAUDECODE; claude --version 2>/dev/null || true)
|
|
169
|
+
if [[ -n "$_ver" ]]; then
|
|
170
|
+
claude_auth_ok=true
|
|
171
|
+
fi
|
|
164
172
|
fi
|
|
165
|
-
rm -f "$_auth_tmp"
|
|
166
173
|
|
|
167
174
|
if [[ "$claude_auth_ok" != "true" ]]; then
|
|
168
|
-
daemon_log ERROR "Claude
|
|
175
|
+
daemon_log ERROR "Claude CLI not found or not working — auto-pausing daemon"
|
|
169
176
|
local pause_json
|
|
170
|
-
pause_json=$(jq -n --arg reason "
|
|
177
|
+
pause_json=$(jq -n --arg reason "claude_cli_missing" --arg ts "$(now_iso)" \
|
|
171
178
|
'{reason: $reason, timestamp: $ts}')
|
|
172
179
|
local _tmp_pause
|
|
173
|
-
_tmp_pause=$(mktemp "${TMPDIR:-/tmp}/sw-pause.XXXXXX")
|
|
180
|
+
_tmp_pause=$(mktemp "${TMPDIR:-/tmp}/sw-pause.XXXXXX") || { daemon_log ERROR "mktemp failed for pause flag"; return 1; }
|
|
174
181
|
echo "$pause_json" > "$_tmp_pause"
|
|
175
|
-
mv "$_tmp_pause" "$PAUSE_FLAG"
|
|
176
|
-
emit_event "daemon.auto_pause" "reason=
|
|
182
|
+
mv "$_tmp_pause" "$PAUSE_FLAG" || rm -f "$_tmp_pause"
|
|
183
|
+
emit_event "daemon.auto_pause" "reason=claude_cli_missing"
|
|
177
184
|
return 1
|
|
178
185
|
fi
|
|
179
186
|
|
|
@@ -458,6 +465,13 @@ get_active_count() {
|
|
|
458
465
|
echo 0
|
|
459
466
|
return
|
|
460
467
|
fi
|
|
468
|
+
# Validate state file JSON before parsing (mid-flight corruption check)
|
|
469
|
+
if ! jq empty "$STATE_FILE" 2>/dev/null; then
|
|
470
|
+
daemon_log WARN "State file corrupted mid-flight — backing up and resetting"
|
|
471
|
+
cp "$STATE_FILE" "${STATE_FILE}.corrupted.$(date +%s)" 2>/dev/null || true
|
|
472
|
+
init_state
|
|
473
|
+
return
|
|
474
|
+
fi
|
|
461
475
|
jq -r '.active_jobs | length' "$STATE_FILE" 2>/dev/null || echo 0
|
|
462
476
|
}
|
|
463
477
|
|
|
@@ -531,10 +545,11 @@ dequeue_next() {
|
|
|
531
545
|
|
|
532
546
|
is_priority_issue() {
|
|
533
547
|
local labels_csv="$1"
|
|
534
|
-
|
|
535
|
-
local
|
|
536
|
-
|
|
537
|
-
for lane_label in
|
|
548
|
+
# Bash 3.2 compatible: iterate over comma-separated labels directly
|
|
549
|
+
local _old_ifs="$IFS"
|
|
550
|
+
IFS=','
|
|
551
|
+
for lane_label in $PRIORITY_LANE_LABELS; do
|
|
552
|
+
IFS="$_old_ifs"
|
|
538
553
|
# Trim whitespace
|
|
539
554
|
lane_label="${lane_label## }"
|
|
540
555
|
lane_label="${lane_label%% }"
|
|
@@ -542,6 +557,7 @@ is_priority_issue() {
|
|
|
542
557
|
return 0
|
|
543
558
|
fi
|
|
544
559
|
done
|
|
560
|
+
IFS="$_old_ifs"
|
|
545
561
|
return 1
|
|
546
562
|
}
|
|
547
563
|
|
|
@@ -592,47 +608,84 @@ claim_issue() {
|
|
|
592
608
|
|
|
593
609
|
[[ "$NO_GITHUB" == "true" ]] && return 0 # No claiming in no-github mode
|
|
594
610
|
|
|
595
|
-
#
|
|
596
|
-
local
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
611
|
+
# Serialize claiming on this machine with flock to prevent local race conditions
|
|
612
|
+
local claim_lock_file="${STATE_DIR:-$HOME/.shipwright}/.claim-${issue_num}.lock"
|
|
613
|
+
mkdir -p "$(dirname "$claim_lock_file")"
|
|
614
|
+
local claim_result=1
|
|
615
|
+
(
|
|
616
|
+
if command -v flock >/dev/null 2>&1; then
|
|
617
|
+
flock -w 10 200 2>/dev/null || {
|
|
618
|
+
daemon_log WARN "claim_issue #${issue_num}: local lock timeout"
|
|
619
|
+
exit 1
|
|
620
|
+
}
|
|
621
|
+
fi
|
|
622
|
+
|
|
623
|
+
# Try dashboard-coordinated claim first (atomic label-based)
|
|
624
|
+
local resp
|
|
625
|
+
resp=$(curl -s --max-time 5 -X POST "${DASHBOARD_URL}/api/claim" \
|
|
626
|
+
-H "Content-Type: application/json" \
|
|
627
|
+
-d "$(jq -n --argjson issue "$issue_num" --arg machine "$machine_name" \
|
|
628
|
+
'{issue: $issue, machine: $machine}')" 2>/dev/null || echo "")
|
|
629
|
+
|
|
630
|
+
if [[ -n "$resp" ]] && echo "$resp" | jq -e '.approved == true' >/dev/null 2>&1; then
|
|
631
|
+
# VERIFY: re-read labels after random backoff to detect races
|
|
632
|
+
local backoff_ms=$(( (RANDOM % 500) + 200 ))
|
|
633
|
+
sleep "0.${backoff_ms}"
|
|
634
|
+
if ! _verify_claim_exclusive "$issue_num" "$machine_name"; then
|
|
635
|
+
daemon_log INFO "Issue #${issue_num} claim race lost (competing claim) — removing our label"
|
|
636
|
+
gh issue edit "$issue_num" --remove-label "claimed:${machine_name}" 2>/dev/null || true
|
|
637
|
+
exit 1
|
|
638
|
+
fi
|
|
639
|
+
exit 0
|
|
640
|
+
elif [[ -n "$resp" ]] && echo "$resp" | jq -e '.approved == false' >/dev/null 2>&1; then
|
|
641
|
+
local claimed_by
|
|
642
|
+
claimed_by=$(echo "$resp" | jq -r '.claimed_by // "another machine"')
|
|
643
|
+
daemon_log INFO "Issue #${issue_num} claimed by ${claimed_by} (via dashboard)"
|
|
644
|
+
exit 1
|
|
645
|
+
fi
|
|
646
|
+
|
|
647
|
+
# Fallback: direct GitHub label check (dashboard unreachable)
|
|
648
|
+
daemon_log WARN "Dashboard unreachable — falling back to direct GitHub label claim"
|
|
649
|
+
local existing_claim
|
|
650
|
+
existing_claim=$(gh issue view "$issue_num" --json labels --jq \
|
|
651
|
+
'[.labels[].name | select(startswith("claimed:"))] | .[0] // ""' 2>/dev/null || true)
|
|
652
|
+
|
|
653
|
+
if [[ -n "$existing_claim" ]]; then
|
|
654
|
+
daemon_log INFO "Issue #${issue_num} already claimed: ${existing_claim}"
|
|
655
|
+
exit 1
|
|
656
|
+
fi
|
|
657
|
+
|
|
658
|
+
gh issue edit "$issue_num" --add-label "claimed:${machine_name}" 2>/dev/null || exit 1
|
|
659
|
+
|
|
660
|
+
# Random backoff before verification to desynchronize competing daemons
|
|
661
|
+
local backoff_ms=$(( (RANDOM % 800) + 300 ))
|
|
662
|
+
sleep "0.${backoff_ms}"
|
|
601
663
|
|
|
602
|
-
if [[ -n "$resp" ]] && echo "$resp" | jq -e '.approved == true' >/dev/null 2>&1; then
|
|
603
664
|
# VERIFY: re-read labels, ensure only our claim exists
|
|
604
665
|
if ! _verify_claim_exclusive "$issue_num" "$machine_name"; then
|
|
605
666
|
daemon_log INFO "Issue #${issue_num} claim race lost (competing claim) — removing our label"
|
|
606
667
|
gh issue edit "$issue_num" --remove-label "claimed:${machine_name}" 2>/dev/null || true
|
|
607
|
-
|
|
668
|
+
# Retry once after full backoff (break tie between two losers)
|
|
669
|
+
sleep "1.$(( RANDOM % 500 ))"
|
|
670
|
+
local retry_existing
|
|
671
|
+
retry_existing=$(gh issue view "$issue_num" --json labels --jq \
|
|
672
|
+
'[.labels[].name | select(startswith("claimed:"))] | length' 2>/dev/null || echo "1")
|
|
673
|
+
if [[ "$retry_existing" == "0" ]]; then
|
|
674
|
+
daemon_log INFO "Issue #${issue_num} unclaimed after race — retrying claim"
|
|
675
|
+
gh issue edit "$issue_num" --add-label "claimed:${machine_name}" 2>/dev/null || exit 1
|
|
676
|
+
sleep "0.$(( (RANDOM % 500) + 300 ))"
|
|
677
|
+
if _verify_claim_exclusive "$issue_num" "$machine_name"; then
|
|
678
|
+
exit 0
|
|
679
|
+
fi
|
|
680
|
+
gh issue edit "$issue_num" --remove-label "claimed:${machine_name}" 2>/dev/null || true
|
|
681
|
+
fi
|
|
682
|
+
exit 1
|
|
608
683
|
fi
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
return 1
|
|
615
|
-
fi
|
|
616
|
-
|
|
617
|
-
# Fallback: direct GitHub label check (dashboard unreachable)
|
|
618
|
-
daemon_log WARN "Dashboard unreachable — falling back to direct GitHub label claim"
|
|
619
|
-
local existing_claim
|
|
620
|
-
existing_claim=$(gh issue view "$issue_num" --json labels --jq \
|
|
621
|
-
'[.labels[].name | select(startswith("claimed:"))] | .[0] // ""' 2>/dev/null || true)
|
|
622
|
-
|
|
623
|
-
if [[ -n "$existing_claim" ]]; then
|
|
624
|
-
daemon_log INFO "Issue #${issue_num} already claimed: ${existing_claim}"
|
|
625
|
-
return 1
|
|
626
|
-
fi
|
|
627
|
-
|
|
628
|
-
gh issue edit "$issue_num" --add-label "claimed:${machine_name}" 2>/dev/null || return 1
|
|
629
|
-
# VERIFY: re-read labels, ensure only our claim exists
|
|
630
|
-
if ! _verify_claim_exclusive "$issue_num" "$machine_name"; then
|
|
631
|
-
daemon_log INFO "Issue #${issue_num} claim race lost (competing claim) — removing our label"
|
|
632
|
-
gh issue edit "$issue_num" --remove-label "claimed:${machine_name}" 2>/dev/null || true
|
|
633
|
-
return 1
|
|
634
|
-
fi
|
|
635
|
-
return 0
|
|
684
|
+
exit 0
|
|
685
|
+
) 200>"$claim_lock_file"
|
|
686
|
+
claim_result=$?
|
|
687
|
+
rm -f "$claim_lock_file" 2>/dev/null || true
|
|
688
|
+
return $claim_result
|
|
636
689
|
}
|
|
637
690
|
|
|
638
691
|
release_claim() {
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
[[ -n "${_DAEMON_TRIAGE_LOADED:-}" ]] && return 0
|
|
4
4
|
_DAEMON_TRIAGE_LOADED=1
|
|
5
5
|
|
|
6
|
+
# Defaults for variables normally set by sw-daemon.sh (safe under set -u).
|
|
7
|
+
SCRIPT_DIR="${SCRIPT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
|
|
8
|
+
REPO_DIR="${REPO_DIR:-$(cd "$SCRIPT_DIR/.." && pwd)}"
|
|
9
|
+
PIPELINE_TEMPLATE="${PIPELINE_TEMPLATE:-autonomous}"
|
|
10
|
+
NO_GITHUB="${NO_GITHUB:-false}"
|
|
11
|
+
|
|
6
12
|
# Extract dependency issue numbers from issue text
|
|
7
13
|
extract_issue_dependencies() {
|
|
8
14
|
local text="$1"
|
|
@@ -35,6 +41,9 @@ triage_score_issue() {
|
|
|
35
41
|
# Store analysis for downstream use (composer, predictions)
|
|
36
42
|
export INTELLIGENCE_ANALYSIS="$analysis"
|
|
37
43
|
export INTELLIGENCE_COMPLEXITY="$ai_complexity"
|
|
44
|
+
local ai_issue_type
|
|
45
|
+
ai_issue_type=$(echo "$analysis" | jq -r '.issue_type // "backend"' 2>/dev/null || echo "backend")
|
|
46
|
+
export INTELLIGENCE_ISSUE_TYPE="$ai_issue_type"
|
|
38
47
|
|
|
39
48
|
# Convert AI analysis to triage score:
|
|
40
49
|
# Higher success probability + lower complexity = higher score (process sooner)
|
|
@@ -55,6 +64,7 @@ triage_score_issue() {
|
|
|
55
64
|
"complexity=$ai_complexity" \
|
|
56
65
|
"risk=$ai_risk" \
|
|
57
66
|
"success_prob=$ai_success_prob" \
|
|
67
|
+
"issue_type=$ai_issue_type" \
|
|
58
68
|
"score=$ai_score"
|
|
59
69
|
|
|
60
70
|
echo "$ai_score"
|