fix(install): fold in both reviews of #460

The two reviews on the PR (DeepSeek Harness, then Claude) found one class of
bug twice and a list of smaller ones; all of them land here, each pinned in
test/install-sh-invariants.test.ts and, where it is bash logic, driven in the
bash:3.2 CI step as well.

The Start line the done screen prints is now composed in one place
(start_command_hint) from every non-default value, the same five the exec
branch exports through export_bind_env, so "do not start" under a sub-path or
a custom port no longer prints a bare `codeman web`. The --lan / --tailscale /
env preset paths read ${CODEMAN_PASSWORD:-$EXISTING_PASSWORD}: a flag re-run on
a unit that carried a password used to rewrite it without the password and
with the unauthenticated ack. --password and --port flip RECONFIGURE so they
reach the unit instead of taking the quiet update path, and `install.sh name`
re-syncs the unit's base URL after the mapping is re-added.

Also: the sudo keepalive is ended before the exec into the foreground server
(exec skips the EXIT trap, and the loop keys on $$); Ctrl+C in the HTTPS-toggle
poll is trapped for the poll only and skips Tailscale for the run instead of
killing the installer; uninstall asks before removing a LaunchDaemon this
installer never wrote; a foreign daemon gets a launchctl kickstart hint and the
done screen stops claiming the new build is running; the preflight summary
reads the Tailscale state with a line grep when node is not installed yet; the
LAN security notice uses the configured port; a bare re-run ends on the done
screen; a build failure after a rename names the install.sh tailscale
recovery; TS_JOINED_HERE (written, never read) is gone; the plan doc and
architecture-invariants say what the code does. A minor changeset is included.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-09-21 03:03:31 +02:00
parent 1ba0684438
commit 72d437ab63
8 changed files with 351 additions and 65 deletions
+13 -1
View File
@@ -121,6 +121,8 @@ jobs:
[[ "$LAUNCH_CHOICE" == "2" ]]
check_tailscale() { return 0; }
ts_status_field() { case "$1" in "s.BackendState") printf Running ;; "s.Self && s.Self.DNSName") printf "box.tail.ts.net." ;; esac; }
ts_backend_state() { printf Running; }
ts_dns_name() { printf box.tail.ts.net; }
ts_serve_443_target_port() { printf 8080; }
ts_serve_find_port_mapping() { :; }
ts_serve_port_used() { return 1; }
@@ -130,7 +132,17 @@ jobs:
RENAMED=""; tailscale_rename_node() { RENAMED="$1"; }
TS_NAME=""; tailscale_choose_name >/dev/null 2>&1
[[ -z "$RENAMED" ]]
echo "bash $BASH_VERSION: question phase (flags, launch default, occupied :443, rename opt-in) ok"
# A flag re-run keeps the password the unit already carries (and so
# never writes the unauthenticated ack), and the hand-start line the
# done screen prints carries every non-default value.
read_existing_binding() { EXISTING_FOUND=1; EXISTING_HOST=0.0.0.0; EXISTING_PASSWORD=s3cret; EXISTING_ACK=0; EXISTING_BASE_URL=""; }
CODEMAN_HOST=0.0.0.0; CODEMAN_TAILSCALE=0; unset CODEMAN_PASSWORD; BIND_ACK=0
choose_network_binding >/dev/null 2>&1
[[ "$BIND_PASSWORD" == "s3cret" && "$BIND_ACK" == "0" ]]
BIND_HOST=0.0.0.0; BIND_PASSWORD=x; BIND_ACK=0; BIND_BASE_URL=/codeman; CODEMAN_PORT=4000
[[ "$(start_command_hint)" == "CODEMAN_HOST=0.0.0.0 CODEMAN_PASSWORD="*" CODEMAN_BASE_URL=/codeman CODEMAN_PORT=4000 codeman web" ]]
RECONFIGURE=0; parse_flags --port 4001; [[ "$RECONFIGURE" == "1" ]]
echo "bash $BASH_VERSION: question phase (flags, launch default, occupied :443, rename opt-in, kept password, start line) ok"
'
- name: CLI catalogue artifacts are in sync with stock.ts