feat(systems): a System names its files — path patterns stored, validated and matched (milestone 444 step 3, #4756)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 15s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m6s
CI & Build / Python tests (push) Successful in 1m50s
CI & Build / Build & push image (push) Successful in 43s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 15s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m6s
CI & Build / Python tests (push) Successful in 1m50s
CI & Build / Build & push image (push) Successful in 43s
A System gains path_patterns: globs relative to the repo root (* within one directory, ** across any depth, a plain directory covering everything under it). One service validates them for every door, so the web UI and MCP refuse the same bad pattern with the same message. systems_for_paths resolves paths to every active System that covers them, which step 4 (#4757) uses to deliver an area's rulings when its files are touched. - schema: systems.path_patterns JSONB NOT NULL default [] (migration 0113) - service: normalize_path_patterns, path_matches, systems_for_paths - routes + MCP create_system/update_system accept it; [] clears - web UI: a Files field in the create and edit forms, patterns on the card - backup carries it through export and restore - using-scribe reflex 7: tagging work keeps a System's files current Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -82,12 +82,16 @@ async def create_system_route(project_id: int):
|
||||
# Exact is mechanical and applied; overlap is a judgment call and is only
|
||||
# offered back for the form to present.
|
||||
applied = canonical["id"] if canonical and canonical["basis"] == "exact" else None
|
||||
system = await systems_svc.create_system(
|
||||
uid, project_id=project_id, name=data["name"],
|
||||
description=data.get("description"), color=data.get("color"),
|
||||
order_index=data.get("order_index", 0),
|
||||
canonical_id=data.get("canonical_id") or applied,
|
||||
)
|
||||
try:
|
||||
system = await systems_svc.create_system(
|
||||
uid, project_id=project_id, name=data["name"],
|
||||
description=data.get("description"), color=data.get("color"),
|
||||
order_index=data.get("order_index", 0),
|
||||
canonical_id=data.get("canonical_id") or applied,
|
||||
path_patterns=data.get("path_patterns"),
|
||||
)
|
||||
except ValueError as e:
|
||||
return jsonify({"error": str(e)}), 400
|
||||
if system is None:
|
||||
return jsonify({"error": "Permission denied"}), 403
|
||||
out = system.to_dict()
|
||||
@@ -125,11 +129,14 @@ async def update_system_route(project_id: int, system_id: int):
|
||||
if system is None or system.project_id != project_id:
|
||||
return not_found("System")
|
||||
data = await request.get_json() or {}
|
||||
allowed = {"name", "description", "color", "status", "order_index"}
|
||||
allowed = {"name", "description", "color", "status", "order_index", "path_patterns"}
|
||||
fields = {k: v for k, v in data.items() if k in allowed}
|
||||
if "status" in fields and fields["status"] not in ("active", "archived"):
|
||||
return jsonify({"error": "status must be 'active' or 'archived'"}), 400
|
||||
updated = await systems_svc.update_system(uid, system_id, **fields)
|
||||
try:
|
||||
updated = await systems_svc.update_system(uid, system_id, **fields)
|
||||
except ValueError as e:
|
||||
return jsonify({"error": str(e)}), 400
|
||||
if updated is None:
|
||||
return not_found("System")
|
||||
return jsonify(updated.to_dict())
|
||||
|
||||
Reference in New Issue
Block a user