Show hostname in Pi footer on operator images (Sam & Codex)

This commit is contained in:
Sam & Claude 2026-06-04 06:46:32 +02:00
parent 7cc78bf828
commit 3bd8bfbba1
4 changed files with 146 additions and 0 deletions

View file

@ -944,6 +944,8 @@ install_live_npm_globals() {
ln -sf "/opt/clawdie/npm-global/bin/$(basename "${_bin}")" "${MOUNT_POINT}/usr/local/bin/$(basename "${_bin}")"
done
patch_live_pi_footer_hostname "${_live_prefix}"
# npm runs as root on the build host and writes everything as
# root:wheel. configure_live_operator_session() used to do this
# chown but ran BEFORE install_live_npm_globals (caller order at
@ -973,6 +975,33 @@ install_live_npm_globals() {
fi
}
patch_live_pi_footer_hostname() {
_npm_prefix="$1"
_patch_script="${SCRIPT_DIR}/firstboot/patch-pi-footer-hostname.js"
_patched=0
if [ ! -f "${_patch_script}" ]; then
echo "ERROR: Pi footer patch script missing: ${_patch_script}"
exit 1
fi
for _footer in \
"${_npm_prefix}/lib/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/footer.js" \
"${_npm_prefix}/lib/node_modules/@mariozechner/pi-coding-agent/dist/modes/interactive/components/footer.js"
do
[ -f "${_footer}" ] || continue
echo " patch Pi footer hostname: ${_footer}"
node "${_patch_script}" "${_footer}"
node --check "${_footer}"
_patched=1
done
if [ "${_patched}" -ne 1 ]; then
echo "ERROR: Pi footer.js not found under ${_npm_prefix}"
exit 1
fi
}
seed_live_ai_source_repo() {
_repo_src="$1"
_repo_name="$2"
@ -1273,6 +1302,8 @@ export npm_config_prefix="${_clawdie_npm_prefix}"
export NPM_CONFIG_PREFIX="${_clawdie_npm_prefix}"
export NPM_CONFIG_UPDATE_NOTIFIER=false
export NO_UPDATE_NOTIFIER=1
export LANG="${LANG:-en_US.UTF-8}"
export LC_ALL="${LC_ALL:-en_US.UTF-8}"
if [ -z "${PATH:-}" ]; then
PATH="${_clawdie_base_path}"
else
@ -1391,6 +1422,13 @@ EOF
"${MOUNT_POINT}/home/clawdie/.config/xfce4/xinitrc" \
"${MOUNT_POINT}/etc/skel/.xinitrc" \
"${MOUNT_POINT}/etc/skel/.config/xfce4/xinitrc"
if [ -f "${MOUNT_POINT}/usr/local/etc/xdg/tumbler/tumbler.rc" ]; then
mkdir -p "${MOUNT_POINT}/home/clawdie/.config/tumbler" "${MOUNT_POINT}/etc/skel/.config/tumbler"
install -m 0644 "${MOUNT_POINT}/usr/local/etc/xdg/tumbler/tumbler.rc" \
"${MOUNT_POINT}/home/clawdie/.config/tumbler/tumbler.rc"
install -m 0644 "${MOUNT_POINT}/usr/local/etc/xdg/tumbler/tumbler.rc" \
"${MOUNT_POINT}/etc/skel/.config/tumbler/tumbler.rc"
fi
chroot "$MOUNT_POINT" chown -R clawdie:clawdie /home/clawdie
mkdir -p "${MOUNT_POINT}/usr/local/share/applications"

View file

@ -0,0 +1,69 @@
#!/usr/bin/env node
// Patch the bundled Pi footer so operator sessions show the runtime hostname.
// This is intentionally a post-install patch because the live image ships Pi as
// an offline npm-global tarball rather than as source built in this repo.
const fs = require("node:fs");
const file = process.argv[2];
if (!file) {
console.error("usage: patch-pi-footer-hostname.js FOOTER_JS");
process.exit(64);
}
let src = fs.readFileSync(file, "utf8");
if (!src.includes('import { hostname } from "node:os";')) {
if (src.includes('import { isAbsolute, relative, resolve, sep } from "node:path";\n')) {
src = src.replace(
'import { isAbsolute, relative, resolve, sep } from "node:path";\n',
'import { isAbsolute, relative, resolve, sep } from "node:path";\nimport { hostname } from "node:os";\n',
);
} else {
src = src.replace(/^(import .*?;\n)/, 'import { hostname } from "node:os";\n$1');
}
}
const oldPwdBlock = ` const pwdLine = truncateToWidth(theme.fg("dim", pwd), width, theme.fg("dim", "..."));
const lines = [pwdLine, dimStatsLeft + dimRemainder];`;
const newPwdBlock = ` // Show runtime hostname on the right of the cwd line. Use the kernel
// hostname instead of parsing FreeBSD rc.conf so Pi stays portable and
// reflects changes made after boot.
const host = hostname();
const minPwdHostPadding = 2;
let hostForLine = host;
let hostWidth = visibleWidth(hostForLine);
if (hostWidth > width) {
hostForLine = truncateToWidth(hostForLine, width, "...");
hostWidth = visibleWidth(hostForLine);
}
const availableForPwd = width - hostWidth - minPwdHostPadding;
let pwdLine;
if (hostForLine && availableForPwd > 0) {
const pwdForLine = visibleWidth(pwd) > availableForPwd ? truncateToWidth(pwd, availableForPwd, "...") : pwd;
const pwdWidth = visibleWidth(pwdForLine);
const padding = " ".repeat(Math.max(minPwdHostPadding, width - pwdWidth - hostWidth));
pwdLine = theme.fg("dim", pwdForLine) + padding + theme.fg("dim", hostForLine);
}
else if (hostForLine) {
pwdLine = theme.fg("dim", hostForLine);
}
else {
pwdLine = truncateToWidth(theme.fg("dim", pwd), width, theme.fg("dim", "..."));
}
const lines = [pwdLine, dimStatsLeft + dimRemainder];`;
if (!src.includes("const minPwdHostPadding = 2;")) {
if (!src.includes(oldPwdBlock)) {
throw new Error(`Pi footer cwd block not found in ${file}`);
}
src = src.replace(oldPwdBlock, newPwdBlock);
}
if (!src.includes('lines.push("");\n return lines;')) {
src = src.replace(' return lines;\n', ' lines.push("");\n return lines;\n');
}
fs.writeFileSync(file, src);
console.log(`patched ${file}`);

View file

@ -84,11 +84,44 @@ clawdie_shell_npm_globals_install() {
return 0
fi
clawdie_shell_npm_globals_patch_pi_footer
echo "[NPM-GLOBALS] SUCCESS" >> "$PROGRESS_FILE"
log_msg "[npm-globals] Install complete"
return 0
}
clawdie_shell_npm_globals_patch_pi_footer() {
_patch_script="${SHARE}/firstboot/patch-pi-footer-hostname.js"
_patched=0
if [ ! -f "$_patch_script" ]; then
log_msg "[npm-globals] ERROR: Pi footer patch script missing: $_patch_script"
return 1
fi
for footer in \
"$NPM_PREFIX/lib/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/footer.js" \
"$NPM_PREFIX/lib/node_modules/@mariozechner/pi-coding-agent/dist/modes/interactive/components/footer.js"
do
[ -f "$footer" ] || continue
log_msg "[npm-globals] Patching Pi footer hostname: $footer"
if node "$_patch_script" "$footer" >>"$LOG_FILE" 2>&1 && node --check "$footer" >>"$LOG_FILE" 2>&1; then
_patched=1
else
log_msg "[npm-globals] ERROR: failed to patch Pi footer hostname"
return 1
fi
done
if [ "$_patched" -ne 1 ]; then
log_msg "[npm-globals] ERROR: Pi footer.js not found under $NPM_PREFIX"
return 1
fi
return 0
}
# ============================================================================
# LOGGING HELPER
# ============================================================================

View file

@ -444,8 +444,14 @@ if [ -n "${ZSH:-}" ] && [ -r "${ZSH}/oh-my-zsh.sh" ]; then
source "${ZSH}/oh-my-zsh.sh"
fi
EOF
if [ -f /usr/local/etc/xdg/tumbler/tumbler.rc ]; then
mkdir -p /home/clawdie/.config/tumbler
cp /usr/local/etc/xdg/tumbler/tumbler.rc /home/clawdie/.config/tumbler/tumbler.rc
fi
chown -R clawdie:clawdie /home/clawdie/.config/tumbler 2>/dev/null || true
chown clawdie:clawdie /home/clawdie/.profile /home/clawdie/.bash_profile /home/clawdie/.bashrc /home/clawdie/.zprofile /home/clawdie/.zshrc 2>/dev/null || true
chmod 644 /home/clawdie/.profile /home/clawdie/.bash_profile /home/clawdie/.bashrc /home/clawdie/.zprofile /home/clawdie/.zshrc 2>/dev/null || true
chmod 644 /home/clawdie/.config/tumbler/tumbler.rc 2>/dev/null || true
fi
log_msg "[system] Created $clawdie_profile"