Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
84 lines
3.7 KiB
TypeScript
84 lines
3.7 KiB
TypeScript
/** Sanitize Docker container/image IDs — must match electron/bridges/systemManager/dockerOps.cjs */
|
|
export function sanitizeDockerContainerId(id: string): string {
|
|
return String(id || '').replace(/[^a-zA-Z0-9]/g, '').slice(0, 64);
|
|
}
|
|
|
|
const CLEAR_STARTUP_OUTPUT_POSIX = "printf '\\033[H\\033[2J\\033[3J';";
|
|
const CLEAR_STARTUP_OUTPUT_WINDOWS = ""; // Windows console doesn't support ANSI clear via printf; let the terminal handle it
|
|
|
|
function shQuote(value: string): string {
|
|
return `'${String(value).replace(/'/g, `'"'"'`)}'`;
|
|
}
|
|
|
|
function buildDockerCommandWithSudoFallback(containerId: string, dockerArgs: string): string {
|
|
const plainCommand = `docker ${dockerArgs}`;
|
|
const sudoCommand = `sudo ${plainCommand}`;
|
|
const script = [
|
|
CLEAR_STARTUP_OUTPUT_POSIX,
|
|
`_nc_docker_err=$(docker inspect ${containerId} 2>&1 >/dev/null);`,
|
|
'_nc_docker_status=$?;',
|
|
`if [ "$_nc_docker_status" -eq 0 ]; then exec ${plainCommand}; fi;`,
|
|
'_nc_docker_lc=$(printf \'%s\' "$_nc_docker_err" | tr \'[:upper:]\' \'[:lower:]\');',
|
|
'case "$_nc_docker_lc" in',
|
|
[
|
|
'*permission\\ denied*docker\\ daemon*',
|
|
'*docker\\ daemon*permission\\ denied*',
|
|
'*permission\\ denied*docker.sock*',
|
|
'*docker.sock*permission\\ denied*',
|
|
'*permission\\ denied*/var/run/docker.sock*',
|
|
'*/var/run/docker.sock*permission\\ denied*',
|
|
'*permission\\ denied*connect\\ to\\ the\\ docker\\ daemon*',
|
|
'*connect\\ to\\ the\\ docker\\ daemon*permission\\ denied*',
|
|
].join('|') + `) exec ${sudoCommand} ;;`,
|
|
'*) printf \'%s\\n\' "$_nc_docker_err" >&2; exit "$_nc_docker_status" ;;',
|
|
'esac',
|
|
].join(' ');
|
|
return `sh -c ${shQuote(script)}`;
|
|
}
|
|
|
|
/**
|
|
* Windows fallback — no sudo (Docker Desktop on Windows runs as current user),
|
|
* no sh wrapper, just direct docker command.
|
|
*/
|
|
function buildDockerCommandWindows(containerId: string, dockerArgs: string): string {
|
|
const safeId = sanitizeDockerContainerId(containerId);
|
|
if (!safeId) return 'echo Invalid container id';
|
|
return `docker ${dockerArgs}`;
|
|
}
|
|
|
|
/** Interactive shell into a container — prefer bash, fall back to sh. */
|
|
export function buildDockerExecShellCommand(containerId: string): string {
|
|
const safeId = sanitizeDockerContainerId(containerId);
|
|
if (!safeId) return 'echo "Invalid container id"';
|
|
return buildDockerCommandWithSudoFallback(
|
|
safeId,
|
|
`exec -it ${safeId} sh -c 'command -v bash >/dev/null 2>&1 && exec bash || exec sh'`,
|
|
);
|
|
}
|
|
|
|
/** Interactive shell into a container — Windows host variant.
|
|
* Docker Desktop on Windows runs Linux containers by default, so the
|
|
* container shell is still bash/sh (not powershell.exe).
|
|
* The Windows variant avoids wrapping the whole thing in a host `sh -c`
|
|
* script (sh.exe is not available on Windows). Instead we exec bash
|
|
* directly and fall back to sh inside the container.
|
|
*/
|
|
export function buildDockerExecShellCommandWindows(containerId: string): string {
|
|
const safeId = sanitizeDockerContainerId(containerId);
|
|
if (!safeId) return 'echo Invalid container id';
|
|
// Use cmd /c to chain two docker exec attempts — first bash, then sh.
|
|
// cmd /c is available on all Windows hosts.
|
|
return `cmd /c "docker exec -it ${safeId} bash || docker exec -it ${safeId} sh"`;
|
|
}
|
|
|
|
export function buildDockerLogsCommand(containerId: string): string {
|
|
const safeId = sanitizeDockerContainerId(containerId);
|
|
if (!safeId) return 'echo "Invalid container id"';
|
|
return buildDockerCommandWithSudoFallback(safeId, `logs -f --tail 200 ${safeId}`);
|
|
}
|
|
|
|
/** Windows variant — no sh wrapper, no sudo. */
|
|
export function buildDockerLogsCommandWindows(containerId: string): string {
|
|
return buildDockerCommandWindows(containerId, `logs -f --tail 200 ${sanitizeDockerContainerId(containerId)}`);
|
|
}
|