@rubytech/create-realagent-code 0.1.614 → 0.1.615

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.
@@ -8,14 +8,16 @@
8
8
  # Xtigervnc :${VNC_DISPLAY} — virtual X11 display per brand
9
9
  # Xtigervnc -rfbport ${RFB_PORT} — RFB port per brand
10
10
  # websockify :${WEBSOCKIFY_PORT} — WebSocket bridge per brand
11
- # Chromium — headless browser with --user-data-dir per brand
11
+ # Chromium — browser with --user-data-dir per brand
12
12
  # CDP :${CDP_PORT} — browser plugin (browser-render) CDP endpoint per brand
13
13
  #
14
- # Task 1562: virtual-mode Chromium is HEADLESS. The X display, RFB port and
15
- # websockify still boot, but no browser renders onto them and no surface reads
16
- # them every consumer (agent browser-* tools, the operator screencast viewer,
17
- # the Claude sign-in browser) is a CDP client on ${CDP_PORT}. Retiring the three
18
- # now-unread components, their ports and their apt deps is Task 2198.
14
+ # Virtual-mode Chromium is HEADED on the brand's Xtigervnc display. Task 1562
15
+ # made it headless on 2026-07-30 and commit b1b007b03 reverted that the next
16
+ # day: Cloudflare's managed challenge on claude.ai refuses `--headless=new`, so
17
+ # Claude sign-in could never complete. Every consumer (agent browser-* tools,
18
+ # the operator screencast viewer, the Claude sign-in browser) is still a CDP
19
+ # client on ${CDP_PORT} rather than a reader of the RFB port; retiring the
20
+ # now-unread RFB and websockify components is Task 2198.
19
21
  #
20
22
  # Brand isolation (Tasks 553 + 924): the X display number, Chromium profile,
21
23
  # rfbport, websockify port, and CDP port are all brand-scoped so any number
@@ -41,11 +43,18 @@
41
43
  # cloudflare-setup actions run via the detached action runner
42
44
  # (/api/admin/actions/*) rather than an in-browser terminal.
43
45
  #
44
- # Display modes (DISPLAY_MODE env var, set by installer --display flag):
45
- # virtual (default) Chromium runs headless; no display at all (Task 1562)
46
+ # Display modes, set by the installer --display flag and recorded in the brand
47
+ # .env. resolve_display_mode() is the ONLY reader of DISPLAY_MODE in this
48
+ # script: it prefers the environment variable and falls back to the .env,
49
+ # defaulting to virtual. No unit file in the fleet exports the variable, so a
50
+ # second reader taking the env var directly always resolved to virtual and
51
+ # silently disagreed with the .env — Task 2780.
52
+ # virtual (default) — Chromium runs headed on the brand's Xtigervnc display
46
53
  # native — Chromium runs on the login session's real display
47
54
  # (discovered via loginctl, NOT from $DISPLAY which
48
55
  # is poisoned by the systemd Environment=DISPLAY line)
56
+ # Both modes are supervised by the standing cdp-liveness check; only the launch
57
+ # precondition differs.
49
58
 
50
59
  set -uo pipefail
51
60
 
@@ -183,10 +192,23 @@ resolve_websockify_bind() {
183
192
  # The standing cdp-liveness probe runs every rss-sampler cycle; skip this
184
193
  # per-invocation resolution line on that path so vnc-boot.log is not spammed.
185
194
  # The FATAL guards above still run (and hard-exit) on every invocation.
195
+ #
196
+ # PER_CYCLE=1 marks that path for every other would-be per-cycle writer too.
197
+ # vnc-boot.log is NOT one of logs-rotate.sh's targets, so nothing bounds it: a
198
+ # writer that fires once per 30s cycle grows it without limit. Keep this file
199
+ # event-driven and let the per-cycle signal go to stdout, which is the
200
+ # rss-sampler's journal and is bounded by journald.
201
+ PER_CYCLE=0
186
202
  if [ "${1:-}" != "cdp-liveness" ]; then
187
203
  log "[vnc.sh:chromium] bin=${CHROMIUM_BIN} realpath=${CHROMIUM_REALPATH} confinement=${CHROMIUM_CONFINEMENT}"
204
+ else
205
+ PER_CYCLE=1
188
206
  fi
189
207
 
208
+ # log() that is a no-op on the per-cycle path. For detail that is worth having
209
+ # when a launch is attempted but must not accumulate once per cycle forever.
210
+ log_event() { [ "$PER_CYCLE" -eq 1 ] || log "$@"; }
211
+
190
212
  kill_stale() {
191
213
  # Brand-scoped matchers: pkill on --user-data-dir narrows the
192
214
  # Chromium kill to this brand's profile only, so two brands on the same
@@ -291,52 +313,75 @@ check_window_on_display() {
291
313
  DISPLAY="$display" xdotool search --onlyvisible --class '[Cc]hrom' >/dev/null 2>&1
292
314
  }
293
315
 
294
- # Discover the login session's display type and display values.
316
+ # Discover the login session Chromium should render onto, by evidence.
295
317
  # Uses loginctl (systemd) to bypass the poisoned $DISPLAY env var.
296
- # Sets: NATIVE_SESSION_TYPE (wayland|x11), NATIVE_DISPLAY (:N),
297
- # NATIVE_WAYLAND_DISPLAY (wayland-0 or from session environ).
298
- # Falls back to x11/:0 when loginctl is unavailable or no graphical session exists.
318
+ #
319
+ # Selection is over EVERY listed session, not the first row: on a box with
320
+ # remote tty sessions the first row is one of those, it reports an empty
321
+ # Display, and the old `:0` substitution then reached the right screen by
322
+ # accident on a single-seat desktop and the wrong screen — or none — anywhere
323
+ # else, while still reporting success. A session qualifies only when it is
324
+ # Active=yes, Remote=no, and Type x11 or wayland.
325
+ #
326
+ # Returns 0 with NATIVE_SESSION_TYPE (x11|wayland), NATIVE_DISPLAY and
327
+ # NATIVE_WAYLAND_DISPLAY set. Returns 1 with NATIVE_DISPLAY UNSET, so a caller
328
+ # that ignores the exit status still cannot launch onto a guess.
299
329
  discover_native_session() {
300
- NATIVE_SESSION_TYPE="x11"
301
- NATIVE_DISPLAY=":0"
330
+ NATIVE_SESSION_TYPE=""
302
331
  NATIVE_WAYLAND_DISPLAY=""
332
+ unset NATIVE_DISPLAY
303
333
 
304
334
  if ! command -v loginctl >/dev/null 2>&1; then
305
- log "WARNING: loginctl not found — falling back to DISPLAY=:0, ozone-platform=x11"
306
- return
335
+ log_event "[vnc.sh:native] no-graphical-session reason=loginctl-absent"
336
+ return 1
307
337
  fi
308
338
 
309
- local session_id
310
- session_id=$(loginctl list-sessions --no-legend 2>/dev/null | awk 'NR==1{print $1}')
311
- if [ -z "$session_id" ]; then
312
- log "WARNING: no login sessions found — falling back to DISPLAY=:0, ozone-platform=x11"
313
- return
339
+ local session_ids session_id active remote session_type session_display leader_pid
340
+ session_ids=$(loginctl list-sessions --no-legend 2>/dev/null | awk '{print $1}')
341
+ if [ -z "$session_ids" ]; then
342
+ log_event "[vnc.sh:native] no-graphical-session reason=no-sessions-listed"
343
+ return 1
314
344
  fi
315
345
 
316
- local session_type
317
- session_type=$(loginctl show-session "$session_id" -p Type --value 2>/dev/null)
318
-
319
- local session_display
320
- session_display=$(loginctl show-session "$session_id" -p Display --value 2>/dev/null)
321
-
322
- if [ "$session_type" = "wayland" ]; then
323
- NATIVE_SESSION_TYPE="wayland"
324
- NATIVE_DISPLAY="${session_display:-:0}"
346
+ for session_id in $session_ids; do
347
+ active=$(loginctl show-session "$session_id" -p Active --value 2>/dev/null)
348
+ [ "$active" = "yes" ] || continue
349
+ remote=$(loginctl show-session "$session_id" -p Remote --value 2>/dev/null)
350
+ [ "$remote" = "no" ] || continue
351
+ session_type=$(loginctl show-session "$session_id" -p Type --value 2>/dev/null)
352
+ case "$session_type" in x11|wayland) ;; *) continue ;; esac
353
+
354
+ session_display=$(loginctl show-session "$session_id" -p Display --value 2>/dev/null)
355
+
356
+ if [ "$session_type" = "wayland" ]; then
357
+ NATIVE_SESSION_TYPE="wayland"
358
+ NATIVE_DISPLAY="$session_display"
359
+ # Discover WAYLAND_DISPLAY from the session leader's environment; it, not
360
+ # DISPLAY, is the launch vector under the wayland ozone backend.
361
+ leader_pid=$(loginctl show-session "$session_id" -p Leader --value 2>/dev/null)
362
+ if [ -n "$leader_pid" ] && [ -r "/proc/$leader_pid/environ" ]; then
363
+ NATIVE_WAYLAND_DISPLAY=$(tr '\0' '\n' < "/proc/$leader_pid/environ" 2>/dev/null | \
364
+ grep '^WAYLAND_DISPLAY=' | cut -d= -f2)
365
+ fi
366
+ NATIVE_WAYLAND_DISPLAY="${NATIVE_WAYLAND_DISPLAY:-wayland-0}"
367
+ log_event "[vnc.sh:native] session=${session_id} type=wayland display=${NATIVE_DISPLAY:-none} wayland=${NATIVE_WAYLAND_DISPLAY}"
368
+ return 0
369
+ fi
325
370
 
326
- # Discover WAYLAND_DISPLAY from the session leader's environment.
327
- local leader_pid
328
- leader_pid=$(loginctl show-session "$session_id" -p Leader --value 2>/dev/null)
329
- if [ -n "$leader_pid" ] && [ -r "/proc/$leader_pid/environ" ]; then
330
- NATIVE_WAYLAND_DISPLAY=$(tr '\0' '\n' < "/proc/$leader_pid/environ" 2>/dev/null | \
331
- grep '^WAYLAND_DISPLAY=' | cut -d= -f2)
371
+ # x11: $DISPLAY IS the launch vector, so a session that names none does not
372
+ # resolve. Keep scanning rather than substituting a value nothing reported.
373
+ if [ -z "$session_display" ]; then
374
+ log_event "[vnc.sh:native] session=${session_id} type=x11 skipped reason=no-display-value"
375
+ continue
332
376
  fi
333
- NATIVE_WAYLAND_DISPLAY="${NATIVE_WAYLAND_DISPLAY:-wayland-0}"
334
- elif [ -n "$session_type" ]; then
335
- NATIVE_SESSION_TYPE="$session_type"
336
- NATIVE_DISPLAY="${session_display:-:0}"
337
- else
338
- log "WARNING: loginctl returned empty session type — falling back to DISPLAY=:0, ozone-platform=x11"
339
- fi
377
+ NATIVE_SESSION_TYPE="x11"
378
+ NATIVE_DISPLAY="$session_display"
379
+ log_event "[vnc.sh:native] session=${session_id} type=x11 display=${NATIVE_DISPLAY}"
380
+ return 0
381
+ done
382
+
383
+ log_event "[vnc.sh:native] no-graphical-session reason=no-active-local-graphical-session"
384
+ return 1
340
385
  }
341
386
 
342
387
  # Virtual-mode Chromium: HEADED on the brand's Xtigervnc display, driven over
@@ -408,8 +453,25 @@ start_chrome() {
408
453
  # admin chat PTY is the only interactive surface.
409
454
  # ---------------------------------------------------------------------------
410
455
 
456
+ # A native launch that cannot name a display must say so on the caller's own
457
+ # op label, so the refusal is visible to whichever grep is watching that path:
458
+ # op=chromium-start on the on-demand ensureCdp path, op=chromium-respawn on the
459
+ # standing-check path. A supervisor that declines to supervise must say so.
460
+ emit_native_decline() {
461
+ echo "[vnc] op=$1 display-mode=native cdp=:${CDP_PORT} outcome=declined reason=no-graphical-session"
462
+ }
463
+
411
464
  start_chrome_native() {
412
- discover_native_session
465
+ # The precondition for a native launch is an active local graphical session.
466
+ # Guarded here rather than at the call sites so BOTH callers are covered: the
467
+ # standing check and the on-demand ensureCdp path from the browser-pane route.
468
+ # ensureCdp shells this through execFileSync, which throws on a non-zero exit,
469
+ # so a refusal already surfaces there as restart-chrome-failed → false.
470
+ if ! discover_native_session; then
471
+ log "ERROR: refusing native Chromium launch — no active local graphical session"
472
+ emit_native_decline chromium-start
473
+ return 1
474
+ fi
413
475
 
414
476
  # Brand-scoped Chromium kill: only this brand's profile-bound chromium.
415
477
  pkill -f "chromium.*--user-data-dir=${CHROMIUM_PROFILE_DIR}" 2>/dev/null || true
@@ -469,8 +531,15 @@ start_chrome_native() {
469
531
  else
470
532
  log "WARNING: Chromium CDP up on :${CDP_PORT} but no window visible on ${NATIVE_DISPLAY} (native) — observability-only, not gating"
471
533
  fi
534
+ echo "[vnc] op=chromium-start display-mode=native mode=${NATIVE_SESSION_TYPE} cdp=:${CDP_PORT} outcome=ready"
472
535
  else
473
536
  log "ERROR: Chromium failed to start on ${NATIVE_DISPLAY} (native) — CDP port ${CDP_PORT} not listening (browser-specialist degraded)"
537
+ echo "[vnc] op=chromium-start display-mode=native mode=${NATIVE_SESSION_TYPE} cdp=:${CDP_PORT} outcome=failed"
538
+ # Deliberately still exit 0, matching start_chrome. Only the DECLINE exits
539
+ # non-zero, because that is the case ensureCdp must not mistake for a launch
540
+ # that merely needs longer. A launch that started and failed keeps the old
541
+ # contract: ensureCdp's own waitForPort classifies it, and execFileSync does
542
+ # not throw, so its second grace window is not cut short.
474
543
  fi
475
544
  }
476
545
 
@@ -489,8 +558,22 @@ start_chrome_native() {
489
558
  # Bounded: after RESPAWN_MAX_FAILS consecutive failed respawns it backs off for
490
559
  # RESPAWN_COOLDOWN_SECS so an unlaunchable Chromium does not hot-loop (the
491
560
  # snap-confinement FATAL guard at the top of this script already hard-exits
492
- # before any respawn). Virtual-mode only: native mode launches Chromium
493
- # on-demand, so display-up + CDP-down is its normal idle state, not a fault.
561
+ # before any respawn).
562
+ #
563
+ # Task 2780: BOTH modes are supervised. Native was previously a silent
564
+ # early-return on the reasoning that its Chromium is launched on-demand, so
565
+ # display-up + CDP-down was its normal idle state. That was wrong twice over:
566
+ # the only native launcher needs an operator to act, so an agent's browser call
567
+ # found no browser and nothing in the product started one; and a supervisor
568
+ # that emits nothing while declining to supervise is indistinguishable in the
569
+ # journal from one that is running and finding everything healthy — the blind
570
+ # spot this check exists to remove, reintroduced by its own gate.
571
+ #
572
+ # What differs per mode is only the LAUNCH PRECONDITION. Virtual renders onto
573
+ # the brand's Xtigervnc display, so it keeps the RFB_PORT check and a down
574
+ # display stays the ensureVnc case. Native's precondition is an active local
575
+ # graphical session, enforced inside start_chrome_native. The state file, cap
576
+ # and cooldown are shared unchanged.
494
577
  # ---------------------------------------------------------------------------
495
578
  RESPAWN_STATE_FILE="${LOG_DIR}/cdp-respawn.state"
496
579
  RESPAWN_MAX_FAILS="${RESPAWN_MAX_FAILS:-3}"
@@ -512,23 +595,32 @@ port_listening() {
512
595
  }
513
596
 
514
597
  cdp_liveness() {
515
- # Native mode supervises nothing here — Chromium is launched on-demand
516
- # (ensureCdp), so display-up + CDP-down is the normal idle state, and a
517
- # respawn would launch an unsolicited browser on the operator's real display.
518
- if [ "$(resolve_display_mode)" = "native" ]; then
519
- return 0
520
- fi
598
+ local mode
599
+ mode="$(resolve_display_mode)"
521
600
 
522
601
  if port_listening "${CDP_PORT}"; then
523
- echo "[vnc] op=cdp-liveness display=${VNC_DISPLAY} cdp=:${CDP_PORT} reachable=true"
602
+ echo "[vnc] op=cdp-liveness display-mode=${mode} display=${VNC_DISPLAY} cdp=:${CDP_PORT} reachable=true"
524
603
  rm -f "$RESPAWN_STATE_FILE" 2>/dev/null || true
525
604
  return 0
526
605
  fi
527
- echo "[vnc] op=cdp-liveness display=${VNC_DISPLAY} cdp=:${CDP_PORT} reachable=false"
528
-
529
- # Only the VNC-display Chromium is supervised. A down display is the
530
- # VNC-stack-restart case (ensureVnc, on the next browser call) out of scope.
531
- port_listening "${RFB_PORT}" || return 0
606
+ echo "[vnc] op=cdp-liveness display-mode=${mode} display=${VNC_DISPLAY} cdp=:${CDP_PORT} reachable=false"
607
+
608
+ # Launch precondition, per mode. Evaluated BEFORE the cooldown gate so a
609
+ # native decline is never silenced by a cooldown a previous failure set.
610
+ if [ "$mode" = "native" ]; then
611
+ # A decline attempts no launch, so there is nothing to hot-loop: it never
612
+ # counts against the cap and never writes the state file. A box whose real
613
+ # display has gone keeps reporting reachable=false plus this decline every
614
+ # cycle, which is the visibility the cap exists to preserve.
615
+ if ! discover_native_session; then
616
+ emit_native_decline chromium-respawn
617
+ return 0
618
+ fi
619
+ else
620
+ # Only the VNC-display Chromium is supervised here. A down display is the
621
+ # VNC-stack-restart case (ensureVnc, on the next browser call).
622
+ port_listening "${RFB_PORT}" || return 0
623
+ fi
532
624
 
533
625
  # Bounded respawn: read the consecutive-failure state.
534
626
  local fails=0 last=0 now
@@ -548,27 +640,37 @@ cdp_liveness() {
548
640
  return 0
549
641
  fi
550
642
 
551
- # Relaunch via the existing brand-scoped start_chrome path, then re-probe to
552
- # classify the outcome. start_chrome already blocks on wait_for_port, so the
553
- # CDP port state is settled when it returns; reading the port directly keeps
554
- # start_chrome's exit contract untouched (the reactive ensureCdp path in
555
- # vnc.ts consumes it).
556
- start_chrome || true
643
+ # Relaunch via the existing brand-scoped start path for this mode, then
644
+ # re-probe to classify the outcome. Both start paths already block on
645
+ # wait_for_port, so the CDP port state is settled when they return; reading
646
+ # the port directly keeps their exit contracts untouched (the reactive
647
+ # ensureCdp path in vnc.ts consumes them).
648
+ if [ "$mode" = "native" ]; then
649
+ start_chrome_native || true
650
+ else
651
+ start_chrome || true
652
+ fi
557
653
  if port_listening "${CDP_PORT}"; then
558
- echo "[vnc] op=chromium-respawn reason=cdp-unreachable cdp=:${CDP_PORT} outcome=ready"
654
+ echo "[vnc] op=chromium-respawn display-mode=${mode} reason=cdp-unreachable cdp=:${CDP_PORT} outcome=ready"
559
655
  rm -f "$RESPAWN_STATE_FILE" 2>/dev/null || true
560
656
  else
561
657
  # Climb to the cap and hold there; bump last so the next attempt waits a
562
658
  # full cooldown rather than retrying every cycle.
563
659
  [ "$fails" -lt "$RESPAWN_MAX_FAILS" ] && fails=$(( fails + 1 ))
564
660
  printf 'fails=%s\nlast=%s\n' "$fails" "$now" > "$RESPAWN_STATE_FILE"
565
- echo "[vnc] op=chromium-respawn reason=cdp-unreachable cdp=:${CDP_PORT} outcome=failed"
661
+ echo "[vnc] op=chromium-respawn display-mode=${mode} reason=cdp-unreachable cdp=:${CDP_PORT} outcome=failed"
566
662
  fi
567
663
  }
568
664
 
569
665
  case "${1:-}" in
570
666
  start)
571
- log "[vnc.sh] start brand=${BRAND_HOSTNAME} display=${VNC_DISPLAY} rfb=${RFB_PORT} websockify=${WEBSOCKIFY_PORT} cdp=${CDP_PORT} profile=${CHROMIUM_PROFILE_DIR} mode=${DISPLAY_MODE:-virtual}"
667
+ # resolve_display_mode() is the ONLY reader of DISPLAY_MODE in this script.
668
+ # Boot previously read the env var directly while the standing check read
669
+ # the brand .env; no unit file in the fleet exports DISPLAY_MODE, so every
670
+ # install whose .env said native still booted the virtual-mode browser
671
+ # while its supervisor believed it was native and supervised nothing.
672
+ START_DISPLAY_MODE="$(resolve_display_mode)"
673
+ log "[vnc.sh] start brand=${BRAND_HOSTNAME} display=${VNC_DISPLAY} rfb=${RFB_PORT} websockify=${WEBSOCKIFY_PORT} cdp=${CDP_PORT} profile=${CHROMIUM_PROFILE_DIR} mode=${START_DISPLAY_MODE}"
572
674
  # Collision checks run BEFORE kill_stale: kill_stale removes our own
573
675
  # locks/processes, so a check afterwards would always see them empty
574
676
  # and never refuse. The checks are no-ops for our own brand's prior
@@ -616,10 +718,11 @@ case "${1:-}" in
616
718
  exit 1
617
719
  fi
618
720
 
619
- # Native mode: VNC stack runs for remote fallback, but Chromium
620
- # is launched on-demand by ensureCdp(transport) not at boot.
621
- if [ "${DISPLAY_MODE:-virtual}" = "native" ]; then
622
- log "Native display mode skipping boot-time Chromium (launched on-demand)"
721
+ # Native mode: VNC stack runs for remote fallback, but Chromium is not
722
+ # launched at boot. It comes up on-demand via ensureCdp(transport), and is
723
+ # restored by the standing cdp-liveness check when it dies.
724
+ if [ "${START_DISPLAY_MODE}" = "native" ]; then
725
+ log "Native display mode — skipping boot-time Chromium (launched on-demand and by the standing check)"
623
726
  else
624
727
  start_chrome
625
728
  fi