shipwright-cli 3.2.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 +4 -4
- 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/dashboard/middleware/auth.ts +134 -0
- package/dashboard/middleware/constants.ts +21 -0
- package/dashboard/public/index.html +2 -6
- package/dashboard/public/styles.css +100 -97
- package/dashboard/routes/auth.ts +38 -0
- package/dashboard/server.ts +66 -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/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 +2 -1
- package/dashboard/src/views/activity.ts +2 -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 +10 -0
- package/scripts/lib/daemon-dispatch.sh +106 -17
- package/scripts/lib/daemon-failure.sh +34 -4
- package/scripts/lib/daemon-patrol.sh +23 -2
- 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 +112 -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 +177 -4
- 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 +100 -2
- 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 +100 -1136
- package/scripts/lib/pipeline-quality-bash-compat.sh +182 -0
- package/scripts/lib/pipeline-quality-checks.sh +17 -715
- 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 +59 -2929
- 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 -2
- package/scripts/sw-adaptive.sh +2 -1
- 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 +5 -1
- package/scripts/sw-cleanup.sh +4 -26
- package/scripts/sw-code-review.sh +10 -4
- package/scripts/sw-connect.sh +2 -1
- package/scripts/sw-context.sh +2 -1
- package/scripts/sw-cost.sh +48 -3
- package/scripts/sw-daemon.sh +66 -9
- package/scripts/sw-dashboard.sh +3 -1
- package/scripts/sw-db.sh +59 -16
- 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 +325 -2
- 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 +4 -3
- package/scripts/sw-e2e-orchestrator.sh +17 -16
- package/scripts/sw-eventbus.sh +7 -1
- 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 +4 -1
- package/scripts/sw-fleet.sh +5 -1
- package/scripts/sw-github-app.sh +16 -3
- 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 +6 -1
- package/scripts/sw-incident.sh +265 -1
- package/scripts/sw-init.sh +18 -2
- package/scripts/sw-instrument.sh +10 -2
- package/scripts/sw-intelligence.sh +42 -6
- 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 +432 -1128
- package/scripts/sw-memory.sh +356 -2
- package/scripts/sw-mission-control.sh +6 -1
- package/scripts/sw-model-router.sh +481 -26
- package/scripts/sw-otel.sh +13 -4
- package/scripts/sw-oversight.sh +14 -5
- package/scripts/sw-patrol-meta.sh +334 -0
- package/scripts/sw-pipeline-composer.sh +5 -1
- package/scripts/sw-pipeline-vitals.sh +2 -1
- package/scripts/sw-pipeline.sh +53 -2664
- package/scripts/sw-pm.sh +12 -5
- package/scripts/sw-pr-lifecycle.sh +2 -1
- package/scripts/sw-predictive.sh +7 -1
- package/scripts/sw-prep.sh +185 -2
- package/scripts/sw-ps.sh +5 -25
- package/scripts/sw-public-dashboard.sh +15 -3
- package/scripts/sw-quality.sh +2 -1
- 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 +10 -3
- package/scripts/sw-security-audit.sh +6 -1
- package/scripts/sw-self-optimize.sh +6 -3
- 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 +4 -1
- package/scripts/sw-stream.sh +7 -1
- package/scripts/sw-swarm.sh +18 -6
- package/scripts/sw-team-stages.sh +13 -6
- package/scripts/sw-templates.sh +5 -29
- package/scripts/sw-testgen.sh +7 -1
- 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 +3 -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 +2 -1
- package/scripts/sw-upgrade.sh +3 -1
- package/scripts/sw-ux.sh +5 -2
- package/scripts/sw-webhook.sh +3 -1
- package/scripts/sw-widgets.sh +3 -1
- 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
|
|
|
@@ -538,10 +545,11 @@ dequeue_next() {
|
|
|
538
545
|
|
|
539
546
|
is_priority_issue() {
|
|
540
547
|
local labels_csv="$1"
|
|
541
|
-
|
|
542
|
-
local
|
|
543
|
-
|
|
544
|
-
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"
|
|
545
553
|
# Trim whitespace
|
|
546
554
|
lane_label="${lane_label## }"
|
|
547
555
|
lane_label="${lane_label%% }"
|
|
@@ -549,6 +557,7 @@ is_priority_issue() {
|
|
|
549
557
|
return 0
|
|
550
558
|
fi
|
|
551
559
|
done
|
|
560
|
+
IFS="$_old_ifs"
|
|
552
561
|
return 1
|
|
553
562
|
}
|
|
554
563
|
|
|
@@ -599,47 +608,84 @@ claim_issue() {
|
|
|
599
608
|
|
|
600
609
|
[[ "$NO_GITHUB" == "true" ]] && return 0 # No claiming in no-github mode
|
|
601
610
|
|
|
602
|
-
#
|
|
603
|
-
local
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
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}"
|
|
608
663
|
|
|
609
|
-
if [[ -n "$resp" ]] && echo "$resp" | jq -e '.approved == true' >/dev/null 2>&1; then
|
|
610
664
|
# VERIFY: re-read labels, ensure only our claim exists
|
|
611
665
|
if ! _verify_claim_exclusive "$issue_num" "$machine_name"; then
|
|
612
666
|
daemon_log INFO "Issue #${issue_num} claim race lost (competing claim) — removing our label"
|
|
613
667
|
gh issue edit "$issue_num" --remove-label "claimed:${machine_name}" 2>/dev/null || true
|
|
614
|
-
|
|
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
|
|
615
683
|
fi
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
return 1
|
|
622
|
-
fi
|
|
623
|
-
|
|
624
|
-
# Fallback: direct GitHub label check (dashboard unreachable)
|
|
625
|
-
daemon_log WARN "Dashboard unreachable — falling back to direct GitHub label claim"
|
|
626
|
-
local existing_claim
|
|
627
|
-
existing_claim=$(gh issue view "$issue_num" --json labels --jq \
|
|
628
|
-
'[.labels[].name | select(startswith("claimed:"))] | .[0] // ""' 2>/dev/null || true)
|
|
629
|
-
|
|
630
|
-
if [[ -n "$existing_claim" ]]; then
|
|
631
|
-
daemon_log INFO "Issue #${issue_num} already claimed: ${existing_claim}"
|
|
632
|
-
return 1
|
|
633
|
-
fi
|
|
634
|
-
|
|
635
|
-
gh issue edit "$issue_num" --add-label "claimed:${machine_name}" 2>/dev/null || return 1
|
|
636
|
-
# VERIFY: re-read labels, ensure only our claim exists
|
|
637
|
-
if ! _verify_claim_exclusive "$issue_num" "$machine_name"; then
|
|
638
|
-
daemon_log INFO "Issue #${issue_num} claim race lost (competing claim) — removing our label"
|
|
639
|
-
gh issue edit "$issue_num" --remove-label "claimed:${machine_name}" 2>/dev/null || true
|
|
640
|
-
return 1
|
|
641
|
-
fi
|
|
642
|
-
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
|
|
643
689
|
}
|
|
644
690
|
|
|
645
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"
|