@runuai/host 0.9.96 → 0.9.97

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.
@@ -933,7 +933,7 @@ console.log(
933
933
  * under tiny restart loops — x11vnc EXITS whenever the X server it watches
934
934
  * isn't up yet (the race that killed the first live run), and the loops
935
935
  * also reattach after the display owner changes. Safe to run repeatedly:
936
- * every piece is pgrep-guarded, including the loops themselves.
936
+ * every piece is guarded by the X lockfile or a pidfile, loops included.
937
937
  */
938
938
  /**
939
939
  * The viewer daemons, one docker-exec each (the single-line nohup shape is
@@ -950,6 +950,22 @@ console.log(
950
950
  * proxy only SOMETIMES and reconnects the rest (live 2026-09-02). So the
951
951
  * start branch — reached only when the tracked loop is already dead — first
952
952
  * reaps anything still holding the port, guaranteeing exactly one listener.
953
+ *
954
+ * That reap MUST be `pkill -A` (--ignore-ancestors). The step runs as
955
+ * `sh -c "<step>"`, so the launching shell's own cmdline carries the launch
956
+ * line and matches the reap pattern: plain `pkill -f` SIGTERMed that shell
957
+ * before it reached the nohup, and neither daemon ever started — host
958
+ * 0.9.94–0.9.96, every Linux runtime (the pgrep self-match above, wearing a
959
+ * kill; reproduced in the uai-linux VM: step exit 143, no pidfile). Both
960
+ * shipped images run procps-ng 4.0.2 (Debian bookworm), which has -A; an
961
+ * older procps rejects the flag with a usage error and reaps nothing, which
962
+ * merely restores the pre-reap behaviour and never the self-kill.
963
+ * `-A` protects the launching chain only: the apt worker below inlines
964
+ * these steps into `su -c` / `nohup sh -c` wrappers whose argv also
965
+ * matches, and a per-session reap that lands inside that worker's ~1 s
966
+ * viewer window can kill its node-uid shell. That only costs the worker
967
+ * its done-marker (set -e), so it re-runs on the next ensure and finds the
968
+ * pidfiles alive — self-healing, and no worse than the pre-reap world.
953
969
  */
954
970
  const VIEWER_STEPS: string[] = [
955
971
  // Xvfb — one-shot; the X lockfile is the truth (also set when an agent
@@ -958,9 +974,9 @@ const VIEWER_STEPS: string[] = [
958
974
  `[ -x /usr/bin/Xvfb ] || exit 0; [ -e ${X_LOCK} ] || /usr/bin/nohup /usr/bin/${XVFB_CMD} >>/tmp/uai-xvfb.log 2>&1 &`,
959
975
  // x11vnc under a restart loop (it exits whenever the X server isn't up
960
976
  // yet). Pidfile-guarded.
961
- `[ -x /usr/bin/x11vnc ] || exit 0; [ -f /tmp/uai-x11vnc.pid ] && /usr/bin/kill -0 "$(/usr/bin/cat /tmp/uai-x11vnc.pid)" 2>/dev/null && exit 0; /usr/bin/pkill -f 'x11vnc -display' 2>/dev/null; /usr/bin/nohup /bin/sh -c 'echo $$ > /tmp/uai-x11vnc.pid; while true; do /usr/bin/x11vnc -display ${SERVER_DISPLAY} -forever -shared -nopw -quiet >>/tmp/uai-x11vnc.log 2>&1; /bin/sleep 2; done' >/dev/null 2>&1 &`,
977
+ `[ -x /usr/bin/x11vnc ] || exit 0; [ -f /tmp/uai-x11vnc.pid ] && /usr/bin/kill -0 "$(/usr/bin/cat /tmp/uai-x11vnc.pid)" 2>/dev/null && exit 0; /usr/bin/pkill -A -f 'x11vnc -display' 2>/dev/null; /usr/bin/nohup /bin/sh -c 'echo $$ > /tmp/uai-x11vnc.pid; while true; do /usr/bin/x11vnc -display ${SERVER_DISPLAY} -forever -shared -nopw -quiet >>/tmp/uai-x11vnc.log 2>&1; /bin/sleep 2; done' >/dev/null 2>&1 &`,
962
978
  // websockify/noVNC under the same pattern.
963
- `[ -x /usr/bin/websockify ] || exit 0; [ -f /tmp/uai-novnc.pid ] && /usr/bin/kill -0 "$(/usr/bin/cat /tmp/uai-novnc.pid)" 2>/dev/null && exit 0; /usr/bin/pkill -f 'websockify.*6080' 2>/dev/null; /usr/bin/nohup /bin/sh -c 'echo $$ > /tmp/uai-novnc.pid; while true; do /usr/bin/websockify --web=/usr/share/novnc 0.0.0.0:6080 localhost:5900 >>/tmp/uai-websockify.log 2>&1; /bin/sleep 2; done' >/dev/null 2>&1 &`,
979
+ `[ -x /usr/bin/websockify ] || exit 0; [ -f /tmp/uai-novnc.pid ] && /usr/bin/kill -0 "$(/usr/bin/cat /tmp/uai-novnc.pid)" 2>/dev/null && exit 0; /usr/bin/pkill -A -f 'websockify.*6080' 2>/dev/null; /usr/bin/nohup /bin/sh -c 'echo $$ > /tmp/uai-novnc.pid; while true; do /usr/bin/websockify --web=/usr/share/novnc 0.0.0.0:6080 localhost:5900 >>/tmp/uai-websockify.log 2>&1; /bin/sleep 2; done' >/dev/null 2>&1 &`,
964
980
  ];
965
981
 
966
982
  const DEFAULT_NODE_BIN =
@@ -1085,13 +1101,20 @@ export async function setupBrowserTesting(
1085
1101
  // costs ~0.5s once the build is present.
1086
1102
  const installed = environment
1087
1103
  ? await (async () => {
1088
- await environment.exec({
1104
+ const chown = await environment.exec({
1089
1105
  argv: ["/usr/bin/chown", "node:node", "/opt/pw-browsers"],
1090
1106
  user: "root",
1091
1107
  env: authorityEnv,
1092
1108
  timeoutMs: 5_000,
1093
1109
  maxOutputBytes: 64 * 1024,
1094
1110
  });
1111
+ if (chown.exitCode !== 0) {
1112
+ // Same non-fatal stance as the CLI path below.
1113
+ console.warn(
1114
+ `[browser] task ${taskId}: chown /opt/pw-browsers failed (status ${chown.exitCode}); ` +
1115
+ `continuing with the prewarm. ${Buffer.from(chown.stderr).toString("utf8").slice(0, 200)}`,
1116
+ );
1117
+ }
1095
1118
  return environment.exec({
1096
1119
  argv: ["sh", "-lc", PREWARM_CMD],
1097
1120
  cwd: "/workspace",
@@ -1113,7 +1136,16 @@ export async function setupBrowserTesting(
1113
1136
  ],
1114
1137
  { timeoutMs: 5_000 },
1115
1138
  ).then(async (chown) => {
1116
- if (chown.status !== 0) return chown;
1139
+ if (chown.status !== 0) {
1140
+ // Not fatal. On apple-container /opt/pw-browsers is a host-wide
1141
+ // virtiofs volume whose ownership the guest cannot change (EPERM)
1142
+ // although it is already node-owned inside the container; the
1143
+ // prewarm below is the real test of writability, so let it decide.
1144
+ console.warn(
1145
+ `[browser] task ${taskId}: chown /opt/pw-browsers failed (status ${chown.status}); ` +
1146
+ `continuing with the prewarm. ${chown.stderr.slice(0, 200)}`,
1147
+ );
1148
+ }
1117
1149
  return taskContainerCli(
1118
1150
  [
1119
1151
  "exec",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runuai/host",
3
- "version": "0.9.96",
3
+ "version": "0.9.97",
4
4
  "description": "Uai host — runs ephemeral AI tasks in containers on a machine you control.",
5
5
  "license": "MIT",
6
6
  "author": "Uai Tech <team@runuai.com>",