@runuai/host 0.9.95 → 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.
- package/lib/browser-testing.ts +37 -5
- package/lib/orchestrator.ts +26 -0
- package/package.json +1 -1
package/lib/browser-testing.ts
CHANGED
|
@@ -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
|
|
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)
|
|
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/lib/orchestrator.ts
CHANGED
|
@@ -3695,6 +3695,31 @@ export function buildSystemPreamble(
|
|
|
3695
3695
|
"someone only to bring them in or hand work off. (2) You may occasionally",
|
|
3696
3696
|
"receive a `[channel check-in]` asking you to catch up on the channel.",
|
|
3697
3697
|
];
|
|
3698
|
+
// Reply cards: agents may offer the human a bounded, clickable answer. Only
|
|
3699
|
+
// the human-facing agents get this (the crew talks to the Secretary, not
|
|
3700
|
+
// people). Engine-agnostic — it is a chat markdown convention.
|
|
3701
|
+
const replyCardBrief =
|
|
3702
|
+
isSecretaryCrew
|
|
3703
|
+
? []
|
|
3704
|
+
: [
|
|
3705
|
+
"When you need a SHORT, bounded answer from the human — pick one of a",
|
|
3706
|
+
"few options, or a yes/no — you may offer a reply card instead of a",
|
|
3707
|
+
"plain question. Write a fenced block the app turns into buttons:",
|
|
3708
|
+
"",
|
|
3709
|
+
"```uai-ask",
|
|
3710
|
+
"type: choice",
|
|
3711
|
+
"question: Which chain should I target first?",
|
|
3712
|
+
"options:",
|
|
3713
|
+
" - Robinhood",
|
|
3714
|
+
" - Base",
|
|
3715
|
+
" - Skip for now",
|
|
3716
|
+
"```",
|
|
3717
|
+
"",
|
|
3718
|
+
"Use `type: confirm` (no options) for a yes/no. The human's click",
|
|
3719
|
+
"arrives as their normal reply. Offer a card only when the answer",
|
|
3720
|
+
"really is a small fixed set — for anything open-ended, just ask in",
|
|
3721
|
+
"prose. At most one card per message, and never for the crew.",
|
|
3722
|
+
];
|
|
3698
3723
|
const comms = [
|
|
3699
3724
|
"## uai task channel",
|
|
3700
3725
|
"",
|
|
@@ -3718,6 +3743,7 @@ export function buildSystemPreamble(
|
|
|
3718
3743
|
...(sessionInboxBrief.length > 0 ? [""] : []),
|
|
3719
3744
|
...secretaryRoleBrief,
|
|
3720
3745
|
...channelConventionsBrief,
|
|
3746
|
+
...(replyCardBrief.length > 0 ? ["", ...replyCardBrief] : []),
|
|
3721
3747
|
...checkInTranscriptBrief,
|
|
3722
3748
|
"",
|
|
3723
3749
|
...handoffBrief,
|