App shell with sidebar and theme switch; attribute-set management; project rename; new pages for projects, runbooks and activity
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 5s
Work Records / validate (push) Successful in 12s

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: sonnet
Assistant-Process: 295952@bnt-lap001
Assistant-Session: e93f64ad-516c-46eb-9666-aad8d300c477
This commit is contained in:
tegwick 2026-09-29 17:38:06 +02:00
parent a6ee6a0a6e
commit 6579618737
9 changed files with 663 additions and 13 deletions

View file

@ -295,3 +295,27 @@ def set_attributes(reg: Registry, doc: Doc, values: dict[str, str]) -> Path:
text["attributes"] = attrs
doc.path.write_text(yaml.safe_dump(text, sort_keys=False))
return doc.path
def update_project(doc: Doc, title: str, description: str = "", goal: str = "") -> Path:
"""Rename a project and edit its description and goal, in its own file."""
if doc.data.get("spec") != "project/v0.1":
raise ValueError("only a project can be edited this way")
from .pack import SECRET_RE
title = title.strip()
if len(title) < 3:
raise ValueError("the project name needs at least 3 characters")
for label, text in (("name", title), ("description", description), ("goal", goal)):
if SECRET_RE.search(text):
raise ValueError(f"the {label} looks like a secret; projects are never secret")
data = yaml.safe_load(doc.path.read_text())
data["title"] = title
for key, text in (("description", description), ("goal", goal)):
if text.strip():
data[key] = text.strip()
else:
data.pop(key, None)
ordered = {k: data[k] for k in ("spec", "id", "title", "description", "goal") if k in data}
ordered.update({k: v for k, v in data.items() if k not in ordered})
doc.path.write_text(yaml.safe_dump(ordered, sort_keys=False))
return doc.path