shipwright-cli 2.2.2 → 2.3.1
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/README.md +12 -11
- package/dashboard/public/index.html +224 -8
- package/dashboard/public/styles.css +1078 -4
- package/dashboard/server.ts +1100 -15
- package/dashboard/src/canvas/interactions.ts +74 -0
- package/dashboard/src/canvas/layout.ts +85 -0
- package/dashboard/src/canvas/overlays.ts +117 -0
- package/dashboard/src/canvas/particles.ts +105 -0
- package/dashboard/src/canvas/renderer.ts +191 -0
- package/dashboard/src/components/charts/bar.ts +54 -0
- package/dashboard/src/components/charts/donut.ts +25 -0
- package/dashboard/src/components/charts/pipeline-rail.ts +105 -0
- package/dashboard/src/components/charts/sparkline.ts +82 -0
- package/dashboard/src/components/header.ts +616 -0
- package/dashboard/src/components/modal.ts +413 -0
- package/dashboard/src/components/terminal.ts +144 -0
- package/dashboard/src/core/api.test.ts +362 -0
- package/dashboard/src/core/api.ts +381 -0
- package/dashboard/src/core/helpers.ts +118 -0
- package/dashboard/src/core/router.test.ts +266 -0
- package/dashboard/src/core/router.ts +190 -0
- package/dashboard/src/core/sse.ts +38 -0
- package/dashboard/src/core/state.test.ts +235 -0
- package/dashboard/src/core/state.ts +150 -0
- package/dashboard/src/core/ws.test.ts +216 -0
- package/dashboard/src/core/ws.ts +143 -0
- package/dashboard/src/design/icons.test.ts +105 -0
- package/dashboard/src/design/icons.ts +131 -0
- package/dashboard/src/design/tokens.test.ts +204 -0
- package/dashboard/src/design/tokens.ts +160 -0
- package/dashboard/src/main.ts +68 -0
- package/dashboard/src/types/api.ts +337 -0
- package/dashboard/src/views/activity.ts +185 -0
- package/dashboard/src/views/agent-cockpit.ts +236 -0
- package/dashboard/src/views/agents.ts +72 -0
- package/dashboard/src/views/fleet-map.ts +299 -0
- package/dashboard/src/views/insights.ts +298 -0
- package/dashboard/src/views/machines.ts +162 -0
- package/dashboard/src/views/metrics.ts +420 -0
- package/dashboard/src/views/overview.ts +409 -0
- package/dashboard/src/views/pipeline-theater.ts +219 -0
- package/dashboard/src/views/pipelines.ts +595 -0
- package/dashboard/src/views/team.ts +362 -0
- package/dashboard/src/views/timeline.ts +389 -0
- package/dashboard/tsconfig.json +21 -0
- package/dashboard/vitest.config.ts +27 -0
- package/docs/AGI-WHATS-NEXT.md +15 -15
- package/package.json +16 -2
- package/scripts/lib/helpers.sh +30 -0
- package/scripts/lib/pipeline-quality-checks.sh +1 -1
- package/scripts/lib/pipeline-stages.sh +59 -0
- package/scripts/sw +86 -167
- package/scripts/sw-activity.sh +1 -1
- package/scripts/sw-adaptive.sh +1 -1
- package/scripts/sw-adversarial.sh +1 -1
- package/scripts/sw-architecture-enforcer.sh +1 -1
- package/scripts/sw-auth.sh +14 -6
- package/scripts/sw-autonomous.sh +230 -13
- package/scripts/sw-changelog.sh +2 -2
- package/scripts/sw-checkpoint.sh +1 -1
- package/scripts/sw-ci.sh +1 -1
- package/scripts/sw-cleanup.sh +1 -1
- package/scripts/sw-code-review.sh +1 -1
- package/scripts/sw-connect.sh +1 -1
- package/scripts/sw-context.sh +1 -1
- package/scripts/sw-cost.sh +1 -1
- package/scripts/sw-daemon.sh +2 -2
- package/scripts/sw-dashboard.sh +1 -1
- package/scripts/sw-db.sh +1 -1
- package/scripts/sw-decompose.sh +1 -1
- package/scripts/sw-deps.sh +1 -1
- package/scripts/sw-developer-simulation.sh +1 -1
- package/scripts/sw-discovery.sh +1 -1
- package/scripts/sw-doc-fleet.sh +1 -1
- package/scripts/sw-docs-agent.sh +1 -1
- package/scripts/sw-docs.sh +1 -1
- package/scripts/sw-doctor.sh +8 -1
- package/scripts/sw-dora.sh +1 -1
- package/scripts/sw-durable.sh +1 -1
- package/scripts/sw-e2e-orchestrator.sh +1 -1
- package/scripts/sw-eventbus.sh +1 -1
- package/scripts/sw-feedback.sh +1 -1
- package/scripts/sw-fix.sh +6 -5
- package/scripts/sw-fleet-discover.sh +1 -1
- package/scripts/sw-fleet-viz.sh +1 -1
- package/scripts/sw-fleet.sh +1 -1
- package/scripts/sw-github-app.sh +5 -2
- package/scripts/sw-github-checks.sh +1 -1
- package/scripts/sw-github-deploy.sh +1 -1
- package/scripts/sw-github-graphql.sh +1 -1
- package/scripts/sw-guild.sh +1 -1
- package/scripts/sw-heartbeat.sh +1 -1
- package/scripts/sw-hygiene.sh +1 -1
- package/scripts/sw-incident.sh +1 -1
- package/scripts/sw-init.sh +112 -9
- package/scripts/sw-instrument.sh +6 -1
- package/scripts/sw-intelligence.sh +5 -1
- package/scripts/sw-jira.sh +1 -1
- package/scripts/sw-launchd.sh +1 -1
- package/scripts/sw-linear.sh +20 -9
- package/scripts/sw-logs.sh +1 -1
- package/scripts/sw-loop.sh +2 -1
- package/scripts/sw-memory.sh +10 -1
- package/scripts/sw-mission-control.sh +1 -1
- package/scripts/sw-model-router.sh +4 -1
- package/scripts/sw-otel.sh +1 -1
- package/scripts/sw-oversight.sh +1 -1
- package/scripts/sw-pipeline-composer.sh +3 -1
- package/scripts/sw-pipeline-vitals.sh +4 -6
- package/scripts/sw-pipeline.sh +4 -1
- package/scripts/sw-pm.sh +5 -2
- package/scripts/sw-pr-lifecycle.sh +1 -1
- package/scripts/sw-predictive.sh +4 -1
- package/scripts/sw-prep.sh +3 -2
- package/scripts/sw-ps.sh +1 -1
- package/scripts/sw-public-dashboard.sh +10 -4
- package/scripts/sw-quality.sh +1 -1
- package/scripts/sw-reaper.sh +1 -1
- package/scripts/sw-recruit.sh +16 -0
- package/scripts/sw-regression.sh +2 -1
- package/scripts/sw-release-manager.sh +1 -1
- package/scripts/sw-release.sh +7 -5
- package/scripts/sw-remote.sh +1 -1
- package/scripts/sw-replay.sh +1 -1
- package/scripts/sw-retro.sh +4 -1
- package/scripts/sw-scale.sh +4 -1
- package/scripts/sw-security-audit.sh +1 -1
- package/scripts/sw-self-optimize.sh +113 -1
- package/scripts/sw-session.sh +1 -1
- package/scripts/sw-setup.sh +1 -1
- package/scripts/sw-standup.sh +2 -1
- package/scripts/sw-status.sh +1 -1
- package/scripts/sw-strategic.sh +2 -1
- package/scripts/sw-stream.sh +1 -1
- package/scripts/sw-swarm.sh +6 -1
- package/scripts/sw-team-stages.sh +1 -1
- package/scripts/sw-templates.sh +1 -1
- package/scripts/sw-testgen.sh +3 -2
- package/scripts/sw-tmux-pipeline.sh +2 -1
- package/scripts/sw-tmux.sh +1 -1
- package/scripts/sw-trace.sh +1 -1
- package/scripts/sw-tracker-jira.sh +1 -0
- package/scripts/sw-tracker-linear.sh +1 -0
- package/scripts/sw-tracker.sh +1 -1
- package/scripts/sw-triage.sh +198 -11
- package/scripts/sw-upgrade.sh +1 -1
- package/scripts/sw-ux.sh +1 -1
- package/scripts/sw-webhook.sh +1 -1
- package/scripts/sw-widgets.sh +2 -2
- package/scripts/sw-worktree.sh +1 -1
- package/dashboard/public/app.js +0 -4422
package/scripts/sw-autonomous.sh
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
9
9
|
|
|
10
|
-
VERSION="2.
|
|
10
|
+
VERSION="2.3.1"
|
|
11
11
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
12
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
13
13
|
|
|
@@ -64,6 +64,7 @@ STATE_FILE="${STATE_DIR}/state.json"
|
|
|
64
64
|
HISTORY_FILE="${STATE_DIR}/history.jsonl"
|
|
65
65
|
CONFIG_FILE="${STATE_DIR}/config.json"
|
|
66
66
|
CYCLE_COUNTER="${STATE_DIR}/cycle-counter.txt"
|
|
67
|
+
AUTONOMOUS_OVERLAP_FILE="${HOME}/.shipwright/autonomous-state.json"
|
|
67
68
|
|
|
68
69
|
# Ensure directories exist
|
|
69
70
|
ensure_state_dir() {
|
|
@@ -80,7 +81,8 @@ ensure_state_dir() {
|
|
|
80
81
|
"max_consecutive_failures": 3,
|
|
81
82
|
"learning_enabled": true,
|
|
82
83
|
"self_improvement_enabled": true,
|
|
83
|
-
"shipwright_self_improvement_threshold": 3
|
|
84
|
+
"shipwright_self_improvement_threshold": 3,
|
|
85
|
+
"daemon_aware": true
|
|
84
86
|
}
|
|
85
87
|
EOF
|
|
86
88
|
info "Created default config at ${CONFIG_FILE}"
|
|
@@ -179,6 +181,110 @@ record_cycle() {
|
|
|
179
181
|
>> "$HISTORY_FILE"
|
|
180
182
|
}
|
|
181
183
|
|
|
184
|
+
# ─── Strategic Agent Integration ────────────────────────────────────────────
|
|
185
|
+
|
|
186
|
+
# Compute word-overlap similarity between two titles (0-100). Used for dedup.
|
|
187
|
+
title_similarity_percent() {
|
|
188
|
+
local title_a="$1"
|
|
189
|
+
local title_b="$2"
|
|
190
|
+
local words_a words_b
|
|
191
|
+
words_a=$(printf '%s' "$title_a" | tr '[:upper:]' '[:lower:]' | tr -cs '[:alnum:]' '\n' | \
|
|
192
|
+
grep -vE '^(a|an|the|and|or|for|to|in|of|is|it|by|on|at|with|from|based)$' | grep -v '^$' | sort -u || true)
|
|
193
|
+
words_b=$(printf '%s' "$title_b" | tr '[:upper:]' '[:lower:]' | tr -cs '[:alnum:]' '\n' | \
|
|
194
|
+
grep -vE '^(a|an|the|and|or|for|to|in|of|is|it|by|on|at|with|from|based)$' | grep -v '^$' | sort -u || true)
|
|
195
|
+
[[ -z "$words_a" || -z "$words_b" ]] && echo "0" && return 0
|
|
196
|
+
local count_a count_b shared min_count
|
|
197
|
+
count_a=$(printf '%s\n' "$words_a" | wc -l | tr -d ' ')
|
|
198
|
+
count_b=$(printf '%s\n' "$words_b" | wc -l | tr -d ' ')
|
|
199
|
+
shared=$(comm -12 <(printf '%s\n' "$words_a") <(printf '%s\n' "$words_b") | wc -l | tr -d ' ')
|
|
200
|
+
[[ "$count_a" -le "$count_b" ]] && min_count="$count_a" || min_count="$count_b"
|
|
201
|
+
[[ "$min_count" -eq 0 ]] && echo "0" && return 0
|
|
202
|
+
echo $(( shared * 100 / min_count ))
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
# Record that a strategic issue has been acknowledged so we don't re-process it.
|
|
206
|
+
autonomous_register_strategic_overlap() {
|
|
207
|
+
local title="$1"
|
|
208
|
+
local issue_num="${2:-}"
|
|
209
|
+
mkdir -p "$(dirname "$AUTONOMOUS_OVERLAP_FILE")"
|
|
210
|
+
local tmp_file
|
|
211
|
+
tmp_file=$(mktemp "${TMPDIR:-/tmp}/sw-autonomous-overlap.XXXXXX")
|
|
212
|
+
if [[ -f "$AUTONOMOUS_OVERLAP_FILE" ]]; then
|
|
213
|
+
jq --arg t "$title" --arg n "$issue_num" --arg ts "$(now_iso)" \
|
|
214
|
+
'.strategic_acknowledged = ((.strategic_acknowledged // []) + [{"title": $t, "issue": (if $n != "" then ($n | tonumber) else null end), "acked_at": $ts}])' \
|
|
215
|
+
"$AUTONOMOUS_OVERLAP_FILE" > "$tmp_file" 2>/dev/null || true
|
|
216
|
+
else
|
|
217
|
+
jq -n --arg t "$title" --arg n "$issue_num" --arg ts "$(now_iso)" \
|
|
218
|
+
'{strategic_acknowledged: [{"title": $t, "issue": (if $n != "" then ($n | tonumber) else null end), "acked_at": $ts}]}' \
|
|
219
|
+
> "$tmp_file" 2>/dev/null || true
|
|
220
|
+
fi
|
|
221
|
+
mv "$tmp_file" "$AUTONOMOUS_OVERLAP_FILE" 2>/dev/null || rm -f "$tmp_file" || true
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
# Read strategic.issue_created events from last 24h; return JSON array of findings.
|
|
225
|
+
# Excludes issues already in strategic_acknowledged. Resolves issue numbers via gh when possible.
|
|
226
|
+
ingest_strategic_findings() {
|
|
227
|
+
local events_file="${EVENTS_FILE:-${HOME}/.shipwright/events.jsonl}"
|
|
228
|
+
[[ ! -f "$events_file" ]] && echo "[]" && return 0
|
|
229
|
+
|
|
230
|
+
local now_e
|
|
231
|
+
now_e=$(now_epoch 2>/dev/null || date +%s)
|
|
232
|
+
local cutoff_e=$(( now_e - 86400 ))
|
|
233
|
+
|
|
234
|
+
local acked_titles
|
|
235
|
+
acked_titles=""
|
|
236
|
+
if [[ -f "$AUTONOMOUS_OVERLAP_FILE" ]]; then
|
|
237
|
+
acked_titles=$(jq -r '.strategic_acknowledged // [] | .[].title' "$AUTONOMOUS_OVERLAP_FILE" 2>/dev/null || echo "")
|
|
238
|
+
fi
|
|
239
|
+
|
|
240
|
+
local findings="[]"
|
|
241
|
+
while IFS= read -r line; do
|
|
242
|
+
[[ -z "$line" ]] && continue
|
|
243
|
+
local ev_type ts_epoch title priority complexity
|
|
244
|
+
ev_type=$(echo "$line" | jq -r '.type // ""' 2>/dev/null) || true
|
|
245
|
+
[[ "$ev_type" != "strategic.issue_created" ]] && continue
|
|
246
|
+
ts_epoch=$(echo "$line" | jq -r '.ts_epoch // 0' 2>/dev/null) || true
|
|
247
|
+
[[ "$ts_epoch" -lt "$cutoff_e" ]] && continue
|
|
248
|
+
title=$(echo "$line" | jq -r '.title // ""' 2>/dev/null) || true
|
|
249
|
+
[[ -z "$title" ]] && continue
|
|
250
|
+
|
|
251
|
+
local already_acked=false
|
|
252
|
+
if [[ -n "$acked_titles" ]]; then
|
|
253
|
+
while IFS= read -r acked; do
|
|
254
|
+
[[ -z "$acked" ]] && continue
|
|
255
|
+
local sim
|
|
256
|
+
sim=$(title_similarity_percent "$title" "$acked" 2>/dev/null || echo "0")
|
|
257
|
+
if [[ "${sim:-0}" -ge 60 ]]; then
|
|
258
|
+
already_acked=true
|
|
259
|
+
break
|
|
260
|
+
fi
|
|
261
|
+
done <<< "$acked_titles"
|
|
262
|
+
fi
|
|
263
|
+
[[ "$already_acked" == true ]] && continue
|
|
264
|
+
|
|
265
|
+
priority=$(echo "$line" | jq -r '.priority // "P2"' 2>/dev/null) || true
|
|
266
|
+
complexity=$(echo "$line" | jq -r '.complexity // "standard"' 2>/dev/null) || true
|
|
267
|
+
|
|
268
|
+
local issue_num=""
|
|
269
|
+
if [[ "${NO_GITHUB:-false}" != "true" ]] && command -v gh &>/dev/null; then
|
|
270
|
+
issue_num=$(gh issue list --state open --search "$title" --json number -q '.[0].number' 2>/dev/null || echo "")
|
|
271
|
+
fi
|
|
272
|
+
|
|
273
|
+
local finding
|
|
274
|
+
finding=$(jq -n \
|
|
275
|
+
--arg title "$title" \
|
|
276
|
+
--arg priority "$priority" \
|
|
277
|
+
--arg complexity "$complexity" \
|
|
278
|
+
--arg source "strategic" \
|
|
279
|
+
--arg issue "$issue_num" \
|
|
280
|
+
'{title: $title, description: ("Strategic: " + $title), priority: $priority, effort: (if $complexity == "fast" then "S" elif $complexity == "full" then "L" else "M" end), labels: ["strategic", "shipwright"], category: "strategic", source: $source, issue: $issue}')
|
|
281
|
+
|
|
282
|
+
findings=$(echo "$findings" | jq -c --argjson f "$finding" '. + [$f]' 2>/dev/null || echo "$findings")
|
|
283
|
+
done < <(grep '"strategic.issue_created"' "$events_file" 2>/dev/null || true)
|
|
284
|
+
|
|
285
|
+
echo "$findings"
|
|
286
|
+
}
|
|
287
|
+
|
|
182
288
|
# ─── Analysis Cycle ────────────────────────────────────────────────────────
|
|
183
289
|
|
|
184
290
|
run_analysis_cycle() {
|
|
@@ -238,7 +344,52 @@ Output ONLY a JSON array, no other text.' --max-turns 3 > "$findings" 2>/dev/nul
|
|
|
238
344
|
} > "$findings"
|
|
239
345
|
fi
|
|
240
346
|
|
|
241
|
-
|
|
347
|
+
# Ingest strategic findings and merge with Claude/heuristic findings
|
|
348
|
+
local strategic_json
|
|
349
|
+
strategic_json=$(ingest_strategic_findings 2>/dev/null || echo "[]")
|
|
350
|
+
|
|
351
|
+
local merged_file
|
|
352
|
+
merged_file=$(mktemp "${TMPDIR:-/tmp}/sw-autonomous-merged.XXXXXX")
|
|
353
|
+
# Parse claude findings (may be invalid if Claude wrapped in markdown)
|
|
354
|
+
local claude_array
|
|
355
|
+
claude_array=$(jq -c '.' "$findings" 2>/dev/null || echo "[]")
|
|
356
|
+
# Extract JSON array from potential markdown-wrapped output
|
|
357
|
+
if ! echo "$claude_array" | jq -e 'type == "array"' &>/dev/null; then
|
|
358
|
+
claude_array=$(sed -n '/^\[/,/^\]/p' "$findings" 2>/dev/null | jq -c '.' 2>/dev/null || echo "[]")
|
|
359
|
+
fi
|
|
360
|
+
if ! echo "$claude_array" | jq -e 'type == "array"' &>/dev/null; then
|
|
361
|
+
claude_array="[]"
|
|
362
|
+
fi
|
|
363
|
+
|
|
364
|
+
# Filter: drop Claude findings that overlap (>=60% similar) with strategic
|
|
365
|
+
local filtered_claude="[]"
|
|
366
|
+
local strategic_titles
|
|
367
|
+
strategic_titles=$(echo "$strategic_json" | jq -r '.[].title' 2>/dev/null || true)
|
|
368
|
+
while IFS= read -r cf; do
|
|
369
|
+
[[ -z "$cf" ]] && continue
|
|
370
|
+
local ctitle
|
|
371
|
+
ctitle=$(echo "$cf" | jq -r '.title // ""' 2>/dev/null) || true
|
|
372
|
+
[[ -z "$ctitle" ]] && continue
|
|
373
|
+
local overlaps=false
|
|
374
|
+
if [[ -n "$strategic_titles" ]]; then
|
|
375
|
+
while IFS= read -r stitle; do
|
|
376
|
+
[[ -z "$stitle" ]] && continue
|
|
377
|
+
local sim
|
|
378
|
+
sim=$(title_similarity_percent "$ctitle" "$stitle" 2>/dev/null || echo "0")
|
|
379
|
+
if [[ "${sim:-0}" -ge 60 ]]; then
|
|
380
|
+
overlaps=true
|
|
381
|
+
break
|
|
382
|
+
fi
|
|
383
|
+
done <<< "$strategic_titles"
|
|
384
|
+
fi
|
|
385
|
+
[[ "$overlaps" == true ]] && continue
|
|
386
|
+
filtered_claude=$(echo "$filtered_claude" | jq -c --argjson f "$cf" '. + [$f]' 2>/dev/null || echo "$filtered_claude")
|
|
387
|
+
done < <(echo "$claude_array" | jq -c '.[]' 2>/dev/null || true)
|
|
388
|
+
|
|
389
|
+
# Merge: filtered Claude + strategic
|
|
390
|
+
jq -n -c --argjson c "$filtered_claude" --argjson s "$strategic_json" '$c + $s' 2>/dev/null > "$merged_file" || cat "$findings" > "$merged_file"
|
|
391
|
+
cat "$merged_file"
|
|
392
|
+
rm -f "$merged_file" "$findings" 2>/dev/null || true
|
|
242
393
|
}
|
|
243
394
|
|
|
244
395
|
# ─── Issue Creation ────────────────────────────────────────────────────────
|
|
@@ -255,11 +406,11 @@ create_issue_from_finding() {
|
|
|
255
406
|
return 1
|
|
256
407
|
fi
|
|
257
408
|
|
|
258
|
-
#
|
|
409
|
+
# Dedup: check if an open issue with the same title already exists
|
|
259
410
|
local existing
|
|
260
|
-
existing=$(gh issue list --search "$title" --json number
|
|
261
|
-
if [[ "$
|
|
262
|
-
warn "
|
|
411
|
+
existing=$(gh issue list --state open --search "$title" --json number,title --limit 20 2>/dev/null | jq -r --arg t "$title" '[.[] | select(.title == $t) | .number][0] // empty' || echo "")
|
|
412
|
+
if [[ -n "$existing" ]]; then
|
|
413
|
+
warn "Open issue with same title already exists: #${existing} ($title)"
|
|
263
414
|
return 1
|
|
264
415
|
fi
|
|
265
416
|
|
|
@@ -290,8 +441,31 @@ create_issue_from_finding() {
|
|
|
290
441
|
return 0
|
|
291
442
|
}
|
|
292
443
|
|
|
444
|
+
# ─── Daemon Awareness ───────────────────────────────────────────────────────
|
|
445
|
+
# Check if daemon is running (avoids duplicate work: autonomous vs daemon)
|
|
446
|
+
daemon_is_running() {
|
|
447
|
+
local daemon_state="${HOME}/.shipwright/daemon-state.json"
|
|
448
|
+
local pid_file="${HOME}/.shipwright/daemon.pid"
|
|
449
|
+
if [[ ! -f "$daemon_state" ]]; then
|
|
450
|
+
return 1
|
|
451
|
+
fi
|
|
452
|
+
if [[ ! -f "$pid_file" ]]; then
|
|
453
|
+
return 1
|
|
454
|
+
fi
|
|
455
|
+
local pid
|
|
456
|
+
pid=$(cat "$pid_file" 2>/dev/null || true)
|
|
457
|
+
[[ -z "$pid" ]] && return 1
|
|
458
|
+
kill -0 "$pid" 2>/dev/null || return 1
|
|
459
|
+
# Optional: also check daemon field if present (API/dashboard format)
|
|
460
|
+
local daemon_status
|
|
461
|
+
daemon_status=$(jq -r '.daemon // "running"' "$daemon_state" 2>/dev/null || echo "running")
|
|
462
|
+
[[ "$daemon_status" == "running" ]] || return 1
|
|
463
|
+
return 0
|
|
464
|
+
}
|
|
465
|
+
|
|
293
466
|
# ─── Issue Processing from Analysis ────────────────────────────────────────
|
|
294
|
-
# Trigger pipeline for a finding issue
|
|
467
|
+
# Trigger pipeline for a finding issue. When daemon is running, delegate via
|
|
468
|
+
# ready-to-build label; otherwise trigger pipeline directly.
|
|
295
469
|
trigger_pipeline_for_finding() {
|
|
296
470
|
local issue_num="$1"
|
|
297
471
|
local title="$2"
|
|
@@ -302,7 +476,27 @@ trigger_pipeline_for_finding() {
|
|
|
302
476
|
return 0
|
|
303
477
|
fi
|
|
304
478
|
|
|
305
|
-
|
|
479
|
+
local daemon_aware
|
|
480
|
+
daemon_aware=$(get_config "daemon_aware" "true")
|
|
481
|
+
if [[ "$daemon_aware" != "true" && "$daemon_aware" != "1" ]]; then
|
|
482
|
+
daemon_aware=false
|
|
483
|
+
else
|
|
484
|
+
daemon_aware=true
|
|
485
|
+
fi
|
|
486
|
+
|
|
487
|
+
if [[ "$daemon_aware" == "true" ]] && daemon_is_running; then
|
|
488
|
+
# Daemon running: label ready-to-build and let daemon pick it up
|
|
489
|
+
if [[ "$NO_GITHUB" != "true" ]]; then
|
|
490
|
+
gh issue edit "$issue_num" --add-label "ready-to-build" 2>/dev/null || {
|
|
491
|
+
warn "Failed to add ready-to-build label to #${issue_num}"
|
|
492
|
+
}
|
|
493
|
+
fi
|
|
494
|
+
info "Delegated issue #${issue_num} to daemon (labeled ready-to-build)"
|
|
495
|
+
emit_event "autonomous.delegated_to_daemon" "issue=$issue_num" "title=$title"
|
|
496
|
+
return 0
|
|
497
|
+
fi
|
|
498
|
+
|
|
499
|
+
# Daemon not running or DAEMON_AWARE=false: trigger pipeline directly
|
|
306
500
|
local -a recruit_args=()
|
|
307
501
|
if [[ -x "$SCRIPT_DIR/sw-recruit.sh" ]]; then
|
|
308
502
|
local recruit_match
|
|
@@ -386,20 +580,37 @@ process_findings() {
|
|
|
386
580
|
[[ -z "$finding" ]] && continue
|
|
387
581
|
|
|
388
582
|
total=$((total + 1))
|
|
389
|
-
[[ "$created" -ge "$max_per_cycle" ]] && break
|
|
390
583
|
|
|
391
|
-
local title description priority effort labels category
|
|
584
|
+
local title description priority effort labels category source issue_num
|
|
392
585
|
title=$(echo "$finding" | jq -r '.title // ""')
|
|
393
586
|
description=$(echo "$finding" | jq -r '.description // ""')
|
|
394
587
|
priority=$(echo "$finding" | jq -r '.priority // "medium"')
|
|
395
588
|
effort=$(echo "$finding" | jq -r '.effort // "M"')
|
|
396
|
-
labels=$(echo "$finding" | jq -r '.labels | join(",") // ""')
|
|
589
|
+
labels=$(echo "$finding" | jq -r '(.labels | if type == "array" then join(",") else . end) // ""')
|
|
397
590
|
category=$(echo "$finding" | jq -r '.category // ""')
|
|
591
|
+
source=$(echo "$finding" | jq -r '.source // ""')
|
|
592
|
+
issue_num=$(echo "$finding" | jq -r '.issue // ""')
|
|
398
593
|
|
|
399
594
|
if [[ -z "$title" ]]; then
|
|
400
595
|
continue
|
|
401
596
|
fi
|
|
402
597
|
|
|
598
|
+
# Strategic findings: issue already created by strategic agent; trigger pipeline and register, skip create
|
|
599
|
+
if [[ "$source" == "strategic" ]]; then
|
|
600
|
+
[[ -z "$issue_num" && "${NO_GITHUB:-false}" != "true" ]] && command -v gh &>/dev/null && \
|
|
601
|
+
issue_num=$(gh issue list --state open --search "$title" --json number -q '.[0].number' 2>/dev/null || echo "")
|
|
602
|
+
if [[ -n "$issue_num" && "$issue_num" =~ ^[0-9]+$ ]]; then
|
|
603
|
+
trigger_pipeline_for_finding "$issue_num" "$title"
|
|
604
|
+
autonomous_register_strategic_overlap "$title" "$issue_num" || true
|
|
605
|
+
info "Acknowledged strategic finding: #${issue_num} $title"
|
|
606
|
+
else
|
|
607
|
+
autonomous_register_strategic_overlap "$title" "" || true
|
|
608
|
+
fi
|
|
609
|
+
continue
|
|
610
|
+
fi
|
|
611
|
+
|
|
612
|
+
[[ "$created" -ge "$max_per_cycle" ]] && continue
|
|
613
|
+
|
|
403
614
|
# Add category to labels if not present
|
|
404
615
|
if [[ "$labels" != *"$category"* ]]; then
|
|
405
616
|
labels="${category}${labels:+,$labels}"
|
|
@@ -420,7 +631,6 @@ process_findings() {
|
|
|
420
631
|
fi
|
|
421
632
|
fi
|
|
422
633
|
|
|
423
|
-
local issue_num
|
|
424
634
|
issue_num=$(create_issue_from_finding "$title" "$description" "$priority" "$effort" "$labels")
|
|
425
635
|
if [[ $? -eq 0 && -n "$issue_num" ]]; then
|
|
426
636
|
created=$((created + 1))
|
|
@@ -664,6 +874,12 @@ set_cycle_config() {
|
|
|
664
874
|
set_config "rollback_on_failures" "$bool_val"
|
|
665
875
|
success "Rollback on failures set to ${CYAN}${bool_val}${RESET}"
|
|
666
876
|
;;
|
|
877
|
+
daemon-aware|daemon_aware)
|
|
878
|
+
local bool_val="true"
|
|
879
|
+
[[ "$value" == "false" || "$value" == "0" || "$value" == "no" ]] && bool_val="false"
|
|
880
|
+
set_config "daemon_aware" "$bool_val"
|
|
881
|
+
success "Daemon-aware (delegate to daemon when running) set to ${CYAN}${bool_val}${RESET}"
|
|
882
|
+
;;
|
|
667
883
|
*)
|
|
668
884
|
error "Unknown config key: $key"
|
|
669
885
|
return 1
|
|
@@ -697,6 +913,7 @@ OPTIONS (for config)
|
|
|
697
913
|
set max-pipelines <num> Set max concurrent pipelines (default 2)
|
|
698
914
|
set approval <bool> Enable human approval mode (default false)
|
|
699
915
|
set rollback <bool> Rollback on failures (default true)
|
|
916
|
+
set daemon-aware <bool> Delegate to daemon when running (default true)
|
|
700
917
|
|
|
701
918
|
EXAMPLES
|
|
702
919
|
sw autonomous start # Start the loop
|
package/scripts/sw-changelog.sh
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
9
9
|
|
|
10
|
-
VERSION="2.
|
|
10
|
+
VERSION="2.3.1"
|
|
11
11
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
12
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
13
13
|
|
|
@@ -138,7 +138,7 @@ parse_commits() {
|
|
|
138
138
|
# Build entry
|
|
139
139
|
local entry="$msg"
|
|
140
140
|
[[ -n "$scope" ]] && entry="**${scope}**: $entry"
|
|
141
|
-
[[ -n "$pr_num" ]] && entry="$entry ([\#$pr_num](
|
|
141
|
+
[[ -n "$pr_num" ]] && entry="$entry ([\#$pr_num]($(_sw_github_url)/pull/$pr_num))"
|
|
142
142
|
|
|
143
143
|
# Categorize
|
|
144
144
|
case "$type" in
|
package/scripts/sw-checkpoint.sh
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
set -euo pipefail
|
|
9
9
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
10
10
|
|
|
11
|
-
VERSION="2.
|
|
11
|
+
VERSION="2.3.1"
|
|
12
12
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
13
|
|
|
14
14
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
package/scripts/sw-ci.sh
CHANGED
package/scripts/sw-cleanup.sh
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# ║ Default: dry-run (shows what would be cleaned). ║
|
|
6
6
|
# ║ Use --force to actually kill sessions and remove files. ║
|
|
7
7
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
8
|
-
VERSION="2.
|
|
8
|
+
VERSION="2.3.1"
|
|
9
9
|
set -euo pipefail
|
|
10
10
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
11
11
|
|
package/scripts/sw-connect.sh
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
set -euo pipefail
|
|
9
9
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
10
10
|
|
|
11
|
-
VERSION="2.
|
|
11
|
+
VERSION="2.3.1"
|
|
12
12
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
13
|
|
|
14
14
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
package/scripts/sw-context.sh
CHANGED
package/scripts/sw-cost.sh
CHANGED
package/scripts/sw-daemon.sh
CHANGED
|
@@ -9,7 +9,7 @@ trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
|
9
9
|
# Allow spawning Claude CLI from within a Claude Code session (daemon, fleet, etc.)
|
|
10
10
|
unset CLAUDECODE 2>/dev/null || true
|
|
11
11
|
|
|
12
|
-
VERSION="2.
|
|
12
|
+
VERSION="2.3.1"
|
|
13
13
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
14
|
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
15
15
|
|
|
@@ -395,7 +395,7 @@ show_help() {
|
|
|
395
395
|
echo -e " 6. Priority lane: ${CYAN}hotfix${RESET}/${CYAN}incident${RESET} issues bypass the queue"
|
|
396
396
|
echo -e " 7. Org mode: watches issues across all repos in a GitHub org"
|
|
397
397
|
echo ""
|
|
398
|
-
echo -e "${DIM}Docs:
|
|
398
|
+
echo -e "${DIM}Docs: $(_sw_docs_url) | GitHub: $(_sw_github_url)${RESET}"
|
|
399
399
|
}
|
|
400
400
|
|
|
401
401
|
# ─── Config Loading ─────────────────────────────────────────────────────────
|
package/scripts/sw-dashboard.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="2.
|
|
9
|
+
VERSION="2.3.1"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
package/scripts/sw-db.sh
CHANGED
package/scripts/sw-decompose.sh
CHANGED
package/scripts/sw-deps.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="2.
|
|
9
|
+
VERSION="2.3.1"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
package/scripts/sw-discovery.sh
CHANGED
package/scripts/sw-doc-fleet.sh
CHANGED
package/scripts/sw-docs-agent.sh
CHANGED
package/scripts/sw-docs.sh
CHANGED
package/scripts/sw-doctor.sh
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# ║ ║
|
|
5
5
|
# ║ Checks prerequisites, installed files, PATH, and common issues. ║
|
|
6
6
|
# ╚═══════════════════════════════════════════════════════════════════════════╝
|
|
7
|
-
VERSION="2.
|
|
7
|
+
VERSION="2.3.1"
|
|
8
8
|
set -euo pipefail
|
|
9
9
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
10
10
|
|
|
@@ -341,6 +341,13 @@ fi
|
|
|
341
341
|
# Check sw subcommands are installed alongside the router
|
|
342
342
|
if command -v sw &>/dev/null; then
|
|
343
343
|
SW_DIR="$(dirname "$(command -v sw)")"
|
|
344
|
+
# Follow symlinks to find the actual scripts directory
|
|
345
|
+
_sw_path="$(command -v sw)"
|
|
346
|
+
if [[ -L "$_sw_path" ]]; then
|
|
347
|
+
_sw_real="$(readlink "$_sw_path")"
|
|
348
|
+
[[ "$_sw_real" != /* ]] && _sw_real="$(cd "$(dirname "$_sw_path")" && cd "$(dirname "$_sw_real")" && pwd)/$(basename "$_sw_real")"
|
|
349
|
+
SW_DIR="$(dirname "$_sw_real")"
|
|
350
|
+
fi
|
|
344
351
|
check_pass "shipwright router found at ${SW_DIR}/sw"
|
|
345
352
|
|
|
346
353
|
missing_subs=()
|
package/scripts/sw-dora.sh
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
set -euo pipefail
|
|
9
9
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
10
10
|
|
|
11
|
-
VERSION="2.
|
|
11
|
+
VERSION="2.3.1"
|
|
12
12
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
13
|
|
|
14
14
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
package/scripts/sw-durable.sh
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
9
9
|
|
|
10
|
-
VERSION="2.
|
|
10
|
+
VERSION="2.3.1"
|
|
11
11
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
12
|
|
|
13
13
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
package/scripts/sw-eventbus.sh
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
9
9
|
|
|
10
|
-
VERSION="2.
|
|
10
|
+
VERSION="2.3.1"
|
|
11
11
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
12
|
|
|
13
13
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
package/scripts/sw-feedback.sh
CHANGED