Skip to content
32 changes: 19 additions & 13 deletions bin/lib/onboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -525,8 +525,9 @@ function isOpenclawReady(sandboxName) {
return Boolean(fetchGatewayAuthTokenFromSandbox(sandboxName));
}

function writeSandboxConfigSyncFile(script, tmpDir = os.tmpdir(), now = Date.now()) {
const scriptFile = path.join(tmpDir, `nemoclaw-sync-${now}.sh`);
function writeSandboxConfigSyncFile(script, tmpDir = os.tmpdir()) {
const dir = fs.mkdtempSync(path.join(tmpDir, "nemoclaw-sync-"));
const scriptFile = path.join(dir, "sync.sh");
fs.writeFileSync(scriptFile, `${script}\n`, { mode: 0o600 });
return scriptFile;
}
Expand Down Expand Up @@ -665,7 +666,8 @@ function probeOpenAiLikeEndpoint(endpointUrl, model, apiKey) {

const failures = [];
for (const probe of probes) {
const bodyFile = path.join(os.tmpdir(), `nemoclaw-probe-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
const probeDir = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-probe-"));
const bodyFile = path.join(probeDir, "body.json");
try {
const cmd = [
"curl -sS",
Expand Down Expand Up @@ -698,7 +700,7 @@ function probeOpenAiLikeEndpoint(endpointUrl, model, apiKey) {
message: summarizeProbeError(body, status || result.status || 0),
});
} finally {
fs.rmSync(bodyFile, { force: true });
fs.rmSync(probeDir, { recursive: true, force: true });
}
}

Expand All @@ -710,7 +712,8 @@ function probeOpenAiLikeEndpoint(endpointUrl, model, apiKey) {
}

function probeAnthropicEndpoint(endpointUrl, model, apiKey) {
const bodyFile = path.join(os.tmpdir(), `nemoclaw-anthropic-probe-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
const probeDir = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-anthropic-probe-"));
const bodyFile = path.join(probeDir, "body.json");
try {
const cmd = [
"curl -sS",
Expand Down Expand Up @@ -753,7 +756,7 @@ function probeAnthropicEndpoint(endpointUrl, model, apiKey) {
],
};
} finally {
fs.rmSync(bodyFile, { force: true });
fs.rmSync(probeDir, { recursive: true, force: true });
}
}

Expand Down Expand Up @@ -857,7 +860,8 @@ async function validateCustomAnthropicSelection(label, endpointUrl, model, crede
}

function fetchNvidiaEndpointModels(apiKey) {
const bodyFile = path.join(os.tmpdir(), `nemoclaw-nvidia-models-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
const probeDir = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-nvidia-models-"));
const bodyFile = path.join(probeDir, "body.json");
try {
const cmd = [
"curl -sS",
Expand Down Expand Up @@ -890,7 +894,7 @@ function fetchNvidiaEndpointModels(apiKey) {
} catch (error) {
return { ok: false, message: error.message || String(error) };
} finally {
fs.rmSync(bodyFile, { force: true });
fs.rmSync(probeDir, { recursive: true, force: true });
}
}

Expand All @@ -912,7 +916,8 @@ function validateNvidiaEndpointModel(model, apiKey) {
}

function fetchOpenAiLikeModels(endpointUrl, apiKey) {
const bodyFile = path.join(os.tmpdir(), `nemoclaw-openai-models-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
const probeDir = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-openai-models-"));
const bodyFile = path.join(probeDir, "body.json");
try {
const cmd = [
"curl -sS",
Expand Down Expand Up @@ -944,12 +949,13 @@ function fetchOpenAiLikeModels(endpointUrl, apiKey) {
} catch (error) {
return { ok: false, status: 0, message: error.message || String(error) };
} finally {
fs.rmSync(bodyFile, { force: true });
fs.rmSync(probeDir, { recursive: true, force: true });
}
}

function fetchAnthropicModels(endpointUrl, apiKey) {
const bodyFile = path.join(os.tmpdir(), `nemoclaw-anthropic-models-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
const probeDir = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-anthropic-models-"));
const bodyFile = path.join(probeDir, "body.json");
try {
const cmd = [
"curl -sS",
Expand Down Expand Up @@ -982,7 +988,7 @@ function fetchAnthropicModels(endpointUrl, apiKey) {
} catch (error) {
return { ok: false, status: 0, message: error.message || String(error) };
} finally {
fs.rmSync(bodyFile, { force: true });
fs.rmSync(probeDir, { recursive: true, force: true });
}
}

Expand Down Expand Up @@ -2417,7 +2423,7 @@ async function setupOpenclaw(sandboxName, model, provider) {
{ stdio: ["ignore", "ignore", "inherit"] }
);
} finally {
fs.unlinkSync(scriptFile);
fs.rmSync(path.dirname(scriptFile), { recursive: true, force: true });
}
}

Expand Down
8 changes: 6 additions & 2 deletions test/onboard.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -428,9 +428,13 @@ describe("onboard helpers", () => {
it("writes sandbox sync scripts to a temp file for stdin redirection", () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-onboard-test-"));
try {
const scriptFile = writeSandboxConfigSyncFile("echo test", tmpDir, 1234);
expect(scriptFile).toBe(path.join(tmpDir, "nemoclaw-sync-1234.sh"));
const scriptFile = writeSandboxConfigSyncFile("echo test", tmpDir);
expect(scriptFile).toMatch(/nemoclaw-sync-.*[/\\]sync\.sh$/);
expect(fs.readFileSync(scriptFile, "utf8")).toBe("echo test\n");
if (process.platform !== "win32") {
const stat = fs.statSync(scriptFile);
expect(stat.mode & 0o777).toBe(0o600);
}
} finally {
fs.rmSync(tmpDir, { recursive: true, force: true });
}
Expand Down
Loading