feat(bus): the bus host runs an explicit Claude Code binary (#1561, row 68)
MOSAIC_CLAUDE_BIN names the claude binary by absolute path instead of finding it on PATH. scripts/bus-service.sh render|install --claude PATH writes it into the unit (default: command -v claude in the installing shell); the claude adapter, the launcher's version read and the seat session environment all use it. Mos's Q18 ask: the unit's PATH found /usr/bin/claude 2.1.259, which refuses claude-opus-5-5. Candidate: round 2 manifest 21c1ab05, round 1 (a2008d8b) rebased ontof2f2861bafter row 55 changed docs/TOOLS.md and packages/cli/README.md; the changed lines are byte-identical. Approved by Filbert (27349, 27374) and Dewey (27350, 27375). Sage's gate onf2f2861bplus the patch: cli 112, seat 27, harness 57, nine scripts/test-*.sh 0 failed, Docker on. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
+55
-8
@@ -7,24 +7,52 @@
|
||||
# business (mosaic-bus@<business>). Nothing here reads a capability, the
|
||||
# binding or the token. See packages/cli/README.md, "Bus host".
|
||||
#
|
||||
# render print the rendered unit on stdout
|
||||
# install [--dir DIR] [--no-reload]
|
||||
# render [--claude PATH] print the rendered unit on stdout
|
||||
# install [--dir DIR] [--no-reload] [--claude PATH]
|
||||
# write the unit (write to a temp file, then
|
||||
# rename) and run `systemctl --user daemon-reload`
|
||||
# uninstall [--dir DIR] [--no-reload]
|
||||
# remove the unit; refuses while an instance is active
|
||||
# status <business> unit state, then `mosaic bus status`
|
||||
#
|
||||
# --claude PATH pins the Claude Code binary the unit's sessions run
|
||||
# (MOSAIC_CLAUDE_BIN); without it, `command -v claude` here. The path is
|
||||
# kept as given, so a symlink that tracks updates keeps tracking them.
|
||||
#
|
||||
# Exit codes: 0 ok, 1 operation failed, 4 usage.
|
||||
set -euo pipefail
|
||||
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
TEMPLATE="$REPO/packages/cli/systemd/mosaic-bus.service.in"
|
||||
UNIT_NAME="[email protected]"
|
||||
USAGE="usage: scripts/bus-service.sh render | install [--dir DIR] [--no-reload] | uninstall [--dir DIR] [--no-reload] | status <business>"
|
||||
USAGE="usage: scripts/bus-service.sh render [--claude PATH] | install [--dir DIR] [--no-reload] [--claude PATH] | uninstall [--dir DIR] [--no-reload] | status <business>"
|
||||
|
||||
die() { echo "bus-service: $*" >&2; exit 1; }
|
||||
usage() { echo "$USAGE" >&2; exit 4; }
|
||||
|
||||
CLAUDE_BIN=""
|
||||
CLAUDE_SET=0
|
||||
|
||||
# The unit's MOSAIC_CLAUDE_BIN line, or a comment when there is no claude to
|
||||
# pin. systemd expands % and splits Environment= on spaces, so the path is
|
||||
# held to a plain character set.
|
||||
claude_line() {
|
||||
local bin
|
||||
if [ "$CLAUDE_SET" = 1 ]; then
|
||||
bin="$CLAUDE_BIN"
|
||||
else
|
||||
bin="$(command -v claude || true)"
|
||||
if [ -z "$bin" ]; then
|
||||
echo "bus-service: no claude on PATH; MOSAIC_CLAUDE_BIN left unset (--claude PATH pins one)" >&2
|
||||
echo "# MOSAIC_CLAUDE_BIN unset: no claude on PATH at install time"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
case "$bin" in /*) ;; *) die "claude path must be absolute: $bin" ;; esac
|
||||
case "$bin" in *[!A-Za-z0-9/._+-]*) die "claude path contains a character the unit cannot carry: $bin" ;; esac
|
||||
[ -f "$bin" ] && [ -x "$bin" ] || die "claude path is not an executable file: $bin"
|
||||
echo "Environment=MOSAIC_CLAUDE_BIN=$bin"
|
||||
}
|
||||
|
||||
render() {
|
||||
[ -f "$TEMPLATE" ] || die "template missing: $TEMPLATE"
|
||||
local node_dir
|
||||
@@ -33,7 +61,9 @@ render() {
|
||||
local path="/usr/local/bin:/usr/bin:/bin"
|
||||
case ":$path:" in *":$node_dir:"*) ;; *) path="$node_dir:$path" ;; esac
|
||||
case "$REPO" in *@*|*'|'*) die "repository path contains a character the template cannot carry: $REPO" ;; esac
|
||||
sed -e "s|@REPO@|$REPO|g" -e "s|@PATH@|$path|g" "$TEMPLATE"
|
||||
local claude
|
||||
claude="$(claude_line)" || exit 1
|
||||
sed -e "s|@REPO@|$REPO|g" -e "s|@PATH@|$path|g" -e "s|^@CLAUDE_ENV@$|$claude|" "$TEMPLATE"
|
||||
}
|
||||
|
||||
UNIT_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user"
|
||||
@@ -43,6 +73,7 @@ parse_flags() {
|
||||
case "$1" in
|
||||
--dir) [ $# -ge 2 ] || usage; UNIT_DIR="$2"; shift 2 ;;
|
||||
--no-reload) RELOAD=0; shift ;;
|
||||
--claude) [ $# -ge 2 ] || usage; CLAUDE_BIN="$2"; CLAUDE_SET=1; shift 2 ;;
|
||||
*) usage ;;
|
||||
esac
|
||||
done
|
||||
@@ -51,9 +82,10 @@ parse_flags() {
|
||||
install_unit() {
|
||||
parse_flags "$@"
|
||||
mkdir -p "$UNIT_DIR"
|
||||
local target="$UNIT_DIR/$UNIT_NAME" tmp
|
||||
local target="$UNIT_DIR/$UNIT_NAME" tmp unit
|
||||
unit="$(render)" || exit 1
|
||||
tmp="$(mktemp "$UNIT_DIR/.$UNIT_NAME.XXXXXX")"
|
||||
render > "$tmp"
|
||||
printf '%s\n' "$unit" > "$tmp"
|
||||
chmod 0644 "$tmp"
|
||||
if [ -f "$target" ] && cmp -s "$tmp" "$target"; then
|
||||
rm -f "$tmp"
|
||||
@@ -62,6 +94,13 @@ install_unit() {
|
||||
mv -f "$tmp" "$target"
|
||||
echo "written: $target"
|
||||
fi
|
||||
local bin
|
||||
bin="$(sed -n 's/^Environment=MOSAIC_CLAUDE_BIN=//p' "$target")"
|
||||
if [ -n "$bin" ]; then
|
||||
echo "claude: $bin ($("$bin" --version 2>/dev/null | head -n 1 || true))"
|
||||
else
|
||||
echo "claude: MOSAIC_CLAUDE_BIN unset; sessions run claude from the unit's PATH"
|
||||
fi
|
||||
if [ "$RELOAD" = 1 ]; then
|
||||
systemctl --user daemon-reload || die "daemon-reload failed"
|
||||
echo "daemon-reload done"
|
||||
@@ -81,6 +120,7 @@ MSG
|
||||
|
||||
uninstall_unit() {
|
||||
parse_flags "$@"
|
||||
[ "$CLAUDE_SET" = 0 ] || usage
|
||||
local target="$UNIT_DIR/$UNIT_NAME"
|
||||
if [ "$RELOAD" = 1 ]; then
|
||||
local active
|
||||
@@ -107,14 +147,21 @@ status_unit() {
|
||||
echo "unit: $unit"
|
||||
echo " enabled: $(systemctl --user is-enabled "$unit" 2>&1 || true)"
|
||||
echo " active: $(systemctl --user is-active "$unit" 2>&1 || true)"
|
||||
systemctl --user show "$unit" -p MainPID -p NRestarts -p ExecMainStartTimestamp -p Result 2>/dev/null | sed 's/^/ /'
|
||||
systemctl --user show "$unit" -p MainPID -p NRestarts -p ExecMainStartTimestamp -p Result -p Environment 2>/dev/null | sed 's/^/ /'
|
||||
"$REPO/scripts/mosaic" bus status | sed 's/^/ /' || true
|
||||
}
|
||||
|
||||
[ $# -ge 1 ] || usage
|
||||
cmd="$1"; shift
|
||||
case "$cmd" in
|
||||
render) [ $# -eq 0 ] || usage; render ;;
|
||||
render)
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--claude) [ $# -ge 2 ] || usage; CLAUDE_BIN="$2"; CLAUDE_SET=1; shift 2 ;;
|
||||
*) usage ;;
|
||||
esac
|
||||
done
|
||||
render ;;
|
||||
install) install_unit "$@" ;;
|
||||
uninstall) uninstall_unit "$@" ;;
|
||||
status) status_unit "$@" ;;
|
||||
|
||||
Reference in New Issue
Block a user