@rubytech/create-realagent 1.0.858 → 1.0.860

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.
@@ -49,6 +49,10 @@ The plugin registers no agent-facing MCP tools. Every Cloudflare operation is dr
49
49
 
50
50
  The agent loads these references on demand via `plugin-read` as the conversation requires. They are not auto-injected into the system prompt.
51
51
 
52
+ ### UI contract
53
+
54
+ `cloudflare-setup-form` (rendered via `render-component`) invokes `useDeviceUrlActions().onShowVnc()` immediately after a successful POST to `/api/admin/cloudflare/setup`. This auto-surfaces the brand-VNC overlay before `ActionLogPanel` shows the OAuth URL inside it, so the operator never has to open the menu manually. The `[browser-viewer] event=mount surface="overlay"` line must appear within 5 s of `[cloudflare-setup] phase=action-launched`; absence is a regression.
55
+
52
56
  ## Identity model
53
57
 
54
58
  - **Product identity** (Maxy vs Real Agent) — known from `brand.json` (`productName`, `configDir`).
@@ -2,7 +2,7 @@
2
2
 
3
3
  Step-by-step recovery path for when the Maxy automation fails or is unavailable. Every command below is isolated in its own code block — nothing to parse from prose. Every path is brand-scoped so multiple brands can coexist on the same Linux user.
4
4
 
5
- Prerequisites: `cloudflared` installed; the brand's VNC running on its own X display + rfbport + websockify + CDP port (per `brand.json`'s `vncDisplay`/`rfbPort`/`websockifyPort`/`cdpPort` fields — Tasks 553 + 924; defaults Maxy=`:99`/`5900`/`6080`/`9222`, Real Agent=`:100`/`5901`/`6081`/`9223`, Maxy-2=`:101`/`5902`/`6082`/`9224`, Maxy-3=`:102`/`5903`/`6083`/`9225`, Maxy-4=`:103`/`5904`/`6084`/`9226`); SSH access to the device.
5
+ Prerequisites: `cloudflared` installed; the brand's VNC running on its own X display + rfbport + websockify + CDP port (per `brand.json`'s `vncDisplay`/`rfbPort`/`websockifyPort`/`cdpPort` fields — Tasks 553 + 924; defaults Maxy=`:99`/`5900`/`6080`/`9222`, Real Agent=`:100`/`5901`/`6081`/`9223`, Maxy-2=`:101`/`5902`/`6082`/`9224`, Maxy-3=`:102`/`5903`/`6083`/`9225`, Maxy-4=`:103`/`5904`/`6084`/`9226`); SSH access to the device. The defaults table is historical — runtime readers (`paths.ts`, admin/MCP, `vnc.sh`, `test-laptop-vnc-boot.sh`) loud-fail with `reason=cdp-port-unresolved` if any of `rfbPort`/`websockifyPort`/`cdpPort` is missing from the live `brand.json`; the values above show what each brand's `brand.json` contains, not what the readers fall back to.
6
6
 
7
7
  ---
8
8
 
@@ -29,7 +29,14 @@ pass() { echo "OK: $*"; }
29
29
  [ -r "$BRAND_JSON" ] || fail "${BRAND_JSON} unreadable"
30
30
  command -v jq >/dev/null 2>&1 || fail "jq not on PATH (apt install jq)"
31
31
  CONFIG_DIR=$(jq -r '.configDir // ".maxy"' "$BRAND_JSON")
32
- CDP_PORT=$(jq -r '.cdpPort // 9222' "$BRAND_JSON")
32
+ # Task 959 — brand.json is the single source of truth for cdpPort at
33
+ # runtime; a missing field is a doctrinal violation, not a fallback.
34
+ if ! CDP_PORT=$(jq -er '.cdpPort' "$BRAND_JSON" 2>/dev/null); then
35
+ _keys=$(jq -r 'keys | join(",")' "$BRAND_JSON" 2>/dev/null || echo "unparseable")
36
+ _brand=$(echo "$CONFIG_DIR" | sed 's/^\.//')
37
+ echo "[test-laptop-vnc-boot] error reason=cdp-port-unresolved brand=$_brand path=$BRAND_JSON field=cdpPort json_keys=$_keys" >&2
38
+ exit 1
39
+ fi
33
40
  PERSIST_DIR="${HOME}/${CONFIG_DIR}"
34
41
  VNC_LOG="${PERSIST_DIR}/logs/vnc-boot.log"
35
42
 
@@ -41,36 +41,42 @@ set -uo pipefail
41
41
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
42
42
  PLATFORM_ROOT="${MAXY_PLATFORM_ROOT:-$(dirname "$SCRIPT_DIR")}"
43
43
  BRAND_JSON="${PLATFORM_ROOT}/config/brand.json"
44
- CONFIG_DIR=".maxy"
45
- VNC_DISPLAY_NUM=99
46
- RFB_PORT=""
47
- WEBSOCKIFY_PORT=""
48
- CDP_PORT=""
49
- BRAND_HOSTNAME="maxy"
50
- if [ -f "$BRAND_JSON" ] && command -v jq >/dev/null 2>&1; then
51
- _dir=$(jq -r '.configDir // empty' "$BRAND_JSON" 2>/dev/null) || true
52
- [ -n "$_dir" ] && CONFIG_DIR="$_dir"
53
- _vd=$(jq -r '.vncDisplay // empty' "$BRAND_JSON" 2>/dev/null) || true
54
- if [ -n "$_vd" ] && [ "$_vd" -eq "$_vd" ] 2>/dev/null; then
55
- VNC_DISPLAY_NUM="$_vd"
56
- fi
57
- _rfb=$(jq -r '.rfbPort // empty' "$BRAND_JSON" 2>/dev/null) || true
58
- if [ -n "$_rfb" ] && [ "$_rfb" -eq "$_rfb" ] 2>/dev/null; then RFB_PORT="$_rfb"; fi
59
- _wsp=$(jq -r '.websockifyPort // empty' "$BRAND_JSON" 2>/dev/null) || true
60
- if [ -n "$_wsp" ] && [ "$_wsp" -eq "$_wsp" ] 2>/dev/null; then WEBSOCKIFY_PORT="$_wsp"; fi
61
- _cdp=$(jq -r '.cdpPort // empty' "$BRAND_JSON" 2>/dev/null) || true
62
- if [ -n "$_cdp" ] && [ "$_cdp" -eq "$_cdp" ] 2>/dev/null; then CDP_PORT="$_cdp"; fi
63
- _hn=$(jq -r '.hostname // empty' "$BRAND_JSON" 2>/dev/null) || true
64
- [ -n "$_hn" ] && BRAND_HOSTNAME="$_hn"
44
+
45
+ # Task 959 — brand.json is the single source of truth at runtime; missing
46
+ # fields loud-fail rather than silently substituting a vncDisplay-derived
47
+ # offset (silent-fallback-masks-root-cause recurrence). The install-time
48
+ # offset rule in packages/create-maxy/src/index.ts stamps every brand at
49
+ # build time, so a correctly-installed device always has all five fields.
50
+ if [ ! -f "$BRAND_JSON" ]; then
51
+ echo "[vnc.sh] error reason=brand-config-missing path=$BRAND_JSON" >&2
52
+ exit 1
53
+ fi
54
+ if ! command -v jq >/dev/null 2>&1; then
55
+ echo "[vnc.sh] error reason=brand-config-missing path=$BRAND_JSON detail=\"jq not on PATH\"" >&2
56
+ exit 1
65
57
  fi
66
58
 
67
- # Task 924 deterministic fallback when brand.json omits any of the three
68
- # new port fields. Mirrors the rule in paths.ts so vnc.sh and the runtime
69
- # always agree on the port set even when only `vncDisplay` is stamped.
70
- _offset=$((VNC_DISPLAY_NUM - 99))
71
- [ -z "$RFB_PORT" ] && RFB_PORT=$((5900 + _offset))
72
- [ -z "$WEBSOCKIFY_PORT" ] && WEBSOCKIFY_PORT=$((6080 + _offset))
73
- [ -z "$CDP_PORT" ] && CDP_PORT=$((9222 + _offset))
59
+ # `exit 1` inside a `$(…)` command substitution only kills the subshell, so
60
+ # the loud-fail uses a parent-context `||` chain instead. Each field is read
61
+ # with `jq -e` (exit non-zero on null/missing) and a parent-context error
62
+ # helper invokes the script-level `exit 1`.
63
+ _fail_brand_field() {
64
+ local field="$1"
65
+ local keys
66
+ keys=$(jq -r 'keys | join(",")' "$BRAND_JSON" 2>/dev/null || echo "unparseable")
67
+ local brand_label
68
+ brand_label=$(jq -r '.configDir // "unknown"' "$BRAND_JSON" 2>/dev/null | sed 's/^\.//')
69
+ echo "[vnc.sh] error reason=cdp-port-unresolved brand=$brand_label path=$BRAND_JSON field=$field json_keys=$keys" >&2
70
+ exit 1
71
+ }
72
+
73
+ CONFIG_DIR=$(jq -er '.configDir' "$BRAND_JSON" 2>/dev/null) || _fail_brand_field configDir
74
+ VNC_DISPLAY_NUM=$(jq -er '.vncDisplay' "$BRAND_JSON" 2>/dev/null) || _fail_brand_field vncDisplay
75
+ RFB_PORT=$(jq -er '.rfbPort' "$BRAND_JSON" 2>/dev/null) || _fail_brand_field rfbPort
76
+ WEBSOCKIFY_PORT=$(jq -er '.websockifyPort' "$BRAND_JSON" 2>/dev/null) || _fail_brand_field websockifyPort
77
+ CDP_PORT=$(jq -er '.cdpPort' "$BRAND_JSON" 2>/dev/null) || _fail_brand_field cdpPort
78
+ BRAND_HOSTNAME=$(jq -r '.hostname // empty' "$BRAND_JSON" 2>/dev/null)
79
+ [ -z "$BRAND_HOSTNAME" ] && BRAND_HOSTNAME="${CONFIG_DIR#.}"
74
80
 
75
81
  VNC_DISPLAY=":${VNC_DISPLAY_NUM}"
76
82
  MAXY_DIR="${HOME}/${CONFIG_DIR}"