@runuai/host 0.9.151 → 0.9.152
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.
|
@@ -1685,7 +1685,11 @@ export async function stopAnchoredEngines(
|
|
|
1685
1685
|
request.taskId,
|
|
1686
1686
|
String(request.runEpoch),
|
|
1687
1687
|
named === undefined ? "all" : "named",
|
|
1688
|
-
|
|
1688
|
+
// Every provider refuses an empty argv entry, and "all" names no
|
|
1689
|
+
// account: a lone newline stands for the empty list (the helper drops
|
|
1690
|
+
// blank names). Live 2026-10-11: the empty string failed every
|
|
1691
|
+
// stop-all, so no cleanup, recovery sweep or relaunch could finish.
|
|
1692
|
+
(named ?? []).map(idPathSegment).join("\n") || "\n",
|
|
1689
1693
|
String(anchorStopSeconds),
|
|
1690
1694
|
carrierRoots(),
|
|
1691
1695
|
],
|
package/lib/orchestrator.ts
CHANGED
|
@@ -3087,7 +3087,14 @@ export class Orchestrator {
|
|
|
3087
3087
|
);
|
|
3088
3088
|
try {
|
|
3089
3089
|
await Promise.all(earlier.map((retired) => this.retireInRuntime(retired)));
|
|
3090
|
-
} catch {
|
|
3090
|
+
} catch (error) {
|
|
3091
|
+
// Live 2026-10-11: this refusal was silent, so agents that never started
|
|
3092
|
+
// left nothing in the log to say why.
|
|
3093
|
+
console.warn(
|
|
3094
|
+
`[orchestrator] ${slot.identity.taskId}/${agentId}: not starting the agent, an earlier start could not be retired in its runtime (${
|
|
3095
|
+
error instanceof Error ? error.message : String(error)
|
|
3096
|
+
})`,
|
|
3097
|
+
);
|
|
3091
3098
|
throw new EngineLaunchRefused("an earlier start of this agent could not be retired in its runtime yet");
|
|
3092
3099
|
}
|
|
3093
3100
|
}
|
|
@@ -100,9 +100,19 @@ export interface RuntimeNamespace {
|
|
|
100
100
|
/** macOS (11 and later): fail if any component of the path is a link. */
|
|
101
101
|
const O_NOFOLLOW_ANY = 0x20000000;
|
|
102
102
|
const DIRECTORY = constants.O_RDONLY | constants.O_DIRECTORY;
|
|
103
|
-
/** macOS: a directory, a link nowhere in its path
|
|
104
|
-
*
|
|
105
|
-
|
|
103
|
+
/** macOS: a directory, a link nowhere in its path, the last component
|
|
104
|
+
* included. Never with O_NOFOLLOW: O_NOFOLLOW_ANY already refuses a final
|
|
105
|
+
* link, and macOS 27 rejects the two together with EINVAL (live
|
|
106
|
+
* 2026-10-11: every workspace read and write failed on the Studio). */
|
|
107
|
+
const DARWIN = process.platform === "darwin";
|
|
108
|
+
/** Elsewhere (tests forcing this mode on Linux, where O_NOFOLLOW_ANY means
|
|
109
|
+
* nothing) O_NOFOLLOW stays, so a final link is still refused there. */
|
|
110
|
+
const DIRECTORY_NOFOLLOW_ANY = DIRECTORY | O_NOFOLLOW_ANY | (DARWIN ? 0 : constants.O_NOFOLLOW);
|
|
111
|
+
/** The flags one file is opened with in this mode: on macOS `flags` without
|
|
112
|
+
* O_NOFOLLOW, which O_NOFOLLOW_ANY covers and cannot be combined with. */
|
|
113
|
+
function nofollowAnyFlags(flags: number): number {
|
|
114
|
+
return (DARWIN ? flags & ~constants.O_NOFOLLOW : flags) | O_NOFOLLOW_ANY;
|
|
115
|
+
}
|
|
106
116
|
|
|
107
117
|
type Containment = "proc-fd" | "nofollow-any" | "verify";
|
|
108
118
|
let containment: Containment | null = null;
|
|
@@ -128,7 +138,9 @@ function probeContainment(): Containment {
|
|
|
128
138
|
}
|
|
129
139
|
}
|
|
130
140
|
if (process.platform === "darwin") {
|
|
131
|
-
|
|
141
|
+
// Resolved: macOS's temporary directory is below /var, itself a link,
|
|
142
|
+
// which O_NOFOLLOW_ANY refuses on every path through it.
|
|
143
|
+
const scratch = realpathSync(mkdtempSync(join(tmpdir(), "uai-nofollow-any-")));
|
|
132
144
|
try {
|
|
133
145
|
mkdirSync(join(scratch, "real"));
|
|
134
146
|
writeFileSync(join(scratch, "real", "file"), "");
|
|
@@ -138,8 +150,23 @@ function probeContainment(): Containment {
|
|
|
138
150
|
// Opened through the link: the flag is not honored here.
|
|
139
151
|
return "verify";
|
|
140
152
|
} catch (error) {
|
|
141
|
-
|
|
153
|
+
if ((error as NodeJS.ErrnoException).code !== "ELOOP") return "verify";
|
|
154
|
+
}
|
|
155
|
+
// The exact flags the real opens use must work on a plain file and
|
|
156
|
+
// directory too: a flag the kernel refuses in combination would
|
|
157
|
+
// otherwise fail every workspace operation, not just links.
|
|
158
|
+
try {
|
|
159
|
+
closeSync(
|
|
160
|
+
openSync(
|
|
161
|
+
join(scratch, "real", "file"),
|
|
162
|
+
nofollowAnyFlags(constants.O_WRONLY | constants.O_APPEND | constants.O_NONBLOCK | constants.O_NOFOLLOW),
|
|
163
|
+
),
|
|
164
|
+
);
|
|
165
|
+
closeSync(openSync(join(scratch, "real"), DIRECTORY_NOFOLLOW_ANY));
|
|
166
|
+
} catch {
|
|
167
|
+
return "verify";
|
|
142
168
|
}
|
|
169
|
+
return "nofollow-any";
|
|
143
170
|
} finally {
|
|
144
171
|
rmSync(scratch, { recursive: true, force: true });
|
|
145
172
|
}
|
|
@@ -255,7 +282,7 @@ function openWithin(root: string, parts: readonly string[], flags: number): numb
|
|
|
255
282
|
}
|
|
256
283
|
}
|
|
257
284
|
if (mode === "nofollow-any") {
|
|
258
|
-
return openSync(join(base, ...parts), finalFlags
|
|
285
|
+
return openSync(join(base, ...parts), nofollowAnyFlags(finalFlags), 0o644);
|
|
259
286
|
}
|
|
260
287
|
// Neither: a read verifies what it opened; nothing is written.
|
|
261
288
|
if ((flags & (constants.O_WRONLY | constants.O_RDWR | constants.O_CREAT)) !== 0) {
|