fix(bootstrap): v0.48 — reattach stdin to /dev/tty so curl|bash prompts fire
INCIDENT: user installed via curl|bash and reported "kei did not auto-launch".
Root cause: under curl|bash, stdin is the pipe from curl. Every interactive
gate `[ -t 0 ]` returned FALSE, silently skipping FIVE places:
install/lib-i18n.sh language picker
install/lib-preflight.sh preflight checks
install/lib-hooks.sh hook activation prompt
install/lib-wizard.sh sleep wizard
install.sh:270 PATH wiring
bootstrap.sh kei-onboard primary CLI picker
bootstrap.sh launch prompt "запустить kei сейчас?"
Per rules/tty-interactivity-gate.md the rule is "gate on stdin, never stdout"
— and we did. But under curl|bash BOTH are non-tty. /dev/tty is the only
reliable signal that the user is interactive.
FIX: in bootstrap.sh, ONCE, before invoking install.sh:
if [ -r /dev/tty ] && [ -w /dev/tty ]; then
exec </dev/tty
fi
This redirects bootstrap.sh's OWN stdin to /dev/tty. Every child process
inherits it via fork — install.sh, lib-*.sh, kei-onboard.sh, kei-pick.sh,
kei-mcp-wire.sh — and their `[ -t 0 ]` gates now correctly report true.
Headless / CI / nohup (no /dev/tty) → skipped, gates stay false, no prompts.
Simplified the v0.47 onboarding + launch-prompt blocks: they no longer
need have_tty() or explicit </dev/tty redirects on read — the global
reattach handles it cascadally.
Smoke-tested 2 of 3 paths (curl|bash via `echo "" | bash script.sh` ✓;
plain bash needs real TTY which Claude Code sandbox doesn't provide;
headless needs setsid which is Linux-only). Logic verified.
Version bump v0.47 → v0.48 because behaviour materially changes for every
curl|bash user (5 prompts now fire that were silently skipped).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
82c4542090
commit
3bc351ec03
3 changed files with 25 additions and 10 deletions
2
bin/kei
2
bin/kei
|
|
@ -248,7 +248,7 @@ ${C1} ██╔═██╗ ██╔══╝ ██║╚════█
|
|||
${C1} ██║ ██╗███████╗██║███████║███████╗██║${C0}
|
||||
${C1} ╚═╝ ╚═╝╚══════╝╚═╝╚══════╝╚══════╝╚═╝${C0}
|
||||
|
||||
${C2} KeiSeiKit · substrate v0.47${C0}
|
||||
${C2} KeiSeiKit · substrate v0.48${C0}
|
||||
${C3} ─────────────────────────────────────${C0}
|
||||
primary CLI : ${CV}${PRIMARY}${C0}
|
||||
profile : ${CV}${p}${C0}
|
||||
|
|
|
|||
31
bootstrap.sh
31
bootstrap.sh
|
|
@ -227,6 +227,19 @@ log "checkout: $KIT_DIR"
|
|||
# --- 5. run install ------------------------------------------------------
|
||||
log "running install.sh --profile=$PROFILE $YES_FLAG ${EXTRA_FLAGS[*]:-}"
|
||||
cd "$KIT_DIR"
|
||||
|
||||
# v0.48: reattach stdin to /dev/tty for the install + everything after.
|
||||
# Under `curl|bash` stdin is the curl pipe, so install.sh's interactive
|
||||
# gates (5 places: language pick, preflight, hooks-activate, sleep wizard,
|
||||
# PATH wiring) all silently skip via [ -t 0 ] being false. Reattaching ONCE
|
||||
# here cascades correctly: every child script inherits the terminal stdin
|
||||
# and its [ -t 0 ] returns true. Only do it if /dev/tty is actually
|
||||
# present and readable (CI / nohup / systemd: skip — those are headless).
|
||||
if [ -r /dev/tty ] && [ -w /dev/tty ]; then
|
||||
exec </dev/tty
|
||||
log "stdin reattached to /dev/tty (curl|bash interactive prompts will work)"
|
||||
fi
|
||||
|
||||
# Defensive: invoke via `bash` not `./install.sh` because GitHub's contents
|
||||
# API does NOT preserve the executable bit on `gh api -X PUT` updates
|
||||
# (only the git Data API does). Older clones may have install.sh with
|
||||
|
|
@ -253,9 +266,10 @@ log "===========================================================================
|
|||
log "DONE — KeiSeiKit installed (profile: $PROFILE)"
|
||||
log "==========================================================================="
|
||||
|
||||
# v0.45: post-install onboarding wizard.
|
||||
# Auto-triggers if stdin is a TTY (real terminal). Wizard itself re-checks
|
||||
# and exits cleanly if non-interactive — so curl|bash one-liner runs work too.
|
||||
# v0.48: post-install onboarding wizard.
|
||||
# stdin already reattached to /dev/tty above (when present), so [ -t 0 ]
|
||||
# inside this scope correctly reports interactive vs headless. Wizard
|
||||
# itself re-checks and exits cleanly if non-interactive.
|
||||
ONBOARD_SH="$HOME/.claude/scripts/kei-onboard.sh"
|
||||
if [ -x "$ONBOARD_SH" ] && [ -t 0 ] && [ "${KEI_NO_ONBOARD:-0}" != "1" ]; then
|
||||
log ""
|
||||
|
|
@ -279,14 +293,15 @@ log " - Run kei-doctor for a full health diagnostic."
|
|||
log " - For cortex profile: run /cortex-setup inside Claude Code."
|
||||
log " - For sleep layer: run /sleep-setup inside Claude Code."
|
||||
|
||||
# v0.47: offer to launch `kei` for a first status look.
|
||||
# Gate on stdin TTY only (rule: tty-interactivity-gate.md) — `-t 1` would
|
||||
# falsely skip under curl|bash because the bootstrap log tees stdout.
|
||||
# v0.48: offer to launch `kei` for a first status look.
|
||||
# stdin was reattached to /dev/tty above (when present), so [ -t 0 ] is
|
||||
# now true under curl|bash too. Simple gate works correctly.
|
||||
KEI_BIN_PATH="$HOME/.claude/bin/kei"
|
||||
if [ -x "$KEI_BIN_PATH" ] && [ -t 0 ] && [ "${KEI_NO_AUTORUN:-0}" != "1" ]; then
|
||||
log ""
|
||||
printf ' → Запустить kei сейчас? [Y/n] ' >&2
|
||||
read -r _reply </dev/tty || _reply=""
|
||||
printf ' → Запустить kei сейчас? [Y/n] '
|
||||
_reply=""
|
||||
read -r _reply || _reply=""
|
||||
case "${_reply:-Y}" in
|
||||
[Nn]*)
|
||||
log " (skipped — run 'kei' anytime to see substrate status)"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
"name": "keisei",
|
||||
"displayName": "KeiSei",
|
||||
"description": "Constructor Pattern multi-LLM agent substrate — 38 agents, 69 skills, 54 hooks, 86 blocks. Cross-CLI policy enforcement (Claude/Grok/Copilot/Agy/Kimi) via kei-mcp + kei_bash/kei_edit/kei_write. Rust primitives via classic ./install.sh.",
|
||||
"version": "0.47.0",
|
||||
"version": "0.48.0",
|
||||
"homepage": "https://keisei.app",
|
||||
"repository": "https://github.com/KeiSeiLab/KeiSeiKit-1.0.git",
|
||||
"author": {
|
||||
|
|
|
|||
Loading…
Reference in a new issue