feat(booth): multi-question asks — a questions list renders one form with a radio group per question and lands as one answer sidecar keyed by question

- asks.py: single {prompt, options} and multi {title, questions:[{key, prompt, options, notes?}]} both normalise to questions[]; per-question notes; every question required on submit
- /answer reads choice.<key> / notes.<key> / notes for multi; single shape unchanged
- booth asks prints per-question picks; README + CLI header; install step symlinks the CLI to ~/.local/bin; v0.1.10; 135 tests
This commit is contained in:
vh
2026-09-09 09:20:35 -07:00
parent 97589dd062
commit 125a1b7fc5
8 changed files with 355 additions and 69 deletions
+8
View File
@@ -28,6 +28,9 @@
# writes <stem>.answer.json next to it. `answer --wait` blocks until that file
# exists and prints it, so a session can `booth ask … && booth answer --wait …`
# and carry on. Re-answering overwrites: the sidecar is the CURRENT answer.
# Several questions in ONE form: write <stem>.ask.json by hand with a
# `questions` list (see services/booth/README.md § Asks); `asks` and `answer`
# handle both shapes.
# Remote sessions: rsync the ask in, then poll
# http://10.100.10.50:8090/b/<name>/<stem>.answer.json (404 until answered).
#
@@ -226,8 +229,13 @@ if not asks:
for a in asks:
if a["error"]:
state = "BROKEN " + a["error"]
elif a["answer"] and a["multi"]:
picks = ", ".join("%s=%s" % (k, v["label"]) for k, v in a["answer"]["answers"].items())
state = "answered %s (%s)" % (picks, a["answer"]["answered_at"])
elif a["answer"]:
state = "answered %s (%s)" % (a["answer"]["label"], a["answer"]["answered_at"])
elif a["multi"]:
state = "open (%d questions)" % len(a["questions"])
else:
state = "open"
print("%-24s %s" % (a["stem"], state))