fix: support ts backend core cli probes

This commit is contained in:
Codex
2026-05-18 16:20:11 +00:00
parent 803a695d0a
commit 29dab8fab2
6 changed files with 95 additions and 20 deletions
+1 -5
View File
@@ -763,11 +763,7 @@ async function deployBackendCoreNow(options: ArtifactRegistryOptions): Promise<R
"image_id=$(docker inspect -f '{{.Image}}' \"$cid\")",
"actual_commit=$(docker image inspect -f '{{ index .Config.Labels \"unidesk.ai/source-commit\" }}' \"$image_id\")",
`test "$actual_commit" = ${shellQuote(commit)}`,
"if docker exec \"$cid\" sh -lc 'command -v backend-core >/dev/null 2>&1'; then",
" docker exec \"$cid\" backend-core --fetch-json http://127.0.0.1:8080/health --require-ok >/tmp/unidesk-backend-core-health.json",
"else",
" docker exec \"$cid\" bun -e \"fetch('http://127.0.0.1:8080/health').then(async r=>{console.log(await r.text()); process.exit(r.ok?0:1)}).catch(e=>{console.error(e); process.exit(1)})\" >/tmp/unidesk-backend-core-health.json",
"fi",
"docker exec \"$cid\" bun -e \"fetch('http://127.0.0.1:8080/health').then(async r=>{const text=await r.text(); console.log(text); process.exit(r.ok?0:1)}).catch(e=>{console.error(e); process.exit(1)})\" >/tmp/unidesk-backend-core-health.json",
"cat /tmp/unidesk-backend-core-health.json",
].join("\n");
const deploy = runCommand(["bash", "-lc", composeLockScript(upScript)], repoRoot, { timeoutMs: Math.max(options.timeoutMs, 300_000) });
+25 -4
View File
@@ -22,9 +22,30 @@ async function readJson(url: string, init?: RequestInit): Promise<unknown> {
}
}
function coreFetchCommand(path: string, init?: { method?: string; body?: unknown }): string[] {
const method = init?.method ?? "GET";
const url = `http://127.0.0.1:8080${path}`;
const body = init?.body === undefined ? "" : JSON.stringify(init.body);
const script = [
"set -euo pipefail",
"if command -v backend-core >/dev/null 2>&1; then",
` exec backend-core --fetch-json ${shellQuote(url)} --method ${shellQuote(method)}${body.length > 0 ? ` --body-json ${shellQuote(body)}` : ""}`,
"fi",
`url=${shellQuote(url)}`,
`method=${shellQuote(method)}`,
`body=${shellQuote(body)}`,
"export url method body",
"bun -e 'const url=process.env.url; const method=process.env.method; const body=process.env.body; fetch(url,{method,body:body?body:undefined,headers:body?{\"content-type\":\"application/json\"}:undefined}).then(async r=>{const text=await r.text(); console.log(JSON.stringify({ok:r.ok,status:r.status,body:text?JSON.parse(text):null})); process.exit(r.ok?0:1);}).catch(e=>{console.error(e); process.exit(1);})'",
].join("\n");
return ["docker", "exec", "unidesk-backend-core", "sh", "-lc", script];
}
function shellQuote(value: string): string {
return `'${value.replace(/'/g, `'\\''`)}'`;
}
function coreInternalFetch(path: string, init?: { method?: string; body?: unknown }): unknown {
const command = ["docker", "exec", "unidesk-backend-core", "backend-core", "--fetch-json", `http://127.0.0.1:8080${path}`, "--method", init?.method ?? "GET"];
if (init?.body !== undefined) command.push("--body-json", JSON.stringify(init.body));
const command = coreFetchCommand(path, init);
const result = runCommand(command, repoRoot);
if (result.exitCode !== 0) {
return { ok: false, exitCode: result.exitCode, stdoutTail: result.stdout.slice(-1200), stderrTail: result.stderr.slice(-1200) };
@@ -37,7 +58,7 @@ function coreInternalFetch(path: string, init?: { method?: string; body?: unknow
}
function coreDockerStatusSummary(): unknown {
const result = runCommand(["docker", "exec", "unidesk-backend-core", "backend-core", "--fetch-json", "http://127.0.0.1:8080/api/nodes/docker-status"], repoRoot);
const result = runCommand(coreFetchCommand("/api/nodes/docker-status"), repoRoot);
if (result.exitCode !== 0) {
return { ok: false, exitCode: result.exitCode, stdoutTail: result.stdout.slice(-1200), stderrTail: result.stderr.slice(-1200) };
}
@@ -67,7 +88,7 @@ function coreDockerStatusSummary(): unknown {
}
function coreSystemStatusSummary(): unknown {
const result = runCommand(["docker", "exec", "unidesk-backend-core", "backend-core", "--fetch-json", "http://127.0.0.1:8080/api/nodes/system-status?limit=24"], repoRoot);
const result = runCommand(coreFetchCommand("/api/nodes/system-status?limit=24"), repoRoot);
if (result.exitCode !== 0) {
return { ok: false, exitCode: result.exitCode, stdoutTail: result.stdout.slice(-1200), stderrTail: result.stderr.slice(-1200) };
}
+11 -1
View File
@@ -400,7 +400,17 @@ async function probe(url: string): Promise<unknown> {
}
function dockerExecJson(container: string, path: string): unknown {
const result = runCommand(["docker", "exec", container, "backend-core", "--fetch-json", `http://127.0.0.1:8080${path}`], repoRoot);
const url = `http://127.0.0.1:8080${path}`;
const script = [
"set -euo pipefail",
"if command -v backend-core >/dev/null 2>&1; then",
` exec backend-core --fetch-json ${shellQuote(url)}`,
"fi",
`url=${shellQuote(url)}`,
"export url",
"bun -e 'const url=process.env.url; fetch(url).then(async r=>{const text=await r.text(); console.log(JSON.stringify({ok:r.ok,status:r.status,body:text?JSON.parse(text):null})); process.exit(r.ok?0:1);}).catch(e=>{console.error(e); process.exit(1)})'",
].join("\n");
const result = runCommand(["docker", "exec", container, "sh", "-lc", script], repoRoot);
if (result.exitCode !== 0) {
return { ok: false, exitCode: result.exitCode, stdout: result.stdout.slice(-1200), stderr: result.stderr.slice(-1200) };
}
+15 -2
View File
@@ -915,8 +915,21 @@ function runPsql(config: UniDeskConfig, sql: string): { ok: boolean; stdout: str
}
function dockerCoreJson(path: string, init?: { method?: string; body?: unknown }): unknown {
const command = ["docker", "exec", "unidesk-backend-core", "backend-core", "--fetch-json", `http://127.0.0.1:8080${path}`, "--method", init?.method ?? "GET"];
if (init?.body !== undefined) command.push("--body-json", JSON.stringify(init.body));
const method = init?.method ?? "GET";
const body = init?.body === undefined ? "" : JSON.stringify(init.body);
const url = `http://127.0.0.1:8080${path}`;
const script = [
"set -euo pipefail",
"if command -v backend-core >/dev/null 2>&1; then",
` exec backend-core --fetch-json ${shellQuote(url)} --method ${shellQuote(method)}${body.length > 0 ? ` --body-json ${shellQuote(body)}` : ""}`,
"fi",
`url=${shellQuote(url)}`,
`method=${shellQuote(method)}`,
`body=${shellQuote(body)}`,
"export url method body",
"bun -e 'const url=process.env.url; const method=process.env.method; const body=process.env.body; fetch(url,{method,body:body?body:undefined,headers:body?{\"content-type\":\"application/json\"}:undefined}).then(async r=>{const text=await r.text(); console.log(JSON.stringify({ok:r.ok,status:r.status,body:text?JSON.parse(text):null})); process.exit(r.ok?0:1);}).catch(e=>{console.error(e); process.exit(1)})'",
].join("\n");
const command = ["docker", "exec", "unidesk-backend-core", "sh", "-lc", script];
const result = runCommand(command, repoRoot);
if (result.exitCode !== 0) return { ok: false, exitCode: result.exitCode, stdout: result.stdout.slice(-1200), stderr: result.stderr.slice(-1200) };
try {
+25 -3
View File
@@ -3,11 +3,33 @@ import { runCommand } from "./command";
import { type UniDeskConfig, repoRoot } from "./config";
import { jsonByteLength, previewJson } from "./preview";
function shellQuote(value: string): string {
return `'${value.replace(/'/g, `'\\''`)}'`;
}
function dockerCoreFetchCommand(path: string, init?: { method?: string; body?: unknown; maxResponseBytes?: number }): string[] {
const maxResponseBytes = Math.max(1024, Math.floor(init?.maxResponseBytes ?? 5_000_000));
const method = init?.method ?? "GET";
const body = init?.body === undefined ? "" : JSON.stringify(init.body);
const url = `http://127.0.0.1:8080${path}`;
const script = [
"set -euo pipefail",
"if command -v backend-core >/dev/null 2>&1; then",
` exec backend-core --fetch-json ${shellQuote(url)} --method ${shellQuote(method)} --max-response-bytes ${shellQuote(String(maxResponseBytes))}${body.length > 0 ? ` --body-json ${shellQuote(body)}` : ""}`,
"fi",
`url=${shellQuote(url)}`,
`method=${shellQuote(method)}`,
`max_bytes=${shellQuote(String(maxResponseBytes))}`,
`body=${shellQuote(body)}`,
"export url method body max_bytes",
"bun -e 'const url=process.env.url; const method=process.env.method; const body=process.env.body; const maxBytes=Number(process.env.max_bytes||\"5000000\"); fetch(url,{method,body:body?body:undefined,headers:body?{\"content-type\":\"application/json\"}:undefined}).then(async r=>{const text=await r.text(); const out={ok:r.ok,status:r.status,body:text?JSON.parse(text):null}; const json=JSON.stringify(out); if (Buffer.byteLength(json) > maxBytes) { console.error(\"response too large\"); process.exit(1); } console.log(json); process.exit(r.ok?0:1);}).catch(e=>{console.error(e); process.exit(1)})'",
].join("\n");
return ["docker", "exec", "unidesk-backend-core", "sh", "-lc", script];
}
export function coreInternalFetch(path: string, init?: { method?: string; body?: unknown; maxResponseBytes?: number }): unknown {
if (!path.startsWith("/")) throw new Error("core internal path must start with /");
const maxResponseBytes = Math.max(1024, Math.floor(init?.maxResponseBytes ?? 5_000_000));
const command = ["docker", "exec", "unidesk-backend-core", "backend-core", "--fetch-json", `http://127.0.0.1:8080${path}`, "--method", init?.method ?? "GET", "--max-response-bytes", String(maxResponseBytes)];
if (init?.body !== undefined) command.push("--body-json", JSON.stringify(init.body));
const command = dockerCoreFetchCommand(path, init);
const result = runCommand(command, repoRoot);
if (result.exitCode !== 0) {
return { ok: false, exitCode: result.exitCode, stdoutTail: result.stdout.slice(-1200), stderrTail: result.stderr.slice(-1200) };
+18 -5
View File
@@ -661,8 +661,9 @@ export function wrapSshRemoteCommand(command: string | null): string {
function brokerSource(): string {
return String.raw`
const open = JSON.parse(process.argv[2] || process.argv[1] || "{}");
const token = process.env.PROVIDER_TOKEN || "";
const url = "ws://backend-core:8080/ws/ssh?token=" + encodeURIComponent(token);
const token = process.env.PROVIDER_TOKEN || process.env.UNIDESK_PROVIDER_TOKEN || "";
const baseUrl = process.env.UNIDESK_SSH_BROKER_URL || "ws://backend-core:8080/ws/ssh";
const url = baseUrl + "?token=" + encodeURIComponent(token);
const ws = new WebSocket(url);
let exitCode = 255;
let canSend = false;
@@ -802,13 +803,25 @@ export async function runSsh(config: UniDeskConfig, providerId: string, args: st
cols: size.cols,
rows: size.rows,
};
const payloadJson = JSON.stringify(payload);
const encodedBrokerSource = Buffer.from(brokerSource(), "utf8").toString("base64");
const script = [
"set -euo pipefail",
`payload=${shellQuote(payloadJson)}`,
"if command -v backend-core >/dev/null 2>&1; then",
' exec backend-core --ssh-broker "$payload"',
"fi",
`export UNIDESK_SSH_BROKER_URL=${shellQuote("ws://127.0.0.1:8080/ws/ssh")}`,
`printf %s ${shellQuote(encodedBrokerSource)} | base64 -d >/tmp/unidesk-ssh-broker.js`,
"exec bun /tmp/unidesk-ssh-broker.js \"$payload\"",
].join("\n");
const child = spawn("docker", [
"exec",
"-i",
"unidesk-backend-core",
"backend-core",
"--ssh-broker",
JSON.stringify(payload),
"sh",
"-lc",
script,
], {
cwd: repoRoot,
stdio: ["pipe", "pipe", "pipe"],