feat: add production init wizard UX

This commit is contained in:
thanhnv
2026-07-24 12:30:37 +07:00
parent eb3525456f
commit bfebfa9d39
7 changed files with 597 additions and 255 deletions
@@ -41,8 +41,8 @@ assert not (root / "packages/casan-harness/level5").exists()
assert not (root / "packages/casan-harness/scripts/bash/ci-harness-gate.sh").exists()
for relative in ("docs/casan/CASAN_ADOPTION_WINDOWS.md", "docs/casan/CASAN_PROMPT_ENFORCEMENT.md"):
text = (root / relative).read_text(encoding="utf-8")
assert "sample-project" in text
assert "Sample Project" in text or relative.endswith("CASAN_PROMPT_ENFORCEMENT.md")
assert "casan init" in text
assert "managed" in text.lower() and "vendored" in text.lower()
assert "__PROJECT_ID__" not in text and "__PROJECT_NAME__" not in text
PY
@@ -80,11 +80,38 @@ assert registry["projects"] == []
PY
"$CASAN" version >/dev/null 2>&1 && pass "casan version works via launcher" || fail "casan version failed"
python3 - "$CASAN_HOME/current/packages/casan-devkit/casan-init.py" <<'PY' \
&& pass "client selector accepts menu numbers, aliases, repeats, and all" \
|| fail "client selector normalization failed"
import importlib.util,sys
&& pass "init wizard resolves runtime and client choices safely" \
|| fail "init wizard selection failed"
import contextlib
import importlib.util
import io
import sys
spec=importlib.util.spec_from_file_location("casan_init",sys.argv[1])
m=importlib.util.module_from_spec(spec); spec.loader.exec_module(m)
# Explicit flags and existing project configuration never open a prompt.
assert m.select_runtime_mode("vendored",None,True)=="vendored"
assert m.select_runtime_mode(None,"vendored",True)=="vendored"
assert m.select_runtime_mode(None,None,False)=="managed"
# Interactive defaults, aliases, validation, and retry behavior.
old_stdin=m.sys.stdin
try:
m.sys.stdin=io.StringIO("\n")
with contextlib.redirect_stderr(io.StringIO()):
assert m.select_runtime_mode(None,None,True)=="managed"
m.sys.stdin=io.StringIO("9\n2\n")
with contextlib.redirect_stderr(io.StringIO()) as errors:
assert m.select_runtime_mode(None,None,True)=="vendored"
assert "Invalid selection" in errors.getvalue()
m.sys.stdin=io.StringIO("bogus\n3\n")
with contextlib.redirect_stderr(io.StringIO()) as errors:
assert m.select_clients(None,True)==["vscode-copilot"]
assert "Invalid selection" in errors.getvalue()
finally:
m.sys.stdin=old_stdin
assert m.select_clients(["1,3"],False)==["claude","vscode-copilot"]
assert m.select_clients(["codex","copilot"],False)==["codex","vscode-copilot"]
assert m.select_clients(["all"],False)==["claude","codex","vscode-copilot"]