fix(dashboard): tolerate missing manifest
test / unit (pull_request) Successful in 25s
test / integration (pull_request) Successful in 44s

This commit is contained in:
2026-05-28 18:44:42 -04:00
parent 7f3998e79e
commit c4449001d1
4 changed files with 36 additions and 5 deletions
+10 -4
View File
@@ -368,8 +368,6 @@ def _picker_modal(
"""Modal agent picker. Type to filter; j/k or arrows to
navigate; Enter to confirm; Esc to abort (first press clears
filter if any, second press exits)."""
if not names:
return None
selected = 0
query = ""
while True:
@@ -455,9 +453,13 @@ def _draw_picker_modal(
list_start_row = 3
visible_rows = box_h - list_start_row - 1
if not filtered:
empty_message = (
"(no agents configured)"
if not all_names else "(no agents match filter)"
)
win.addnstr(
list_start_row, 2,
"(no agents match filter)",
empty_message,
box_w - 4, curses.A_DIM,
)
else:
@@ -1154,6 +1156,8 @@ def _new_agent_flow(
names = sorted(manifest.agents.keys())
picked = _picker_modal(stdscr, names, _running_counts(bottles, agents_now))
if picked is None:
if not names:
return "no agents configured; create ~/.bot-bottle/agents/*.md"
return "agent start aborted"
# Backend picker (issue #77): operator chooses docker /
@@ -1401,8 +1405,10 @@ def _main_loop(stdscr: "curses._CursesWindow") -> None:
def _get_manifest() -> Manifest:
if manifest_cache[0] is None:
manifest_cache[0] = Manifest.resolve(USER_CWD)
manifest_cache[0] = Manifest.resolve(USER_CWD, missing_ok=True)
return manifest_cache[0]
if not _get_manifest().bottles and not _get_manifest().agents:
status_line = "warning: no bot-bottle config/agents found; new-agent picker is empty"
# First-tick guard: a brand-new dashboard finds any
# pre-existing queue entries on its first poll; those
# shouldn't ring the bell as if they just arrived.
+8 -1
View File
@@ -661,7 +661,7 @@ class Manifest:
agents: Mapping[str, Agent]
@classmethod
def resolve(cls, cwd: str) -> "Manifest":
def resolve(cls, cwd: str, *, missing_ok: bool = False) -> "Manifest":
"""Walk the per-file manifest tree and build a Manifest.
Layout (PRD 0011):
@@ -674,6 +674,11 @@ class Manifest:
warning and ignored the filesystem layout IS the trust
boundary.
If `missing_ok` is true, a missing `$HOME/.bot-bottle/`
returns an empty manifest instead of dying. This is for
passive UI surfaces like the dashboard, which can still
monitor already-running agents without launch config.
If `bot-bottle.json` exists alongside a missing
`.bot-bottle/` directory at either side, dies with a
clear pointer at the README's manifest section — the
@@ -689,6 +694,8 @@ class Manifest:
_check_stale_json(cwd_dir, cwd_md, "$CWD")
if not home_md.is_dir():
if missing_ok:
return cls.from_json_obj({"bottles": {}, "agents": {}})
die(
f"no manifest found: {home_md} does not exist. "
f"See README.md for the per-file Markdown layout "